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.")
DEFINE_BOOL(log_api, false, "Log API events to the log file.")
DEFINE_BOOL(log_code, false,
"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_suspect, false, "Log suspect operations.")
DEFINE_BOOL(log_source_code, false, "Log source code.")
......@@ -1721,6 +1724,7 @@ DEFINE_BOOL(log_function_events, false,
DEFINE_IMPLICATION(log_all, log_api)
DEFINE_IMPLICATION(log_all, log_code)
DEFINE_IMPLICATION(log_all, log_code_disassemble)
DEFINE_IMPLICATION(log_all, log_suspect)
DEFINE_IMPLICATION(log_all, log_handles)
DEFINE_IMPLICATION(log_all, log_internal_timer_events)
......
This diff is collapsed.
......@@ -280,9 +280,6 @@ class Logger : public CodeEventListener {
V8_INLINE static CodeEventListener::LogEventsAndTags ToNativeByScript(
CodeEventListener::LogEventsAndTags, Script);
// Used for logging stubs found in the snapshot.
void LogCodeObject(Object code_object);
private:
void UpdateIsLogging(bool value);
......@@ -314,6 +311,10 @@ class Logger : public CodeEventListener {
// each script is logged only once.
bool EnsureLogScriptSource(Script script);
void LogSourceCodeInformation(Handle<AbstractCode> code,
Handle<SharedFunctionInfo> shared);
void LogCodeDisassemble(Handle<AbstractCode> code);
int64_t Time();
Isolate* isolate_;
......
......@@ -86,8 +86,16 @@ export class Script {
}
class SourcePositionInfo{
constructor(script, startPos, endPos, sourcePositionTable, inliningPositions, inlinedFunctions) {
class SourceInfo{
script;
start;
end;
positions;
inlined ;
fns;
disassemble;
setSourcePositionInfo(script, startPos, endPos, sourcePositionTable, inliningPositions, inlinedFunctions) {
this.script = script;
this.start = startPos;
this.end = endPos;
......@@ -95,6 +103,10 @@ class SourcePositionInfo{
this.inlined = inliningPositions;
this.fns = inlinedFunctions;
}
setDisassemble(code) {
this.disassemble = code;
}
}
/**
......@@ -297,8 +309,6 @@ export class Profile {
const script = this.getOrCreateScript(scriptId);
const entry = this.codeMap_.findDynamicEntryByStartAddress(start);
if (!entry) return;
const codeId = entry.codeId;
// Resolve the inlined functions list.
if (inlinedFunctions.length > 0) {
inlinedFunctions = inlinedFunctions.substring(1).split("S");
......@@ -317,12 +327,21 @@ export class Profile {
inlinedFunctions = [];
}
entry.source =
new SourcePositionInfo(
this.getOrCreateSourceInfo(entry).setSourcePositionInfo(
script, startPos, endPos, sourcePositionTable, inliningPositions,
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) {
const script = this.getOrCreateScript(id);
script.update(url, source);
......
......@@ -20,7 +20,7 @@ found in the LICENSE file. -->
let module = await import('./index.mjs');
globalThis.app = new module.App("#log-file-reader", "#map-panel", "#map-stats-panel",
"#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>
......@@ -110,6 +110,7 @@ found in the LICENSE file. -->
<stats-panel id="map-stats-panel"></stats-panel>
<ic-panel id="ic-panel" onchange="app.handleSelectIc(event)"></ic-panel>
<source-panel id="source-panel"></source-panel>
<code-panel id="code-panel"></code-panel>
</div>
</section>
......@@ -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>:
<ul>
<li>
<code>/path/do/d8 --trace-maps --trace_ic --log-source-code $FILE</code>
<code>/path/do/d8 $LOG_FLAGS $FILE</code>
</li>
</ul>
For generating a v8.log file from Chrome:
<ul>
<li>
<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>
</li>
</ul>
<h3>Log Options:</h3>
<h3><code>LOG_FLAGS</code>:</h3>
<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">
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
<a href="https://mathiasbynens.be/notes/shapes-ics" target="_blank">
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>
<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>
<h3>Keyboard Shortcuts for Navigation</h3>
......
......@@ -5,6 +5,7 @@
import {SourcePosition} from '../profile.mjs';
import {State} from './app-model.mjs';
import {CodeLogEntry} from './log/code.mjs';
import {IcLogEntry} from './log/ic.mjs';
import {MapLogEntry} from './log/map.mjs';
import {Processor} from './processor.mjs';
......@@ -19,7 +20,7 @@ class App {
constructor(
fileReaderId, mapPanelId, mapStatsPanelId, timelinePanelId, icPanelId,
mapTrackId, icTrackId, deoptTrackId, codeTrackId, sourcePanelId,
toolTipId) {
codePanelId, toolTipId) {
this._view = {
__proto__: null,
logFileReader: $(fileReaderId),
......@@ -32,6 +33,7 @@ class App {
deoptTrack: $(deoptTrackId),
codeTrack: $(codeTrackId),
sourcePanel: $(sourcePanelId),
codePanel: $(codePanelId),
toolTip: $(toolTipId),
};
this.toggleSwitch = $('.theme-switch input[type="checkbox"]');
......@@ -50,6 +52,7 @@ class App {
import('./view/stats-panel.mjs'),
import('./view/map-panel.mjs'),
import('./view/source-panel.mjs'),
import('./view/code-panel.mjs'),
import('./view/tool-tip.mjs'),
]);
document.addEventListener(
......@@ -71,6 +74,8 @@ class App {
this.showIcEntries(e.entries);
} else if (entry instanceof SourcePosition) {
this.showSourcePositionEntries(e.entries);
} else if (e.entries[0] instanceof CodeLogEntry) {
this.showCodeEntries(e.entries);
} else {
throw new Error('Unknown selection type!');
}
......@@ -96,6 +101,7 @@ class App {
showCodeEntries(entries) {
// TODO: creat list panel
this._state.selectedCodeLogEntries = entries;
this._view.codePanel.selectedEntries = entries;
}
showSourcePositionEntries(entries) {
......@@ -125,6 +131,8 @@ class App {
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!');
}
......@@ -142,6 +150,11 @@ class App {
this._view.icPanel.selectedEntry = [entry];
}
selectCodeLogEntry(entry) {
this._state.code = entry;
this._view.codePanel.entry = entry;
}
selectSourcePosition(sourcePositions) {
if (!sourcePositions.script) return;
this._view.sourcePanel.selectedSourcePositions = [sourcePositions];
......@@ -179,6 +192,7 @@ class App {
this._view.mapStatsPanel.timeline = mapTimeline;
this._view.icPanel.timeline = icTimeline;
this._view.sourcePanel.data = processor.scripts;
this._view.codePanel.timeline = codeTimeline;
this.refreshTimelineTrackView();
} catch (e) {
this._view.logFileReader.error = 'Log file contains errors!'
......
......@@ -15,6 +15,7 @@ export class DeoptLogEntry extends LogEntry {
this._codeSize = codeSize;
this._inliningId = inliningId;
}
toString() {
return `Deopt(${this.type})${this._deoptReason}: ${this._deoptLocation}`;
}
......@@ -26,7 +27,12 @@ export class CodeLogEntry extends LogEntry {
this._kind = kind;
this._entry = 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 {
],
processor: this.processCodeSourceInfo
},
'code-disassemble': {
parsers: [
parseInt,
parseString,
parseString,
],
processor: this.processCodeDisassemble
},
'script-source': {
parsers: [parseInt, parseString, parseString],
processor: this.processScriptSource
......@@ -176,15 +184,18 @@ export class Processor extends LogReader {
processCodeCreation(type, kind, timestamp, start, size, name, maybe_func) {
let entry;
let stateName = '';
if (maybe_func.length) {
const funcAddr = parseInt(maybe_func[0]);
stateName = maybe_func[1] ?? '';
const state = Profile.parseState(maybe_func[1]);
entry = this._profile.addFuncCode(
type, name, timestamp, start, size, funcAddr, state);
} else {
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(
......@@ -229,6 +240,10 @@ export class Processor extends LogReader {
inlinedFunctions);
}
processCodeDisassemble(start, kind, disassemble) {
this._profile.addDisassemble(start, kind, disassemble);
}
processPropertyIC(
type, pc, time, line, column, old_state, new_state, map, key, modifier,
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