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 <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 #ifndef PRODUCT | 18 #ifndef PRODUCT |
19 | 19 |
20 DEFINE_FLAG(bool, complete_timeline, false, "Record the complete timeline"); | 20 DEFINE_FLAG(bool, complete_timeline, false, "Record the complete timeline"); |
21 DEFINE_FLAG(bool, trace_timeline, false, | 21 DEFINE_FLAG(bool, trace_timeline, false, |
22 "Trace timeline backend"); | 22 "Trace timeline backend"); |
23 DEFINE_FLAG(bool, trace_timeline_analysis, false, | 23 DEFINE_FLAG(bool, trace_timeline_analysis, false, |
24 "Trace timeline analysis backend"); | 24 "Trace timeline analysis backend"); |
25 DEFINE_FLAG(bool, timing, false, | 25 DEFINE_FLAG(bool, timing, false, |
26 "Dump isolate timing information from timeline."); | 26 "Dump isolate timing information from timeline."); |
27 DEFINE_FLAG(charp, timeline_dir, NULL, | 27 DEFINE_FLAG(charp, timeline_dir, NULL, |
28 "Enable all timeline trace streams and output VM global trace " | 28 "Enable all timeline trace streams and output VM global trace " |
29 "into specified directory."); | 29 "into specified directory."); |
30 DEFINE_FLAG(charp, timeline_streams, NULL, | |
31 "Comma separated list of timeline streams to record. " | |
32 "Valid values: all, api, compiler, dart, debugger, embedder, " | |
33 "gc, isolate, and vm."); | |
30 | 34 |
31 // Implementation notes: | 35 // Implementation notes: |
32 // | 36 // |
33 // Writing events: | 37 // Writing events: |
34 // |TimelineEvent|s are written into |TimelineEventBlock|s. Each |Thread| caches | 38 // |TimelineEvent|s are written into |TimelineEventBlock|s. Each |Thread| caches |
35 // a |TimelineEventBlock| object so that it can write events without | 39 // a |TimelineEventBlock| object so that it can write events without |
36 // synchronizing with other threads in the system. Even though the |Thread| owns | 40 // synchronizing with other threads in the system. Even though the |Thread| owns |
37 // the |TimelineEventBlock| the block may need to be reclaimed by the reporting | 41 // the |TimelineEventBlock| the block may need to be reclaimed by the reporting |
38 // system. To support that, a |Thread| must hold its |timeline_block_lock_| | 42 // system. To support that, a |Thread| must hold its |timeline_block_lock_| |
39 // when operating on the |TimelineEventBlock|. This lock will only ever be | 43 // when operating on the |TimelineEventBlock|. This lock will only ever be |
(...skipping 23 matching lines...) Expand all Loading... | |
63 // cached block is being operated on. | 67 // cached block is being operated on. |
64 // - |Thread::thread_list_lock_| This lock is held when iterating over | 68 // - |Thread::thread_list_lock_| This lock is held when iterating over |
65 // |Thread|s. | 69 // |Thread|s. |
66 // | 70 // |
67 // Locks must always be taken in the following order: | 71 // Locks must always be taken in the following order: |
68 // |Thread::thread_list_lock_| | 72 // |Thread::thread_list_lock_| |
69 // |Thread::timeline_block_lock_| | 73 // |Thread::timeline_block_lock_| |
70 // |TimelineEventRecorder::lock_| | 74 // |TimelineEventRecorder::lock_| |
71 // | 75 // |
72 | 76 |
77 | |
78 // Returns a caller freed array of stream names in FLAG_timeline_streams. | |
79 static MallocGrowableArray<char*>* GetEnabledByDefaultTimelineStreams() { | |
80 MallocGrowableArray<char*>* result = new MallocGrowableArray<char*>(); | |
81 if (FLAG_timeline_streams == NULL) { | |
82 // Nothing set. | |
83 return result; | |
84 } | |
85 char* save_ptr; // Needed for strtok_r. | |
86 // strtok modifies arg 1 so we make a copy of it. | |
87 char* streams = strdup(FLAG_timeline_streams); | |
88 char* token = strtok_r(streams, ",", &save_ptr); | |
89 while (token != NULL) { | |
90 result->Add(strdup(token)); | |
91 token = strtok_r(NULL, ",", &save_ptr); | |
92 } | |
93 free(streams); | |
94 for (intptr_t i = 0; i < result->length(); i++) { | |
95 const char* s = (*result)[i]; | |
96 OS::Print("%s\n", s); | |
zra
2016/02/12 18:57:56
Leftover debug print?
Cutch
2016/02/12 20:13:57
Done.
| |
97 } | |
98 return result; | |
99 } | |
100 | |
101 | |
102 // Frees the result of |GetEnabledByDefaultTimelineStreams|. | |
103 static void FreeEnabledByDefaultTimelineStreams( | |
104 MallocGrowableArray<char*>* streams) { | |
105 if (streams == NULL) { | |
106 return; | |
107 } | |
108 for (intptr_t i = 0; i < streams->length(); i++) { | |
109 free((*streams)[i]); | |
110 } | |
111 delete streams; | |
112 } | |
113 | |
114 | |
115 // Returns true if |streams| contains |stream| or "all". Not case sensitive. | |
116 static bool HasStream(MallocGrowableArray<char*>* streams, const char* stream) { | |
117 if ((FLAG_timeline_dir != NULL) || FLAG_timing || FLAG_complete_timeline) { | |
118 return true; | |
119 } | |
120 for (intptr_t i = 0; i < streams->length(); i++) { | |
121 const char* checked_stream = (*streams)[i]; | |
122 if ((strcasestr(checked_stream, "all") != NULL) || | |
123 (strcasestr(checked_stream, stream) != NULL)) { | |
124 return true; | |
125 } | |
126 } | |
127 return false; | |
128 } | |
129 | |
130 | |
73 void Timeline::InitOnce() { | 131 void Timeline::InitOnce() { |
74 ASSERT(recorder_ == NULL); | 132 ASSERT(recorder_ == NULL); |
75 // Default to ring recorder being enabled. | 133 // Default to ring recorder being enabled. |
76 const bool use_ring_recorder = true; | 134 const bool use_ring_recorder = true; |
77 // Some flags require that we use the endless recorder. | 135 // Some flags require that we use the endless recorder. |
78 const bool use_endless_recorder = | 136 const bool use_endless_recorder = |
79 (FLAG_timeline_dir != NULL) || FLAG_timing || FLAG_complete_timeline; | 137 (FLAG_timeline_dir != NULL) || FLAG_timing || FLAG_complete_timeline; |
80 if (use_endless_recorder) { | 138 if (use_endless_recorder) { |
81 recorder_ = new TimelineEventEndlessRecorder(); | 139 recorder_ = new TimelineEventEndlessRecorder(); |
82 } else if (use_ring_recorder) { | 140 } else if (use_ring_recorder) { |
83 recorder_ = new TimelineEventRingRecorder(); | 141 recorder_ = new TimelineEventRingRecorder(); |
84 } | 142 } |
85 vm_stream_.Init("VM", EnableStreamByDefault("VM"), NULL); | 143 MallocGrowableArray<char*>* enabled_streams = |
144 GetEnabledByDefaultTimelineStreams(); | |
145 vm_stream_.Init("VM", HasStream(enabled_streams, "VM"), NULL); | |
86 vm_api_stream_.Init("API", | 146 vm_api_stream_.Init("API", |
87 EnableStreamByDefault("API"), | 147 HasStream(enabled_streams, "API"), |
88 &stream_API_enabled_); | 148 &stream_API_enabled_); |
89 // Global overrides. | 149 // Global overrides. |
90 #define ISOLATE_TIMELINE_STREAM_FLAG_DEFAULT(name, not_used) \ | 150 #define ISOLATE_TIMELINE_STREAM_FLAG_DEFAULT(name, not_used) \ |
91 stream_##name##_enabled_ = EnableStreamByDefault(#name); | 151 stream_##name##_enabled_ = HasStream(enabled_streams, #name); |
92 ISOLATE_TIMELINE_STREAM_LIST(ISOLATE_TIMELINE_STREAM_FLAG_DEFAULT) | 152 ISOLATE_TIMELINE_STREAM_LIST(ISOLATE_TIMELINE_STREAM_FLAG_DEFAULT) |
93 #undef ISOLATE_TIMELINE_STREAM_FLAG_DEFAULT | 153 #undef ISOLATE_TIMELINE_STREAM_FLAG_DEFAULT |
154 FreeEnabledByDefaultTimelineStreams(enabled_streams); | |
zra
2016/02/12 18:57:56
Will this ever be different? Why not cache it some
Cutch
2016/02/12 20:13:57
Done.
| |
94 } | 155 } |
95 | 156 |
96 | 157 |
158 void Timeline::SetVMStreamEnabled(bool enabled) { | |
159 vm_stream_.set_enabled(enabled); | |
160 } | |
161 | |
162 | |
97 void Timeline::Shutdown() { | 163 void Timeline::Shutdown() { |
98 ASSERT(recorder_ != NULL); | 164 ASSERT(recorder_ != NULL); |
99 if (FLAG_timeline_dir != NULL) { | 165 if (FLAG_timeline_dir != NULL) { |
100 recorder_->WriteTo(FLAG_timeline_dir); | 166 recorder_->WriteTo(FLAG_timeline_dir); |
101 } | 167 } |
102 // Disable global streams. | 168 // Disable global streams. |
103 vm_stream_.set_enabled(false); | 169 vm_stream_.set_enabled(false); |
104 vm_api_stream_.set_enabled(false); | 170 vm_api_stream_.set_enabled(false); |
105 #define ISOLATE_TIMELINE_STREAM_DISABLE(name, not_used) \ | 171 #define ISOLATE_TIMELINE_STREAM_DISABLE(name, not_used) \ |
106 stream_##name##_enabled_ = false; | 172 stream_##name##_enabled_ = false; |
107 ISOLATE_TIMELINE_STREAM_LIST(ISOLATE_TIMELINE_STREAM_DISABLE) | 173 ISOLATE_TIMELINE_STREAM_LIST(ISOLATE_TIMELINE_STREAM_DISABLE) |
108 #undef ISOLATE_TIMELINE_STREAM_DISABLE | 174 #undef ISOLATE_TIMELINE_STREAM_DISABLE |
109 delete recorder_; | 175 delete recorder_; |
110 recorder_ = NULL; | 176 recorder_ = NULL; |
111 } | 177 } |
112 | 178 |
113 | 179 |
114 TimelineEventRecorder* Timeline::recorder() { | 180 TimelineEventRecorder* Timeline::recorder() { |
115 return recorder_; | 181 return recorder_; |
116 } | 182 } |
117 | 183 |
zra
2016/02/12 18:57:56
Missing newline
Cutch
2016/02/12 20:13:57
Done.
| |
184 void Timeline::SetupIsolateStreams(Isolate* isolate) { | |
185 MallocGrowableArray<char*>* enabled_streams = | |
186 GetEnabledByDefaultTimelineStreams(); | |
118 | 187 |
119 bool Timeline::EnableStreamByDefault(const char* stream_name) { | 188 #define ISOLATE_TIMELINE_STREAM_INIT(name, enabled_by_default) \ |
120 // TODO(johnmccutchan): Allow for command line control over streams. | 189 isolate->Get##name##Stream()->Init( \ |
121 return (FLAG_timeline_dir != NULL) || FLAG_timing || FLAG_complete_timeline; | 190 #name, \ |
191 (enabled_by_default || HasStream(enabled_streams, #name)), \ | |
192 Timeline::Stream##name##EnabledFlag()); | |
193 ISOLATE_TIMELINE_STREAM_LIST(ISOLATE_TIMELINE_STREAM_INIT); | |
194 #undef ISOLATE_TIMELINE_STREAM_INIT | |
195 | |
196 FreeEnabledByDefaultTimelineStreams(enabled_streams); | |
122 } | 197 } |
123 | 198 |
124 | 199 |
125 TimelineStream* Timeline::GetVMStream() { | 200 TimelineStream* Timeline::GetVMStream() { |
126 return &vm_stream_; | 201 return &vm_stream_; |
127 } | 202 } |
128 | 203 |
129 | 204 |
130 TimelineStream* Timeline::GetVMApiStream() { | 205 TimelineStream* Timeline::GetVMApiStream() { |
131 return &vm_api_stream_; | 206 return &vm_api_stream_; |
(...skipping 15 matching lines...) Expand all Loading... | |
147 TimelineEventBlock* block = thread->timeline_block(); | 222 TimelineEventBlock* block = thread->timeline_block(); |
148 thread->set_timeline_block(NULL); | 223 thread->set_timeline_block(NULL); |
149 // TODO(johnmccutchan): Consider dropping the timeline_block_lock here | 224 // TODO(johnmccutchan): Consider dropping the timeline_block_lock here |
150 // if we can do it everywhere. This would simplify the lock ordering | 225 // if we can do it everywhere. This would simplify the lock ordering |
151 // requirements. | 226 // requirements. |
152 recorder->FinishBlock(block); | 227 recorder->FinishBlock(block); |
153 } | 228 } |
154 } | 229 } |
155 | 230 |
156 | 231 |
232 void Timeline::PrintFlagsToJSON(JSONStream* js) { | |
233 JSONObject obj(js); | |
234 obj.AddProperty("type", "TimelineFlags"); | |
235 TimelineEventRecorder* recorder = Timeline::recorder(); | |
236 if (recorder == NULL) { | |
237 obj.AddProperty("recorderName", "null"); | |
238 } else { | |
239 obj.AddProperty("recorderName", recorder->name()); | |
240 } | |
241 { | |
242 JSONArray availableStreams(&obj, "availableStreams"); | |
243 #define ADD_STREAM_NAME(name, not_used) \ | |
244 availableStreams.AddValue(#name); | |
245 ISOLATE_TIMELINE_STREAM_LIST(ADD_STREAM_NAME); | |
246 #undef ADD_STREAM_NAME | |
247 availableStreams.AddValue("VM"); | |
248 } | |
249 { | |
250 JSONArray recordedStreams(&obj, "recordedStreams"); | |
251 #define ADD_RECORDED_STREAM_NAME(name, not_used) \ | |
252 if (stream_##name##_enabled_) { \ | |
253 recordedStreams.AddValue(#name); \ | |
254 } | |
255 ISOLATE_TIMELINE_STREAM_LIST(ADD_RECORDED_STREAM_NAME); | |
256 #undef ADD_RECORDED_STREAM_NAME | |
257 if (vm_stream_.enabled()) { | |
258 recordedStreams.AddValue("VM"); | |
259 } | |
260 } | |
261 } | |
262 | |
zra
2016/02/12 18:57:56
Missing newline
Cutch
2016/02/12 20:13:57
Done.
| |
157 void Timeline::Clear() { | 263 void Timeline::Clear() { |
158 TimelineEventRecorder* recorder = Timeline::recorder(); | 264 TimelineEventRecorder* recorder = Timeline::recorder(); |
159 if (recorder == NULL) { | 265 if (recorder == NULL) { |
160 return; | 266 return; |
161 } | 267 } |
162 ReclaimCachedBlocksFromThreads(); | 268 ReclaimCachedBlocksFromThreads(); |
163 recorder->Clear(); | 269 recorder->Clear(); |
164 } | 270 } |
165 | 271 |
166 | 272 |
(...skipping 1235 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1402 TimelineEventBlock* TimelineEventBlockIterator::Next() { | 1508 TimelineEventBlock* TimelineEventBlockIterator::Next() { |
1403 ASSERT(current_ != NULL); | 1509 ASSERT(current_ != NULL); |
1404 TimelineEventBlock* r = current_; | 1510 TimelineEventBlock* r = current_; |
1405 current_ = current_->next(); | 1511 current_ = current_->next(); |
1406 return r; | 1512 return r; |
1407 } | 1513 } |
1408 | 1514 |
1409 #endif // !PRODUCT | 1515 #endif // !PRODUCT |
1410 | 1516 |
1411 } // namespace dart | 1517 } // namespace dart |
OLD | NEW |