11cb0ef41Sopenharmony_ci// Copyright 2017 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_ci"use strict"; 61cb0ef41Sopenharmony_ci 71cb0ef41Sopenharmony_cilet codeKinds = [ 81cb0ef41Sopenharmony_ci "UNKNOWN", 91cb0ef41Sopenharmony_ci "CPP_PARSE", 101cb0ef41Sopenharmony_ci "CPP_COMP_BC", 111cb0ef41Sopenharmony_ci "CPP_COMP_BASELINE", 121cb0ef41Sopenharmony_ci "CPP_COMP", 131cb0ef41Sopenharmony_ci "CPP_GC", 141cb0ef41Sopenharmony_ci "CPP_EXT", 151cb0ef41Sopenharmony_ci "CPP", 161cb0ef41Sopenharmony_ci "LIB", 171cb0ef41Sopenharmony_ci "IC", 181cb0ef41Sopenharmony_ci "BC", 191cb0ef41Sopenharmony_ci "STUB", 201cb0ef41Sopenharmony_ci "BUILTIN", 211cb0ef41Sopenharmony_ci "REGEXP", 221cb0ef41Sopenharmony_ci "JS_OPT", 231cb0ef41Sopenharmony_ci "JS_UNOPT", 241cb0ef41Sopenharmony_ci "JS_TURBOPROP", 251cb0ef41Sopenharmony_ci "JS_BASELINE", 261cb0ef41Sopenharmony_ci]; 271cb0ef41Sopenharmony_ci 281cb0ef41Sopenharmony_cifunction resolveCodeKind(code) { 291cb0ef41Sopenharmony_ci if (!code || !code.type) { 301cb0ef41Sopenharmony_ci return "UNKNOWN"; 311cb0ef41Sopenharmony_ci } else if (code.type === "CPP") { 321cb0ef41Sopenharmony_ci return "CPP"; 331cb0ef41Sopenharmony_ci } else if (code.type === "SHARED_LIB") { 341cb0ef41Sopenharmony_ci return "LIB"; 351cb0ef41Sopenharmony_ci } else if (code.type === "CODE") { 361cb0ef41Sopenharmony_ci if (code.kind === "LoadIC" || 371cb0ef41Sopenharmony_ci code.kind === "StoreIC" || 381cb0ef41Sopenharmony_ci code.kind === "KeyedStoreIC" || 391cb0ef41Sopenharmony_ci code.kind === "KeyedLoadIC" || 401cb0ef41Sopenharmony_ci code.kind === "LoadGlobalIC" || 411cb0ef41Sopenharmony_ci code.kind === "Handler") { 421cb0ef41Sopenharmony_ci return "IC"; 431cb0ef41Sopenharmony_ci } else if (code.kind === "BytecodeHandler") { 441cb0ef41Sopenharmony_ci return "BC"; 451cb0ef41Sopenharmony_ci } else if (code.kind === "Stub") { 461cb0ef41Sopenharmony_ci return "STUB"; 471cb0ef41Sopenharmony_ci } else if (code.kind === "Builtin") { 481cb0ef41Sopenharmony_ci return "BUILTIN"; 491cb0ef41Sopenharmony_ci } else if (code.kind === "RegExp") { 501cb0ef41Sopenharmony_ci return "REGEXP"; 511cb0ef41Sopenharmony_ci } 521cb0ef41Sopenharmony_ci console.log("Unknown CODE: '" + code.kind + "'."); 531cb0ef41Sopenharmony_ci return "CODE"; 541cb0ef41Sopenharmony_ci } else if (code.type === "JS") { 551cb0ef41Sopenharmony_ci if (code.kind === "Builtin") { 561cb0ef41Sopenharmony_ci return "JS_UNOPT"; 571cb0ef41Sopenharmony_ci } else if (code.kind === "Opt") { 581cb0ef41Sopenharmony_ci return "JS_OPT"; 591cb0ef41Sopenharmony_ci } else if (code.kind === "Unopt") { 601cb0ef41Sopenharmony_ci return "JS_UNOPT"; 611cb0ef41Sopenharmony_ci } else if (code.kind === "Baseline") { 621cb0ef41Sopenharmony_ci return "JS_BASELINE"; 631cb0ef41Sopenharmony_ci } else if (code.kind === "Turboprop") { 641cb0ef41Sopenharmony_ci return "JS_TURBOPROP"; 651cb0ef41Sopenharmony_ci } 661cb0ef41Sopenharmony_ci } 671cb0ef41Sopenharmony_ci console.log("Unknown code type '" + type + "'."); 681cb0ef41Sopenharmony_ci} 691cb0ef41Sopenharmony_ci 701cb0ef41Sopenharmony_cifunction resolveCodeKindAndVmState(code, vmState) { 711cb0ef41Sopenharmony_ci let kind = resolveCodeKind(code); 721cb0ef41Sopenharmony_ci if (kind === "CPP") { 731cb0ef41Sopenharmony_ci if (vmState === 1) { 741cb0ef41Sopenharmony_ci kind = "CPP_GC"; 751cb0ef41Sopenharmony_ci } else if (vmState === 2) { 761cb0ef41Sopenharmony_ci kind = "CPP_PARSE"; 771cb0ef41Sopenharmony_ci } else if (vmState === 3) { 781cb0ef41Sopenharmony_ci kind = "CPP_COMP_BC"; 791cb0ef41Sopenharmony_ci } else if (vmState === 4) { 801cb0ef41Sopenharmony_ci kind = "CPP_COMP"; 811cb0ef41Sopenharmony_ci } else if (vmState === 6) { 821cb0ef41Sopenharmony_ci kind = "CPP_EXT"; 831cb0ef41Sopenharmony_ci } 841cb0ef41Sopenharmony_ci // TODO(cbruni): add CPP_COMP_BASELINE 851cb0ef41Sopenharmony_ci } 861cb0ef41Sopenharmony_ci return kind; 871cb0ef41Sopenharmony_ci} 881cb0ef41Sopenharmony_ci 891cb0ef41Sopenharmony_cifunction codeEquals(code1, code2, allowDifferentKinds = false) { 901cb0ef41Sopenharmony_ci if (!code1 || !code2) return false; 911cb0ef41Sopenharmony_ci if (code1.name !== code2.name || code1.type !== code2.type) return false; 921cb0ef41Sopenharmony_ci 931cb0ef41Sopenharmony_ci if (code1.type === 'CODE') { 941cb0ef41Sopenharmony_ci if (!allowDifferentKinds && code1.kind !== code2.kind) return false; 951cb0ef41Sopenharmony_ci } else if (code1.type === 'JS') { 961cb0ef41Sopenharmony_ci if (!allowDifferentKinds && code1.kind !== code2.kind) return false; 971cb0ef41Sopenharmony_ci if (code1.func !== code2.func) return false; 981cb0ef41Sopenharmony_ci } 991cb0ef41Sopenharmony_ci return true; 1001cb0ef41Sopenharmony_ci} 1011cb0ef41Sopenharmony_ci 1021cb0ef41Sopenharmony_cifunction createNodeFromStackEntry(code, codeId, vmState) { 1031cb0ef41Sopenharmony_ci let name = code ? code.name : "UNKNOWN"; 1041cb0ef41Sopenharmony_ci let node = createEmptyNode(name); 1051cb0ef41Sopenharmony_ci node.codeId = codeId; 1061cb0ef41Sopenharmony_ci node.type = resolveCodeKindAndVmState(code, vmState); 1071cb0ef41Sopenharmony_ci return node; 1081cb0ef41Sopenharmony_ci} 1091cb0ef41Sopenharmony_ci 1101cb0ef41Sopenharmony_cifunction childIdFromCode(codeId, code) { 1111cb0ef41Sopenharmony_ci // For JavaScript function, pretend there is one instance of optimized 1121cb0ef41Sopenharmony_ci // function and one instance of unoptimized function per SFI. 1131cb0ef41Sopenharmony_ci // Otherwise, just compute the id from code id. 1141cb0ef41Sopenharmony_ci let type = resolveCodeKind(code); 1151cb0ef41Sopenharmony_ci if (type === "JSOPT") { 1161cb0ef41Sopenharmony_ci return code.func * 4 + 1; 1171cb0ef41Sopenharmony_ci } else if (type === "JSUNOPT") { 1181cb0ef41Sopenharmony_ci return code.func * 4 + 2; 1191cb0ef41Sopenharmony_ci } else { 1201cb0ef41Sopenharmony_ci return codeId * 4; 1211cb0ef41Sopenharmony_ci } 1221cb0ef41Sopenharmony_ci} 1231cb0ef41Sopenharmony_ci 1241cb0ef41Sopenharmony_ci// We store list of ticks and positions within the ticks stack by 1251cb0ef41Sopenharmony_ci// storing flattened triplets of { tickIndex, depth, count }. 1261cb0ef41Sopenharmony_ci// Triplet { 123, 2, 3 } encodes positions in ticks 123, 124, 125, 1271cb0ef41Sopenharmony_ci// all of them at depth 2. The flattened array is used to encode 1281cb0ef41Sopenharmony_ci// position within the call-tree. 1291cb0ef41Sopenharmony_ci 1301cb0ef41Sopenharmony_ci// The following function helps to encode such triplets. 1311cb0ef41Sopenharmony_cifunction addFrameToFrameList(paths, pathIndex, depth) { 1321cb0ef41Sopenharmony_ci // Try to combine with the previous code run. 1331cb0ef41Sopenharmony_ci if (paths.length > 0 && 1341cb0ef41Sopenharmony_ci paths[paths.length - 3] + 1 === pathIndex && 1351cb0ef41Sopenharmony_ci paths[paths.length - 2] === depth) { 1361cb0ef41Sopenharmony_ci paths[paths.length - 1]++; 1371cb0ef41Sopenharmony_ci } else { 1381cb0ef41Sopenharmony_ci paths.push(pathIndex, depth, 1); 1391cb0ef41Sopenharmony_ci } 1401cb0ef41Sopenharmony_ci} 1411cb0ef41Sopenharmony_ci 1421cb0ef41Sopenharmony_cifunction findNextFrame(file, stack, stackPos, step, filter) { 1431cb0ef41Sopenharmony_ci let codeId = -1; 1441cb0ef41Sopenharmony_ci let code = null; 1451cb0ef41Sopenharmony_ci while (stackPos >= 0 && stackPos < stack.length) { 1461cb0ef41Sopenharmony_ci codeId = stack[stackPos]; 1471cb0ef41Sopenharmony_ci code = codeId >= 0 ? file.code[codeId] : undefined; 1481cb0ef41Sopenharmony_ci 1491cb0ef41Sopenharmony_ci if (filter) { 1501cb0ef41Sopenharmony_ci let type = code ? code.type : undefined; 1511cb0ef41Sopenharmony_ci let kind = code ? code.kind : undefined; 1521cb0ef41Sopenharmony_ci if (filter(type, kind)) return stackPos; 1531cb0ef41Sopenharmony_ci } 1541cb0ef41Sopenharmony_ci stackPos += step; 1551cb0ef41Sopenharmony_ci } 1561cb0ef41Sopenharmony_ci return -1; 1571cb0ef41Sopenharmony_ci} 1581cb0ef41Sopenharmony_ci 1591cb0ef41Sopenharmony_cifunction addOrUpdateChildNode(parent, file, stackIndex, stackPos, ascending) { 1601cb0ef41Sopenharmony_ci if (stackPos === -1) { 1611cb0ef41Sopenharmony_ci // We reached the end without finding the next step. 1621cb0ef41Sopenharmony_ci // If we are doing top-down call tree, update own ticks. 1631cb0ef41Sopenharmony_ci if (!ascending) { 1641cb0ef41Sopenharmony_ci parent.ownTicks++; 1651cb0ef41Sopenharmony_ci } 1661cb0ef41Sopenharmony_ci return; 1671cb0ef41Sopenharmony_ci } 1681cb0ef41Sopenharmony_ci 1691cb0ef41Sopenharmony_ci let stack = file.ticks[stackIndex].s; 1701cb0ef41Sopenharmony_ci console.assert(stackPos >= 0 && stackPos < stack.length); 1711cb0ef41Sopenharmony_ci let codeId = stack[stackPos]; 1721cb0ef41Sopenharmony_ci let code = codeId >= 0 ? file.code[codeId] : undefined; 1731cb0ef41Sopenharmony_ci // We found a child node. 1741cb0ef41Sopenharmony_ci let childId = childIdFromCode(codeId, code); 1751cb0ef41Sopenharmony_ci let child = parent.children[childId]; 1761cb0ef41Sopenharmony_ci if (!child) { 1771cb0ef41Sopenharmony_ci let vmState = file.ticks[stackIndex].vm; 1781cb0ef41Sopenharmony_ci child = createNodeFromStackEntry(code, codeId, vmState); 1791cb0ef41Sopenharmony_ci child.delayedExpansion = { frameList : [], ascending }; 1801cb0ef41Sopenharmony_ci parent.children[childId] = child; 1811cb0ef41Sopenharmony_ci } 1821cb0ef41Sopenharmony_ci child.ticks++; 1831cb0ef41Sopenharmony_ci addFrameToFrameList(child.delayedExpansion.frameList, stackIndex, stackPos); 1841cb0ef41Sopenharmony_ci} 1851cb0ef41Sopenharmony_ci 1861cb0ef41Sopenharmony_ci// This expands a tree node (direct children only). 1871cb0ef41Sopenharmony_cifunction expandTreeNode(file, node, filter) { 1881cb0ef41Sopenharmony_ci let { frameList, ascending } = node.delayedExpansion; 1891cb0ef41Sopenharmony_ci 1901cb0ef41Sopenharmony_ci let step = ascending ? 2 : -2; 1911cb0ef41Sopenharmony_ci 1921cb0ef41Sopenharmony_ci for (let i = 0; i < frameList.length; i+= 3) { 1931cb0ef41Sopenharmony_ci let firstStackIndex = frameList[i]; 1941cb0ef41Sopenharmony_ci let depth = frameList[i + 1]; 1951cb0ef41Sopenharmony_ci let count = frameList[i + 2]; 1961cb0ef41Sopenharmony_ci for (let j = 0; j < count; j++) { 1971cb0ef41Sopenharmony_ci let stackIndex = firstStackIndex + j; 1981cb0ef41Sopenharmony_ci let stack = file.ticks[stackIndex].s; 1991cb0ef41Sopenharmony_ci 2001cb0ef41Sopenharmony_ci // Get to the next frame that has not been filtered out. 2011cb0ef41Sopenharmony_ci let stackPos = findNextFrame(file, stack, depth + step, step, filter); 2021cb0ef41Sopenharmony_ci addOrUpdateChildNode(node, file, stackIndex, stackPos, ascending); 2031cb0ef41Sopenharmony_ci } 2041cb0ef41Sopenharmony_ci } 2051cb0ef41Sopenharmony_ci node.delayedExpansion = null; 2061cb0ef41Sopenharmony_ci} 2071cb0ef41Sopenharmony_ci 2081cb0ef41Sopenharmony_cifunction createEmptyNode(name) { 2091cb0ef41Sopenharmony_ci return { 2101cb0ef41Sopenharmony_ci name : name, 2111cb0ef41Sopenharmony_ci codeId: -1, 2121cb0ef41Sopenharmony_ci type : "CAT", 2131cb0ef41Sopenharmony_ci children : [], 2141cb0ef41Sopenharmony_ci ownTicks : 0, 2151cb0ef41Sopenharmony_ci ticks : 0 2161cb0ef41Sopenharmony_ci }; 2171cb0ef41Sopenharmony_ci} 2181cb0ef41Sopenharmony_ci 2191cb0ef41Sopenharmony_ciclass RuntimeCallTreeProcessor { 2201cb0ef41Sopenharmony_ci constructor() { 2211cb0ef41Sopenharmony_ci this.tree = createEmptyNode("root"); 2221cb0ef41Sopenharmony_ci this.tree.delayedExpansion = { frameList : [], ascending : false }; 2231cb0ef41Sopenharmony_ci } 2241cb0ef41Sopenharmony_ci 2251cb0ef41Sopenharmony_ci addStack(file, tickIndex) { 2261cb0ef41Sopenharmony_ci this.tree.ticks++; 2271cb0ef41Sopenharmony_ci 2281cb0ef41Sopenharmony_ci let stack = file.ticks[tickIndex].s; 2291cb0ef41Sopenharmony_ci let i; 2301cb0ef41Sopenharmony_ci for (i = 0; i < stack.length; i += 2) { 2311cb0ef41Sopenharmony_ci let codeId = stack[i]; 2321cb0ef41Sopenharmony_ci if (codeId < 0) return; 2331cb0ef41Sopenharmony_ci let code = file.code[codeId]; 2341cb0ef41Sopenharmony_ci if (code.type !== "CPP" && code.type !== "SHARED_LIB") { 2351cb0ef41Sopenharmony_ci i -= 2; 2361cb0ef41Sopenharmony_ci break; 2371cb0ef41Sopenharmony_ci } 2381cb0ef41Sopenharmony_ci } 2391cb0ef41Sopenharmony_ci if (i < 0 || i >= stack.length) return; 2401cb0ef41Sopenharmony_ci addOrUpdateChildNode(this.tree, file, tickIndex, i, false); 2411cb0ef41Sopenharmony_ci } 2421cb0ef41Sopenharmony_ci} 2431cb0ef41Sopenharmony_ci 2441cb0ef41Sopenharmony_ciclass PlainCallTreeProcessor { 2451cb0ef41Sopenharmony_ci constructor(filter, isBottomUp) { 2461cb0ef41Sopenharmony_ci this.filter = filter; 2471cb0ef41Sopenharmony_ci this.tree = createEmptyNode("root"); 2481cb0ef41Sopenharmony_ci this.tree.delayedExpansion = { frameList : [], ascending : isBottomUp }; 2491cb0ef41Sopenharmony_ci this.isBottomUp = isBottomUp; 2501cb0ef41Sopenharmony_ci } 2511cb0ef41Sopenharmony_ci 2521cb0ef41Sopenharmony_ci addStack(file, tickIndex) { 2531cb0ef41Sopenharmony_ci let stack = file.ticks[tickIndex].s; 2541cb0ef41Sopenharmony_ci let step = this.isBottomUp ? 2 : -2; 2551cb0ef41Sopenharmony_ci let start = this.isBottomUp ? 0 : stack.length - 2; 2561cb0ef41Sopenharmony_ci 2571cb0ef41Sopenharmony_ci let stackPos = findNextFrame(file, stack, start, step, this.filter); 2581cb0ef41Sopenharmony_ci addOrUpdateChildNode(this.tree, file, tickIndex, stackPos, this.isBottomUp); 2591cb0ef41Sopenharmony_ci 2601cb0ef41Sopenharmony_ci this.tree.ticks++; 2611cb0ef41Sopenharmony_ci } 2621cb0ef41Sopenharmony_ci} 2631cb0ef41Sopenharmony_ci 2641cb0ef41Sopenharmony_cifunction buildCategoryTreeAndLookup() { 2651cb0ef41Sopenharmony_ci let root = createEmptyNode("root"); 2661cb0ef41Sopenharmony_ci let categories = {}; 2671cb0ef41Sopenharmony_ci function addCategory(name, types) { 2681cb0ef41Sopenharmony_ci let n = createEmptyNode(name); 2691cb0ef41Sopenharmony_ci for (let i = 0; i < types.length; i++) { 2701cb0ef41Sopenharmony_ci categories[types[i]] = n; 2711cb0ef41Sopenharmony_ci } 2721cb0ef41Sopenharmony_ci root.children.push(n); 2731cb0ef41Sopenharmony_ci } 2741cb0ef41Sopenharmony_ci addCategory("JS Optimized", [ "JS_OPT" ]); 2751cb0ef41Sopenharmony_ci addCategory("JS Turboprop", [ "JS_TURBOPROP" ]); 2761cb0ef41Sopenharmony_ci addCategory("JS Baseline", [ "JS_BASELINE" ]); 2771cb0ef41Sopenharmony_ci addCategory("JS Unoptimized", [ "JS_UNOPT", "BC" ]); 2781cb0ef41Sopenharmony_ci addCategory("IC", [ "IC" ]); 2791cb0ef41Sopenharmony_ci addCategory("RegExp", [ "REGEXP" ]); 2801cb0ef41Sopenharmony_ci addCategory("Other generated", [ "STUB", "BUILTIN" ]); 2811cb0ef41Sopenharmony_ci addCategory("C++", [ "CPP", "LIB" ]); 2821cb0ef41Sopenharmony_ci addCategory("C++/GC", [ "CPP_GC" ]); 2831cb0ef41Sopenharmony_ci addCategory("C++/Parser", [ "CPP_PARSE" ]); 2841cb0ef41Sopenharmony_ci addCategory("C++/Bytecode Compiler", [ "CPP_COMP_BC" ]); 2851cb0ef41Sopenharmony_ci addCategory("C++/Baseline Compiler", [ "CPP_COMP_BASELINE" ]); 2861cb0ef41Sopenharmony_ci addCategory("C++/Compiler", [ "CPP_COMP" ]); 2871cb0ef41Sopenharmony_ci addCategory("C++/External", [ "CPP_EXT" ]); 2881cb0ef41Sopenharmony_ci addCategory("Unknown", [ "UNKNOWN" ]); 2891cb0ef41Sopenharmony_ci 2901cb0ef41Sopenharmony_ci return { categories, root }; 2911cb0ef41Sopenharmony_ci} 2921cb0ef41Sopenharmony_ci 2931cb0ef41Sopenharmony_ciclass CategorizedCallTreeProcessor { 2941cb0ef41Sopenharmony_ci constructor(filter, isBottomUp) { 2951cb0ef41Sopenharmony_ci this.filter = filter; 2961cb0ef41Sopenharmony_ci let { categories, root } = buildCategoryTreeAndLookup(); 2971cb0ef41Sopenharmony_ci 2981cb0ef41Sopenharmony_ci this.tree = root; 2991cb0ef41Sopenharmony_ci this.categories = categories; 3001cb0ef41Sopenharmony_ci this.isBottomUp = isBottomUp; 3011cb0ef41Sopenharmony_ci } 3021cb0ef41Sopenharmony_ci 3031cb0ef41Sopenharmony_ci addStack(file, tickIndex) { 3041cb0ef41Sopenharmony_ci let stack = file.ticks[tickIndex].s; 3051cb0ef41Sopenharmony_ci let vmState = file.ticks[tickIndex].vm; 3061cb0ef41Sopenharmony_ci if (stack.length === 0) return; 3071cb0ef41Sopenharmony_ci let codeId = stack[0]; 3081cb0ef41Sopenharmony_ci let code = codeId >= 0 ? file.code[codeId] : undefined; 3091cb0ef41Sopenharmony_ci let kind = resolveCodeKindAndVmState(code, vmState); 3101cb0ef41Sopenharmony_ci let node = this.categories[kind]; 3111cb0ef41Sopenharmony_ci 3121cb0ef41Sopenharmony_ci this.tree.ticks++; 3131cb0ef41Sopenharmony_ci node.ticks++; 3141cb0ef41Sopenharmony_ci 3151cb0ef41Sopenharmony_ci let step = this.isBottomUp ? 2 : -2; 3161cb0ef41Sopenharmony_ci let start = this.isBottomUp ? 0 : stack.length - 2; 3171cb0ef41Sopenharmony_ci 3181cb0ef41Sopenharmony_ci let stackPos = findNextFrame(file, stack, start, step, this.filter); 3191cb0ef41Sopenharmony_ci addOrUpdateChildNode(node, file, tickIndex, stackPos, this.isBottomUp); 3201cb0ef41Sopenharmony_ci } 3211cb0ef41Sopenharmony_ci} 3221cb0ef41Sopenharmony_ci 3231cb0ef41Sopenharmony_ciclass FunctionListTree { 3241cb0ef41Sopenharmony_ci constructor(filter, withCategories) { 3251cb0ef41Sopenharmony_ci if (withCategories) { 3261cb0ef41Sopenharmony_ci let { categories, root } = buildCategoryTreeAndLookup(); 3271cb0ef41Sopenharmony_ci this.tree = root; 3281cb0ef41Sopenharmony_ci this.categories = categories; 3291cb0ef41Sopenharmony_ci } else { 3301cb0ef41Sopenharmony_ci this.tree = createEmptyNode("root"); 3311cb0ef41Sopenharmony_ci this.categories = null; 3321cb0ef41Sopenharmony_ci } 3331cb0ef41Sopenharmony_ci 3341cb0ef41Sopenharmony_ci this.codeVisited = []; 3351cb0ef41Sopenharmony_ci this.filter = filter; 3361cb0ef41Sopenharmony_ci } 3371cb0ef41Sopenharmony_ci 3381cb0ef41Sopenharmony_ci addStack(file, tickIndex) { 3391cb0ef41Sopenharmony_ci let stack = file.ticks[tickIndex].s; 3401cb0ef41Sopenharmony_ci let vmState = file.ticks[tickIndex].vm; 3411cb0ef41Sopenharmony_ci 3421cb0ef41Sopenharmony_ci this.tree.ticks++; 3431cb0ef41Sopenharmony_ci let child = null; 3441cb0ef41Sopenharmony_ci let tree = null; 3451cb0ef41Sopenharmony_ci for (let i = stack.length - 2; i >= 0; i -= 2) { 3461cb0ef41Sopenharmony_ci let codeId = stack[i]; 3471cb0ef41Sopenharmony_ci if (codeId < 0 || this.codeVisited[codeId]) continue; 3481cb0ef41Sopenharmony_ci 3491cb0ef41Sopenharmony_ci let code = file.code[codeId]; 3501cb0ef41Sopenharmony_ci if (this.filter) { 3511cb0ef41Sopenharmony_ci let type = code ? code.type : undefined; 3521cb0ef41Sopenharmony_ci let kind = code ? code.kind : undefined; 3531cb0ef41Sopenharmony_ci if (!this.filter(type, kind)) continue; 3541cb0ef41Sopenharmony_ci } 3551cb0ef41Sopenharmony_ci let childId = childIdFromCode(codeId, code); 3561cb0ef41Sopenharmony_ci if (this.categories) { 3571cb0ef41Sopenharmony_ci let kind = resolveCodeKindAndVmState(code, vmState); 3581cb0ef41Sopenharmony_ci tree = this.categories[kind]; 3591cb0ef41Sopenharmony_ci } else { 3601cb0ef41Sopenharmony_ci tree = this.tree; 3611cb0ef41Sopenharmony_ci } 3621cb0ef41Sopenharmony_ci child = tree.children[childId]; 3631cb0ef41Sopenharmony_ci if (!child) { 3641cb0ef41Sopenharmony_ci child = createNodeFromStackEntry(code, codeId, vmState); 3651cb0ef41Sopenharmony_ci child.children[0] = createEmptyNode("Top-down tree"); 3661cb0ef41Sopenharmony_ci child.children[0].delayedExpansion = 3671cb0ef41Sopenharmony_ci { frameList : [], ascending : false }; 3681cb0ef41Sopenharmony_ci child.children[1] = createEmptyNode("Bottom-up tree"); 3691cb0ef41Sopenharmony_ci child.children[1].delayedExpansion = 3701cb0ef41Sopenharmony_ci { frameList : [], ascending : true }; 3711cb0ef41Sopenharmony_ci tree.children[childId] = child; 3721cb0ef41Sopenharmony_ci } 3731cb0ef41Sopenharmony_ci child.ticks++; 3741cb0ef41Sopenharmony_ci child.children[0].ticks++; 3751cb0ef41Sopenharmony_ci addFrameToFrameList( 3761cb0ef41Sopenharmony_ci child.children[0].delayedExpansion.frameList, tickIndex, i); 3771cb0ef41Sopenharmony_ci child.children[1].ticks++; 3781cb0ef41Sopenharmony_ci addFrameToFrameList( 3791cb0ef41Sopenharmony_ci child.children[1].delayedExpansion.frameList, tickIndex, i); 3801cb0ef41Sopenharmony_ci this.codeVisited[codeId] = true; 3811cb0ef41Sopenharmony_ci } 3821cb0ef41Sopenharmony_ci if (child) { 3831cb0ef41Sopenharmony_ci child.ownTicks++; 3841cb0ef41Sopenharmony_ci console.assert(tree !== null); 3851cb0ef41Sopenharmony_ci tree.ticks++; 3861cb0ef41Sopenharmony_ci console.assert(tree.type === "CAT"); 3871cb0ef41Sopenharmony_ci } 3881cb0ef41Sopenharmony_ci 3891cb0ef41Sopenharmony_ci for (let i = 0; i < stack.length; i += 2) { 3901cb0ef41Sopenharmony_ci let codeId = stack[i]; 3911cb0ef41Sopenharmony_ci if (codeId >= 0) this.codeVisited[codeId] = false; 3921cb0ef41Sopenharmony_ci } 3931cb0ef41Sopenharmony_ci } 3941cb0ef41Sopenharmony_ci} 3951cb0ef41Sopenharmony_ci 3961cb0ef41Sopenharmony_ci 3971cb0ef41Sopenharmony_ciclass CategorySampler { 3981cb0ef41Sopenharmony_ci constructor(file, bucketCount) { 3991cb0ef41Sopenharmony_ci this.bucketCount = bucketCount; 4001cb0ef41Sopenharmony_ci 4011cb0ef41Sopenharmony_ci this.firstTime = file.ticks[0].tm; 4021cb0ef41Sopenharmony_ci let lastTime = file.ticks[file.ticks.length - 1].tm; 4031cb0ef41Sopenharmony_ci this.step = (lastTime - this.firstTime) / bucketCount; 4041cb0ef41Sopenharmony_ci 4051cb0ef41Sopenharmony_ci this.buckets = []; 4061cb0ef41Sopenharmony_ci let bucket = {}; 4071cb0ef41Sopenharmony_ci for (let i = 0; i < codeKinds.length; i++) { 4081cb0ef41Sopenharmony_ci bucket[codeKinds[i]] = 0; 4091cb0ef41Sopenharmony_ci } 4101cb0ef41Sopenharmony_ci for (let i = 0; i < bucketCount; i++) { 4111cb0ef41Sopenharmony_ci this.buckets.push(Object.assign({ total : 0 }, bucket)); 4121cb0ef41Sopenharmony_ci } 4131cb0ef41Sopenharmony_ci } 4141cb0ef41Sopenharmony_ci 4151cb0ef41Sopenharmony_ci addStack(file, tickIndex) { 4161cb0ef41Sopenharmony_ci let { tm : timestamp, vm : vmState, s : stack } = file.ticks[tickIndex]; 4171cb0ef41Sopenharmony_ci 4181cb0ef41Sopenharmony_ci let i = Math.floor((timestamp - this.firstTime) / this.step); 4191cb0ef41Sopenharmony_ci if (i === this.buckets.length) i--; 4201cb0ef41Sopenharmony_ci console.assert(i >= 0 && i < this.buckets.length); 4211cb0ef41Sopenharmony_ci 4221cb0ef41Sopenharmony_ci let bucket = this.buckets[i]; 4231cb0ef41Sopenharmony_ci bucket.total++; 4241cb0ef41Sopenharmony_ci 4251cb0ef41Sopenharmony_ci let codeId = (stack.length > 0) ? stack[0] : -1; 4261cb0ef41Sopenharmony_ci let code = codeId >= 0 ? file.code[codeId] : undefined; 4271cb0ef41Sopenharmony_ci let kind = resolveCodeKindAndVmState(code, vmState); 4281cb0ef41Sopenharmony_ci bucket[kind]++; 4291cb0ef41Sopenharmony_ci } 4301cb0ef41Sopenharmony_ci} 4311cb0ef41Sopenharmony_ci 4321cb0ef41Sopenharmony_ciclass FunctionTimelineProcessor { 4331cb0ef41Sopenharmony_ci constructor(functionCodeId, filter) { 4341cb0ef41Sopenharmony_ci this.functionCodeId = functionCodeId; 4351cb0ef41Sopenharmony_ci this.filter = filter; 4361cb0ef41Sopenharmony_ci this.blocks = []; 4371cb0ef41Sopenharmony_ci this.currentBlock = null; 4381cb0ef41Sopenharmony_ci } 4391cb0ef41Sopenharmony_ci 4401cb0ef41Sopenharmony_ci addStack(file, tickIndex) { 4411cb0ef41Sopenharmony_ci if (!this.functionCodeId) return; 4421cb0ef41Sopenharmony_ci 4431cb0ef41Sopenharmony_ci let { tm : timestamp, vm : vmState, s : stack } = file.ticks[tickIndex]; 4441cb0ef41Sopenharmony_ci let functionCode = file.code[this.functionCodeId]; 4451cb0ef41Sopenharmony_ci 4461cb0ef41Sopenharmony_ci // Find if the function is on the stack, and its position on the stack, 4471cb0ef41Sopenharmony_ci // ignoring any filtered entries. 4481cb0ef41Sopenharmony_ci let stackCode = undefined; 4491cb0ef41Sopenharmony_ci let functionPosInStack = -1; 4501cb0ef41Sopenharmony_ci let filteredI = 0; 4511cb0ef41Sopenharmony_ci for (let i = 0; i < stack.length - 1; i += 2) { 4521cb0ef41Sopenharmony_ci let codeId = stack[i]; 4531cb0ef41Sopenharmony_ci let code = codeId >= 0 ? file.code[codeId] : undefined; 4541cb0ef41Sopenharmony_ci let type = code ? code.type : undefined; 4551cb0ef41Sopenharmony_ci let kind = code ? code.kind : undefined; 4561cb0ef41Sopenharmony_ci if (!this.filter(type, kind)) continue; 4571cb0ef41Sopenharmony_ci 4581cb0ef41Sopenharmony_ci // Match other instances of the same function (e.g. unoptimised, various 4591cb0ef41Sopenharmony_ci // different optimised versions). 4601cb0ef41Sopenharmony_ci if (codeEquals(code, functionCode, true)) { 4611cb0ef41Sopenharmony_ci functionPosInStack = filteredI; 4621cb0ef41Sopenharmony_ci stackCode = code; 4631cb0ef41Sopenharmony_ci break; 4641cb0ef41Sopenharmony_ci } 4651cb0ef41Sopenharmony_ci filteredI++; 4661cb0ef41Sopenharmony_ci } 4671cb0ef41Sopenharmony_ci 4681cb0ef41Sopenharmony_ci if (functionPosInStack >= 0) { 4691cb0ef41Sopenharmony_ci let stackKind = resolveCodeKindAndVmState(stackCode, vmState); 4701cb0ef41Sopenharmony_ci 4711cb0ef41Sopenharmony_ci let codeIsTopOfStack = (functionPosInStack === 0); 4721cb0ef41Sopenharmony_ci 4731cb0ef41Sopenharmony_ci if (this.currentBlock !== null) { 4741cb0ef41Sopenharmony_ci this.currentBlock.end = timestamp; 4751cb0ef41Sopenharmony_ci 4761cb0ef41Sopenharmony_ci if (codeIsTopOfStack === this.currentBlock.topOfStack 4771cb0ef41Sopenharmony_ci && stackKind === this.currentBlock.kind) { 4781cb0ef41Sopenharmony_ci // If we haven't changed the stack top or the function kind, then 4791cb0ef41Sopenharmony_ci // we're happy just extending the current block and not starting 4801cb0ef41Sopenharmony_ci // a new one. 4811cb0ef41Sopenharmony_ci return; 4821cb0ef41Sopenharmony_ci } 4831cb0ef41Sopenharmony_ci } 4841cb0ef41Sopenharmony_ci 4851cb0ef41Sopenharmony_ci // Start a new block at the current timestamp. 4861cb0ef41Sopenharmony_ci this.currentBlock = { 4871cb0ef41Sopenharmony_ci start: timestamp, 4881cb0ef41Sopenharmony_ci end: timestamp, 4891cb0ef41Sopenharmony_ci code: stackCode, 4901cb0ef41Sopenharmony_ci kind: stackKind, 4911cb0ef41Sopenharmony_ci topOfStack: codeIsTopOfStack 4921cb0ef41Sopenharmony_ci }; 4931cb0ef41Sopenharmony_ci this.blocks.push(this.currentBlock); 4941cb0ef41Sopenharmony_ci } else { 4951cb0ef41Sopenharmony_ci this.currentBlock = null; 4961cb0ef41Sopenharmony_ci } 4971cb0ef41Sopenharmony_ci } 4981cb0ef41Sopenharmony_ci} 4991cb0ef41Sopenharmony_ci 5001cb0ef41Sopenharmony_ci// Generates a tree out of a ticks sequence. 5011cb0ef41Sopenharmony_ci// {file} is the JSON files with the ticks and code objects. 5021cb0ef41Sopenharmony_ci// {startTime}, {endTime} is the interval. 5031cb0ef41Sopenharmony_ci// {tree} is the processor of stacks. 5041cb0ef41Sopenharmony_cifunction generateTree( 5051cb0ef41Sopenharmony_ci file, startTime, endTime, tree) { 5061cb0ef41Sopenharmony_ci let ticks = file.ticks; 5071cb0ef41Sopenharmony_ci let i = 0; 5081cb0ef41Sopenharmony_ci while (i < ticks.length && ticks[i].tm < startTime) { 5091cb0ef41Sopenharmony_ci i++; 5101cb0ef41Sopenharmony_ci } 5111cb0ef41Sopenharmony_ci 5121cb0ef41Sopenharmony_ci let tickCount = 0; 5131cb0ef41Sopenharmony_ci while (i < ticks.length && ticks[i].tm < endTime) { 5141cb0ef41Sopenharmony_ci tree.addStack(file, i); 5151cb0ef41Sopenharmony_ci i++; 5161cb0ef41Sopenharmony_ci tickCount++; 5171cb0ef41Sopenharmony_ci } 5181cb0ef41Sopenharmony_ci 5191cb0ef41Sopenharmony_ci return tickCount; 5201cb0ef41Sopenharmony_ci} 5211cb0ef41Sopenharmony_ci 5221cb0ef41Sopenharmony_cifunction computeOptimizationStats(file, 5231cb0ef41Sopenharmony_ci timeStart = -Infinity, timeEnd = Infinity) { 5241cb0ef41Sopenharmony_ci function newCollection() { 5251cb0ef41Sopenharmony_ci return { count : 0, functions : [], functionTable : [] }; 5261cb0ef41Sopenharmony_ci } 5271cb0ef41Sopenharmony_ci function addToCollection(collection, code) { 5281cb0ef41Sopenharmony_ci collection.count++; 5291cb0ef41Sopenharmony_ci let funcData = collection.functionTable[code.func]; 5301cb0ef41Sopenharmony_ci if (!funcData) { 5311cb0ef41Sopenharmony_ci funcData = { f : file.functions[code.func], instances : [] }; 5321cb0ef41Sopenharmony_ci collection.functionTable[code.func] = funcData; 5331cb0ef41Sopenharmony_ci collection.functions.push(funcData); 5341cb0ef41Sopenharmony_ci } 5351cb0ef41Sopenharmony_ci funcData.instances.push(code); 5361cb0ef41Sopenharmony_ci } 5371cb0ef41Sopenharmony_ci 5381cb0ef41Sopenharmony_ci let functionCount = 0; 5391cb0ef41Sopenharmony_ci let optimizedFunctionCount = 0; 5401cb0ef41Sopenharmony_ci let turbopropOptimizedFunctionCount = 0; 5411cb0ef41Sopenharmony_ci let deoptimizedFunctionCount = 0; 5421cb0ef41Sopenharmony_ci let optimizations = newCollection(); 5431cb0ef41Sopenharmony_ci let turbopropOptimizations = newCollection(); 5441cb0ef41Sopenharmony_ci let eagerDeoptimizations = newCollection(); 5451cb0ef41Sopenharmony_ci let softDeoptimizations = newCollection(); 5461cb0ef41Sopenharmony_ci let lazyDeoptimizations = newCollection(); 5471cb0ef41Sopenharmony_ci let softBailouts = newCollection(); 5481cb0ef41Sopenharmony_ci let eagerBailouts = newCollection(); 5491cb0ef41Sopenharmony_ci 5501cb0ef41Sopenharmony_ci for (let i = 0; i < file.functions.length; i++) { 5511cb0ef41Sopenharmony_ci let f = file.functions[i]; 5521cb0ef41Sopenharmony_ci 5531cb0ef41Sopenharmony_ci // Skip special SFIs that do not correspond to JS functions. 5541cb0ef41Sopenharmony_ci if (f.codes.length === 0) continue; 5551cb0ef41Sopenharmony_ci if (file.code[f.codes[0]].type !== "JS") continue; 5561cb0ef41Sopenharmony_ci 5571cb0ef41Sopenharmony_ci functionCount++; 5581cb0ef41Sopenharmony_ci let optimized = false; 5591cb0ef41Sopenharmony_ci let turboprop_optimized = false; 5601cb0ef41Sopenharmony_ci let deoptimized = false; 5611cb0ef41Sopenharmony_ci 5621cb0ef41Sopenharmony_ci for (let j = 0; j < f.codes.length; j++) { 5631cb0ef41Sopenharmony_ci let code = file.code[f.codes[j]]; 5641cb0ef41Sopenharmony_ci console.assert(code.type === "JS"); 5651cb0ef41Sopenharmony_ci if (code.kind === "Opt") { 5661cb0ef41Sopenharmony_ci optimized = true; 5671cb0ef41Sopenharmony_ci if (code.tm >= timeStart && code.tm <= timeEnd) { 5681cb0ef41Sopenharmony_ci addToCollection(optimizations, code); 5691cb0ef41Sopenharmony_ci } 5701cb0ef41Sopenharmony_ci } 5711cb0ef41Sopenharmony_ci if (code.kind === "Turboprop") { 5721cb0ef41Sopenharmony_ci turboprop_optimized = true; 5731cb0ef41Sopenharmony_ci if (code.tm >= timeStart && code.tm <= timeEnd) { 5741cb0ef41Sopenharmony_ci addToCollection(turbopropOptimizations, code); 5751cb0ef41Sopenharmony_ci } 5761cb0ef41Sopenharmony_ci } 5771cb0ef41Sopenharmony_ci if (code.deopt) { 5781cb0ef41Sopenharmony_ci if (code.deopt.bailoutType === "deopt-lazy" || code.deopt.bailoutType === "deopt-eager" || code.deopt.bailoutType === "deopt-lazy") { 5791cb0ef41Sopenharmony_ci deoptimized = true; 5801cb0ef41Sopenharmony_ci } 5811cb0ef41Sopenharmony_ci if (code.deopt.tm >= timeStart && code.deopt.tm <= timeEnd) { 5821cb0ef41Sopenharmony_ci switch (code.deopt.bailoutType) { 5831cb0ef41Sopenharmony_ci case "deopt-lazy": 5841cb0ef41Sopenharmony_ci addToCollection(lazyDeoptimizations, code); 5851cb0ef41Sopenharmony_ci break; 5861cb0ef41Sopenharmony_ci case "deopt-eager": 5871cb0ef41Sopenharmony_ci addToCollection(eagerDeoptimizations, code); 5881cb0ef41Sopenharmony_ci break; 5891cb0ef41Sopenharmony_ci case "deopt-soft": 5901cb0ef41Sopenharmony_ci addToCollection(softDeoptimizations, code); 5911cb0ef41Sopenharmony_ci break; 5921cb0ef41Sopenharmony_ci case "bailout-soft": 5931cb0ef41Sopenharmony_ci addToCollection(softBailouts, code); 5941cb0ef41Sopenharmony_ci break; 5951cb0ef41Sopenharmony_ci case "bailout": 5961cb0ef41Sopenharmony_ci addToCollection(eagerBailouts, code); 5971cb0ef41Sopenharmony_ci break; 5981cb0ef41Sopenharmony_ci } 5991cb0ef41Sopenharmony_ci } 6001cb0ef41Sopenharmony_ci } 6011cb0ef41Sopenharmony_ci } 6021cb0ef41Sopenharmony_ci if (optimized) { 6031cb0ef41Sopenharmony_ci optimizedFunctionCount++; 6041cb0ef41Sopenharmony_ci } 6051cb0ef41Sopenharmony_ci if (turboprop_optimized) { 6061cb0ef41Sopenharmony_ci turbopropOptimizedFunctionCount++; 6071cb0ef41Sopenharmony_ci } 6081cb0ef41Sopenharmony_ci if (deoptimized) { 6091cb0ef41Sopenharmony_ci deoptimizedFunctionCount++; 6101cb0ef41Sopenharmony_ci } 6111cb0ef41Sopenharmony_ci } 6121cb0ef41Sopenharmony_ci 6131cb0ef41Sopenharmony_ci function sortCollection(collection) { 6141cb0ef41Sopenharmony_ci collection.functions.sort( 6151cb0ef41Sopenharmony_ci (a, b) => a.instances.length - b.instances.length); 6161cb0ef41Sopenharmony_ci } 6171cb0ef41Sopenharmony_ci 6181cb0ef41Sopenharmony_ci sortCollection(eagerDeoptimizations); 6191cb0ef41Sopenharmony_ci sortCollection(lazyDeoptimizations); 6201cb0ef41Sopenharmony_ci sortCollection(softDeoptimizations); 6211cb0ef41Sopenharmony_ci sortCollection(optimizations); 6221cb0ef41Sopenharmony_ci sortCollection(turbopropOptimizations); 6231cb0ef41Sopenharmony_ci 6241cb0ef41Sopenharmony_ci return { 6251cb0ef41Sopenharmony_ci functionCount, 6261cb0ef41Sopenharmony_ci optimizedFunctionCount, 6271cb0ef41Sopenharmony_ci turbopropOptimizedFunctionCount, 6281cb0ef41Sopenharmony_ci deoptimizedFunctionCount, 6291cb0ef41Sopenharmony_ci optimizations, 6301cb0ef41Sopenharmony_ci turbopropOptimizations, 6311cb0ef41Sopenharmony_ci eagerDeoptimizations, 6321cb0ef41Sopenharmony_ci lazyDeoptimizations, 6331cb0ef41Sopenharmony_ci softDeoptimizations, 6341cb0ef41Sopenharmony_ci softBailouts, 6351cb0ef41Sopenharmony_ci eagerBailouts, 6361cb0ef41Sopenharmony_ci }; 6371cb0ef41Sopenharmony_ci} 6381cb0ef41Sopenharmony_ci 6391cb0ef41Sopenharmony_cifunction normalizeLeadingWhitespace(lines) { 6401cb0ef41Sopenharmony_ci let regex = /^\s*/; 6411cb0ef41Sopenharmony_ci let minimumLeadingWhitespaceChars = Infinity; 6421cb0ef41Sopenharmony_ci for (let line of lines) { 6431cb0ef41Sopenharmony_ci minimumLeadingWhitespaceChars = 6441cb0ef41Sopenharmony_ci Math.min(minimumLeadingWhitespaceChars, regex.exec(line)[0].length); 6451cb0ef41Sopenharmony_ci } 6461cb0ef41Sopenharmony_ci for (let i = 0; i < lines.length; i++) { 6471cb0ef41Sopenharmony_ci lines[i] = lines[i].substring(minimumLeadingWhitespaceChars); 6481cb0ef41Sopenharmony_ci } 6491cb0ef41Sopenharmony_ci} 650