| Index: chrome/browser/resources/gpu_internals/timeline_model.js
|
| diff --git a/chrome/browser/resources/gpu_internals/timeline_model.js b/chrome/browser/resources/gpu_internals/timeline_model.js
|
| deleted file mode 100644
|
| index a92d6ac3f0b1a0c081fcc4809632d2a04e02b453..0000000000000000000000000000000000000000
|
| --- a/chrome/browser/resources/gpu_internals/timeline_model.js
|
| +++ /dev/null
|
| @@ -1,419 +0,0 @@
|
| -// Copyright (c) 2011 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.
|
| -
|
| -
|
| -/**
|
| - * @fileoverview TimelineModel 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.
|
| - *
|
| - */
|
| -cr.define('gpu', function() {
|
| - /**
|
| - * A TimelineSlice represents an interval of time on a given thread
|
| - * associated with a specific trace event. For example,
|
| - * TRACE_EVENT_BEGIN1("x","myArg", 7) at time=0.1ms
|
| - * TRACE_EVENT_END() at time=0.3ms
|
| - * Results in a single timeline slice from 0.1 with duration 0.2.
|
| - *
|
| - * All time units are stored in milliseconds.
|
| - * @constructor
|
| - */
|
| - function TimelineSlice(title, colorId, start, args) {
|
| - this.title = title;
|
| - this.start = start;
|
| - this.colorId = colorId;
|
| - this.args = args;
|
| - this.didNotFinish = false;
|
| - this.subSlices = [];
|
| - }
|
| -
|
| - TimelineSlice.prototype = {
|
| - selected: false,
|
| -
|
| - duration: undefined,
|
| -
|
| - get end() {
|
| - return this.start + this.duration;
|
| - }
|
| - };
|
| -
|
| - /**
|
| - * A TimelineThread stores all the trace events collected for a particular
|
| - * thread. We organize the slices on a thread by "subrows," where subrow 0
|
| - * has all the root slices, subrow 1 those nested 1 deep, and so on. There
|
| - * is also a set of non-nested subrows.
|
| - *
|
| - * @constructor
|
| - */
|
| - function TimelineThread(parent, tid) {
|
| - this.parent = parent;
|
| - this.tid = tid;
|
| - this.subRows = [[]];
|
| - this.nonNestedSubRows = [];
|
| - }
|
| -
|
| - TimelineThread.prototype = {
|
| - /**
|
| - * Name of the thread, if present.
|
| - */
|
| - name: undefined,
|
| -
|
| - getSubrow: function(i) {
|
| - while (i >= this.subRows.length)
|
| - this.subRows.push([]);
|
| - return this.subRows[i];
|
| - },
|
| -
|
| - addNonNestedSlice: function(slice) {
|
| - for (var i = 0; i < this.nonNestedSubRows.length; i++) {
|
| - var currSubRow = this.nonNestedSubRows[i];
|
| - var lastSlice = currSubRow[currSubRow.length - 1];
|
| - if (slice.start >= lastSlice.start + lastSlice.duration) {
|
| - currSubRow.push(slice);
|
| - return;
|
| - }
|
| - }
|
| - this.nonNestedSubRows.push([slice]);
|
| - },
|
| -
|
| - /**
|
| - * Updates the minTimestamp and maxTimestamp fields based on the
|
| - * current slices and nonNestedSubRows attached to the thread.
|
| - */
|
| - updateBounds: function() {
|
| - var values = [];
|
| - var slices;
|
| - if (this.subRows[0].length != 0) {
|
| - slices = this.subRows[0];
|
| - values.push(slices[0].start);
|
| - values.push(slices[slices.length - 1].end);
|
| - }
|
| - for (var i = 0; i < this.nonNestedSubRows.length; ++i) {
|
| - slices = this.nonNestedSubRows[i];
|
| - values.push(slices[0].start);
|
| - values.push(slices[slices.length - 1].end);
|
| - }
|
| - if (values.length) {
|
| - this.minTimestamp = Math.min.apply(Math, values);
|
| - this.maxTimestamp = Math.max.apply(Math, values);
|
| - } else {
|
| - this.minTimestamp = undefined;
|
| - this.maxTimestamp = undefined;
|
| - }
|
| - }
|
| -
|
| - };
|
| -
|
| - /**
|
| - * Comparison between threads that orders first by pid,
|
| - * then by names, then by tid.
|
| - */
|
| - TimelineThread.compare = function(x,y) {
|
| - if(x.parent.pid != y.parent.pid) {
|
| - return x.parent.pid - y.parent.pid;
|
| - }
|
| -
|
| - if (x.name && y.name) {
|
| - var tmp = x.name.localeCompare(y.name);
|
| - if (tmp == 0)
|
| - return x.tid - y.tid;
|
| - return tmp;
|
| - } else if (x.name) {
|
| - return -1;
|
| - } else if (y.name){
|
| - return 1;
|
| - } else {
|
| - return x.tid - y.tid;
|
| - }
|
| - };
|
| -
|
| -
|
| - /**
|
| - * The TimelineProcess represents a single process in the
|
| - * trace. Right now, we keep this around purely for bookkeeping
|
| - * reasons.
|
| - * @constructor
|
| - */
|
| - function TimelineProcess(pid) {
|
| - this.pid = pid;
|
| - this.threads = {};
|
| - };
|
| -
|
| - TimelineProcess.prototype = {
|
| - getThread: function(tid) {
|
| - if (!this.threads[tid])
|
| - this.threads[tid] = new TimelineThread(this, tid);
|
| - return this.threads[tid];
|
| - }
|
| - };
|
| -
|
| - /**
|
| - * Builds a model from an array of TraceEvent objects.
|
| - * @param {Array} events An array of TraceEvents created by
|
| - * TraceEvent.ToJSON().
|
| - * @constructor
|
| - */
|
| - function TimelineModel(events) {
|
| - this.processes = {};
|
| - this.importErrors = [];
|
| -
|
| - if (events)
|
| - this.importEvents(events);
|
| - }
|
| -
|
| - TimelineModel.prototype = {
|
| - __proto__: cr.EventTarget.prototype,
|
| -
|
| - getProcess: function(pid) {
|
| - if (!this.processes[pid])
|
| - this.processes[pid] = new TimelineProcess(pid);
|
| - return this.processes[pid];
|
| - },
|
| -
|
| - /**
|
| - * The import takes an array of json-ified TraceEvents and adds them into
|
| - * the TimelineModel as processes, threads, and slices.
|
| - */
|
| - importEvents: function(events) {
|
| - // A ptid is a pid and tid joined together x:y fashion, eg 1024:130
|
| - // The ptid is a unique key for a thread in the trace.
|
| - this.importErrors = [];
|
| -
|
| - // Threadstate
|
| - const numColorIds = 30;
|
| - function ThreadState(tid) {
|
| - this.openSlices = [];
|
| - this.openNonNestedSlices = {};
|
| - }
|
| - var threadStateByPTID = {};
|
| -
|
| - var nameToColorMap = {};
|
| - function getColor(name) {
|
| - if (!(name in nameToColorMap)) {
|
| - // Compute a simplistic hashcode of the string so we get consistent
|
| - // coloring across traces.
|
| - var hash = 0;
|
| - for (var i = 0; i < name.length; ++i)
|
| - hash = (hash + 37 * hash + 11 * name.charCodeAt(i)) % 0xFFFFFFFF;
|
| - nameToColorMap[name] = hash % numColorIds;
|
| - }
|
| - return nameToColorMap[name];
|
| - }
|
| -
|
| - var self = this;
|
| -
|
| - /**
|
| - * Helper to process a 'begin' event (e.g. initiate a slice).
|
| - * @param {ThreadState} state Thread state (holds slices).
|
| - * @param {Object} event The current trace event.
|
| - */
|
| - function processBegin(state, event) {
|
| - var colorId = getColor(event.name);
|
| - var slice =
|
| - { index: eI,
|
| - slice: new TimelineSlice(event.name, colorId, event.ts,
|
| - event.args) };
|
| - if (event.args['ui-nest'] === '0') {
|
| - var sliceID = event.name;
|
| - for (var x in event.args)
|
| - sliceID += ';' + event.args[x];
|
| - if (state.openNonNestedSlices[sliceID])
|
| - this.importErrors.push('Event ' + sliceID + ' already open.');
|
| - state.openNonNestedSlices[sliceID] = slice;
|
| - } else {
|
| - state.openSlices.push(slice);
|
| - }
|
| - }
|
| -
|
| - /**
|
| - * Helper to process an 'end' event (e.g. close a slice).
|
| - * @param {ThreadState} state Thread state (holds slices).
|
| - * @param {Object} event The current trace event.
|
| - */
|
| - function processEnd(state, event) {
|
| - if (event.args['ui-nest'] === '0') {
|
| - var sliceID = event.name;
|
| - for (var x in event.args)
|
| - sliceID += ';' + event.args[x];
|
| - var slice = state.openNonNestedSlices[sliceID];
|
| - if (!slice)
|
| - return;
|
| - slice.slice.duration = event.ts - slice.slice.start;
|
| -
|
| - // Store the slice in a non-nested subrow.
|
| - var thread = self.getProcess(event.pid).getThread(event.tid);
|
| - thread.addNonNestedSlice(slice.slice);
|
| - delete state.openNonNestedSlices[name];
|
| - } else {
|
| - if (state.openSlices.length == 0) {
|
| - // Ignore E events that are unmatched.
|
| - return;
|
| - }
|
| - var slice = state.openSlices.pop().slice;
|
| - slice.duration = event.ts - slice.start;
|
| -
|
| - // Store the slice on the correct subrow.
|
| - var thread = self.getProcess(event.pid).getThread(event.tid);
|
| - var subRowIndex = state.openSlices.length;
|
| - thread.getSubrow(subRowIndex).push(slice);
|
| -
|
| - // Add the slice to the subSlices array of its parent.
|
| - if (state.openSlices.length) {
|
| - var parentSlice = state.openSlices[state.openSlices.length - 1];
|
| - parentSlice.slice.subSlices.push(slice);
|
| - }
|
| - }
|
| - }
|
| -
|
| - // Walk through events
|
| - for (var eI = 0; eI < events.length; eI++) {
|
| - var event = events[eI];
|
| - var ptid = event.pid + ':' + event.tid;
|
| -
|
| - if (!(ptid in threadStateByPTID))
|
| - threadStateByPTID[ptid] = new ThreadState();
|
| - var state = threadStateByPTID[ptid];
|
| -
|
| - if (event.ph == 'B') {
|
| - processBegin(state, event);
|
| - } else if (event.ph == 'E') {
|
| - processEnd(state, event);
|
| - } else if (event.ph == 'I') {
|
| - // Treat an Instant event as a duration 0 slice.
|
| - // TimelineSliceTrack's redraw() knows how to handle this.
|
| - processBegin(state, event);
|
| - processEnd(state, event);
|
| - } else if (event.ph == 'M') {
|
| - if (event.name == 'thread_name') {
|
| - var thread = this.getProcess(event.pid).getThread(event.tid);
|
| - thread.name = event.args.name;
|
| - } else {
|
| - this.importErrors.push('Unrecognized metadata name: ' + event.name);
|
| - }
|
| - } else {
|
| - this.importErrors.push('Unrecognized event phase: ' + event.ph +
|
| - '(' + event.name + ')');
|
| - }
|
| - }
|
| - this.pruneEmptyThreads();
|
| - this.updateBounds();
|
| -
|
| - // Add end events for any events that are still on the stack. These
|
| - // are events that were still open when trace was ended, and can often
|
| - // indicate deadlock behavior.
|
| - for (var ptid in threadStateByPTID) {
|
| - var state = threadStateByPTID[ptid];
|
| - while (state.openSlices.length > 0) {
|
| - var slice = state.openSlices.pop();
|
| - slice.slice.duration = this.maxTimestamp - slice.slice.start;
|
| - slice.slice.didNotFinish = true;
|
| - var event = events[slice.index];
|
| -
|
| - // Store the slice on the correct subrow.
|
| - var thread = this.getProcess(event.pid).getThread(event.tid);
|
| - var subRowIndex = state.openSlices.length;
|
| - thread.getSubrow(subRowIndex).push(slice.slice);
|
| -
|
| - // Add the slice to the subSlices array of its parent.
|
| - if (state.openSlices.length) {
|
| - var parentSlice = state.openSlices[state.openSlices.length - 1];
|
| - parentSlice.slice.subSlices.push(slice.slice);
|
| - }
|
| - }
|
| - }
|
| -
|
| - this.shiftWorldToMicroseconds();
|
| -
|
| - var boost = (this.maxTimestamp - this.minTimestamp) * 0.15;
|
| - this.minTimestamp = this.minTimestamp - boost;
|
| - this.maxTimestamp = this.maxTimestamp + boost;
|
| - },
|
| -
|
| - /**
|
| - * Removes threads from the model that have no subrows.
|
| - */
|
| - pruneEmptyThreads: function() {
|
| - for (var pid in this.processes) {
|
| - var process = this.processes[pid];
|
| - var prunedThreads = [];
|
| - for (var tid in process.threads) {
|
| - var thread = process.threads[tid];
|
| - if (thread.subRows[0].length || thread.nonNestedSubRows.legnth)
|
| - prunedThreads.push(thread);
|
| - }
|
| - process.threads = prunedThreads;
|
| - }
|
| - },
|
| -
|
| - updateBounds: function() {
|
| - var wmin = Infinity;
|
| - var wmax = -wmin;
|
| - var threads = this.getAllThreads();
|
| - for (var tI = 0; tI < threads.length; tI++) {
|
| - var thread = threads[tI];
|
| - thread.updateBounds();
|
| - if (thread.minTimestamp != undefined &&
|
| - thread.maxTimestamp != undefined) {
|
| - wmin = Math.min(wmin, thread.minTimestamp);
|
| - wmax = Math.max(wmax, thread.maxTimestamp);
|
| - }
|
| - }
|
| - this.minTimestamp = wmin;
|
| - this.maxTimestamp = wmax;
|
| - },
|
| -
|
| - shiftWorldToMicroseconds: function() {
|
| - var timeBase = this.minTimestamp;
|
| - var threads = this.getAllThreads();
|
| - for (var tI = 0; tI < threads.length; tI++) {
|
| - var thread = threads[tI];
|
| - var shiftSubRow = function(subRow) {
|
| - for (var tS = 0; tS < subRow.length; tS++) {
|
| - var slice = subRow[tS];
|
| - slice.start = (slice.start - timeBase) / 1000;
|
| - slice.duration /= 1000;
|
| - }
|
| - };
|
| - for (var tSR = 0; tSR < thread.subRows.length; tSR++) {
|
| - shiftSubRow(thread.subRows[tSR]);
|
| - }
|
| - for (var tSR = 0; tSR < thread.nonNestedSubRows.length; tSR++) {
|
| - shiftSubRow(thread.nonNestedSubRows[tSR]);
|
| - }
|
| - }
|
| -
|
| - this.updateBounds();
|
| - },
|
| -
|
| - getAllThreads: function() {
|
| - var threads = [];
|
| - 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 {
|
| - TimelineSlice: TimelineSlice,
|
| - TimelineThread: TimelineThread,
|
| - TimelineProcess: TimelineProcess,
|
| - TimelineModel: TimelineModel
|
| - };
|
| -});
|
|
|