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

Side by Side Diff: runtime/vm/timeline.cc

Issue 1363033003: Make TimelineEventBlocks reclaimable (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: Created 5 years, 3 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
« no previous file with comments | « runtime/vm/timeline.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 <cstdlib> 5 #include <cstdlib>
6 6
7 #include "vm/atomic.h" 7 #include "vm/atomic.h"
8 #include "vm/isolate.h" 8 #include "vm/isolate.h"
9 #include "vm/json_stream.h" 9 #include "vm/json_stream.h"
10 #include "vm/lockers.h" 10 #include "vm/lockers.h"
11 #include "vm/log.h" 11 #include "vm/log.h"
12 #include "vm/object.h" 12 #include "vm/object.h"
13 #include "vm/thread.h" 13 #include "vm/thread.h"
14 #include "vm/timeline.h" 14 #include "vm/timeline.h"
15 15
16 namespace dart { 16 namespace dart {
17 17
18 DEFINE_FLAG(bool, complete_timeline, false, "Record the complete timeline"); 18 DEFINE_FLAG(bool, complete_timeline, false, "Record the complete timeline");
19 DEFINE_FLAG(bool, trace_timeline, false, 19 DEFINE_FLAG(bool, trace_timeline, false,
20 "Trace timeline backend"); 20 "Trace timeline backend");
21 DEFINE_FLAG(bool, trace_timeline_analysis, false, 21 DEFINE_FLAG(bool, trace_timeline_analysis, false,
22 "Trace timeline analysis backend"); 22 "Trace timeline analysis backend");
23 DEFINE_FLAG(bool, timing, false, 23 DEFINE_FLAG(bool, timing, false,
24 "Dump isolate timing information from timeline."); 24 "Dump isolate timing information from timeline.");
25 DEFINE_FLAG(charp, timeline_dir, NULL, 25 DEFINE_FLAG(charp, timeline_dir, NULL,
26 "Enable all timeline trace streams and output VM global trace " 26 "Enable all timeline trace streams and output VM global trace "
27 "into specified directory."); 27 "into specified directory.");
28 28
29 // Implementation notes:
30 //
31 // Writing events:
32 // |TimelineEvent|s are written into |TimelineEventBlock|s. Each |Thread| caches
33 // a |TimelineEventBlock| in TLS so that it can write events without
34 // synchronizing with other threads in the system. Even though the |Thread| owns
35 // the |TimelineEventBlock| the block may need to be reclaimed by the reporting
36 // system. To support that, a |Thread| must hold its |timeline_block_lock_|
37 // when operating on the |TimelineEventBlock|. This lock will only ever be
38 // busy if blocks are being reclaimed by the reporting system.
39 //
40 // Reporting:
41 // When requested, the timeline is serialized in the trace-event format
42 // (https://goo.gl/hDZw5M). The request can be for a VM-wide timeline or an
43 // isolate specific timeline. In both cases it may be that a thread has
44 // a |TimelineEventBlock| cached in TLS. In order to report a complete timeline
45 // the cached |TimelineEventBlock|s need to be reclaimed.
46 //
47 // Reclaiming open |TimelineEventBlock|s for an isolate:
48 //
49 // Cached |TimelineEventBlock|s can be in two places:
50 // 1) In a |Thread| (Thread currently in an |Isolate|)
51 // 2) In a |Thread::State| (Thread not currently in an |Isolate|).
52 //
53 // As a |Thread| enters and exits an |Isolate|, a |TimelineEventBlock|
54 // will move between (1) and (2).
55 //
56 // The first case occurs for |Thread|s that are currently running inside an
57 // isolate. The second case occurs for |Thread|s that are not currently
58 // running inside an isolate.
59 //
60 // To reclaim the first case, we take the |Thread|'s |timeline_block_lock_|
61 // and reclaim the cached block.
62 //
63 // To reclaim the second case, we can take the |ThreadRegistry| lock and
64 // reclaim these blocks.
65 //
66 // |Timeline::ReclaimIsolateBlocks| and |Timeline::ReclaimAllBlocks| are
67 // the two utility methods used to reclaim blocks before reporting.
68 //
69 // Locking notes:
70 // The following locks are used by the timeline system:
71 // - |TimelineEventRecorder::lock_| This lock is held whenever a
72 // |TimelineEventBlock| is being requested or reclaimed.
73 // - |Thread::timeline_block_lock_| This lock is held whenever a |Thread|'s
74 // cached block is being operated on.
75 // - |ThreadRegistry::monitor_| This lock protects the cached block for
76 // unscheduled threads of an isolate.
77 // - |Isolate::isolates_list_monitor_| This lock protects the list of
78 // isolates in the system.
79 //
80 // Locks must always be taken in the following order:
81 // |Isolate::isolates_list_monitor_|
82 // |ThreadRegistry::monitor_|
83 // |Thread::timeline_block_lock_|
84 // |TimelineEventRecorder::lock_|
85 //
86
29 void Timeline::InitOnce() { 87 void Timeline::InitOnce() {
30 ASSERT(recorder_ == NULL); 88 ASSERT(recorder_ == NULL);
31 // Default to ring recorder being enabled. 89 // Default to ring recorder being enabled.
32 const bool use_ring_recorder = true; 90 const bool use_ring_recorder = true;
33 // Some flags require that we use the endless recorder. 91 // Some flags require that we use the endless recorder.
34 const bool use_endless_recorder = 92 const bool use_endless_recorder =
35 (FLAG_timeline_dir != NULL) || FLAG_timing; 93 (FLAG_timeline_dir != NULL) || FLAG_timing;
36 if (use_endless_recorder) { 94 if (use_endless_recorder) {
37 recorder_ = new TimelineEventEndlessRecorder(); 95 recorder_ = new TimelineEventEndlessRecorder();
38 } else if (use_ring_recorder) { 96 } else if (use_ring_recorder) {
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
70 return (FLAG_timeline_dir != NULL) || FLAG_timing; 128 return (FLAG_timeline_dir != NULL) || FLAG_timing;
71 } 129 }
72 130
73 131
74 TimelineStream* Timeline::GetVMStream() { 132 TimelineStream* Timeline::GetVMStream() {
75 ASSERT(vm_stream_ != NULL); 133 ASSERT(vm_stream_ != NULL);
76 return vm_stream_; 134 return vm_stream_;
77 } 135 }
78 136
79 137
138 void Timeline::ReclaimIsolateBlocks() {
139 ReclaimBlocksForIsolate(Isolate::Current());
140 }
141
142
143 class ReclaimBlocksIsolateVisitor : public IsolateVisitor {
144 public:
145 ReclaimBlocksIsolateVisitor() {}
146
147 virtual void VisitIsolate(Isolate* isolate) {
148 Timeline::ReclaimBlocksForIsolate(isolate);
149 }
150
151 private:
152 };
153
154
155 void Timeline::ReclaimAllBlocks() {
156 if (recorder() == NULL) {
157 return;
158 }
159 // Reclaim all blocks cached for all isolates.
160 ReclaimBlocksIsolateVisitor visitor;
161 Isolate::VisitIsolates(&visitor);
162 // Reclaim the global VM block.
163 recorder()->ReclaimGlobalBlock();
164 }
165
166
167 void Timeline::ReclaimBlocksForIsolate(Isolate* isolate) {
168 if (recorder() == NULL) {
169 return;
170 }
171 ASSERT(isolate != NULL);
172 isolate->ReclaimTimelineBlocks();
173 }
174
175
80 TimelineEventRecorder* Timeline::recorder_ = NULL; 176 TimelineEventRecorder* Timeline::recorder_ = NULL;
81 TimelineStream* Timeline::vm_stream_ = NULL; 177 TimelineStream* Timeline::vm_stream_ = NULL;
82 178
83 #define ISOLATE_TIMELINE_STREAM_DEFINE_FLAG(name, enabled_by_default) \ 179 #define ISOLATE_TIMELINE_STREAM_DEFINE_FLAG(name, enabled_by_default) \
84 bool Timeline::stream_##name##_enabled_ = false; 180 bool Timeline::stream_##name##_enabled_ = false;
85 ISOLATE_TIMELINE_STREAM_LIST(ISOLATE_TIMELINE_STREAM_DEFINE_FLAG) 181 ISOLATE_TIMELINE_STREAM_LIST(ISOLATE_TIMELINE_STREAM_DEFINE_FLAG)
86 #undef ISOLATE_TIMELINE_STREAM_DEFINE_FLAG 182 #undef ISOLATE_TIMELINE_STREAM_DEFINE_FLAG
87 183
88 TimelineEvent::TimelineEvent() 184 TimelineEvent::TimelineEvent()
89 : timestamp0_(0), 185 : timestamp0_(0),
(...skipping 297 matching lines...) Expand 10 before | Expand all | Expand 10 after
387 : global_block_(NULL), 483 : global_block_(NULL),
388 async_id_(0) { 484 async_id_(0) {
389 } 485 }
390 486
391 487
392 void TimelineEventRecorder::PrintJSONMeta(JSONArray* events) const { 488 void TimelineEventRecorder::PrintJSONMeta(JSONArray* events) const {
393 } 489 }
394 490
395 491
396 TimelineEvent* TimelineEventRecorder::ThreadBlockStartEvent() { 492 TimelineEvent* TimelineEventRecorder::ThreadBlockStartEvent() {
397 // Grab the thread's timeline event block. 493 // Grab the current thread.
398 Thread* thread = Thread::Current(); 494 Thread* thread = Thread::Current();
399 ASSERT(thread != NULL); 495 ASSERT(thread != NULL);
496 // We are accessing the thread's timeline block- so take the lock.
497 MutexLocker ml(thread->timeline_block_lock());
400 498
401 if (thread->isolate() == NULL) { 499 if (thread->isolate() == NULL) {
402 // Non-isolate thread case. This should be infrequent. 500 // Non-isolate thread case. This should be infrequent.
403 return GlobalBlockStartEvent(); 501 return GlobalBlockStartEvent();
404 } 502 }
405 503
406 TimelineEventBlock* thread_block = thread->timeline_block(); 504 TimelineEventBlock* thread_block = thread->timeline_block();
407 505
408 if ((thread_block != NULL) && thread_block->IsFull()) { 506 if ((thread_block != NULL) && thread_block->IsFull()) {
409 MutexLocker ml(&lock_); 507 MutexLocker ml(&lock_);
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after
453 551
454 552
455 void TimelineEventRecorder::WriteTo(const char* directory) { 553 void TimelineEventRecorder::WriteTo(const char* directory) {
456 Dart_FileOpenCallback file_open = Isolate::file_open_callback(); 554 Dart_FileOpenCallback file_open = Isolate::file_open_callback();
457 Dart_FileWriteCallback file_write = Isolate::file_write_callback(); 555 Dart_FileWriteCallback file_write = Isolate::file_write_callback();
458 Dart_FileCloseCallback file_close = Isolate::file_close_callback(); 556 Dart_FileCloseCallback file_close = Isolate::file_close_callback();
459 if ((file_open == NULL) || (file_write == NULL) || (file_close == NULL)) { 557 if ((file_open == NULL) || (file_write == NULL) || (file_close == NULL)) {
460 return; 558 return;
461 } 559 }
462 560
463 FinishGlobalBlock(); 561 Timeline::ReclaimAllBlocks();
464 562
465 JSONStream js; 563 JSONStream js;
466 TimelineEventFilter filter; 564 TimelineEventFilter filter;
467 PrintJSON(&js, &filter); 565 PrintJSON(&js, &filter);
468 566
469 intptr_t pid = OS::ProcessId(); 567 intptr_t pid = OS::ProcessId();
470 char* filename = OS::SCreate(NULL, 568 char* filename = OS::SCreate(NULL,
471 "%s/dart-timeline-%" Pd ".json", directory, pid); 569 "%s/dart-timeline-%" Pd ".json", directory, pid);
472 void* file = (*file_open)(filename, true); 570 void* file = (*file_open)(filename, true);
473 if (file == NULL) { 571 if (file == NULL) {
474 OS::Print("Failed to write timeline file: %s\n", filename); 572 OS::Print("Failed to write timeline file: %s\n", filename);
475 free(filename); 573 free(filename);
476 return; 574 return;
477 } 575 }
478 free(filename); 576 free(filename);
479 (*file_write)(js.buffer()->buf(), js.buffer()->length(), file); 577 (*file_write)(js.buffer()->buf(), js.buffer()->length(), file);
480 (*file_close)(file); 578 (*file_close)(file);
481 } 579 }
482 580
483 581
484 void TimelineEventRecorder::FinishGlobalBlock() { 582 void TimelineEventRecorder::ReclaimGlobalBlock() {
485 MutexLocker ml(&lock_); 583 MutexLocker ml(&lock_);
486 if (global_block_ != NULL) { 584 if (global_block_ != NULL) {
487 global_block_->Finish(); 585 global_block_->Finish();
488 global_block_ = NULL; 586 global_block_ = NULL;
489 } 587 }
490 } 588 }
491 589
492 590
493 int64_t TimelineEventRecorder::GetNextAsyncId() { 591 int64_t TimelineEventRecorder::GetNextAsyncId() {
494 // TODO(johnmccutchan): Gracefully handle wrap around. 592 // TODO(johnmccutchan): Gracefully handle wrap around.
495 uint32_t next = static_cast<uint32_t>( 593 uint32_t next = static_cast<uint32_t>(
496 AtomicOperations::FetchAndIncrement(&async_id_)); 594 AtomicOperations::FetchAndIncrement(&async_id_));
497 return static_cast<int64_t>(next); 595 return static_cast<int64_t>(next);
498 } 596 }
499 597
500 598
599 void TimelineEventRecorder::FinishBlock(TimelineEventBlock* block) {
600 if (block == NULL) {
601 return;
602 }
603 MutexLocker ml(&lock_);
604 block->Finish();
605 }
606
607
501 TimelineEventBlock* TimelineEventRecorder::GetNewBlock() { 608 TimelineEventBlock* TimelineEventRecorder::GetNewBlock() {
502 MutexLocker ml(&lock_); 609 MutexLocker ml(&lock_);
503 return GetNewBlockLocked(Isolate::Current()); 610 return GetNewBlockLocked(Isolate::Current());
504 } 611 }
505 612
506 613
507 TimelineEventRingRecorder::TimelineEventRingRecorder(intptr_t capacity) 614 TimelineEventRingRecorder::TimelineEventRingRecorder(intptr_t capacity)
508 : blocks_(NULL), 615 : blocks_(NULL),
509 capacity_(capacity), 616 capacity_(capacity),
510 num_blocks_(0), 617 num_blocks_(0),
(...skipping 226 matching lines...) Expand 10 before | Expand all | Expand 10 after
737 head_ = NULL; 844 head_ = NULL;
738 block_index_ = 0; 845 block_index_ = 0;
739 Thread* thread = Thread::Current(); 846 Thread* thread = Thread::Current();
740 thread->set_timeline_block(NULL); 847 thread->set_timeline_block(NULL);
741 } 848 }
742 849
743 850
744 TimelineEventBlock::TimelineEventBlock(intptr_t block_index) 851 TimelineEventBlock::TimelineEventBlock(intptr_t block_index)
745 : next_(NULL), 852 : next_(NULL),
746 length_(0), 853 length_(0),
747 block_index_(block_index) { 854 block_index_(block_index),
855 isolate_(NULL),
856 in_use_(false) {
748 } 857 }
749 858
750 859
751 TimelineEventBlock::~TimelineEventBlock() { 860 TimelineEventBlock::~TimelineEventBlock() {
752 Reset(); 861 Reset();
753 } 862 }
754 863
755 864
756 TimelineEvent* TimelineEventBlock::StartEvent() { 865 TimelineEvent* TimelineEventBlock::StartEvent() {
757 ASSERT(!IsFull()); 866 ASSERT(!IsFull());
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after
801 } 910 }
802 911
803 912
804 void TimelineEventBlock::Reset() { 913 void TimelineEventBlock::Reset() {
805 for (intptr_t i = 0; i < kBlockSize; i++) { 914 for (intptr_t i = 0; i < kBlockSize; i++) {
806 // Clear any extra data. 915 // Clear any extra data.
807 events_[i].Reset(); 916 events_[i].Reset();
808 } 917 }
809 length_ = 0; 918 length_ = 0;
810 isolate_ = NULL; 919 isolate_ = NULL;
811 open_ = false; 920 in_use_ = false;
812 } 921 }
813 922
814 923
815 void TimelineEventBlock::Open(Isolate* isolate) { 924 void TimelineEventBlock::Open(Isolate* isolate) {
816 isolate_ = isolate; 925 isolate_ = isolate;
817 open_ = true; 926 in_use_ = true;
818 } 927 }
819 928
820 929
821 void TimelineEventBlock::Finish() { 930 void TimelineEventBlock::Finish() {
822 if (FLAG_trace_timeline) { 931 if (FLAG_trace_timeline) {
823 OS::Print("Finish block %p\n", this); 932 OS::Print("Finish block %p\n", this);
824 } 933 }
825 open_ = false; 934 in_use_ = false;
826 } 935 }
827 936
828 937
829 TimelineEventBlockIterator::TimelineEventBlockIterator( 938 TimelineEventBlockIterator::TimelineEventBlockIterator(
830 TimelineEventRecorder* recorder) 939 TimelineEventRecorder* recorder)
831 : current_(NULL), 940 : current_(NULL),
832 recorder_(NULL) { 941 recorder_(NULL) {
833 Reset(recorder); 942 Reset(recorder);
834 } 943 }
835 944
(...skipping 27 matching lines...) Expand all
863 972
864 973
865 TimelineEventBlock* TimelineEventBlockIterator::Next() { 974 TimelineEventBlock* TimelineEventBlockIterator::Next() {
866 ASSERT(current_ != NULL); 975 ASSERT(current_ != NULL);
867 TimelineEventBlock* r = current_; 976 TimelineEventBlock* r = current_;
868 current_ = current_->next(); 977 current_ = current_->next();
869 return r; 978 return r;
870 } 979 }
871 980
872 } // namespace dart 981 } // namespace dart
OLDNEW
« no previous file with comments | « runtime/vm/timeline.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698