11cb0ef41Sopenharmony_ci// Copyright 2021 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 {TickLogEntry} from '../../log/tick.mjs'; 61cb0ef41Sopenharmony_ciimport {Timeline} from '../../timeline.mjs'; 71cb0ef41Sopenharmony_ciimport {delay, DOM, SVG} from '../helper.mjs'; 81cb0ef41Sopenharmony_ci 91cb0ef41Sopenharmony_ciimport {TimelineTrackStackedBase} from './timeline-track-stacked-base.mjs' 101cb0ef41Sopenharmony_ci 111cb0ef41Sopenharmony_ciclass Flame { 121cb0ef41Sopenharmony_ci constructor(time, logEntry, depth) { 131cb0ef41Sopenharmony_ci this._time = time; 141cb0ef41Sopenharmony_ci this._logEntry = logEntry; 151cb0ef41Sopenharmony_ci this.depth = depth; 161cb0ef41Sopenharmony_ci this._duration = -1; 171cb0ef41Sopenharmony_ci this.parent = undefined; 181cb0ef41Sopenharmony_ci this.children = []; 191cb0ef41Sopenharmony_ci } 201cb0ef41Sopenharmony_ci 211cb0ef41Sopenharmony_ci static add(time, logEntry, stack, flames) { 221cb0ef41Sopenharmony_ci const depth = stack.length; 231cb0ef41Sopenharmony_ci const newFlame = new Flame(time, logEntry, depth) 241cb0ef41Sopenharmony_ci if (depth > 0) { 251cb0ef41Sopenharmony_ci const parent = stack[depth - 1]; 261cb0ef41Sopenharmony_ci newFlame.parent = parent; 271cb0ef41Sopenharmony_ci parent.children.push(newFlame); 281cb0ef41Sopenharmony_ci } 291cb0ef41Sopenharmony_ci flames.push(newFlame); 301cb0ef41Sopenharmony_ci stack.push(newFlame); 311cb0ef41Sopenharmony_ci } 321cb0ef41Sopenharmony_ci 331cb0ef41Sopenharmony_ci stop(time) { 341cb0ef41Sopenharmony_ci if (this._duration !== -1) throw new Error('Already stopped'); 351cb0ef41Sopenharmony_ci this._duration = time - this._time 361cb0ef41Sopenharmony_ci } 371cb0ef41Sopenharmony_ci 381cb0ef41Sopenharmony_ci get time() { 391cb0ef41Sopenharmony_ci return this._time; 401cb0ef41Sopenharmony_ci } 411cb0ef41Sopenharmony_ci 421cb0ef41Sopenharmony_ci get logEntry() { 431cb0ef41Sopenharmony_ci return this._logEntry; 441cb0ef41Sopenharmony_ci } 451cb0ef41Sopenharmony_ci 461cb0ef41Sopenharmony_ci get startTime() { 471cb0ef41Sopenharmony_ci return this._time; 481cb0ef41Sopenharmony_ci } 491cb0ef41Sopenharmony_ci 501cb0ef41Sopenharmony_ci get endTime() { 511cb0ef41Sopenharmony_ci return this._time + this._duration; 521cb0ef41Sopenharmony_ci } 531cb0ef41Sopenharmony_ci 541cb0ef41Sopenharmony_ci get duration() { 551cb0ef41Sopenharmony_ci return this._duration; 561cb0ef41Sopenharmony_ci } 571cb0ef41Sopenharmony_ci 581cb0ef41Sopenharmony_ci get type() { 591cb0ef41Sopenharmony_ci return TickLogEntry.extractCodeEntryType(this._logEntry?.entry); 601cb0ef41Sopenharmony_ci } 611cb0ef41Sopenharmony_ci} 621cb0ef41Sopenharmony_ci 631cb0ef41Sopenharmony_ciDOM.defineCustomElement( 641cb0ef41Sopenharmony_ci 'view/timeline/timeline-track', 'timeline-track-tick', 651cb0ef41Sopenharmony_ci (templateText) => class TimelineTrackTick extends TimelineTrackStackedBase { 661cb0ef41Sopenharmony_ci constructor() { 671cb0ef41Sopenharmony_ci super(templateText); 681cb0ef41Sopenharmony_ci this._annotations = new Annotations(this); 691cb0ef41Sopenharmony_ci } 701cb0ef41Sopenharmony_ci 711cb0ef41Sopenharmony_ci _prepareDrawableItems() { 721cb0ef41Sopenharmony_ci const tmpFlames = []; 731cb0ef41Sopenharmony_ci // flameStack = [bottom, ..., top]; 741cb0ef41Sopenharmony_ci const flameStack = []; 751cb0ef41Sopenharmony_ci const ticks = this._timeline.values; 761cb0ef41Sopenharmony_ci let maxDepth = 0; 771cb0ef41Sopenharmony_ci for (let tickIndex = 0; tickIndex < ticks.length; tickIndex++) { 781cb0ef41Sopenharmony_ci const tick = ticks[tickIndex]; 791cb0ef41Sopenharmony_ci const tickStack = tick.stack; 801cb0ef41Sopenharmony_ci maxDepth = Math.max(maxDepth, tickStack.length); 811cb0ef41Sopenharmony_ci // tick.stack = [top, .... , bottom]; 821cb0ef41Sopenharmony_ci for (let stackIndex = tickStack.length - 1; stackIndex >= 0; 831cb0ef41Sopenharmony_ci stackIndex--) { 841cb0ef41Sopenharmony_ci const codeEntry = tickStack[stackIndex]; 851cb0ef41Sopenharmony_ci // codeEntry is either a CodeEntry or a raw pc. 861cb0ef41Sopenharmony_ci const logEntry = codeEntry?.logEntry; 871cb0ef41Sopenharmony_ci const flameStackIndex = tickStack.length - stackIndex - 1; 881cb0ef41Sopenharmony_ci if (flameStackIndex < flameStack.length) { 891cb0ef41Sopenharmony_ci if (flameStack[flameStackIndex].logEntry === logEntry) continue; 901cb0ef41Sopenharmony_ci for (let k = flameStackIndex; k < flameStack.length; k++) { 911cb0ef41Sopenharmony_ci flameStack[k].stop(tick.time); 921cb0ef41Sopenharmony_ci } 931cb0ef41Sopenharmony_ci flameStack.length = flameStackIndex; 941cb0ef41Sopenharmony_ci } 951cb0ef41Sopenharmony_ci Flame.add(tick.time, logEntry, flameStack, tmpFlames); 961cb0ef41Sopenharmony_ci } 971cb0ef41Sopenharmony_ci if (tickStack.length < flameStack.length) { 981cb0ef41Sopenharmony_ci for (let k = tickStack.length; k < flameStack.length; k++) { 991cb0ef41Sopenharmony_ci flameStack[k].stop(tick.time); 1001cb0ef41Sopenharmony_ci } 1011cb0ef41Sopenharmony_ci flameStack.length = tickStack.length; 1021cb0ef41Sopenharmony_ci } 1031cb0ef41Sopenharmony_ci } 1041cb0ef41Sopenharmony_ci const lastTime = ticks[ticks.length - 1].time; 1051cb0ef41Sopenharmony_ci for (let k = 0; k < flameStack.length; k++) { 1061cb0ef41Sopenharmony_ci flameStack[k].stop(lastTime); 1071cb0ef41Sopenharmony_ci } 1081cb0ef41Sopenharmony_ci this._drawableItems = new Timeline(Flame, tmpFlames); 1091cb0ef41Sopenharmony_ci this._annotations.flames = this._drawableItems; 1101cb0ef41Sopenharmony_ci this._adjustStackDepth(maxDepth); 1111cb0ef41Sopenharmony_ci } 1121cb0ef41Sopenharmony_ci 1131cb0ef41Sopenharmony_ci _drawAnnotations(logEntry, time) { 1141cb0ef41Sopenharmony_ci if (time === undefined) { 1151cb0ef41Sopenharmony_ci time = this.relativePositionToTime(this._timelineScrollLeft); 1161cb0ef41Sopenharmony_ci } 1171cb0ef41Sopenharmony_ci this._annotations.update(logEntry, time); 1181cb0ef41Sopenharmony_ci } 1191cb0ef41Sopenharmony_ci 1201cb0ef41Sopenharmony_ci _drawableItemToLogEntry(flame) { 1211cb0ef41Sopenharmony_ci const logEntry = flame?.logEntry; 1221cb0ef41Sopenharmony_ci if (logEntry === undefined || typeof logEntry == 'number') 1231cb0ef41Sopenharmony_ci return undefined; 1241cb0ef41Sopenharmony_ci return logEntry; 1251cb0ef41Sopenharmony_ci } 1261cb0ef41Sopenharmony_ci }) 1271cb0ef41Sopenharmony_ci 1281cb0ef41Sopenharmony_ciclass Annotations { 1291cb0ef41Sopenharmony_ci _flames; 1301cb0ef41Sopenharmony_ci _logEntry; 1311cb0ef41Sopenharmony_ci _buffer; 1321cb0ef41Sopenharmony_ci 1331cb0ef41Sopenharmony_ci constructor(track) { 1341cb0ef41Sopenharmony_ci this._track = track; 1351cb0ef41Sopenharmony_ci } 1361cb0ef41Sopenharmony_ci 1371cb0ef41Sopenharmony_ci set flames(flames) { 1381cb0ef41Sopenharmony_ci this._flames = flames; 1391cb0ef41Sopenharmony_ci } 1401cb0ef41Sopenharmony_ci 1411cb0ef41Sopenharmony_ci get _node() { 1421cb0ef41Sopenharmony_ci return this._track.timelineAnnotationsNode; 1431cb0ef41Sopenharmony_ci } 1441cb0ef41Sopenharmony_ci 1451cb0ef41Sopenharmony_ci async update(logEntry, time) { 1461cb0ef41Sopenharmony_ci if (this._logEntry == logEntry) return; 1471cb0ef41Sopenharmony_ci this._logEntry = logEntry; 1481cb0ef41Sopenharmony_ci this._node.innerHTML = ''; 1491cb0ef41Sopenharmony_ci if (logEntry === undefined) return; 1501cb0ef41Sopenharmony_ci this._buffer = ''; 1511cb0ef41Sopenharmony_ci const start = this._flames.find(time); 1521cb0ef41Sopenharmony_ci let offset = 0; 1531cb0ef41Sopenharmony_ci // Draw annotations gradually outwards starting form the given time. 1541cb0ef41Sopenharmony_ci let deadline = performance.now() + 100; 1551cb0ef41Sopenharmony_ci for (let range = 0; range < this._flames.length; range += 10000) { 1561cb0ef41Sopenharmony_ci this._markFlames(start - range, start - offset); 1571cb0ef41Sopenharmony_ci this._markFlames(start + offset, start + range); 1581cb0ef41Sopenharmony_ci offset = range; 1591cb0ef41Sopenharmony_ci if ((navigator?.scheduling?.isInputPending({includeContinuous: true}) ?? 1601cb0ef41Sopenharmony_ci false) || 1611cb0ef41Sopenharmony_ci performance.now() >= deadline) { 1621cb0ef41Sopenharmony_ci // Yield if we have to handle an input event, or we're out of time. 1631cb0ef41Sopenharmony_ci await delay(50); 1641cb0ef41Sopenharmony_ci // Abort if we started another update asynchronously. 1651cb0ef41Sopenharmony_ci if (this._logEntry != logEntry) return; 1661cb0ef41Sopenharmony_ci 1671cb0ef41Sopenharmony_ci deadline = performance.now() + 100; 1681cb0ef41Sopenharmony_ci } 1691cb0ef41Sopenharmony_ci this._drawBuffer(); 1701cb0ef41Sopenharmony_ci } 1711cb0ef41Sopenharmony_ci this._drawBuffer(); 1721cb0ef41Sopenharmony_ci } 1731cb0ef41Sopenharmony_ci 1741cb0ef41Sopenharmony_ci _markFlames(start, end) { 1751cb0ef41Sopenharmony_ci const rawFlames = this._flames.values; 1761cb0ef41Sopenharmony_ci if (start < 0) start = 0; 1771cb0ef41Sopenharmony_ci if (end > rawFlames.length) end = rawFlames.length; 1781cb0ef41Sopenharmony_ci const logEntry = this._logEntry; 1791cb0ef41Sopenharmony_ci // Also compare against the function, if any. 1801cb0ef41Sopenharmony_ci const func = logEntry.entry?.func ?? -1; 1811cb0ef41Sopenharmony_ci for (let i = start; i < end; i++) { 1821cb0ef41Sopenharmony_ci const flame = rawFlames[i]; 1831cb0ef41Sopenharmony_ci const flameLogEntry = flame.logEntry; 1841cb0ef41Sopenharmony_ci if (!flameLogEntry) continue; 1851cb0ef41Sopenharmony_ci if (flameLogEntry !== logEntry) { 1861cb0ef41Sopenharmony_ci if (flameLogEntry.entry?.func !== func) continue; 1871cb0ef41Sopenharmony_ci } 1881cb0ef41Sopenharmony_ci this._buffer += this._track._drawItem(flame, i, true); 1891cb0ef41Sopenharmony_ci } 1901cb0ef41Sopenharmony_ci } 1911cb0ef41Sopenharmony_ci 1921cb0ef41Sopenharmony_ci _drawBuffer() { 1931cb0ef41Sopenharmony_ci if (this._buffer.length == 0) return; 1941cb0ef41Sopenharmony_ci const svg = SVG.svg(); 1951cb0ef41Sopenharmony_ci svg.innerHTML = this._buffer; 1961cb0ef41Sopenharmony_ci this._node.appendChild(svg); 1971cb0ef41Sopenharmony_ci this._buffer = ''; 1981cb0ef41Sopenharmony_ci } 1991cb0ef41Sopenharmony_ci} 200