e8d24c66b9
This CL modifies the logging pipeline of V8 to track timestamps of the IC events across the log file. Modifies the current IC-explorer's code to make it compatible with the IC event time processing. Change-Id: I2a0f652e2657bdebe8cecd7862a7545f7b050cdb Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2274613 Commit-Queue: Zeynep Cankara <zcankara@google.com> Reviewed-by: Camillo Bruni <cbruni@chromium.org> Reviewed-by: Sathya Gunasekaran <gsathya@chromium.org> Cr-Commit-Position: refs/heads/master@{#68849}
250 lines
6.9 KiB
JavaScript
250 lines
6.9 KiB
JavaScript
// Copyright 2020 the V8 project authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
// found in the LICENSE file.
|
|
|
|
/**
|
|
* Parser for dynamic code optimization state.
|
|
*/
|
|
function parseState(s) {
|
|
switch (s) {
|
|
case '':
|
|
return Profile.CodeState.COMPILED;
|
|
case '~':
|
|
return Profile.CodeState.OPTIMIZABLE;
|
|
case '*':
|
|
return Profile.CodeState.OPTIMIZED;
|
|
}
|
|
throw new Error('unknown code state: ' + s);
|
|
}
|
|
|
|
class IcProcessor extends LogReader {
|
|
constructor() {
|
|
super();
|
|
let propertyICParser = [
|
|
parseInt, parseInt, parseInt, parseInt, parseString, parseString,
|
|
parseInt, parseString, parseString, parseString
|
|
];
|
|
LogReader.call(this, {
|
|
'code-creation': {
|
|
parsers: [
|
|
parseString, parseInt, parseInt, parseInt, parseInt, parseString,
|
|
parseVarArgs
|
|
],
|
|
processor: this.processCodeCreation
|
|
},
|
|
'code-move':
|
|
{parsers: [parseInt, parseInt], processor: this.processCodeMove},
|
|
'code-delete': {parsers: [parseInt], processor: this.processCodeDelete},
|
|
'sfi-move':
|
|
{parsers: [parseInt, parseInt], processor: this.processFunctionMove},
|
|
'LoadGlobalIC': {
|
|
parsers: propertyICParser,
|
|
processor: this.processPropertyIC.bind(this, 'LoadGlobalIC')
|
|
},
|
|
'StoreGlobalIC': {
|
|
parsers: propertyICParser,
|
|
processor: this.processPropertyIC.bind(this, 'StoreGlobalIC')
|
|
},
|
|
'LoadIC': {
|
|
parsers: propertyICParser,
|
|
processor: this.processPropertyIC.bind(this, 'LoadIC')
|
|
},
|
|
'StoreIC': {
|
|
parsers: propertyICParser,
|
|
processor: this.processPropertyIC.bind(this, 'StoreIC')
|
|
},
|
|
'KeyedLoadIC': {
|
|
parsers: propertyICParser,
|
|
processor: this.processPropertyIC.bind(this, 'KeyedLoadIC')
|
|
},
|
|
'KeyedStoreIC': {
|
|
parsers: propertyICParser,
|
|
processor: this.processPropertyIC.bind(this, 'KeyedStoreIC')
|
|
},
|
|
'StoreInArrayLiteralIC': {
|
|
parsers: propertyICParser,
|
|
processor: this.processPropertyIC.bind(this, 'StoreInArrayLiteralIC')
|
|
},
|
|
});
|
|
this.profile_ = new Profile();
|
|
|
|
this.LoadGlobalIC = 0;
|
|
this.StoreGlobalIC = 0;
|
|
this.LoadIC = 0;
|
|
this.StoreIC = 0;
|
|
this.KeyedLoadIC = 0;
|
|
this.KeyedStoreIC = 0;
|
|
this.StoreInArrayLiteralIC = 0;
|
|
}
|
|
/**
|
|
* @override
|
|
*/
|
|
printError(str) {
|
|
print(str);
|
|
}
|
|
processString(string) {
|
|
let end = string.length;
|
|
let current = 0;
|
|
let next = 0;
|
|
let line;
|
|
let i = 0;
|
|
let entry;
|
|
while (current < end) {
|
|
next = string.indexOf('\n', current);
|
|
if (next === -1) break;
|
|
i++;
|
|
line = string.substring(current, next);
|
|
current = next + 1;
|
|
this.processLogLine(line);
|
|
}
|
|
}
|
|
processLogFile(fileName) {
|
|
this.collectEntries = true;
|
|
this.lastLogFileName_ = fileName;
|
|
let line;
|
|
while (line = readline()) {
|
|
this.processLogLine(line);
|
|
}
|
|
print();
|
|
print('=====================');
|
|
print('LoadGlobal: ' + this.LoadGlobalIC);
|
|
print('StoreGlobal: ' + this.StoreGlobalIC);
|
|
print('Load: ' + this.LoadIC);
|
|
print('Store: ' + this.StoreIC);
|
|
print('KeyedLoad: ' + this.KeyedLoadIC);
|
|
print('KeyedStore: ' + this.KeyedStoreIC);
|
|
print('StoreInArrayLiteral: ' + this.StoreInArrayLiteralIC);
|
|
}
|
|
addEntry(entry) {
|
|
this.entries.push(entry);
|
|
}
|
|
processCodeCreation(type, kind, timestamp, start, size, name, maybe_func) {
|
|
if (maybe_func.length) {
|
|
let funcAddr = parseInt(maybe_func[0]);
|
|
let state = parseState(maybe_func[1]);
|
|
this.profile_.addFuncCode(
|
|
type, name, timestamp, start, size, funcAddr, state);
|
|
} else {
|
|
this.profile_.addCode(type, name, timestamp, start, size);
|
|
}
|
|
}
|
|
processCodeMove(from, to) {
|
|
this.profile_.moveCode(from, to);
|
|
}
|
|
processCodeDelete(start) {
|
|
this.profile_.deleteCode(start);
|
|
}
|
|
processFunctionMove(from, to) {
|
|
this.profile_.moveFunc(from, to);
|
|
}
|
|
formatName(entry) {
|
|
if (!entry) return '<unknown>';
|
|
let name = entry.func.getName();
|
|
let re = /(.*):[0-9]+:[0-9]+$/;
|
|
let array = re.exec(name);
|
|
if (!array) return name;
|
|
return entry.getState() + array[1];
|
|
}
|
|
|
|
processPropertyIC(
|
|
type, pc, time, line, column, old_state, new_state, map, name, modifier,
|
|
slow_reason) {
|
|
this[type]++;
|
|
let entry = this.profile_.findEntry(pc);
|
|
print(
|
|
type + ' (' + old_state + '->' + new_state + modifier + ') at ' +
|
|
this.formatName(entry) + ':' + line + ':' + column + ' ' + name +
|
|
' (map 0x' + map.toString(16) + ')' +
|
|
(slow_reason ? ' ' + slow_reason : '') + 'time: ' + time);
|
|
}
|
|
}
|
|
|
|
// ================
|
|
|
|
IcProcessor.kProperties = [
|
|
'type',
|
|
'category',
|
|
'functionName',
|
|
'filePosition',
|
|
'state',
|
|
'key',
|
|
'map',
|
|
'reason',
|
|
'file'
|
|
];
|
|
|
|
class CustomIcProcessor extends IcProcessor {
|
|
constructor() {
|
|
super();
|
|
this.entries = [];
|
|
}
|
|
|
|
functionName(pc) {
|
|
let entry = this.profile_.findEntry(pc);
|
|
return this.formatName(entry);
|
|
}
|
|
|
|
processPropertyIC(
|
|
type, pc, time, line, column, old_state, new_state, map, key, modifier,
|
|
slow_reason) {
|
|
let fnName = this.functionName(pc);
|
|
this.entries.push(new Entry(
|
|
type, fnName, time, line, column, key, old_state, new_state, map,
|
|
slow_reason));
|
|
}
|
|
};
|
|
|
|
class Entry {
|
|
constructor(
|
|
type, fn_file, time, line, column, key, oldState, newState, map, reason,
|
|
additional) {
|
|
this.time = time;
|
|
this.type = type;
|
|
this.category = 'other';
|
|
if (this.type.indexOf('Store') !== -1) {
|
|
this.category = 'Store';
|
|
} else if (this.type.indexOf('Load') !== -1) {
|
|
this.category = 'Load';
|
|
}
|
|
let parts = fn_file.split(' ');
|
|
this.functionName = parts[0];
|
|
this.file = parts[1];
|
|
let position = line + ':' + column;
|
|
this.filePosition = this.file + ':' + position;
|
|
this.oldState = oldState;
|
|
this.newState = newState;
|
|
this.state = this.oldState + ' → ' + this.newState;
|
|
this.key = key;
|
|
this.map = map.toString(16);
|
|
this.reason = reason;
|
|
this.additional = additional;
|
|
}
|
|
|
|
parseMapProperties(parts, offset) {
|
|
let next = parts[++offset];
|
|
if (!next.startsWith('dict')) return offset;
|
|
this.propertiesMode = next.substr(5) == '0' ? 'fast' : 'slow';
|
|
this.numberOfOwnProperties = parts[++offset].substr(4);
|
|
next = parts[++offset];
|
|
this.instanceType = next.substr(5, next.length - 6);
|
|
return offset;
|
|
}
|
|
|
|
parsePositionAndFile(parts, start) {
|
|
// find the position of 'at' in the parts array.
|
|
let offset = start;
|
|
for (let i = start + 1; i < parts.length; i++) {
|
|
offset++;
|
|
if (parts[i] == 'at') break;
|
|
}
|
|
if (parts[offset] !== 'at') return -1;
|
|
this.position = parts.slice(start, offset).join(' ');
|
|
offset += 1;
|
|
this.isNative = parts[offset] == 'native'
|
|
offset += this.isNative ? 1 : 0;
|
|
this.file = parts[offset];
|
|
return offset;
|
|
}
|
|
}
|
|
|
|
export { CustomIcProcessor as default }; |