Chromium Code Reviews| OLD | NEW |
|---|---|
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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> |
| OLD | NEW |