summaryrefslogtreecommitdiff
path: root/deps/v8/tools/system-analyzer/processor.mjs
diff options
context:
space:
mode:
Diffstat (limited to 'deps/v8/tools/system-analyzer/processor.mjs')
-rw-r--r--deps/v8/tools/system-analyzer/processor.mjs292
1 files changed, 191 insertions, 101 deletions
diff --git a/deps/v8/tools/system-analyzer/processor.mjs b/deps/v8/tools/system-analyzer/processor.mjs
index 49448bb9da..9685e09ad6 100644
--- a/deps/v8/tools/system-analyzer/processor.mjs
+++ b/deps/v8/tools/system-analyzer/processor.mjs
@@ -5,7 +5,8 @@
import {LogReader, parseString, parseVarArgs} from '../logreader.mjs';
import {Profile} from '../profile.mjs';
-import {DeoptLogEntry} from './log/deopt.mjs';
+import {ApiLogEntry} from './log/api.mjs';
+import {CodeLogEntry, DeoptLogEntry} from './log/code.mjs';
import {IcLogEntry} from './log/ic.mjs';
import {Edge, MapLogEntry} from './log/map.mjs';
import {Timeline} from './timeline.mjs';
@@ -17,17 +18,28 @@ export class Processor extends LogReader {
_mapTimeline = new Timeline();
_icTimeline = new Timeline();
_deoptTimeline = new Timeline();
+ _codeTimeline = new Timeline();
+ _apiTimeline = new Timeline();
_formatPCRegexp = /(.*):[0-9]+:[0-9]+$/;
+ _lastTimestamp = 0;
+ _lastCodeLogEntry;
MAJOR_VERSION = 7;
MINOR_VERSION = 6;
constructor(logString) {
super();
- this.propertyICParser = [
+ const propertyICParser = [
parseInt, parseInt, parseInt, parseInt, parseString, parseString,
parseString, parseString, parseString, parseString
];
this.dispatchTable_ = {
__proto__: null,
+ 'v8-version': {
+ parsers: [
+ parseInt,
+ parseInt,
+ ],
+ processor: this.processV8Version
+ },
'code-creation': {
parsers: [
parseString, parseInt, parseInt, parseInt, parseInt, parseString,
@@ -42,20 +54,28 @@ export class Processor extends LogReader {
],
processor: this.processCodeDeopt
},
- 'v8-version': {
+ 'code-move':
+ {parsers: [parseInt, parseInt], processor: this.processCodeMove},
+ 'code-delete': {parsers: [parseInt], processor: this.processCodeDelete},
+ 'code-source-info': {
+ parsers: [
+ parseInt, parseInt, parseInt, parseInt, parseString, parseString,
+ parseString
+ ],
+ processor: this.processCodeSourceInfo
+ },
+ 'code-disassemble': {
parsers: [
parseInt,
- parseInt,
+ parseString,
+ parseString,
],
- processor: this.processV8Version
+ processor: this.processCodeDisassemble
},
'script-source': {
parsers: [parseInt, parseString, parseString],
processor: this.processScriptSource
},
- 'code-move':
- {parsers: [parseInt, parseInt], processor: this.processCodeMove},
- 'code-delete': {parsers: [parseInt], processor: this.processCodeDelete},
'sfi-move':
{parsers: [parseInt, parseInt], processor: this.processFunctionMove},
'map-create':
@@ -72,33 +92,37 @@ export class Processor extends LogReader {
processor: this.processMapDetails
},
'LoadGlobalIC': {
- parsers: this.propertyICParser,
+ parsers: propertyICParser,
processor: this.processPropertyIC.bind(this, 'LoadGlobalIC')
},
'StoreGlobalIC': {
- parsers: this.propertyICParser,
+ parsers: propertyICParser,
processor: this.processPropertyIC.bind(this, 'StoreGlobalIC')
},
'LoadIC': {
- parsers: this.propertyICParser,
+ parsers: propertyICParser,
processor: this.processPropertyIC.bind(this, 'LoadIC')
},
'StoreIC': {
- parsers: this.propertyICParser,
+ parsers: propertyICParser,
processor: this.processPropertyIC.bind(this, 'StoreIC')
},
'KeyedLoadIC': {
- parsers: this.propertyICParser,
+ parsers: propertyICParser,
processor: this.processPropertyIC.bind(this, 'KeyedLoadIC')
},
'KeyedStoreIC': {
- parsers: this.propertyICParser,
+ parsers: propertyICParser,
processor: this.processPropertyIC.bind(this, 'KeyedStoreIC')
},
'StoreInArrayLiteralIC': {
- parsers: this.propertyICParser,
+ parsers: propertyICParser,
processor: this.processPropertyIC.bind(this, 'StoreInArrayLiteralIC')
},
+ 'api': {
+ parsers: [parseString, parseVarArgs],
+ processor: this.processApiEvent
+ },
};
if (logString) this.processString(logString);
}
@@ -166,45 +190,56 @@ export class Processor extends LogReader {
});
}
- /**
- * Parser for dynamic code optimization state.
- */
- parseState(s) {
- switch (s) {
- case '':
- return Profile.CodeState.COMPILED;
- case '~':
- return Profile.CodeState.OPTIMIZABLE;
- case '*':
- return Profile.CodeState.OPTIMIZED;
+ processV8Version(majorVersion, minorVersion) {
+ if ((majorVersion == this.MAJOR_VERSION &&
+ minorVersion <= this.MINOR_VERSION) ||
+ (majorVersion < this.MAJOR_VERSION)) {
+ window.alert(
+ `Unsupported version ${majorVersion}.${minorVersion}. \n` +
+ `Please use the matching tool for given the V8 version.`);
}
- throw new Error(`unknown code state: ${s}`);
}
processCodeCreation(type, kind, timestamp, start, size, name, maybe_func) {
+ this._lastTimestamp = timestamp;
+ let entry;
+ let stateName = '';
if (maybe_func.length) {
const funcAddr = parseInt(maybe_func[0]);
- const state = this.parseState(maybe_func[1]);
- this._profile.addFuncCode(
+ stateName = maybe_func[1] ?? '';
+ const state = Profile.parseState(maybe_func[1]);
+ entry = this._profile.addFuncCode(
type, name, timestamp, start, size, funcAddr, state);
} else {
- this._profile.addCode(type, name, timestamp, start, size);
+ entry = this._profile.addCode(type, name, timestamp, start, size);
}
+ this._lastCodeLogEntry =
+ new CodeLogEntry(type + stateName, timestamp, kind, entry);
+ this._codeTimeline.push(this._lastCodeLogEntry);
}
processCodeDeopt(
timestamp, codeSize, instructionStart, inliningId, scriptOffset,
deoptKind, deoptLocation, deoptReason) {
- this._deoptTimeline.push(new DeoptLogEntry(deoptKind, timestamp));
- }
-
- processV8Version(majorVersion, minorVersion) {
- if ((majorVersion == this.MAJOR_VERSION &&
- minorVersion <= this.MINOR_VERSION) ||
- (majorVersion < this.MAJOR_VERSION)) {
- window.alert(
- `Unsupported version ${majorVersion}.${minorVersion}. \n` +
- `Please use the matching tool for given the V8 version.`);
+ this._lastTimestamp = timestamp;
+ const codeEntry = this._profile.findEntry(instructionStart);
+ const logEntry = new DeoptLogEntry(
+ deoptKind, timestamp, codeEntry, deoptReason, deoptLocation,
+ scriptOffset, instructionStart, codeSize, inliningId);
+ this._deoptTimeline.push(logEntry);
+ this.addSourcePosition(codeEntry, logEntry);
+ logEntry.functionSourcePosition = logEntry.sourcePosition;
+ // custom parse deopt location
+ if (deoptLocation !== '<unknown>') {
+ const colSeparator = deoptLocation.lastIndexOf(':');
+ const rowSeparator = deoptLocation.lastIndexOf(':', colSeparator - 1);
+ const script = this.getScript(deoptLocation.substring(1, rowSeparator));
+ const line =
+ parseInt(deoptLocation.substring(rowSeparator + 1, colSeparator));
+ const column = parseInt(
+ deoptLocation.substring(colSeparator + 1, deoptLocation.length - 1));
+ logEntry.sourcePosition =
+ script.addSourcePosition(line, column, logEntry);
}
}
@@ -224,111 +259,138 @@ export class Processor extends LogReader {
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];
+ processCodeSourceInfo(
+ start, scriptId, startPos, endPos, sourcePositions, inliningPositions,
+ inlinedFunctions) {
+ this._profile.addSourcePositions(
+ start, scriptId, startPos, endPos, sourcePositions, inliningPositions,
+ inlinedFunctions);
+ let profileEntry = this._profile.findEntry(start);
+ if (profileEntry !== this._lastCodeLogEntry._entry) return;
+ this.addSourcePosition(profileEntry, this._lastCodeLogEntry);
+ this._lastCodeLogEntry = undefined;
+ }
+
+ addSourcePosition(profileEntry, logEntry) {
+ let script = this.getProfileEntryScript(profileEntry);
+ const parts = profileEntry.getRawName().split(':');
+ if (parts.length < 3) return;
+ const line = parseInt(parts[parts.length - 2]);
+ const column = parseInt(parts[parts.length - 1]);
+ logEntry.sourcePosition = script.addSourcePosition(line, column, logEntry);
+ }
+
+ processCodeDisassemble(start, kind, disassemble) {
+ this._profile.addDisassemble(start, kind, disassemble);
}
processPropertyIC(
- type, pc, time, line, column, old_state, new_state, map, key, modifier,
+ type, pc, time, line, column, old_state, new_state, mapId, key, modifier,
slow_reason) {
- let fnName = this.functionName(pc);
- let parts = fnName.split(' ');
- let fileName = parts[parts.length - 1];
- let script = this.getScript(fileName);
+ this._lastTimestamp = time;
+ const profileEntry = this._profile.findEntry(pc);
+ const fnName = this.formatProfileEntry(profileEntry);
+ const script = this.getProfileEntryScript(profileEntry);
+ const map = this.getOrCreateMapEntry(mapId, time);
// TODO: Use SourcePosition here directly
let entry = new IcLogEntry(
type, fnName, time, line, column, key, old_state, new_state, map,
- slow_reason, script, modifier);
+ slow_reason, modifier);
if (script) {
entry.sourcePosition = script.addSourcePosition(line, column, entry);
}
this._icTimeline.push(entry);
}
- functionName(pc) {
- let entry = this._profile.findEntry(pc);
- return this.formatName(entry);
- }
- formatPC(pc, line, column) {
- let entry = this._profile.findEntry(pc);
- if (!entry) return '<unknown>'
- if (entry.type === 'Builtin') {
- return entry.name;
- }
- let name = entry.func.getName();
- let array = this._formatPCRegexp.exec(name);
- if (array === null) {
- entry = name;
- } else {
- entry = entry.getState() + array[1];
- }
- return entry + ':' + line + ':' + column;
+ formatProfileEntry(profileEntry, line, column) {
+ if (!profileEntry) return '<unknown>';
+ if (profileEntry.type === 'Builtin') return profileEntry.name;
+ const name = profileEntry.func.getName();
+ const array = this._formatPCRegexp.exec(name);
+ const formatted =
+ (array === null) ? name : profileEntry.getState() + array[1];
+ if (line === undefined || column === undefined) return formatted;
+ return `${formatted}:${line}:${column}`;
}
- processFileName(filePositionLine) {
- if (!filePositionLine.includes(' ')) return;
- // Try to handle urls with file positions: https://foo.bar.com/:17:330"
- filePositionLine = filePositionLine.split(' ');
- let parts = filePositionLine[1].split(':');
- if (parts[0].length <= 5) return parts[0] + ':' + parts[1];
- return parts[1];
+ getProfileEntryScript(profileEntry) {
+ if (!profileEntry) return undefined;
+ if (profileEntry.type === 'Builtin') return undefined;
+ const script = profileEntry.source?.script;
+ if (script !== undefined) return script;
+ // Slow path, try to get the script from the url:
+ const fnName = this.formatProfileEntry(profileEntry);
+ let parts = fnName.split(' ');
+ let fileName = parts[parts.length - 1];
+ return this.getScript(fileName);
}
processMap(type, time, from, to, pc, line, column, reason, name) {
- let time_ = parseInt(time);
+ this._lastTimestamp = time;
+ const time_ = parseInt(time);
if (type === 'Deprecate') return this.deprecateMap(type, time_, from);
- let from_ = this.getExistingMapEntry(from, time_);
- let to_ = this.getExistingMapEntry(to, time_);
+ // Skip normalized maps that were cached so we don't introduce multiple
+ // edges with the same source and target map.
+ if (type === 'NormalizeCached') return;
+ const from_ = this.getOrCreateMapEntry(from, time_);
+ const to_ = this.getOrCreateMapEntry(to, time_);
+ if (type === 'Normalize') {
+ // Fix a bug where we log "Normalize" transitions for maps created from
+ // the NormalizedMapCache.
+ if (to_.parent()?.id === from || to_.time < from_.time || to_.depth > 0) {
+ console.log(`Skipping transition to cached normalized map`);
+ return;
+ }
+ }
// TODO: use SourcePosition directly.
let edge = new Edge(type, name, reason, time, from_, to_);
- to_.filePosition = this.formatPC(pc, line, column);
- let fileName = this.processFileName(to_.filePosition);
- // TODO: avoid undefined source positions.
- if (fileName !== undefined) {
- to_.script = this.getScript(fileName);
+ const profileEntry = this._profile.findEntry(pc)
+ to_.entry = profileEntry;
+ let script = this.getProfileEntryScript(profileEntry);
+ if (script) {
+ to_.sourcePosition = script.addSourcePosition(line, column, to_)
}
- if (to_.script) {
- to_.sourcePosition = to_.script.addSourcePosition(line, column, to_)
+ if (to_.parent() !== undefined && to_.parent() === from_) {
+ // Fix bug where we double log transitions.
+ console.warn('Fixing up double transition');
+ to_.edge.updateFrom(edge);
+ } else {
+ edge.finishSetup();
}
- edge.finishSetup();
}
deprecateMap(type, time, id) {
- this.getExistingMapEntry(id, time).deprecate();
+ this._lastTimestamp = time;
+ this.getOrCreateMapEntry(id, time).deprecate();
}
processMapCreate(time, id) {
// map-create events might override existing maps if the addresses get
// recycled. Hence we do not check for existing maps.
- let map = this.createMapEntry(id, time);
+ this._lastTimestamp = time;
+ this.createMapEntry(id, time);
}
processMapDetails(time, id, string) {
// TODO(cbruni): fix initial map logging.
- let map = this.getExistingMapEntry(id, time);
+ const map = this.getOrCreateMapEntry(id, time);
map.description = string;
}
createMapEntry(id, time) {
- let map = new MapLogEntry(id, time);
+ this._lastTimestamp = time;
+ const map = new MapLogEntry(id, time);
this._mapTimeline.push(map);
return map;
}
- getExistingMapEntry(id, time) {
+ getOrCreateMapEntry(id, time) {
if (id === '0x000000000000') return undefined;
- let map = MapLogEntry.get(id, time);
- if (map === undefined) {
- console.error(`No map details provided: id=${id}`);
- // Manually patch in a map to continue running.
- return this.createMapEntry(id, time);
- };
- return map;
+ const map = MapLogEntry.get(id, time);
+ if (map !== undefined) return map;
+ console.warn(`No map details provided: id=${id}`);
+ // Manually patch in a map to continue running.
+ return this.createMapEntry(id, time);
}
getScript(url) {
@@ -340,6 +402,22 @@ export class Processor extends LogReader {
return script;
}
+ processApiEvent(type, varArgs) {
+ let name, arg1;
+ if (varArgs.length == 0) {
+ const index = type.indexOf(':');
+ if (index > 0) {
+ name = type;
+ type = type.substr(0, index);
+ }
+ } else {
+ name = varArgs[0];
+ arg1 = varArgs[1];
+ }
+ this._apiTimeline.push(
+ new ApiLogEntry(type, this._lastTimestamp, name, arg1));
+ }
+
get icTimeline() {
return this._icTimeline;
}
@@ -352,7 +430,19 @@ export class Processor extends LogReader {
return this._deoptTimeline;
}
+ get codeTimeline() {
+ return this._codeTimeline;
+ }
+
+ get apiTimeline() {
+ return this._apiTimeline;
+ }
+
get scripts() {
return this._profile.scripts_.filter(script => script !== undefined);
}
+
+ get profile() {
+ return this._profile;
+ }
}