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

[tools] Use profiler code-source-info in processor.mjs

Attach SourcePositionInfo objects to existing code entries if we find
code-source-info log entries. This improves fixes finding scripts for
anonymous functions.

Bug: v8:10644
Change-Id: I6fc1e029b17107cacce89dc74a67d4d448d9a979
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2562672
Commit-Queue: Camillo Bruni <cbruni@chromium.org>
Reviewed-by: 's avatarSathya Gunasekaran  <gsathya@chromium.org>
Cr-Commit-Position: refs/heads/master@{#71482}
parent 571e35e8
......@@ -31,19 +31,25 @@ import {
[288,{size:1,
name:'v8::internal::Runtime_DebugGetPropertyDetails(v8::internal::Arguments)',
type:'CPP',
nameUpdated_:false}
nameUpdated_:false,
source: undefined,
}
]);
assertEquals(staticEntries[1],
[272,{size:1,
name:'v8::internal::Runtime::GetElementOrCharAt(v8::internal::Handle<v8::internal::Object>, unsigned int)',
type:'CPP',
nameUpdated_:false}
nameUpdated_:false,
source: undefined,
}
]);
assertEquals(staticEntries[2],
[256,{size:1,
name:'v8::internal::Runtime_StringReplaceRegExpWithString(v8::internal::Arguments)',
type:'CPP',
nameUpdated_:false}
nameUpdated_:false,
source: undefined,
}
]);
UnixCppEntriesProvider.prototype.loadSymbols = oldLoadSymbols;
......
......@@ -266,6 +266,7 @@ export class CodeMap {
* @param {number} size Code entry size in bytes.
* @param {string} opt_name Code entry name.
* @param {string} opt_type Code entry type, e.g. SHARED_LIB, CPP.
* @param {object} source Optional source position information
* @constructor
*/
export class CodeEntry {
......@@ -274,6 +275,7 @@ export class CodeEntry {
this.name = opt_name || '';
this.type = opt_type || '';
this.nameUpdated_ = false;
this.source = undefined;
}
getName() {
......
......@@ -28,6 +28,7 @@
import { CodeMap, CodeEntry } from "./codemap.mjs";
import { ConsArray } from "./consarray.mjs";
// Used to associate log entries with source positions in scripts.
// TODO: move to separate modules
export class SourcePosition {
constructor(script, line, column) {
......@@ -42,13 +43,19 @@ export class SourcePosition {
}
export class Script {
constructor(id, name, source) {
name;
source;
// Map<line, Map<column, SourcePosition>>
lineToColumn = new Map();
constructor(id) {
this.id = id;
this.sourcePositions = [];
}
update(name, source) {
this.name = name;
this.source = source;
this.sourcePositions = [];
// Map<line, Map<column, SourcePosition>>
this.lineToColumn = new Map();
}
get length() {
......@@ -78,6 +85,18 @@ export class Script {
}
}
class SourcePositionInfo{
constructor(script, startPos, endPos, sourcePositionTable, inliningPositions, inlinedFunctions) {
this.script = script;
this.start = startPos;
this.end = endPos;
this.positions = sourcePositionTable;
this.inlined = inliningPositions;
this.fns = inlinedFunctions;
}
}
/**
* Creates a profile object for processing profiling-related events
* and calculating function execution times.
......@@ -252,23 +271,52 @@ export class Profile {
/**
* Adds source positions for given code.
*/
addSourcePositions(start, script, startPos, endPos, sourcePositions,
addSourcePositions(start, scriptId, startPos, endPos, sourcePositionTable,
inliningPositions, inlinedFunctions) {
// CLI does not need source code => ignore.
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");
for (let i = 0; i < inlinedFunctions.length; i++) {
const funcAddr = parseInt(inlinedFunctions[i]);
const func = this.codeMap_.findDynamicEntryByStartAddress(funcAddr);
if (!func || func.funcId === undefined) {
// TODO: fix
console.warn(`Could not find function ${inlinedFunctions[i]}`);
inlinedFunctions[i] = null;
} else {
inlinedFunctions[i] = func.funcId;
}
}
} else {
inlinedFunctions = [];
}
entry.source =
new SourcePositionInfo(
script, startPos, endPos, sourcePositionTable, inliningPositions,
inlinedFunctions);
}
/**
* Adds script source code.
*/
addScriptSource(id, url, source) {
const script = new Script(id, url, source);
this.scripts_[id] = script;
const script = this.getOrCreateScript(id);
script.update(url, source);
this.urlToScript_.set(url, script);
}
/**
* Adds script source code.
*/
getOrCreateScript(id) {
let script = this.scripts_[id];
if (!script) {
script = new Script(id);
this.scripts_[id] = script;
}
return script;
}
getScript(url) {
return this.urlToScript_.get(url);
}
......
......@@ -23,12 +23,19 @@ export class Processor extends LogReader {
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,
......@@ -43,20 +50,20 @@ 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, parseInt, parseInt, parseString, parseString,
parseString
],
processor: this.processV8Version
processor: this.processCodeSourceInfo
},
'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':
......@@ -73,31 +80,31 @@ 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')
},
};
......@@ -229,22 +236,20 @@ 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, script, startPos, endPos, sourcePositions, inliningPositions,
inlinedFunctions) {
this._profile.addSourcePositions(
start, script, startPos, endPos, sourcePositions, inliningPositions,
inlinedFunctions);
}
processPropertyIC(
type, pc, time, line, column, old_state, new_state, map, key, modifier,
slow_reason) {
let fnName = this.functionName(pc);
let parts = fnName.split(' ');
let fileName = parts[parts.length - 1];
let script = this.getScript(fileName);
let profileEntry = this._profile.findEntry(pc);
let fnName = this.formatProfileEntry(profileEntry);
let script = this.getProfileEntryScript(profileEntry);
// TODO: Use SourcePosition here directly
let entry = new IcLogEntry(
type, fnName, time, line, column, key, old_state, new_state, map,
......@@ -255,33 +260,27 @@ export class Processor extends LogReader {
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) {
......@@ -291,13 +290,11 @@ export class Processor extends LogReader {
let to_ = this.getExistingMapEntry(to, time_);
// 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);
}
if (to_.script) {
const profileEntry = this._profile.findEntry(pc)
to_.filePosition = this.formatProfileEntry(profileEntry, line, column);
let script = this.getProfileEntryScript(profileEntry);
if (script) {
to_.script = script;
to_.sourcePosition = to_.script.addSourcePosition(line, column, to_)
}
edge.finishSetup();
......
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