Commit 79896eeb authored by Camillo Bruni's avatar Camillo Bruni Committed by Commit Bot

[tools] Add code-creation timeline track to system-analyzer

Drive-by-fix:
- better handle tooltip text

Bug: v8:10644
Change-Id: Ibe20a1e0a0ebd298855afcbdc6f28e6fa4d1e64e
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2563660
Commit-Queue: Camillo Bruni <cbruni@chromium.org>
Reviewed-by: 's avatarSathya Gunasekaran  <gsathya@chromium.org>
Cr-Commit-Position: refs/heads/master@{#71479}
parent f5950e25
...@@ -26,7 +26,7 @@ group("v8_mjsunit") { ...@@ -26,7 +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/deopt.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",
"../../tools/system-analyzer/log/map.mjs", "../../tools/system-analyzer/log/map.mjs",
......
...@@ -232,7 +232,7 @@ export class Profile { ...@@ -232,7 +232,7 @@ export class Profile {
} }
} }
deoptCode( timestamp, code, inliningId, scriptOffset, bailoutType, deoptCode(timestamp, code, inliningId, scriptOffset, bailoutType,
sourcePositionText, deoptReasonText) { sourcePositionText, deoptReasonText) {
} }
......
...@@ -9,17 +9,21 @@ class State { ...@@ -9,17 +9,21 @@ class State {
_selectedMapLogEntries; _selectedMapLogEntries;
_selectedIcLogEntries; _selectedIcLogEntries;
_selectedDeoptLogEntries; _selectedDeoptLogEntries;
_selecteCodeLogEntries;
_selectedSourcePositions; _selectedSourcePositions;
_nofChunks; _nofChunks;
_chunks; _chunks;
_icTimeline; _icTimeline;
_mapTimeline; _mapTimeline;
_deoptTimeline; _deoptTimeline;
_codeTimeline;
_minStartTime = Number.POSITIVE_INFINITY; _minStartTime = Number.POSITIVE_INFINITY;
_maxEndTime = Number.NEGATIVE_INFINITY; _maxEndTime = Number.NEGATIVE_INFINITY;
get minStartTime() { get minStartTime() {
return this._minStartTime; return this._minStartTime;
} }
get maxEndTime() { get maxEndTime() {
return this._maxEndTime; return this._maxEndTime;
} }
...@@ -30,15 +34,20 @@ class State { ...@@ -30,15 +34,20 @@ class State {
this._icTimeline.selectTimeRange(start, end); this._icTimeline.selectTimeRange(start, end);
this._mapTimeline.selectTimeRange(start, end); this._mapTimeline.selectTimeRange(start, end);
this._deoptTimeline.selectTimeRange(start, end); this._deoptTimeline.selectTimeRange(start, end);
this._codeTimeline.selectTimeRange(start, end);
} }
_updateTimeRange() { setTimelines(mapTimeline, icTimeline, deoptTimeline, codeTimeline) {
for (let timeline of this.timelines) { this._mapTimeline = mapTimeline;
this._icTimeline = icTimeline;
this._deoptTimeline = deoptTimeline;
this._codeTimeline = codeTimeline;
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);
this._maxEndTime = Math.max(this._maxEndTime, timeline.endTime); this._maxEndTime = Math.max(this._maxEndTime, timeline.endTime);
} }
for (let timeline of this.timelines) { for (let timeline of arguments) {
timeline.startTime = this._minStartTime; timeline.startTime = this._minStartTime;
timeline.endTime = this._maxEndTime; timeline.endTime = this._maxEndTime;
} }
...@@ -47,37 +56,35 @@ class State { ...@@ -47,37 +56,35 @@ class State {
get mapTimeline() { get mapTimeline() {
return this._mapTimeline; return this._mapTimeline;
} }
set mapTimeline(timeline) {
this._mapTimeline = timeline;
this._updateTimeRange();
}
get icTimeline() { get icTimeline() {
return this._icTimeline; return this._icTimeline;
} }
set icTimeline(timeline) {
this._icTimeline = timeline;
this._updateTimeRange();
}
get deoptTimeline() { get deoptTimeline() {
return this._deoptTimeline; return this._deoptTimeline;
} }
set deoptTimeline(timeline) {
this._deoptTimeline = timeline; get codeTimeline() {
this._updateTimeRange(); return this._codeTimeline;
} }
get timelines() { get timelines() {
return [this.mapTimeline, this.icTimeline, this.deoptTimeline]; return [
this.mapTimeline, this.icTimeline, this.deoptTimeline, this.codeTimeline
];
} }
set chunks(value) { set chunks(value) {
// TODO(zcankara) split up between maps and ics, and every timeline track // TODO(zcankara) split up between maps and ics, and every timeline track
this._chunks = value; this._chunks = value;
} }
get chunks() { get chunks() {
// TODO(zcankara) split up between maps and ics, and every timeline track // TODO(zcankara) split up between maps and ics, and every timeline track
return this._chunks; return this._chunks;
} }
get nofChunks() { get nofChunks() {
return this._nofChunks; return this._nofChunks;
} }
......
...@@ -20,7 +20,7 @@ found in the LICENSE file. --> ...@@ -20,7 +20,7 @@ found in the LICENSE file. -->
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("#log-file-reader", "#map-panel", "#map-stats-panel",
"#timeline-panel", "#ic-panel", "#map-track", "#ic-track", "#deopt-track", "#timeline-panel", "#ic-panel", "#map-track", "#ic-track", "#deopt-track",
"#source-panel", "#tool-tip"); "#code-track", "#source-panel", "#tool-tip");
})(); })();
</script> </script>
...@@ -103,6 +103,7 @@ found in the LICENSE file. --> ...@@ -103,6 +103,7 @@ found in the LICENSE file. -->
<timeline-track id="map-track"></timeline-track> <timeline-track id="map-track"></timeline-track>
<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-panel> </timeline-panel>
<div class="panels"> <div class="panels">
<map-panel id="map-panel"></map-panel> <map-panel id="map-panel"></map-panel>
......
...@@ -18,7 +18,8 @@ class App { ...@@ -18,7 +18,8 @@ class App {
_startupPromise; _startupPromise;
constructor( constructor(
fileReaderId, mapPanelId, mapStatsPanelId, timelinePanelId, icPanelId, fileReaderId, mapPanelId, mapStatsPanelId, timelinePanelId, icPanelId,
mapTrackId, icTrackId, deoptTrackId, sourcePanelId, toolTipId) { mapTrackId, icTrackId, deoptTrackId, codeTrackId, sourcePanelId,
toolTipId) {
this._view = { this._view = {
__proto__: null, __proto__: null,
logFileReader: $(fileReaderId), logFileReader: $(fileReaderId),
...@@ -29,6 +30,7 @@ class App { ...@@ -29,6 +30,7 @@ class App {
mapTrack: $(mapTrackId), mapTrack: $(mapTrackId),
icTrack: $(icTrackId), icTrack: $(icTrackId),
deoptTrack: $(deoptTrackId), deoptTrack: $(deoptTrackId),
codeTrack: $(codeTrackId),
sourcePanel: $(sourcePanelId), sourcePanel: $(sourcePanelId),
toolTip: $(toolTipId), toolTip: $(toolTipId),
}; };
...@@ -73,18 +75,28 @@ class App { ...@@ -73,18 +75,28 @@ class App {
} }
e.stopPropagation(); e.stopPropagation();
} }
showMapEntries(entries) { showMapEntries(entries) {
this._state.selectedMapLogEntries = entries; this._state.selectedMapLogEntries = entries;
this._view.mapPanel.selectedMapLogEntries = entries; this._view.mapPanel.selectedMapLogEntries = entries;
this._view.mapStatsPanel.selectedLogEntries = entries; this._view.mapStatsPanel.selectedLogEntries = entries;
} }
showIcEntries(entries) { showIcEntries(entries) {
this._state.selectedIcLogEntries = entries; this._state.selectedIcLogEntries = entries;
this._view.icPanel.selectedLogEntries = entries; this._view.icPanel.selectedLogEntries = entries;
} }
showDeoptEntries(entries) { showDeoptEntries(entries) {
// TODO: creat list panel.
this._state.selectedDeoptLogEntries = entries; this._state.selectedDeoptLogEntries = entries;
} }
showCodeEntries(entries) {
// TODO: creat list panel
this._state.selectedCodeLogEntries = entries;
}
showSourcePositionEntries(entries) { showSourcePositionEntries(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
...@@ -100,6 +112,7 @@ class App { ...@@ -100,6 +112,7 @@ class App {
this.showMapEntries(this._state.mapTimeline.selection); this.showMapEntries(this._state.mapTimeline.selection);
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._view.timelinePanel.timeSelection = {start, end}; this._view.timelinePanel.timeSelection = {start, end};
} }
...@@ -115,15 +128,18 @@ class App { ...@@ -115,15 +128,18 @@ class App {
} }
e.stopPropagation(); 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.selectedLogEntries = [entry]; this._view.icPanel.selectedLogEntries = [entry];
} }
selectSourcePosition(sourcePositions) { selectSourcePosition(sourcePositions) {
if (!sourcePositions.script) return; if (!sourcePositions.script) return;
this._view.sourcePanel.selectedSourcePositions = [sourcePositions]; this._view.sourcePanel.selectedSourcePositions = [sourcePositions];
...@@ -151,19 +167,17 @@ class App { ...@@ -151,19 +167,17 @@ class App {
const mapTimeline = processor.mapTimeline; const mapTimeline = processor.mapTimeline;
const icTimeline = processor.icTimeline; const icTimeline = processor.icTimeline;
const deoptTimeline = processor.deoptTimeline; const deoptTimeline = processor.deoptTimeline;
this._state.mapTimeline = mapTimeline; const codeTimeline = processor.codeTimeline;
this._state.icTimeline = icTimeline; this._state.setTimelines(
this._state.deoptTimeline = deoptTimeline; mapTimeline, icTimeline, deoptTimeline, codeTimeline);
// 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.mapTrack.data = mapTimeline;
this._view.mapStatsPanel.transitions = this._view.mapStatsPanel.transitions =
this._state.mapTimeline.transitions; this._state.mapTimeline.transitions;
this._view.mapStatsPanel.timeline = mapTimeline; this._view.mapStatsPanel.timeline = mapTimeline;
this._view.icPanel.timeline = icTimeline; this._view.icPanel.timeline = icTimeline;
this._view.icTrack.data = icTimeline; this._view.sourcePanel.data =
this._view.deoptTrack.data = deoptTimeline; processor.scripts this.refreshTimelineTrackView();
this._view.sourcePanel.data = processor.scripts
} catch (e) { } catch (e) {
this._view.logFileReader.error = 'Log file contains errors!' this._view.logFileReader.error = 'Log file contains errors!'
throw (e); throw (e);
...@@ -177,6 +191,7 @@ class App { ...@@ -177,6 +191,7 @@ class App {
this._view.mapTrack.data = this._state.mapTimeline; this._view.mapTrack.data = this._state.mapTimeline;
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;
} }
switchTheme(event) { switchTheme(event) {
......
...@@ -4,10 +4,29 @@ ...@@ -4,10 +4,29 @@
import {LogEntry} from './log.mjs'; import {LogEntry} from './log.mjs';
export class DeoptLogEntry extends LogEntry { export class DeoptLogEntry extends LogEntry {
constructor(type, time) { constructor(
type, time, deoptReason, deoptLocation, scriptOffset, instructionStart,
codeSize, inliningId) {
super(type, time); super(type, time);
this._deoptReason = deoptReason;
this._deoptLocation = deoptLocation;
this._scriptOffset = scriptOffset;
this._instructionStart = instructionStart;
this._codeSize = codeSize;
this._inliningId = inliningId;
} }
toString() { toString() {
return `Deopt(${this.type})`; return `Deopt(${this.type})${this._deoptReason}: ${this._deoptLocation}`;
}
}
export class CodeLogEntry extends LogEntry {
constructor(type, time, kind, entry) {
super(type, time);
this._kind = kind;
this._entry = entry;
}
toString() {
return `Code(${this.type}): ${this._entry.toString()}`;
} }
} }
...@@ -5,7 +5,7 @@ ...@@ -5,7 +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 {DeoptLogEntry} from './log/deopt.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';
import {Timeline} from './timeline.mjs'; import {Timeline} from './timeline.mjs';
...@@ -17,6 +17,7 @@ export class Processor extends LogReader { ...@@ -17,6 +17,7 @@ export class Processor extends LogReader {
_mapTimeline = new Timeline(); _mapTimeline = new Timeline();
_icTimeline = new Timeline(); _icTimeline = new Timeline();
_deoptTimeline = new Timeline(); _deoptTimeline = new Timeline();
_codeTimeline = new Timeline();
_formatPCRegexp = /(.*):[0-9]+:[0-9]+$/; _formatPCRegexp = /(.*):[0-9]+:[0-9]+$/;
MAJOR_VERSION = 7; MAJOR_VERSION = 7;
MINOR_VERSION = 6; MINOR_VERSION = 6;
...@@ -182,20 +183,24 @@ export class Processor extends LogReader { ...@@ -182,20 +183,24 @@ export class Processor extends LogReader {
} }
processCodeCreation(type, kind, timestamp, start, size, name, maybe_func) { processCodeCreation(type, kind, timestamp, start, size, name, maybe_func) {
let entry;
if (maybe_func.length) { if (maybe_func.length) {
const funcAddr = parseInt(maybe_func[0]); const funcAddr = parseInt(maybe_func[0]);
const state = this.parseState(maybe_func[1]); const state = this.parseState(maybe_func[1]);
this._profile.addFuncCode( entry = this._profile.addFuncCode(
type, name, timestamp, start, size, funcAddr, state); type, name, timestamp, start, size, funcAddr, state);
} else { } else {
this._profile.addCode(type, name, timestamp, start, size); entry = this._profile.addCode(type, name, timestamp, start, size);
} }
this._codeTimeline.push(new CodeLogEntry(type, timestamp, kind, entry));
} }
processCodeDeopt( processCodeDeopt(
timestamp, codeSize, instructionStart, inliningId, scriptOffset, timestamp, codeSize, instructionStart, inliningId, scriptOffset,
deoptKind, deoptLocation, deoptReason) { deoptKind, deoptLocation, deoptReason) {
this._deoptTimeline.push(new DeoptLogEntry(deoptKind, timestamp)); this._deoptTimeline.push(new DeoptLogEntry(
deoptKind, timestamp, deoptReason, deoptLocation, scriptOffset,
instructionStart, codeSize, inliningId));
} }
processV8Version(majorVersion, minorVersion) { processV8Version(majorVersion, minorVersion) {
...@@ -352,6 +357,10 @@ export class Processor extends LogReader { ...@@ -352,6 +357,10 @@ export class Processor extends LogReader {
return this._deoptTimeline; return this._deoptTimeline;
} }
get codeTimeline() {
return this._codeTimeline;
}
get scripts() { get scripts() {
return this._profile.scripts_.filter(script => script !== undefined); return this._profile.scripts_.filter(script => script !== undefined);
} }
......
...@@ -18,6 +18,14 @@ found in the LICENSE file. --> ...@@ -18,6 +18,14 @@ found in the LICENSE file. -->
min-height: 100px; min-height: 100px;
padding: 10px; padding: 10px;
box-shadow: 0px 0px 10px rgba(0,0,0,0.5); box-shadow: 0px 0px 10px rgba(0,0,0,0.5);
width: auto;
}
.textContent {
font-family: monospace;
white-space: pre;
overflow-x: hidden;
max-width: 500px;
} }
#body { #body {
......
...@@ -79,10 +79,11 @@ DOM.defineCustomElement( ...@@ -79,10 +79,11 @@ DOM.defineCustomElement(
this.show(); this.show();
if (typeof content === 'string') { if (typeof content === 'string') {
this.contentNode.innerHTML = content; this.contentNode.innerHTML = content;
this.contentNode.className = 'textContent';
} else { } else {
const newContent = DOM.div(); const newContent = DOM.div();
newContent.appendChild(content); newContent.appendChild(content);
this.contentNode.replaceWih(newContent); this.contentNode.replaceWith(newContent);
newContent.id = 'content'; newContent.id = 'content';
} }
} }
......
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