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_ = async_id; |
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_ = async_id; |
62 } | 113 } |
(...skipping 72 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 |
| 438 FinishGlobalBlock(); |
| 439 |
350 JSONStream js; | 440 JSONStream js; |
351 PrintJSON(&js); | 441 TimelineEventFilter filter; |
| 442 PrintJSON(&js, &filter); |
352 | 443 |
353 const char* format = "%s/dart-timeline-%" Pd "-%" Pd ".json"; | 444 const char* format = "%s/dart-timeline-%" Pd ".json"; |
354 intptr_t pid = OS::ProcessId(); | 445 intptr_t pid = OS::ProcessId(); |
355 intptr_t len = OS::SNPrint(NULL, 0, format, | 446 intptr_t len = OS::SNPrint(NULL, 0, format, directory, pid); |
356 directory, pid, isolate->main_port()); | 447 char* filename = reinterpret_cast<char*>(malloc(len + 1)); |
357 char* filename = Thread::Current()->zone()->Alloc<char>(len + 1); | 448 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); | 449 void* file = (*file_open)(filename, true); |
361 if (file == NULL) { | 450 if (file == NULL) { |
362 OS::Print("Failed to write timeline file: %s\n", filename); | 451 OS::Print("Failed to write timeline file: %s\n", filename); |
| 452 free(filename); |
363 return; | 453 return; |
364 } | 454 } |
| 455 free(filename); |
365 (*file_write)(js.buffer()->buf(), js.buffer()->length(), file); | 456 (*file_write)(js.buffer()->buf(), js.buffer()->length(), file); |
366 (*file_close)(file); | 457 (*file_close)(file); |
367 } | 458 } |
368 | 459 |
369 | 460 |
| 461 void TimelineEventRecorder::FinishGlobalBlock() { |
| 462 MutexLocker ml(&lock_); |
| 463 if (global_block_ != NULL) { |
| 464 global_block_->Finish(); |
| 465 global_block_ = NULL; |
| 466 } |
| 467 } |
| 468 |
| 469 |
| 470 int64_t TimelineEventRecorder::GetNextAsyncId() { |
| 471 // TODO(johnmccutchan): Gracefully handle wrap around. |
| 472 uint32_t next = static_cast<uint32_t>( |
| 473 AtomicOperations::FetchAndIncrement(&async_id_)); |
| 474 return static_cast<int64_t>(next); |
| 475 } |
| 476 |
| 477 |
| 478 TimelineEventBlock* TimelineEventRecorder::GetNewBlock() { |
| 479 MutexLocker ml(&lock_); |
| 480 return GetNewBlockLocked(Isolate::Current()); |
| 481 } |
| 482 |
370 | 483 |
371 TimelineEventRingRecorder::TimelineEventRingRecorder(intptr_t capacity) | 484 TimelineEventRingRecorder::TimelineEventRingRecorder(intptr_t capacity) |
372 : blocks_(NULL), | 485 : blocks_(NULL), |
373 event_objects_(Array::null()), | |
374 capacity_(capacity), | 486 capacity_(capacity), |
375 num_blocks_(0), | 487 num_blocks_(0), |
376 block_cursor_(0) { | 488 block_cursor_(0) { |
377 // Capacity must be a multiple of TimelineEventBlock::kBlockSize | 489 // Capacity must be a multiple of TimelineEventBlock::kBlockSize |
378 ASSERT((capacity % TimelineEventBlock::kBlockSize) == 0); | 490 ASSERT((capacity % TimelineEventBlock::kBlockSize) == 0); |
379 // Allocate blocks array. | 491 // Allocate blocks array. |
380 num_blocks_ = capacity / TimelineEventBlock::kBlockSize; | 492 num_blocks_ = capacity / TimelineEventBlock::kBlockSize; |
381 blocks_ = | 493 blocks_ = |
382 reinterpret_cast<TimelineEventBlock**>( | 494 reinterpret_cast<TimelineEventBlock**>( |
383 calloc(num_blocks_, sizeof(TimelineEventBlock*))); | 495 calloc(num_blocks_, sizeof(TimelineEventBlock*))); |
384 // Allocate each block. | 496 // Allocate each block. |
385 for (intptr_t i = 0; i < num_blocks_; i++) { | 497 for (intptr_t i = 0; i < num_blocks_; i++) { |
386 blocks_[i] = new TimelineEventBlock(i); | 498 blocks_[i] = new TimelineEventBlock(i); |
387 } | 499 } |
388 // Chain blocks together. | 500 // Chain blocks together. |
389 for (intptr_t i = 0; i < num_blocks_ - 1; i++) { | 501 for (intptr_t i = 0; i < num_blocks_ - 1; i++) { |
390 blocks_[i]->set_next(blocks_[i + 1]); | 502 blocks_[i]->set_next(blocks_[i + 1]); |
391 } | 503 } |
392 const Array& array = Array::Handle(Array::New(capacity, Heap::kOld)); | |
393 event_objects_ = array.raw(); | |
394 } | 504 } |
395 | 505 |
396 | 506 |
397 TimelineEventRingRecorder::~TimelineEventRingRecorder() { | 507 TimelineEventRingRecorder::~TimelineEventRingRecorder() { |
398 // Delete all blocks. | 508 // Delete all blocks. |
399 for (intptr_t i = 0; i < num_blocks_; i++) { | 509 for (intptr_t i = 0; i < num_blocks_; i++) { |
400 TimelineEventBlock* block = blocks_[i]; | 510 TimelineEventBlock* block = blocks_[i]; |
401 delete block; | 511 delete block; |
402 } | 512 } |
403 free(blocks_); | 513 free(blocks_); |
404 event_objects_ = Array::null(); | |
405 } | 514 } |
406 | 515 |
407 | 516 |
408 void TimelineEventRingRecorder::PrintJSONEvents(JSONArray* events) const { | 517 void TimelineEventRingRecorder::PrintJSONEvents( |
| 518 JSONArray* events, |
| 519 TimelineEventFilter* filter) const { |
409 intptr_t block_offset = FindOldestBlockIndex(); | 520 intptr_t block_offset = FindOldestBlockIndex(); |
410 if (block_offset == -1) { | 521 if (block_offset == -1) { |
411 // All blocks are empty. | 522 // All blocks are empty. |
412 return; | 523 return; |
413 } | 524 } |
414 for (intptr_t block_idx = 0; block_idx < num_blocks_; block_idx++) { | 525 for (intptr_t block_idx = 0; block_idx < num_blocks_; block_idx++) { |
415 TimelineEventBlock* block = | 526 TimelineEventBlock* block = |
416 blocks_[(block_idx + block_offset) % num_blocks_]; | 527 blocks_[(block_idx + block_offset) % num_blocks_]; |
417 if (block->IsEmpty()) { | 528 if (!filter->IncludeBlock(block)) { |
418 // Skip empty blocks. | |
419 continue; | 529 continue; |
420 } | 530 } |
421 for (intptr_t event_idx = 0; event_idx < block->length(); event_idx++) { | 531 for (intptr_t event_idx = 0; event_idx < block->length(); event_idx++) { |
422 TimelineEvent* event = block->At(event_idx); | 532 TimelineEvent* event = block->At(event_idx); |
423 if (event->IsValid()) { | 533 if (filter->IncludeEvent(event)) { |
424 events->AddValue(event); | 534 events->AddValue(event); |
425 } | 535 } |
426 } | 536 } |
427 } | 537 } |
428 } | 538 } |
429 | 539 |
430 | 540 |
431 void TimelineEventRingRecorder::PrintJSON(JSONStream* js) { | 541 void TimelineEventRingRecorder::PrintJSON(JSONStream* js, |
| 542 TimelineEventFilter* filter) { |
432 MutexLocker ml(&lock_); | 543 MutexLocker ml(&lock_); |
433 JSONObject topLevel(js); | 544 JSONObject topLevel(js); |
434 topLevel.AddProperty("type", "_Timeline"); | 545 topLevel.AddProperty("type", "_Timeline"); |
435 { | 546 { |
436 JSONArray events(&topLevel, "traceEvents"); | 547 JSONArray events(&topLevel, "traceEvents"); |
437 PrintJSONMeta(&events); | 548 PrintJSONMeta(&events); |
438 PrintJSONEvents(&events); | 549 PrintJSONEvents(&events, filter); |
439 } | 550 } |
440 } | 551 } |
441 | 552 |
442 | 553 |
443 TimelineEventBlock* TimelineEventRingRecorder::GetNewBlock() { | 554 TimelineEventBlock* TimelineEventRingRecorder::GetHeadBlockLocked() { |
444 MutexLocker ml(&lock_); | |
445 return GetNewBlockLocked(); | |
446 } | |
447 | |
448 | |
449 TimelineEventBlock* TimelineEventRingRecorder::GetHeadBlock() { | |
450 return blocks_[0]; | 555 return blocks_[0]; |
451 } | 556 } |
452 | 557 |
453 | 558 |
454 TimelineEventBlock* TimelineEventRingRecorder::GetNewBlockLocked() { | 559 TimelineEventBlock* TimelineEventRingRecorder::GetNewBlockLocked( |
| 560 Isolate* isolate) { |
| 561 // TODO(johnmccutchan): This function should only hand out blocks |
| 562 // which have been marked as finished. |
455 if (block_cursor_ == num_blocks_) { | 563 if (block_cursor_ == num_blocks_) { |
456 block_cursor_ = 0; | 564 block_cursor_ = 0; |
457 } | 565 } |
458 TimelineEventBlock* block = blocks_[block_cursor_++]; | 566 TimelineEventBlock* block = blocks_[block_cursor_++]; |
459 block->Reset(); | 567 block->Reset(); |
| 568 block->Open(isolate); |
460 return block; | 569 return block; |
461 } | 570 } |
462 | 571 |
463 | 572 |
464 intptr_t TimelineEventRingRecorder::FindOldestBlockIndex() const { | 573 intptr_t TimelineEventRingRecorder::FindOldestBlockIndex() const { |
465 int64_t earliest_time = kMaxInt64; | 574 int64_t earliest_time = kMaxInt64; |
466 intptr_t earliest_index = -1; | 575 intptr_t earliest_index = -1; |
467 for (intptr_t block_idx = 0; block_idx < num_blocks_; block_idx++) { | 576 for (intptr_t block_idx = 0; block_idx < num_blocks_; block_idx++) { |
468 TimelineEventBlock* block = blocks_[block_idx]; | 577 TimelineEventBlock* block = blocks_[block_idx]; |
469 if (block->IsEmpty()) { | 578 if (block->IsEmpty()) { |
(...skipping 20 matching lines...) Expand all Loading... |
490 | 599 |
491 | 600 |
492 TimelineEventStreamingRecorder::TimelineEventStreamingRecorder() { | 601 TimelineEventStreamingRecorder::TimelineEventStreamingRecorder() { |
493 } | 602 } |
494 | 603 |
495 | 604 |
496 TimelineEventStreamingRecorder::~TimelineEventStreamingRecorder() { | 605 TimelineEventStreamingRecorder::~TimelineEventStreamingRecorder() { |
497 } | 606 } |
498 | 607 |
499 | 608 |
500 void TimelineEventStreamingRecorder::PrintJSON(JSONStream* js) { | 609 void TimelineEventStreamingRecorder::PrintJSON(JSONStream* js, |
| 610 TimelineEventFilter* filter) { |
501 JSONObject topLevel(js); | 611 JSONObject topLevel(js); |
502 topLevel.AddProperty("type", "_Timeline"); | 612 topLevel.AddProperty("type", "_Timeline"); |
503 { | 613 { |
504 JSONArray events(&topLevel, "traceEvents"); | 614 JSONArray events(&topLevel, "traceEvents"); |
505 PrintJSONMeta(&events); | 615 PrintJSONMeta(&events); |
506 } | 616 } |
507 } | 617 } |
508 | 618 |
509 | 619 |
510 TimelineEvent* TimelineEventStreamingRecorder::StartEvent() { | 620 TimelineEvent* TimelineEventStreamingRecorder::StartEvent() { |
511 TimelineEvent* event = new TimelineEvent(); | 621 TimelineEvent* event = new TimelineEvent(); |
512 return event; | 622 return event; |
513 } | 623 } |
514 | 624 |
515 | 625 |
516 void TimelineEventStreamingRecorder::CompleteEvent(TimelineEvent* event) { | 626 void TimelineEventStreamingRecorder::CompleteEvent(TimelineEvent* event) { |
517 StreamEvent(event); | 627 StreamEvent(event); |
518 delete event; | 628 delete event; |
519 } | 629 } |
520 | 630 |
521 | 631 |
522 TimelineEventEndlessRecorder::TimelineEventEndlessRecorder() | 632 TimelineEventEndlessRecorder::TimelineEventEndlessRecorder() |
523 : head_(NULL), | 633 : head_(NULL), |
524 block_index_(0) { | 634 block_index_(0) { |
525 GetNewBlock(); | 635 GetNewBlock(); |
526 } | 636 } |
527 | 637 |
528 | 638 |
529 void TimelineEventEndlessRecorder::PrintJSON(JSONStream* js) { | 639 void TimelineEventEndlessRecorder::PrintJSON(JSONStream* js, |
| 640 TimelineEventFilter* filter) { |
530 MutexLocker ml(&lock_); | 641 MutexLocker ml(&lock_); |
531 JSONObject topLevel(js); | 642 JSONObject topLevel(js); |
532 topLevel.AddProperty("type", "_Timeline"); | 643 topLevel.AddProperty("type", "_Timeline"); |
533 { | 644 { |
534 JSONArray events(&topLevel, "traceEvents"); | 645 JSONArray events(&topLevel, "traceEvents"); |
535 PrintJSONMeta(&events); | 646 PrintJSONMeta(&events); |
536 PrintJSONEvents(&events); | 647 PrintJSONEvents(&events, filter); |
537 } | 648 } |
538 } | 649 } |
539 | 650 |
540 | 651 |
541 TimelineEventBlock* TimelineEventEndlessRecorder::GetNewBlock() { | 652 TimelineEventBlock* TimelineEventEndlessRecorder::GetHeadBlockLocked() { |
542 MutexLocker ml(&lock_); | |
543 return GetNewBlockLocked(); | |
544 } | |
545 | |
546 | |
547 TimelineEventBlock* TimelineEventEndlessRecorder::GetHeadBlock() { | |
548 return head_; | 653 return head_; |
549 } | 654 } |
550 | 655 |
551 | 656 |
552 TimelineEvent* TimelineEventEndlessRecorder::StartEvent() { | 657 TimelineEvent* TimelineEventEndlessRecorder::StartEvent() { |
553 return ThreadBlockStartEvent(); | 658 return ThreadBlockStartEvent(); |
554 } | 659 } |
555 | 660 |
556 | 661 |
557 void TimelineEventEndlessRecorder::CompleteEvent(TimelineEvent* event) { | 662 void TimelineEventEndlessRecorder::CompleteEvent(TimelineEvent* event) { |
558 // no-op. | 663 // no-op. |
559 } | 664 } |
560 | 665 |
561 | 666 |
562 TimelineEventBlock* TimelineEventEndlessRecorder::GetNewBlockLocked() { | 667 TimelineEventBlock* TimelineEventEndlessRecorder::GetNewBlockLocked( |
| 668 Isolate* isolate) { |
563 TimelineEventBlock* block = new TimelineEventBlock(block_index_++); | 669 TimelineEventBlock* block = new TimelineEventBlock(block_index_++); |
564 block->set_next(head_); | 670 block->set_next(head_); |
| 671 block->Open(isolate); |
565 head_ = block; | 672 head_ = block; |
566 return head_; | 673 return head_; |
567 } | 674 } |
568 | 675 |
569 | 676 |
570 void TimelineEventEndlessRecorder::PrintJSONEvents(JSONArray* events) const { | 677 void TimelineEventEndlessRecorder::PrintJSONEvents( |
| 678 JSONArray* events, |
| 679 TimelineEventFilter* filter) const { |
571 TimelineEventBlock* current = head_; | 680 TimelineEventBlock* current = head_; |
| 681 |
572 while (current != NULL) { | 682 while (current != NULL) { |
| 683 if (!filter->IncludeBlock(current)) { |
| 684 current = current->next(); |
| 685 continue; |
| 686 } |
573 intptr_t length = current->length(); | 687 intptr_t length = current->length(); |
574 for (intptr_t i = 0; i < length; i++) { | 688 for (intptr_t i = 0; i < length; i++) { |
575 TimelineEvent* event = current->At(i); | 689 TimelineEvent* event = current->At(i); |
576 if (!event->IsValid()) { | 690 if (!filter->IncludeEvent(event)) { |
577 continue; | 691 continue; |
578 } | 692 } |
579 events->AddValue(event); | 693 events->AddValue(event); |
580 } | 694 } |
581 current = current->next(); | 695 current = current->next(); |
582 } | 696 } |
583 } | 697 } |
584 | 698 |
585 | 699 |
586 void TimelineEventEndlessRecorder::Clear() { | 700 void TimelineEventEndlessRecorder::Clear() { |
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
652 return true; | 766 return true; |
653 } | 767 } |
654 | 768 |
655 | 769 |
656 void TimelineEventBlock::Reset() { | 770 void TimelineEventBlock::Reset() { |
657 for (intptr_t i = 0; i < kBlockSize; i++) { | 771 for (intptr_t i = 0; i < kBlockSize; i++) { |
658 // Clear any extra data. | 772 // Clear any extra data. |
659 events_[i].Reset(); | 773 events_[i].Reset(); |
660 } | 774 } |
661 length_ = 0; | 775 length_ = 0; |
| 776 isolate_ = NULL; |
| 777 open_ = false; |
662 } | 778 } |
663 | 779 |
664 | 780 |
| 781 void TimelineEventBlock::Open(Isolate* isolate) { |
| 782 isolate_ = isolate; |
| 783 open_ = true; |
| 784 } |
| 785 |
| 786 |
| 787 void TimelineEventBlock::Finish() { |
| 788 open_ = false; |
| 789 } |
| 790 |
| 791 |
665 TimelineEventBlockIterator::TimelineEventBlockIterator( | 792 TimelineEventBlockIterator::TimelineEventBlockIterator( |
666 TimelineEventRecorder* recorder) | 793 TimelineEventRecorder* recorder) |
667 : current_(NULL), | 794 : current_(NULL), |
668 recorder_(NULL) { | 795 recorder_(NULL) { |
669 Reset(recorder); | 796 Reset(recorder); |
670 } | 797 } |
671 | 798 |
672 | 799 |
673 TimelineEventBlockIterator::~TimelineEventBlockIterator() { | 800 TimelineEventBlockIterator::~TimelineEventBlockIterator() { |
674 Reset(NULL); | 801 Reset(NULL); |
675 } | 802 } |
676 | 803 |
677 | 804 |
678 void TimelineEventBlockIterator::Reset(TimelineEventRecorder* recorder) { | 805 void TimelineEventBlockIterator::Reset(TimelineEventRecorder* recorder) { |
679 // Clear current. | 806 // Clear current. |
680 current_ = NULL; | 807 current_ = NULL; |
681 if (recorder_ != NULL) { | 808 if (recorder_ != NULL) { |
682 // Unlock old recorder. | 809 // Unlock old recorder. |
683 recorder_->lock_.Unlock(); | 810 recorder_->lock_.Unlock(); |
684 } | 811 } |
685 recorder_ = recorder; | 812 recorder_ = recorder; |
686 if (recorder_ == NULL) { | 813 if (recorder_ == NULL) { |
687 return; | 814 return; |
688 } | 815 } |
689 // Lock new recorder. | 816 // Lock new recorder. |
690 recorder_->lock_.Lock(); | 817 recorder_->lock_.Lock(); |
691 // Queue up first block. | 818 // Queue up first block. |
692 current_ = recorder_->GetHeadBlock(); | 819 current_ = recorder_->GetHeadBlockLocked(); |
693 } | 820 } |
694 | 821 |
695 | 822 |
696 bool TimelineEventBlockIterator::HasNext() const { | 823 bool TimelineEventBlockIterator::HasNext() const { |
697 return current_ != NULL; | 824 return current_ != NULL; |
698 } | 825 } |
699 | 826 |
700 | 827 |
701 TimelineEventBlock* TimelineEventBlockIterator::Next() { | 828 TimelineEventBlock* TimelineEventBlockIterator::Next() { |
702 ASSERT(current_ != NULL); | 829 ASSERT(current_ != NULL); |
703 TimelineEventBlock* r = current_; | 830 TimelineEventBlock* r = current_; |
704 current_ = current_->next(); | 831 current_ = current_->next(); |
705 return r; | 832 return r; |
706 } | 833 } |
707 | 834 |
708 } // namespace dart | 835 } // namespace dart |
OLD | NEW |