| Index: tracing/tracing/extras/importer/trace_event_importer.html
|
| diff --git a/tracing/tracing/extras/importer/trace_event_importer.html b/tracing/tracing/extras/importer/trace_event_importer.html
|
| index ab0f98bef184c363213019d9f28fed7297ad83fe..16c5e15ac9e75443da37cdae013385cf00b3ec2b 100644
|
| --- a/tracing/tracing/extras/importer/trace_event_importer.html
|
| +++ b/tracing/tracing/extras/importer/trace_event_importer.html
|
| @@ -9,9 +9,11 @@ found in the LICENSE file.
|
| <link rel="import" href="/tracing/base/color_scheme.html">
|
| <link rel="import" href="/tracing/base/math/range.html">
|
| <link rel="import" href="/tracing/base/scalar.html">
|
| +<link rel="import" href="/tracing/base/trace_stream.html">
|
| <link rel="import" href="/tracing/base/unit.html">
|
| <link rel="import" href="/tracing/base/utils.html">
|
| <link rel="import" href="/tracing/extras/importer/heap_dump_trace_event_importer.html">
|
| +<link rel="import" href="/tracing/extras/importer/oboe.html">
|
| <link rel="import" href="/tracing/extras/importer/trace_code_entry.html">
|
| <link rel="import" href="/tracing/extras/importer/trace_code_map.html">
|
| <link rel="import" href="/tracing/extras/importer/v8/codemap.html">
|
| @@ -121,6 +123,7 @@ tr.exportTo('tr.e.importer', function() {
|
| // The complete list of fields on the trace that should not be treated as
|
| // trace metadata.
|
| var NON_METADATA_FIELDS = new Set([
|
| + 'displayTimeUnit',
|
| 'samples',
|
| 'stackFrames',
|
| 'traceAnnotations',
|
| @@ -129,6 +132,7 @@ tr.exportTo('tr.e.importer', function() {
|
| ]);
|
|
|
| function TraceEventImporter(model, eventData) {
|
| + this.hasEvents_ = undefined; // Set properly when importEvents is called.
|
| this.importPriority = 1;
|
| this.model_ = model;
|
| this.events_ = undefined;
|
| @@ -196,53 +200,38 @@ tr.exportTo('tr.e.importer', function() {
|
| this.events_ = eventData;
|
| }
|
|
|
| - this.traceAnnotations_ = this.events_.traceAnnotations;
|
| -
|
| // Some trace_event implementations put the actual trace events
|
| // inside a container. E.g { ... , traceEvents: [ ] }
|
| // If we see that, just pull out the trace events.
|
| if (this.events_.traceEvents) {
|
| - var container = this.events_;
|
| + const container = this.events_;
|
| this.events_ = this.events_.traceEvents;
|
|
|
| - // Some trace authors store subtraces as specific properties of the trace.
|
| - for (var subtraceField of SUBTRACE_FIELDS) {
|
| + for (const subtraceField of SUBTRACE_FIELDS) {
|
| if (container[subtraceField]) {
|
| - this.subtraces_.push(container[subtraceField]);
|
| - }
|
| - }
|
| -
|
| - // Sampling data.
|
| - this.sampleEvents_ = container.samples;
|
| - this.stackFrameEvents_ = container.stackFrames;
|
| -
|
| - // Some implementations specify displayTimeUnit
|
| - if (container.displayTimeUnit) {
|
| - var unitName = container.displayTimeUnit;
|
| - var unit = tr.b.TimeDisplayModes[unitName];
|
| - if (unit === undefined) {
|
| - throw new Error('Unit ' + unitName + ' is not supported.');
|
| - }
|
| - this.model_.intrinsicTimeUnit = unit;
|
| - }
|
| -
|
| - // Any other fields in the container should be treated as metadata.
|
| - for (var fieldName in container) {
|
| - if (NON_METADATA_FIELDS.has(fieldName)) continue;
|
| -
|
| - this.model_.metadata.push(
|
| - { name: fieldName, value: container[fieldName] });
|
| -
|
| - if (fieldName === 'metadata') {
|
| - var metadata = container[fieldName];
|
| - if (metadata['highres-ticks']) {
|
| - this.model_.isTimeHighResolution = metadata['highres-ticks'];
|
| - }
|
| - if (metadata['clock-domain']) {
|
| - this.clockDomainId_ = metadata['clock-domain'];
|
| - }
|
| - }
|
| - }
|
| + this.storeSubtrace_(container[subtraceField]);
|
| + }
|
| + }
|
| + this.storeSamples_(container.samples);
|
| + this.storeStackFrames_(container.stackFrames);
|
| + this.storeDisplayTimeUnit_(container.displayTimeUnit);
|
| + this.storeTraceAnnotations_(container.traceAnnotations);
|
| + this.storeMetadata_(container);
|
| + } else if (this.events_ instanceof tr.b.TraceStream) {
|
| + const parser = oboe()
|
| + .node('{cat ph}', function(e) { return oboe.drop; })
|
| + .node('!.powerTraceAsString', this.storeSubtrace_.bind(this))
|
| + .node('!.systemTraceEvents', this.storeSubtrace_.bind(this))
|
| + .node('!.samples', this.storeSamples_.bind(this))
|
| + .node('!.stackFrames', this.storeStackFrames_.bind(this))
|
| + .node('!.displayTimeUnit', this.storeDisplayTimeUnit_.bind(this))
|
| + .node('!.traceAnnotations', this.storeTraceAnnotations_.bind(this))
|
| + .done(this.storeMetadata_.bind(this));
|
| + this.events_.rewind();
|
| + while (this.events_.hasData) {
|
| + parser.write(this.events_.readNumBytes());
|
| + }
|
| + parser.finish();
|
| }
|
| }
|
|
|
| @@ -255,6 +244,11 @@ tr.exportTo('tr.e.importer', function() {
|
| // - eventData that starts with [ are probably trace_event
|
| // - eventData that starts with { are probably trace_event
|
| // May be encoded JSON. Treat files that start with { as importable by us.
|
| + if (eventData instanceof tr.b.TraceStream) {
|
| + if (eventData.isBinary) return false;
|
| + eventData = eventData.header;
|
| + }
|
| +
|
| if (typeof(eventData) === 'string' || eventData instanceof String) {
|
| eventData = eventData.trim();
|
| return eventData[0] === '{' || eventData[0] === '[';
|
| @@ -271,7 +265,8 @@ tr.exportTo('tr.e.importer', function() {
|
| if (eventData.traceEvents.length && eventData.traceEvents[0].ph) {
|
| return true;
|
| }
|
| - if (eventData.samples.length && eventData.stackFrames !== undefined) {
|
| + if (eventData.samples && eventData.samples.length &&
|
| + eventData.stackFrames !== undefined) {
|
| return true;
|
| }
|
| }
|
| @@ -1079,24 +1074,36 @@ tr.exportTo('tr.e.importer', function() {
|
| },
|
|
|
| importClockSyncMarkers: function() {
|
| - for (var i = 0; i < this.events_.length; i++) {
|
| - var event = this.events_[i];
|
| + if (this.events_ instanceof tr.b.TraceStream) {
|
| + const parser = oboe().node(
|
| + '{cat ph}', this.importClockSyncMarker_.bind(this));
|
| + this.events_.rewind();
|
| + while (this.events_.hasData) {
|
| + parser.write(this.events_.readNumBytes());
|
| + }
|
| + parser.finish();
|
| + } else {
|
| + for (let i = 0; i < this.events_.length; i++) {
|
| + this.importClockSyncMarker_(this.events_[i]);
|
| + }
|
| + }
|
| + },
|
|
|
| - var isLegacyChromeClockSync = isLegacyChromeClockSyncEvent(event);
|
| - if (event.ph !== 'c' && !isLegacyChromeClockSync) continue;
|
| + importClockSyncMarker_: function(event) {
|
| + const isLegacyChromeClockSync = isLegacyChromeClockSyncEvent(event);
|
| + if (event.ph !== 'c' && !isLegacyChromeClockSync) return;
|
|
|
| - var eventSizeInBytes =
|
| - this.model_.importOptions.trackDetailedModelStats ?
|
| - JSON.stringify(event).length : undefined;
|
| + const eventSizeInBytes =
|
| + this.model_.importOptions.trackDetailedModelStats ?
|
| + JSON.stringify(event).length : undefined;
|
|
|
| - this.model_.stats.willProcessBasicTraceEvent(
|
| - 'clock_sync', event.cat, event.name, event.ts, eventSizeInBytes);
|
| + this.model_.stats.willProcessBasicTraceEvent(
|
| + 'clock_sync', event.cat, event.name, event.ts, eventSizeInBytes);
|
|
|
| - if (isLegacyChromeClockSync) {
|
| - this.processLegacyChromeClockSyncEvent(event);
|
| - } else {
|
| - this.processClockSyncEvent(event);
|
| - }
|
| + if (isLegacyChromeClockSync) {
|
| + this.processLegacyChromeClockSyncEvent(event);
|
| + } else {
|
| + this.processClockSyncEvent(event);
|
| }
|
| },
|
|
|
| @@ -1105,95 +1112,199 @@ tr.exportTo('tr.e.importer', function() {
|
| * model_.
|
| */
|
| importEvents: function() {
|
| + this.hasEvents_ = false;
|
| if (this.stackFrameEvents_) {
|
| this.importStackFrames_(this.stackFrameEvents_, 'g');
|
| }
|
|
|
| - if (this.traceAnnotations_) {
|
| - this.importAnnotations_();
|
| + if (this.traceAnnotations_) this.importAnnotations_();
|
| +
|
| + if (this.events_ instanceof tr.b.TraceStream) {
|
| + const parser = oboe().node('{cat ph}', this.processEvent_.bind(this));
|
| + this.events_.rewind();
|
| + while (this.events_.hasData) {
|
| + parser.write(this.events_.readNumBytes());
|
| + }
|
| + parser.finish();
|
| + } else {
|
| + for (let eI = 0; eI < this.events_.length; eI++) {
|
| + this.processEvent_(this.events_[eI]);
|
| + }
|
| }
|
|
|
| - var importOptions = this.model_.importOptions;
|
| - var trackDetailedModelStats = importOptions.trackDetailedModelStats;
|
| + this.processV8Events();
|
|
|
| - var modelStats = this.model_.stats;
|
| + // Remove all the root stack frame children as they should
|
| + // already be added.
|
| + for (const frame of Object.values(this.v8ProcessRootStackFrame_)) {
|
| + frame.removeAllChildren();
|
| + }
|
| + },
|
|
|
| - var events = this.events_;
|
| - for (var eI = 0; eI < events.length; eI++) {
|
| - var event = events[eI];
|
| + // Some trace authors store subtraces as specific properties of the trace.
|
| + storeSubtrace_: function(subtrace) {
|
| + this.subtraces_.push(subtrace);
|
| + return oboe.drop;
|
| + },
|
|
|
| - if (event.args === '__stripped__') {
|
| - event.argsStripped = true;
|
| - event.args = undefined;
|
| - }
|
| + storeSamples_: function(samples) {
|
| + this.sampleEvents_ = samples;
|
| + return oboe.drop;
|
| + },
|
|
|
| - var eventSizeInBytes;
|
| - if (trackDetailedModelStats) {
|
| - eventSizeInBytes = JSON.stringify(event).length;
|
| - } else {
|
| - eventSizeInBytes = undefined;
|
| + storeStackFrames_: function(stackFrames) {
|
| + this.stackFrameEvents_ = stackFrames;
|
| + return oboe.drop;
|
| + },
|
| +
|
| + // Some implementations specify displayTimeUnit
|
| + storeDisplayTimeUnit_: function(unitName) {
|
| + if (!unitName) return;
|
| + const unit = tr.b.TimeDisplayModes[unitName];
|
| + if (unit === undefined) {
|
| + throw new Error('Unit ' + unitName + ' is not supported.');
|
| + }
|
| + this.model_.intrinsicTimeUnit = unit;
|
| + return oboe.drop;
|
| + },
|
| +
|
| + storeTraceAnnotations_: function(traceAnnotations) {
|
| + this.traceAnnotations_ = traceAnnotations;
|
| + return oboe.drop;
|
| + },
|
| +
|
| + // Any fields in the container that is not in NON_METADATA_FIELDS should be
|
| + // treated as metadata.
|
| + storeMetadata_: function(container) {
|
| + for (const fieldName of Object.keys(container)) {
|
| + if (NON_METADATA_FIELDS.has(fieldName)) continue;
|
| + this.model_.metadata.push(
|
| + { name: fieldName, value: container[fieldName] });
|
| + if (fieldName !== 'metadata') continue;
|
| + const metadata = container[fieldName];
|
| + if (metadata['highres-ticks']) {
|
| + this.model_.isTimeHighResolution = metadata['highres-ticks'];
|
| }
|
| + if (metadata['clock-domain']) {
|
| + this.clockDomainId_ = metadata['clock-domain'];
|
| + }
|
| + }
|
| + return oboe.drop;
|
| + },
|
|
|
| - if (event.ph === 'B' || event.ph === 'E') {
|
| + processEvent_: function(event) {
|
| + this.hasEvents_ = true;
|
| + const importOptions = this.model_.importOptions;
|
| + const trackDetailedModelStats = importOptions.trackDetailedModelStats;
|
| + const modelStats = this.model_.stats;
|
| +
|
| + if (event.args === '__stripped__') {
|
| + event.argsStripped = true;
|
| + event.args = undefined;
|
| + }
|
| +
|
| + let eventSizeInBytes = undefined;
|
| + if (trackDetailedModelStats) {
|
| + eventSizeInBytes = JSON.stringify(event).length;
|
| + }
|
| +
|
| + switch (event.ph) {
|
| + case 'B':
|
| + case 'E':
|
| modelStats.willProcessBasicTraceEvent(
|
| 'begin_end (non-compact)', event.cat, event.name, event.ts,
|
| eventSizeInBytes);
|
| this.processDurationEvent(event);
|
| - } else if (event.ph === 'X') {
|
| + break;
|
| +
|
| + case 'X': {
|
| modelStats.willProcessBasicTraceEvent(
|
| 'begin_end (compact)', event.cat, event.name, event.ts,
|
| eventSizeInBytes);
|
| - var slice = this.processCompleteEvent(event);
|
| + const slice = this.processCompleteEvent(event);
|
| // TODO(yuhaoz): If Chrome supports creating other events with flow,
|
| // we will need to call processFlowEvent for them also.
|
| // https://github.com/catapult-project/catapult/issues/1259
|
| if (slice !== undefined && event.bind_id !== undefined) {
|
| this.processFlowEvent(event, slice);
|
| }
|
| - } else if (event.ph === 'b' || event.ph === 'e' || event.ph === 'n' ||
|
| - event.ph === 'S' || event.ph === 'F' || event.ph === 'T' ||
|
| - event.ph === 'p') {
|
| + break;
|
| + }
|
| +
|
| + case 'b':
|
| + case 'e':
|
| + case 'n':
|
| + case 'S':
|
| + case 'F':
|
| + case 'T':
|
| + case 'p':
|
| modelStats.willProcessBasicTraceEvent(
|
| 'async', event.cat, event.name, event.ts, eventSizeInBytes);
|
| this.processAsyncEvent(event);
|
| + break;
|
|
|
| // Note, I is historic. The instant event marker got changed, but we
|
| // want to support loading old trace files so we have both I and i.
|
| - } else if (event.ph === 'I' || event.ph === 'i' || event.ph === 'R') {
|
| + case 'I':
|
| + case 'i':
|
| + case 'R':
|
| modelStats.willProcessBasicTraceEvent(
|
| 'instant', event.cat, event.name, event.ts, eventSizeInBytes);
|
| this.processInstantEvent(event);
|
| - } else if (event.ph === 'P') {
|
| + break;
|
| +
|
| + case 'P':
|
| modelStats.willProcessBasicTraceEvent(
|
| 'samples', event.cat, event.name, event.ts, eventSizeInBytes);
|
| this.processTraceSampleEvent(event);
|
| - } else if (event.ph === 'C') {
|
| + break;
|
| +
|
| + case 'C':
|
| modelStats.willProcessBasicTraceEvent(
|
| 'counters', event.cat, event.name, event.ts, eventSizeInBytes);
|
| this.processCounterEvent(event);
|
| - } else if (event.ph === 'M') {
|
| + break;
|
| +
|
| + case 'M':
|
| modelStats.willProcessBasicTraceEvent(
|
| 'metadata', event.cat, event.name, event.ts, eventSizeInBytes);
|
| this.processMetadataEvent(event);
|
| - } else if (event.ph === 'N' || event.ph === 'D' || event.ph === 'O') {
|
| + break;
|
| +
|
| + case 'N':
|
| + case 'D':
|
| + case 'O':
|
| modelStats.willProcessBasicTraceEvent(
|
| 'objects', event.cat, event.name, event.ts, eventSizeInBytes);
|
| this.processObjectEvent(event);
|
| - } else if (event.ph === 's' || event.ph === 't' || event.ph === 'f') {
|
| + break;
|
| +
|
| + case 's':
|
| + case 't':
|
| + case 'f':
|
| modelStats.willProcessBasicTraceEvent(
|
| 'flows', event.cat, event.name, event.ts, eventSizeInBytes);
|
| this.processFlowEvent(event);
|
| - } else if (event.ph === 'v') {
|
| + break;
|
| +
|
| + case 'v':
|
| modelStats.willProcessBasicTraceEvent(
|
| 'memory_dumps', event.cat, event.name, event.ts,
|
| eventSizeInBytes);
|
| this.processMemoryDumpEvent(event);
|
| - } else if (event.ph === '(' || event.ph === ')') {
|
| + break;
|
| +
|
| + case '(':
|
| + case ')':
|
| this.processContextEvent(event);
|
| - } else if (event.ph === 'c') {
|
| - // No-op. Clock sync events have already been processed in
|
| - // importClockSyncMarkers().
|
| - } else {
|
| + break;
|
| +
|
| + // No-op. Clock sync events have already been processed in
|
| + // importClockSyncMarkers().
|
| + case 'c':
|
| + break;
|
| +
|
| + default:
|
| modelStats.willProcessBasicTraceEvent(
|
| 'unknown', event.cat, event.name, event.ts, eventSizeInBytes);
|
| this.model_.importWarning({
|
| @@ -1201,15 +1312,8 @@ tr.exportTo('tr.e.importer', function() {
|
| message: 'Unrecognized event phase: ' +
|
| event.ph + ' (' + event.name + ')'
|
| });
|
| - }
|
| - }
|
| - this.processV8Events();
|
| -
|
| - // Remove all the root stack frame children as they should
|
| - // already be added.
|
| - for (var frame of Object.values(this.v8ProcessRootStackFrame_)) {
|
| - frame.removeAllChildren();
|
| }
|
| + return oboe.drop;
|
| },
|
|
|
| importStackFrames_: function(rawStackFrames, idPrefix) {
|
| @@ -1424,7 +1528,9 @@ tr.exportTo('tr.e.importer', function() {
|
|
|
| // If this is the only importer, then fake-create the threads.
|
| var events = this.sampleEvents_;
|
| - if (this.events_.length === 0) {
|
| + if (this.hasEvents_ === undefined) {
|
| + throw new Error('importEvents is not run before importSampleData');
|
| + } else if (!this.hasEvents_) {
|
| for (var i = 0; i < events.length; i++) {
|
| var event = events[i];
|
| m.getOrCreateProcess(event.tid).getOrCreateThread(event.tid);
|
|
|