summaryrefslogtreecommitdiff
path: root/deps/v8/tools/heap-stats/trace-file-reader.js
diff options
context:
space:
mode:
Diffstat (limited to 'deps/v8/tools/heap-stats/trace-file-reader.js')
-rw-r--r--deps/v8/tools/heap-stats/trace-file-reader.js231
1 files changed, 98 insertions, 133 deletions
diff --git a/deps/v8/tools/heap-stats/trace-file-reader.js b/deps/v8/tools/heap-stats/trace-file-reader.js
index 59825fe514..ef563a43cb 100644
--- a/deps/v8/tools/heap-stats/trace-file-reader.js
+++ b/deps/v8/tools/heap-stats/trace-file-reader.js
@@ -23,6 +23,10 @@ class TraceFileReader extends HTMLElement {
return this.shadowRoot.querySelector(id);
}
+ get section() {
+ return this.$('#fileReaderSection');
+ }
+
updateLabel(text) {
this.$('#label').innerText = text;
}
@@ -50,34 +54,42 @@ class TraceFileReader extends HTMLElement {
return;
}
- const result = new FileReader();
- result.onload = (e) => {
- let contents = e.target.result.split('\n');
- const return_data = (e.target.result.includes('V8.GC_Objects_Stats')) ?
- this.createModelFromChromeTraceFile(contents) :
- this.createModelFromV8TraceFile(contents);
- this.updateLabel('Finished loading \'' + file.name + '\'.');
- this.dispatchEvent(new CustomEvent(
- 'change', {bubbles: true, composed: true, detail: return_data}));
- };
- result.readAsText(file);
+ this.section.className = 'loading';
+ const reader = new FileReader();
+
+ if (['application/gzip', 'application/x-gzip'].includes(file.type)) {
+ reader.onload = (e) => {
+ try {
+ const textResult = pako.inflate(e.target.result, {to: 'string'});
+ this.processRawText(file, textResult);
+ this.section.className = 'success';
+ } catch (err) {
+ console.error(err);
+ this.section.className = 'failure';
+ }
+ };
+ reader.readAsArrayBuffer(file);
+ } else {
+ reader.onload = (e) => this.processRawText(file, e.target.result);
+ reader.readAsText(file);
+ }
}
- createOrUpdateEntryIfNeeded(data, keys, entry) {
+ processRawText(file, result) {
+ let contents = result.split('\n');
+ const return_data = (result.includes('V8.GC_Objects_Stats')) ?
+ this.createModelFromChromeTraceFile(contents) :
+ this.createModelFromV8TraceFile(contents);
+ this.extendAndSanitizeModel(return_data);
+ this.updateLabel('Finished loading \'' + file.name + '\'.');
+ this.dispatchEvent(new CustomEvent(
+ 'change', {bubbles: true, composed: true, detail: return_data}));
+ }
+
+ createOrUpdateEntryIfNeeded(data, entry) {
console.assert(entry.isolate, 'entry should have an isolate');
- if (!(entry.isolate in keys)) {
- keys[entry.isolate] = new Set();
- }
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)) {
@@ -91,7 +103,7 @@ class TraceFileReader extends HTMLElement {
}
}
- createDatasetIfNeeded(data, keys, entry, data_set) {
+ createDatasetIfNeeded(data, entry, data_set) {
if (!(data_set in data[entry.isolate].gcs[entry.id])) {
data[entry.isolate].gcs[entry.id][data_set] = {
instance_type_data: {},
@@ -102,9 +114,7 @@ class TraceFileReader extends HTMLElement {
}
}
- addInstanceTypeData(
- data, keys, isolate, gc_id, data_set, instance_type, entry) {
- keys[isolate].add(data_set);
+ addInstanceTypeData(data, isolate, gc_id, data_set, instance_type, entry) {
data[isolate].gcs[gc_id][data_set].instance_type_data[instance_type] = {
overall: entry.overall,
count: entry.count,
@@ -121,117 +131,75 @@ class TraceFileReader extends HTMLElement {
}
}
- extendAndSanitizeModel(data, keys) {
+ extendAndSanitizeModel(data) {
const checkNonNegativeProperty = (obj, property) => {
console.assert(obj[property] >= 0, 'negative property', obj, property);
};
- for (const isolate of Object.keys(data)) {
- for (const gc of Object.keys(data[isolate].gcs)) {
- for (const data_set_key of keys[isolate]) {
- const data_set = data[isolate].gcs[gc][data_set_key];
- // 1. 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;
- });
-
- let known_count = 0;
- let known_overall = 0;
- let known_histogram =
- Array(
- data_set.instance_type_data.FIXED_ARRAY_TYPE.histogram.length)
- .fill(0);
- for (const instance_type in data_set.instance_type_data) {
- if (!instance_type.startsWith('*FIXED_ARRAY')) continue;
- const subtype = data_set.instance_type_data[instance_type];
- known_count += subtype.count;
- known_overall += subtype.count;
- for (let i = 0; i < subtype.histogram.length; i++) {
- known_histogram[i] += subtype.histogram[i];
- }
- }
-
- const fixed_array_data = data_set.instance_type_data.FIXED_ARRAY_TYPE;
- const unknown_entry = {
- count: fixed_array_data.count - known_count,
- overall: fixed_array_data.overall - known_overall,
- histogram: fixed_array_data.histogram.map(
- (value, index) => value - known_histogram[index])
- };
-
- // Check for non-negative values.
- checkNonNegativeProperty(unknown_entry, 'count');
- checkNonNegativeProperty(unknown_entry, 'overall');
- for (let i = 0; i < unknown_entry.histogram.length; i++) {
- checkNonNegativeProperty(unknown_entry.histogram, i);
- }
-
- data_set.instance_type_data['*FIXED_ARRAY_UNKNOWN_SUB_TYPE'] =
- unknown_entry;
- data_set.non_empty_instance_types.add(
- '*FIXED_ARRAY_UNKNOWN_SUB_TYPE');
- }
- }
- }
+ Object.values(data).forEach(isolate => isolate.finalize());
}
createModelFromChromeTraceFile(contents) {
- console.log('Processing log as chrome trace file.');
- const data = Object.create(null); // Final data container.
- const keys = Object.create(null); // Collecting 'keys' per isolate.
+ // Trace files support two formats.
+ // {traceEvents: [ data ]}
+ const kObjectTraceFile = {
+ name: 'object',
+ endToken: ']}',
+ getDataArray: o => o.traceEvents
+ };
+ // [ data ]
+ const kArrayTraceFile = {
+ name: 'array',
+ endToken: ']',
+ getDataArray: o => o
+ };
+ const handler =
+ (contents[0][0] === '{') ? kObjectTraceFile : kArrayTraceFile;
+ console.log(`Processing log as chrome trace file (${handler.name}).`);
// Pop last line in log as it might be broken.
contents.pop();
// Remove trailing comma.
contents[contents.length - 1] = contents[contents.length - 1].slice(0, -1);
// Terminate JSON.
- const sanitized_contents = [...contents, ']}'].join('');
+ const sanitized_contents = [...contents, handler.endToken].join('');
+
+ const data = Object.create(null); // Final data container.
try {
const raw_data = JSON.parse(sanitized_contents);
- const objects_stats_data =
- raw_data.traceEvents.filter(e => e.name == 'V8.GC_Objects_Stats');
- objects_stats_data.forEach(trace_data => {
- const actual_data = trace_data.args;
- const data_sets = new Set(Object.keys(actual_data));
- Object.keys(actual_data).forEach(data_set => {
- const string_entry = actual_data[data_set];
- try {
- const entry = JSON.parse(string_entry);
- this.createOrUpdateEntryIfNeeded(data, keys, entry);
- this.createDatasetIfNeeded(data, keys, entry, data_set);
- const isolate = entry.isolate;
- const time = entry.time;
- const gc_id = entry.id;
- data[isolate].gcs[gc_id].time = time;
- data[isolate].gcs[gc_id][data_set].bucket_sizes =
- entry.bucket_sizes;
- for (let [instance_type, value] of Object.entries(
- entry.type_data)) {
- // Trace file format uses markers that do not have actual
- // properties.
- if (!('overall' in value)) continue;
- this.addInstanceTypeData(
- data, keys, isolate, gc_id, data_set, instance_type, value);
- }
- } catch (e) {
- console.log('Unable to parse data set entry', e);
- }
- });
- });
+ const raw_array_data = handler.getDataArray(raw_data);
+ raw_array_data.filter(e => e.name === 'V8.GC_Objects_Stats')
+ .forEach(trace_data => {
+ const actual_data = trace_data.args;
+ const data_sets = new Set(Object.keys(actual_data));
+ Object.keys(actual_data).forEach(data_set => {
+ const string_entry = actual_data[data_set];
+ try {
+ const entry = JSON.parse(string_entry);
+ this.createOrUpdateEntryIfNeeded(data, entry);
+ this.createDatasetIfNeeded(data, entry, data_set);
+ const isolate = entry.isolate;
+ const time = entry.time;
+ const gc_id = entry.id;
+ data[isolate].gcs[gc_id].time = time;
+ data[isolate].gcs[gc_id][data_set].bucket_sizes =
+ entry.bucket_sizes;
+ for (let [instance_type, value] of Object.entries(
+ entry.type_data)) {
+ // Trace file format uses markers that do not have actual
+ // properties.
+ if (!('overall' in value)) continue;
+ this.addInstanceTypeData(
+ data, isolate, gc_id, data_set, instance_type, value);
+ }
+ } catch (e) {
+ console.log('Unable to parse data set entry', e);
+ }
+ });
+ });
} catch (e) {
- console.log('Unable to parse chrome trace file.', e);
+ console.error('Unable to parse chrome trace file.', e);
}
- this.extendAndSanitizeModel(data, keys);
return data;
}
@@ -249,14 +217,12 @@ class TraceFileReader extends HTMLElement {
});
const data = Object.create(null); // Final data container.
- const keys = Object.create(null); // Collecting 'keys' per isolate.
-
for (var entry of contents) {
if (entry === null || entry.type === undefined) {
continue;
}
if (entry.type === 'zone') {
- this.createOrUpdateEntryIfNeeded(data, keys, entry);
+ this.createOrUpdateEntryIfNeeded(data, entry);
const stacktrace = ('stacktrace' in entry) ? entry.stacktrace : [];
data[entry.isolate].samples.zone[entry.time] = {
allocated: entry.allocated,
@@ -265,26 +231,26 @@ class TraceFileReader extends HTMLElement {
};
} else if (
entry.type === 'zonecreation' || entry.type === 'zonedestruction') {
- this.createOrUpdateEntryIfNeeded(data, keys, entry);
+ this.createOrUpdateEntryIfNeeded(data, entry);
data[entry.isolate].zonetags.push(
Object.assign({opening: entry.type === 'zonecreation'}, entry));
} else if (entry.type === 'gc_descriptor') {
- this.createOrUpdateEntryIfNeeded(data, keys, entry);
+ this.createOrUpdateEntryIfNeeded(data, entry);
data[entry.isolate].gcs[entry.id].time = entry.time;
if ('zone' in entry)
data[entry.isolate].gcs[entry.id].malloced = entry.zone;
} else if (entry.type === 'instance_type_data') {
if (entry.id in data[entry.isolate].gcs) {
- this.createOrUpdateEntryIfNeeded(data, keys, entry);
- this.createDatasetIfNeeded(data, keys, entry, entry.key);
+ this.createOrUpdateEntryIfNeeded(data, entry);
+ this.createDatasetIfNeeded(data, entry, entry.key);
this.addInstanceTypeData(
- data, keys, entry.isolate, entry.id, entry.key,
+ data, entry.isolate, entry.id, entry.key,
entry.instance_type_name, entry);
}
} else if (entry.type === 'bucket_sizes') {
if (entry.id in data[entry.isolate].gcs) {
- this.createOrUpdateEntryIfNeeded(data, keys, entry);
- this.createDatasetIfNeeded(data, keys, entry, entry.key);
+ this.createOrUpdateEntryIfNeeded(data, entry);
+ this.createDatasetIfNeeded(data, entry, entry.key);
data[entry.isolate].gcs[entry.id][entry.key].bucket_sizes =
entry.sizes;
}
@@ -292,7 +258,6 @@ class TraceFileReader extends HTMLElement {
console.log('Unknown entry type: ' + entry.type);
}
}
- this.extendAndSanitizeModel(data, keys);
return data;
}
}