Commit 767c9549 authored by Camillo Bruni's avatar Camillo Bruni Committed by Commit Bot

[tools] Improve HeapStats

- Categorize more instance types
- Fix GC selection dropdown labels
- Show GC times in seconds
- Collapse file reader after loading

Bug: v8:7266
Change-Id: If967ebdb887105e808cfc8fb3bc92f9da5c91fd2
No-Try: true
Reviewed-on: https://chromium-review.googlesource.com/945908Reviewed-by: 's avatarMichael Lippautz <mlippautz@chromium.org>
Commit-Queue: Camillo Bruni <cbruni@chromium.org>
Cr-Commit-Position: refs/heads/master@{#51690}
parent a6f84875
......@@ -15,6 +15,8 @@ const CATEGORIES = new Map([
'EXTERNAL_ONE_BYTE_STRING_TYPE',
'EXTERNAL_STRING_TYPE',
'EXTERNAL_STRING_WITH_ONE_BYTE_DATA_TYPE',
'FIXED_BIGINT64_ARRAY_TYPE',
'FIXED_BIGUINT64_ARRAY_TYPE',
'FIXED_DOUBLE_ARRAY_TYPE',
'FIXED_FLOAT32_ARRAY_TYPE',
'FIXED_FLOAT64_ARRAY_TYPE',
......@@ -49,6 +51,7 @@ const CATEGORIES = new Map([
'JS_GLOBAL_PROXY_TYPE',
'JS_MAP_KEY_VALUE_ITERATOR_TYPE',
'JS_MAP_TYPE',
'JS_MAP_VALUE_ITERATOR_TYPE',
'JS_MESSAGE_OBJECT_TYPE',
'JS_OBJECT_TYPE',
'JS_PROMISE_TYPE',
......@@ -62,9 +65,10 @@ const CATEGORIES = new Map([
'JS_WEAK_MAP_TYPE',
'MUTABLE_HEAP_NUMBER_TYPE',
'NATIVE_CONTEXT_TYPE',
'OBJECT_PROPERTY_DICTIONARY_TYPE',
'ONE_BYTE_INTERNALIZED_STRING_TYPE',
'ONE_BYTE_STRING_TYPE',
'OBJECT_PROPERTY_DICTIONARY_TYPE',
'OTHER_CONTEXT_TYPE',
'PROPERTY_ARRAY_TYPE',
'SHORT_EXTERNAL_INTERNALIZED_STRING_TYPE',
'SHORT_EXTERNAL_ONE_BYTE_INTERNALIZED_STRING_TYPE',
......@@ -143,9 +147,10 @@ const CATEGORIES = new Map([
'CODE_DATA_CONTAINER_TYPE',
'DEOPTIMIZATION_DATA_TYPE',
'EMBEDDED_OBJECT_TYPE',
'FEEDBACK_CELL_TYPE',
'FEEDBACK_METADATA_TYPE',
'FEEDBACK_VECTOR_HEADER_TYPE',
'FEEDBACK_VECTOR_ENTRY_TYPE',
'FEEDBACK_VECTOR_HEADER_TYPE',
'FEEDBACK_VECTOR_SLOT_CALL_TYPE',
'FEEDBACK_VECTOR_SLOT_CALL_UNUSED_TYPE',
'FEEDBACK_VECTOR_SLOT_ENUM_TYPE',
......
......@@ -146,8 +146,8 @@ class DetailsSelection extends HTMLElement {
this.populateSelect(
'#gc-select',
Object.keys(this.selectedIsolate.gcs)
.map(v => [v, this.selectedIsolate.gcs[v].time]),
time => time + 'ms');
.map(id => [id, this.selectedIsolate.gcs[id].time]),
(key, time, index) => index + ': ' + (time * kMillis2Seconds) + 's');
this.populateCategories();
this.notifySelectionChanged();
}
......@@ -249,8 +249,10 @@ class DetailsSelection extends HTMLElement {
populateSelect(id, iterable, labelFn = null, autoselect = null) {
if (labelFn == null) labelFn = e => e;
let index = 0;
for (let [key, value] of iterable) {
const label = labelFn(key, value);
index++;
const label = labelFn(key, value, index);
const option = this.createOption(key, label);
if (autoselect === key) {
option.selected = 'selected';
......
......@@ -4,9 +4,6 @@
'use strict';
const KB = 1024;
const MB = KB * KB;
const global_timeline_template =
document.currentScript.ownerDocument.querySelector(
'#global-timeline-template');
......@@ -70,7 +67,7 @@ class GlobalTimeline extends HTMLElement {
const gc_data = isolate_data.gcs[gc_key];
const data_set = gc_data[this.selection.data_set].instance_type_data;
const data = [];
data.push(gc_data.time);
data.push(gc_data.time * kMillis2Seconds);
Object.values(this.selection.categories).forEach(instance_types => {
data.push(
instance_types
......@@ -96,7 +93,7 @@ class GlobalTimeline extends HTMLElement {
const gc_data = isolate_data.gcs[gc_key];
const data_set = gc_data[this.selection.data_set].instance_type_data;
const data = [];
data.push(gc_data.time);
data.push(gc_data.time * kMillis2Seconds);
instance_types.forEach(instance_type => {
data.push(data_set[instance_type].overall / KB);
});
......@@ -116,10 +113,14 @@ class GlobalTimeline extends HTMLElement {
const options = {
isStacked: true,
hAxis: {
title: 'Time [ms]',
format: '###.##s',
title: 'Time [s]',
},
vAxis: {
format: '#,###KB',
title: 'Memory consumption [KBytes]'
},
vAxis: {title: 'Memory consumption [KBytes]'},
chartArea: {width: '85%', height: '70%'},
chartArea: {left:100, width: '85%', height: '70%'},
legend: {position: 'top', maxLines: '1'},
pointsVisible: true,
pointSize: 5,
......
......@@ -68,13 +68,13 @@ function globalSelectionChangedA(e) {
</head>
<body>
<h1>V8 Heap Statistics</h1>
<trace-file-reader onchange="globalDataChanged(event)"></trace-file-reader>
<details-selection id="details-selection" onchange="globalSelectionChangedA(event)"></details-selection>
<global-timeline id="global-timeline"></global-timeline>
<histogram-viewer id="histogram-viewer"></histogram-viewer>
<h1>V8 Heap Statistics</h1>
<p>Visualize object statistics that have been gathered using</p>
<ul>
<li><code>--trace-gc-object-stats</code> on V8</li>
......@@ -85,6 +85,10 @@ function globalSelectionChangedA(e) {
<code>v8.gc_stats</code>.
</li>
</ul>
<p>
Note that you only get a data point on major GCs. You can enforce this by
using the <code>--gc-global</code> flag.
</p>
<p>
Note that the visualizer needs to run on a web server due to HTML imports
requiring <a
......
......@@ -4,6 +4,10 @@
'use strict';
const KB = 1024;
const MB = KB * KB;
const kMillis2Seconds = 1 / 1000;
class Isolate {
constructor(address) {
this.address = address;
......@@ -30,7 +34,7 @@ class Isolate {
getLabel() {
let label = `${this.address}: gc=#${Object.keys(this.gcs).length}`;
const peakSizeMB = Math.round(this.peakMemory / 1024 / 1024 * 100) / 100;
label += ` max=${peakSizeMB}MB`
label += ` peak=${peakSizeMB}MB`
return label;
}
......
......@@ -11,6 +11,16 @@ found in the LICENSE file. -->
border: solid 1px #000000;
border-radius: 5px;
cursor: pointer;
transition: all 0.5s ease-in-out;
}
#fileReader.done {
height: 20px;
line-height: 20px;
}
#fileReader:hover {
background-color: #e0edfe ;
}
.loading #fileReader {
......@@ -21,11 +31,12 @@ found in the LICENSE file. -->
display: none;
}
#loader {
display: none;
}
.loading #loader{
.loading #loader {
display: block;
position: fixed;
top: 0px;
......
......@@ -63,15 +63,17 @@ class TraceFileReader extends HTMLElement {
const textResult = pako.inflate(e.target.result, {to: 'string'});
this.processRawText(file, textResult);
this.section.className = 'success';
this.$('#fileReader').classList.add('done');
} catch (err) {
console.error(err);
this.section.className = 'failure';
}
};
reader.readAsArrayBuffer(file);
// Delay the loading a bit to allow for CSS animations to happen.
setTimeout(() => reader.readAsArrayBuffer(file), 10);
} else {
reader.onload = (e) => this.processRawText(file, e.target.result);
reader.readAsText(file);
setTimeout(() => reader.readAsText(file), 10);
}
}
......@@ -96,10 +98,12 @@ class TraceFileReader extends HTMLElement {
data_object.gcs[entry.id] = {non_empty_instance_types: new Set()};
}
if ('time' in entry) {
if (data_object.end === null || data_object.end < entry.time)
if (data_object.end === null || data_object.end < entry.time) {
data_object.end = entry.time;
if (data_object.start === null || data_object.start > entry.time)
}
if (data_object.start === null || data_object.start > entry.time) {
data_object.start = entry.time;
}
}
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment