Chromium Code Reviews| 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 #ifndef PRODUCT | 5 #ifndef PRODUCT |
| 6 | 6 |
| 7 #include <fcntl.h> | |
| 7 #include <cstdlib> | 8 #include <cstdlib> |
| 8 | 9 |
| 9 #include "vm/atomic.h" | 10 #include "vm/atomic.h" |
| 10 #include "vm/isolate.h" | 11 #include "vm/isolate.h" |
| 11 #include "vm/json_stream.h" | 12 #include "vm/json_stream.h" |
| 12 #include "vm/lockers.h" | 13 #include "vm/lockers.h" |
| 13 #include "vm/log.h" | 14 #include "vm/log.h" |
| 14 #include "vm/object.h" | 15 #include "vm/object.h" |
| 15 #include "vm/service_event.h" | 16 #include "vm/service_event.h" |
| 16 #include "vm/thread.h" | 17 #include "vm/thread.h" |
| 17 #include "vm/timeline.h" | 18 #include "vm/timeline.h" |
| 18 | 19 |
| 19 namespace dart { | 20 namespace dart { |
| 20 | 21 |
| 21 DEFINE_FLAG(bool, complete_timeline, false, "Record the complete timeline"); | 22 DEFINE_FLAG(bool, complete_timeline, false, "Record the complete timeline"); |
| 22 DEFINE_FLAG(bool, startup_timeline, false, "Record the startup timeline"); | 23 DEFINE_FLAG(bool, startup_timeline, false, "Record the startup timeline"); |
| 24 DEFINE_FLAG(bool, systrace_timeline, false, "Record the timeline to systrace"); | |
| 23 DEFINE_FLAG(bool, trace_timeline, false, | 25 DEFINE_FLAG(bool, trace_timeline, false, |
| 24 "Trace timeline backend"); | 26 "Trace timeline backend"); |
| 25 DEFINE_FLAG(bool, trace_timeline_analysis, false, | 27 DEFINE_FLAG(bool, trace_timeline_analysis, false, |
| 26 "Trace timeline analysis backend"); | 28 "Trace timeline analysis backend"); |
| 27 DEFINE_FLAG(bool, timing, false, | 29 DEFINE_FLAG(bool, timing, false, |
| 28 "Dump isolate timing information from timeline."); | 30 "Dump isolate timing information from timeline."); |
| 29 DEFINE_FLAG(charp, timeline_dir, NULL, | 31 DEFINE_FLAG(charp, timeline_dir, NULL, |
| 30 "Enable all timeline trace streams and output VM global trace " | 32 "Enable all timeline trace streams and output VM global trace " |
| 31 "into specified directory."); | 33 "into specified directory."); |
| 32 DEFINE_FLAG(charp, timeline_streams, NULL, | 34 DEFINE_FLAG(charp, timeline_streams, NULL, |
| 33 "Comma separated list of timeline streams to record. " | 35 "Comma separated list of timeline streams to record. " |
| 34 "Valid values: all, API, Compiler, Dart, Debugger, Embedder, " | 36 "Valid values: all, API, Compiler, Dart, Debugger, Embedder, " |
| 35 "GC, Isolate, and VM."); | 37 "GC, Isolate, and VM."); |
| 36 DEFINE_FLAG(charp, timeline_recorder, "ring", | 38 DEFINE_FLAG(charp, timeline_recorder, "ring", |
| 37 "Select the timeline recorder used. " | 39 "Select the timeline recorder used. " |
| 38 "Valid values: ring, endless, and startup.") | 40 "Valid values: ring, endless, startup, and systrace.") |
| 39 | 41 |
| 40 // Implementation notes: | 42 // Implementation notes: |
| 41 // | 43 // |
| 42 // Writing events: | 44 // Writing events: |
| 43 // |TimelineEvent|s are written into |TimelineEventBlock|s. Each |Thread| caches | 45 // |TimelineEvent|s are written into |TimelineEventBlock|s. Each |Thread| caches |
| 44 // a |TimelineEventBlock| object so that it can write events without | 46 // a |TimelineEventBlock| object so that it can write events without |
| 45 // synchronizing with other threads in the system. Even though the |Thread| owns | 47 // synchronizing with other threads in the system. Even though the |Thread| owns |
| 46 // the |TimelineEventBlock| the block may need to be reclaimed by the reporting | 48 // the |TimelineEventBlock| the block may need to be reclaimed by the reporting |
| 47 // system. To support that, a |Thread| must hold its |timeline_block_lock_| | 49 // system. To support that, a |Thread| must hold its |timeline_block_lock_| |
| 48 // when operating on the |TimelineEventBlock|. This lock will only ever be | 50 // when operating on the |TimelineEventBlock|. This lock will only ever be |
| (...skipping 30 matching lines...) Expand all Loading... | |
| 79 // |TimelineEventRecorder::lock_| | 81 // |TimelineEventRecorder::lock_| |
| 80 // | 82 // |
| 81 | 83 |
| 82 | 84 |
| 83 static TimelineEventRecorder* CreateTimelineRecorder() { | 85 static TimelineEventRecorder* CreateTimelineRecorder() { |
| 84 // Some flags require that we use the endless recorder. | 86 // Some flags require that we use the endless recorder. |
| 85 const bool use_endless_recorder = | 87 const bool use_endless_recorder = |
| 86 (FLAG_timeline_dir != NULL) || FLAG_timing || FLAG_complete_timeline; | 88 (FLAG_timeline_dir != NULL) || FLAG_timing || FLAG_complete_timeline; |
| 87 | 89 |
| 88 const bool use_startup_recorder = FLAG_startup_timeline; | 90 const bool use_startup_recorder = FLAG_startup_timeline; |
| 91 const bool use_systrace_recorder = FLAG_systrace_timeline; | |
| 89 | 92 |
| 90 const char* flag = FLAG_timeline_recorder; | 93 const char* flag = FLAG_timeline_recorder; |
| 91 | 94 |
| 95 if (use_systrace_recorder || (flag != NULL)) { | |
| 96 if (use_systrace_recorder || (strcmp("systrace", flag) == 0)) { | |
| 97 if (FLAG_trace_timeline) { | |
| 98 THR_Print("Using the Systrace timeline recorder.\n"); | |
| 99 } | |
| 100 return new TimelineEventSystraceRecorder(); | |
| 101 } | |
| 102 } | |
| 103 | |
| 92 if (use_endless_recorder || (flag != NULL)) { | 104 if (use_endless_recorder || (flag != NULL)) { |
| 93 if (use_endless_recorder || (strcmp("endless", flag) == 0)) { | 105 if (use_endless_recorder || (strcmp("endless", flag) == 0)) { |
| 94 if (FLAG_trace_timeline) { | 106 if (FLAG_trace_timeline) { |
| 95 THR_Print("Using the endless timeline recorder.\n"); | 107 THR_Print("Using the endless timeline recorder.\n"); |
| 96 } | 108 } |
| 97 return new TimelineEventEndlessRecorder(); | 109 return new TimelineEventEndlessRecorder(); |
| 98 } | 110 } |
| 99 } | 111 } |
| 100 | 112 |
| 101 if (use_startup_recorder || (flag != NULL)) { | 113 if (use_startup_recorder || (flag != NULL)) { |
| (...skipping 388 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 490 } | 502 } |
| 491 | 503 |
| 492 | 504 |
| 493 void TimelineEvent::StealArguments(intptr_t arguments_length, | 505 void TimelineEvent::StealArguments(intptr_t arguments_length, |
| 494 TimelineEventArgument* arguments) { | 506 TimelineEventArgument* arguments) { |
| 495 arguments_length_ = arguments_length; | 507 arguments_length_ = arguments_length; |
| 496 arguments_ = arguments; | 508 arguments_ = arguments; |
| 497 } | 509 } |
| 498 | 510 |
| 499 | 511 |
| 512 intptr_t TimelineEvent::PrintSystrace(char* buffer, intptr_t buffer_size) { | |
| 513 ASSERT(buffer != NULL); | |
| 514 ASSERT(buffer_size > 0); | |
| 515 buffer[0] = '\0'; | |
| 516 intptr_t length = 0; | |
| 517 int64_t pid = OS::ProcessId(); | |
| 518 switch (event_type()) { | |
| 519 case kBegin: { | |
| 520 length = snprintf(buffer, buffer_size, "B|%" Pd64 "|%s", pid, label()); | |
|
rmacnak
2016/09/08 18:17:09
OS::SNPrint
Cutch
2016/09/08 18:24:08
Done.
| |
| 521 } | |
| 522 break; | |
| 523 case kEnd: { | |
| 524 length = snprintf(buffer, buffer_size, "E"); | |
|
rmacnak
2016/09/08 18:17:09
"
Cutch
2016/09/08 18:24:08
Done.
| |
| 525 } | |
| 526 break; | |
| 527 case kCounter: { | |
| 528 if (arguments_length_ > 0) { | |
| 529 // We only report the first counter value. | |
| 530 length = snprintf(buffer, buffer_size, | |
| 531 "C|%" Pd64 "|%s|%s", | |
| 532 pid, | |
| 533 label(), | |
| 534 arguments_[0].value); | |
| 535 } | |
| 536 } | |
| 537 default: | |
| 538 // Ignore event types that we cannot serialize to the Systrace format. | |
| 539 break; | |
| 540 } | |
| 541 return length; | |
| 542 } | |
| 543 | |
| 544 | |
| 500 void TimelineEvent::Complete() { | 545 void TimelineEvent::Complete() { |
| 501 TimelineEventRecorder* recorder = Timeline::recorder(); | 546 TimelineEventRecorder* recorder = Timeline::recorder(); |
| 502 if (recorder != NULL) { | 547 if (recorder != NULL) { |
| 503 recorder->CompleteEvent(this); | 548 recorder->CompleteEvent(this); |
| 504 } | 549 } |
| 505 } | 550 } |
| 506 | 551 |
| 507 | 552 |
| 508 void TimelineEvent::FreeArguments() { | 553 void TimelineEvent::FreeArguments() { |
| 509 if (arguments_ == NULL) { | 554 if (arguments_ == NULL) { |
| (...skipping 837 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1347 | 1392 |
| 1348 | 1393 |
| 1349 void TimelineEventFixedBufferRecorder::CompleteEvent(TimelineEvent* event) { | 1394 void TimelineEventFixedBufferRecorder::CompleteEvent(TimelineEvent* event) { |
| 1350 if (event == NULL) { | 1395 if (event == NULL) { |
| 1351 return; | 1396 return; |
| 1352 } | 1397 } |
| 1353 ThreadBlockCompleteEvent(event); | 1398 ThreadBlockCompleteEvent(event); |
| 1354 } | 1399 } |
| 1355 | 1400 |
| 1356 | 1401 |
| 1402 static const char* kSystracePath = "/sys/kernel/debug/tracing/trace_marker"; | |
| 1403 | |
| 1404 | |
| 1405 TimelineEventSystraceRecorder::TimelineEventSystraceRecorder(intptr_t capacity) | |
| 1406 : TimelineEventFixedBufferRecorder(capacity), | |
| 1407 systrace_fd_(-1) { | |
| 1408 systrace_fd_ = open(kSystracePath, O_WRONLY); | |
|
rmacnak
2016/09/08 18:17:09
ifdef TARGET_OS_LINUX or TARGET_OS_ANDROID
else
Cutch
2016/09/08 18:24:08
Done.
| |
| 1409 if ((systrace_fd_ < 0) && FLAG_trace_timeline) { | |
| 1410 OS::PrintErr("TimelineEventSystraceRecorder: Could not open `%s`\n", | |
| 1411 kSystracePath); | |
| 1412 } | |
| 1413 } | |
| 1414 | |
| 1415 | |
| 1416 TimelineEventSystraceRecorder::~TimelineEventSystraceRecorder() { | |
| 1417 if (systrace_fd_ >= 0) { | |
| 1418 close(systrace_fd_); | |
| 1419 } | |
| 1420 } | |
| 1421 | |
| 1422 | |
| 1423 TimelineEventBlock* TimelineEventSystraceRecorder::GetNewBlockLocked() { | |
| 1424 // TODO(johnmccutchan): This function should only hand out blocks | |
| 1425 // which have been marked as finished. | |
| 1426 if (block_cursor_ == num_blocks_) { | |
| 1427 block_cursor_ = 0; | |
| 1428 } | |
| 1429 TimelineEventBlock* block = blocks_[block_cursor_++]; | |
| 1430 block->Reset(); | |
| 1431 block->Open(); | |
| 1432 return block; | |
| 1433 } | |
| 1434 | |
| 1435 | |
| 1436 void TimelineEventSystraceRecorder::CompleteEvent(TimelineEvent* event) { | |
| 1437 if (event == NULL) { | |
| 1438 return; | |
| 1439 } | |
| 1440 if (systrace_fd_ >= 0) { | |
|
rmacnak
2016/09/08 18:17:09
ifdef TARGET_OS_LINUX or TARGET_OS_ANDROID
Cutch
2016/09/08 18:24:08
Done.
| |
| 1441 // Serialize to the systrace format. | |
| 1442 const intptr_t kBufferLength = 1024; | |
| 1443 char buffer[kBufferLength]; | |
| 1444 const intptr_t event_length = | |
| 1445 event->PrintSystrace(&buffer[0], kBufferLength); | |
| 1446 if (event_length > 0) { | |
| 1447 ssize_t result = write(systrace_fd_, buffer, event_length); | |
| 1448 // Ignore failures writing to systrace_fd_. | |
| 1449 USE(result); | |
| 1450 } | |
| 1451 } | |
| 1452 ThreadBlockCompleteEvent(event); | |
| 1453 } | |
| 1454 | |
| 1455 | |
| 1357 TimelineEventBlock* TimelineEventRingRecorder::GetNewBlockLocked() { | 1456 TimelineEventBlock* TimelineEventRingRecorder::GetNewBlockLocked() { |
| 1358 // TODO(johnmccutchan): This function should only hand out blocks | 1457 // TODO(johnmccutchan): This function should only hand out blocks |
| 1359 // which have been marked as finished. | 1458 // which have been marked as finished. |
| 1360 if (block_cursor_ == num_blocks_) { | 1459 if (block_cursor_ == num_blocks_) { |
| 1361 block_cursor_ = 0; | 1460 block_cursor_ = 0; |
| 1362 } | 1461 } |
| 1363 TimelineEventBlock* block = blocks_[block_cursor_++]; | 1462 TimelineEventBlock* block = blocks_[block_cursor_++]; |
| 1364 block->Reset(); | 1463 block->Reset(); |
| 1365 block->Open(); | 1464 block->Open(); |
| 1366 return block; | 1465 return block; |
| (...skipping 321 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1688 TimelineEventBlock* TimelineEventBlockIterator::Next() { | 1787 TimelineEventBlock* TimelineEventBlockIterator::Next() { |
| 1689 ASSERT(current_ != NULL); | 1788 ASSERT(current_ != NULL); |
| 1690 TimelineEventBlock* r = current_; | 1789 TimelineEventBlock* r = current_; |
| 1691 current_ = current_->next(); | 1790 current_ = current_->next(); |
| 1692 return r; | 1791 return r; |
| 1693 } | 1792 } |
| 1694 | 1793 |
| 1695 } // namespace dart | 1794 } // namespace dart |
| 1696 | 1795 |
| 1697 #endif // !PRODUCT | 1796 #endif // !PRODUCT |
| OLD | NEW |