From 432fd08944a5be027a2ba28dc1f166de82eb4546 Mon Sep 17 00:00:00 2001 From: "A.Olokhtonov" Date: Sat, 20 Jul 2024 14:20:28 +0300 Subject: [PATCH] iterate some traces --- default.css | 11 ++++ index.html | 23 ++++++++ index.js | 5 ++ input.js | 52 +++++++++++++++++++ parse.js | 147 ++++++++++++++++++++++++++++++++++++++++++++++++++++ render.js | 0 6 files changed, 238 insertions(+) create mode 100644 default.css create mode 100644 index.html create mode 100644 index.js create mode 100644 input.js create mode 100644 parse.js create mode 100644 render.js diff --git a/default.css b/default.css new file mode 100644 index 0000000..062217e --- /dev/null +++ b/default.css @@ -0,0 +1,11 @@ +html, body { + margin: 0; + padding: 0; + width: 100%; + height: 100%; + overflow: hidden; +} + +body .main { + height: 100%; +} diff --git a/index.html b/index.html new file mode 100644 index 0000000..4b71c67 --- /dev/null +++ b/index.html @@ -0,0 +1,23 @@ + + + + + Nitka + + + + + + + + + + + + + + +
+
+ + diff --git a/index.js b/index.js new file mode 100644 index 0000000..5d31e11 --- /dev/null +++ b/index.js @@ -0,0 +1,5 @@ +document.addEventListener('DOMContentLoaded', main); + +function main() { + init_listeners(); +} diff --git a/input.js b/input.js new file mode 100644 index 0000000..defadf1 --- /dev/null +++ b/input.js @@ -0,0 +1,52 @@ +function init_listeners() { + document.querySelector('.main').addEventListener('dragover', cancel); + document.querySelector('.main').addEventListener('drop', drop); +} + +function cancel(e) { + e.preventDefault(); + e.stopPropagation(); +} + +function drop(e) { + e.preventDefault(); + + if (e.dataTransfer.files.length !== 1) { + console.error('Only one file at once, please!'); + return false; + } + + const file = e.dataTransfer.files[0]; + const fr = new FileReader(); + + const upload_failed = () => { + console.error('Upload failed'); + }; + + const upload_started = () => { + console.log('Upload started'); + }; + + const upload_finished = () => { + const text = fr.result; + console.log('Finished. String length:', text.length); + parse(text); + }; + + const upload_progress = (e) => { + if (e.lengthComputable) { + const percent = Math.floor(e.loaded / e.total * 100); + console.log(`Progress: ${percent}%`); + } else { + console.log('Progress: unknown'); + } + }; + + fr.addEventListener('abort', upload_failed); + fr.addEventListener('error', upload_failed); + fr.addEventListener('load', upload_finished); + fr.addEventListener('loadstart', upload_started); + fr.addEventListener('progress', upload_progress); + + fr.readAsText(file); +} diff --git a/parse.js b/parse.js new file mode 100644 index 0000000..cfe283f --- /dev/null +++ b/parse.js @@ -0,0 +1,147 @@ +function parse(text) { + // https://github.com/shioyadan/Konata/blob/master/docs/kanata-log-format.md + + const before = performance.now(); + + let line_start = 0; + let line_index = 0; + + //console.log(text); + + for (let i = 0; i < text.length; ++i) { + const c = text[i]; + + if (c === '\n') { + // TODO: speed + const line_copy = text.substring(line_start, i); + const line_parts = line_copy.split(/\s+/); + + if (line_parts.length === 0) { + console.error('Parser error: empty line'); + return false; + } + + const command = line_parts[0]; + switch (command) { + case 'Kanata': { + if (!assert_arglen(line_parts, 1, 'Kanata')) return false; + + const version = Number(line_parts[1]); + if (version !== 4) { + console.error('Parser error: only Kanata traces version 4 are supported'); + return false; + } + + break; + } + + case 'C=': { + if (!assert_arglen(line_parts, 1, 'C=')) return false; + + const cycles = Number(line_parts[1]); + + break; + } + + case 'C': { + if (!assert_arglen(line_parts, 1, 'C')) return false; + + const cycles = Number(line_parts[1]); + + break; + } + + case 'I': { + if (!assert_arglen(line_parts, 3, 'I')) return false; + + const insn_id_in_file = Number(line_parts[1]); + const insn_id_in_sim = Number(line_parts[2]); + const thread_id = Number(line_parts[3]); + + break; + } + + case 'L': { + if (!assert_arglenmin(line_parts, 3, 'L')) return false; + + const id = Number(line_parts[1]); + const type = Number(line_parts[2]); + const text = line_parts.slice(3).join(' '); // TODO: preserve spacing, newlines + + break; + } + + case 'S': { + if (!assert_arglen(line_parts, 3, 'S')) return false; + + const id = Number(line_parts[1]); + const lane = Number(line_parts[2]); + const stage = line_parts[3]; + + break; + } + + case 'E': { + if (!assert_arglen(line_parts, 3, 'E')) return false; + + const id = Number(line_parts[1]); + const lane = Number(line_parts[2]); + const stage = line_parts[3]; + + break; + } + + case 'R': { + if (!assert_arglen(line_parts, 3, 'R')) return false; + + const id = Number(line_parts[1]); + const retire_id = Number(line_parts[2]); + const type = Number(line_parts[3]); + + break; + } + + case 'W': { + if (!assert_arglen(line_parts, 3, 'W')) return false; + + const consumer_id = Number(line_parts[1]); + const producer_id = Number(line_parts[2]); + const type = Number(line_parts[3]); + + break; + } + + default: { + console.error('Parser error: unexpected command', command); + return false; + } + } + //console.log(command); + + line_start = i + 1; + line_index += 1; + } + } + + const after = performance.now(); + + console.log(`Parsed in ${Math.round(after - before)}ms`); +} + +function assert_arglen(args, arglen, command) { + if (args.length !== arglen + 1) { + console.error(`Parser error: command ${command} requires ${arglen} argument(s)`); + return false; + } + + return true; +} + +function assert_arglenmin(args, arglen, command) { + if (args.length < arglen + 1) { + console.error(`Parser error: command ${command} requires at least ${arglen} argument(s)`); + return false; + } + + return true; +} diff --git a/render.js b/render.js new file mode 100644 index 0000000..e69de29