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 {MB} from '../js/helper.mjs'; 61cb0ef41Sopenharmony_ciimport {DOM} from '../js/web-api-helper.mjs'; 71cb0ef41Sopenharmony_ci 81cb0ef41Sopenharmony_ciimport {getColorFromSpaceName, kSpaceNames} from './space-categories.mjs'; 91cb0ef41Sopenharmony_ci 101cb0ef41Sopenharmony_ciclass TrendLineHelper { 111cb0ef41Sopenharmony_ci static re_gc_count = /(?<=(Before|After) GC:)\d+(?=,)/; 121cb0ef41Sopenharmony_ci static re_allocated = /allocated/; 131cb0ef41Sopenharmony_ci static re_space_name = /^[a-z_]+_space/; 141cb0ef41Sopenharmony_ci 151cb0ef41Sopenharmony_ci static snapshotHeaderToXLabel(header) { 161cb0ef41Sopenharmony_ci const gc_count = this.re_gc_count.exec(header)[0]; 171cb0ef41Sopenharmony_ci const alpha = header[0]; 181cb0ef41Sopenharmony_ci return alpha + gc_count; 191cb0ef41Sopenharmony_ci } 201cb0ef41Sopenharmony_ci 211cb0ef41Sopenharmony_ci static getLineSymbolFromTrendLineName(trend_line_name) { 221cb0ef41Sopenharmony_ci const is_allocated_line = this.re_allocated.test(trend_line_name); 231cb0ef41Sopenharmony_ci if (is_allocated_line) { 241cb0ef41Sopenharmony_ci return 'emptyTriangle'; 251cb0ef41Sopenharmony_ci } 261cb0ef41Sopenharmony_ci return 'emptyCircle'; 271cb0ef41Sopenharmony_ci } 281cb0ef41Sopenharmony_ci 291cb0ef41Sopenharmony_ci static getSizeTrendLineName(space_name) { 301cb0ef41Sopenharmony_ci return space_name + ' size'; 311cb0ef41Sopenharmony_ci } 321cb0ef41Sopenharmony_ci 331cb0ef41Sopenharmony_ci static getAllocatedTrendSizeName(space_name) { 341cb0ef41Sopenharmony_ci return space_name + ' allocated'; 351cb0ef41Sopenharmony_ci } 361cb0ef41Sopenharmony_ci 371cb0ef41Sopenharmony_ci static getSpaceNameFromTrendLineName(trend_line_name) { 381cb0ef41Sopenharmony_ci const space_name = this.re_space_name.exec(trend_line_name)[0]; 391cb0ef41Sopenharmony_ci return space_name; 401cb0ef41Sopenharmony_ci } 411cb0ef41Sopenharmony_ci} 421cb0ef41Sopenharmony_ci 431cb0ef41Sopenharmony_ciDOM.defineCustomElement('heap-size-trend-viewer', 441cb0ef41Sopenharmony_ci (templateText) => 451cb0ef41Sopenharmony_ci class HeapSizeTrendViewer extends HTMLElement { 461cb0ef41Sopenharmony_ci constructor() { 471cb0ef41Sopenharmony_ci super(); 481cb0ef41Sopenharmony_ci const shadowRoot = this.attachShadow({mode: 'open'}); 491cb0ef41Sopenharmony_ci shadowRoot.innerHTML = templateText; 501cb0ef41Sopenharmony_ci this.chart = echarts.init(this.$('#chart'), null, { 511cb0ef41Sopenharmony_ci renderer: 'canvas', 521cb0ef41Sopenharmony_ci }); 531cb0ef41Sopenharmony_ci this.chart.getZr().on('click', 'series.line', (params) => { 541cb0ef41Sopenharmony_ci const pointInPixel = [params.offsetX, params.offsetY]; 551cb0ef41Sopenharmony_ci const pointInGrid = 561cb0ef41Sopenharmony_ci this.chart.convertFromPixel({seriesIndex: 0}, pointInPixel); 571cb0ef41Sopenharmony_ci const xIndex = pointInGrid[0]; 581cb0ef41Sopenharmony_ci this.dispatchEvent(new CustomEvent('change', { 591cb0ef41Sopenharmony_ci bubbles: true, 601cb0ef41Sopenharmony_ci composed: true, 611cb0ef41Sopenharmony_ci detail: xIndex, 621cb0ef41Sopenharmony_ci })); 631cb0ef41Sopenharmony_ci this.setXMarkLine(xIndex); 641cb0ef41Sopenharmony_ci }); 651cb0ef41Sopenharmony_ci this.chartXAxisData = null; 661cb0ef41Sopenharmony_ci this.chartSeriesData = null; 671cb0ef41Sopenharmony_ci this.currentIndex = 0; 681cb0ef41Sopenharmony_ci window.addEventListener('resize', () => { 691cb0ef41Sopenharmony_ci this.chart.resize(); 701cb0ef41Sopenharmony_ci }); 711cb0ef41Sopenharmony_ci } 721cb0ef41Sopenharmony_ci 731cb0ef41Sopenharmony_ci $(id) { 741cb0ef41Sopenharmony_ci return this.shadowRoot.querySelector(id); 751cb0ef41Sopenharmony_ci } 761cb0ef41Sopenharmony_ci 771cb0ef41Sopenharmony_ci set data(value) { 781cb0ef41Sopenharmony_ci this._data = value; 791cb0ef41Sopenharmony_ci this.stateChanged(); 801cb0ef41Sopenharmony_ci } 811cb0ef41Sopenharmony_ci 821cb0ef41Sopenharmony_ci get data() { 831cb0ef41Sopenharmony_ci return this._data; 841cb0ef41Sopenharmony_ci } 851cb0ef41Sopenharmony_ci 861cb0ef41Sopenharmony_ci hide() { 871cb0ef41Sopenharmony_ci this.$('#container').style.display = 'none'; 881cb0ef41Sopenharmony_ci } 891cb0ef41Sopenharmony_ci 901cb0ef41Sopenharmony_ci show() { 911cb0ef41Sopenharmony_ci this.$('#container').style.display = 'block'; 921cb0ef41Sopenharmony_ci } 931cb0ef41Sopenharmony_ci 941cb0ef41Sopenharmony_ci stateChanged() { 951cb0ef41Sopenharmony_ci this.initTrendLineNames(); 961cb0ef41Sopenharmony_ci this.initXAxisDataAndSeries(); 971cb0ef41Sopenharmony_ci this.drawChart(); 981cb0ef41Sopenharmony_ci } 991cb0ef41Sopenharmony_ci 1001cb0ef41Sopenharmony_ci initTrendLineNames() { 1011cb0ef41Sopenharmony_ci this.trend_line_names = []; 1021cb0ef41Sopenharmony_ci for (const space_name of kSpaceNames) { 1031cb0ef41Sopenharmony_ci this.trend_line_names.push( 1041cb0ef41Sopenharmony_ci TrendLineHelper.getSizeTrendLineName(space_name)); 1051cb0ef41Sopenharmony_ci this.trend_line_names.push( 1061cb0ef41Sopenharmony_ci TrendLineHelper.getAllocatedTrendSizeName(space_name)); 1071cb0ef41Sopenharmony_ci } 1081cb0ef41Sopenharmony_ci } 1091cb0ef41Sopenharmony_ci 1101cb0ef41Sopenharmony_ci // X axis represent the moment before or after nth GC : [B1,A1,...Bn,An]. 1111cb0ef41Sopenharmony_ci initXAxisDataAndSeries() { 1121cb0ef41Sopenharmony_ci this.chartXAxisData = []; 1131cb0ef41Sopenharmony_ci this.chartSeriesData = []; 1141cb0ef41Sopenharmony_ci let trend_line_name_data_dict = {}; 1151cb0ef41Sopenharmony_ci 1161cb0ef41Sopenharmony_ci for (const trend_line_name of this.trend_line_names) { 1171cb0ef41Sopenharmony_ci trend_line_name_data_dict[trend_line_name] = []; 1181cb0ef41Sopenharmony_ci } 1191cb0ef41Sopenharmony_ci 1201cb0ef41Sopenharmony_ci // Init x axis data and trend line series. 1211cb0ef41Sopenharmony_ci for (const snapshot of this.data) { 1221cb0ef41Sopenharmony_ci this.chartXAxisData.push( 1231cb0ef41Sopenharmony_ci TrendLineHelper.snapshotHeaderToXLabel(snapshot.header)); 1241cb0ef41Sopenharmony_ci for (const [space_name, pageinfos] of Object.entries(snapshot.data)) { 1251cb0ef41Sopenharmony_ci const size_trend_line_name = 1261cb0ef41Sopenharmony_ci TrendLineHelper.getSizeTrendLineName(space_name); 1271cb0ef41Sopenharmony_ci const allocated_trend_line_name = 1281cb0ef41Sopenharmony_ci TrendLineHelper.getAllocatedTrendSizeName(space_name); 1291cb0ef41Sopenharmony_ci let size_sum = 0; 1301cb0ef41Sopenharmony_ci let allocated_sum = 0; 1311cb0ef41Sopenharmony_ci for (const pageinfo of pageinfos) { 1321cb0ef41Sopenharmony_ci size_sum += pageinfo[2] - pageinfo[1]; 1331cb0ef41Sopenharmony_ci allocated_sum += pageinfo[3]; 1341cb0ef41Sopenharmony_ci } 1351cb0ef41Sopenharmony_ci trend_line_name_data_dict[size_trend_line_name].push(size_sum); 1361cb0ef41Sopenharmony_ci trend_line_name_data_dict[allocated_trend_line_name].push( 1371cb0ef41Sopenharmony_ci allocated_sum); 1381cb0ef41Sopenharmony_ci } 1391cb0ef41Sopenharmony_ci } 1401cb0ef41Sopenharmony_ci 1411cb0ef41Sopenharmony_ci // Init mark line series as the first series 1421cb0ef41Sopenharmony_ci const markline_series = { 1431cb0ef41Sopenharmony_ci name: 'mark-line', 1441cb0ef41Sopenharmony_ci type: 'line', 1451cb0ef41Sopenharmony_ci 1461cb0ef41Sopenharmony_ci markLine: { 1471cb0ef41Sopenharmony_ci silent: true, 1481cb0ef41Sopenharmony_ci symbol: 'none', 1491cb0ef41Sopenharmony_ci label: { 1501cb0ef41Sopenharmony_ci show: false, 1511cb0ef41Sopenharmony_ci }, 1521cb0ef41Sopenharmony_ci lineStyle: { 1531cb0ef41Sopenharmony_ci color: '#333', 1541cb0ef41Sopenharmony_ci }, 1551cb0ef41Sopenharmony_ci data: [ 1561cb0ef41Sopenharmony_ci { 1571cb0ef41Sopenharmony_ci xAxis: 0, 1581cb0ef41Sopenharmony_ci }, 1591cb0ef41Sopenharmony_ci ], 1601cb0ef41Sopenharmony_ci }, 1611cb0ef41Sopenharmony_ci }; 1621cb0ef41Sopenharmony_ci this.chartSeriesData.push(markline_series); 1631cb0ef41Sopenharmony_ci 1641cb0ef41Sopenharmony_ci for (const [trend_line_name, trend_line_data] of Object.entries( 1651cb0ef41Sopenharmony_ci trend_line_name_data_dict)) { 1661cb0ef41Sopenharmony_ci const color = getColorFromSpaceName( 1671cb0ef41Sopenharmony_ci TrendLineHelper.getSpaceNameFromTrendLineName(trend_line_name)); 1681cb0ef41Sopenharmony_ci const trend_line_series = { 1691cb0ef41Sopenharmony_ci name: trend_line_name, 1701cb0ef41Sopenharmony_ci type: 'line', 1711cb0ef41Sopenharmony_ci data: trend_line_data, 1721cb0ef41Sopenharmony_ci lineStyle: { 1731cb0ef41Sopenharmony_ci color: color, 1741cb0ef41Sopenharmony_ci }, 1751cb0ef41Sopenharmony_ci itemStyle: { 1761cb0ef41Sopenharmony_ci color: color, 1771cb0ef41Sopenharmony_ci }, 1781cb0ef41Sopenharmony_ci symbol: TrendLineHelper.getLineSymbolFromTrendLineName(trend_line_name), 1791cb0ef41Sopenharmony_ci symbolSize: 8, 1801cb0ef41Sopenharmony_ci }; 1811cb0ef41Sopenharmony_ci this.chartSeriesData.push(trend_line_series); 1821cb0ef41Sopenharmony_ci } 1831cb0ef41Sopenharmony_ci } 1841cb0ef41Sopenharmony_ci 1851cb0ef41Sopenharmony_ci setXMarkLine(index) { 1861cb0ef41Sopenharmony_ci if (index < 0 || index >= this.data.length) { 1871cb0ef41Sopenharmony_ci console.error('Invalid index:', index); 1881cb0ef41Sopenharmony_ci return; 1891cb0ef41Sopenharmony_ci } 1901cb0ef41Sopenharmony_ci // Set the mark-line series 1911cb0ef41Sopenharmony_ci this.chartSeriesData[0].markLine.data[0].xAxis = index; 1921cb0ef41Sopenharmony_ci this.chart.setOption({ 1931cb0ef41Sopenharmony_ci series: this.chartSeriesData, 1941cb0ef41Sopenharmony_ci }); 1951cb0ef41Sopenharmony_ci this.currentIndex = index; 1961cb0ef41Sopenharmony_ci } 1971cb0ef41Sopenharmony_ci 1981cb0ef41Sopenharmony_ci drawChart() { 1991cb0ef41Sopenharmony_ci const option = { 2001cb0ef41Sopenharmony_ci dataZoom: [ 2011cb0ef41Sopenharmony_ci { 2021cb0ef41Sopenharmony_ci type: 'inside', 2031cb0ef41Sopenharmony_ci filterMode: 'weakFilter', 2041cb0ef41Sopenharmony_ci }, 2051cb0ef41Sopenharmony_ci { 2061cb0ef41Sopenharmony_ci type: 'slider', 2071cb0ef41Sopenharmony_ci filterMode: 'weakFilter', 2081cb0ef41Sopenharmony_ci labelFormatter: '', 2091cb0ef41Sopenharmony_ci }, 2101cb0ef41Sopenharmony_ci ], 2111cb0ef41Sopenharmony_ci title: { 2121cb0ef41Sopenharmony_ci text: 'Size Trend', 2131cb0ef41Sopenharmony_ci left: 'center', 2141cb0ef41Sopenharmony_ci }, 2151cb0ef41Sopenharmony_ci tooltip: { 2161cb0ef41Sopenharmony_ci trigger: 'axis', 2171cb0ef41Sopenharmony_ci position(point, params, dom, rect, size) { 2181cb0ef41Sopenharmony_ci let ret_x = point[0] + 10; 2191cb0ef41Sopenharmony_ci if (point[0] > size.viewSize[0] * 0.7) { 2201cb0ef41Sopenharmony_ci ret_x = point[0] - dom.clientWidth - 10; 2211cb0ef41Sopenharmony_ci } 2221cb0ef41Sopenharmony_ci return [ret_x, '85%']; 2231cb0ef41Sopenharmony_ci }, 2241cb0ef41Sopenharmony_ci formatter(params) { 2251cb0ef41Sopenharmony_ci const colorSpan = (color) => 2261cb0ef41Sopenharmony_ci '<span style="display:inline-block;margin-right:1px;border-radius:5px;width:9px;height:9px;background-color:' + 2271cb0ef41Sopenharmony_ci color + '"></span>'; 2281cb0ef41Sopenharmony_ci let result = '<p>' + params[0].axisValue + '</p>'; 2291cb0ef41Sopenharmony_ci params.forEach((item) => { 2301cb0ef41Sopenharmony_ci const xx = '<p style="margin:0;">' + colorSpan(item.color) + ' ' + 2311cb0ef41Sopenharmony_ci item.seriesName + ': ' + (item.data / MB).toFixed(2) + 'MB' + 2321cb0ef41Sopenharmony_ci '</p>'; 2331cb0ef41Sopenharmony_ci result += xx; 2341cb0ef41Sopenharmony_ci }); 2351cb0ef41Sopenharmony_ci 2361cb0ef41Sopenharmony_ci return result; 2371cb0ef41Sopenharmony_ci }, 2381cb0ef41Sopenharmony_ci }, 2391cb0ef41Sopenharmony_ci legend: { 2401cb0ef41Sopenharmony_ci data: this.trend_line_names, 2411cb0ef41Sopenharmony_ci top: '6%', 2421cb0ef41Sopenharmony_ci type: 'scroll', 2431cb0ef41Sopenharmony_ci }, 2441cb0ef41Sopenharmony_ci 2451cb0ef41Sopenharmony_ci xAxis: { 2461cb0ef41Sopenharmony_ci minInterval: 1, 2471cb0ef41Sopenharmony_ci type: 'category', 2481cb0ef41Sopenharmony_ci boundaryGap: false, 2491cb0ef41Sopenharmony_ci data: this.chartXAxisData, 2501cb0ef41Sopenharmony_ci }, 2511cb0ef41Sopenharmony_ci yAxis: { 2521cb0ef41Sopenharmony_ci type: 'value', 2531cb0ef41Sopenharmony_ci axisLabel: { 2541cb0ef41Sopenharmony_ci formatter(value, index) { 2551cb0ef41Sopenharmony_ci return (value / MB).toFixed(3) + 'MB'; 2561cb0ef41Sopenharmony_ci }, 2571cb0ef41Sopenharmony_ci }, 2581cb0ef41Sopenharmony_ci }, 2591cb0ef41Sopenharmony_ci 2601cb0ef41Sopenharmony_ci series: this.chartSeriesData, 2611cb0ef41Sopenharmony_ci }; 2621cb0ef41Sopenharmony_ci this.show(); 2631cb0ef41Sopenharmony_ci this.chart.resize(); 2641cb0ef41Sopenharmony_ci this.chart.setOption(option); 2651cb0ef41Sopenharmony_ci } 2661cb0ef41Sopenharmony_ci}); 267