Commit c899ad5e authored by Camillo Bruni's avatar Camillo Bruni Committed by Commit Bot

[tools][log] Add support for disassembled code

- Add FLAG_log_code_disassemble
- Add code-disassamble log entries for Code and BytecodeArray
- Add basic code-panel to system-analyzer

Bug: v8:10644
Change-Id: I1abb339a42b55df01265d63d0f0d8c1ac2e041dc
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2565517Reviewed-by: 's avatarSathya Gunasekaran  <gsathya@chromium.org>
Commit-Queue: Camillo Bruni <cbruni@chromium.org>
Cr-Commit-Position: refs/heads/master@{#71556}
parent 2afb00c0
...@@ -1712,6 +1712,9 @@ DEFINE_BOOL(log_all, false, "Log all events to the log file.") ...@@ -1712,6 +1712,9 @@ DEFINE_BOOL(log_all, false, "Log all events to the log file.")
DEFINE_BOOL(log_api, false, "Log API events to the log file.") DEFINE_BOOL(log_api, false, "Log API events to the log file.")
DEFINE_BOOL(log_code, false, DEFINE_BOOL(log_code, false,
"Log code events to the log file without profiling.") "Log code events to the log file without profiling.")
DEFINE_BOOL(log_code_disassemble, false,
"Log all disassembled code to the log file.")
DEFINE_IMPLICATION(log_code_disassemble, log_code)
DEFINE_BOOL(log_handles, false, "Log global handle events.") DEFINE_BOOL(log_handles, false, "Log global handle events.")
DEFINE_BOOL(log_suspect, false, "Log suspect operations.") DEFINE_BOOL(log_suspect, false, "Log suspect operations.")
DEFINE_BOOL(log_source_code, false, "Log source code.") DEFINE_BOOL(log_source_code, false, "Log source code.")
...@@ -1721,6 +1724,7 @@ DEFINE_BOOL(log_function_events, false, ...@@ -1721,6 +1724,7 @@ DEFINE_BOOL(log_function_events, false,
DEFINE_IMPLICATION(log_all, log_api) DEFINE_IMPLICATION(log_all, log_api)
DEFINE_IMPLICATION(log_all, log_code) DEFINE_IMPLICATION(log_all, log_code)
DEFINE_IMPLICATION(log_all, log_code_disassemble)
DEFINE_IMPLICATION(log_all, log_suspect) DEFINE_IMPLICATION(log_all, log_suspect)
DEFINE_IMPLICATION(log_all, log_handles) DEFINE_IMPLICATION(log_all, log_handles)
DEFINE_IMPLICATION(log_all, log_internal_timer_events) DEFINE_IMPLICATION(log_all, log_internal_timer_events)
......
This diff is collapsed.
...@@ -280,9 +280,6 @@ class Logger : public CodeEventListener { ...@@ -280,9 +280,6 @@ class Logger : public CodeEventListener {
V8_INLINE static CodeEventListener::LogEventsAndTags ToNativeByScript( V8_INLINE static CodeEventListener::LogEventsAndTags ToNativeByScript(
CodeEventListener::LogEventsAndTags, Script); CodeEventListener::LogEventsAndTags, Script);
// Used for logging stubs found in the snapshot.
void LogCodeObject(Object code_object);
private: private:
void UpdateIsLogging(bool value); void UpdateIsLogging(bool value);
...@@ -314,6 +311,10 @@ class Logger : public CodeEventListener { ...@@ -314,6 +311,10 @@ class Logger : public CodeEventListener {
// each script is logged only once. // each script is logged only once.
bool EnsureLogScriptSource(Script script); bool EnsureLogScriptSource(Script script);
void LogSourceCodeInformation(Handle<AbstractCode> code,
Handle<SharedFunctionInfo> shared);
void LogCodeDisassemble(Handle<AbstractCode> code);
int64_t Time(); int64_t Time();
Isolate* isolate_; Isolate* isolate_;
......
...@@ -86,8 +86,16 @@ export class Script { ...@@ -86,8 +86,16 @@ export class Script {
} }
class SourcePositionInfo{ class SourceInfo{
constructor(script, startPos, endPos, sourcePositionTable, inliningPositions, inlinedFunctions) { script;
start;
end;
positions;
inlined ;
fns;
disassemble;
setSourcePositionInfo(script, startPos, endPos, sourcePositionTable, inliningPositions, inlinedFunctions) {
this.script = script; this.script = script;
this.start = startPos; this.start = startPos;
this.end = endPos; this.end = endPos;
...@@ -95,6 +103,10 @@ class SourcePositionInfo{ ...@@ -95,6 +103,10 @@ class SourcePositionInfo{
this.inlined = inliningPositions; this.inlined = inliningPositions;
this.fns = inlinedFunctions; this.fns = inlinedFunctions;
} }
setDisassemble(code) {
this.disassemble = code;
}
} }
/** /**
...@@ -297,8 +309,6 @@ export class Profile { ...@@ -297,8 +309,6 @@ export class Profile {
const script = this.getOrCreateScript(scriptId); const script = this.getOrCreateScript(scriptId);
const entry = this.codeMap_.findDynamicEntryByStartAddress(start); const entry = this.codeMap_.findDynamicEntryByStartAddress(start);
if (!entry) return; if (!entry) return;
const codeId = entry.codeId;
// Resolve the inlined functions list. // Resolve the inlined functions list.
if (inlinedFunctions.length > 0) { if (inlinedFunctions.length > 0) {
inlinedFunctions = inlinedFunctions.substring(1).split("S"); inlinedFunctions = inlinedFunctions.substring(1).split("S");
...@@ -317,12 +327,21 @@ export class Profile { ...@@ -317,12 +327,21 @@ export class Profile {
inlinedFunctions = []; inlinedFunctions = [];
} }
entry.source = this.getOrCreateSourceInfo(entry).setSourcePositionInfo(
new SourcePositionInfo(
script, startPos, endPos, sourcePositionTable, inliningPositions, script, startPos, endPos, sourcePositionTable, inliningPositions,
inlinedFunctions); inlinedFunctions);
} }
addDisassemble(start, kind, disassemble) {
const entry = this.codeMap_.findDynamicEntryByStartAddress(start);
if (!entry) return;
this.getOrCreateSourceInfo(entry).setDisassemble(disassemble);
}
getOrCreateSourceInfo(entry) {
return entry.source ?? (entry.source = new SourceInfo());
}
addScriptSource(id, url, source) { addScriptSource(id, url, source) {
const script = this.getOrCreateScript(id); const script = this.getOrCreateScript(id);
script.update(url, source); script.update(url, source);
......
...@@ -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",
"#code-track", "#source-panel", "#tool-tip"); "#code-track", "#source-panel", "#code-panel", "#tool-tip");
})(); })();
</script> </script>
...@@ -110,6 +110,7 @@ found in the LICENSE file. --> ...@@ -110,6 +110,7 @@ found in the LICENSE file. -->
<stats-panel id="map-stats-panel"></stats-panel> <stats-panel id="map-stats-panel"></stats-panel>
<ic-panel id="ic-panel" onchange="app.handleSelectIc(event)"></ic-panel> <ic-panel id="ic-panel" onchange="app.handleSelectIc(event)"></ic-panel>
<source-panel id="source-panel"></source-panel> <source-panel id="source-panel"></source-panel>
<code-panel id="code-panel"></code-panel>
</div> </div>
</section> </section>
...@@ -133,29 +134,53 @@ found in the LICENSE file. --> ...@@ -133,29 +134,53 @@ found in the LICENSE file. -->
For generating a v8.log file from <a href="https://v8.dev/docs/build">d8</a>: For generating a v8.log file from <a href="https://v8.dev/docs/build">d8</a>:
<ul> <ul>
<li> <li>
<code>/path/do/d8 --trace-maps --trace_ic --log-source-code $FILE</code> <code>/path/do/d8 $LOG_FLAGS $FILE</code>
</li> </li>
</ul> </ul>
For generating a v8.log file from Chrome: For generating a v8.log file from Chrome:
<ul> <ul>
<li> <li>
<code>/path/to/chrome --user-data-dir=/var/tmp/chr$RANDOM --no-sandbox <code>/path/to/chrome --user-data-dir=/var/tmp/chr$RANDOM --no-sandbox
--js-flags='--trace-ic --trace-maps --log-source-code --js-flags='$LOG_FLAGS
$WEBSITE_URL</code> $WEBSITE_URL</code>
</li> </li>
</ul> </ul>
<h3>Log Options:</h3> <h3><code>LOG_FLAGS</code>:</h3>
<dl class="d8-options"> <dl class="d8-options">
<dt><code>--trace-maps</code></dt> <dt>
<a href="https://source.chromium.org/search?q=FLAG_log_all">
<code>--log-all</code>
</a>
</dt>
<dd>Enable all V8 logging options.</dd>
<dt>
<a href="https://source.chromium.org/search?q=FLAG_trace_maps">
<code>--trace-maps</code>
</a>
</dt>
<dd>Log<a href="https://v8.dev/blog/fast-properties" target="_blank"> <dd>Log<a href="https://v8.dev/blog/fast-properties" target="_blank">
Maps</a></dd> Maps</a></dd>
<dt><code>--trace-ic</code></dt> <dt>
<a href="https://source.chromium.org/search?q=FLAG_trace_ic">
<code>--trace-ic</code>
</a>
</dt>
<dd>Log <dd>Log
<a href="https://mathiasbynens.be/notes/shapes-ics" target="_blank"> <a href="https://mathiasbynens.be/notes/shapes-ics" target="_blank">
ICs</a></dd> ICs</a></dd>
<dt><code>--log-source-code</code></dt> <dt>
<a href="https://source.chromium.org/search?q=FLAG_log_source_code">
<code>--log-source-code</code>
</a>
</dt>
<dd>Log source code</dd> <dd>Log source code</dd>
<dt>
<a href="https://source.chromium.org/search?q=FLAG_log_code_disassemble">
<code>--log-code-disassemble</code>
</a>
</dt>
<dd>Log detailed generated generated code</dd>
</dl> </dl>
<h3>Keyboard Shortcuts for Navigation</h3> <h3>Keyboard Shortcuts for Navigation</h3>
......
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
import {SourcePosition} from '../profile.mjs'; import {SourcePosition} from '../profile.mjs';
import {State} from './app-model.mjs'; import {State} from './app-model.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';
import {Processor} from './processor.mjs'; import {Processor} from './processor.mjs';
...@@ -19,7 +20,7 @@ class App { ...@@ -19,7 +20,7 @@ class App {
constructor( constructor(
fileReaderId, mapPanelId, mapStatsPanelId, timelinePanelId, icPanelId, fileReaderId, mapPanelId, mapStatsPanelId, timelinePanelId, icPanelId,
mapTrackId, icTrackId, deoptTrackId, codeTrackId, sourcePanelId, mapTrackId, icTrackId, deoptTrackId, codeTrackId, sourcePanelId,
toolTipId) { codePanelId, toolTipId) {
this._view = { this._view = {
__proto__: null, __proto__: null,
logFileReader: $(fileReaderId), logFileReader: $(fileReaderId),
...@@ -32,6 +33,7 @@ class App { ...@@ -32,6 +33,7 @@ class App {
deoptTrack: $(deoptTrackId), deoptTrack: $(deoptTrackId),
codeTrack: $(codeTrackId), codeTrack: $(codeTrackId),
sourcePanel: $(sourcePanelId), sourcePanel: $(sourcePanelId),
codePanel: $(codePanelId),
toolTip: $(toolTipId), toolTip: $(toolTipId),
}; };
this.toggleSwitch = $('.theme-switch input[type="checkbox"]'); this.toggleSwitch = $('.theme-switch input[type="checkbox"]');
...@@ -50,6 +52,7 @@ class App { ...@@ -50,6 +52,7 @@ class App {
import('./view/stats-panel.mjs'), import('./view/stats-panel.mjs'),
import('./view/map-panel.mjs'), import('./view/map-panel.mjs'),
import('./view/source-panel.mjs'), import('./view/source-panel.mjs'),
import('./view/code-panel.mjs'),
import('./view/tool-tip.mjs'), import('./view/tool-tip.mjs'),
]); ]);
document.addEventListener( document.addEventListener(
...@@ -71,6 +74,8 @@ class App { ...@@ -71,6 +74,8 @@ class App {
this.showIcEntries(e.entries); this.showIcEntries(e.entries);
} else if (entry instanceof SourcePosition) { } else if (entry instanceof SourcePosition) {
this.showSourcePositionEntries(e.entries); this.showSourcePositionEntries(e.entries);
} else if (e.entries[0] instanceof CodeLogEntry) {
this.showCodeEntries(e.entries);
} else { } else {
throw new Error('Unknown selection type!'); throw new Error('Unknown selection type!');
} }
...@@ -96,6 +101,7 @@ class App { ...@@ -96,6 +101,7 @@ class App {
showCodeEntries(entries) { showCodeEntries(entries) {
// TODO: creat list panel // TODO: creat list panel
this._state.selectedCodeLogEntries = entries; this._state.selectedCodeLogEntries = entries;
this._view.codePanel.selectedEntries = entries;
} }
showSourcePositionEntries(entries) { showSourcePositionEntries(entries) {
...@@ -125,6 +131,8 @@ class App { ...@@ -125,6 +131,8 @@ class App {
this.selectICLogEntry(e.entry); this.selectICLogEntry(e.entry);
} else if (entry instanceof SourcePosition) { } else if (entry instanceof SourcePosition) {
this.selectSourcePosition(e.entry); this.selectSourcePosition(e.entry);
} else if (e.entry instanceof CodeLogEntry) {
this.selectCodeLogEntry(e.entry);
} else { } else {
throw new Error('Unknown selection type!'); throw new Error('Unknown selection type!');
} }
...@@ -142,6 +150,11 @@ class App { ...@@ -142,6 +150,11 @@ class App {
this._view.icPanel.selectedEntry = [entry]; this._view.icPanel.selectedEntry = [entry];
} }
selectCodeLogEntry(entry) {
this._state.code = entry;
this._view.codePanel.entry = entry;
}
selectSourcePosition(sourcePositions) { selectSourcePosition(sourcePositions) {
if (!sourcePositions.script) return; if (!sourcePositions.script) return;
this._view.sourcePanel.selectedSourcePositions = [sourcePositions]; this._view.sourcePanel.selectedSourcePositions = [sourcePositions];
...@@ -179,6 +192,7 @@ class App { ...@@ -179,6 +192,7 @@ class App {
this._view.mapStatsPanel.timeline = mapTimeline; this._view.mapStatsPanel.timeline = mapTimeline;
this._view.icPanel.timeline = icTimeline; this._view.icPanel.timeline = icTimeline;
this._view.sourcePanel.data = processor.scripts; this._view.sourcePanel.data = processor.scripts;
this._view.codePanel.timeline = codeTimeline;
this.refreshTimelineTrackView(); this.refreshTimelineTrackView();
} catch (e) { } catch (e) {
this._view.logFileReader.error = 'Log file contains errors!' this._view.logFileReader.error = 'Log file contains errors!'
......
...@@ -15,6 +15,7 @@ export class DeoptLogEntry extends LogEntry { ...@@ -15,6 +15,7 @@ export class DeoptLogEntry extends LogEntry {
this._codeSize = codeSize; this._codeSize = codeSize;
this._inliningId = inliningId; this._inliningId = inliningId;
} }
toString() { toString() {
return `Deopt(${this.type})${this._deoptReason}: ${this._deoptLocation}`; return `Deopt(${this.type})${this._deoptReason}: ${this._deoptLocation}`;
} }
...@@ -26,7 +27,12 @@ export class CodeLogEntry extends LogEntry { ...@@ -26,7 +27,12 @@ export class CodeLogEntry extends LogEntry {
this._kind = kind; this._kind = kind;
this._entry = entry; this._entry = entry;
} }
toString() { toString() {
return `Code(${this.type}): ${this._entry.toString()}`; return `Code(${this.type}): ${this._entry.toString()}`;
} }
get disassemble() {
return this._entry?.source?.disassemble;
}
} }
...@@ -60,6 +60,14 @@ export class Processor extends LogReader { ...@@ -60,6 +60,14 @@ export class Processor extends LogReader {
], ],
processor: this.processCodeSourceInfo processor: this.processCodeSourceInfo
}, },
'code-disassemble': {
parsers: [
parseInt,
parseString,
parseString,
],
processor: this.processCodeDisassemble
},
'script-source': { 'script-source': {
parsers: [parseInt, parseString, parseString], parsers: [parseInt, parseString, parseString],
processor: this.processScriptSource processor: this.processScriptSource
...@@ -176,15 +184,18 @@ export class Processor extends LogReader { ...@@ -176,15 +184,18 @@ 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; let entry;
let stateName = '';
if (maybe_func.length) { if (maybe_func.length) {
const funcAddr = parseInt(maybe_func[0]); const funcAddr = parseInt(maybe_func[0]);
stateName = maybe_func[1] ?? '';
const state = Profile.parseState(maybe_func[1]); const state = Profile.parseState(maybe_func[1]);
entry = this._profile.addFuncCode( entry = this._profile.addFuncCode(
type, name, timestamp, start, size, funcAddr, state); type, name, timestamp, start, size, funcAddr, state);
} else { } else {
entry = 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)); this._codeTimeline.push(
new CodeLogEntry(type + stateName, timestamp, kind, entry));
} }
processCodeDeopt( processCodeDeopt(
...@@ -229,6 +240,10 @@ export class Processor extends LogReader { ...@@ -229,6 +240,10 @@ export class Processor extends LogReader {
inlinedFunctions); inlinedFunctions);
} }
processCodeDisassemble(start, kind, disassemble) {
this._profile.addDisassemble(start, kind, disassemble);
}
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) {
......
<!-- 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. -->
<head>
<link href="./index.css" rel="stylesheet">
</head>
<style>
</style>
<div class="panel">
<h2>Code Panel</h2>
<div class="panelBody">
<pre id="code"></pre>
</div>
</div>
// 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 {IcLogEntry} from '../log/ic.mjs';
import {MapLogEntry} from '../log/map.mjs';
import {FocusEvent, SelectionEvent, ToolTipEvent} from './events.mjs';
import {delay, DOM, formatBytes, V8CustomElement} from './helper.mjs';
DOM.defineCustomElement(
'view/code-panel',
(templateText) => class CodePanel extends V8CustomElement {
_timeline;
_selectedEntries;
_entry;
constructor() {
super(templateText);
}
set timeline(timeline) {
this._timeline = timeline;
this.update();
}
set selectedEntries(entries) {
this._selectedEntries = entries;
this.update();
}
set entry(entry) {
this._entry = entry;
this.update();
}
get codeNode() {
return this.$('#code');
}
_update() {
this.codeNode.innerText = this._entry?.disassemble ?? '';
}
});
\ No newline at end of file
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