Commit e0fd4277 authored by Camillo Bruni's avatar Camillo Bruni Committed by Commit Bot

[tools] Add Isolate model to heap stats visualizer

- Display details in isolate selection dropdown
- Sort isolates by peak live heap memory

Bug: v8:7266
Change-Id: I01dd6cced4a5febd8e58cc4b7e2bb337c30f0812
No-try: true
Reviewed-on: https://chromium-review.googlesource.com/916062Reviewed-by: 's avatarMichael Lippautz <mlippautz@chromium.org>
Commit-Queue: Camillo Bruni <cbruni@chromium.org>
Cr-Commit-Position: refs/heads/master@{#51282}
parent 7a51f1fa
......@@ -99,11 +99,18 @@ class DetailsSelection extends HTMLElement {
dataChanged() {
this.selection = {categories: {}};
this.resetUI(true);
this.populateSelect(
'#isolate-select', Object.keys(this.data).map(v => [v, v]));
this.populateIsolateSelect();
this.handleIsolateChange();
}
populateIsolateSelect() {
let entries = Object.entries(this.data);
// Sorty by peak heap memory consumption.
entries.sort((a, b) => b[1].peakMemory - a[1].peakMemory);
this.populateSelect(
'#isolate-select', entries, (key, isolate) => isolate.getLabel());
}
resetUI(resetIsolateSelect) {
if (resetIsolateSelect) removeAllChildren(this.isolateSelect);
......@@ -124,11 +131,12 @@ class DetailsSelection extends HTMLElement {
this.resetUI(false);
this.populateSelect(
'#dataset-select',
this.data[this.selection.isolate].data_sets.entries(), 'live');
this.data[this.selection.isolate].data_sets.entries(), null, 'live');
this.populateSelect(
'#gc-select',
Object.keys(this.data[this.selection.isolate].gcs)
.map(v => [v, this.data[this.selection.isolate].gcs[v].time]));
.map(v => [v, this.data[this.selection.isolate].gcs[v].time]),
time => time + 'ms');
this.populateCategories();
this.notifySelectionChanged();
}
......@@ -213,10 +221,12 @@ class DetailsSelection extends HTMLElement {
return option;
}
populateSelect(id, iterable, autoselect = null) {
for (let [value, text] of iterable) {
const option = this.createOption(value, text);
if (autoselect === value) {
populateSelect(id, iterable, labelFn = null, autoselect = null) {
if (labelFn == null) labelFn = e => e;
for (let [key, value] of iterable) {
const label = labelFn(key, value);
const option = this.createOption(key, label);
if (autoselect === key) {
option.selected = 'selected';
}
this.$(id).appendChild(option);
......
// Copyright 2018 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.
'use strict';
class Isolate {
constructor(address) {
this.address = address;
this.start = null;
this.end = null;
this.samples = Object.create(null);
this.non_empty_instance_types = new Set();
this.gcs = Object.create(null);
this.zonetags = [];
this.samples = {zone: {}};
this.data_sets = new Set();
this.peakMemory = 0;
}
finalize() {
Object.values(this.gcs).forEach(gc => this.finalizeGC(gc));
}
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`
return label;
}
finalizeGC(gc_data) {
this.data_sets.forEach(key => this.finalizeDataSet(gc_data[key]));
if ('live' in gc_data) {
this.peakMemory = Math.max(this.peakMemory, gc_data['live'].overall);
}
}
finalizeDataSet(data_set) {
// Create a ranked instance type array that sorts instance types by
// memory size (overall).
data_set.ranked_instance_types =
[...data_set.non_empty_instance_types].sort(function(a, b) {
if (data_set.instance_type_data[a].overall >
data_set.instance_type_data[b].overall) {
return 1;
} else if (
data_set.instance_type_data[a].overall <
data_set.instance_type_data[b].overall) {
return -1;
}
return 0;
});
Object.entries(data_set.instance_type_data).forEach(([name, entry]) => {
this.checkHistogram(
name, entry, data_set.bucket_sizes, 'histogram', ' overall');
this.checkHistogram(
name, entry, data_set.bucket_sizes, 'over_allocated_histogram',
' over_allocated');
});
}
// Check that a lower bound for histogram memory does not exceed the
// overall counter.
checkHistogram(type, entry, bucket_sizes, histogram, overallProperty) {
let sum = 0;
for (let i = 1; i < entry[histogram].length; i++) {
sum += entry[histogram][i] * bucket_sizes[i - 1];
}
const overall = entry[overallProperty];
if (sum >= overall) {
console.error(
`${type}: sum('${histogram}') > overall (${sum} > ${overall})`);
}
}
}
......@@ -23,4 +23,5 @@ found in the LICENSE file. -->
<input id="file" type="file" name="file" />
</div>
</template>
<script type="text/javascript" src="model.js"></script>
<script type="text/javascript" src="trace-file-reader.js"></script>
......@@ -82,15 +82,7 @@ class TraceFileReader extends HTMLElement {
createOrUpdateEntryIfNeeded(data, entry) {
console.assert(entry.isolate, 'entry should have an isolate');
if (!(entry.isolate in data)) {
data[entry.isolate] = {
non_empty_instance_types: new Set(),
gcs: {},
zonetags: [],
samples: {zone: {}},
start: null,
end: null,
data_sets: new Set()
};
data[entry.isolate] = new Isolate(entry.isolate);
}
const data_object = data[entry.isolate];
if (('id' in entry) && !(entry.id in data_object.gcs)) {
......@@ -137,55 +129,7 @@ class TraceFileReader extends HTMLElement {
console.assert(obj[property] >= 0, 'negative property', obj, property);
};
for (const isolate of Object.keys(data)) {
const isolate_data = data[isolate];
for (const gc of Object.keys(isolate_data.gcs)) {
const gc_data = isolate_data.gcs[gc];
for (const data_set_key of isolate_data.data_sets) {
const data_set = data[isolate].gcs[gc][data_set_key];
// Create a ranked instance type array that sorts instance types by
// memory size (overall).
data_set.ranked_instance_types =
[...data_set.non_empty_instance_types].sort(function(a, b) {
if (data_set.instance_type_data[a].overall >
data_set.instance_type_data[b].overall) {
return 1;
} else if (
data_set.instance_type_data[a].overall <
data_set.instance_type_data[b].overall) {
return -1;
}
return 0;
});
// Check that a lower bound for histogram memory does not exceed the
// overall counter.
const checkHistogram =
(type, entry, bucket_sizes, histogram, overallProperty) => {
let sum = 0;
for (let i = 1; i < entry[histogram].length; i++) {
sum += entry[histogram][i] * bucket_sizes[i - 1];
}
const overall = entry[overallProperty];
if (sum >= overall) {
console.error(
`${type}: sum('${
histogram
}') > overall (${sum} > ${overall})`);
}
};
Object.entries(data_set.instance_type_data).forEach(([
name, entry
]) => {
checkHistogram(
name, entry, data_set.bucket_sizes, 'histogram', ' overall');
checkHistogram(
name, entry, data_set.bucket_sizes, 'over_allocated_histogram',
' over_allocated');
});
}
}
}
Object.values(data).forEach(isolate => isolate.finalize());
}
createModelFromChromeTraceFile(contents) {
......
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