kanat is too fat
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

207 lines
6.3 KiB

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;
let c = -1;
const instructions = {};
//console.log(text);
for (let i = 0; i < text.length; ++i) {
if (text[i] === '\n') {
if (line_index === 0) {
line_start = i + 1;
line_index += 1;
continue;
}
// TODO: speed
const line_copy = text.substring(line_start, i);
const line_parts = line_copy.split(/\t/);
if (line_parts.length === 0) {
console.error('Parser error: empty line');
return false;
}
const command = line_parts[0];
switch (command) {
case 'C=': {
// Specify the number of cycles since the start of simulation.
if (!assert_arglen(line_parts, 1, 'C=')) return false;
const cycles = Number(line_parts[1]);
c = cycles;
break;
}
case 'C': {
// Specifies the number of elapsed cycles since the last output of any commands.
if (!assert_arglen(line_parts, 1, 'C')) return false;
const cycles = Number(line_parts[1]);
c += cycles;
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]);
instructions[insn_id_in_file] = {
'cycle': c,
'file_id': insn_id_in_file,
'sim_id': insn_id_in_sim,
'thread_id': thread_id,
'text': '',
'popover_text': '',
'lanes': {},
};
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[3].replaceAll('\\n', '\n');
if (id in instructions) {
if (type === 0) {
instructions[id].text += text;
} else {
instructions[id].popover_text += text;
}
} else {
console.error('Parser error: label for an instruction that does not exist');
return false;
}
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];
if (id in instructions) {
if (!(lane in instructions[id].lanes)) {
instructions[id].lanes[lane] = [];
}
instructions[id].lanes[lane].push({
'name': stage,
'c': c,
});
} else {
console.error('Parser error: pipeline start for an instruction that does not exist');
return false;
}
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];
// This command can be ommited
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]);
if (id in instructions) {
if (type === 0) {
instructions[id].retired = true;
} else {
instructions[id].retired = false;
}
instructions[id].retcyc = c;
} else {
console.error('Parser error: retire for an instruction that does not exist');
return false;
}
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]);
// TODO
break;
}
default: {
console.error('Parser error: unexpected command', command);
return false;
}
}
line_start = i + 1;
line_index += 1;
}
}
const after = performance.now();
console.log(`Parsed in ${Math.round(after - before)}ms`);
traces['0'] = {
'raw': instructions,
};
traces['0'].geo = generate('0');
return true;
}
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;
}