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

Side by Side Diff: tracing/tracing/extras/importer/trace_event_importer.html

Issue 1276003004: Process v8 sampling data into the trace model. (Closed) Base URL: git@github.com:catapult-project/catapult.git@master
Patch Set: Created 5 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
OLDNEW
1 <!DOCTYPE html> 1 <!DOCTYPE html>
2 <!-- 2 <!--
3 Copyright (c) 2012 The Chromium Authors. All rights reserved. 3 Copyright (c) 2012 The Chromium Authors. All rights reserved.
4 Use of this source code is governed by a BSD-style license that can be 4 Use of this source code is governed by a BSD-style license that can be
5 found in the LICENSE file. 5 found in the LICENSE file.
6 --> 6 -->
7 7
8 <link rel="import" href="/tracing/ui/base/color_scheme.html">
9 <link rel="import" href="/tracing/base/quad.html"> 8 <link rel="import" href="/tracing/base/quad.html">
10 <link rel="import" href="/tracing/base/range.html"> 9 <link rel="import" href="/tracing/base/range.html">
11 <link rel="import" href="/tracing/base/utils.html"> 10 <link rel="import" href="/tracing/base/utils.html">
12 <link rel="import" href="/tracing/base/units/time.html"> 11 <link rel="import" href="/tracing/base/units/time.html">
12 <link rel="import" href="/tracing/extras/importer/trace_code_entry.html">
13 <link rel="import" href="/tracing/extras/importer/v8/codemap.html">
13 <link rel="import" href="/tracing/importer/importer.html"> 14 <link rel="import" href="/tracing/importer/importer.html">
14 <link rel="import" href="/tracing/model/attribute.html"> 15 <link rel="import" href="/tracing/model/attribute.html">
15 <link rel="import" href="/tracing/model/comment_box_annotation.html"> 16 <link rel="import" href="/tracing/model/comment_box_annotation.html">
16 <link rel="import" href="/tracing/model/instant_event.html"> 17 <link rel="import" href="/tracing/model/instant_event.html">
17 <link rel="import" href="/tracing/model/flow_event.html"> 18 <link rel="import" href="/tracing/model/flow_event.html">
18 <link rel="import" href="/tracing/model/counter_series.html"> 19 <link rel="import" href="/tracing/model/counter_series.html">
19 <link rel="import" href="/tracing/model/slice_group.html"> 20 <link rel="import" href="/tracing/model/slice_group.html">
20 <link rel="import" href="/tracing/model/global_memory_dump.html"> 21 <link rel="import" href="/tracing/model/global_memory_dump.html">
21 <link rel="import" href="/tracing/model/memory_allocator_dump.html"> 22 <link rel="import" href="/tracing/model/memory_allocator_dump.html">
22 <link rel="import" href="/tracing/model/process_memory_dump.html"> 23 <link rel="import" href="/tracing/model/process_memory_dump.html">
23 <link rel="import" href="/tracing/model/rect_annotation.html"> 24 <link rel="import" href="/tracing/model/rect_annotation.html">
24 <link rel="import" href="/tracing/model/x_marker_annotation.html"> 25 <link rel="import" href="/tracing/model/x_marker_annotation.html">
25 <link rel="import" href="/tracing/model/model.html"> 26 <link rel="import" href="/tracing/model/model.html">
27 <link rel="import" href="/tracing/ui/base/color_scheme.html">
26 28
27 <script> 29 <script>
28 'use strict'; 30 'use strict';
29 31
30 /** 32 /**
31 * @fileoverview TraceEventImporter imports TraceEvent-formatted data 33 * @fileoverview TraceEventImporter imports TraceEvent-formatted data
32 * into the provided model. 34 * into the provided model.
33 */ 35 */
34 tr.exportTo('tr.e.importer', function() { 36 tr.exportTo('tr.e.importer', function() {
35
36 var Importer = tr.importer.Importer; 37 var Importer = tr.importer.Importer;
37
38 var deepCopy = tr.b.deepCopy; 38 var deepCopy = tr.b.deepCopy;
39 39
40 function getEventColor(event, opt_customName) { 40 function getEventColor(event, opt_customName) {
41 if (event.cname) 41 if (event.cname)
42 return tr.ui.b.getColorIdForReservedName(event.cname); 42 return tr.ui.b.getColorIdForReservedName(event.cname);
43 else if (opt_customName || event.name) { 43 else if (opt_customName || event.name) {
44 return tr.ui.b.getColorIdForGeneralPurposeString( 44 return tr.ui.b.getColorIdForGeneralPurposeString(
45 opt_customName || event.name); 45 opt_customName || event.name);
46 } 46 }
47 } 47 }
48 48
49 var timestampFromUs = tr.b.units.Time.timestampFromUs; 49 var timestampFromUs = tr.b.units.Time.timestampFromUs;
50 var maybeTimestampFromUs = tr.b.units.Time.maybeTimestampFromUs; 50 var maybeTimestampFromUs = tr.b.units.Time.maybeTimestampFromUs;
51 51
52 function TraceEventImporter(model, eventData) { 52 function TraceEventImporter(model, eventData) {
53 this.importPriority = 1; 53 this.importPriority = 1;
54 this.model_ = model; 54 this.model_ = model;
55 this.events_ = undefined; 55 this.events_ = undefined;
56 this.sampleEvents_ = undefined; 56 this.sampleEvents_ = undefined;
57 this.stackFrameEvents_ = undefined; 57 this.stackFrameEvents_ = undefined;
58 this.systemTraceEvents_ = undefined; 58 this.systemTraceEvents_ = undefined;
59 this.battorData_ = undefined; 59 this.battorData_ = undefined;
60 this.eventsWereFromString_ = false; 60 this.eventsWereFromString_ = false;
61 this.softwareMeasuredCpuCount_ = undefined; 61 this.softwareMeasuredCpuCount_ = undefined;
62
62 this.allAsyncEvents_ = []; 63 this.allAsyncEvents_ = [];
63 this.allFlowEvents_ = []; 64 this.allFlowEvents_ = [];
64 this.allObjectEvents_ = []; 65 this.allObjectEvents_ = [];
66
65 this.traceEventSampleStackFramesByName_ = {}; 67 this.traceEventSampleStackFramesByName_ = {};
66 68
69 this.v8ProcessCodeMaps_ = {};
70 this.v8ProcessRootStackFrame_ = {};
71
67 // Dump ID -> {global: (event | undefined), process: [events]} 72 // Dump ID -> {global: (event | undefined), process: [events]}
68 this.allMemoryDumpEvents_ = {}; 73 this.allMemoryDumpEvents_ = {};
69 74
70 if (typeof(eventData) === 'string' || eventData instanceof String) { 75 if (typeof(eventData) === 'string' || eventData instanceof String) {
71 eventData = eventData.trim(); 76 eventData = eventData.trim();
72 // If the event data begins with a [, then we know it should end with a ]. 77 // If the event data begins with a [, then we know it should end with a ].
73 // The reason we check for this is because some tracing implementations 78 // The reason we check for this is because some tracing implementations
74 // cannot guarantee that a ']' gets written to the trace file. So, we are 79 // cannot guarantee that a ']' gets written to the trace file. So, we are
75 // forgiving and if this is obviously the case, we fix it up before 80 // forgiving and if this is obviously the case, we fix it up before
76 // throwing the string at JSON.parse. 81 // throwing the string at JSON.parse.
(...skipping 317 matching lines...) Expand 10 before | Expand all | Expand 10 after
394 n = Math.max(n, this.softwareMeasuredCpuCount_); 399 n = Math.max(n, this.softwareMeasuredCpuCount_);
395 this.softwareMeasuredCpuCount_ = n; 400 this.softwareMeasuredCpuCount_ = n;
396 } else { 401 } else {
397 this.model_.importWarning({ 402 this.model_.importWarning({
398 type: 'metadata_parse_error', 403 type: 'metadata_parse_error',
399 message: 'Unrecognized metadata name: ' + event.name 404 message: 'Unrecognized metadata name: ' + event.name
400 }); 405 });
401 } 406 }
402 }, 407 },
403 408
409 processJitCodeEvent: function(event) {
410 if (this.v8ProcessCodeMaps_[event.pid] === undefined)
411 this.v8ProcessCodeMaps_[event.pid] = new tr.e.importer.v8.CodeMap();
412 var map = this.v8ProcessCodeMaps_[event.pid];
413
414 var data = event.args.data;
415 var startAddr = parseInt(data.code_start, 16);
416 if (event.name === 'JitCodeMoved') {
417 try {
418 map.moveCode(startAddr, parseInt(data.new_code_start, 16));
419 } catch (err) {
420 // Ignore moved error. Means we didn't find the original block.
421 // We won't know the name if we try to insert the code here.
422 }
423 } else {
424 map.addCode(startAddr,
425 new tr.e.importer.TraceCodeEntry(data.code_len, data.name));
426 }
427 },
428
404 processInstantEvent: function(event) { 429 processInstantEvent: function(event) {
430 // V8 JIT events are logged as phase 'I' so we need to separate them out
431 // and handle specially.
432 //
433 // TODO(dsinclair): There are _a lot_ of JitCode events so I'm skipping
434 // the display for now. Can revisit later if we want to show them.
435 if (event.name === 'JitCodeAdded' || event.name === 'JitCodeMoved') {
436 this.processJitCodeEvent(event);
437 return;
438 }
439
405 // Thread-level instant events are treated as zero-duration slices. 440 // Thread-level instant events are treated as zero-duration slices.
406 if (event.s == 't' || event.s === undefined) { 441 if (event.s == 't' || event.s === undefined) {
407 this.processDurationEvent(event); 442 this.processDurationEvent(event);
408 return; 443 return;
409 } 444 }
410 445
411 var constructor; 446 var constructor;
412 switch (event.s) { 447 switch (event.s) {
413 case 'g': 448 case 'g':
414 constructor = tr.model.GlobalInstantEvent; 449 constructor = tr.model.GlobalInstantEvent;
(...skipping 21 matching lines...) Expand all
436 case tr.model.InstantEventType.PROCESS: 471 case tr.model.InstantEventType.PROCESS:
437 var process = this.model_.getOrCreateProcess(event.pid); 472 var process = this.model_.getOrCreateProcess(event.pid);
438 process.pushInstantEvent(instantEvent); 473 process.pushInstantEvent(instantEvent);
439 break; 474 break;
440 475
441 default: 476 default:
442 throw new Error('Unknown instant event type: ' + event.s); 477 throw new Error('Unknown instant event type: ' + event.s);
443 } 478 }
444 }, 479 },
445 480
446 processTraceSampleEvent: function(event) { 481 processV8Sample: function(event) {
482 var stack = [];
petrcermak 2015/08/13 15:15:56 nit: It seems to me that there is no need to decla
dsinclair 2015/08/13 15:43:38 Actually, I don't need this at all anymore. I was
483 var data = event.args.data;
484
485 var rootStackFrame = this.v8ProcessRootStackFrame_[event.pid];
486 if (!rootStackFrame) {
487 rootStackFrame = new tr.model.StackFrame(
488 undefined /* parent */, 'v8-root-stack-frame' /* id */,
489 'v8' /* category */, 'v8-root-stack-frame' /* title */,
490 0 /* colorId */);
491 this.v8ProcessRootStackFrame_[event.pid] = rootStackFrame;
492 }
493
494 var findChildWithEntryID = function(stackFrame, entryID) {
petrcermak 2015/08/13 15:15:56 nit: I think that the following is preferred: fun
dsinclair 2015/08/13 15:43:38 Done.
495 return tr.b.findFirstInArray(stackFrame.children, function(child) {
496 return child.entryID === entryID;
497 });
498 }
499
500 var addStackFrame = function(lastStackFrame, entry) {
petrcermak 2015/08/13 15:15:56 ditto
dsinclair 2015/08/13 15:43:38 Acknowledged.
501 var childFrame = findChildWithEntryID(lastStackFrame, entry.id);
502 if (childFrame)
503 return childFrame;
504
505 var frame = new tr.model.StackFrame(
506 lastStackFrame, tr.b.GUID.allocate(),
507 'v8', entry.name,
508 tr.ui.b.getColorIdForGeneralPurposeString(entry.name),
509 entry.sourceInfo);
510
511 frame.entryID = entry.id;
512 this.model_.addStackFrame(frame);
513 return frame;
514 }.bind(this);
515
516 var lastStackFrame = rootStackFrame;
517
518 // There are several types of v8 sample events, gc, native, compiler, etc.
519 // Some of these types have stacks and some dones, we handle those two
petrcermak 2015/08/13 15:15:56 s/dones/don't/ ?
dsinclair 2015/08/13 15:43:38 I .... don't know what that was supposed to be ...
520 // cases differently. For types that don't have any stack frames attached
521 // we synthesize one base on the type of thing that's happening so when
petrcermak 2015/08/13 15:15:56 nit: s/base/based/
dsinclair 2015/08/13 15:43:38 Done.
522 // we view all the samples we'll see something like 'external' or 'gc'
523 // as a fraction of the time spent.
524 if (data.stack.length > 0 &&
525 this.v8ProcessCodeMaps_[event.pid]) {
petrcermak 2015/08/13 15:15:56 nit: I think that this will fit on the previous li
dsinclair 2015/08/13 15:43:38 Done.
526
527 var map = this.v8ProcessCodeMaps_[event.pid];
528
529 // Stacks have the leaf node first, flip them around so the root
530 // comes first.
531 data.stack.reverse();
532
533 for (var i = 0; i < data.stack.length; i++) {
petrcermak 2015/08/13 15:15:56 Observation: I've just realized that this function
dsinclair 2015/08/13 15:43:38 I actually removed the stack assignments.
534 var addr = parseInt(data.stack[i], 16);
535 var entry = map.findEntry(addr);
536
537 if (entry === null) {
538 entry = {
539 id: 'unknown',
540 name: 'unknown',
541 sourceInfo: undefined
542 };
543 }
544
545 lastStackFrame = addStackFrame(lastStackFrame, entry);
546 stack.push(entry);
547 }
548 } else {
549 var entry = {
550 id: data.vm_state,
551 name: data.vm_state,
552 sourceInfo: undefined
553 };
554 lastStackFrame = addStackFrame(lastStackFrame, entry);
555 }
556
447 var thread = this.model_.getOrCreateProcess(event.pid) 557 var thread = this.model_.getOrCreateProcess(event.pid)
448 .getOrCreateThread(event.tid); 558 .getOrCreateThread(event.tid);
449 559
560 var sample = new tr.model.Sample(
561 undefined /* cpu */, thread, 'V8 Sample',
562 timestampFromUs(event.ts), lastStackFrame, 1 /* weight */,
563 this.deepCopyIfNeeded_(event.args));
564 this.model_.samples.push(sample);
565 },
566
567 processTraceSampleEvent: function(event) {
568 if (event.name === 'V8Sample') {
569 this.processV8Sample(event);
570 return;
571 }
572
450 var stackFrame = this.getStackFrameForEvent_(event); 573 var stackFrame = this.getStackFrameForEvent_(event);
451 if (stackFrame === undefined) { 574 if (stackFrame === undefined) {
452 stackFrame = this.traceEventSampleStackFramesByName_[ 575 stackFrame = this.traceEventSampleStackFramesByName_[
453 event.name]; 576 event.name];
454 } 577 }
455 if (stackFrame === undefined) { 578 if (stackFrame === undefined) {
456 var id = 'te-' + tr.b.GUID.allocate(); 579 var id = 'te-' + tr.b.GUID.allocate();
457 stackFrame = new tr.model.StackFrame( 580 stackFrame = new tr.model.StackFrame(
458 undefined, id, 581 undefined, id,
459 event.cat, event.name, 582 event.cat, event.name,
460 tr.ui.b.getColorIdForGeneralPurposeString(event.name)); 583 tr.ui.b.getColorIdForGeneralPurposeString(event.name));
461 this.model_.addStackFrame(stackFrame); 584 this.model_.addStackFrame(stackFrame);
462 this.traceEventSampleStackFramesByName_[event.name] = stackFrame; 585 this.traceEventSampleStackFramesByName_[event.name] = stackFrame;
463 } 586 }
464 587
588 var thread = this.model_.getOrCreateProcess(event.pid)
589 .getOrCreateThread(event.tid);
590
465 var sample = new tr.model.Sample( 591 var sample = new tr.model.Sample(
466 undefined, thread, 'TRACE_EVENT_SAMPLE', 592 undefined, thread, 'Trace Event Sample',
467 timestampFromUs(event.ts), stackFrame, 1, 593 timestampFromUs(event.ts), stackFrame, 1,
468 this.deepCopyIfNeeded_(event.args)); 594 this.deepCopyIfNeeded_(event.args));
469 this.model_.samples.push(sample); 595 this.model_.samples.push(sample);
470 }, 596 },
471 597
472 getOrCreateMemoryDumpEvents_: function(dumpId) { 598 getOrCreateMemoryDumpEvents_: function(dumpId) {
473 if (this.allMemoryDumpEvents_[dumpId] === undefined) { 599 if (this.allMemoryDumpEvents_[dumpId] === undefined) {
474 this.allMemoryDumpEvents_[dumpId] = { 600 this.allMemoryDumpEvents_[dumpId] = {
475 global: undefined, 601 global: undefined,
476 process: [] 602 process: []
(...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after
563 this.processMemoryDumpEvent(event); 689 this.processMemoryDumpEvent(event);
564 690
565 } else { 691 } else {
566 this.model_.importWarning({ 692 this.model_.importWarning({
567 type: 'parse_error', 693 type: 'parse_error',
568 message: 'Unrecognized event phase: ' + 694 message: 'Unrecognized event phase: ' +
569 event.ph + ' (' + event.name + ')' 695 event.ph + ' (' + event.name + ')'
570 }); 696 });
571 } 697 }
572 } 698 }
699
700 // Remove all the root stack frame children as they should
701 // already be added.
702 tr.b.iterItems(this.v8ProcessRootStackFrame_, function(name, frame) {
703 frame.removeAllChildren();
704 });
573 }, 705 },
574 706
575 importStackFrames_: function() { 707 importStackFrames_: function() {
576 var m = this.model_; 708 var m = this.model_;
577 var events = this.stackFrameEvents_; 709 var events = this.stackFrameEvents_;
578 710
579 for (var id in events) { 711 for (var id in events) {
580 var event = events[id]; 712 var event = events[id];
581 var textForColor = event.category ? event.category : event.name; 713 var textForColor = event.category ? event.category : event.name;
582 var frame = new tr.model.StackFrame( 714 var frame = new tr.model.StackFrame(
(...skipping 1363 matching lines...) Expand 10 before | Expand all | Expand 10 after
1946 } 2078 }
1947 }; 2079 };
1948 2080
1949 tr.importer.Importer.register(TraceEventImporter); 2081 tr.importer.Importer.register(TraceEventImporter);
1950 2082
1951 return { 2083 return {
1952 TraceEventImporter: TraceEventImporter 2084 TraceEventImporter: TraceEventImporter
1953 }; 2085 };
1954 }); 2086 });
1955 </script> 2087 </script>
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698