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.
202 lines
6.2 KiB
202 lines
6.2 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'] = instructions; |
|
|
|
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; |
|
}
|
|
|