| OLD | NEW |
| 1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 #include "platform/globals.h" |
| 5 #ifndef PRODUCT | 6 #ifndef PRODUCT |
| 6 | 7 |
| 7 #include <errno.h> | 8 #include <errno.h> |
| 8 #include <fcntl.h> | 9 #include <fcntl.h> |
| 9 #include <cstdlib> | 10 #include <cstdlib> |
| 10 | 11 |
| 12 #if defined(HOST_OS_FUCHSIA) |
| 13 #include "apps/tracing/lib/trace/event.h" |
| 14 #endif |
| 15 |
| 11 #include "vm/atomic.h" | 16 #include "vm/atomic.h" |
| 12 #include "vm/isolate.h" | 17 #include "vm/isolate.h" |
| 13 #include "vm/json_stream.h" | 18 #include "vm/json_stream.h" |
| 14 #include "vm/lockers.h" | 19 #include "vm/lockers.h" |
| 15 #include "vm/log.h" | 20 #include "vm/log.h" |
| 16 #include "vm/object.h" | 21 #include "vm/object.h" |
| 17 #include "vm/service_event.h" | 22 #include "vm/service_event.h" |
| 18 #include "vm/thread.h" | 23 #include "vm/thread.h" |
| 19 #include "vm/timeline.h" | 24 #include "vm/timeline.h" |
| 20 | 25 |
| 21 namespace dart { | 26 namespace dart { |
| 22 | 27 |
| 23 DEFINE_FLAG(bool, complete_timeline, false, "Record the complete timeline"); | 28 DEFINE_FLAG(bool, complete_timeline, false, "Record the complete timeline"); |
| 24 DEFINE_FLAG(bool, startup_timeline, false, "Record the startup timeline"); | 29 DEFINE_FLAG(bool, startup_timeline, false, "Record the startup timeline"); |
| 25 DEFINE_FLAG(bool, systrace_timeline, false, "Record the timeline to systrace"); | 30 DEFINE_FLAG( |
| 31 bool, |
| 32 systrace_timeline, |
| 33 false, |
| 34 "Record the timeline to the platform's tracing service if there is one"); |
| 26 DEFINE_FLAG(bool, trace_timeline, false, "Trace timeline backend"); | 35 DEFINE_FLAG(bool, trace_timeline, false, "Trace timeline backend"); |
| 27 DEFINE_FLAG(bool, | 36 DEFINE_FLAG(bool, |
| 28 trace_timeline_analysis, | 37 trace_timeline_analysis, |
| 29 false, | 38 false, |
| 30 "Trace timeline analysis backend"); | 39 "Trace timeline analysis backend"); |
| 31 DEFINE_FLAG(bool, | 40 DEFINE_FLAG(bool, |
| 32 timing, | 41 timing, |
| 33 false, | 42 false, |
| 34 "Dump isolate timing information from timeline."); | 43 "Dump isolate timing information from timeline."); |
| 35 DEFINE_FLAG(charp, | 44 DEFINE_FLAG(charp, |
| (...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 100 const bool use_startup_recorder = FLAG_startup_timeline; | 109 const bool use_startup_recorder = FLAG_startup_timeline; |
| 101 const bool use_systrace_recorder = FLAG_systrace_timeline; | 110 const bool use_systrace_recorder = FLAG_systrace_timeline; |
| 102 | 111 |
| 103 const char* flag = FLAG_timeline_recorder; | 112 const char* flag = FLAG_timeline_recorder; |
| 104 | 113 |
| 105 if (use_systrace_recorder || (flag != NULL)) { | 114 if (use_systrace_recorder || (flag != NULL)) { |
| 106 if (use_systrace_recorder || (strcmp("systrace", flag) == 0)) { | 115 if (use_systrace_recorder || (strcmp("systrace", flag) == 0)) { |
| 107 if (FLAG_trace_timeline) { | 116 if (FLAG_trace_timeline) { |
| 108 THR_Print("Using the Systrace timeline recorder.\n"); | 117 THR_Print("Using the Systrace timeline recorder.\n"); |
| 109 } | 118 } |
| 119 #if defined(HOST_OS_FUCHSIA) |
| 120 return new TimelineEventFuchsiaRecorder(); |
| 121 #else |
| 110 return new TimelineEventSystraceRecorder(); | 122 return new TimelineEventSystraceRecorder(); |
| 123 #endif |
| 111 } | 124 } |
| 112 } | 125 } |
| 113 | 126 |
| 114 if (use_endless_recorder || (flag != NULL)) { | 127 if (use_endless_recorder || (flag != NULL)) { |
| 115 if (use_endless_recorder || (strcmp("endless", flag) == 0)) { | 128 if (use_endless_recorder || (strcmp("endless", flag) == 0)) { |
| 116 if (FLAG_trace_timeline) { | 129 if (FLAG_trace_timeline) { |
| 117 THR_Print("Using the endless timeline recorder.\n"); | 130 THR_Print("Using the endless timeline recorder.\n"); |
| 118 } | 131 } |
| 119 return new TimelineEventEndlessRecorder(); | 132 return new TimelineEventEndlessRecorder(); |
| 120 } | 133 } |
| (...skipping 388 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 509 } | 522 } |
| 510 | 523 |
| 511 | 524 |
| 512 void TimelineEvent::StealArguments(intptr_t arguments_length, | 525 void TimelineEvent::StealArguments(intptr_t arguments_length, |
| 513 TimelineEventArgument* arguments) { | 526 TimelineEventArgument* arguments) { |
| 514 arguments_length_ = arguments_length; | 527 arguments_length_ = arguments_length; |
| 515 arguments_ = arguments; | 528 arguments_ = arguments; |
| 516 } | 529 } |
| 517 | 530 |
| 518 | 531 |
| 532 #if defined(HOST_OS_FUCHSIA) |
| 533 |
| 534 // TODO(zra): The functions below emit Dart's timeline events all as category |
| 535 // "dart". Instead, we could have finer-grained categories that make use of |
| 536 // the name of the timeline stream, e.g. "VM", "GC", etc. |
| 537 |
| 538 #define FUCHSIA_EVENT_ARGS_LIST(V) \ |
| 539 V(Begin, TRACE_DURATION_BEGIN) \ |
| 540 V(End, TRACE_DURATION_END) |
| 541 |
| 542 #define EMIT_FUCHSIA_EVENT(__name, __macro) \ |
| 543 static void EmitFuchsia##__name##Event(const char* label, \ |
| 544 TimelineEventArgument* arguments, \ |
| 545 intptr_t arguments_length) { \ |
| 546 if (arguments_length == 0) { \ |
| 547 __macro("dart", label); \ |
| 548 } else if (arguments_length == 1) { \ |
| 549 __macro("dart", label, arguments[0].name, \ |
| 550 const_cast<const char*>(arguments[0].value)); \ |
| 551 } else { \ |
| 552 __macro("dart", label, arguments[0].name, \ |
| 553 const_cast<const char*>(arguments[0].value), arguments[1].name, \ |
| 554 const_cast<const char*>(arguments[1].value)); \ |
| 555 } \ |
| 556 } |
| 557 |
| 558 FUCHSIA_EVENT_ARGS_LIST(EMIT_FUCHSIA_EVENT) |
| 559 #undef EMIT_FUCHSIA_EVENT |
| 560 |
| 561 #define FUCHSIA_EVENT_ID_ARGS_LIST(V) \ |
| 562 V(Instant, TRACE_INSTANT, ::tracing::EventScope) \ |
| 563 V(AsyncBegin, TRACE_ASYNC_BEGIN, int64_t) \ |
| 564 V(AsyncEnd, TRACE_ASYNC_END, int64_t) \ |
| 565 V(AsyncInstant, TRACE_ASYNC_INSTANT, int64_t) |
| 566 |
| 567 #define EMIT_FUCHSIA_EVENT(__name, __macro, __id_typ) \ |
| 568 static void EmitFuchsia##__name##Event(const char* label, __id_typ id, \ |
| 569 TimelineEventArgument* arguments, \ |
| 570 intptr_t arguments_length) { \ |
| 571 if (arguments_length == 0) { \ |
| 572 __macro("dart", label, id); \ |
| 573 } else if (arguments_length == 1) { \ |
| 574 __macro("dart", label, id, arguments[0].name, \ |
| 575 const_cast<const char*>(arguments[0].value)); \ |
| 576 } else { \ |
| 577 __macro("dart", label, id, arguments[0].name, \ |
| 578 const_cast<const char*>(arguments[0].value), arguments[1].name, \ |
| 579 const_cast<const char*>(arguments[1].value)); \ |
| 580 } \ |
| 581 } |
| 582 |
| 583 FUCHSIA_EVENT_ID_ARGS_LIST(EMIT_FUCHSIA_EVENT) |
| 584 #undef EMIT_FUCHSIA_EVENT |
| 585 |
| 586 |
| 587 void TimelineEvent::EmitFuchsiaEvent() { |
| 588 switch (event_type()) { |
| 589 case kBegin: |
| 590 EmitFuchsiaBeginEvent(label_, arguments_, arguments_length_); |
| 591 break; |
| 592 case kEnd: |
| 593 EmitFuchsiaEndEvent(label_, arguments_, arguments_length_); |
| 594 break; |
| 595 case kInstant: |
| 596 EmitFuchsiaInstantEvent(label_, TRACE_SCOPE_THREAD, arguments_, |
| 597 arguments_length_); |
| 598 break; |
| 599 case kAsyncBegin: |
| 600 EmitFuchsiaAsyncBeginEvent(label_, AsyncId(), arguments_, |
| 601 arguments_length_); |
| 602 break; |
| 603 case kAsyncEnd: |
| 604 EmitFuchsiaAsyncEndEvent(label_, AsyncId(), arguments_, |
| 605 arguments_length_); |
| 606 break; |
| 607 case kAsyncInstant: |
| 608 EmitFuchsiaAsyncInstantEvent(label_, AsyncId(), arguments_, |
| 609 arguments_length_); |
| 610 break; |
| 611 default: |
| 612 // TODO(zra): Figure out what to do with kDuration, kCounter, and |
| 613 // kMetadata. |
| 614 break; |
| 615 } |
| 616 } |
| 617 #endif |
| 618 |
| 619 |
| 519 intptr_t TimelineEvent::PrintSystrace(char* buffer, intptr_t buffer_size) { | 620 intptr_t TimelineEvent::PrintSystrace(char* buffer, intptr_t buffer_size) { |
| 520 ASSERT(buffer != NULL); | 621 ASSERT(buffer != NULL); |
| 521 ASSERT(buffer_size > 0); | 622 ASSERT(buffer_size > 0); |
| 522 buffer[0] = '\0'; | 623 buffer[0] = '\0'; |
| 523 intptr_t length = 0; | 624 intptr_t length = 0; |
| 524 int64_t pid = OS::ProcessId(); | 625 int64_t pid = OS::ProcessId(); |
| 525 switch (event_type()) { | 626 switch (event_type()) { |
| 526 case kBegin: { | 627 case kBegin: { |
| 527 length = OS::SNPrint(buffer, buffer_size, "B|%" Pd64 "|%s", pid, label()); | 628 length = OS::SNPrint(buffer, buffer_size, "B|%" Pd64 "|%s", pid, label()); |
| 528 } break; | 629 } break; |
| (...skipping 377 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 906 arguments_ = NULL; | 1007 arguments_ = NULL; |
| 907 } | 1008 } |
| 908 | 1009 |
| 909 | 1010 |
| 910 TimelineDurationScope::TimelineDurationScope(TimelineStream* stream, | 1011 TimelineDurationScope::TimelineDurationScope(TimelineStream* stream, |
| 911 const char* label) | 1012 const char* label) |
| 912 : TimelineEventScope(stream, label) { | 1013 : TimelineEventScope(stream, label) { |
| 913 if (!FLAG_support_timeline || !enabled()) { | 1014 if (!FLAG_support_timeline || !enabled()) { |
| 914 return; | 1015 return; |
| 915 } | 1016 } |
| 1017 #if defined(HOST_OS_FUCHSIA) |
| 1018 TRACE_DURATION_BEGIN("dart", label); |
| 1019 #else |
| 916 timestamp_ = OS::GetCurrentMonotonicMicros(); | 1020 timestamp_ = OS::GetCurrentMonotonicMicros(); |
| 917 thread_timestamp_ = OS::GetCurrentThreadCPUMicros(); | 1021 thread_timestamp_ = OS::GetCurrentThreadCPUMicros(); |
| 1022 #endif |
| 918 } | 1023 } |
| 919 | 1024 |
| 920 | 1025 |
| 921 TimelineDurationScope::TimelineDurationScope(Thread* thread, | 1026 TimelineDurationScope::TimelineDurationScope(Thread* thread, |
| 922 TimelineStream* stream, | 1027 TimelineStream* stream, |
| 923 const char* label) | 1028 const char* label) |
| 924 : TimelineEventScope(thread, stream, label) { | 1029 : TimelineEventScope(thread, stream, label) { |
| 925 if (!FLAG_support_timeline || !enabled()) { | 1030 if (!FLAG_support_timeline || !enabled()) { |
| 926 return; | 1031 return; |
| 927 } | 1032 } |
| 1033 #if defined(HOST_OS_FUCHSIA) |
| 1034 TRACE_DURATION_BEGIN("dart", label); |
| 1035 #else |
| 928 timestamp_ = OS::GetCurrentMonotonicMicros(); | 1036 timestamp_ = OS::GetCurrentMonotonicMicros(); |
| 929 thread_timestamp_ = OS::GetCurrentThreadCPUMicros(); | 1037 thread_timestamp_ = OS::GetCurrentThreadCPUMicros(); |
| 1038 #endif |
| 930 } | 1039 } |
| 931 | 1040 |
| 932 | 1041 |
| 933 TimelineDurationScope::~TimelineDurationScope() { | 1042 TimelineDurationScope::~TimelineDurationScope() { |
| 934 if (!FLAG_support_timeline) { | 1043 if (!FLAG_support_timeline) { |
| 935 return; | 1044 return; |
| 936 } | 1045 } |
| 937 if (!ShouldEmitEvent()) { | 1046 if (!ShouldEmitEvent()) { |
| 938 return; | 1047 return; |
| 939 } | 1048 } |
| 1049 #if defined(HOST_OS_FUCHSIA) |
| 1050 EmitFuchsiaEndEvent(label(), arguments(), arguments_length()); |
| 1051 #else |
| 940 TimelineEvent* event = stream()->StartEvent(); | 1052 TimelineEvent* event = stream()->StartEvent(); |
| 941 if (event == NULL) { | 1053 if (event == NULL) { |
| 942 // Stream is now disabled. | 1054 // Stream is now disabled. |
| 943 return; | 1055 return; |
| 944 } | 1056 } |
| 945 ASSERT(event != NULL); | 1057 ASSERT(event != NULL); |
| 946 // Emit a duration event. | 1058 // Emit a duration event. |
| 947 event->Duration(label(), timestamp_, OS::GetCurrentMonotonicMicros(), | 1059 event->Duration(label(), timestamp_, OS::GetCurrentMonotonicMicros(), |
| 948 thread_timestamp_, OS::GetCurrentThreadCPUMicros()); | 1060 thread_timestamp_, OS::GetCurrentThreadCPUMicros()); |
| 949 StealArguments(event); | 1061 StealArguments(event); |
| 950 event->Complete(); | 1062 event->Complete(); |
| 1063 #endif |
| 951 } | 1064 } |
| 952 | 1065 |
| 953 | 1066 |
| 954 TimelineBeginEndScope::TimelineBeginEndScope(TimelineStream* stream, | 1067 TimelineBeginEndScope::TimelineBeginEndScope(TimelineStream* stream, |
| 955 const char* label) | 1068 const char* label) |
| 956 : TimelineEventScope(stream, label) { | 1069 : TimelineEventScope(stream, label) { |
| 957 if (!FLAG_support_timeline) { | 1070 if (!FLAG_support_timeline) { |
| 958 return; | 1071 return; |
| 959 } | 1072 } |
| 960 EmitBegin(); | 1073 EmitBegin(); |
| (...skipping 468 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1429 do { | 1542 do { |
| 1430 __result = write(systrace_fd_, buffer, event_length); | 1543 __result = write(systrace_fd_, buffer, event_length); |
| 1431 } while ((__result == -1L) && (errno == EINTR)); | 1544 } while ((__result == -1L) && (errno == EINTR)); |
| 1432 } | 1545 } |
| 1433 } | 1546 } |
| 1434 #endif | 1547 #endif |
| 1435 ThreadBlockCompleteEvent(event); | 1548 ThreadBlockCompleteEvent(event); |
| 1436 } | 1549 } |
| 1437 | 1550 |
| 1438 | 1551 |
| 1552 #if defined(HOST_OS_FUCHSIA) |
| 1553 TimelineEventFuchsiaRecorder::TimelineEventFuchsiaRecorder(intptr_t capacity) |
| 1554 : TimelineEventFixedBufferRecorder(capacity) {} |
| 1555 |
| 1556 |
| 1557 TimelineEventBlock* TimelineEventFuchsiaRecorder::GetNewBlockLocked() { |
| 1558 // TODO(johnmccutchan): This function should only hand out blocks |
| 1559 // which have been marked as finished. |
| 1560 if (block_cursor_ == num_blocks_) { |
| 1561 block_cursor_ = 0; |
| 1562 } |
| 1563 TimelineEventBlock* block = blocks_[block_cursor_++]; |
| 1564 block->Reset(); |
| 1565 block->Open(); |
| 1566 return block; |
| 1567 } |
| 1568 |
| 1569 |
| 1570 void TimelineEventFuchsiaRecorder::CompleteEvent(TimelineEvent* event) { |
| 1571 if (event == NULL) { |
| 1572 return; |
| 1573 } |
| 1574 event->EmitFuchsiaEvent(); |
| 1575 ThreadBlockCompleteEvent(event); |
| 1576 } |
| 1577 #endif // defined(HOST_OS_FUCHSIA) |
| 1578 |
| 1579 |
| 1439 TimelineEventBlock* TimelineEventRingRecorder::GetNewBlockLocked() { | 1580 TimelineEventBlock* TimelineEventRingRecorder::GetNewBlockLocked() { |
| 1440 // TODO(johnmccutchan): This function should only hand out blocks | 1581 // TODO(johnmccutchan): This function should only hand out blocks |
| 1441 // which have been marked as finished. | 1582 // which have been marked as finished. |
| 1442 if (block_cursor_ == num_blocks_) { | 1583 if (block_cursor_ == num_blocks_) { |
| 1443 block_cursor_ = 0; | 1584 block_cursor_ = 0; |
| 1444 } | 1585 } |
| 1445 TimelineEventBlock* block = blocks_[block_cursor_++]; | 1586 TimelineEventBlock* block = blocks_[block_cursor_++]; |
| 1446 block->Reset(); | 1587 block->Reset(); |
| 1447 block->Open(); | 1588 block->Open(); |
| 1448 return block; | 1589 return block; |
| (...skipping 325 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1774 TimelineEventBlock* TimelineEventBlockIterator::Next() { | 1915 TimelineEventBlock* TimelineEventBlockIterator::Next() { |
| 1775 ASSERT(current_ != NULL); | 1916 ASSERT(current_ != NULL); |
| 1776 TimelineEventBlock* r = current_; | 1917 TimelineEventBlock* r = current_; |
| 1777 current_ = current_->next(); | 1918 current_ = current_->next(); |
| 1778 return r; | 1919 return r; |
| 1779 } | 1920 } |
| 1780 | 1921 |
| 1781 } // namespace dart | 1922 } // namespace dart |
| 1782 | 1923 |
| 1783 #endif // !PRODUCT | 1924 #endif // !PRODUCT |
| OLD | NEW |