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_ci'use strict'; 61cb0ef41Sopenharmony_ci 71cb0ef41Sopenharmony_ciimport {categoryByZoneName} from './categories.js'; 81cb0ef41Sopenharmony_ci 91cb0ef41Sopenharmony_ciimport { 101cb0ef41Sopenharmony_ci VIEW_TOTALS, 111cb0ef41Sopenharmony_ci VIEW_BY_ZONE_NAME, 121cb0ef41Sopenharmony_ci VIEW_BY_ZONE_CATEGORY, 131cb0ef41Sopenharmony_ci 141cb0ef41Sopenharmony_ci KIND_ALLOCATED_MEMORY, 151cb0ef41Sopenharmony_ci KIND_USED_MEMORY, 161cb0ef41Sopenharmony_ci KIND_FREED_MEMORY, 171cb0ef41Sopenharmony_ci} from './details-selection.js'; 181cb0ef41Sopenharmony_ci 191cb0ef41Sopenharmony_cidefineCustomElement('global-timeline', (templateText) => 201cb0ef41Sopenharmony_ci class GlobalTimeline extends HTMLElement { 211cb0ef41Sopenharmony_ci constructor() { 221cb0ef41Sopenharmony_ci super(); 231cb0ef41Sopenharmony_ci const shadowRoot = this.attachShadow({mode: 'open'}); 241cb0ef41Sopenharmony_ci shadowRoot.innerHTML = templateText; 251cb0ef41Sopenharmony_ci } 261cb0ef41Sopenharmony_ci 271cb0ef41Sopenharmony_ci $(id) { 281cb0ef41Sopenharmony_ci return this.shadowRoot.querySelector(id); 291cb0ef41Sopenharmony_ci } 301cb0ef41Sopenharmony_ci 311cb0ef41Sopenharmony_ci set data(value) { 321cb0ef41Sopenharmony_ci this._data = value; 331cb0ef41Sopenharmony_ci this.stateChanged(); 341cb0ef41Sopenharmony_ci } 351cb0ef41Sopenharmony_ci 361cb0ef41Sopenharmony_ci get data() { 371cb0ef41Sopenharmony_ci return this._data; 381cb0ef41Sopenharmony_ci } 391cb0ef41Sopenharmony_ci 401cb0ef41Sopenharmony_ci set selection(value) { 411cb0ef41Sopenharmony_ci this._selection = value; 421cb0ef41Sopenharmony_ci this.stateChanged(); 431cb0ef41Sopenharmony_ci } 441cb0ef41Sopenharmony_ci 451cb0ef41Sopenharmony_ci get selection() { 461cb0ef41Sopenharmony_ci return this._selection; 471cb0ef41Sopenharmony_ci } 481cb0ef41Sopenharmony_ci 491cb0ef41Sopenharmony_ci isValid() { 501cb0ef41Sopenharmony_ci return this.data && this.selection; 511cb0ef41Sopenharmony_ci } 521cb0ef41Sopenharmony_ci 531cb0ef41Sopenharmony_ci hide() { 541cb0ef41Sopenharmony_ci this.$('#container').style.display = 'none'; 551cb0ef41Sopenharmony_ci } 561cb0ef41Sopenharmony_ci 571cb0ef41Sopenharmony_ci show() { 581cb0ef41Sopenharmony_ci this.$('#container').style.display = 'block'; 591cb0ef41Sopenharmony_ci } 601cb0ef41Sopenharmony_ci 611cb0ef41Sopenharmony_ci stateChanged() { 621cb0ef41Sopenharmony_ci if (this.isValid()) { 631cb0ef41Sopenharmony_ci const isolate_data = this.data[this.selection.isolate]; 641cb0ef41Sopenharmony_ci const peakAllocatedMemory = isolate_data.peakAllocatedMemory; 651cb0ef41Sopenharmony_ci this.$('#peak-memory-label').innerText = formatBytes(peakAllocatedMemory); 661cb0ef41Sopenharmony_ci this.drawChart(); 671cb0ef41Sopenharmony_ci } else { 681cb0ef41Sopenharmony_ci this.hide(); 691cb0ef41Sopenharmony_ci } 701cb0ef41Sopenharmony_ci } 711cb0ef41Sopenharmony_ci 721cb0ef41Sopenharmony_ci getZoneLabels(zone_names) { 731cb0ef41Sopenharmony_ci switch (this.selection.data_kind) { 741cb0ef41Sopenharmony_ci case KIND_ALLOCATED_MEMORY: 751cb0ef41Sopenharmony_ci return zone_names.map(name => { 761cb0ef41Sopenharmony_ci return {label: name + " (allocated)", type: 'number'}; 771cb0ef41Sopenharmony_ci }); 781cb0ef41Sopenharmony_ci 791cb0ef41Sopenharmony_ci case KIND_USED_MEMORY: 801cb0ef41Sopenharmony_ci return zone_names.map(name => { 811cb0ef41Sopenharmony_ci return {label: name + " (used)", type: 'number'}; 821cb0ef41Sopenharmony_ci }); 831cb0ef41Sopenharmony_ci 841cb0ef41Sopenharmony_ci case KIND_FREED_MEMORY: 851cb0ef41Sopenharmony_ci return zone_names.map(name => { 861cb0ef41Sopenharmony_ci return {label: name + " (freed)", type: 'number'}; 871cb0ef41Sopenharmony_ci }); 881cb0ef41Sopenharmony_ci 891cb0ef41Sopenharmony_ci default: 901cb0ef41Sopenharmony_ci // Don't show detailed per-zone information. 911cb0ef41Sopenharmony_ci return []; 921cb0ef41Sopenharmony_ci } 931cb0ef41Sopenharmony_ci } 941cb0ef41Sopenharmony_ci 951cb0ef41Sopenharmony_ci getTotalsData() { 961cb0ef41Sopenharmony_ci const isolate_data = this.data[this.selection.isolate]; 971cb0ef41Sopenharmony_ci const labels = [ 981cb0ef41Sopenharmony_ci { label: "Time", type: "number" }, 991cb0ef41Sopenharmony_ci { label: "Total allocated", type: "number" }, 1001cb0ef41Sopenharmony_ci { label: "Total used", type: "number" }, 1011cb0ef41Sopenharmony_ci { label: "Total freed", type: "number" }, 1021cb0ef41Sopenharmony_ci ]; 1031cb0ef41Sopenharmony_ci const chart_data = [labels]; 1041cb0ef41Sopenharmony_ci 1051cb0ef41Sopenharmony_ci const timeStart = this.selection.timeStart; 1061cb0ef41Sopenharmony_ci const timeEnd = this.selection.timeEnd; 1071cb0ef41Sopenharmony_ci const filter_entries = timeStart > 0 || timeEnd > 0; 1081cb0ef41Sopenharmony_ci 1091cb0ef41Sopenharmony_ci for (const [time, zone_data] of isolate_data.samples) { 1101cb0ef41Sopenharmony_ci if (filter_entries && (time < timeStart || time > timeEnd)) continue; 1111cb0ef41Sopenharmony_ci const data = []; 1121cb0ef41Sopenharmony_ci data.push(time * kMillis2Seconds); 1131cb0ef41Sopenharmony_ci data.push(zone_data.allocated / KB); 1141cb0ef41Sopenharmony_ci data.push(zone_data.used / KB); 1151cb0ef41Sopenharmony_ci data.push(zone_data.freed / KB); 1161cb0ef41Sopenharmony_ci chart_data.push(data); 1171cb0ef41Sopenharmony_ci } 1181cb0ef41Sopenharmony_ci return chart_data; 1191cb0ef41Sopenharmony_ci } 1201cb0ef41Sopenharmony_ci 1211cb0ef41Sopenharmony_ci getZoneData() { 1221cb0ef41Sopenharmony_ci const isolate_data = this.data[this.selection.isolate]; 1231cb0ef41Sopenharmony_ci const selected_zones = this.selection.zones; 1241cb0ef41Sopenharmony_ci const zone_names = isolate_data.sorted_zone_names.filter( 1251cb0ef41Sopenharmony_ci zone_name => selected_zones.has(zone_name)); 1261cb0ef41Sopenharmony_ci const data_kind = this.selection.data_kind; 1271cb0ef41Sopenharmony_ci const show_totals = this.selection.show_totals; 1281cb0ef41Sopenharmony_ci const zones_labels = this.getZoneLabels(zone_names); 1291cb0ef41Sopenharmony_ci 1301cb0ef41Sopenharmony_ci const totals_labels = show_totals 1311cb0ef41Sopenharmony_ci ? [ 1321cb0ef41Sopenharmony_ci { label: "Total allocated", type: "number" }, 1331cb0ef41Sopenharmony_ci { label: "Total used", type: "number" }, 1341cb0ef41Sopenharmony_ci { label: "Total freed", type: "number" }, 1351cb0ef41Sopenharmony_ci ] 1361cb0ef41Sopenharmony_ci : []; 1371cb0ef41Sopenharmony_ci 1381cb0ef41Sopenharmony_ci const labels = [ 1391cb0ef41Sopenharmony_ci { label: "Time", type: "number" }, 1401cb0ef41Sopenharmony_ci ...totals_labels, 1411cb0ef41Sopenharmony_ci ...zones_labels, 1421cb0ef41Sopenharmony_ci ]; 1431cb0ef41Sopenharmony_ci const chart_data = [labels]; 1441cb0ef41Sopenharmony_ci 1451cb0ef41Sopenharmony_ci const timeStart = this.selection.timeStart; 1461cb0ef41Sopenharmony_ci const timeEnd = this.selection.timeEnd; 1471cb0ef41Sopenharmony_ci const filter_entries = timeStart > 0 || timeEnd > 0; 1481cb0ef41Sopenharmony_ci 1491cb0ef41Sopenharmony_ci for (const [time, zone_data] of isolate_data.samples) { 1501cb0ef41Sopenharmony_ci if (filter_entries && (time < timeStart || time > timeEnd)) continue; 1511cb0ef41Sopenharmony_ci const active_zone_stats = Object.create(null); 1521cb0ef41Sopenharmony_ci if (zone_data.zones !== undefined) { 1531cb0ef41Sopenharmony_ci for (const [zone_name, zone_stats] of zone_data.zones) { 1541cb0ef41Sopenharmony_ci if (!selected_zones.has(zone_name)) continue; // Not selected, skip. 1551cb0ef41Sopenharmony_ci 1561cb0ef41Sopenharmony_ci const current_stats = active_zone_stats[zone_name]; 1571cb0ef41Sopenharmony_ci if (current_stats === undefined) { 1581cb0ef41Sopenharmony_ci active_zone_stats[zone_name] = 1591cb0ef41Sopenharmony_ci { allocated: zone_stats.allocated, 1601cb0ef41Sopenharmony_ci used: zone_stats.used, 1611cb0ef41Sopenharmony_ci freed: zone_stats.freed, 1621cb0ef41Sopenharmony_ci }; 1631cb0ef41Sopenharmony_ci } else { 1641cb0ef41Sopenharmony_ci // We've got two zones with the same name. 1651cb0ef41Sopenharmony_ci console.log("=== Duplicate zone names: " + zone_name); 1661cb0ef41Sopenharmony_ci // Sum stats. 1671cb0ef41Sopenharmony_ci current_stats.allocated += zone_stats.allocated; 1681cb0ef41Sopenharmony_ci current_stats.used += zone_stats.used; 1691cb0ef41Sopenharmony_ci current_stats.freed += zone_stats.freed; 1701cb0ef41Sopenharmony_ci } 1711cb0ef41Sopenharmony_ci } 1721cb0ef41Sopenharmony_ci } 1731cb0ef41Sopenharmony_ci 1741cb0ef41Sopenharmony_ci const data = []; 1751cb0ef41Sopenharmony_ci data.push(time * kMillis2Seconds); 1761cb0ef41Sopenharmony_ci if (show_totals) { 1771cb0ef41Sopenharmony_ci data.push(zone_data.allocated / KB); 1781cb0ef41Sopenharmony_ci data.push(zone_data.used / KB); 1791cb0ef41Sopenharmony_ci data.push(zone_data.freed / KB); 1801cb0ef41Sopenharmony_ci } 1811cb0ef41Sopenharmony_ci 1821cb0ef41Sopenharmony_ci zone_names.forEach(zone => { 1831cb0ef41Sopenharmony_ci const sample = active_zone_stats[zone]; 1841cb0ef41Sopenharmony_ci let value = null; 1851cb0ef41Sopenharmony_ci if (sample !== undefined) { 1861cb0ef41Sopenharmony_ci if (data_kind == KIND_ALLOCATED_MEMORY) { 1871cb0ef41Sopenharmony_ci value = sample.allocated / KB; 1881cb0ef41Sopenharmony_ci } else if (data_kind == KIND_FREED_MEMORY) { 1891cb0ef41Sopenharmony_ci value = sample.freed / KB; 1901cb0ef41Sopenharmony_ci } else { 1911cb0ef41Sopenharmony_ci // KIND_USED_MEMORY 1921cb0ef41Sopenharmony_ci value = sample.used / KB; 1931cb0ef41Sopenharmony_ci } 1941cb0ef41Sopenharmony_ci } 1951cb0ef41Sopenharmony_ci data.push(value); 1961cb0ef41Sopenharmony_ci }); 1971cb0ef41Sopenharmony_ci chart_data.push(data); 1981cb0ef41Sopenharmony_ci } 1991cb0ef41Sopenharmony_ci return chart_data; 2001cb0ef41Sopenharmony_ci } 2011cb0ef41Sopenharmony_ci 2021cb0ef41Sopenharmony_ci getCategoryData() { 2031cb0ef41Sopenharmony_ci const isolate_data = this.data[this.selection.isolate]; 2041cb0ef41Sopenharmony_ci const categories = Object.keys(this.selection.categories); 2051cb0ef41Sopenharmony_ci const categories_names = 2061cb0ef41Sopenharmony_ci categories.map(k => this.selection.category_names.get(k)); 2071cb0ef41Sopenharmony_ci const selected_zones = this.selection.zones; 2081cb0ef41Sopenharmony_ci const data_kind = this.selection.data_kind; 2091cb0ef41Sopenharmony_ci const show_totals = this.selection.show_totals; 2101cb0ef41Sopenharmony_ci 2111cb0ef41Sopenharmony_ci const categories_labels = this.getZoneLabels(categories_names); 2121cb0ef41Sopenharmony_ci 2131cb0ef41Sopenharmony_ci const totals_labels = show_totals 2141cb0ef41Sopenharmony_ci ? [ 2151cb0ef41Sopenharmony_ci { label: "Total allocated", type: "number" }, 2161cb0ef41Sopenharmony_ci { label: "Total used", type: "number" }, 2171cb0ef41Sopenharmony_ci { label: "Total freed", type: "number" }, 2181cb0ef41Sopenharmony_ci ] 2191cb0ef41Sopenharmony_ci : []; 2201cb0ef41Sopenharmony_ci 2211cb0ef41Sopenharmony_ci const labels = [ 2221cb0ef41Sopenharmony_ci { label: "Time", type: "number" }, 2231cb0ef41Sopenharmony_ci ...totals_labels, 2241cb0ef41Sopenharmony_ci ...categories_labels, 2251cb0ef41Sopenharmony_ci ]; 2261cb0ef41Sopenharmony_ci const chart_data = [labels]; 2271cb0ef41Sopenharmony_ci 2281cb0ef41Sopenharmony_ci const timeStart = this.selection.timeStart; 2291cb0ef41Sopenharmony_ci const timeEnd = this.selection.timeEnd; 2301cb0ef41Sopenharmony_ci const filter_entries = timeStart > 0 || timeEnd > 0; 2311cb0ef41Sopenharmony_ci 2321cb0ef41Sopenharmony_ci for (const [time, zone_data] of isolate_data.samples) { 2331cb0ef41Sopenharmony_ci if (filter_entries && (time < timeStart || time > timeEnd)) continue; 2341cb0ef41Sopenharmony_ci const active_category_stats = Object.create(null); 2351cb0ef41Sopenharmony_ci if (zone_data.zones !== undefined) { 2361cb0ef41Sopenharmony_ci for (const [zone_name, zone_stats] of zone_data.zones) { 2371cb0ef41Sopenharmony_ci const category = selected_zones.get(zone_name); 2381cb0ef41Sopenharmony_ci if (category === undefined) continue; // Zone was not selected. 2391cb0ef41Sopenharmony_ci 2401cb0ef41Sopenharmony_ci const current_stats = active_category_stats[category]; 2411cb0ef41Sopenharmony_ci if (current_stats === undefined) { 2421cb0ef41Sopenharmony_ci active_category_stats[category] = 2431cb0ef41Sopenharmony_ci { allocated: zone_stats.allocated, 2441cb0ef41Sopenharmony_ci used: zone_stats.used, 2451cb0ef41Sopenharmony_ci freed: zone_stats.freed, 2461cb0ef41Sopenharmony_ci }; 2471cb0ef41Sopenharmony_ci } else { 2481cb0ef41Sopenharmony_ci // Sum stats. 2491cb0ef41Sopenharmony_ci current_stats.allocated += zone_stats.allocated; 2501cb0ef41Sopenharmony_ci current_stats.used += zone_stats.used; 2511cb0ef41Sopenharmony_ci current_stats.freed += zone_stats.freed; 2521cb0ef41Sopenharmony_ci } 2531cb0ef41Sopenharmony_ci } 2541cb0ef41Sopenharmony_ci } 2551cb0ef41Sopenharmony_ci 2561cb0ef41Sopenharmony_ci const data = []; 2571cb0ef41Sopenharmony_ci data.push(time * kMillis2Seconds); 2581cb0ef41Sopenharmony_ci if (show_totals) { 2591cb0ef41Sopenharmony_ci data.push(zone_data.allocated / KB); 2601cb0ef41Sopenharmony_ci data.push(zone_data.used / KB); 2611cb0ef41Sopenharmony_ci data.push(zone_data.freed / KB); 2621cb0ef41Sopenharmony_ci } 2631cb0ef41Sopenharmony_ci 2641cb0ef41Sopenharmony_ci categories.forEach(category => { 2651cb0ef41Sopenharmony_ci const sample = active_category_stats[category]; 2661cb0ef41Sopenharmony_ci let value = null; 2671cb0ef41Sopenharmony_ci if (sample !== undefined) { 2681cb0ef41Sopenharmony_ci if (data_kind == KIND_ALLOCATED_MEMORY) { 2691cb0ef41Sopenharmony_ci value = sample.allocated / KB; 2701cb0ef41Sopenharmony_ci } else if (data_kind == KIND_FREED_MEMORY) { 2711cb0ef41Sopenharmony_ci value = sample.freed / KB; 2721cb0ef41Sopenharmony_ci } else { 2731cb0ef41Sopenharmony_ci // KIND_USED_MEMORY 2741cb0ef41Sopenharmony_ci value = sample.used / KB; 2751cb0ef41Sopenharmony_ci } 2761cb0ef41Sopenharmony_ci } 2771cb0ef41Sopenharmony_ci data.push(value); 2781cb0ef41Sopenharmony_ci }); 2791cb0ef41Sopenharmony_ci chart_data.push(data); 2801cb0ef41Sopenharmony_ci } 2811cb0ef41Sopenharmony_ci return chart_data; 2821cb0ef41Sopenharmony_ci } 2831cb0ef41Sopenharmony_ci 2841cb0ef41Sopenharmony_ci getChartData() { 2851cb0ef41Sopenharmony_ci switch (this.selection.data_view) { 2861cb0ef41Sopenharmony_ci case VIEW_BY_ZONE_NAME: 2871cb0ef41Sopenharmony_ci return this.getZoneData(); 2881cb0ef41Sopenharmony_ci case VIEW_BY_ZONE_CATEGORY: 2891cb0ef41Sopenharmony_ci return this.getCategoryData(); 2901cb0ef41Sopenharmony_ci case VIEW_TOTALS: 2911cb0ef41Sopenharmony_ci default: 2921cb0ef41Sopenharmony_ci return this.getTotalsData(); 2931cb0ef41Sopenharmony_ci } 2941cb0ef41Sopenharmony_ci } 2951cb0ef41Sopenharmony_ci 2961cb0ef41Sopenharmony_ci getChartOptions() { 2971cb0ef41Sopenharmony_ci const options = { 2981cb0ef41Sopenharmony_ci isStacked: true, 2991cb0ef41Sopenharmony_ci interpolateNulls: true, 3001cb0ef41Sopenharmony_ci hAxis: { 3011cb0ef41Sopenharmony_ci format: '###.##s', 3021cb0ef41Sopenharmony_ci title: 'Time [s]', 3031cb0ef41Sopenharmony_ci }, 3041cb0ef41Sopenharmony_ci vAxis: { 3051cb0ef41Sopenharmony_ci format: '#,###KB', 3061cb0ef41Sopenharmony_ci title: 'Memory consumption [KBytes]' 3071cb0ef41Sopenharmony_ci }, 3081cb0ef41Sopenharmony_ci chartArea: {left:100, width: '85%', height: '70%'}, 3091cb0ef41Sopenharmony_ci legend: {position: 'top', maxLines: '1'}, 3101cb0ef41Sopenharmony_ci pointsVisible: true, 3111cb0ef41Sopenharmony_ci pointSize: 3, 3121cb0ef41Sopenharmony_ci explorer: {}, 3131cb0ef41Sopenharmony_ci }; 3141cb0ef41Sopenharmony_ci 3151cb0ef41Sopenharmony_ci // Overlay total allocated/used points on top of the graph. 3161cb0ef41Sopenharmony_ci const series = {} 3171cb0ef41Sopenharmony_ci if (this.selection.data_view == VIEW_TOTALS) { 3181cb0ef41Sopenharmony_ci series[0] = {type: 'line', color: "red"}; 3191cb0ef41Sopenharmony_ci series[1] = {type: 'line', color: "blue"}; 3201cb0ef41Sopenharmony_ci series[2] = {type: 'line', color: "orange"}; 3211cb0ef41Sopenharmony_ci } else if (this.selection.show_totals) { 3221cb0ef41Sopenharmony_ci series[0] = {type: 'line', color: "red", lineDashStyle: [13, 13]}; 3231cb0ef41Sopenharmony_ci series[1] = {type: 'line', color: "blue", lineDashStyle: [13, 13]}; 3241cb0ef41Sopenharmony_ci series[2] = {type: 'line', color: "orange", lineDashStyle: [13, 13]}; 3251cb0ef41Sopenharmony_ci } 3261cb0ef41Sopenharmony_ci return Object.assign(options, {series: series}); 3271cb0ef41Sopenharmony_ci } 3281cb0ef41Sopenharmony_ci 3291cb0ef41Sopenharmony_ci drawChart() { 3301cb0ef41Sopenharmony_ci console.assert(this.data, 'invalid data'); 3311cb0ef41Sopenharmony_ci console.assert(this.selection, 'invalid selection'); 3321cb0ef41Sopenharmony_ci 3331cb0ef41Sopenharmony_ci const chart_data = this.getChartData(); 3341cb0ef41Sopenharmony_ci 3351cb0ef41Sopenharmony_ci const data = google.visualization.arrayToDataTable(chart_data); 3361cb0ef41Sopenharmony_ci const options = this.getChartOptions(); 3371cb0ef41Sopenharmony_ci const chart = new google.visualization.AreaChart(this.$('#chart')); 3381cb0ef41Sopenharmony_ci this.show(); 3391cb0ef41Sopenharmony_ci chart.draw(data, google.charts.Line.convertOptions(options)); 3401cb0ef41Sopenharmony_ci } 3411cb0ef41Sopenharmony_ci}); 342