aboutsummaryrefslogtreecommitdiff
path: root/data/vue
diff options
context:
space:
mode:
Diffstat (limited to 'data/vue')
-rw-r--r--data/vue/App.vue212
-rw-r--r--data/vue/Plot.vue104
-rw-r--r--data/vue/Section.vue4
3 files changed, 215 insertions, 105 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>
diff --git a/data/vue/Plot.vue b/data/vue/Plot.vue
index 3c08d73..5bbc89a 100644
--- a/data/vue/Plot.vue
+++ b/data/vue/Plot.vue
@@ -11,7 +11,7 @@
<script setup>
import { defineProps, inject, onMounted, ref, useTemplateRef, watch } from 'vue'
-const props = defineProps({ section: String, name: String })
+const props = defineProps({ is_heatmap: Boolean, section: String, name: String })
const maximized = ref(false)
@@ -19,8 +19,12 @@ const plot_ref = useTemplateRef('plot_ref')
const plot_container = useTemplateRef('plot_container')
const plots = inject('plots')
+const heatmaps = inject('heatmaps')
const entries = inject('entries')
const x_axis = inject('x_axis')
+const hm_left = inject('hm_left')
+const hm_px_count = inject('hm_px_count')
+const hm_px_pow = inject('hm_px_pow')
const data = inject('data')
const plot_toggle_maximize = () => {
@@ -34,32 +38,32 @@ const prevent_plotly_buttons_tab_focus = () => {
focusableElements.forEach(elem => elem.setAttribute('tabindex', '-1'))
}
-onMounted(() => {
- const plot_config = plots.value[props.section][props.name]
+const heatmap_init = [{ colorscale: 'Electric', type: 'heatmap', x: [], y: [], z: [] }]
- switch (plot_config.type) {
- case 'lines':
- var data_defs = { mode: 'lines', line: { width: 1 }}
- break
- case 'stack':
- var data_defs = { mode: 'lines', line: { width: 1 }, stackgroup: 'stackgroup' }
- break
- case 'stack_percent':
- var data_defs = { mode: 'lines', line: { width: 1 }, stackgroup: 'stackgroup', groupnorm: 'percent' }
- break
- }
+const plot_init = () => {
+ const plot_config = plots.value[props.section][props.name]
+ const plot_defs = { mode: 'lines', line: { width: 1 }, x: [], y: [] }
+
+ switch (plot_config.type) {
+ case 'lines':
+ return Array.from(plot_config.cols, col => ({ ...plot_defs, name: col }))
+ case 'stack':
+ return Array.from(plot_config.cols, col => ({ ...plot_defs, stackgroup: 'sg', name: col }))
+ case 'stack_percent':
+ return Array.from(plot_config.cols, col => ({ ...plot_defs, stackgroup: 'sg', groupnorm: 'percent', name: col }))
+ }
+}
- const columns = plot_config.cols
- const data = Array.from(columns, column => ({ ...data_defs, x: [], y: [], name: column }))
-
- Plotly.newPlot(plot_ref.value, data, {
- legend: { font: { color: '#586e75', family: 'monospace' }, maxheight: 100, orientation: 'h' },
- margin: { b: 32, l: 32, r: 32, t: 32 },
- paper_bgcolor: '#002b36',
- plot_bgcolor: '#002b36',
- title: { font: { color: '#586e75' }, text: props.name, x: 0, xref: 'paper' },
- xaxis: { gridcolor: '#073642', tickfont: { color: '#586e75' }, zerolinecolor: '#586e75' },
- yaxis: { gridcolor: '#073642', tickfont: { color: '#586e75' }, zerolinecolor: '#586e75' },
+onMounted(() => {
+ Plotly.newPlot(plot_ref.value, props.is_heatmap ? heatmap_init : plot_init(), {
+ font: { color: 'gray', family: 'monospace' },
+ legend: { maxheight: 100, orientation: 'h' },
+ margin: { b: 48, l: 48, r: 48, t: 48 },
+ paper_bgcolor: 'black',
+ plot_bgcolor: 'black',
+ title: { font: { size: 16 }, text: props.name, x: 0, xref: 'paper' },
+ xaxis: { gridcolor: '#111', tickfont: { color: 'gray' }, zerolinecolor: 'gray' },
+ yaxis: { gridcolor: '#111', tickfont: { color: 'gray' }, zerolinecolor: 'gray' },
}, {
displayModeBar: true,
responsive: true,
@@ -68,32 +72,54 @@ onMounted(() => {
prevent_plotly_buttons_tab_focus()
})
-watch(data, new_data => {
+const update_plot = new_data => {
const plot_config = plots.value[props.section][props.name]
- const columns = plot_config.cols
- const column_count = columns.length
- const table_data = new_data.values[plot_config.table]
- const traces = [...Array(column_count).keys()]
- const xs = Array(column_count).fill(table_data.map(elem => elem[x_axis.value]))
- const ys = columns.map(column => table_data.map(elem => elem[column]))
+ const cols = plot_config.cols
+ const cols_count = cols.length
+ const table_data = new_data.plot_values[plot_config.table]
+ const traces = [...Array(cols_count).keys()]
+ const xs = Array(cols_count).fill(table_data.map(elem => elem[x_axis.value]))
+ const ys = cols.map(column => table_data.map(elem => elem[column]))
// Clear traces
if (new_data.redraw) {
const restyle = {
- x: Array.from(columns, () => []),
- y: Array.from(columns, () => []),
+ x: Array.from(cols, () => []),
+ y: Array.from(cols, () => []),
}
Plotly.restyle(plot_ref.value, restyle)
}
Plotly.extendTraces(plot_ref.value, { x: xs, y: ys }, traces, entries.value)
-})
+}
+
+const update_heatmap = new_data => {
+ const heatmap_config = heatmaps.value[props.section][props.name]
+ const table_data = new_data.heatmap_values[heatmap_config.table]
+ const ys = [table_data.map(elem => elem[x_axis.value])]
+ const zs = [table_data.map(elem => elem.eva_render.split(' ').map(str => Number('0x' + str)))]
+
+ if (new_data.redraw) {
+ const px_size = Math.pow(2, Number(hm_px_pow.value))
+ const restyle = {
+ x: [Array.from(Array(Number(hm_px_count.value)).keys()).map(i => Number(hm_left.value) + i * px_size)],
+ y: [[]],
+ z: [[]],
+ }
+
+ Plotly.restyle(plot_ref.value, restyle)
+ }
+
+ Plotly.extendTraces(plot_ref.value, { y: ys, z: zs }, [0], entries.value)
+}
+
+watch(data, props.is_heatmap ? update_heatmap : update_plot)
</script>
<style>
.plot_container {
- background-color: #002b36;
+ background-color: black;
display: inline-block;
width: 100%;
}
@@ -113,9 +139,9 @@ watch(data, new_data => {
}
.plot_button {
- background-color: #002b36;
- border: 1.5px solid #586e75;
- color: #586e75;
+ background-color: black;
+ border: 1.5px solid gray;
+ color: gray;
cursor: pointer;
font-family: monospace;
font-size: 18px;
diff --git a/data/vue/Section.vue b/data/vue/Section.vue
index f0202c0..7f4d633 100644
--- a/data/vue/Section.vue
+++ b/data/vue/Section.vue
@@ -24,9 +24,9 @@ defineExpose({ visible })
<style>
.section_header {
- border-bottom: 1px solid #586e75;
+ border-bottom: 1px solid gray;
cursor: pointer;
- font-size: 18px;
+ font-size: 16px;
font-weight: normal;
}