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/isolate.h" | 8 #include "vm/isolate.h" |
8 #include "vm/json_stream.h" | 9 #include "vm/json_stream.h" |
9 #include "vm/lockers.h" | 10 #include "vm/lockers.h" |
10 #include "vm/object.h" | 11 #include "vm/object.h" |
11 #include "vm/thread.h" | 12 #include "vm/thread.h" |
12 #include "vm/timeline.h" | 13 #include "vm/timeline.h" |
13 | 14 |
14 namespace dart { | 15 namespace dart { |
15 | 16 |
16 DEFINE_FLAG(bool, trace_timeline, false, "Trace timeline backend"); | 17 DEFINE_FLAG(bool, trace_timeline, false, "Trace timeline backend"); |
17 DEFINE_FLAG(bool, complete_timeline, false, "Record the complete timeline"); | 18 DEFINE_FLAG(bool, complete_timeline, false, "Record the complete timeline"); |
18 | 19 |
20 DEFINE_FLAG(charp, timeline_dir, NULL, | |
21 "Enable all timeline trace streams and output VM global trace " | |
22 "into specified directory."); | |
23 | |
24 void Timeline::InitOnce() { | |
25 ASSERT(recorder_ == NULL); | |
26 // Default to ring recorder being enabled. | |
27 const bool use_ring_recorder = true; | |
28 // Some flags require that we use the endless recorder. | |
29 const bool use_endless_recorder = (FLAG_timeline_dir != NULL); | |
30 if (use_endless_recorder) { | |
31 recorder_ = new TimelineEventEndlessRecorder(); | |
32 } else if (use_ring_recorder) { | |
33 recorder_ = new TimelineEventRingRecorder(); | |
34 } | |
35 vm_stream_ = new TimelineStream(); | |
36 vm_stream_->Init("VM", EnableStreamByDefault("VM")); | |
37 } | |
38 | |
39 | |
40 void Timeline::Shutdown() { | |
41 ASSERT(recorder_ != NULL); | |
42 if (FLAG_timeline_dir != NULL) { | |
43 recorder_->WriteTo(FLAG_timeline_dir); | |
44 } | |
45 delete recorder_; | |
46 recorder_ = NULL; | |
47 delete vm_stream_; | |
48 vm_stream_ = NULL; | |
49 } | |
50 | |
51 | |
52 TimelineEventRecorder* Timeline::recorder() { | |
53 return recorder_; | |
54 } | |
55 | |
56 | |
57 bool Timeline::EnableStreamByDefault(const char* stream_name) { | |
58 // TODO(johnmccutchan): Allow for command line control over streams. | |
59 return FLAG_timeline_dir != NULL; | |
60 } | |
61 | |
62 | |
63 TimelineStream* Timeline::GetVMStream() { | |
64 ASSERT(vm_stream_ != NULL); | |
65 return vm_stream_; | |
66 } | |
67 | |
68 | |
69 TimelineEventRecorder* Timeline::recorder_ = NULL; | |
70 TimelineStream* Timeline::vm_stream_ = NULL; | |
71 | |
19 TimelineEvent::TimelineEvent() | 72 TimelineEvent::TimelineEvent() |
20 : timestamp0_(0), | 73 : timestamp0_(0), |
21 timestamp1_(0), | 74 timestamp1_(0), |
22 arguments_(NULL), | 75 arguments_(NULL), |
23 arguments_length_(0), | 76 arguments_length_(0), |
24 state_(0), | 77 state_(0), |
25 label_(NULL), | 78 label_(NULL), |
26 stream_(NULL), | 79 category_(""), |
27 thread_(OSThread::kInvalidThreadId) { | 80 thread_(OSThread::kInvalidThreadId) { |
28 } | 81 } |
29 | 82 |
30 | 83 |
31 TimelineEvent::~TimelineEvent() { | 84 TimelineEvent::~TimelineEvent() { |
32 Reset(); | 85 Reset(); |
33 } | 86 } |
34 | 87 |
35 | 88 |
36 void TimelineEvent::Reset() { | 89 void TimelineEvent::Reset() { |
37 set_event_type(kNone); | 90 set_event_type(kNone); |
38 thread_ = OSThread::kInvalidThreadId; | 91 thread_ = OSThread::kInvalidThreadId; |
39 stream_ = NULL; | 92 isolate_ = NULL; |
93 category_ = ""; | |
40 label_ = NULL; | 94 label_ = NULL; |
41 FreeArguments(); | 95 FreeArguments(); |
42 } | 96 } |
43 | 97 |
44 | 98 |
45 int64_t TimelineEvent::AsyncBegin(const char* label) { | 99 void TimelineEvent::AsyncBegin(const char* label, int64_t async_id) { |
46 Init(kAsyncBegin, label); | 100 Init(kAsyncBegin, label); |
47 timestamp0_ = OS::GetCurrentTimeMicros(); | 101 timestamp0_ = OS::GetCurrentTimeMicros(); |
48 ASSERT(stream_ != NULL); | |
49 int64_t async_id = stream_->GetNextSeq(); | |
50 // Overload timestamp1_ with the async_id. | 102 // Overload timestamp1_ with the async_id. |
51 timestamp1_ = async_id; | 103 timestamp1_ = static_cast<int64_t>(async_id); |
rmacnak
2015/08/18 21:09:00
Unnecessary cast
Cutch
2015/08/18 21:50:18
Done.
| |
52 return async_id; | |
53 } | 104 } |
54 | 105 |
55 | 106 |
56 void TimelineEvent::AsyncInstant(const char* label, | 107 void TimelineEvent::AsyncInstant(const char* label, |
57 int64_t async_id) { | 108 int64_t async_id) { |
58 Init(kAsyncInstant, label); | 109 Init(kAsyncInstant, label); |
59 timestamp0_ = OS::GetCurrentTimeMicros(); | 110 timestamp0_ = OS::GetCurrentTimeMicros(); |
60 // Overload timestamp1_ with the async_id. | 111 // Overload timestamp1_ with the async_id. |
61 timestamp1_ = async_id; | 112 timestamp1_ = static_cast<int64_t>(async_id);; |
rmacnak
2015/08/18 21:09:00
"
Cutch
2015/08/18 21:50:18
Done.
| |
62 } | 113 } |
63 | 114 |
64 | 115 |
65 void TimelineEvent::AsyncEnd(const char* label, | 116 void TimelineEvent::AsyncEnd(const char* label, |
66 int64_t async_id) { | 117 int64_t async_id) { |
67 Init(kAsyncEnd, label); | 118 Init(kAsyncEnd, label); |
68 timestamp0_ = OS::GetCurrentTimeMicros(); | 119 timestamp0_ = OS::GetCurrentTimeMicros(); |
69 // Overload timestamp1_ with the async_id. | 120 // Overload timestamp1_ with the async_id. |
70 timestamp1_ = async_id; | 121 timestamp1_ = static_cast<int64_t>(async_id);; |
rmacnak
2015/08/18 21:09:00
"
Cutch
2015/08/18 21:50:18
Done.
| |
71 } | 122 } |
72 | 123 |
73 | 124 |
74 void TimelineEvent::DurationBegin(const char* label) { | 125 void TimelineEvent::DurationBegin(const char* label) { |
75 Init(kDuration, label); | 126 Init(kDuration, label); |
76 timestamp0_ = OS::GetCurrentTimeMicros(); | 127 timestamp0_ = OS::GetCurrentTimeMicros(); |
77 } | 128 } |
78 | 129 |
79 | 130 |
80 void TimelineEvent::DurationEnd() { | 131 void TimelineEvent::DurationEnd() { |
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
135 | 186 |
136 | 187 |
137 void TimelineEvent::CopyArgument(intptr_t i, | 188 void TimelineEvent::CopyArgument(intptr_t i, |
138 const char* name, | 189 const char* name, |
139 const char* argument) { | 190 const char* argument) { |
140 SetArgument(i, name, strdup(argument)); | 191 SetArgument(i, name, strdup(argument)); |
141 } | 192 } |
142 | 193 |
143 | 194 |
144 void TimelineEvent::Complete() { | 195 void TimelineEvent::Complete() { |
145 stream_->CompleteEvent(this); | 196 TimelineEventRecorder* recorder = Timeline::recorder(); |
197 if (recorder != NULL) { | |
198 recorder->CompleteEvent(this); | |
199 } | |
146 } | 200 } |
147 | 201 |
148 | 202 |
149 void TimelineEvent::FreeArguments() { | 203 void TimelineEvent::FreeArguments() { |
150 if (arguments_ == NULL) { | 204 if (arguments_ == NULL) { |
151 return; | 205 return; |
152 } | 206 } |
153 for (intptr_t i = 0; i < arguments_length_; i++) { | 207 for (intptr_t i = 0; i < arguments_length_; i++) { |
154 free(arguments_[i].value); | 208 free(arguments_[i].value); |
155 } | 209 } |
156 free(arguments_); | 210 free(arguments_); |
157 arguments_ = NULL; | 211 arguments_ = NULL; |
158 arguments_length_ = 0; | 212 arguments_length_ = 0; |
159 } | 213 } |
160 | 214 |
161 | 215 |
162 void TimelineEvent::StreamInit(TimelineStream* stream) { | 216 void TimelineEvent::StreamInit(TimelineStream* stream) { |
163 ASSERT(stream != NULL); | 217 if (stream != NULL) { |
164 stream_ = stream; | 218 category_ = stream->name(); |
219 } else { | |
220 category_ = ""; | |
221 } | |
165 } | 222 } |
166 | 223 |
167 | 224 |
168 void TimelineEvent::Init(EventType event_type, | 225 void TimelineEvent::Init(EventType event_type, |
169 const char* label) { | 226 const char* label) { |
170 ASSERT(label != NULL); | 227 ASSERT(label != NULL); |
171 set_event_type(event_type); | 228 set_event_type(event_type); |
172 timestamp0_ = 0; | 229 timestamp0_ = 0; |
173 timestamp1_ = 0; | 230 timestamp1_ = 0; |
174 thread_ = OSThread::GetCurrentThreadId(); | 231 thread_ = OSThread::GetCurrentThreadId(); |
232 isolate_ = Isolate::Current(); | |
175 label_ = label; | 233 label_ = label; |
176 FreeArguments(); | 234 FreeArguments(); |
177 } | 235 } |
178 | 236 |
179 | 237 |
180 void TimelineEvent::PrintJSON(JSONStream* stream) const { | 238 void TimelineEvent::PrintJSON(JSONStream* stream) const { |
181 JSONObject obj(stream); | 239 JSONObject obj(stream); |
182 int64_t pid = OS::ProcessId(); | 240 int64_t pid = OS::ProcessId(); |
183 int64_t tid = OSThread::ThreadIdToIntPtr(thread_); | 241 int64_t tid = OSThread::ThreadIdToIntPtr(thread_); |
184 obj.AddProperty("name", label_); | 242 obj.AddProperty("name", label_); |
185 obj.AddProperty("cat", stream_->name()); | 243 obj.AddProperty("cat", category_); |
186 obj.AddProperty64("tid", tid); | 244 obj.AddProperty64("tid", tid); |
187 obj.AddProperty64("pid", pid); | 245 obj.AddProperty64("pid", pid); |
188 obj.AddPropertyTimeMillis("ts", TimeOrigin()); | 246 obj.AddPropertyTimeMillis("ts", TimeOrigin()); |
189 | 247 |
190 switch (event_type()) { | 248 switch (event_type()) { |
191 case kDuration: { | 249 case kDuration: { |
192 obj.AddProperty("ph", "X"); | 250 obj.AddProperty("ph", "X"); |
193 obj.AddPropertyTimeMillis("dur", TimeDuration()); | 251 obj.AddPropertyTimeMillis("dur", TimeDuration()); |
194 } | 252 } |
195 break; | 253 break; |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
239 int64_t TimelineEvent::TimeDuration() const { | 297 int64_t TimelineEvent::TimeDuration() const { |
240 if (timestamp1_ == 0) { | 298 if (timestamp1_ == 0) { |
241 // This duration is still open, use current time as end. | 299 // This duration is still open, use current time as end. |
242 return OS::GetCurrentTimeMicros() - timestamp0_; | 300 return OS::GetCurrentTimeMicros() - timestamp0_; |
243 } | 301 } |
244 return timestamp1_ - timestamp0_; | 302 return timestamp1_ - timestamp0_; |
245 } | 303 } |
246 | 304 |
247 | 305 |
248 TimelineStream::TimelineStream() | 306 TimelineStream::TimelineStream() |
249 : recorder_(NULL), | 307 : name_(NULL), |
250 name_(NULL), | 308 enabled_(false) { |
251 enabled_(false), | |
252 seq_(0) { | |
253 } | 309 } |
254 | 310 |
255 | 311 |
256 void TimelineStream::Init(const char* name, bool enabled) { | 312 void TimelineStream::Init(const char* name, bool enabled) { |
257 name_ = name; | 313 name_ = name; |
258 enabled_ = enabled; | 314 enabled_ = enabled; |
259 } | 315 } |
260 | 316 |
261 | 317 |
262 TimelineEvent* TimelineStream::StartEvent() { | 318 TimelineEvent* TimelineStream::StartEvent() { |
263 if (!enabled_ || (recorder_ == NULL)) { | 319 TimelineEventRecorder* recorder = Timeline::recorder(); |
320 if (!enabled_ || (recorder == NULL)) { | |
264 return NULL; | 321 return NULL; |
265 } | 322 } |
266 ASSERT(name_ != NULL); | 323 ASSERT(name_ != NULL); |
267 TimelineEvent* event = recorder_->StartEvent(); | 324 TimelineEvent* event = recorder->StartEvent(); |
268 if (event != NULL) { | 325 if (event != NULL) { |
269 event->StreamInit(this); | 326 event->StreamInit(this); |
270 } | 327 } |
271 return event; | 328 return event; |
272 } | 329 } |
273 | 330 |
274 | 331 |
275 void TimelineStream::CompleteEvent(TimelineEvent* event) { | |
276 if (!enabled_ || (recorder_ == NULL)) { | |
277 return; | |
278 } | |
279 recorder_->CompleteEvent(event); | |
280 } | |
281 | |
282 | |
283 int64_t TimelineStream::GetNextSeq() { | |
284 seq_++; | |
285 if (seq_ < 0) { | |
286 seq_ = 0; | |
287 } | |
288 return seq_; | |
289 } | |
290 | |
291 | |
292 void TimelineDurationScope::FormatArgument(intptr_t i, | 332 void TimelineDurationScope::FormatArgument(intptr_t i, |
293 const char* name, | 333 const char* name, |
294 const char* fmt, ...) { | 334 const char* fmt, ...) { |
295 if (event_ == NULL) { | 335 if (event_ == NULL) { |
296 return; | 336 return; |
297 } | 337 } |
298 va_list args; | 338 va_list args; |
299 va_start(args, fmt); | 339 va_start(args, fmt); |
300 intptr_t len = OS::VSNPrint(NULL, 0, fmt, args); | 340 intptr_t len = OS::VSNPrint(NULL, 0, fmt, args); |
301 va_end(args); | 341 va_end(args); |
302 | 342 |
303 char* buffer = reinterpret_cast<char*>(malloc(len + 1)); | 343 char* buffer = reinterpret_cast<char*>(malloc(len + 1)); |
304 va_list args2; | 344 va_list args2; |
305 va_start(args2, fmt); | 345 va_start(args2, fmt); |
306 OS::VSNPrint(buffer, (len + 1), fmt, args2); | 346 OS::VSNPrint(buffer, (len + 1), fmt, args2); |
307 va_end(args2); | 347 va_end(args2); |
308 | 348 |
309 event_->SetArgument(i, name, buffer); | 349 event_->SetArgument(i, name, buffer); |
310 } | 350 } |
311 | 351 |
312 | 352 |
313 TimelineEventRecorder::TimelineEventRecorder() { | 353 TimelineEventFilter::TimelineEventFilter() { |
314 } | 354 } |
315 | 355 |
316 | 356 |
357 TimelineEventFilter::~TimelineEventFilter() { | |
358 } | |
359 | |
360 | |
361 IsolateTimelineEventFilter::IsolateTimelineEventFilter(Isolate* isolate) | |
362 : isolate_(isolate) { | |
363 } | |
364 | |
365 | |
366 TimelineEventRecorder::TimelineEventRecorder() | |
367 : global_block_(NULL), | |
368 async_id_(0) { | |
369 } | |
370 | |
371 | |
317 void TimelineEventRecorder::PrintJSONMeta(JSONArray* events) const { | 372 void TimelineEventRecorder::PrintJSONMeta(JSONArray* events) const { |
318 } | 373 } |
319 | 374 |
320 | 375 |
321 TimelineEvent* TimelineEventRecorder::ThreadBlockStartEvent() { | 376 TimelineEvent* TimelineEventRecorder::ThreadBlockStartEvent() { |
322 // Grab the thread's timeline event block. | 377 // Grab the thread's timeline event block. |
323 Thread* thread = Thread::Current(); | 378 Thread* thread = Thread::Current(); |
379 ASSERT(thread != NULL); | |
380 | |
381 if (thread->isolate() == NULL) { | |
382 // Non-isolate thread case. This should be infrequent. | |
383 return GlobalBlockStartEvent(); | |
384 } | |
385 | |
324 TimelineEventBlock* thread_block = thread->timeline_block(); | 386 TimelineEventBlock* thread_block = thread->timeline_block(); |
325 if ((thread_block == NULL) || thread_block->IsFull()) { | 387 |
326 // If it is full, request a new block. | 388 if ((thread_block != NULL) && thread_block->IsFull()) { |
327 thread_block = GetNewBlock(); | 389 MutexLocker ml(&lock_); |
390 // Thread has a block and it is full: | |
391 // 1) Mark it as finished. | |
392 thread_block->Finish(); | |
393 // 2) Allocate a new block. | |
394 thread_block = GetNewBlockLocked(thread->isolate()); | |
395 thread->set_timeline_block(thread_block); | |
396 } else if (thread_block == NULL) { | |
397 MutexLocker ml(&lock_); | |
398 // Thread has no block. Attempt to allocate one. | |
399 thread_block = GetNewBlockLocked(thread->isolate()); | |
328 thread->set_timeline_block(thread_block); | 400 thread->set_timeline_block(thread_block); |
329 } | 401 } |
330 if (thread_block == NULL) { | 402 if (thread_block != NULL) { |
331 // Could not allocate block. | 403 ASSERT(!thread_block->IsFull()); |
332 return NULL; | 404 return thread_block->StartEvent(); |
333 } | 405 } |
334 ASSERT(thread_block != NULL); | 406 return NULL; |
335 ASSERT(!thread_block->IsFull()); | 407 } |
336 return thread_block->StartEvent(); | 408 |
409 | |
410 | |
411 TimelineEvent* TimelineEventRecorder::GlobalBlockStartEvent() { | |
412 MutexLocker ml(&lock_); | |
413 if ((global_block_ != NULL) && global_block_->IsFull()) { | |
414 // Global block is full. | |
415 global_block_->Finish(); | |
416 global_block_ = NULL; | |
417 } | |
418 if (global_block_ == NULL) { | |
419 // Allocate a new block. | |
420 global_block_ = GetNewBlockLocked(NULL); | |
421 } | |
422 if (global_block_ != NULL) { | |
423 ASSERT(!global_block_->IsFull()); | |
424 return global_block_->StartEvent(); | |
425 } | |
426 return NULL; | |
337 } | 427 } |
338 | 428 |
339 | 429 |
340 void TimelineEventRecorder::WriteTo(const char* directory) { | 430 void TimelineEventRecorder::WriteTo(const char* directory) { |
341 Isolate* isolate = Isolate::Current(); | |
342 | |
343 Dart_FileOpenCallback file_open = Isolate::file_open_callback(); | 431 Dart_FileOpenCallback file_open = Isolate::file_open_callback(); |
344 Dart_FileWriteCallback file_write = Isolate::file_write_callback(); | 432 Dart_FileWriteCallback file_write = Isolate::file_write_callback(); |
345 Dart_FileCloseCallback file_close = Isolate::file_close_callback(); | 433 Dart_FileCloseCallback file_close = Isolate::file_close_callback(); |
346 if ((file_open == NULL) || (file_write == NULL) || (file_close == NULL)) { | 434 if ((file_open == NULL) || (file_write == NULL) || (file_close == NULL)) { |
347 return; | 435 return; |
348 } | 436 } |
349 | 437 |
350 JSONStream js; | 438 JSONStream js; |
351 PrintJSON(&js); | 439 TimelineEventFilter filter; |
440 PrintJSON(&js, &filter); | |
352 | 441 |
353 const char* format = "%s/dart-timeline-%" Pd "-%" Pd ".json"; | 442 const char* format = "%s/dart-timeline-%" Pd ".json"; |
354 intptr_t pid = OS::ProcessId(); | 443 intptr_t pid = OS::ProcessId(); |
355 intptr_t len = OS::SNPrint(NULL, 0, format, | 444 intptr_t len = OS::SNPrint(NULL, 0, format, directory, pid); |
356 directory, pid, isolate->main_port()); | 445 char* filename = reinterpret_cast<char*>(malloc(len + 1)); |
357 char* filename = Thread::Current()->zone()->Alloc<char>(len + 1); | 446 OS::SNPrint(filename, len + 1, format, directory, pid); |
358 OS::SNPrint(filename, len + 1, format, | |
359 directory, pid, isolate->main_port()); | |
360 void* file = (*file_open)(filename, true); | 447 void* file = (*file_open)(filename, true); |
361 if (file == NULL) { | 448 if (file == NULL) { |
362 OS::Print("Failed to write timeline file: %s\n", filename); | 449 OS::Print("Failed to write timeline file: %s\n", filename); |
450 free(filename); | |
363 return; | 451 return; |
364 } | 452 } |
453 free(filename); | |
365 (*file_write)(js.buffer()->buf(), js.buffer()->length(), file); | 454 (*file_write)(js.buffer()->buf(), js.buffer()->length(), file); |
366 (*file_close)(file); | 455 (*file_close)(file); |
367 } | 456 } |
368 | 457 |
369 | 458 |
459 int64_t TimelineEventRecorder::GetNextAsyncId() { | |
460 // TODO(johnmccutchan): Gracefully handle wrap around. | |
461 uint32_t next = static_cast<uint32_t>( | |
462 AtomicOperations::FetchAndIncrement(&async_id_)); | |
463 return static_cast<int64_t>(next); | |
464 } | |
465 | |
466 | |
467 TimelineEventBlock* TimelineEventRecorder::GetNewBlock() { | |
468 MutexLocker ml(&lock_); | |
469 return GetNewBlockLocked(Isolate::Current()); | |
470 } | |
471 | |
370 | 472 |
371 TimelineEventRingRecorder::TimelineEventRingRecorder(intptr_t capacity) | 473 TimelineEventRingRecorder::TimelineEventRingRecorder(intptr_t capacity) |
372 : blocks_(NULL), | 474 : blocks_(NULL), |
373 event_objects_(Array::null()), | |
374 capacity_(capacity), | 475 capacity_(capacity), |
375 num_blocks_(0), | 476 num_blocks_(0), |
376 block_cursor_(0) { | 477 block_cursor_(0) { |
377 // Capacity must be a multiple of TimelineEventBlock::kBlockSize | 478 // Capacity must be a multiple of TimelineEventBlock::kBlockSize |
378 ASSERT((capacity % TimelineEventBlock::kBlockSize) == 0); | 479 ASSERT((capacity % TimelineEventBlock::kBlockSize) == 0); |
379 // Allocate blocks array. | 480 // Allocate blocks array. |
380 num_blocks_ = capacity / TimelineEventBlock::kBlockSize; | 481 num_blocks_ = capacity / TimelineEventBlock::kBlockSize; |
381 blocks_ = | 482 blocks_ = |
382 reinterpret_cast<TimelineEventBlock**>( | 483 reinterpret_cast<TimelineEventBlock**>( |
383 calloc(num_blocks_, sizeof(TimelineEventBlock*))); | 484 calloc(num_blocks_, sizeof(TimelineEventBlock*))); |
384 // Allocate each block. | 485 // Allocate each block. |
385 for (intptr_t i = 0; i < num_blocks_; i++) { | 486 for (intptr_t i = 0; i < num_blocks_; i++) { |
386 blocks_[i] = new TimelineEventBlock(i); | 487 blocks_[i] = new TimelineEventBlock(i); |
387 } | 488 } |
388 // Chain blocks together. | 489 // Chain blocks together. |
389 for (intptr_t i = 0; i < num_blocks_ - 1; i++) { | 490 for (intptr_t i = 0; i < num_blocks_ - 1; i++) { |
390 blocks_[i]->set_next(blocks_[i + 1]); | 491 blocks_[i]->set_next(blocks_[i + 1]); |
391 } | 492 } |
392 const Array& array = Array::Handle(Array::New(capacity, Heap::kOld)); | |
393 event_objects_ = array.raw(); | |
394 } | 493 } |
395 | 494 |
396 | 495 |
397 TimelineEventRingRecorder::~TimelineEventRingRecorder() { | 496 TimelineEventRingRecorder::~TimelineEventRingRecorder() { |
398 // Delete all blocks. | 497 // Delete all blocks. |
399 for (intptr_t i = 0; i < num_blocks_; i++) { | 498 for (intptr_t i = 0; i < num_blocks_; i++) { |
400 TimelineEventBlock* block = blocks_[i]; | 499 TimelineEventBlock* block = blocks_[i]; |
401 delete block; | 500 delete block; |
402 } | 501 } |
403 free(blocks_); | 502 free(blocks_); |
404 event_objects_ = Array::null(); | |
405 } | 503 } |
406 | 504 |
407 | 505 |
408 void TimelineEventRingRecorder::PrintJSONEvents(JSONArray* events) const { | 506 void TimelineEventRingRecorder::PrintJSONEvents( |
507 JSONArray* events, | |
508 TimelineEventFilter* filter) const { | |
409 intptr_t block_offset = FindOldestBlockIndex(); | 509 intptr_t block_offset = FindOldestBlockIndex(); |
410 if (block_offset == -1) { | 510 if (block_offset == -1) { |
411 // All blocks are empty. | 511 // All blocks are empty. |
412 return; | 512 return; |
413 } | 513 } |
414 for (intptr_t block_idx = 0; block_idx < num_blocks_; block_idx++) { | 514 for (intptr_t block_idx = 0; block_idx < num_blocks_; block_idx++) { |
415 TimelineEventBlock* block = | 515 TimelineEventBlock* block = |
416 blocks_[(block_idx + block_offset) % num_blocks_]; | 516 blocks_[(block_idx + block_offset) % num_blocks_]; |
417 if (block->IsEmpty()) { | 517 if (block->IsEmpty()) { |
418 // Skip empty blocks. | 518 // Skip empty blocks. |
419 continue; | 519 continue; |
420 } | 520 } |
421 for (intptr_t event_idx = 0; event_idx < block->length(); event_idx++) { | 521 for (intptr_t event_idx = 0; event_idx < block->length(); event_idx++) { |
422 TimelineEvent* event = block->At(event_idx); | 522 TimelineEvent* event = block->At(event_idx); |
423 if (event->IsValid()) { | 523 if (event->IsValid()) { |
424 events->AddValue(event); | 524 events->AddValue(event); |
425 } | 525 } |
426 } | 526 } |
427 } | 527 } |
428 } | 528 } |
429 | 529 |
430 | 530 |
431 void TimelineEventRingRecorder::PrintJSON(JSONStream* js) { | 531 void TimelineEventRingRecorder::PrintJSON(JSONStream* js, |
532 TimelineEventFilter* filter) { | |
432 MutexLocker ml(&lock_); | 533 MutexLocker ml(&lock_); |
433 JSONObject topLevel(js); | 534 JSONObject topLevel(js); |
434 topLevel.AddProperty("type", "_Timeline"); | 535 topLevel.AddProperty("type", "_Timeline"); |
435 { | 536 { |
436 JSONArray events(&topLevel, "traceEvents"); | 537 JSONArray events(&topLevel, "traceEvents"); |
437 PrintJSONMeta(&events); | 538 PrintJSONMeta(&events); |
438 PrintJSONEvents(&events); | 539 PrintJSONEvents(&events, filter); |
439 } | 540 } |
440 } | 541 } |
441 | 542 |
442 | 543 |
443 TimelineEventBlock* TimelineEventRingRecorder::GetNewBlock() { | 544 TimelineEventBlock* TimelineEventRingRecorder::GetHeadBlockLocked() { |
444 MutexLocker ml(&lock_); | |
445 return GetNewBlockLocked(); | |
446 } | |
447 | |
448 | |
449 TimelineEventBlock* TimelineEventRingRecorder::GetHeadBlock() { | |
450 return blocks_[0]; | 545 return blocks_[0]; |
451 } | 546 } |
452 | 547 |
453 | 548 |
454 TimelineEventBlock* TimelineEventRingRecorder::GetNewBlockLocked() { | 549 TimelineEventBlock* TimelineEventRingRecorder::GetNewBlockLocked( |
550 Isolate* isolate) { | |
551 // TODO(johnmccutchan): This function should only hand out blocks | |
552 // which have been marked as finished. | |
455 if (block_cursor_ == num_blocks_) { | 553 if (block_cursor_ == num_blocks_) { |
456 block_cursor_ = 0; | 554 block_cursor_ = 0; |
457 } | 555 } |
458 TimelineEventBlock* block = blocks_[block_cursor_++]; | 556 TimelineEventBlock* block = blocks_[block_cursor_++]; |
459 block->Reset(); | 557 block->Reset(); |
558 block->Open(isolate); | |
460 return block; | 559 return block; |
461 } | 560 } |
462 | 561 |
463 | 562 |
464 intptr_t TimelineEventRingRecorder::FindOldestBlockIndex() const { | 563 intptr_t TimelineEventRingRecorder::FindOldestBlockIndex() const { |
465 int64_t earliest_time = kMaxInt64; | 564 int64_t earliest_time = kMaxInt64; |
466 intptr_t earliest_index = -1; | 565 intptr_t earliest_index = -1; |
467 for (intptr_t block_idx = 0; block_idx < num_blocks_; block_idx++) { | 566 for (intptr_t block_idx = 0; block_idx < num_blocks_; block_idx++) { |
468 TimelineEventBlock* block = blocks_[block_idx]; | 567 TimelineEventBlock* block = blocks_[block_idx]; |
469 if (block->IsEmpty()) { | 568 if (block->IsEmpty()) { |
(...skipping 20 matching lines...) Expand all Loading... | |
490 | 589 |
491 | 590 |
492 TimelineEventStreamingRecorder::TimelineEventStreamingRecorder() { | 591 TimelineEventStreamingRecorder::TimelineEventStreamingRecorder() { |
493 } | 592 } |
494 | 593 |
495 | 594 |
496 TimelineEventStreamingRecorder::~TimelineEventStreamingRecorder() { | 595 TimelineEventStreamingRecorder::~TimelineEventStreamingRecorder() { |
497 } | 596 } |
498 | 597 |
499 | 598 |
500 void TimelineEventStreamingRecorder::PrintJSON(JSONStream* js) { | 599 void TimelineEventStreamingRecorder::PrintJSON(JSONStream* js, |
600 TimelineEventFilter* filter) { | |
501 JSONObject topLevel(js); | 601 JSONObject topLevel(js); |
502 topLevel.AddProperty("type", "_Timeline"); | 602 topLevel.AddProperty("type", "_Timeline"); |
503 { | 603 { |
504 JSONArray events(&topLevel, "traceEvents"); | 604 JSONArray events(&topLevel, "traceEvents"); |
505 PrintJSONMeta(&events); | 605 PrintJSONMeta(&events); |
506 } | 606 } |
507 } | 607 } |
508 | 608 |
509 | 609 |
510 TimelineEvent* TimelineEventStreamingRecorder::StartEvent() { | 610 TimelineEvent* TimelineEventStreamingRecorder::StartEvent() { |
511 TimelineEvent* event = new TimelineEvent(); | 611 TimelineEvent* event = new TimelineEvent(); |
512 return event; | 612 return event; |
513 } | 613 } |
514 | 614 |
515 | 615 |
516 void TimelineEventStreamingRecorder::CompleteEvent(TimelineEvent* event) { | 616 void TimelineEventStreamingRecorder::CompleteEvent(TimelineEvent* event) { |
517 StreamEvent(event); | 617 StreamEvent(event); |
518 delete event; | 618 delete event; |
519 } | 619 } |
520 | 620 |
521 | 621 |
522 TimelineEventEndlessRecorder::TimelineEventEndlessRecorder() | 622 TimelineEventEndlessRecorder::TimelineEventEndlessRecorder() |
523 : head_(NULL), | 623 : head_(NULL), |
524 block_index_(0) { | 624 block_index_(0) { |
525 GetNewBlock(); | 625 GetNewBlock(); |
526 } | 626 } |
527 | 627 |
528 | 628 |
529 void TimelineEventEndlessRecorder::PrintJSON(JSONStream* js) { | 629 void TimelineEventEndlessRecorder::PrintJSON(JSONStream* js, |
630 TimelineEventFilter* filter) { | |
530 MutexLocker ml(&lock_); | 631 MutexLocker ml(&lock_); |
531 JSONObject topLevel(js); | 632 JSONObject topLevel(js); |
532 topLevel.AddProperty("type", "_Timeline"); | 633 topLevel.AddProperty("type", "_Timeline"); |
533 { | 634 { |
534 JSONArray events(&topLevel, "traceEvents"); | 635 JSONArray events(&topLevel, "traceEvents"); |
535 PrintJSONMeta(&events); | 636 PrintJSONMeta(&events); |
536 PrintJSONEvents(&events); | 637 PrintJSONEvents(&events, filter); |
537 } | 638 } |
538 } | 639 } |
539 | 640 |
540 | 641 |
541 TimelineEventBlock* TimelineEventEndlessRecorder::GetNewBlock() { | 642 TimelineEventBlock* TimelineEventEndlessRecorder::GetHeadBlockLocked() { |
542 MutexLocker ml(&lock_); | |
543 return GetNewBlockLocked(); | |
544 } | |
545 | |
546 | |
547 TimelineEventBlock* TimelineEventEndlessRecorder::GetHeadBlock() { | |
548 return head_; | 643 return head_; |
549 } | 644 } |
550 | 645 |
551 | 646 |
552 TimelineEvent* TimelineEventEndlessRecorder::StartEvent() { | 647 TimelineEvent* TimelineEventEndlessRecorder::StartEvent() { |
553 return ThreadBlockStartEvent(); | 648 return ThreadBlockStartEvent(); |
554 } | 649 } |
555 | 650 |
556 | 651 |
557 void TimelineEventEndlessRecorder::CompleteEvent(TimelineEvent* event) { | 652 void TimelineEventEndlessRecorder::CompleteEvent(TimelineEvent* event) { |
558 // no-op. | 653 // no-op. |
559 } | 654 } |
560 | 655 |
561 | 656 |
562 TimelineEventBlock* TimelineEventEndlessRecorder::GetNewBlockLocked() { | 657 TimelineEventBlock* TimelineEventEndlessRecorder::GetNewBlockLocked( |
658 Isolate* isolate) { | |
563 TimelineEventBlock* block = new TimelineEventBlock(block_index_++); | 659 TimelineEventBlock* block = new TimelineEventBlock(block_index_++); |
564 block->set_next(head_); | 660 block->set_next(head_); |
661 block->Open(isolate); | |
565 head_ = block; | 662 head_ = block; |
566 return head_; | 663 return head_; |
567 } | 664 } |
568 | 665 |
569 | 666 |
570 void TimelineEventEndlessRecorder::PrintJSONEvents(JSONArray* events) const { | 667 void TimelineEventEndlessRecorder::PrintJSONEvents( |
668 JSONArray* events, | |
669 TimelineEventFilter* filter) const { | |
571 TimelineEventBlock* current = head_; | 670 TimelineEventBlock* current = head_; |
671 | |
572 while (current != NULL) { | 672 while (current != NULL) { |
573 intptr_t length = current->length(); | 673 intptr_t length = current->length(); |
574 for (intptr_t i = 0; i < length; i++) { | 674 for (intptr_t i = 0; i < length; i++) { |
575 TimelineEvent* event = current->At(i); | 675 TimelineEvent* event = current->At(i); |
576 if (!event->IsValid()) { | 676 if (!event->IsValid()) { |
577 continue; | 677 continue; |
578 } | 678 } |
579 events->AddValue(event); | 679 events->AddValue(event); |
580 } | 680 } |
581 current = current->next(); | 681 current = current->next(); |
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
652 return true; | 752 return true; |
653 } | 753 } |
654 | 754 |
655 | 755 |
656 void TimelineEventBlock::Reset() { | 756 void TimelineEventBlock::Reset() { |
657 for (intptr_t i = 0; i < kBlockSize; i++) { | 757 for (intptr_t i = 0; i < kBlockSize; i++) { |
658 // Clear any extra data. | 758 // Clear any extra data. |
659 events_[i].Reset(); | 759 events_[i].Reset(); |
660 } | 760 } |
661 length_ = 0; | 761 length_ = 0; |
762 isolate_ = NULL; | |
763 open_ = false; | |
662 } | 764 } |
663 | 765 |
664 | 766 |
767 void TimelineEventBlock::Open(Isolate* isolate) { | |
768 isolate_ = isolate; | |
769 open_ = true; | |
770 } | |
771 | |
772 | |
773 void TimelineEventBlock::Finish() { | |
774 open_ = false; | |
775 } | |
776 | |
777 | |
665 TimelineEventBlockIterator::TimelineEventBlockIterator( | 778 TimelineEventBlockIterator::TimelineEventBlockIterator( |
666 TimelineEventRecorder* recorder) | 779 TimelineEventRecorder* recorder) |
667 : current_(NULL), | 780 : current_(NULL), |
668 recorder_(NULL) { | 781 recorder_(NULL) { |
669 Reset(recorder); | 782 Reset(recorder); |
670 } | 783 } |
671 | 784 |
672 | 785 |
673 TimelineEventBlockIterator::~TimelineEventBlockIterator() { | 786 TimelineEventBlockIterator::~TimelineEventBlockIterator() { |
674 Reset(NULL); | 787 Reset(NULL); |
675 } | 788 } |
676 | 789 |
677 | 790 |
678 void TimelineEventBlockIterator::Reset(TimelineEventRecorder* recorder) { | 791 void TimelineEventBlockIterator::Reset(TimelineEventRecorder* recorder) { |
679 // Clear current. | 792 // Clear current. |
680 current_ = NULL; | 793 current_ = NULL; |
681 if (recorder_ != NULL) { | 794 if (recorder_ != NULL) { |
682 // Unlock old recorder. | 795 // Unlock old recorder. |
683 recorder_->lock_.Unlock(); | 796 recorder_->lock_.Unlock(); |
684 } | 797 } |
685 recorder_ = recorder; | 798 recorder_ = recorder; |
686 if (recorder_ == NULL) { | 799 if (recorder_ == NULL) { |
687 return; | 800 return; |
688 } | 801 } |
689 // Lock new recorder. | 802 // Lock new recorder. |
690 recorder_->lock_.Lock(); | 803 recorder_->lock_.Lock(); |
691 // Queue up first block. | 804 // Queue up first block. |
692 current_ = recorder_->GetHeadBlock(); | 805 current_ = recorder_->GetHeadBlockLocked(); |
693 } | 806 } |
694 | 807 |
695 | 808 |
696 bool TimelineEventBlockIterator::HasNext() const { | 809 bool TimelineEventBlockIterator::HasNext() const { |
697 return current_ != NULL; | 810 return current_ != NULL; |
698 } | 811 } |
699 | 812 |
700 | 813 |
701 TimelineEventBlock* TimelineEventBlockIterator::Next() { | 814 TimelineEventBlock* TimelineEventBlockIterator::Next() { |
702 ASSERT(current_ != NULL); | 815 ASSERT(current_ != NULL); |
703 TimelineEventBlock* r = current_; | 816 TimelineEventBlock* r = current_; |
704 current_ = current_->next(); | 817 current_ = current_->next(); |
705 return r; | 818 return r; |
706 } | 819 } |
707 | 820 |
708 } // namespace dart | 821 } // namespace dart |
OLD | NEW |