summaryrefslogtreecommitdiffstats
path: root/chromium/third_party/trace-viewer/src/tracing/trace_model.js
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/third_party/trace-viewer/src/tracing/trace_model.js')
-rw-r--r--chromium/third_party/trace-viewer/src/tracing/trace_model.js507
1 files changed, 0 insertions, 507 deletions
diff --git a/chromium/third_party/trace-viewer/src/tracing/trace_model.js b/chromium/third_party/trace-viewer/src/tracing/trace_model.js
deleted file mode 100644
index 8fb50b3f409..00000000000
--- a/chromium/third_party/trace-viewer/src/tracing/trace_model.js
+++ /dev/null
@@ -1,507 +0,0 @@
-// Copyright (c) 2012 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.
-
-'use strict';
-
-/**
- * @fileoverview TraceModel is a parsed representation of the
- * TraceEvents obtained from base/trace_event in which the begin-end
- * tokens are converted into a hierarchy of processes, threads,
- * subrows, and slices.
- *
- * The building block of the model is a slice. A slice is roughly
- * equivalent to function call executing on a specific thread. As a
- * result, slices may have one or more subslices.
- *
- * A thread contains one or more subrows of slices. Row 0 corresponds to
- * the "root" slices, e.g. the topmost slices. Row 1 contains slices that
- * are nested 1 deep in the stack, and so on. We use these subrows to draw
- * nesting tasks.
- *
- */
-base.require('base.range');
-base.require('base.events');
-base.require('base.interval_tree');
-base.require('tracing.importer.importer');
-base.require('tracing.importer.task');
-base.require('tracing.trace_model.process');
-base.require('tracing.trace_model.kernel');
-base.require('tracing.filter');
-base.require('ui.overlay');
-
-base.exportTo('tracing', function() {
-
- var Importer = tracing.importer.Importer;
- var Process = tracing.trace_model.Process;
- var Kernel = tracing.trace_model.Kernel;
-
- /**
- * Builds a model from an array of TraceEvent objects.
- * @param {Object=} opt_eventData Data from a single trace to be imported into
- * the new model. See TraceModel.importTraces for details on how to
- * import multiple traces at once.
- * @param {bool=} opt_shiftWorldToZero Whether to shift the world to zero.
- * Defaults to true.
- * @constructor
- */
- function TraceModel(opt_eventData, opt_shiftWorldToZero) {
- this.kernel = new Kernel(this);
- this.processes = {};
- this.metadata = [];
- this.categories = [];
- this.bounds = new base.Range();
- this.instantEvents = [];
- this.flowEvents = [];
-
- this.flowIntervalTree = new base.IntervalTree(
- function(s) { return s.start; },
- function(e) { return e.start; });
-
- this.importWarnings_ = [];
- this.reportedImportWarnings_ = {};
-
- if (opt_eventData)
- this.importTraces([opt_eventData], opt_shiftWorldToZero);
- }
-
- TraceModel.importerConstructors_ = [];
-
- /**
- * Registers an importer. All registered importers are considered
- * when processing an import request.
- *
- * @param {Function} importerConstructor The importer's constructor function.
- */
- TraceModel.registerImporter = function(importerConstructor) {
- TraceModel.importerConstructors_.push(importerConstructor);
- };
-
- TraceModel.prototype = {
- __proto__: base.EventTarget.prototype,
-
- get numProcesses() {
- var n = 0;
- for (var p in this.processes)
- n++;
- return n;
- },
-
- /**
- * @return {Process} Gets a TimlineProcess for a specified pid or
- * creates one if it does not exist.
- */
- getOrCreateProcess: function(pid) {
- if (!this.processes[pid])
- this.processes[pid] = new Process(this, pid);
- return this.processes[pid];
- },
-
- pushInstantEvent: function(instantEvent) {
- this.instantEvents.push(instantEvent);
- },
-
- /**
- * Generates the set of categories from the slices and counters.
- */
- updateCategories_: function() {
- var categoriesDict = {};
- this.kernel.addCategoriesToDict(categoriesDict);
- for (var pid in this.processes)
- this.processes[pid].addCategoriesToDict(categoriesDict);
-
- this.categories = [];
- for (var category in categoriesDict)
- if (category != '')
- this.categories.push(category);
- },
-
- updateBounds: function() {
- this.bounds.reset();
-
- this.kernel.updateBounds();
- this.bounds.addRange(this.kernel.bounds);
-
- for (var pid in this.processes) {
- this.processes[pid].updateBounds();
- this.bounds.addRange(this.processes[pid].bounds);
- }
- },
-
- shiftWorldToZero: function() {
- if (this.bounds.isEmpty)
- return;
- var timeBase = this.bounds.min;
- this.kernel.shiftTimestampsForward(-timeBase);
-
- for (var id in this.instantEvents)
- this.instantEvents[id].start -= timeBase;
-
- for (var pid in this.processes)
- this.processes[pid].shiftTimestampsForward(-timeBase);
-
- this.updateBounds();
- },
-
- getAllThreads: function() {
- var threads = [];
- for (var tid in this.kernel.threads) {
- threads.push(process.threads[tid]);
- }
- for (var pid in this.processes) {
- var process = this.processes[pid];
- for (var tid in process.threads) {
- threads.push(process.threads[tid]);
- }
- }
- return threads;
- },
-
- /**
- * @return {Array} An array of all processes in the model.
- */
- getAllProcesses: function() {
- var processes = [];
- for (var pid in this.processes)
- processes.push(this.processes[pid]);
- return processes;
- },
-
- /**
- * @return {Array} An array of all the counters in the model.
- */
- getAllCounters: function() {
- var counters = [];
- counters.push.apply(
- counters, base.dictionaryValues(this.kernel.counters));
- for (var pid in this.processes) {
- var process = this.processes[pid];
- for (var tid in process.counters) {
- counters.push(process.counters[tid]);
- }
- }
- return counters;
- },
-
- /**
- * @param {String} The name of the thread to find.
- * @return {Array} An array of all the matched threads.
- */
- findAllThreadsNamed: function(name) {
- var namedThreads = [];
- namedThreads.push.apply(
- namedThreads,
- this.kernel.findAllThreadsNamed(name));
- for (var pid in this.processes) {
- namedThreads.push.apply(
- namedThreads,
- this.processes[pid].findAllThreadsNamed(name));
- }
- return namedThreads;
- },
-
- createImporter_: function(eventData) {
- var importerConstructor;
- for (var i = 0; i < TraceModel.importerConstructors_.length; ++i) {
- if (TraceModel.importerConstructors_[i].canImport(eventData)) {
- importerConstructor = TraceModel.importerConstructors_[i];
- break;
- }
- }
- if (!importerConstructor)
- throw new Error(
- 'Could not find an importer for the provided eventData.');
-
- var importer = new importerConstructor(
- this, eventData);
- return importer;
- },
-
- /**
- * Imports the provided traces into the model. The eventData type
- * is undefined and will be passed to all the importers registered
- * via TraceModel.registerImporter. The first importer that returns true
- * for canImport(events) will be used to import the events.
- *
- * The primary trace is provided via the eventData variable. If multiple
- * traces are to be imported, specify the first one as events, and the
- * remainder in the opt_additionalEventData array.
- *
- * @param {Array} traces An array of eventData to be imported. Each
- * eventData should correspond to a single trace file and will be handled by
- * a separate importer.
- * @param {bool=} opt_shiftWorldToZero Whether to shift the world to zero.
- * Defaults to true.
- * @param {bool=} opt_pruneEmptyContainers Whether to prune empty
- * containers. Defaults to true.
- */
- importTraces: function(traces,
- opt_shiftWorldToZero,
- opt_pruneEmptyContainers) {
- var progressMeter = {
- update: function(msg) {}
- };
- var task = this.createImportTracesTask(
- progressMeter,
- traces,
- opt_shiftWorldToZero,
- opt_pruneEmptyContainers);
- tracing.importer.Task.RunSynchronously(task);
- },
-
- /**
- * Imports a trace with the usual options from importTraces, but
- * does so using idle callbacks, putting up an import dialog
- * during the import process.
- */
- importTracesWithProgressDialog: function(traces,
- opt_shiftWorldToZero,
- opt_pruneEmptyContainers) {
- var overlay = ui.Overlay();
- overlay.title = 'Importing...';
- overlay.userCanClose = false;
- overlay.msgEl = document.createElement('div');
- overlay.appendChild(overlay.msgEl);
- overlay.msgEl.style.margin = '20px';
- overlay.update = function(msg) {
- this.msgEl.textContent = msg;
- }
- overlay.visible = true;
-
- var task = this.createImportTracesTask(
- overlay,
- traces,
- opt_shiftWorldToZero,
- opt_pruneEmptyContainers);
- var promise = tracing.importer.Task.RunWhenIdle(task);
- promise.then(
- function() {
- overlay.visible = false;
- }, function(err) {
- overlay.visible = false;
- });
- return promise;
- },
-
- /**
- * Creates a task that will import the provided traces into the model,
- * updating the progressMeter as it goes. Parameters are as defined in
- * importTraces.
- */
- createImportTracesTask: function(progressMeter,
- traces,
- opt_shiftWorldToZero,
- opt_pruneEmptyContainers) {
- if (this.importing_)
- throw new Error('Already importing.');
- if (opt_shiftWorldToZero === undefined)
- opt_shiftWorldToZero = true;
- if (opt_pruneEmptyContainers === undefined)
- opt_pruneEmptyContainers = true;
- this.importing_ = true;
-
- // Just some simple setup. It is useful to have a nop first
- // task so that we can set up the lastTask = lastTask.after()
- // pattern that follows.
- var importTask = new tracing.importer.Task(function() {
- progressMeter.update('I will now import your traces for you...');
- }, this);
- var lastTask = importTask;
-
- var importers = [];
-
- lastTask = lastTask.after(function() {
- // Copy the traces array, we may mutate it.
- traces = traces.slice(0);
- progressMeter.update('Creating importers...');
- // Figure out which importers to use.
- for (var i = 0; i < traces.length; ++i)
- importers.push(this.createImporter_(traces[i]));
-
- // Some traces have other traces inside them. Before doing the full
- // import, ask the importer if it has any subtraces, and if so, create
- // importers for them, also.
- for (var i = 0; i < importers.length; i++) {
- var subtraces = importers[i].extractSubtraces();
- for (var j = 0; j < subtraces.length; j++) {
- traces.push(subtraces[j]);
- importers.push(this.createImporter_(subtraces[j]));
- }
- }
-
- // Sort them on priority. This ensures importing happens in a
- // predictable order, e.g. linux_perf_importer before
- // trace_event_importer.
- importers.sort(function(x, y) {
- return x.importPriority - y.importPriority;
- });
- }, this);
-
- // Run the import.
- lastTask = lastTask.after(function(task) {
- importers.forEach(function(importer, index) {
- task.subTask(function() {
- progressMeter.update(
- 'Importing ' + (index + 1) + ' of ' + importers.length);
- importer.importEvents(index > 0);
- }, this);
- }, this);
- }, this);
-
- // Autoclose open slices.
- lastTask = lastTask.after(function() {
- progressMeter.update('Autoclosing open slices...');
- this.updateBounds();
- this.kernel.autoCloseOpenSlices(this.bounds.max);
- for (var pid in this.processes)
- this.processes[pid].autoCloseOpenSlices(this.bounds.max);
- }, this);
-
- // Finalize import.
- lastTask = lastTask.after(function(task) {
- importers.forEach(function(importer, index) {
- progressMeter.update(
- 'Finalizing import ' + (index + 1) + '/' + importers.length);
- importer.finalizeImport();
- }, this);
- }, this);
-
- // Run preinit.
- lastTask = lastTask.after(function() {
- progressMeter.update('Initializing objects (step 1/2)...');
- for (var pid in this.processes)
- this.processes[pid].preInitializeObjects();
- }, this);
-
- // Prune empty containers.
- if (opt_pruneEmptyContainers) {
- lastTask = lastTask.after(function() {
- progressMeter.update('Pruning empty containers...');
- this.kernel.pruneEmptyContainers();
- for (var pid in this.processes) {
- this.processes[pid].pruneEmptyContainers();
- }
- }, this);
- }
-
- // Merge kernel and userland slices on each thread.
- lastTask = lastTask.after(function() {
- progressMeter.update('Merging kernel with userland...');
- for (var pid in this.processes)
- this.processes[pid].mergeKernelWithUserland();
- }, this);
-
- lastTask = lastTask.after(function() {
- progressMeter.update('Computing final world bounds...');
- this.updateBounds();
- this.updateCategories_();
-
- if (opt_shiftWorldToZero)
- this.shiftWorldToZero();
- }, this);
-
- // Build the flow event interval tree.
- lastTask = lastTask.after(function() {
- progressMeter.update('Building flow event map...');
- for (var i = 0; i < this.flowEvents.length; ++i) {
- var pair = this.flowEvents[i];
- this.flowIntervalTree.insert(pair[0], pair[1]);
- }
- this.flowIntervalTree.updateHighValues();
- }, this);
-
- // Join refs.
- lastTask = lastTask.after(function() {
- progressMeter.update('Joining object refs...');
- for (var i = 0; i < importers.length; i++)
- importers[i].joinRefs();
- }, this);
-
- // Delete any undeleted objects.
- lastTask = lastTask.after(function() {
- progressMeter.update('Cleaning up undeleted objects...');
- for (var pid in this.processes)
- this.processes[pid].autoDeleteObjects(this.bounds.max);
- }, this);
-
- // Run initializers.
- lastTask = lastTask.after(function() {
- progressMeter.update('Initializing objects (step 2/2)...');
- for (var pid in this.processes)
- this.processes[pid].initializeObjects();
- }, this);
-
- // Cleanup.
- lastTask.after(function() {
- this.importing_ = false;
- }, this);
- return importTask;
- },
-
- /**
- * @param {Object} data The import warning data. Data must provide two
- * accessors: type, message. The types are used to determine if we
- * should output the message, we'll only output one message of each type.
- * The message is the actual warning content.
- */
- importWarning: function(data) {
- this.importWarnings_.push(data);
-
- // Only log each warning type once. We may want to add some kind of
- // flag to allow reporting all importer warnings.
- if (this.reportedImportWarnings_[data.type] === true)
- return;
-
- console.warn(data.message);
- this.reportedImportWarnings_[data.type] = true;
- },
-
- get hasImportWarnings() {
- return (this.importWarnings_.length > 0);
- },
-
- get importWarnings() {
- return this.importWarnings_;
- },
-
- /**
- * Iterates all events in the model and calls callback on each event.
- * @param {function(event)} callback The callback called for every event.
- */
- iterateAllEvents: function(callback) {
- this.instantEvents.forEach(callback);
-
- this.kernel.iterateAllEvents(callback);
-
- for (var pid in this.processes)
- this.processes[pid].iterateAllEvents(callback);
- }
- };
-
- /**
- * Importer for empty strings and arrays.
- * @constructor
- */
- function TraceModelEmptyImporter(events) {
- this.importPriority = 0;
- };
-
- TraceModelEmptyImporter.canImport = function(eventData) {
- if (eventData instanceof Array && eventData.length == 0)
- return true;
- if (typeof(eventData) === 'string' || eventData instanceof String) {
- return eventData.length == 0;
- }
- return false;
- };
-
- TraceModelEmptyImporter.prototype = {
- __proto__: Importer.prototype
- };
-
- TraceModel.registerImporter(TraceModelEmptyImporter);
-
- return {
- TraceModel: TraceModel
- };
-});