// 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';
const histogram_viewer_template =
document.currentScript.ownerDocument.querySelector(
'#histogram-viewer-template');
class HistogramViewer extends HTMLElement {
constructor() {
super();
const shadowRoot = this.attachShadow({mode: 'open'});
shadowRoot.appendChild(histogram_viewer_template.content.cloneNode(true));
}
$(id) {
return this.shadowRoot.querySelector(id);
}
set data(value) {
this._data = value;
this.stateChanged();
}
get data() {
return this._data;
}
set selection(value) {
this._selection = value;
this.stateChanged();
}
get selection() {
return this._selection;
}
isValid() {
return this.data && this.selection &&
(this.selection.data_view === VIEW_BY_INSTANCE_CATEGORY ||
this.selection.data_view === VIEW_BY_INSTANCE_TYPE);
;
}
hide() {
this.$('#container').style.display = 'none';
}
show() {
this.$('#container').style.display = 'block';
}
getOverallValue() {
switch (this.selection.data_view) {
case VIEW_BY_FIELD_TYPE:
return NaN;
case VIEW_BY_INSTANCE_CATEGORY:
return this.getPropertyForCategory('overall');
case VIEW_BY_INSTANCE_TYPE:
default:
return this.getPropertyForInstanceTypes('overall');
}
}
stateChanged() {
if (this.isValid()) {
const overall_bytes = this.getOverallValue();
this.$('#overall').innerHTML = `Overall: ${overall_bytes / KB} KB`;
this.drawChart();
} else {
this.hide();
}
}
get selectedData() {
console.assert(this.data, 'invalid data');
console.assert(this.selection, 'invalid selection');
return this.data[this.selection.isolate]
.gcs[this.selection.gc][this.selection.data_set];
}
get selectedInstanceTypes() {
console.assert(this.selection, 'invalid selection');
return Object.values(this.selection.categories)
.reduce((accu, current) => accu.concat(current), []);
}
getPropertyForCategory(property) {
return Object.values(this.selection.categories)
.reduce(
(outer_accu, instance_types) => outer_accu +
instance_types.reduce(
(inner_accu, instance_type) => inner_accu +
this.selectedData
.instance_type_data[instance_type][property],
0),
0);
}
getPropertyForInstanceTypes(property) {
return this.selectedInstanceTypes.reduce(
(accu, instance_type) => accu +
this.selectedData.instance_type_data[instance_type][property],
0);
}
formatBytes(bytes) {
const units = ['B', 'KiB', 'MiB'];
const divisor = 1024;
let index = 0;
while (index < units.length && bytes >= divisor) {
index++;
bytes /= divisor;
}
return bytes + units[index];
}
getCategoryData() {
const labels = [
'Bucket',
...Object.keys(this.selection.categories)
.map(k => this.selection.category_names.get(k))
];
const data = this.selectedData.bucket_sizes.map(
(bucket_size, index) =>
[`<${this.formatBytes(bucket_size)}`,
...Object.values(this.selection.categories)
.map(
instance_types =>
instance_types
.map(
instance_type =>
this.selectedData
.instance_type_data[instance_type]
.histogram[index])
.reduce((accu, current) => accu + current, 0))]);
// Adjust last histogram bucket label.
data[data.length - 1][0] = 'rest';
return [labels, ...data];
}
getInstanceTypeData() {
const instance_types = this.selectedInstanceTypes;
const labels = ['Bucket', ...instance_types];
const data = this.selectedData.bucket_sizes.map(
(bucket_size, index) =>
[`<${bucket_size}`,
...instance_types.map(
instance_type =>
this.selectedData.instance_type_data[instance_type]
.histogram[index])]);
// Adjust last histogram bucket label.
data[data.length - 1][0] = 'rest';
return [labels, ...data];
}
getChartData() {
switch (this.selection.data_view) {
case VIEW_BY_FIELD_TYPE:
return this.getFieldData();
case VIEW_BY_INSTANCE_CATEGORY:
return this.getCategoryData();
case VIEW_BY_INSTANCE_TYPE:
default:
return this.getInstanceTypeData();
}
}
drawChart() {
const chart_data = this.getChartData();
const data = google.visualization.arrayToDataTable(chart_data);
const options = {
legend: {position: 'top', maxLines: '1'},
chartArea: {width: '85%', height: '85%'},
bar: {groupWidth: '80%'},
hAxis: {
title: 'Count',
minValue: 0
},
explorer: {},
};
const chart = new google.visualization.BarChart(this.$('#chart'));
this.show();
chart.draw(data, options);
}
}
customElements.define('histogram-viewer', HistogramViewer);