Commit 1d7aa2f8 authored by Camillo Bruni's avatar Camillo Bruni Committed by Commit Bot

[tools] Add api events timeline-track to system-analyzer

- Clean up entry selection code
- Add source positions for code and deopt events
- Fix log entry selection from script
- Improve log parsing speed

Bug: v8:10644
Change-Id: Ie466679132b8ce24506ecf75223118b32275f931
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2569756
Commit-Queue: Camillo Bruni <cbruni@chromium.org>
Reviewed-by: 's avatarSathya Gunasekaran  <gsathya@chromium.org>
Cr-Commit-Position: refs/heads/master@{#71624}
parent ddbc2ba4
...@@ -26,6 +26,7 @@ group("v8_mjsunit") { ...@@ -26,6 +26,7 @@ group("v8_mjsunit") {
"../../tools/profile_view.mjs", "../../tools/profile_view.mjs",
"../../tools/splaytree.mjs", "../../tools/splaytree.mjs",
"../../tools/system-analyzer/helper.mjs", "../../tools/system-analyzer/helper.mjs",
"../../tools/system-analyzer/log/api.mjs",
"../../tools/system-analyzer/log/code.mjs", "../../tools/system-analyzer/log/code.mjs",
"../../tools/system-analyzer/log/ic.mjs", "../../tools/system-analyzer/log/ic.mjs",
"../../tools/system-analyzer/log/log.mjs", "../../tools/system-analyzer/log/log.mjs",
......
...@@ -62,7 +62,11 @@ export class CsvParser { ...@@ -62,7 +62,11 @@ export class CsvParser {
} }
// Convert the selected escape sequence to a single character. // Convert the selected escape sequence to a single character.
let escapeChars = string.substring(pos, nextPos); let escapeChars = string.substring(pos, nextPos);
result += String.fromCharCode(parseInt(escapeChars, 16)); if (escapeChars === '2C') {
result += ',';
} else {
result += String.fromCharCode(parseInt(escapeChars, 16));
}
} }
// Continue looking for the next escape sequence. // Continue looking for the next escape sequence.
......
...@@ -47,6 +47,7 @@ export class Script { ...@@ -47,6 +47,7 @@ export class Script {
source; source;
// Map<line, Map<column, SourcePosition>> // Map<line, Map<column, SourcePosition>>
lineToColumn = new Map(); lineToColumn = new Map();
_entries = [];
constructor(id) { constructor(id) {
this.id = id; this.id = id;
...@@ -62,6 +63,10 @@ export class Script { ...@@ -62,6 +63,10 @@ export class Script {
return this.source.length; return this.source.length;
} }
get entries() {
return this._entries;
}
addSourcePosition(line, column, entry) { addSourcePosition(line, column, entry) {
let sourcePosition = this.lineToColumn.get(line)?.get(column); let sourcePosition = this.lineToColumn.get(line)?.get(column);
if (sourcePosition === undefined) { if (sourcePosition === undefined) {
...@@ -69,6 +74,7 @@ export class Script { ...@@ -69,6 +74,7 @@ export class Script {
this._addSourcePosition(line, column, sourcePosition); this._addSourcePosition(line, column, sourcePosition);
} }
sourcePosition.addEntry(entry); sourcePosition.addEntry(entry);
this._entries.push(entry);
return sourcePosition; return sourcePosition;
} }
...@@ -83,10 +89,12 @@ export class Script { ...@@ -83,10 +89,12 @@ export class Script {
this.sourcePositions.push(sourcePosition); this.sourcePositions.push(sourcePosition);
columnToSourcePosition.set(column, sourcePosition); columnToSourcePosition.set(column, sourcePosition);
} }
} }
class SourceInfo{ class SourceInfo {
script; script;
start; start;
end; end;
...@@ -107,6 +115,10 @@ class SourceInfo{ ...@@ -107,6 +115,10 @@ class SourceInfo{
setDisassemble(code) { setDisassemble(code) {
this.disassemble = code; this.disassemble = code;
} }
getSourceCode() {
return this.script.source?.substring(this.start, this.end);
}
} }
/** /**
...@@ -170,7 +182,7 @@ export class Profile { ...@@ -170,7 +182,7 @@ export class Profile {
return this.CodeState.IGNITION; return this.CodeState.IGNITION;
case '-': case '-':
return this.CodeState.NATIVE_CONTEXT_INDEPENDENT; return this.CodeState.NATIVE_CONTEXT_INDEPENDENT;
case '=': case '+':
return this.CodeState.TURBOPROP; return this.CodeState.TURBOPROP;
case '*': case '*':
return this.CodeState.TURBOFAN; return this.CodeState.TURBOFAN;
...@@ -639,9 +651,14 @@ class DynamicFuncCodeEntry extends CodeEntry { ...@@ -639,9 +651,14 @@ class DynamicFuncCodeEntry extends CodeEntry {
constructor(size, type, func, state) { constructor(size, type, func, state) {
super(size, '', type); super(size, '', type);
this.func = func; this.func = func;
func.addDynamicCode(this);
this.state = state; this.state = state;
} }
getSourceCode() {
return this.source?.getSourceCode();
}
static STATE_PREFIX = ["", "~", "-", "+", "*"]; static STATE_PREFIX = ["", "~", "-", "+", "*"];
getState() { getState() {
return DynamicFuncCodeEntry.STATE_PREFIX[this.state]; return DynamicFuncCodeEntry.STATE_PREFIX[this.state];
...@@ -675,10 +692,26 @@ class DynamicFuncCodeEntry extends CodeEntry { ...@@ -675,10 +692,26 @@ class DynamicFuncCodeEntry extends CodeEntry {
* @constructor * @constructor
*/ */
class FunctionEntry extends CodeEntry { class FunctionEntry extends CodeEntry {
// Contains the list of generated code for this function.
_codeEntries = new Set();
constructor(name) { constructor(name) {
super(0, name); super(0, name);
} }
addDynamicCode(code) {
if (code.func != this) {
throw new Error("Adding dynamic code to wrong function");
}
this._codeEntries.add(code);
}
getSourceCode() {
// All code entries should map to the same source positions.
return this._codeEntries.values().next().value.getSourceCode();
}
/** /**
* Returns node name. * Returns node name.
*/ */
......
...@@ -17,6 +17,7 @@ class State { ...@@ -17,6 +17,7 @@ class State {
_mapTimeline; _mapTimeline;
_deoptTimeline; _deoptTimeline;
_codeTimeline; _codeTimeline;
_apiTimeline;
_minStartTime = Number.POSITIVE_INFINITY; _minStartTime = Number.POSITIVE_INFINITY;
_maxEndTime = Number.NEGATIVE_INFINITY; _maxEndTime = Number.NEGATIVE_INFINITY;
...@@ -38,11 +39,13 @@ class State { ...@@ -38,11 +39,13 @@ class State {
} }
} }
setTimelines(mapTimeline, icTimeline, deoptTimeline, codeTimeline) { setTimelines(
mapTimeline, icTimeline, deoptTimeline, codeTimeline, apiTimeline) {
this._mapTimeline = mapTimeline; this._mapTimeline = mapTimeline;
this._icTimeline = icTimeline; this._icTimeline = icTimeline;
this._deoptTimeline = deoptTimeline; this._deoptTimeline = deoptTimeline;
this._codeTimeline = codeTimeline; this._codeTimeline = codeTimeline;
this._apiTimeline = apiTimeline;
for (let timeline of arguments) { for (let timeline of arguments) {
if (timeline === undefined) return; if (timeline === undefined) return;
this._minStartTime = Math.min(this._minStartTime, timeline.startTime); this._minStartTime = Math.min(this._minStartTime, timeline.startTime);
...@@ -70,9 +73,14 @@ class State { ...@@ -70,9 +73,14 @@ class State {
return this._codeTimeline; return this._codeTimeline;
} }
get apiTimeline() {
return this._apiTimeline;
}
get timelines() { get timelines() {
return [ return [
this.mapTimeline, this.icTimeline, this.deoptTimeline, this.codeTimeline this._mapTimeline, this._icTimeline, this._deoptTimeline,
this._codeTimeline, this._apiTimeline
]; ];
} }
......
...@@ -18,9 +18,7 @@ found in the LICENSE file. --> ...@@ -18,9 +18,7 @@ found in the LICENSE file. -->
// Delay loading of the main App // Delay loading of the main App
(async function() { (async function() {
let module = await import('./index.mjs'); let module = await import('./index.mjs');
globalThis.app = new module.App("#log-file-reader", "#map-panel", "#map-stats-panel", globalThis.app = new module.App();
"#timeline-panel", "#ic-panel", "#map-track", "#ic-track", "#deopt-track",
"#code-track", "#source-panel", "#code-panel", "#tool-tip");
})(); })();
</script> </script>
...@@ -104,6 +102,7 @@ found in the LICENSE file. --> ...@@ -104,6 +102,7 @@ found in the LICENSE file. -->
<timeline-track id="ic-track"></timeline-track> <timeline-track id="ic-track"></timeline-track>
<timeline-track id="deopt-track"></timeline-track> <timeline-track id="deopt-track"></timeline-track>
<timeline-track id="code-track"></timeline-track> <timeline-track id="code-track"></timeline-track>
<timeline-track id="api-track"></timeline-track>
</timeline-panel> </timeline-panel>
<div class="panels"> <div class="panels">
<map-panel id="map-panel"></map-panel> <map-panel id="map-panel"></map-panel>
...@@ -159,16 +158,17 @@ found in the LICENSE file. --> ...@@ -159,16 +158,17 @@ found in the LICENSE file. -->
<code>--trace-maps</code> <code>--trace-maps</code>
</a> </a>
</dt> </dt>
<dd>Log<a href="https://v8.dev/blog/fast-properties" target="_blank"> <dd>
Maps</a></dd> Log<a href="https://v8.dev/blog/fast-properties">Maps</a>
</dd>
<dt> <dt>
<a href="https://source.chromium.org/search?q=FLAG_trace_ic"> <a href="https://source.chromium.org/search?q=FLAG_trace_ic">
<code>--trace-ic</code> <code>--trace-ic</code>
</a> </a>
</dt> </dt>
<dd>Log <dd>
<a href="https://mathiasbynens.be/notes/shapes-ics" target="_blank"> Log <a href="https://mathiasbynens.be/notes/shapes-ics">ICs</a>
ICs</a></dd> </dd>
<dt> <dt>
<a href="https://source.chromium.org/search?q=FLAG_log_source_code"> <a href="https://source.chromium.org/search?q=FLAG_log_source_code">
<code>--log-source-code</code> <code>--log-source-code</code>
...@@ -181,6 +181,12 @@ found in the LICENSE file. --> ...@@ -181,6 +181,12 @@ found in the LICENSE file. -->
</a> </a>
</dt> </dt>
<dd>Log detailed generated generated code</dd> <dd>Log detailed generated generated code</dd>
<dt>
<a href="https://source.chromium.org/search?q=FLAG_log_api">
<code>--log-api</code>
</a>
</dt>
<dd>Log various API uses.</dd>
</dl> </dl>
<h3>Keyboard Shortcuts for Navigation</h3> <h3>Keyboard Shortcuts for Navigation</h3>
......
...@@ -5,6 +5,8 @@ ...@@ -5,6 +5,8 @@
import {SourcePosition} from '../profile.mjs'; import {SourcePosition} from '../profile.mjs';
import {State} from './app-model.mjs'; import {State} from './app-model.mjs';
import {ApiLogEntry} from './log/api.mjs';
import {DeoptLogEntry} from './log/code.mjs';
import {CodeLogEntry} from './log/code.mjs'; import {CodeLogEntry} from './log/code.mjs';
import {IcLogEntry} from './log/ic.mjs'; import {IcLogEntry} from './log/ic.mjs';
import {MapLogEntry} from './log/map.mjs'; import {MapLogEntry} from './log/map.mjs';
...@@ -17,24 +19,22 @@ class App { ...@@ -17,24 +19,22 @@ class App {
_view; _view;
_navigation; _navigation;
_startupPromise; _startupPromise;
constructor( constructor() {
fileReaderId, mapPanelId, mapStatsPanelId, timelinePanelId, icPanelId,
mapTrackId, icTrackId, deoptTrackId, codeTrackId, sourcePanelId,
codePanelId, toolTipId) {
this._view = { this._view = {
__proto__: null, __proto__: null,
logFileReader: $(fileReaderId), logFileReader: $('#log-file-reader'),
icPanel: $(icPanelId), mapPanel: $('#map-panel'),
mapPanel: $(mapPanelId), mapStatsPanel: $('#map-stats-panel'),
mapStatsPanel: $(mapStatsPanelId), timelinePanel: $('#timeline-panel'),
timelinePanel: $(timelinePanelId), mapTrack: $('#map-track'),
mapTrack: $(mapTrackId), icTrack: $('#ic-track'),
icTrack: $(icTrackId), icPanel: $('#ic-panel'),
deoptTrack: $(deoptTrackId), deoptTrack: $('#deopt-track'),
codeTrack: $(codeTrackId), codePanel: $('#code-panel'),
sourcePanel: $(sourcePanelId), codeTrack: $('#code-track'),
codePanel: $(codePanelId), apiTrack: $('#api-track'),
toolTip: $(toolTipId), sourcePanel: $('#source-panel'),
toolTip: $('#tool-tip'),
}; };
this.toggleSwitch = $('.theme-switch input[type="checkbox"]'); this.toggleSwitch = $('.theme-switch input[type="checkbox"]');
this.toggleSwitch.addEventListener('change', (e) => this.switchTheme(e)); this.toggleSwitch.addEventListener('change', (e) => this.switchTheme(e));
...@@ -67,19 +67,61 @@ class App { ...@@ -67,19 +67,61 @@ class App {
} }
handleShowEntries(e) { handleShowEntries(e) {
const entry = e.entries[0]; e.stopPropagation();
if (entry instanceof MapLogEntry) { this.showEntries(e.entries);
this.showMapEntries(e.entries); }
} else if (entry instanceof IcLogEntry) {
this.showIcEntries(e.entries); showEntries(entries) {
} else if (entry instanceof SourcePosition) { const groups = new Map();
this.showSourcePositionEntries(e.entries); for (let entry of entries) {
} else if (e.entries[0] instanceof CodeLogEntry) { const group = groups.get(entry.constructor);
this.showCodeEntries(e.entries); if (group !== undefined) {
} else { group.push(entry);
throw new Error('Unknown selection type!'); } else {
groups.set(entry.constructor, [entry]);
}
}
groups.forEach(entries => this.showEntriesOfSingleType(entries));
}
showEntriesOfSingleType(entries) {
switch (entries[0].constructor) {
case SourcePosition:
return this.showSourcePositions(entries);
case MapLogEntry:
return this.showMapEntries(entries);
case IcLogEntry:
return this.showIcEntries(entries);
case ApiLogEntry:
return this.showApiEntries(entries);
case CodeLogEntry:
return this.showCodeEntries(entries);
case DeoptLogEntry:
return this.showDeoptEntries(entries);
default:
throw new Error('Unknown selection type!');
} }
}
handleShowEntryDetail(e) {
e.stopPropagation(); e.stopPropagation();
const entry = e.entry;
switch (entry.constructor) {
case SourcePosition:
return this.selectSourcePosition(entry);
case MapLogEntry:
return this.selectMapLogEntry(entry);
case IcLogEntry:
return this.selectIcLogEntry(entry);
case ApiLogEntry:
return this.selectApiLogEntry(entry);
case CodeLogEntry:
return this.selectCodeLogEntry(entry);
case DeoptLogEntry:
return this.selectDeoptLogEntry(entry);
default:
throw new Error('Unknown selection type!');
}
} }
showMapEntries(entries) { showMapEntries(entries) {
...@@ -94,17 +136,22 @@ class App { ...@@ -94,17 +136,22 @@ class App {
} }
showDeoptEntries(entries) { showDeoptEntries(entries) {
// TODO: creat list panel. // TODO: create list panel.
this._state.selectedDeoptLogEntries = entries; this._state.selectedDeoptLogEntries = entries;
} }
showCodeEntries(entries) { showCodeEntries(entries) {
// TODO: creat list panel // TODO: create list panel
this._state.selectedCodeLogEntries = entries; this._state.selectedCodeLogEntries = entries;
this._view.codePanel.selectedEntries = entries; this._view.codePanel.selectedEntries = entries;
} }
showSourcePositionEntries(entries) { showApiEntries(entries) {
// TODO: create list panel
this._state.selectedApiLogEntries = entries;
}
showSourcePositions(entries) {
// TODO: Handle multiple source position selection events // TODO: Handle multiple source position selection events
this._view.sourcePanel.selectedSourcePositions = entries this._view.sourcePanel.selectedSourcePositions = entries
} }
...@@ -120,32 +167,17 @@ class App { ...@@ -120,32 +167,17 @@ class App {
this.showIcEntries(this._state.icTimeline.selection ?? []); this.showIcEntries(this._state.icTimeline.selection ?? []);
this.showDeoptEntries(this._state.deoptTimeline.selection ?? []); this.showDeoptEntries(this._state.deoptTimeline.selection ?? []);
this.showCodeEntries(this._state.codeTimeline.selection ?? []); this.showCodeEntries(this._state.codeTimeline.selection ?? []);
this.showApiEntries(this._state.apiTimeline.selection ?? []);
this._view.timelinePanel.timeSelection = {start, end}; this._view.timelinePanel.timeSelection = {start, end};
} }
handleShowEntryDetail(e) {
const entry = e.entry;
if (entry instanceof MapLogEntry) {
this.selectMapLogEntry(e.entry);
} else if (entry instanceof IcLogEntry) {
this.selectICLogEntry(e.entry);
} else if (entry instanceof SourcePosition) {
this.selectSourcePosition(e.entry);
} else if (e.entry instanceof CodeLogEntry) {
this.selectCodeLogEntry(e.entry);
} else {
throw new Error('Unknown selection type!');
}
e.stopPropagation();
}
selectMapLogEntry(entry) { selectMapLogEntry(entry) {
this._state.map = entry; this._state.map = entry;
this._view.mapTrack.selectedEntry = entry; this._view.mapTrack.selectedEntry = entry;
this._view.mapPanel.map = entry; this._view.mapPanel.map = entry;
} }
selectICLogEntry(entry) { selectIcLogEntry(entry) {
this._state.ic = entry; this._state.ic = entry;
this._view.icPanel.selectedEntry = [entry]; this._view.icPanel.selectedEntry = [entry];
} }
...@@ -155,6 +187,15 @@ class App { ...@@ -155,6 +187,15 @@ class App {
this._view.codePanel.entry = entry; this._view.codePanel.entry = entry;
} }
selectDeoptLogEntry(entry) {
// TODO
}
selectApiLogEntry(entry) {
this._state.apiLogEntry = entry;
this._view.apiTrack.selectedEntry = entry;
}
selectSourcePosition(sourcePositions) { selectSourcePosition(sourcePositions) {
if (!sourcePositions.script) return; if (!sourcePositions.script) return;
this._view.sourcePanel.selectedSourcePositions = [sourcePositions]; this._view.sourcePanel.selectedSourcePositions = [sourcePositions];
...@@ -183,8 +224,9 @@ class App { ...@@ -183,8 +224,9 @@ class App {
const icTimeline = processor.icTimeline; const icTimeline = processor.icTimeline;
const deoptTimeline = processor.deoptTimeline; const deoptTimeline = processor.deoptTimeline;
const codeTimeline = processor.codeTimeline; const codeTimeline = processor.codeTimeline;
const apiTimeline = processor.apiTimeline;
this._state.setTimelines( this._state.setTimelines(
mapTimeline, icTimeline, deoptTimeline, codeTimeline); mapTimeline, icTimeline, deoptTimeline, codeTimeline, apiTimeline);
// Transitions must be set before timeline for stats panel. // Transitions must be set before timeline for stats panel.
this._view.mapPanel.timeline = mapTimeline; this._view.mapPanel.timeline = mapTimeline;
this._view.mapStatsPanel.transitions = this._view.mapStatsPanel.transitions =
...@@ -208,6 +250,7 @@ class App { ...@@ -208,6 +250,7 @@ class App {
this._view.icTrack.data = this._state.icTimeline; this._view.icTrack.data = this._state.icTimeline;
this._view.deoptTrack.data = this._state.deoptTimeline; this._view.deoptTrack.data = this._state.deoptTimeline;
this._view.codeTrack.data = this._state.codeTimeline; this._view.codeTrack.data = this._state.codeTimeline;
this._view.apiTrack.data = this._state.apiTimeline;
} }
switchTheme(event) { switchTheme(event) {
......
// 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.
import {LogEntry} from './log.mjs';
export class ApiLogEntry extends LogEntry {
constructor(type, time, name) {
super(type, time);
this._name = name;
}
toString() {
return `Api(${this.type}): ${this._name}`;
}
}
...@@ -14,7 +14,7 @@ export class IcLogEntry extends LogEntry { ...@@ -14,7 +14,7 @@ export class IcLogEntry extends LogEntry {
} else if (this.type.indexOf('Load') !== -1) { } else if (this.type.indexOf('Load') !== -1) {
this.category = 'Load'; this.category = 'Load';
} }
let parts = fn_file.split(' '); const parts = fn_file.split(' ');
this.functionName = parts[0]; this.functionName = parts[0];
this.file = parts[1]; this.file = parts[1];
let position = line + ':' + column; let position = line + ':' + column;
......
...@@ -3,19 +3,20 @@ ...@@ -3,19 +3,20 @@
// found in the LICENSE file. // found in the LICENSE file.
export class LogEntry { export class LogEntry {
_time;
_type;
constructor(type, time) { constructor(type, time) {
// TODO(zcankara) remove type and add empty getters to override
this._time = time; this._time = time;
this._type = type; this._type = type;
this.sourcePosition = undefined;
} }
get time() { get time() {
return this._time; return this._time;
} }
get type() { get type() {
return this._type; return this._type;
} }
// Returns an Array of all possible #type values. // Returns an Array of all possible #type values.
static get allTypes() { static get allTypes() {
throw new Error('Not implemented.'); throw new Error('Not implemented.');
......
...@@ -34,17 +34,6 @@ define(Array.prototype, 'last', function() { ...@@ -34,17 +34,6 @@ define(Array.prototype, 'last', function() {
// Map Log Events // Map Log Events
class MapLogEntry extends LogEntry { class MapLogEntry extends LogEntry {
id = -1;
edge = undefined;
children = [];
depth = 0;
_isDeprecated = false;
deprecatedTargets = null;
leftId = 0;
rightId = 0;
filePosition = '';
script = '';
description = '';
constructor(id, time) { constructor(id, time) {
if (!time) throw new Error('Invalid time'); if (!time) throw new Error('Invalid time');
// Use MapLogEntry.type getter instead of property, since we only know the // Use MapLogEntry.type getter instead of property, since we only know the
...@@ -52,6 +41,17 @@ class MapLogEntry extends LogEntry { ...@@ -52,6 +41,17 @@ class MapLogEntry extends LogEntry {
super(undefined, time); super(undefined, time);
this.id = id; this.id = id;
MapLogEntry.set(id, this); MapLogEntry.set(id, this);
this.id = -1;
this.edge = undefined;
this.children = [];
this.depth = 0;
this._isDeprecated = false;
this.deprecatedTargets = null;
this.leftId = 0;
this.rightId = 0;
this.filePosition = '';
this.script = '';
this.description = '';
} }
toString() { toString() {
......
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
import {LogReader, parseString, parseVarArgs} from '../logreader.mjs'; import {LogReader, parseString, parseVarArgs} from '../logreader.mjs';
import {Profile} from '../profile.mjs'; import {Profile} from '../profile.mjs';
import {ApiLogEntry} from './log/api.mjs';
import {CodeLogEntry, DeoptLogEntry} from './log/code.mjs'; import {CodeLogEntry, DeoptLogEntry} from './log/code.mjs';
import {IcLogEntry} from './log/ic.mjs'; import {IcLogEntry} from './log/ic.mjs';
import {Edge, MapLogEntry} from './log/map.mjs'; import {Edge, MapLogEntry} from './log/map.mjs';
...@@ -18,7 +19,10 @@ export class Processor extends LogReader { ...@@ -18,7 +19,10 @@ export class Processor extends LogReader {
_icTimeline = new Timeline(); _icTimeline = new Timeline();
_deoptTimeline = new Timeline(); _deoptTimeline = new Timeline();
_codeTimeline = new Timeline(); _codeTimeline = new Timeline();
_apiTimeline = new Timeline();
_formatPCRegexp = /(.*):[0-9]+:[0-9]+$/; _formatPCRegexp = /(.*):[0-9]+:[0-9]+$/;
_lastTimestamp = 0;
_lastCodeLogEntry;
MAJOR_VERSION = 7; MAJOR_VERSION = 7;
MINOR_VERSION = 6; MINOR_VERSION = 6;
constructor(logString) { constructor(logString) {
...@@ -115,6 +119,10 @@ export class Processor extends LogReader { ...@@ -115,6 +119,10 @@ export class Processor extends LogReader {
parsers: propertyICParser, parsers: propertyICParser,
processor: this.processPropertyIC.bind(this, 'StoreInArrayLiteralIC') processor: this.processPropertyIC.bind(this, 'StoreInArrayLiteralIC')
}, },
'api': {
parsers: [parseString, parseVarArgs],
processor: this.processApiEvent
},
}; };
if (logString) this.processString(logString); if (logString) this.processString(logString);
} }
...@@ -182,7 +190,21 @@ export class Processor extends LogReader { ...@@ -182,7 +190,21 @@ export class Processor extends LogReader {
}); });
} }
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.`);
}
}
processCodeCreation(type, kind, timestamp, start, size, name, maybe_func) { processCodeCreation(type, kind, timestamp, start, size, name, maybe_func) {
this._lastTimestamp = timestamp;
if (timestamp == 5724567) {
console.log(start);
}
let entry; let entry;
let stateName = ''; let stateName = '';
if (maybe_func.length) { if (maybe_func.length) {
...@@ -194,26 +216,20 @@ export class Processor extends LogReader { ...@@ -194,26 +216,20 @@ export class Processor extends LogReader {
} else { } else {
entry = this._profile.addCode(type, name, timestamp, start, size); entry = this._profile.addCode(type, name, timestamp, start, size);
} }
this._codeTimeline.push( this._lastCodeLogEntry =
new CodeLogEntry(type + stateName, timestamp, kind, entry)); new CodeLogEntry(type + stateName, timestamp, kind, entry);
this._codeTimeline.push(this._lastCodeLogEntry);
} }
processCodeDeopt( processCodeDeopt(
timestamp, codeSize, instructionStart, inliningId, scriptOffset, timestamp, codeSize, instructionStart, inliningId, scriptOffset,
deoptKind, deoptLocation, deoptReason) { deoptKind, deoptLocation, deoptReason) {
this._deoptTimeline.push(new DeoptLogEntry( this._lastTimestamp = timestamp;
const logEntry = new DeoptLogEntry(
deoptKind, timestamp, deoptReason, deoptLocation, scriptOffset, deoptKind, timestamp, deoptReason, deoptLocation, scriptOffset,
instructionStart, codeSize, inliningId)); instructionStart, codeSize, inliningId);
} this._deoptTimeline.push(logEntry);
this.addSourcePosition(this._profile.findEntry(instructionStart), logEntry);
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.`);
}
} }
processScriptSource(scriptId, url, source) { processScriptSource(scriptId, url, source) {
...@@ -233,11 +249,24 @@ export class Processor extends LogReader { ...@@ -233,11 +249,24 @@ export class Processor extends LogReader {
} }
processCodeSourceInfo( processCodeSourceInfo(
start, script, startPos, endPos, sourcePositions, inliningPositions, start, scriptId, startPos, endPos, sourcePositions, inliningPositions,
inlinedFunctions) { inlinedFunctions) {
this._profile.addSourcePositions( this._profile.addSourcePositions(
start, script, startPos, endPos, sourcePositions, inliningPositions, start, scriptId, startPos, endPos, sourcePositions, inliningPositions,
inlinedFunctions); 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) { processCodeDisassemble(start, kind, disassemble) {
...@@ -247,6 +276,7 @@ export class Processor extends LogReader { ...@@ -247,6 +276,7 @@ export class Processor extends LogReader {
processPropertyIC( processPropertyIC(
type, pc, time, line, column, old_state, new_state, map, key, modifier, type, pc, time, line, column, old_state, new_state, map, key, modifier,
slow_reason) { slow_reason) {
this._lastTimestamp = time;
let profileEntry = this._profile.findEntry(pc); let profileEntry = this._profile.findEntry(pc);
let fnName = this.formatProfileEntry(profileEntry); let fnName = this.formatProfileEntry(profileEntry);
let script = this.getProfileEntryScript(profileEntry); let script = this.getProfileEntryScript(profileEntry);
...@@ -284,6 +314,7 @@ export class Processor extends LogReader { ...@@ -284,6 +314,7 @@ export class Processor extends LogReader {
} }
processMap(type, time, from, to, pc, line, column, reason, name) { processMap(type, time, from, to, pc, line, column, reason, name) {
this._lastTimestamp = time;
const time_ = parseInt(time); const time_ = parseInt(time);
if (type === 'Deprecate') return this.deprecateMap(type, time_, from); if (type === 'Deprecate') return this.deprecateMap(type, time_, from);
// Skip normalized maps that were cached so we don't introduce multiple // Skip normalized maps that were cached so we don't introduce multiple
...@@ -318,12 +349,14 @@ export class Processor extends LogReader { ...@@ -318,12 +349,14 @@ export class Processor extends LogReader {
} }
deprecateMap(type, time, id) { deprecateMap(type, time, id) {
this._lastTimestamp = time;
this.getMapEntry(id, time).deprecate(); this.getMapEntry(id, time).deprecate();
} }
processMapCreate(time, id) { processMapCreate(time, id) {
// map-create events might override existing maps if the addresses get // map-create events might override existing maps if the addresses get
// recycled. Hence we do not check for existing maps. // recycled. Hence we do not check for existing maps.
this._lastTimestamp = time;
this.createMapEntry(id, time); this.createMapEntry(id, time);
} }
...@@ -334,6 +367,7 @@ export class Processor extends LogReader { ...@@ -334,6 +367,7 @@ export class Processor extends LogReader {
} }
createMapEntry(id, time) { createMapEntry(id, time) {
this._lastTimestamp = time;
const map = new MapLogEntry(id, time); const map = new MapLogEntry(id, time);
this._mapTimeline.push(map); this._mapTimeline.push(map);
return map; return map;
...@@ -357,6 +391,16 @@ export class Processor extends LogReader { ...@@ -357,6 +391,16 @@ export class Processor extends LogReader {
return script; return script;
} }
processApiEvent(name, varArgs) {
if (varArgs.length == 0) {
varArgs = [name];
const index = name.indexOf(':');
if (index > 0) name = name.substr(0, index);
}
this._apiTimeline.push(
new ApiLogEntry(name, this._lastTimestamp, varArgs[0]));
}
get icTimeline() { get icTimeline() {
return this._icTimeline; return this._icTimeline;
} }
...@@ -373,6 +417,10 @@ export class Processor extends LogReader { ...@@ -373,6 +417,10 @@ export class Processor extends LogReader {
return this._codeTimeline; return this._codeTimeline;
} }
get apiTimeline() {
return this._apiTimeline;
}
get scripts() { get scripts() {
return this._profile.scripts_.filter(script => script !== undefined); return this._profile.scripts_.filter(script => script !== undefined);
} }
......
...@@ -25,6 +25,8 @@ DOM.defineCustomElement( ...@@ -25,6 +25,8 @@ DOM.defineCustomElement(
set selectedEntries(entries) { set selectedEntries(entries) {
this._selectedEntries = entries; this._selectedEntries = entries;
// TODO: add code selection dropdown
this._entry = entries.first();
this.update(); this.update();
} }
......
...@@ -105,7 +105,7 @@ DOM.defineCustomElement('view/source-panel', ...@@ -105,7 +105,7 @@ DOM.defineCustomElement('view/source-panel',
const option = const option =
this.scriptDropdown.options[this.scriptDropdown.selectedIndex]; this.scriptDropdown.options[this.scriptDropdown.selectedIndex];
this.script = option.script; this.script = option.script;
this.selectLogEntries(this._script.entries()); this.selectLogEntries(this._script.entries);
} }
handleSourcePositionClick(e) { handleSourcePositionClick(e) {
...@@ -124,21 +124,7 @@ DOM.defineCustomElement('view/source-panel', ...@@ -124,21 +124,7 @@ DOM.defineCustomElement('view/source-panel',
} }
selectLogEntries(logEntries) { selectLogEntries(logEntries) {
let icLogEntries = []; this.dispatchEvent(new SelectionEvent(logEntries));
let mapLogEntries = [];
for (const entry of logEntries) {
if (entry instanceof MapLogEntry) {
mapLogEntries.push(entry);
} else if (entry instanceof IcLogEntry) {
icLogEntries.push(entry);
}
}
if (icLogEntries.length > 0) {
this.dispatchEvent(new SelectionEvent(icLogEntries));
}
if (mapLogEntries.length > 0) {
this.dispatchEvent(new SelectionEvent(mapLogEntries));
}
} }
}); });
......
...@@ -4,6 +4,11 @@ found in the LICENSE file. --> ...@@ -4,6 +4,11 @@ found in the LICENSE file. -->
<head> <head>
<link href="./index.css" rel="stylesheet"> <link href="./index.css" rel="stylesheet">
<style>
.panel {
padding-bottom: 0px;
}
</style>
</head> </head>
<div class="panel"> <div class="panel">
<h2>Timeline Panel</h2> <h2>Timeline Panel</h2>
......
...@@ -63,36 +63,40 @@ found in the LICENSE file. --> ...@@ -63,36 +63,40 @@ found in the LICENSE file. -->
font-size: 10px; font-size: 10px;
} }
#legend { .legend {
position: relative; position: relative;
float: right; float: right;
width: 100%; height: calc(200px + 12px);
max-width: 280px; overflow-y: scroll;
padding-left: 20px; margin-right: -10px;
padding-top: 10px; padding-right: 2px;
}
#legendTable {
width: 280px;
border-collapse: collapse; border-collapse: collapse;
} }
th, th,
td { td {
width: 200px; padding: 1px 3px 2px 3px;
text-align: left;
padding-bottom: 3px;
} }
/* right align numbers */
#legend td:nth-of-type(4n+3),
#legend td:nth-of-type(4n+4) {
text-align: right;
}
/* Center colors */ /* Center colors */
#legend td:nth-of-type(4n+1) { #legendTable td:nth-of-type(4n+1) {
text-align: center;; text-align: center;
padding-top: 3px;
} }
/* Left align text*/
.legendTypeColumn { #legendTable td:nth-of-type(4n+2) {
text-align: left;
width: 100%; width: 100%;
} }
/* right align numbers */
#legendTable td:nth-of-type(4n+3),
#legendTable td:nth-of-type(4n+4) {
text-align: right;
}
.timeline { .timeline {
background-color: var(--timeline-background-color); background-color: var(--timeline-background-color);
...@@ -120,17 +124,18 @@ found in the LICENSE file. --> ...@@ -120,17 +124,18 @@ found in the LICENSE file. -->
position: absolute; position: absolute;
} }
</style> </style>
<table id="legend" class="typeStatsTable"> <div class="legend">
<thead> <table id="legendTable">
<tr> <thead>
<td></td> <tr>
<td>Type</td> <td>Type</td>
<td>Count</td> <td>Count</td>
<td>Percent</td> <td>Percent</td>
</tr> </tr>
</thead> </thead>
<tbody></tbody> <tbody></tbody>
</table> </table>
</div>
<div id="timeline"> <div id="timeline">
<div id="selection"> <div id="selection">
<div id="leftHandle"></div> <div id="leftHandle"></div>
......
...@@ -25,7 +25,7 @@ DOM.defineCustomElement('view/timeline/timeline-track', ...@@ -25,7 +25,7 @@ DOM.defineCustomElement('view/timeline/timeline-track',
constructor() { constructor() {
super(templateText); super(templateText);
this._selectionHandler = new SelectionHandler(this); this._selectionHandler = new SelectionHandler(this);
this._legend = new Legend(this.$('#legend')); this._legend = new Legend(this.$('#legendTable'));
this._legend.onFilter = (type) => this._handleFilterTimeline(); this._legend.onFilter = (type) => this._handleFilterTimeline();
this.timelineNode.addEventListener( this.timelineNode.addEventListener(
'scroll', e => this._handleTimelineScroll(e)); 'scroll', e => this._handleTimelineScroll(e));
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment