257b0a43ac
Design doc: https://docs.google.com/document/d/1rxM3sDd-ZiOLznqw7MvYraulAPWJSVqC_CztO4YpUTQ/edit Change-Id: I471ff31f32b7bdd22cb03005c1dcc18aa485ad77 Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3313793 Auto-Submit: Jianxiao Lu <jianxiao.lu@intel.com> Reviewed-by: Camillo Bruni <cbruni@chromium.org> Commit-Queue: Shiyu Zhang <shiyu.zhang@intel.com> Cr-Commit-Position: refs/heads/main@{#78428}
226 lines
5.7 KiB
JavaScript
226 lines
5.7 KiB
JavaScript
// Copyright 2021 the V8 project authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
// found in the LICENSE file.
|
|
|
|
import {GB, MB} from '../js/helper.mjs';
|
|
import {DOM} from '../js/web-api-helper.mjs';
|
|
|
|
import {getColorFromSpaceName, kSpaceNames} from './space-categories.mjs';
|
|
|
|
DOM.defineCustomElement('heap-layout-viewer',
|
|
(templateText) =>
|
|
class HeapLayoutViewer extends HTMLElement {
|
|
constructor() {
|
|
super();
|
|
const shadowRoot = this.attachShadow({mode: 'open'});
|
|
shadowRoot.innerHTML = templateText;
|
|
this.chart = echarts.init(this.$('#chart'), null, {
|
|
renderer: 'canvas',
|
|
});
|
|
window.addEventListener('resize', () => {
|
|
this.chart.resize();
|
|
});
|
|
this.currentIndex = 0;
|
|
}
|
|
|
|
$(id) {
|
|
return this.shadowRoot.querySelector(id);
|
|
}
|
|
|
|
set data(value) {
|
|
this._data = value;
|
|
this.stateChanged();
|
|
}
|
|
|
|
get data() {
|
|
return this._data;
|
|
}
|
|
|
|
hide() {
|
|
this.$('#container').style.display = 'none';
|
|
}
|
|
|
|
show() {
|
|
this.$('#container').style.display = 'block';
|
|
}
|
|
|
|
stateChanged() {
|
|
this.drawChart(0);
|
|
}
|
|
|
|
getChartTitle(index) {
|
|
return this.data[index].header;
|
|
}
|
|
|
|
getSeriesData(pageinfos) {
|
|
let ret = [];
|
|
for (let pageinfo of pageinfos) {
|
|
ret.push({value: pageinfo});
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
getChartSeries(index) {
|
|
const snapshot = this.data[index];
|
|
let series = [];
|
|
for (const [space_name, pageinfos] of Object.entries(snapshot.data)) {
|
|
let space_series = {
|
|
name: space_name,
|
|
type: 'custom',
|
|
renderItem(params, api) {
|
|
const addressBegin = api.value(1);
|
|
const addressEnd = api.value(2);
|
|
const allocated = api.value(3);
|
|
const start = api.coord([addressBegin, 0]);
|
|
const end = api.coord([addressEnd, 0]);
|
|
|
|
const allocatedRate = allocated / (addressEnd - addressBegin);
|
|
const unAllocatedRate = 1 - allocatedRate;
|
|
|
|
const standardH = api.size([0, 1])[1];
|
|
const standardY = start[1] - standardH / 2;
|
|
|
|
const allocatedY = standardY + standardH * unAllocatedRate;
|
|
const allocatedH = standardH * allocatedRate;
|
|
|
|
const unAllocatedY = standardY;
|
|
const unAllocatedH = standardH - allocatedH;
|
|
|
|
const allocatedShape = echarts.graphic.clipRectByRect(
|
|
{
|
|
x: start[0],
|
|
y: allocatedY,
|
|
width: end[0] - start[0],
|
|
height: allocatedH,
|
|
},
|
|
{
|
|
x: params.coordSys.x,
|
|
y: params.coordSys.y,
|
|
width: params.coordSys.width,
|
|
height: params.coordSys.height,
|
|
});
|
|
|
|
const unAllocatedShape = echarts.graphic.clipRectByRect(
|
|
{
|
|
x: start[0],
|
|
y: unAllocatedY,
|
|
width: end[0] - start[0],
|
|
height: unAllocatedH,
|
|
},
|
|
{
|
|
x: params.coordSys.x,
|
|
y: params.coordSys.y,
|
|
width: params.coordSys.width,
|
|
height: params.coordSys.height,
|
|
});
|
|
|
|
const ret = {
|
|
type: 'group',
|
|
children: [
|
|
{
|
|
type: 'rect',
|
|
shape: allocatedShape,
|
|
style: api.style(),
|
|
},
|
|
{
|
|
type: 'rect',
|
|
shape: unAllocatedShape,
|
|
style: {
|
|
fill: '#000000',
|
|
},
|
|
},
|
|
],
|
|
};
|
|
return ret;
|
|
},
|
|
data: this.getSeriesData(pageinfos),
|
|
encode: {
|
|
x: [1, 2],
|
|
},
|
|
itemStyle: {
|
|
color: getColorFromSpaceName(space_name),
|
|
},
|
|
};
|
|
series.push(space_series);
|
|
}
|
|
return series;
|
|
}
|
|
|
|
drawChart(index) {
|
|
if (index >= this.data.length || index < 0) {
|
|
console.error('Invalid index:', index);
|
|
return;
|
|
}
|
|
const option = {
|
|
tooltip: {
|
|
formatter(params) {
|
|
const ret = params.marker + params.value[0] + '<br>' +
|
|
'address:' + (params.value[1] / MB).toFixed(3) + 'MB' +
|
|
'<br>' +
|
|
'size:' + ((params.value[2] - params.value[1]) / MB).toFixed(3) +
|
|
'MB' +
|
|
'<br>' +
|
|
'allocated:' + (params.value[3] / MB).toFixed(3) + 'MB' +
|
|
'<br>' +
|
|
'wasted:' + params.value[4] + 'B';
|
|
return ret;
|
|
},
|
|
},
|
|
grid: {
|
|
bottom: 120,
|
|
top: 120,
|
|
},
|
|
dataZoom: [
|
|
{
|
|
type: 'slider',
|
|
filterMode: 'weakFilter',
|
|
showDataShadow: true,
|
|
labelFormatter: '',
|
|
},
|
|
{
|
|
type: 'inside',
|
|
filterMode: 'weakFilter',
|
|
},
|
|
],
|
|
legend: {
|
|
show: true,
|
|
data: kSpaceNames,
|
|
top: '6%',
|
|
type: 'scroll',
|
|
},
|
|
title: {
|
|
text: this.getChartTitle(index),
|
|
left: 'center',
|
|
},
|
|
xAxis: {
|
|
name: 'Address offset in heap(MB)',
|
|
nameLocation: 'center',
|
|
nameTextStyle: {
|
|
fontSize: 25,
|
|
padding: [30, 0, 50, 0],
|
|
},
|
|
type: 'value',
|
|
min: 0,
|
|
max: 4 * GB,
|
|
axisLabel: {
|
|
rotate: 0,
|
|
formatter(value, index) {
|
|
value = value / MB;
|
|
value = value.toFixed(3);
|
|
return value;
|
|
},
|
|
},
|
|
},
|
|
yAxis: {
|
|
data: ['Page'],
|
|
},
|
|
series: this.getChartSeries(index),
|
|
};
|
|
|
|
this.show();
|
|
this.chart.resize();
|
|
this.chart.setOption(option);
|
|
this.currentIndex = index;
|
|
}
|
|
});
|