11cb0ef41Sopenharmony_ci// Copyright 2020 the V8 project authors. All rights reserved. 21cb0ef41Sopenharmony_ci// Use of this source code is governed by a BSD-style license that can be 31cb0ef41Sopenharmony_ci// found in the LICENSE file. 41cb0ef41Sopenharmony_ci 51cb0ef41Sopenharmony_ciimport {LogReader, parseString, parseVarArgs} from '../logreader.mjs'; 61cb0ef41Sopenharmony_ciimport {Profile} from '../profile.mjs'; 71cb0ef41Sopenharmony_ciimport {RemoteLinuxCppEntriesProvider, RemoteMacOSCppEntriesProvider} from '../tickprocessor.mjs' 81cb0ef41Sopenharmony_ci 91cb0ef41Sopenharmony_ciimport {CodeLogEntry, DeoptLogEntry, FeedbackVectorEntry, SharedLibLogEntry} from './log/code.mjs'; 101cb0ef41Sopenharmony_ciimport {IcLogEntry} from './log/ic.mjs'; 111cb0ef41Sopenharmony_ciimport {Edge, MapLogEntry} from './log/map.mjs'; 121cb0ef41Sopenharmony_ciimport {TickLogEntry} from './log/tick.mjs'; 131cb0ef41Sopenharmony_ciimport {TimerLogEntry} from './log/timer.mjs'; 141cb0ef41Sopenharmony_ciimport {Timeline} from './timeline.mjs'; 151cb0ef41Sopenharmony_ci 161cb0ef41Sopenharmony_ci// =========================================================================== 171cb0ef41Sopenharmony_ci 181cb0ef41Sopenharmony_ciclass AsyncConsumer { 191cb0ef41Sopenharmony_ci constructor(consumer_fn) { 201cb0ef41Sopenharmony_ci this._chunks = []; 211cb0ef41Sopenharmony_ci this._consumer = consumer_fn; 221cb0ef41Sopenharmony_ci this._pendingWork = Promise.resolve(); 231cb0ef41Sopenharmony_ci this._isConsuming = false; 241cb0ef41Sopenharmony_ci } 251cb0ef41Sopenharmony_ci 261cb0ef41Sopenharmony_ci get pendingWork() { 271cb0ef41Sopenharmony_ci return this._pendingWork; 281cb0ef41Sopenharmony_ci } 291cb0ef41Sopenharmony_ci 301cb0ef41Sopenharmony_ci push(chunk) { 311cb0ef41Sopenharmony_ci this._chunks.push(chunk); 321cb0ef41Sopenharmony_ci this.consumeAll(); 331cb0ef41Sopenharmony_ci } 341cb0ef41Sopenharmony_ci 351cb0ef41Sopenharmony_ci async consumeAll() { 361cb0ef41Sopenharmony_ci if (!this._isConsuming) this._pendingWork = this._consumeAll(); 371cb0ef41Sopenharmony_ci return await this._pendingWork; 381cb0ef41Sopenharmony_ci } 391cb0ef41Sopenharmony_ci 401cb0ef41Sopenharmony_ci async _consumeAll() { 411cb0ef41Sopenharmony_ci this._isConsuming = true; 421cb0ef41Sopenharmony_ci while (this._chunks.length > 0) { 431cb0ef41Sopenharmony_ci await this._consumer(this._chunks.shift()); 441cb0ef41Sopenharmony_ci } 451cb0ef41Sopenharmony_ci this._isConsuming = false; 461cb0ef41Sopenharmony_ci } 471cb0ef41Sopenharmony_ci} 481cb0ef41Sopenharmony_ci 491cb0ef41Sopenharmony_ciexport class Processor extends LogReader { 501cb0ef41Sopenharmony_ci _profile = new Profile(); 511cb0ef41Sopenharmony_ci _codeTimeline = new Timeline(); 521cb0ef41Sopenharmony_ci _deoptTimeline = new Timeline(); 531cb0ef41Sopenharmony_ci _icTimeline = new Timeline(); 541cb0ef41Sopenharmony_ci _mapTimeline = new Timeline(); 551cb0ef41Sopenharmony_ci _tickTimeline = new Timeline(); 561cb0ef41Sopenharmony_ci _timerTimeline = new Timeline(); 571cb0ef41Sopenharmony_ci _formatPCRegexp = /(.*):[0-9]+:[0-9]+$/; 581cb0ef41Sopenharmony_ci _lastTimestamp = 0; 591cb0ef41Sopenharmony_ci _lastCodeLogEntry; 601cb0ef41Sopenharmony_ci _lastTickLogEntry; 611cb0ef41Sopenharmony_ci _chunkRemainder = ''; 621cb0ef41Sopenharmony_ci 631cb0ef41Sopenharmony_ci _totalInputBytes = 0; 641cb0ef41Sopenharmony_ci _processedInputChars = 0; 651cb0ef41Sopenharmony_ci _progressCallback; 661cb0ef41Sopenharmony_ci 671cb0ef41Sopenharmony_ci MAJOR_VERSION = 7; 681cb0ef41Sopenharmony_ci MINOR_VERSION = 6; 691cb0ef41Sopenharmony_ci constructor() { 701cb0ef41Sopenharmony_ci super(); 711cb0ef41Sopenharmony_ci this._chunkConsumer = 721cb0ef41Sopenharmony_ci new AsyncConsumer((chunk) => this._processChunk(chunk)); 731cb0ef41Sopenharmony_ci const propertyICParser = [ 741cb0ef41Sopenharmony_ci parseInt, parseInt, parseInt, parseInt, parseString, parseString, 751cb0ef41Sopenharmony_ci parseString, parseString, parseString, parseString 761cb0ef41Sopenharmony_ci ]; 771cb0ef41Sopenharmony_ci this.setDispatchTable({ 781cb0ef41Sopenharmony_ci __proto__: null, 791cb0ef41Sopenharmony_ci 'v8-version': { 801cb0ef41Sopenharmony_ci parsers: [ 811cb0ef41Sopenharmony_ci parseInt, 821cb0ef41Sopenharmony_ci parseInt, 831cb0ef41Sopenharmony_ci ], 841cb0ef41Sopenharmony_ci processor: this.processV8Version, 851cb0ef41Sopenharmony_ci }, 861cb0ef41Sopenharmony_ci 'shared-library': { 871cb0ef41Sopenharmony_ci parsers: [parseString, parseInt, parseInt, parseInt], 881cb0ef41Sopenharmony_ci processor: this.processSharedLibrary.bind(this), 891cb0ef41Sopenharmony_ci isAsync: true, 901cb0ef41Sopenharmony_ci }, 911cb0ef41Sopenharmony_ci 'code-creation': { 921cb0ef41Sopenharmony_ci parsers: [ 931cb0ef41Sopenharmony_ci parseString, parseInt, parseInt, parseInt, parseInt, parseString, 941cb0ef41Sopenharmony_ci parseVarArgs 951cb0ef41Sopenharmony_ci ], 961cb0ef41Sopenharmony_ci processor: this.processCodeCreation 971cb0ef41Sopenharmony_ci }, 981cb0ef41Sopenharmony_ci 'code-deopt': { 991cb0ef41Sopenharmony_ci parsers: [ 1001cb0ef41Sopenharmony_ci parseInt, parseInt, parseInt, parseInt, parseInt, parseString, 1011cb0ef41Sopenharmony_ci parseString, parseString 1021cb0ef41Sopenharmony_ci ], 1031cb0ef41Sopenharmony_ci processor: this.processCodeDeopt 1041cb0ef41Sopenharmony_ci }, 1051cb0ef41Sopenharmony_ci 'code-move': 1061cb0ef41Sopenharmony_ci {parsers: [parseInt, parseInt], processor: this.processCodeMove}, 1071cb0ef41Sopenharmony_ci 'code-delete': {parsers: [parseInt], processor: this.processCodeDelete}, 1081cb0ef41Sopenharmony_ci 'code-source-info': { 1091cb0ef41Sopenharmony_ci parsers: [ 1101cb0ef41Sopenharmony_ci parseInt, parseInt, parseInt, parseInt, parseString, parseString, 1111cb0ef41Sopenharmony_ci parseString 1121cb0ef41Sopenharmony_ci ], 1131cb0ef41Sopenharmony_ci processor: this.processCodeSourceInfo 1141cb0ef41Sopenharmony_ci }, 1151cb0ef41Sopenharmony_ci 'code-disassemble': { 1161cb0ef41Sopenharmony_ci parsers: [ 1171cb0ef41Sopenharmony_ci parseInt, 1181cb0ef41Sopenharmony_ci parseString, 1191cb0ef41Sopenharmony_ci parseString, 1201cb0ef41Sopenharmony_ci ], 1211cb0ef41Sopenharmony_ci processor: this.processCodeDisassemble 1221cb0ef41Sopenharmony_ci }, 1231cb0ef41Sopenharmony_ci 'feedback-vector': { 1241cb0ef41Sopenharmony_ci parsers: [ 1251cb0ef41Sopenharmony_ci parseInt, parseString, parseInt, parseInt, parseString, parseString, 1261cb0ef41Sopenharmony_ci parseInt, parseInt, parseString 1271cb0ef41Sopenharmony_ci ], 1281cb0ef41Sopenharmony_ci processor: this.processFeedbackVector 1291cb0ef41Sopenharmony_ci }, 1301cb0ef41Sopenharmony_ci 'script-source': { 1311cb0ef41Sopenharmony_ci parsers: [parseInt, parseString, parseString], 1321cb0ef41Sopenharmony_ci processor: this.processScriptSource 1331cb0ef41Sopenharmony_ci }, 1341cb0ef41Sopenharmony_ci 'sfi-move': 1351cb0ef41Sopenharmony_ci {parsers: [parseInt, parseInt], processor: this.processFunctionMove}, 1361cb0ef41Sopenharmony_ci 'tick': { 1371cb0ef41Sopenharmony_ci parsers: 1381cb0ef41Sopenharmony_ci [parseInt, parseInt, parseInt, parseInt, parseInt, parseVarArgs], 1391cb0ef41Sopenharmony_ci processor: this.processTick 1401cb0ef41Sopenharmony_ci }, 1411cb0ef41Sopenharmony_ci 'active-runtime-timer': undefined, 1421cb0ef41Sopenharmony_ci 'heap-sample-begin': undefined, 1431cb0ef41Sopenharmony_ci 'heap-sample-end': undefined, 1441cb0ef41Sopenharmony_ci 'timer-event-start': { 1451cb0ef41Sopenharmony_ci parsers: [parseString, parseInt], 1461cb0ef41Sopenharmony_ci processor: this.processTimerEventStart 1471cb0ef41Sopenharmony_ci }, 1481cb0ef41Sopenharmony_ci 'timer-event-end': { 1491cb0ef41Sopenharmony_ci parsers: [parseString, parseInt], 1501cb0ef41Sopenharmony_ci processor: this.processTimerEventEnd 1511cb0ef41Sopenharmony_ci }, 1521cb0ef41Sopenharmony_ci 'map-create': 1531cb0ef41Sopenharmony_ci {parsers: [parseInt, parseString], processor: this.processMapCreate}, 1541cb0ef41Sopenharmony_ci 'map': { 1551cb0ef41Sopenharmony_ci parsers: [ 1561cb0ef41Sopenharmony_ci parseString, parseInt, parseString, parseString, parseInt, parseInt, 1571cb0ef41Sopenharmony_ci parseInt, parseString, parseString 1581cb0ef41Sopenharmony_ci ], 1591cb0ef41Sopenharmony_ci processor: this.processMap 1601cb0ef41Sopenharmony_ci }, 1611cb0ef41Sopenharmony_ci 'map-details': { 1621cb0ef41Sopenharmony_ci parsers: [parseInt, parseString, parseString], 1631cb0ef41Sopenharmony_ci processor: this.processMapDetails 1641cb0ef41Sopenharmony_ci }, 1651cb0ef41Sopenharmony_ci 'LoadGlobalIC': { 1661cb0ef41Sopenharmony_ci parsers: propertyICParser, 1671cb0ef41Sopenharmony_ci processor: this.processPropertyIC.bind(this, 'LoadGlobalIC') 1681cb0ef41Sopenharmony_ci }, 1691cb0ef41Sopenharmony_ci 'StoreGlobalIC': { 1701cb0ef41Sopenharmony_ci parsers: propertyICParser, 1711cb0ef41Sopenharmony_ci processor: this.processPropertyIC.bind(this, 'StoreGlobalIC') 1721cb0ef41Sopenharmony_ci }, 1731cb0ef41Sopenharmony_ci 'LoadIC': { 1741cb0ef41Sopenharmony_ci parsers: propertyICParser, 1751cb0ef41Sopenharmony_ci processor: this.processPropertyIC.bind(this, 'LoadIC') 1761cb0ef41Sopenharmony_ci }, 1771cb0ef41Sopenharmony_ci 'StoreIC': { 1781cb0ef41Sopenharmony_ci parsers: propertyICParser, 1791cb0ef41Sopenharmony_ci processor: this.processPropertyIC.bind(this, 'StoreIC') 1801cb0ef41Sopenharmony_ci }, 1811cb0ef41Sopenharmony_ci 'KeyedLoadIC': { 1821cb0ef41Sopenharmony_ci parsers: propertyICParser, 1831cb0ef41Sopenharmony_ci processor: this.processPropertyIC.bind(this, 'KeyedLoadIC') 1841cb0ef41Sopenharmony_ci }, 1851cb0ef41Sopenharmony_ci 'KeyedStoreIC': { 1861cb0ef41Sopenharmony_ci parsers: propertyICParser, 1871cb0ef41Sopenharmony_ci processor: this.processPropertyIC.bind(this, 'KeyedStoreIC') 1881cb0ef41Sopenharmony_ci }, 1891cb0ef41Sopenharmony_ci 'StoreInArrayLiteralIC': { 1901cb0ef41Sopenharmony_ci parsers: propertyICParser, 1911cb0ef41Sopenharmony_ci processor: this.processPropertyIC.bind(this, 'StoreInArrayLiteralIC') 1921cb0ef41Sopenharmony_ci }, 1931cb0ef41Sopenharmony_ci 'api': { 1941cb0ef41Sopenharmony_ci parsers: [parseString, parseVarArgs], 1951cb0ef41Sopenharmony_ci processor: this.processApiEvent 1961cb0ef41Sopenharmony_ci }, 1971cb0ef41Sopenharmony_ci }); 1981cb0ef41Sopenharmony_ci // TODO(cbruni): Choose correct cpp entries provider 1991cb0ef41Sopenharmony_ci this._cppEntriesProvider = new RemoteLinuxCppEntriesProvider(); 2001cb0ef41Sopenharmony_ci } 2011cb0ef41Sopenharmony_ci 2021cb0ef41Sopenharmony_ci printError(str) { 2031cb0ef41Sopenharmony_ci console.error(str); 2041cb0ef41Sopenharmony_ci throw str 2051cb0ef41Sopenharmony_ci } 2061cb0ef41Sopenharmony_ci 2071cb0ef41Sopenharmony_ci processChunk(chunk) { 2081cb0ef41Sopenharmony_ci this._chunkConsumer.push(chunk) 2091cb0ef41Sopenharmony_ci } 2101cb0ef41Sopenharmony_ci 2111cb0ef41Sopenharmony_ci setProgressCallback(totalSize, callback) { 2121cb0ef41Sopenharmony_ci this._totalInputBytes = totalSize; 2131cb0ef41Sopenharmony_ci this._progressCallback = callback; 2141cb0ef41Sopenharmony_ci } 2151cb0ef41Sopenharmony_ci 2161cb0ef41Sopenharmony_ci async _updateProgress() { 2171cb0ef41Sopenharmony_ci if (!this._progressCallback) return; 2181cb0ef41Sopenharmony_ci // We use chars and bytes interchangeably for simplicity. This causes us to 2191cb0ef41Sopenharmony_ci // slightly underestimate progress. 2201cb0ef41Sopenharmony_ci this._progressCallback( 2211cb0ef41Sopenharmony_ci this._processedInputChars / this._totalInputBytes, 2221cb0ef41Sopenharmony_ci this._processedInputChars); 2231cb0ef41Sopenharmony_ci } 2241cb0ef41Sopenharmony_ci 2251cb0ef41Sopenharmony_ci async _processChunk(chunk) { 2261cb0ef41Sopenharmony_ci const prevProcessedInputChars = this._processedInputChars; 2271cb0ef41Sopenharmony_ci let end = chunk.length; 2281cb0ef41Sopenharmony_ci let current = 0; 2291cb0ef41Sopenharmony_ci let next = 0; 2301cb0ef41Sopenharmony_ci let line; 2311cb0ef41Sopenharmony_ci let lineNumber = 1; 2321cb0ef41Sopenharmony_ci try { 2331cb0ef41Sopenharmony_ci while (current < end) { 2341cb0ef41Sopenharmony_ci next = chunk.indexOf('\n', current); 2351cb0ef41Sopenharmony_ci if (next === -1) { 2361cb0ef41Sopenharmony_ci this._chunkRemainder = chunk.substring(current); 2371cb0ef41Sopenharmony_ci break; 2381cb0ef41Sopenharmony_ci } 2391cb0ef41Sopenharmony_ci line = chunk.substring(current, next); 2401cb0ef41Sopenharmony_ci if (this._chunkRemainder) { 2411cb0ef41Sopenharmony_ci line = this._chunkRemainder + line; 2421cb0ef41Sopenharmony_ci this._chunkRemainder = ''; 2431cb0ef41Sopenharmony_ci } 2441cb0ef41Sopenharmony_ci current = next + 1; 2451cb0ef41Sopenharmony_ci lineNumber++; 2461cb0ef41Sopenharmony_ci await this.processLogLine(line); 2471cb0ef41Sopenharmony_ci this._processedInputChars = prevProcessedInputChars + current; 2481cb0ef41Sopenharmony_ci } 2491cb0ef41Sopenharmony_ci this._updateProgress(); 2501cb0ef41Sopenharmony_ci } catch (e) { 2511cb0ef41Sopenharmony_ci console.error( 2521cb0ef41Sopenharmony_ci `Could not parse log line ${lineNumber}, trying to continue: ${e}`); 2531cb0ef41Sopenharmony_ci } 2541cb0ef41Sopenharmony_ci } 2551cb0ef41Sopenharmony_ci 2561cb0ef41Sopenharmony_ci async processLogFile(fileName) { 2571cb0ef41Sopenharmony_ci this.collectEntries = true; 2581cb0ef41Sopenharmony_ci this.lastLogFileName_ = fileName; 2591cb0ef41Sopenharmony_ci let i = 1; 2601cb0ef41Sopenharmony_ci let line; 2611cb0ef41Sopenharmony_ci try { 2621cb0ef41Sopenharmony_ci while (line = readline()) { 2631cb0ef41Sopenharmony_ci await this.processLogLine(line); 2641cb0ef41Sopenharmony_ci i++; 2651cb0ef41Sopenharmony_ci } 2661cb0ef41Sopenharmony_ci } catch (e) { 2671cb0ef41Sopenharmony_ci console.error( 2681cb0ef41Sopenharmony_ci `Error occurred during parsing line ${i}` + 2691cb0ef41Sopenharmony_ci ', trying to continue: ' + e); 2701cb0ef41Sopenharmony_ci } 2711cb0ef41Sopenharmony_ci this.finalize(); 2721cb0ef41Sopenharmony_ci } 2731cb0ef41Sopenharmony_ci 2741cb0ef41Sopenharmony_ci async finalize() { 2751cb0ef41Sopenharmony_ci await this._chunkConsumer.consumeAll(); 2761cb0ef41Sopenharmony_ci if (this._profile.warnings.size > 0) { 2771cb0ef41Sopenharmony_ci console.warn('Found profiler warnings:', this._profile.warnings); 2781cb0ef41Sopenharmony_ci } 2791cb0ef41Sopenharmony_ci // TODO(cbruni): print stats; 2801cb0ef41Sopenharmony_ci this._mapTimeline.transitions = new Map(); 2811cb0ef41Sopenharmony_ci let id = 0; 2821cb0ef41Sopenharmony_ci this._mapTimeline.forEach(map => { 2831cb0ef41Sopenharmony_ci if (map.isRoot()) id = map.finalizeRootMap(id + 1); 2841cb0ef41Sopenharmony_ci if (map.edge && map.edge.name) { 2851cb0ef41Sopenharmony_ci const edge = map.edge; 2861cb0ef41Sopenharmony_ci const list = this._mapTimeline.transitions.get(edge.name); 2871cb0ef41Sopenharmony_ci if (list === undefined) { 2881cb0ef41Sopenharmony_ci this._mapTimeline.transitions.set(edge.name, [edge]); 2891cb0ef41Sopenharmony_ci } else { 2901cb0ef41Sopenharmony_ci list.push(edge); 2911cb0ef41Sopenharmony_ci } 2921cb0ef41Sopenharmony_ci } 2931cb0ef41Sopenharmony_ci }); 2941cb0ef41Sopenharmony_ci } 2951cb0ef41Sopenharmony_ci 2961cb0ef41Sopenharmony_ci processV8Version(majorVersion, minorVersion) { 2971cb0ef41Sopenharmony_ci if ((majorVersion == this.MAJOR_VERSION && 2981cb0ef41Sopenharmony_ci minorVersion <= this.MINOR_VERSION) || 2991cb0ef41Sopenharmony_ci (majorVersion < this.MAJOR_VERSION)) { 3001cb0ef41Sopenharmony_ci window.alert( 3011cb0ef41Sopenharmony_ci `Unsupported version ${majorVersion}.${minorVersion}. \n` + 3021cb0ef41Sopenharmony_ci `Please use the matching tool for given the V8 version.`); 3031cb0ef41Sopenharmony_ci } 3041cb0ef41Sopenharmony_ci } 3051cb0ef41Sopenharmony_ci 3061cb0ef41Sopenharmony_ci async processSharedLibrary(name, startAddr, endAddr, aslrSlide) { 3071cb0ef41Sopenharmony_ci const entry = this._profile.addLibrary(name, startAddr, endAddr); 3081cb0ef41Sopenharmony_ci entry.logEntry = new SharedLibLogEntry(entry); 3091cb0ef41Sopenharmony_ci // Many events rely on having a script around, creating fake entries for 3101cb0ef41Sopenharmony_ci // shared libraries. 3111cb0ef41Sopenharmony_ci this._profile.addScriptSource(-1, name, ''); 3121cb0ef41Sopenharmony_ci await this._cppEntriesProvider.parseVmSymbols( 3131cb0ef41Sopenharmony_ci name, startAddr, endAddr, aslrSlide, (fName, fStart, fEnd) => { 3141cb0ef41Sopenharmony_ci this._profile.addStaticCode(fName, fStart, fEnd); 3151cb0ef41Sopenharmony_ci }); 3161cb0ef41Sopenharmony_ci } 3171cb0ef41Sopenharmony_ci 3181cb0ef41Sopenharmony_ci processCodeCreation(type, kind, timestamp, start, size, name, maybe_func) { 3191cb0ef41Sopenharmony_ci this._lastTimestamp = timestamp; 3201cb0ef41Sopenharmony_ci let entry; 3211cb0ef41Sopenharmony_ci let stateName = ''; 3221cb0ef41Sopenharmony_ci if (maybe_func.length) { 3231cb0ef41Sopenharmony_ci const funcAddr = parseInt(maybe_func[0]); 3241cb0ef41Sopenharmony_ci stateName = maybe_func[1] ?? ''; 3251cb0ef41Sopenharmony_ci const state = Profile.parseState(maybe_func[1]); 3261cb0ef41Sopenharmony_ci entry = this._profile.addFuncCode( 3271cb0ef41Sopenharmony_ci type, name, timestamp, start, size, funcAddr, state); 3281cb0ef41Sopenharmony_ci } else { 3291cb0ef41Sopenharmony_ci entry = this._profile.addCode(type, name, timestamp, start, size); 3301cb0ef41Sopenharmony_ci } 3311cb0ef41Sopenharmony_ci this._lastCodeLogEntry = new CodeLogEntry( 3321cb0ef41Sopenharmony_ci type + stateName, timestamp, 3331cb0ef41Sopenharmony_ci Profile.getKindFromState(Profile.parseState(stateName)), kind, entry); 3341cb0ef41Sopenharmony_ci this._codeTimeline.push(this._lastCodeLogEntry); 3351cb0ef41Sopenharmony_ci } 3361cb0ef41Sopenharmony_ci 3371cb0ef41Sopenharmony_ci processCodeDeopt( 3381cb0ef41Sopenharmony_ci timestamp, codeSize, instructionStart, inliningId, scriptOffset, 3391cb0ef41Sopenharmony_ci deoptKind, deoptLocation, deoptReason) { 3401cb0ef41Sopenharmony_ci this._lastTimestamp = timestamp; 3411cb0ef41Sopenharmony_ci const profCodeEntry = this._profile.findEntry(instructionStart); 3421cb0ef41Sopenharmony_ci const logEntry = new DeoptLogEntry( 3431cb0ef41Sopenharmony_ci deoptKind, timestamp, profCodeEntry, deoptReason, deoptLocation, 3441cb0ef41Sopenharmony_ci scriptOffset, instructionStart, codeSize, inliningId); 3451cb0ef41Sopenharmony_ci profCodeEntry.logEntry.add(logEntry); 3461cb0ef41Sopenharmony_ci this._deoptTimeline.push(logEntry); 3471cb0ef41Sopenharmony_ci this.addSourcePosition(profCodeEntry, logEntry); 3481cb0ef41Sopenharmony_ci logEntry.functionSourcePosition = logEntry.sourcePosition; 3491cb0ef41Sopenharmony_ci // custom parse deopt location 3501cb0ef41Sopenharmony_ci if (deoptLocation === '<unknown>') return; 3511cb0ef41Sopenharmony_ci // Handle deopt location for inlined code: <location> inlined at <location> 3521cb0ef41Sopenharmony_ci const inlinedPos = deoptLocation.indexOf(' inlined at '); 3531cb0ef41Sopenharmony_ci if (inlinedPos > 0) { 3541cb0ef41Sopenharmony_ci deoptLocation = deoptLocation.substring(0, inlinedPos) 3551cb0ef41Sopenharmony_ci } 3561cb0ef41Sopenharmony_ci const script = this.getProfileEntryScript(profCodeEntry); 3571cb0ef41Sopenharmony_ci if (!script) return; 3581cb0ef41Sopenharmony_ci const colSeparator = deoptLocation.lastIndexOf(':'); 3591cb0ef41Sopenharmony_ci const rowSeparator = deoptLocation.lastIndexOf(':', colSeparator - 1); 3601cb0ef41Sopenharmony_ci const line = 3611cb0ef41Sopenharmony_ci parseInt(deoptLocation.substring(rowSeparator + 1, colSeparator)); 3621cb0ef41Sopenharmony_ci const column = parseInt( 3631cb0ef41Sopenharmony_ci deoptLocation.substring(colSeparator + 1, deoptLocation.length - 1)); 3641cb0ef41Sopenharmony_ci logEntry.sourcePosition = script.addSourcePosition(line, column, logEntry); 3651cb0ef41Sopenharmony_ci } 3661cb0ef41Sopenharmony_ci 3671cb0ef41Sopenharmony_ci processFeedbackVector( 3681cb0ef41Sopenharmony_ci timestamp, fbv_address, fbv_length, instructionStart, optimization_marker, 3691cb0ef41Sopenharmony_ci optimization_tier, invocation_count, profiler_ticks, fbv_string) { 3701cb0ef41Sopenharmony_ci const profCodeEntry = this._profile.findEntry(instructionStart); 3711cb0ef41Sopenharmony_ci if (!profCodeEntry) { 3721cb0ef41Sopenharmony_ci console.warn('Didn\'t find code for FBV', {fbv, instructionStart}); 3731cb0ef41Sopenharmony_ci return; 3741cb0ef41Sopenharmony_ci } 3751cb0ef41Sopenharmony_ci const fbv = new FeedbackVectorEntry( 3761cb0ef41Sopenharmony_ci timestamp, profCodeEntry.logEntry, fbv_address, fbv_length, 3771cb0ef41Sopenharmony_ci optimization_marker, optimization_tier, invocation_count, 3781cb0ef41Sopenharmony_ci profiler_ticks, fbv_string); 3791cb0ef41Sopenharmony_ci profCodeEntry.logEntry.setFeedbackVector(fbv); 3801cb0ef41Sopenharmony_ci } 3811cb0ef41Sopenharmony_ci 3821cb0ef41Sopenharmony_ci processScriptSource(scriptId, url, source) { 3831cb0ef41Sopenharmony_ci this._profile.addScriptSource(scriptId, url, source); 3841cb0ef41Sopenharmony_ci } 3851cb0ef41Sopenharmony_ci 3861cb0ef41Sopenharmony_ci processCodeMove(from, to) { 3871cb0ef41Sopenharmony_ci this._profile.moveCode(from, to); 3881cb0ef41Sopenharmony_ci } 3891cb0ef41Sopenharmony_ci 3901cb0ef41Sopenharmony_ci processCodeDelete(start) { 3911cb0ef41Sopenharmony_ci this._profile.deleteCode(start); 3921cb0ef41Sopenharmony_ci } 3931cb0ef41Sopenharmony_ci 3941cb0ef41Sopenharmony_ci processFunctionMove(from, to) { 3951cb0ef41Sopenharmony_ci this._profile.moveFunc(from, to); 3961cb0ef41Sopenharmony_ci } 3971cb0ef41Sopenharmony_ci 3981cb0ef41Sopenharmony_ci processTick( 3991cb0ef41Sopenharmony_ci pc, time_ns, is_external_callback, tos_or_external_callback, vmState, 4001cb0ef41Sopenharmony_ci stack) { 4011cb0ef41Sopenharmony_ci if (is_external_callback) { 4021cb0ef41Sopenharmony_ci // Don't use PC when in external callback code, as it can point 4031cb0ef41Sopenharmony_ci // inside callback's code, and we will erroneously report 4041cb0ef41Sopenharmony_ci // that a callback calls itself. Instead we use tos_or_external_callback, 4051cb0ef41Sopenharmony_ci // as simply resetting PC will produce unaccounted ticks. 4061cb0ef41Sopenharmony_ci pc = tos_or_external_callback; 4071cb0ef41Sopenharmony_ci tos_or_external_callback = 0; 4081cb0ef41Sopenharmony_ci } else if (tos_or_external_callback) { 4091cb0ef41Sopenharmony_ci // Find out, if top of stack was pointing inside a JS function 4101cb0ef41Sopenharmony_ci // meaning that we have encountered a frameless invocation. 4111cb0ef41Sopenharmony_ci const funcEntry = this._profile.findEntry(tos_or_external_callback); 4121cb0ef41Sopenharmony_ci if (!funcEntry?.isJSFunction?.()) { 4131cb0ef41Sopenharmony_ci tos_or_external_callback = 0; 4141cb0ef41Sopenharmony_ci } 4151cb0ef41Sopenharmony_ci } 4161cb0ef41Sopenharmony_ci const entryStack = this._profile.recordTick( 4171cb0ef41Sopenharmony_ci time_ns, vmState, 4181cb0ef41Sopenharmony_ci this.processStack(pc, tos_or_external_callback, stack)); 4191cb0ef41Sopenharmony_ci const newEntry = new TickLogEntry(time_ns, vmState, entryStack); 4201cb0ef41Sopenharmony_ci this._tickTimeline.push(newEntry); 4211cb0ef41Sopenharmony_ci if (this._lastTickLogEntry !== undefined) { 4221cb0ef41Sopenharmony_ci this._lastTickLogEntry.end(time_ns); 4231cb0ef41Sopenharmony_ci } 4241cb0ef41Sopenharmony_ci this._lastTickLogEntry = newEntry; 4251cb0ef41Sopenharmony_ci } 4261cb0ef41Sopenharmony_ci 4271cb0ef41Sopenharmony_ci processCodeSourceInfo( 4281cb0ef41Sopenharmony_ci start, scriptId, startPos, endPos, sourcePositions, inliningPositions, 4291cb0ef41Sopenharmony_ci inlinedFunctions) { 4301cb0ef41Sopenharmony_ci this._profile.addSourcePositions( 4311cb0ef41Sopenharmony_ci start, scriptId, startPos, endPos, sourcePositions, inliningPositions, 4321cb0ef41Sopenharmony_ci inlinedFunctions); 4331cb0ef41Sopenharmony_ci if (this._lastCodeLogEntry === undefined) return; 4341cb0ef41Sopenharmony_ci let profileEntry = this._profile.findEntry(start); 4351cb0ef41Sopenharmony_ci if (profileEntry !== this._lastCodeLogEntry._entry) return; 4361cb0ef41Sopenharmony_ci this.addSourcePosition(profileEntry, this._lastCodeLogEntry); 4371cb0ef41Sopenharmony_ci this._lastCodeLogEntry = undefined; 4381cb0ef41Sopenharmony_ci } 4391cb0ef41Sopenharmony_ci 4401cb0ef41Sopenharmony_ci addSourcePosition(profileEntry, logEntry) { 4411cb0ef41Sopenharmony_ci let script = this.getProfileEntryScript(profileEntry); 4421cb0ef41Sopenharmony_ci const parts = profileEntry.getRawName().split(':'); 4431cb0ef41Sopenharmony_ci if (parts.length < 3) return; 4441cb0ef41Sopenharmony_ci const line = parseInt(parts[parts.length - 2]); 4451cb0ef41Sopenharmony_ci const column = parseInt(parts[parts.length - 1]); 4461cb0ef41Sopenharmony_ci logEntry.sourcePosition = script.addSourcePosition(line, column, logEntry); 4471cb0ef41Sopenharmony_ci } 4481cb0ef41Sopenharmony_ci 4491cb0ef41Sopenharmony_ci processCodeDisassemble(start, kind, disassemble) { 4501cb0ef41Sopenharmony_ci this._profile.addDisassemble(start, kind, disassemble); 4511cb0ef41Sopenharmony_ci } 4521cb0ef41Sopenharmony_ci 4531cb0ef41Sopenharmony_ci processPropertyIC( 4541cb0ef41Sopenharmony_ci type, pc, time, line, column, old_state, new_state, mapId, key, modifier, 4551cb0ef41Sopenharmony_ci slow_reason) { 4561cb0ef41Sopenharmony_ci this._lastTimestamp = time; 4571cb0ef41Sopenharmony_ci const codeEntry = this._profile.findEntry(pc); 4581cb0ef41Sopenharmony_ci const fnName = this.formatProfileEntry(codeEntry); 4591cb0ef41Sopenharmony_ci const script = this.getProfileEntryScript(codeEntry); 4601cb0ef41Sopenharmony_ci const map = this.getOrCreateMapEntry(mapId, time); 4611cb0ef41Sopenharmony_ci // TODO: Use SourcePosition here directly 4621cb0ef41Sopenharmony_ci let entry = new IcLogEntry( 4631cb0ef41Sopenharmony_ci type, fnName, time, line, column, key, old_state, new_state, map, 4641cb0ef41Sopenharmony_ci slow_reason, modifier, codeEntry); 4651cb0ef41Sopenharmony_ci if (script) { 4661cb0ef41Sopenharmony_ci entry.sourcePosition = script.addSourcePosition(line, column, entry); 4671cb0ef41Sopenharmony_ci } 4681cb0ef41Sopenharmony_ci this._icTimeline.push(entry); 4691cb0ef41Sopenharmony_ci } 4701cb0ef41Sopenharmony_ci 4711cb0ef41Sopenharmony_ci formatProfileEntry(profileEntry, line, column) { 4721cb0ef41Sopenharmony_ci if (!profileEntry) return '<unknown>'; 4731cb0ef41Sopenharmony_ci if (profileEntry.type === 'Builtin') return profileEntry.name; 4741cb0ef41Sopenharmony_ci const name = profileEntry.func.getName(); 4751cb0ef41Sopenharmony_ci const array = this._formatPCRegexp.exec(name); 4761cb0ef41Sopenharmony_ci const formatted = 4771cb0ef41Sopenharmony_ci (array === null) ? name : profileEntry.getState() + array[1]; 4781cb0ef41Sopenharmony_ci if (line === undefined || column === undefined) return formatted; 4791cb0ef41Sopenharmony_ci return `${formatted}:${line}:${column}`; 4801cb0ef41Sopenharmony_ci } 4811cb0ef41Sopenharmony_ci 4821cb0ef41Sopenharmony_ci getProfileEntryScript(profileEntry) { 4831cb0ef41Sopenharmony_ci if (!profileEntry) return undefined; 4841cb0ef41Sopenharmony_ci if (profileEntry.type === 'Builtin') return undefined; 4851cb0ef41Sopenharmony_ci const script = profileEntry.source?.script; 4861cb0ef41Sopenharmony_ci if (script !== undefined) return script; 4871cb0ef41Sopenharmony_ci let fileName; 4881cb0ef41Sopenharmony_ci if (profileEntry.type === 'SHARED_LIB') { 4891cb0ef41Sopenharmony_ci fileName = profileEntry.name; 4901cb0ef41Sopenharmony_ci } else { 4911cb0ef41Sopenharmony_ci // Slow path, try to get the script from the url: 4921cb0ef41Sopenharmony_ci const fnName = this.formatProfileEntry(profileEntry); 4931cb0ef41Sopenharmony_ci let parts = fnName.split(' '); 4941cb0ef41Sopenharmony_ci fileName = parts[parts.length - 1]; 4951cb0ef41Sopenharmony_ci } 4961cb0ef41Sopenharmony_ci return this.getScript(fileName); 4971cb0ef41Sopenharmony_ci } 4981cb0ef41Sopenharmony_ci 4991cb0ef41Sopenharmony_ci processMap(type, time, from, to, pc, line, column, reason, name) { 5001cb0ef41Sopenharmony_ci this._lastTimestamp = time; 5011cb0ef41Sopenharmony_ci const time_ = parseInt(time); 5021cb0ef41Sopenharmony_ci if (type === 'Deprecate') return this.deprecateMap(type, time_, from); 5031cb0ef41Sopenharmony_ci // Skip normalized maps that were cached so we don't introduce multiple 5041cb0ef41Sopenharmony_ci // edges with the same source and target map. 5051cb0ef41Sopenharmony_ci if (type === 'NormalizeCached') return; 5061cb0ef41Sopenharmony_ci const from_ = this.getOrCreateMapEntry(from, time_); 5071cb0ef41Sopenharmony_ci const to_ = this.getOrCreateMapEntry(to, time_); 5081cb0ef41Sopenharmony_ci if (type === 'Normalize') { 5091cb0ef41Sopenharmony_ci // Fix a bug where we log "Normalize" transitions for maps created from 5101cb0ef41Sopenharmony_ci // the NormalizedMapCache. 5111cb0ef41Sopenharmony_ci if (to_.parent?.id === from || to_.time < from_.time || to_.depth > 0) { 5121cb0ef41Sopenharmony_ci console.log(`Skipping transition to cached normalized map`); 5131cb0ef41Sopenharmony_ci return; 5141cb0ef41Sopenharmony_ci } 5151cb0ef41Sopenharmony_ci } 5161cb0ef41Sopenharmony_ci if (pc) { 5171cb0ef41Sopenharmony_ci const profCodeEntry = this._profile.findEntry(pc); 5181cb0ef41Sopenharmony_ci if (profCodeEntry) { 5191cb0ef41Sopenharmony_ci to_.entry = profCodeEntry; 5201cb0ef41Sopenharmony_ci profCodeEntry.logEntry.add(to_); 5211cb0ef41Sopenharmony_ci let script = this.getProfileEntryScript(profCodeEntry); 5221cb0ef41Sopenharmony_ci if (script) { 5231cb0ef41Sopenharmony_ci to_.sourcePosition = script.addSourcePosition(line, column, to_); 5241cb0ef41Sopenharmony_ci } 5251cb0ef41Sopenharmony_ci } 5261cb0ef41Sopenharmony_ci } 5271cb0ef41Sopenharmony_ci let edge = new Edge(type, name, reason, time, from_, to_); 5281cb0ef41Sopenharmony_ci if (to_.parent !== undefined && to_.parent === from_) { 5291cb0ef41Sopenharmony_ci // Fix bug where we double log transitions. 5301cb0ef41Sopenharmony_ci console.warn('Fixing up double transition'); 5311cb0ef41Sopenharmony_ci to_.edge.updateFrom(edge); 5321cb0ef41Sopenharmony_ci } else { 5331cb0ef41Sopenharmony_ci edge.finishSetup(); 5341cb0ef41Sopenharmony_ci } 5351cb0ef41Sopenharmony_ci } 5361cb0ef41Sopenharmony_ci 5371cb0ef41Sopenharmony_ci deprecateMap(type, time, id) { 5381cb0ef41Sopenharmony_ci this._lastTimestamp = time; 5391cb0ef41Sopenharmony_ci this.getOrCreateMapEntry(id, time).deprecate(); 5401cb0ef41Sopenharmony_ci } 5411cb0ef41Sopenharmony_ci 5421cb0ef41Sopenharmony_ci processMapCreate(time, id) { 5431cb0ef41Sopenharmony_ci // map-create events might override existing maps if the addresses get 5441cb0ef41Sopenharmony_ci // recycled. Hence we do not check for existing maps. 5451cb0ef41Sopenharmony_ci this._lastTimestamp = time; 5461cb0ef41Sopenharmony_ci this.createMapEntry(id, time); 5471cb0ef41Sopenharmony_ci } 5481cb0ef41Sopenharmony_ci 5491cb0ef41Sopenharmony_ci processMapDetails(time, id, string) { 5501cb0ef41Sopenharmony_ci // TODO(cbruni): fix initial map logging. 5511cb0ef41Sopenharmony_ci const map = this.getOrCreateMapEntry(id, time); 5521cb0ef41Sopenharmony_ci map.description = string; 5531cb0ef41Sopenharmony_ci } 5541cb0ef41Sopenharmony_ci 5551cb0ef41Sopenharmony_ci createMapEntry(id, time) { 5561cb0ef41Sopenharmony_ci this._lastTimestamp = time; 5571cb0ef41Sopenharmony_ci const map = new MapLogEntry(id, time); 5581cb0ef41Sopenharmony_ci this._mapTimeline.push(map); 5591cb0ef41Sopenharmony_ci return map; 5601cb0ef41Sopenharmony_ci } 5611cb0ef41Sopenharmony_ci 5621cb0ef41Sopenharmony_ci getOrCreateMapEntry(id, time) { 5631cb0ef41Sopenharmony_ci if (id === '0x000000000000') return undefined; 5641cb0ef41Sopenharmony_ci const map = MapLogEntry.get(id, time); 5651cb0ef41Sopenharmony_ci if (map !== undefined) return map; 5661cb0ef41Sopenharmony_ci console.warn(`No map details provided: id=${id}`); 5671cb0ef41Sopenharmony_ci // Manually patch in a map to continue running. 5681cb0ef41Sopenharmony_ci return this.createMapEntry(id, time); 5691cb0ef41Sopenharmony_ci } 5701cb0ef41Sopenharmony_ci 5711cb0ef41Sopenharmony_ci getScript(url) { 5721cb0ef41Sopenharmony_ci const script = this._profile.getScript(url); 5731cb0ef41Sopenharmony_ci // TODO create placeholder script for empty urls. 5741cb0ef41Sopenharmony_ci if (script === undefined) { 5751cb0ef41Sopenharmony_ci console.error(`Could not find script for url: '${url}'`) 5761cb0ef41Sopenharmony_ci } 5771cb0ef41Sopenharmony_ci return script; 5781cb0ef41Sopenharmony_ci } 5791cb0ef41Sopenharmony_ci 5801cb0ef41Sopenharmony_ci processApiEvent(type, varArgs) { 5811cb0ef41Sopenharmony_ci // legacy events that are no longer supported 5821cb0ef41Sopenharmony_ci } 5831cb0ef41Sopenharmony_ci 5841cb0ef41Sopenharmony_ci processTimerEventStart(type, time) { 5851cb0ef41Sopenharmony_ci const entry = new TimerLogEntry(type, time); 5861cb0ef41Sopenharmony_ci this._timerTimeline.push(entry); 5871cb0ef41Sopenharmony_ci } 5881cb0ef41Sopenharmony_ci 5891cb0ef41Sopenharmony_ci processTimerEventEnd(type, time) { 5901cb0ef41Sopenharmony_ci // Timer-events are infrequent, and not deeply nested, doing a linear walk 5911cb0ef41Sopenharmony_ci // is usually good enough. 5921cb0ef41Sopenharmony_ci for (let i = this._timerTimeline.length - 1; i >= 0; i--) { 5931cb0ef41Sopenharmony_ci const timer = this._timerTimeline.at(i); 5941cb0ef41Sopenharmony_ci if (timer.type == type && !timer.isInitialized) { 5951cb0ef41Sopenharmony_ci timer.end(time); 5961cb0ef41Sopenharmony_ci return; 5971cb0ef41Sopenharmony_ci } 5981cb0ef41Sopenharmony_ci } 5991cb0ef41Sopenharmony_ci console.error('Couldn\'t find matching timer event start', {type, time}); 6001cb0ef41Sopenharmony_ci } 6011cb0ef41Sopenharmony_ci 6021cb0ef41Sopenharmony_ci get icTimeline() { 6031cb0ef41Sopenharmony_ci return this._icTimeline; 6041cb0ef41Sopenharmony_ci } 6051cb0ef41Sopenharmony_ci 6061cb0ef41Sopenharmony_ci get mapTimeline() { 6071cb0ef41Sopenharmony_ci return this._mapTimeline; 6081cb0ef41Sopenharmony_ci } 6091cb0ef41Sopenharmony_ci 6101cb0ef41Sopenharmony_ci get deoptTimeline() { 6111cb0ef41Sopenharmony_ci return this._deoptTimeline; 6121cb0ef41Sopenharmony_ci } 6131cb0ef41Sopenharmony_ci 6141cb0ef41Sopenharmony_ci get codeTimeline() { 6151cb0ef41Sopenharmony_ci return this._codeTimeline; 6161cb0ef41Sopenharmony_ci } 6171cb0ef41Sopenharmony_ci 6181cb0ef41Sopenharmony_ci get tickTimeline() { 6191cb0ef41Sopenharmony_ci return this._tickTimeline; 6201cb0ef41Sopenharmony_ci } 6211cb0ef41Sopenharmony_ci 6221cb0ef41Sopenharmony_ci get timerTimeline() { 6231cb0ef41Sopenharmony_ci return this._timerTimeline; 6241cb0ef41Sopenharmony_ci } 6251cb0ef41Sopenharmony_ci 6261cb0ef41Sopenharmony_ci get scripts() { 6271cb0ef41Sopenharmony_ci return this._profile.scripts_.filter(script => script !== undefined); 6281cb0ef41Sopenharmony_ci } 6291cb0ef41Sopenharmony_ci 6301cb0ef41Sopenharmony_ci get profile() { 6311cb0ef41Sopenharmony_ci return this._profile; 6321cb0ef41Sopenharmony_ci } 6331cb0ef41Sopenharmony_ci} 634