diff options
Diffstat (limited to 'data/vue/App.vue')
| -rw-r--r-- | data/vue/App.vue | 212 |
1 files changed, 148 insertions, 64 deletions
diff --git a/data/vue/App.vue b/data/vue/App.vue index e672911..73923dd 100644 --- a/data/vue/App.vue +++ b/data/vue/App.vue @@ -9,11 +9,15 @@ </span> </h1> <form @change="trigger_reload"> - <span class="nobr">Entries (max): <input class="input_small" v-model="entries" /></span><wbr /> - <span class="nobr">nth: <input class="input_small" v-model="nth" /></span><wbr /> - <span class="nobr">X-axis: <select class="input_small" v-model="x_axis"><option v-for="axis in x_axes">{{ axis }}</option></select></span><wbr /> + <span class="nobr">Entries: <input v-model="entries" /></span><wbr /> + <span class="nobr">nth: <input v-model="nth" /></span><wbr /> + <span class="nobr">X-axis: <select v-model="x_axis"><option v-for="axis in x_axes">{{ axis }}</option></select></span><wbr /> <span class="nobr">X-low: <input v-model="x_low" /></span><wbr /> - <span class="nobr">X-high: <input v-model="x_high" /></span> + <span class="nobr">X-high: <input v-model="x_high" /></span><wbr /> + <span class="nobr">Left: <input v-model="hm_left" /></span><wbr /> + <span class="nobr">Px-count: <input v-model="hm_px_count" /></span><wbr /> + <span class="nobr">Px-pow: <input v-model="hm_px_pow" /></span><wbr /> + <span class="reset_button" @click="reset_inputs">↻</span> </form> </div> <Section name="Options" visible> @@ -29,6 +33,9 @@ <Section :name="section" grid ref="plot_sections" :visible="section === 'General'" triggers_reload v-for="(section_plots, section) in plots"> <Plot :name="name" :section="section" v-for="(_, name) in section_plots" /> </Section> + <Section :name="section" grid ref="heatmap_sections" triggers_reload v-for="(section_heatmaps, section) in heatmaps"> + <Plot is_heatmap :name="name" :section="section" v-for="(_, name) in section_heatmaps" /> + </Section> </div> </template> @@ -41,7 +48,7 @@ import Section from './Section.vue' const root = window.location.href const id = v => v const hex = v => v !== undefined ? `0x${v.toString(16)}` : '' -const hex_pow = v => v !== undefined ? `0x${Math.pow(2, v).toString(16)}` : '' +const hex_pow = v => v !== undefined ? `0x${(2 ** v).toString(16)}` : '' const disabled = v => v ? 'disabled' : 'enabled' const opt_fmts = [ @@ -58,88 +65,120 @@ const opt_fmts = [ ['Seed', 'seed', hex], ] -let visible_tables = [] +let visible_plot_tables = [] +let visible_heatmap_tables = [] let query_timeout = null -let plot_x_low = 0n +let plot_x_low = 0 let plot_redraw = false +let mvec_size = 0 + +const uint32_max = (2 ** 32) - 1 +const hm_max_pixels = 2 ** 11 + +const entries_def = 2000 +const nth_def = 1 +const x_axis_def = 'rowid' +const x_low_def = hex(0) +const x_high_def = hex(uint32_max) +const hm_left_def = hex(0) +const hm_px_count_def = hex(2 ** 10) + +const entries = ref(entries_def) +const nth = ref(nth_def) +const x_axes = ref(['rowid', 'step']) +const x_axis = ref(x_axis_def) +const x_low = ref(x_low_def) +const x_high = ref(x_high_def) +const hm_left = ref(hm_left_def) +const hm_px_count = ref(hm_px_count_def) +const hm_px_pow = ref(hex(0)) const opts = ref({}) const plots = ref({}) +const heatmaps = ref({}) const loaded = ref(false) -const entries = ref(2000) -const nth = ref(BigInt(1)) -const x_axes = ref(['rowid', 'step']) -const x_axis = ref(x_axes.value[0]) -const x_low = ref(hex(BigInt(0))) -const x_high = ref(hex(BigInt(Math.pow(2, 64)))) - const query_in_progress = ref(false) const data = ref([]) const top_pad = useTemplateRef('top_pad') const top_bar = useTemplateRef('top_bar') const plot_sections = useTemplateRef('plot_sections') +const heatmap_sections = useTemplateRef('heatmap_sections') const update_visible_tables = () => { - const section_visibility = plot_sections.value.map(section => section.visible) - visible_tables = Object.entries(plots.value).filter((_, i) => section_visibility[i]).map((section, _) => [...new Set(Object.entries(section[1]).map(plot => plot[1].table))]).flat() + const plot_section_visibility = plot_sections.value.map(section => section.visible) + const heatmap_section_visibility = heatmap_sections.value.map(section => section.visible) + visible_plot_tables = Object.entries(plots.value).filter((_, i) => plot_section_visibility[i]).map((section, _) => [...new Set(Object.entries(section[1]).map(plot => plot[1].table))]).flat() + visible_heatmap_tables = Object.entries(heatmaps.value).filter((_, i) => heatmap_section_visibility[i]).map((section, _) => [...new Set(Object.entries(section[1]).map(plot => plot[1].table))]).flat() } const sanitize = (input, min, max, def, fmt) => { - if (isNaN(Number(input.value)) || input.value === '' || input.value < min || input.value > max) { + if (isNaN(Number(input.value)) || input.value === '' || input.value < min || input.value >= max) { input.value = fmt(def) } } +const max_hm_px_pow = () => Math.floor(Math.log2((mvec_size - Number(hm_left.value)) / Number(hm_px_count.value))) + const trigger_reload = () => { update_visible_tables() - sanitize(entries, 1n, BigInt(Math.pow(2, 64)), 2000n, id) - sanitize(nth, 1n, BigInt(Math.pow(2, 64)), 1n, id) - sanitize(x_low, 0n, BigInt(Math.pow(2, 64)), 0n, hex) - sanitize(x_high, 1n, BigInt(Math.pow(2, 64)), BigInt(Math.pow(2, 64)), hex) + sanitize(entries, 1, uint32_max, 2000, id) + sanitize(nth, 1, uint32_max, 1, id) + sanitize(x_low, 0, uint32_max, 0, hex) + sanitize(x_high, 1, uint32_max, uint32_max, hex) + + if (opts.value.mvec_loop) { + sanitize(hm_left, 0, uint32_max, 0, hex) + sanitize(hm_px_count, 1, hm_max_pixels, hm_max_pixels, hex) + sanitize(hm_px_pow, 0, uint32_max, uint32_max, hex) + } else { + sanitize(hm_left, 0, mvec_size, 0, hex) + sanitize(hm_px_count, 1, hm_max_pixels, hm_max_pixels, hex) + sanitize(hm_px_pow, 0, max_hm_px_pow(), max_hm_px_pow(), hex) + } - plot_x_low = x_low.value + plot_x_low = Number(x_low.value) plot_redraw = true query() } -const pad_top_bar = () => { - top_pad.value.style.height = `${Math.round(top_bar.value.getBoundingClientRect().height)}px` -} - -const reviver = (_, val, { source }) => { - if (Number.isInteger(val) && !Number.isSafeInteger(val)) { - try { return BigInt(source) } catch {} - } - - return val +const reset_inputs = () => { + entries.value = entries_def + nth.value = nth_def + x_axis.value = x_axis_def + x_low.value = x_low_def + x_high.value = x_high_def + hm_left.value = hm_left_def + hm_px_count.value = hm_px_count_def + hm_px_pow.value = max_hm_px_pow() + + trigger_reload() } -const query_table = async table => { +const query_table = async (table, is_heatmap, x_high_now) => { const params = { table: table, entries: entries.value, nth: nth.value, x_axis: x_axis.value, - x_low: Number(plot_x_low), - x_high: Number(x_high.value), + x_low: plot_x_low, + x_high: x_high_now, + is_eva: is_heatmap, + ...is_heatmap ? { + hm_left: Number(hm_left.value), + hm_px_count: Number(hm_px_count.value), + hm_px_pow: Number(hm_px_pow.value), + } : {}, } const search_params = new URLSearchParams(params) const resp_table = await fetch(root + `data?${search_params}`, { method: 'GET' }) - const resp_json = JSON.parse(await resp_table.text(), reviver) + const text_table = await resp_table.text() - // Keep track of the highest x-axis value fetched so far. - // Future queries will set this as the minimum, which prevents re-fetching already stored data. - if (resp_json.length) { - const x_last = BigInt(resp_json.slice(-1)[0][x_axis.value] + 1) - plot_x_low = plot_x_low > x_last ? plot_x_low : x_last - } - - return resp_json + return JSON.parse(text_table) } const query = async () => { @@ -148,27 +187,51 @@ const query = async () => { clearTimeout(query_timeout) query_in_progress.value = true - const query_results = await Promise.all(visible_tables.map(query_table)) - const query_values = Object.fromEntries(visible_tables.map((key, i) => [key, query_results[i]])) + const high_params = new URLSearchParams({ x_axis: x_axis.value }) + const resp_x_high = await fetch(root + `x_high?${high_params}`, { method: 'GET' }) + const text_x_high = await resp_x_high.text() + const json_x_high = JSON.parse(text_x_high) + const x_high_max = json_x_high.x_high + 1 + const x_high_val = Number(x_high.value) + const x_high_now = x_high_max < x_high_val ? x_high_max : x_high_val; + + const plot_query_results = await Promise.all(visible_plot_tables.map(table => query_table(table, false, x_high_now))) + const heatmap_query_results = await Promise.all(visible_heatmap_tables.map(table => query_table(table, true, x_high_now))) + const plot_query_values = Object.fromEntries(visible_plot_tables.map((table, i) => [table, plot_query_results[i]])) + const heatmap_query_values = Object.fromEntries(visible_heatmap_tables.map((table, i) => [table, heatmap_query_results[i]])) - data.value = { redraw: plot_redraw, values: query_values } + // Keep track of the highest x-axis value fetched so far. + // Future queries will set this as the minimum, which prevents re-fetching already stored data. + plot_x_low = x_high_now + + data.value = { redraw: plot_redraw, plot_values: plot_query_values, heatmap_values: heatmap_query_values } plot_redraw = false query_in_progress.value = false query_timeout = setTimeout(query, 10000) } -onMounted(async () => { - window.onresize = _ => pad_top_bar() - pad_top_bar() +const with_big_ints = (_, val, { source }) => { + if (Number.isInteger(val) && !Number.isSafeInteger(val)) { + try { return BigInt(source) } catch {} + } + return val +} + +onMounted(async () => { const resp_opts = await fetch(root + 'opts', { method: 'GET' }) const resp_plots = await fetch(root + 'plots', { method: 'GET' }) + const resp_heatmaps = await fetch(root + 'heatmaps', { method: 'GET' }) - opts.value = JSON.parse(await resp_opts.text(), reviver) - plots.value = JSON.parse(await resp_plots.text(), reviver) + opts.value = JSON.parse(await resp_opts.text(), with_big_ints) + plots.value = JSON.parse(await resp_plots.text()) + heatmaps.value = JSON.parse(await resp_heatmaps.text()) loaded.value = true + mvec_size = 2 ** opts.value.mvec_pow + hm_px_pow.value = hex(max_hm_px_pow()) + // All tables should include one cycle column for each core. // This allows normalizing the plots against each core's cycle count // (i.e. making `cycl_#` the plots' x-axis). @@ -176,37 +239,45 @@ onMounted(async () => { }) watch(loaded, _ => { + top_pad.value.style.height = `${Math.round(top_bar.value.getBoundingClientRect().height)}px` + update_visible_tables() query() }, { flush: 'post' }) provide('plots', plots) +provide('heatmaps', heatmaps) provide('entries', entries) provide('x_axis', x_axis) +provide('hm_left', hm_left) +provide('hm_px_count', hm_px_count) +provide('hm_px_pow', hm_px_pow) provide('data', data) provide('trigger_reload', trigger_reload) </script> <style> html { - background-color: #002b36; - color: #586e75; + background-color: black; + color: gray; font-family: sans-serif; } h1 { - font-size: 20px; + font-size: 18px; font-weight: 600; + margin: 8px 0; } input, select { - background-color: #586e75; + background-color: gray; border: none; - color: #002b36; + color: black; font-family: monospace; - font-size: 14px; + font-size: 12px; margin: 0 4px; padding: 2px; + width: 80px; } table { @@ -217,7 +288,7 @@ table { } tr:nth-child(odd) { - background-color: #073642; + background-color: #111; } td { @@ -228,7 +299,7 @@ td { } .top_bar { - background-color: #073642; + background-color: #111; left: 0; padding: 8px; position: fixed; @@ -243,12 +314,25 @@ td { } .nobr { - line-height: 32px; - margin-right: 16px; + font-size: 12px; + line-height: 28px; + margin-right: 6px; white-space: nowrap; } -.input_small { - width: 80px; +.reset_button { + background-color: black; + border: 1.5px solid gray; + color: gray; + cursor: pointer; + display: inline-block; + font-family: monospace; + font-size: 14px; + height: 16px; + line-height: 16px; + margin: 0 4px; + padding: 2px; + text-align: center; + width: 16px; } </style> |
