Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(61)

Side by Side Diff: chrome/browser/resources/gpu_internals/timeline_model.js

Issue 7495036: about:gpu support for thread name metadata. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: More cleanup Created 9 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 5
6 /** 6 /**
7 * @fileoverview TimelineModel is a parsed representation of the 7 * @fileoverview TimelineModel is a parsed representation of the
8 * TraceEvents obtained from base/trace_event in which the begin-end 8 * TraceEvents obtained from base/trace_event in which the begin-end
9 * tokens are converted into a hierarchy of processes, threads, 9 * tokens are converted into a hierarchy of processes, threads,
10 * subrows, and slices. 10 * subrows, and slices.
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after
58 * @constructor 58 * @constructor
59 */ 59 */
60 function TimelineThread(parent, tid) { 60 function TimelineThread(parent, tid) {
61 this.parent = parent; 61 this.parent = parent;
62 this.tid = tid; 62 this.tid = tid;
63 this.subRows = [[]]; 63 this.subRows = [[]];
64 this.nonNestedSubRows = []; 64 this.nonNestedSubRows = [];
65 } 65 }
66 66
67 TimelineThread.prototype = { 67 TimelineThread.prototype = {
68 /**
69 * Name of the thread, if present.
70 */
71 name: undefined,
72
68 getSubrow: function(i) { 73 getSubrow: function(i) {
69 while (i >= this.subRows.length) 74 while (i >= this.subRows.length)
70 this.subRows.push([]); 75 this.subRows.push([]);
71 return this.subRows[i]; 76 return this.subRows[i];
72 }, 77 },
73 78
74 addNonNestedSlice: function(slice) { 79 addNonNestedSlice: function(slice) {
75 for (var i = 0; i < this.nonNestedSubRows.length; i++) { 80 for (var i = 0; i < this.nonNestedSubRows.length; i++) {
76 var currSubRow = this.nonNestedSubRows[i]; 81 var currSubRow = this.nonNestedSubRows[i];
77 var lastSlice = currSubRow[currSubRow.length - 1]; 82 var lastSlice = currSubRow[currSubRow.length - 1];
78 if (slice.start >= lastSlice.start + lastSlice.duration) { 83 if (slice.start >= lastSlice.start + lastSlice.duration) {
79 currSubRow.push(slice); 84 currSubRow.push(slice);
80 return; 85 return;
81 } 86 }
82 } 87 }
83 this.nonNestedSubRows.push([slice]); 88 this.nonNestedSubRows.push([slice]);
84 }, 89 },
85 90
91 /**
92 * Updates the minTimestamp and maxTimestamp fields based on the
93 * current slices and nonNestedSubRows attached to the thread.
94 */
86 updateBounds: function() { 95 updateBounds: function() {
87 var slices = this.subRows[0]; 96 var values = [];
88 if (slices.length != 0) { 97 var slices;
89 this.minTimestamp = slices[0].start; 98 if (this.subRows[0].length != 0) {
90 this.maxTimestamp = slices[slices.length - 1].end; 99 slices = this.subRows[0];
100 values.push(slices[0].start);
101 values.push(slices[slices.length - 1].end);
102 }
103 for (var i = 0; i < this.nonNestedSubRows.length; ++i) {
104 slices = this.nonNestedSubRows[i];
105 values.push(slices[0].start);
106 values.push(slices[slices.length - 1].end);
107 }
108 if (values.length) {
109 this.minTimestamp = Math.min.apply(Math, values);
110 this.maxTimestamp = Math.max.apply(Math, values);
91 } else { 111 } else {
92 this.minTimestamp = undefined; 112 this.minTimestamp = undefined;
93 this.maxTimestamp = undefined; 113 this.maxTimestamp = undefined;
94 } 114 }
95 } 115 }
96 116
97 }; 117 };
98 118
99 /** 119 /**
120 * Comparison between threads that orders first by pid,
121 * then by names, then by tid.
122 */
123 TimelineThread.compare = function(x,y) {
124 if(x.parent.pid != y.parent.pid) {
125 return x.parent.pid - y.parent.pid;
126 }
127
128 if (x.name && y.name) {
129 var tmp = x.name.localeCompare(y.name);
130 if (tmp == 0)
131 return x.tid - y.tid;
132 return tmp;
133 } else if (x.name) {
134 return -1;
135 } else if (y.name){
136 return 1;
137 } else {
138 return x.tid - y.tid;
139 }
140 };
141
142
143 /**
100 * The TimelineProcess represents a single process in the 144 * The TimelineProcess represents a single process in the
101 * trace. Right now, we keep this around purely for bookkeeping 145 * trace. Right now, we keep this around purely for bookkeeping
102 * reasons. 146 * reasons.
103 * @constructor 147 * @constructor
104 */ 148 */
105 function TimelineProcess(pid) { 149 function TimelineProcess(pid) {
106 this.pid = pid; 150 this.pid = pid;
107 this.threads = {}; 151 this.threads = {};
108 }; 152 };
109 153
110 TimelineProcess.prototype = { 154 TimelineProcess.prototype = {
111 getThread: function(tid) { 155 getThread: function(tid) {
112 if (!this.threads[tid]) 156 if (!this.threads[tid])
113 this.threads[tid] = new TimelineThread(this, tid); 157 this.threads[tid] = new TimelineThread(this, tid);
114 return this.threads[tid]; 158 return this.threads[tid];
115 } 159 }
116 }; 160 };
117 161
118 /** 162 /**
119 * Builds a model from an array of TraceEvent objects. 163 * Builds a model from an array of TraceEvent objects.
120 * @param {Array} events An array of TraceEvents created by 164 * @param {Array} events An array of TraceEvents created by
121 * TraceEvent.ToJSON(). 165 * TraceEvent.ToJSON().
122 * @constructor 166 * @constructor
123 */ 167 */
124 function TimelineModel(events) { 168 function TimelineModel(events) {
125 this.processes = {}; 169 this.processes = {};
170 this.importErrors = [];
126 171
127 if (events) 172 if (events)
128 this.importEvents(events); 173 this.importEvents(events);
129 } 174 }
130 175
131 TimelineModel.prototype = { 176 TimelineModel.prototype = {
132 __proto__: cr.EventTarget.prototype, 177 __proto__: cr.EventTarget.prototype,
133 178
134 getProcess: function(pid) { 179 getProcess: function(pid) {
135 if (!this.processes[pid]) 180 if (!this.processes[pid])
136 this.processes[pid] = new TimelineProcess(pid); 181 this.processes[pid] = new TimelineProcess(pid);
137 return this.processes[pid]; 182 return this.processes[pid];
138 }, 183 },
139 184
140 /** 185 /**
141 * The import takes an array of json-ified TraceEvents and adds them into 186 * The import takes an array of json-ified TraceEvents and adds them into
142 * the TimelineModel as processes, threads, and slices. 187 * the TimelineModel as processes, threads, and slices.
143 */ 188 */
144 importEvents: function(events) { 189 importEvents: function(events) {
145 // A ptid is a pid and tid joined together x:y fashion, eg 1024:130 190 // A ptid is a pid and tid joined together x:y fashion, eg 1024:130
146 // The ptid is a unique key for a thread in the trace. 191 // The ptid is a unique key for a thread in the trace.
147 192 this.importErrors = [];
148 193
149 // Threadstate 194 // Threadstate
150 const numColorIds = 30; 195 const numColorIds = 30;
151 function ThreadState(tid) { 196 function ThreadState(tid) {
152 this.openSlices = []; 197 this.openSlices = [];
153 this.openNonNestedSlices = {}; 198 this.openNonNestedSlices = {};
154 } 199 }
155 var threadStateByPTID = {}; 200 var threadStateByPTID = {};
156 201
157 var nameToColorMap = {}; 202 var nameToColorMap = {};
(...skipping 23 matching lines...) Expand all
181 var slice = 226 var slice =
182 { index: eI, 227 { index: eI,
183 slice: new TimelineSlice(event.name, colorId, event.ts, 228 slice: new TimelineSlice(event.name, colorId, event.ts,
184 event.args) }; 229 event.args) };
185 if (event.args['ui-nest'] === '0') { 230 if (event.args['ui-nest'] === '0') {
186 var sliceID = event.name; 231 var sliceID = event.name;
187 for (var x in event.args) { 232 for (var x in event.args) {
188 sliceID += ';' + event.args[x]; 233 sliceID += ';' + event.args[x];
189 } 234 }
190 if (state.openNonNestedSlices[sliceID]) 235 if (state.openNonNestedSlices[sliceID])
191 console.log('Event ' + sliceID + ' already open.'); 236 this.importErrors.push('Event ' + sliceID + ' already open.');
192 state.openNonNestedSlices[sliceID] = slice; 237 state.openNonNestedSlices[sliceID] = slice;
193 } else 238 } else
194 state.openSlices.push(slice); 239 state.openSlices.push(slice);
195 } else if (event.ph == 'E') { 240 } else if (event.ph == 'E') {
196 if (event.args['ui-nest'] === '0') { 241 if (event.args['ui-nest'] === '0') {
197 var sliceID = event.name; 242 var sliceID = event.name;
198 for (var x in event.args) { 243 for (var x in event.args) {
199 sliceID += ';' + event.args[x]; 244 sliceID += ';' + event.args[x];
200 } 245 }
201 var slice = state.openNonNestedSlices[sliceID]; 246 var slice = state.openNonNestedSlices[sliceID];
(...skipping 20 matching lines...) Expand all
222 267
223 // Add the slice to the subSlices array of its parent. 268 // Add the slice to the subSlices array of its parent.
224 if (state.openSlices.length) { 269 if (state.openSlices.length) {
225 var parentSlice = state.openSlices[state.openSlices.length - 1]; 270 var parentSlice = state.openSlices[state.openSlices.length - 1];
226 parentSlice.slice.subSlices.push(slice); 271 parentSlice.slice.subSlices.push(slice);
227 } 272 }
228 } 273 }
229 } else if (event.ph == 'I') { 274 } else if (event.ph == 'I') {
230 // TODO(nduca): Implement parsing of immediate events. 275 // TODO(nduca): Implement parsing of immediate events.
231 console.log('Parsing of I-type events not implemented.'); 276 console.log('Parsing of I-type events not implemented.');
277 } else if (event.ph == 'M') {
278 if (event.name == 'thread_name') {
279 var thread = this.getProcess(event.pid).getThread(event.tid);
280 thread.name = event.args.name;
281 } else {
282 this.importErrors.push('Unrecognized metadata name: ' + event.name);
283 }
232 } else { 284 } else {
233 throw new Error('Unrecognized event phase: ' + event.ph + 285 this.importErrors.push('Unrecognized event phase: ' + event.ph +
234 '(' + event.name + ')'); 286 '(' + event.name + ')');
235 } 287 }
236 } 288 }
237 289 this.pruneEmptyThreads();
238 this.updateBounds(); 290 this.updateBounds();
239 291
240 // Add end events for any events that are still on the stack. These 292 // Add end events for any events that are still on the stack. These
241 // are events that were still open when trace was ended, and can often 293 // are events that were still open when trace was ended, and can often
242 // indicate deadlock behavior. 294 // indicate deadlock behavior.
243 for (var ptid in threadStateByPTID) { 295 for (var ptid in threadStateByPTID) {
244 var state = threadStateByPTID[ptid]; 296 var state = threadStateByPTID[ptid];
245 while (state.openSlices.length > 0) { 297 while (state.openSlices.length > 0) {
246 var slice = state.openSlices.pop(); 298 var slice = state.openSlices.pop();
247 slice.slice.duration = this.maxTimestamp - slice.slice.start; 299 slice.slice.duration = this.maxTimestamp - slice.slice.start;
(...skipping 13 matching lines...) Expand all
261 } 313 }
262 } 314 }
263 315
264 this.shiftWorldToMicroseconds(); 316 this.shiftWorldToMicroseconds();
265 317
266 var boost = (this.maxTimestamp - this.minTimestamp) * 0.15; 318 var boost = (this.maxTimestamp - this.minTimestamp) * 0.15;
267 this.minTimestamp = this.minTimestamp - boost; 319 this.minTimestamp = this.minTimestamp - boost;
268 this.maxTimestamp = this.maxTimestamp + boost; 320 this.maxTimestamp = this.maxTimestamp + boost;
269 }, 321 },
270 322
323 /**
324 * Removes threads from the model that have no subrows.
325 */
326 pruneEmptyThreads: function() {
327 for (var pid in this.processes) {
328 var process = this.processes[pid];
329 var prunedThreads = [];
330 for (var tid in process.threads) {
331 var thread = process.threads[tid];
332 if (thread.subRows[0].length || thread.nonNestedSubRows.legnth)
333 prunedThreads.push(thread);
334 }
335 process.threads = prunedThreads;
336 }
337 },
338
271 updateBounds: function() { 339 updateBounds: function() {
272 var wmin = Infinity; 340 var wmin = Infinity;
273 var wmax = -wmin; 341 var wmax = -wmin;
274 var threads = this.getAllThreads(); 342 var threads = this.getAllThreads();
275 for (var tI = 0; tI < threads.length; tI++) { 343 for (var tI = 0; tI < threads.length; tI++) {
276 var thread = threads[tI]; 344 var thread = threads[tI];
277 thread.updateBounds(); 345 thread.updateBounds();
278 if (thread.minTimestamp && thread.maxTimestamp) { 346 if (thread.minTimestamp != undefined &&
347 thread.maxTimestamp != undefined) {
279 wmin = Math.min(wmin, thread.minTimestamp); 348 wmin = Math.min(wmin, thread.minTimestamp);
280 wmax = Math.max(wmax, thread.maxTimestamp); 349 wmax = Math.max(wmax, thread.maxTimestamp);
281 } 350 }
282 } 351 }
283 this.minTimestamp = wmin; 352 this.minTimestamp = wmin;
284 this.maxTimestamp = wmax; 353 this.maxTimestamp = wmax;
285 }, 354 },
286 355
287 shiftWorldToMicroseconds: function() { 356 shiftWorldToMicroseconds: function() {
288 var timeBase = this.minTimestamp; 357 var timeBase = this.minTimestamp;
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
320 389
321 }; 390 };
322 391
323 return { 392 return {
324 TimelineSlice: TimelineSlice, 393 TimelineSlice: TimelineSlice,
325 TimelineThread: TimelineThread, 394 TimelineThread: TimelineThread,
326 TimelineProcess: TimelineProcess, 395 TimelineProcess: TimelineProcess,
327 TimelineModel: TimelineModel 396 TimelineModel: TimelineModel
328 }; 397 };
329 }); 398 });
OLDNEW
« no previous file with comments | « chrome/browser/resources/gpu_internals/timeline.js ('k') | chrome/browser/resources/gpu_internals/timeline_track.js » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698