Index: tracing/tracing/extras/importer/heap_dump_trace_event_importer.html |
diff --git a/tracing/tracing/extras/importer/heap_dump_trace_event_importer.html b/tracing/tracing/extras/importer/heap_dump_trace_event_importer.html |
index e11e40313f0e369e517640e1ed1fb1862d6b7e64..e22671b6359bbcba0bdecc47e9f52d107b2a1feb 100644 |
--- a/tracing/tracing/extras/importer/heap_dump_trace_event_importer.html |
+++ b/tracing/tracing/extras/importer/heap_dump_trace_event_importer.html |
@@ -1,6 +1,6 @@ |
<!DOCTYPE html> |
<!-- |
-Copyright 2016 The Chromium Authors. All rights reserved. |
+Copyright 2017 The Chromium Authors. All rights reserved. |
Use of this source code is governed by a BSD-style license that can be |
found in the LICENSE file. |
--> |
@@ -16,169 +16,72 @@ found in the LICENSE file. |
tr.exportTo('tr.e.importer', function() { |
/** |
* @constructor |
- * @param {!tr.model.Model} model The model we are currently building. |
- * @param {!tr.model.ProcessMemoryDump} processMemoryDump |
- * The parent memory dump for this heap dump. |
- * @param {!Map|undefined} processObjectTypeNameMap |
- * A map from raw heap dump 'type' ids to human-readable names. |
- * @param {!string} idPrefix Process-specific prefix to prepend to a stack |
- * trace id before looking it up in the model. |
- * @param {!string} dumpId |
- * Raw heap dump id, used only for nice error messages. |
*/ |
function HeapDumpTraceEventImporter( |
- model, processMemoryDump, processObjectTypeNameMap, idPrefix, dumpId) { |
- this.model_ = model; |
- this.processObjectTypeNameMap_ = processObjectTypeNameMap; |
- this.idPrefix_ = idPrefix; |
- this.processMemoryDump_ = processMemoryDump; |
- this.pid_ = this.processMemoryDump_.process.pid; |
- this.dumpId_ = dumpId; |
+ heapProfileExpander, |
+ stackFrames, |
+ processMemoryDump, |
+ idPrefix, |
+ model) { |
+ this.expander = heapProfileExpander; |
+ this.stackFrames = stackFrames; |
+ this.processMemoryDump = processMemoryDump; |
+ this.idPrefix = idPrefix; |
+ this.model = model; |
} |
HeapDumpTraceEventImporter.prototype = { |
- /** |
- * Parse rawHeapDump and add entries to heapDump. |
- * |
- * @param {!{!entries:(!Array<!Object>|undefined)}} rawHeapDump |
- * The data we're going to parse. |
- * @param {!string} allocatorName e.g. malloc. |
- * @return {!tr.model.HeapDump} on success or undefined on an error. |
- */ |
- parseRawHeapDump(rawHeapDump, allocatorName) { |
- const model = this.model_; |
- const processMemoryDump = this.processMemoryDump_; |
- const heapDump = new tr.model.HeapDump(processMemoryDump, allocatorName); |
- const entries = rawHeapDump.entries; |
- if (entries === undefined || entries.length === 0) { |
- this.model_.importWarning({ |
- type: 'memory_dump_parse_error', |
- message: 'No heap entries in a ' + allocatorName + |
- ' heap dump for PID=' + this.pid_ + |
- ' and dump ID=' + this.dumpId_ + '.' |
- }); |
+ getLeafStackFrame(stackFrameId) { |
+ // Root. |
+ if (stackFrameId === '') return undefined; |
+ const parentId = this.idPrefix + stackFrameId; |
+ const id = parentId + ':self'; |
- return undefined; |
+ // In the new format all values are 'self' values, |
+ // we distingiush these from the totals in the UI via |
+ // artificial '<self>' stack frames. |
+ if (!this.stackFrames[id]) { |
+ const parentStackFrame = this.stackFrames[parentId]; |
+ const stackFrame = new tr.model.StackFrame( |
+ parentStackFrame, id, '<self>', |
+ undefined /* colorId */); |
+ this.model.addStackFrame(stackFrame); |
} |
+ return this.stackFrames[id]; |
+ }, |
- // The old format always starts with a {size: <total>} entry. |
- // See https://goo.gl/WYStil |
- // TODO(petrcermak): Remove support for the old format once the new |
- // format has been around long enough. |
- const isOldFormat = entries[0].bt === undefined; |
- if (!isOldFormat && this.processObjectTypeNameMap_ === undefined) { |
- // Mapping from object type IDs to names must be provided in the new |
- // format. |
- return undefined; |
+ parseEntry(entry, heapDump) { |
+ const size = entry.size; |
+ const count = entry.count; |
+ const leafStackFrame = this.getLeafStackFrame(entry.node.id); |
+ const objectTypeName = entry.type.name; |
+ const valuesAreTotals = false; |
+ if (objectTypeName === undefined) { |
+ this.model_.importWarning({ |
+ type: 'memory_dump_parse_error', |
+ message: 'Missing object type name (ID ' + typeId + ')', |
+ }); |
} |
+ heapDump.addEntry( |
+ leafStackFrame, objectTypeName, size, count, valuesAreTotals); |
+ }, |
- for (let i = 0; i < entries.length; i++) { |
- const entry = entries[i]; |
- const size = parseInt(entry.size, 16); |
- const leafStackFrameIndex = entry.bt; |
- let leafStackFrame; |
- |
- // There are two possible mappings from leaf stack frame indices |
- // (provided in the trace) to the corresponding stack frames |
- // depending on the format. |
- if (isOldFormat) { |
- // Old format: |
- // Undefined index -> / (root) |
- // Defined index for /A/B -> /A/B/<self> |
- if (leafStackFrameIndex === undefined) { |
- leafStackFrame = undefined; /* root */ |
- } else { |
- // Get the leaf stack frame corresponding to the provided index. |
- let leafStackFrameId = this.idPrefix_ + leafStackFrameIndex; |
- if (leafStackFrameIndex === '') { |
- leafStackFrame = undefined; /* root */ |
- } else { |
- leafStackFrame = model.stackFrames[leafStackFrameId]; |
- if (leafStackFrame === undefined) { |
- this.model_.importWarning({ |
- type: 'memory_dump_parse_error', |
- message: 'Missing leaf stack frame (ID ' + |
- leafStackFrameId + ') of heap entry ' + i + ' (size ' + |
- size + ') in a ' + allocatorName + |
- ' heap dump for PID=' + this.pid_ + '.' |
- }); |
- continue; |
- } |
- } |
- |
- // Inject an artificial <self> leaf stack frame. |
- leafStackFrameId += ':self'; |
- if (model.stackFrames[leafStackFrameId] !== undefined) { |
- // The frame might already exist if there are multiple process |
- // memory dumps (for the same process) in the trace. |
- leafStackFrame = model.stackFrames[leafStackFrameId]; |
- } else { |
- leafStackFrame = new tr.model.StackFrame( |
- leafStackFrame, leafStackFrameId, '<self>', |
- undefined /* colorId */); |
- model.addStackFrame(leafStackFrame); |
- } |
- } |
- } else { |
- // New format: |
- // Undefined index -> (invalid value) |
- // Defined index for /A/B -> /A/B |
- if (leafStackFrameIndex === undefined) { |
- this.model_.importWarning({ |
- type: 'memory_dump_parse_error', |
- message: 'Missing stack frame ID of heap entry ' + i + |
- ' (size ' + size + ') in a ' + allocatorName + |
- ' heap dump for PID=' + this.pid_ + '.' |
- }); |
- continue; |
- } |
- |
- // Get the leaf stack frame corresponding to the provided index. |
- const leafStackFrameId = this.idPrefix_ + leafStackFrameIndex; |
- if (leafStackFrameIndex === '') { |
- leafStackFrame = undefined; /* root */ |
- } else { |
- leafStackFrame = model.stackFrames[leafStackFrameId]; |
- if (leafStackFrame === undefined) { |
- this.model_.importWarning({ |
- type: 'memory_dump_parse_error', |
- message: 'Missing leaf stack frame (ID ' + leafStackFrameId + |
- ') of heap entry ' + i + ' (size ' + size + ') in a ' + |
- allocatorName + ' heap dump for PID=' + this.pid_ + '.' |
- }); |
- continue; |
- } |
- } |
- } |
- |
- const objectTypeId = entry.type; |
- let objectTypeName; |
- if (objectTypeId === undefined) { |
- objectTypeName = undefined; /* total over all types */ |
- } else if (this.processObjectTypeNameMap_ === undefined) { |
- // This can only happen when the old format is used. |
- continue; |
- } else { |
- objectTypeName = this.processObjectTypeNameMap_[objectTypeId]; |
- if (objectTypeName === undefined) { |
- this.model_.importWarning({ |
- type: 'memory_dump_parse_error', |
- message: 'Missing object type name (ID ' + objectTypeId + |
- ') of heap entry ' + i + ' (size ' + size + ') in a ' + |
- allocatorName + ' heap dump for PID=' + this.pid_ + '.' |
- }); |
- continue; |
- } |
+ parse() { |
+ const heapDumps = {}; |
+ const inflated = this.expander.inflated; |
+ for (const [allocatorName, entries] of Object.entries(inflated)) { |
+ const heapDump = |
+ new tr.model.HeapDump(this.processMemoryDump, allocatorName); |
+ for (const entry of entries) { |
+ this.parseEntry(entry, heapDump); |
} |
- |
- const count = entry.count === undefined ? undefined : |
- parseInt(entry.count, 16); |
- heapDump.addEntry(leafStackFrame, objectTypeName, size, count); |
+ heapDump.isComplete = true; |
+ heapDumps[allocatorName] = heapDump; |
} |
- |
- return heapDump; |
+ return heapDumps; |
}, |
+ |
}; |
return { |