| 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 return result; |
| 95 } |
| 96 |
| 97 |
| 98 // Frees the result of |GetEnabledByDefaultTimelineStreams|. |
| 99 static void FreeEnabledByDefaultTimelineStreams( |
| 100 MallocGrowableArray<char*>* streams) { |
| 101 if (streams == NULL) { |
| 102 return; |
| 103 } |
| 104 for (intptr_t i = 0; i < streams->length(); i++) { |
| 105 free((*streams)[i]); |
| 106 } |
| 107 delete streams; |
| 108 } |
| 109 |
| 110 |
| 111 // Returns true if |streams| contains |stream| or "all". Not case sensitive. |
| 112 static bool HasStream(MallocGrowableArray<char*>* streams, const char* stream) { |
| 113 if ((FLAG_timeline_dir != NULL) || FLAG_timing || FLAG_complete_timeline) { |
| 114 return true; |
| 115 } |
| 116 for (intptr_t i = 0; i < streams->length(); i++) { |
| 117 const char* checked_stream = (*streams)[i]; |
| 118 if ((strcasestr(checked_stream, "all") != NULL) || |
| 119 (strcasestr(checked_stream, stream) != NULL)) { |
| 120 return true; |
| 121 } |
| 122 } |
| 123 return false; |
| 124 } |
| 125 |
| 126 |
| 73 void Timeline::InitOnce() { | 127 void Timeline::InitOnce() { |
| 74 ASSERT(recorder_ == NULL); | 128 ASSERT(recorder_ == NULL); |
| 75 // Default to ring recorder being enabled. | 129 // Default to ring recorder being enabled. |
| 76 const bool use_ring_recorder = true; | 130 const bool use_ring_recorder = true; |
| 77 // Some flags require that we use the endless recorder. | 131 // Some flags require that we use the endless recorder. |
| 78 const bool use_endless_recorder = | 132 const bool use_endless_recorder = |
| 79 (FLAG_timeline_dir != NULL) || FLAG_timing || FLAG_complete_timeline; | 133 (FLAG_timeline_dir != NULL) || FLAG_timing || FLAG_complete_timeline; |
| 80 if (use_endless_recorder) { | 134 if (use_endless_recorder) { |
| 81 recorder_ = new TimelineEventEndlessRecorder(); | 135 recorder_ = new TimelineEventEndlessRecorder(); |
| 82 } else if (use_ring_recorder) { | 136 } else if (use_ring_recorder) { |
| 83 recorder_ = new TimelineEventRingRecorder(); | 137 recorder_ = new TimelineEventRingRecorder(); |
| 84 } | 138 } |
| 85 vm_stream_.Init("VM", EnableStreamByDefault("VM"), NULL); | 139 enabled_streams_ = GetEnabledByDefaultTimelineStreams(); |
| 140 vm_stream_.Init("VM", HasStream(enabled_streams_, "VM"), NULL); |
| 86 vm_api_stream_.Init("API", | 141 vm_api_stream_.Init("API", |
| 87 EnableStreamByDefault("API"), | 142 HasStream(enabled_streams_, "API"), |
| 88 &stream_API_enabled_); | 143 &stream_API_enabled_); |
| 89 // Global overrides. | 144 // Global overrides. |
| 90 #define ISOLATE_TIMELINE_STREAM_FLAG_DEFAULT(name, not_used) \ | 145 #define ISOLATE_TIMELINE_STREAM_FLAG_DEFAULT(name, not_used) \ |
| 91 stream_##name##_enabled_ = EnableStreamByDefault(#name); | 146 stream_##name##_enabled_ = HasStream(enabled_streams_, #name); |
| 92 ISOLATE_TIMELINE_STREAM_LIST(ISOLATE_TIMELINE_STREAM_FLAG_DEFAULT) | 147 ISOLATE_TIMELINE_STREAM_LIST(ISOLATE_TIMELINE_STREAM_FLAG_DEFAULT) |
| 93 #undef ISOLATE_TIMELINE_STREAM_FLAG_DEFAULT | 148 #undef ISOLATE_TIMELINE_STREAM_FLAG_DEFAULT |
| 94 } | 149 } |
| 95 | 150 |
| 96 | 151 |
| 152 void Timeline::SetVMStreamEnabled(bool enabled) { |
| 153 vm_stream_.set_enabled(enabled); |
| 154 } |
| 155 |
| 156 |
| 97 void Timeline::Shutdown() { | 157 void Timeline::Shutdown() { |
| 98 ASSERT(recorder_ != NULL); | 158 ASSERT(recorder_ != NULL); |
| 99 if (FLAG_timeline_dir != NULL) { | 159 if (FLAG_timeline_dir != NULL) { |
| 100 recorder_->WriteTo(FLAG_timeline_dir); | 160 recorder_->WriteTo(FLAG_timeline_dir); |
| 101 } | 161 } |
| 102 // Disable global streams. | 162 // Disable global streams. |
| 103 vm_stream_.set_enabled(false); | 163 vm_stream_.set_enabled(false); |
| 104 vm_api_stream_.set_enabled(false); | 164 vm_api_stream_.set_enabled(false); |
| 105 #define ISOLATE_TIMELINE_STREAM_DISABLE(name, not_used) \ | 165 #define ISOLATE_TIMELINE_STREAM_DISABLE(name, not_used) \ |
| 106 stream_##name##_enabled_ = false; | 166 stream_##name##_enabled_ = false; |
| 107 ISOLATE_TIMELINE_STREAM_LIST(ISOLATE_TIMELINE_STREAM_DISABLE) | 167 ISOLATE_TIMELINE_STREAM_LIST(ISOLATE_TIMELINE_STREAM_DISABLE) |
| 108 #undef ISOLATE_TIMELINE_STREAM_DISABLE | 168 #undef ISOLATE_TIMELINE_STREAM_DISABLE |
| 109 delete recorder_; | 169 delete recorder_; |
| 110 recorder_ = NULL; | 170 recorder_ = NULL; |
| 171 if (enabled_streams_ != NULL) { |
| 172 FreeEnabledByDefaultTimelineStreams(enabled_streams_); |
| 173 enabled_streams_ = NULL; |
| 174 } |
| 111 } | 175 } |
| 112 | 176 |
| 113 | 177 |
| 114 TimelineEventRecorder* Timeline::recorder() { | 178 TimelineEventRecorder* Timeline::recorder() { |
| 115 return recorder_; | 179 return recorder_; |
| 116 } | 180 } |
| 117 | 181 |
| 118 | 182 |
| 119 bool Timeline::EnableStreamByDefault(const char* stream_name) { | 183 void Timeline::SetupIsolateStreams(Isolate* isolate) { |
| 120 // TODO(johnmccutchan): Allow for command line control over streams. | 184 #define ISOLATE_TIMELINE_STREAM_INIT(name, enabled_by_default) \ |
| 121 return (FLAG_timeline_dir != NULL) || FLAG_timing || FLAG_complete_timeline; | 185 isolate->Get##name##Stream()->Init( \ |
| 186 #name, \ |
| 187 (enabled_by_default || HasStream(enabled_streams_, #name)), \ |
| 188 Timeline::Stream##name##EnabledFlag()); |
| 189 ISOLATE_TIMELINE_STREAM_LIST(ISOLATE_TIMELINE_STREAM_INIT); |
| 190 #undef ISOLATE_TIMELINE_STREAM_INIT |
| 122 } | 191 } |
| 123 | 192 |
| 124 | 193 |
| 125 TimelineStream* Timeline::GetVMStream() { | 194 TimelineStream* Timeline::GetVMStream() { |
| 126 return &vm_stream_; | 195 return &vm_stream_; |
| 127 } | 196 } |
| 128 | 197 |
| 129 | 198 |
| 130 TimelineStream* Timeline::GetVMApiStream() { | 199 TimelineStream* Timeline::GetVMApiStream() { |
| 131 return &vm_api_stream_; | 200 return &vm_api_stream_; |
| (...skipping 15 matching lines...) Expand all Loading... |
| 147 TimelineEventBlock* block = thread->timeline_block(); | 216 TimelineEventBlock* block = thread->timeline_block(); |
| 148 thread->set_timeline_block(NULL); | 217 thread->set_timeline_block(NULL); |
| 149 // TODO(johnmccutchan): Consider dropping the timeline_block_lock here | 218 // TODO(johnmccutchan): Consider dropping the timeline_block_lock here |
| 150 // if we can do it everywhere. This would simplify the lock ordering | 219 // if we can do it everywhere. This would simplify the lock ordering |
| 151 // requirements. | 220 // requirements. |
| 152 recorder->FinishBlock(block); | 221 recorder->FinishBlock(block); |
| 153 } | 222 } |
| 154 } | 223 } |
| 155 | 224 |
| 156 | 225 |
| 226 void Timeline::PrintFlagsToJSON(JSONStream* js) { |
| 227 JSONObject obj(js); |
| 228 obj.AddProperty("type", "TimelineFlags"); |
| 229 TimelineEventRecorder* recorder = Timeline::recorder(); |
| 230 if (recorder == NULL) { |
| 231 obj.AddProperty("recorderName", "null"); |
| 232 } else { |
| 233 obj.AddProperty("recorderName", recorder->name()); |
| 234 } |
| 235 { |
| 236 JSONArray availableStreams(&obj, "availableStreams"); |
| 237 #define ADD_STREAM_NAME(name, not_used) \ |
| 238 availableStreams.AddValue(#name); |
| 239 ISOLATE_TIMELINE_STREAM_LIST(ADD_STREAM_NAME); |
| 240 #undef ADD_STREAM_NAME |
| 241 availableStreams.AddValue("VM"); |
| 242 } |
| 243 { |
| 244 JSONArray recordedStreams(&obj, "recordedStreams"); |
| 245 #define ADD_RECORDED_STREAM_NAME(name, not_used) \ |
| 246 if (stream_##name##_enabled_) { \ |
| 247 recordedStreams.AddValue(#name); \ |
| 248 } |
| 249 ISOLATE_TIMELINE_STREAM_LIST(ADD_RECORDED_STREAM_NAME); |
| 250 #undef ADD_RECORDED_STREAM_NAME |
| 251 if (vm_stream_.enabled()) { |
| 252 recordedStreams.AddValue("VM"); |
| 253 } |
| 254 } |
| 255 } |
| 256 |
| 257 |
| 157 void Timeline::Clear() { | 258 void Timeline::Clear() { |
| 158 TimelineEventRecorder* recorder = Timeline::recorder(); | 259 TimelineEventRecorder* recorder = Timeline::recorder(); |
| 159 if (recorder == NULL) { | 260 if (recorder == NULL) { |
| 160 return; | 261 return; |
| 161 } | 262 } |
| 162 ReclaimCachedBlocksFromThreads(); | 263 ReclaimCachedBlocksFromThreads(); |
| 163 recorder->Clear(); | 264 recorder->Clear(); |
| 164 } | 265 } |
| 165 | 266 |
| 166 | 267 |
| 167 TimelineEventRecorder* Timeline::recorder_ = NULL; | 268 TimelineEventRecorder* Timeline::recorder_ = NULL; |
| 168 TimelineStream Timeline::vm_stream_; | 269 TimelineStream Timeline::vm_stream_; |
| 169 TimelineStream Timeline::vm_api_stream_; | 270 TimelineStream Timeline::vm_api_stream_; |
| 271 MallocGrowableArray<char*>* Timeline::enabled_streams_ = NULL; |
| 170 | 272 |
| 171 #define ISOLATE_TIMELINE_STREAM_DEFINE_FLAG(name, enabled_by_default) \ | 273 #define ISOLATE_TIMELINE_STREAM_DEFINE_FLAG(name, enabled_by_default) \ |
| 172 bool Timeline::stream_##name##_enabled_ = enabled_by_default; | 274 bool Timeline::stream_##name##_enabled_ = enabled_by_default; |
| 173 ISOLATE_TIMELINE_STREAM_LIST(ISOLATE_TIMELINE_STREAM_DEFINE_FLAG) | 275 ISOLATE_TIMELINE_STREAM_LIST(ISOLATE_TIMELINE_STREAM_DEFINE_FLAG) |
| 174 #undef ISOLATE_TIMELINE_STREAM_DEFINE_FLAG | 276 #undef ISOLATE_TIMELINE_STREAM_DEFINE_FLAG |
| 175 | 277 |
| 176 TimelineEvent::TimelineEvent() | 278 TimelineEvent::TimelineEvent() |
| 177 : timestamp0_(0), | 279 : timestamp0_(0), |
| 178 timestamp1_(0), | 280 timestamp1_(0), |
| 179 arguments_(NULL), | 281 arguments_(NULL), |
| (...skipping 1222 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1402 TimelineEventBlock* TimelineEventBlockIterator::Next() { | 1504 TimelineEventBlock* TimelineEventBlockIterator::Next() { |
| 1403 ASSERT(current_ != NULL); | 1505 ASSERT(current_ != NULL); |
| 1404 TimelineEventBlock* r = current_; | 1506 TimelineEventBlock* r = current_; |
| 1405 current_ = current_->next(); | 1507 current_ = current_->next(); |
| 1406 return r; | 1508 return r; |
| 1407 } | 1509 } |
| 1408 | 1510 |
| 1409 #endif // !PRODUCT | 1511 #endif // !PRODUCT |
| 1410 | 1512 |
| 1411 } // namespace dart | 1513 } // namespace dart |
| OLD | NEW |