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

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
« runtime/vm/timeline.h ('K') | « 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 if (recorder() == NULL) {
140 return;
141 }
turnidge 2015/09/24 17:05:52 This check is redundant (also in callee).
Cutch 2015/09/24 18:14:16 Done.
142 ReclaimBlocksForIsolate(Isolate::Current());
143 }
144
145
146 class ReclaimBlocksIsolateVisitor : public IsolateVisitor {
147 public:
148 ReclaimBlocksIsolateVisitor() {}
149
150 virtual void VisitIsolate(Isolate* isolate) {
151 Timeline::ReclaimBlocksForIsolate(isolate);
152 }
153
154 private:
155 };
156
157
158 void Timeline::ReclaimAllBlocks() {
159 if (recorder() == NULL) {
160 return;
161 }
162 // Reclaim all blocks cached for all isolates.
163 ReclaimBlocksIsolateVisitor visitor;
164 Isolate::VisitIsolates(&visitor);
165 // Reclaim the global VM block.
166 recorder()->ReclaimGlobalBlock();
167 }
168
169
170 void Timeline::ReclaimBlocksForIsolate(Isolate* isolate) {
171 if (recorder() == NULL) {
172 return;
173 }
174 if (isolate == NULL) {
175 return;
176 }
turnidge 2015/09/24 17:05:52 Consider an ASSERT for isolate != NULL?
Cutch 2015/09/24 18:14:16 Done.
177 isolate->ReclaimTimelineBlocks();
178 }
179
180
80 TimelineEventRecorder* Timeline::recorder_ = NULL; 181 TimelineEventRecorder* Timeline::recorder_ = NULL;
81 TimelineStream* Timeline::vm_stream_ = NULL; 182 TimelineStream* Timeline::vm_stream_ = NULL;
82 183
83 #define ISOLATE_TIMELINE_STREAM_DEFINE_FLAG(name, enabled_by_default) \ 184 #define ISOLATE_TIMELINE_STREAM_DEFINE_FLAG(name, enabled_by_default) \
84 bool Timeline::stream_##name##_enabled_ = false; 185 bool Timeline::stream_##name##_enabled_ = false;
85 ISOLATE_TIMELINE_STREAM_LIST(ISOLATE_TIMELINE_STREAM_DEFINE_FLAG) 186 ISOLATE_TIMELINE_STREAM_LIST(ISOLATE_TIMELINE_STREAM_DEFINE_FLAG)
86 #undef ISOLATE_TIMELINE_STREAM_DEFINE_FLAG 187 #undef ISOLATE_TIMELINE_STREAM_DEFINE_FLAG
87 188
88 TimelineEvent::TimelineEvent() 189 TimelineEvent::TimelineEvent()
89 : timestamp0_(0), 190 : timestamp0_(0),
(...skipping 297 matching lines...) Expand 10 before | Expand all | Expand 10 after
387 : global_block_(NULL), 488 : global_block_(NULL),
388 async_id_(0) { 489 async_id_(0) {
389 } 490 }
390 491
391 492
392 void TimelineEventRecorder::PrintJSONMeta(JSONArray* events) const { 493 void TimelineEventRecorder::PrintJSONMeta(JSONArray* events) const {
393 } 494 }
394 495
395 496
396 TimelineEvent* TimelineEventRecorder::ThreadBlockStartEvent() { 497 TimelineEvent* TimelineEventRecorder::ThreadBlockStartEvent() {
397 // Grab the thread's timeline event block. 498 // Grab the current thread.
398 Thread* thread = Thread::Current(); 499 Thread* thread = Thread::Current();
399 ASSERT(thread != NULL); 500 ASSERT(thread != NULL);
501 // We are accessing the thread's timeline block- so take the lock.
502 MutexLocker ml(thread->timeline_block_lock());
400 503
401 if (thread->isolate() == NULL) { 504 if (thread->isolate() == NULL) {
402 // Non-isolate thread case. This should be infrequent. 505 // Non-isolate thread case. This should be infrequent.
403 return GlobalBlockStartEvent(); 506 return GlobalBlockStartEvent();
404 } 507 }
405 508
406 TimelineEventBlock* thread_block = thread->timeline_block(); 509 TimelineEventBlock* thread_block = thread->timeline_block();
407 510
408 if ((thread_block != NULL) && thread_block->IsFull()) { 511 if ((thread_block != NULL) && thread_block->IsFull()) {
409 MutexLocker ml(&lock_); 512 MutexLocker ml(&lock_);
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after
453 556
454 557
455 void TimelineEventRecorder::WriteTo(const char* directory) { 558 void TimelineEventRecorder::WriteTo(const char* directory) {
456 Dart_FileOpenCallback file_open = Isolate::file_open_callback(); 559 Dart_FileOpenCallback file_open = Isolate::file_open_callback();
457 Dart_FileWriteCallback file_write = Isolate::file_write_callback(); 560 Dart_FileWriteCallback file_write = Isolate::file_write_callback();
458 Dart_FileCloseCallback file_close = Isolate::file_close_callback(); 561 Dart_FileCloseCallback file_close = Isolate::file_close_callback();
459 if ((file_open == NULL) || (file_write == NULL) || (file_close == NULL)) { 562 if ((file_open == NULL) || (file_write == NULL) || (file_close == NULL)) {
460 return; 563 return;
461 } 564 }
462 565
463 FinishGlobalBlock(); 566 Timeline::ReclaimAllBlocks();
464 567
465 JSONStream js; 568 JSONStream js;
466 TimelineEventFilter filter; 569 TimelineEventFilter filter;
467 PrintJSON(&js, &filter); 570 PrintJSON(&js, &filter);
468 571
469 intptr_t pid = OS::ProcessId(); 572 intptr_t pid = OS::ProcessId();
470 char* filename = OS::SCreate(NULL, 573 char* filename = OS::SCreate(NULL,
471 "%s/dart-timeline-%" Pd ".json", directory, pid); 574 "%s/dart-timeline-%" Pd ".json", directory, pid);
472 void* file = (*file_open)(filename, true); 575 void* file = (*file_open)(filename, true);
473 if (file == NULL) { 576 if (file == NULL) {
474 OS::Print("Failed to write timeline file: %s\n", filename); 577 OS::Print("Failed to write timeline file: %s\n", filename);
475 free(filename); 578 free(filename);
476 return; 579 return;
477 } 580 }
478 free(filename); 581 free(filename);
479 (*file_write)(js.buffer()->buf(), js.buffer()->length(), file); 582 (*file_write)(js.buffer()->buf(), js.buffer()->length(), file);
480 (*file_close)(file); 583 (*file_close)(file);
481 } 584 }
482 585
483 586
484 void TimelineEventRecorder::FinishGlobalBlock() { 587 void TimelineEventRecorder::ReclaimGlobalBlock() {
485 MutexLocker ml(&lock_); 588 MutexLocker ml(&lock_);
486 if (global_block_ != NULL) { 589 if (global_block_ != NULL) {
487 global_block_->Finish(); 590 global_block_->Finish();
488 global_block_ = NULL; 591 global_block_ = NULL;
489 } 592 }
490 } 593 }
491 594
492 595
493 int64_t TimelineEventRecorder::GetNextAsyncId() { 596 int64_t TimelineEventRecorder::GetNextAsyncId() {
494 // TODO(johnmccutchan): Gracefully handle wrap around. 597 // TODO(johnmccutchan): Gracefully handle wrap around.
(...skipping 368 matching lines...) Expand 10 before | Expand all | Expand 10 after
863 966
864 967
865 TimelineEventBlock* TimelineEventBlockIterator::Next() { 968 TimelineEventBlock* TimelineEventBlockIterator::Next() {
866 ASSERT(current_ != NULL); 969 ASSERT(current_ != NULL);
867 TimelineEventBlock* r = current_; 970 TimelineEventBlock* r = current_;
868 current_ = current_->next(); 971 current_ = current_->next();
869 return r; 972 return r;
870 } 973 }
871 974
872 } // namespace dart 975 } // namespace dart
OLDNEW
« runtime/vm/timeline.h ('K') | « runtime/vm/timeline.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698