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/isolate.h" | 7 #include "vm/isolate.h" |
8 #include "vm/json_stream.h" | 8 #include "vm/json_stream.h" |
9 #include "vm/lockers.h" | 9 #include "vm/lockers.h" |
10 #include "vm/object.h" | 10 #include "vm/object.h" |
(...skipping 314 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
325 | 325 |
326 | 326 |
327 TimelineEventRecorder::TimelineEventRecorder() { | 327 TimelineEventRecorder::TimelineEventRecorder() { |
328 } | 328 } |
329 | 329 |
330 | 330 |
331 void TimelineEventRecorder::PrintJSONMeta(JSONArray* events) const { | 331 void TimelineEventRecorder::PrintJSONMeta(JSONArray* events) const { |
332 } | 332 } |
333 | 333 |
334 | 334 |
| 335 TimelineEvent* TimelineEventRecorder::ThreadBlockStartEvent() { |
| 336 // Grab the thread's timeline event block. |
| 337 Thread* thread = Thread::Current(); |
| 338 TimelineEventBlock* thread_block = thread->timeline_block(); |
| 339 if ((thread_block == NULL) || thread_block->IsFull()) { |
| 340 // If it is full, request a new block. |
| 341 thread_block = GetNewBlock(); |
| 342 thread->set_timeline_block(thread_block); |
| 343 } |
| 344 if (thread_block == NULL) { |
| 345 // Could not allocate block. |
| 346 return NULL; |
| 347 } |
| 348 ASSERT(thread_block != NULL); |
| 349 ASSERT(!thread_block->IsFull()); |
| 350 return thread_block->StartEvent(); |
| 351 } |
| 352 |
| 353 |
335 void TimelineEventRecorder::WriteTo(const char* directory) { | 354 void TimelineEventRecorder::WriteTo(const char* directory) { |
336 Isolate* isolate = Isolate::Current(); | 355 Isolate* isolate = Isolate::Current(); |
337 | 356 |
338 Dart_FileOpenCallback file_open = Isolate::file_open_callback(); | 357 Dart_FileOpenCallback file_open = Isolate::file_open_callback(); |
339 Dart_FileWriteCallback file_write = Isolate::file_write_callback(); | 358 Dart_FileWriteCallback file_write = Isolate::file_write_callback(); |
340 Dart_FileCloseCallback file_close = Isolate::file_close_callback(); | 359 Dart_FileCloseCallback file_close = Isolate::file_close_callback(); |
341 if ((file_open == NULL) || (file_write == NULL) || (file_close == NULL)) { | 360 if ((file_open == NULL) || (file_write == NULL) || (file_close == NULL)) { |
342 return; | 361 return; |
343 } | 362 } |
344 | 363 |
(...skipping 10 matching lines...) Expand all Loading... |
355 void* file = (*file_open)(filename, true); | 374 void* file = (*file_open)(filename, true); |
356 if (file == NULL) { | 375 if (file == NULL) { |
357 OS::Print("Failed to write timeline file: %s\n", filename); | 376 OS::Print("Failed to write timeline file: %s\n", filename); |
358 return; | 377 return; |
359 } | 378 } |
360 (*file_write)(js.buffer()->buf(), js.buffer()->length(), file); | 379 (*file_write)(js.buffer()->buf(), js.buffer()->length(), file); |
361 (*file_close)(file); | 380 (*file_close)(file); |
362 } | 381 } |
363 | 382 |
364 | 383 |
365 intptr_t TimelineEventRingRecorder::SizeForCapacity(intptr_t capacity) { | |
366 return sizeof(TimelineEvent) * capacity; | |
367 } | |
368 | |
369 | 384 |
370 TimelineEventRingRecorder::TimelineEventRingRecorder(intptr_t capacity) | 385 TimelineEventRingRecorder::TimelineEventRingRecorder(intptr_t capacity) |
371 : events_(NULL), | 386 : blocks_(NULL), |
372 event_objects_(Array::null()), | 387 event_objects_(Array::null()), |
373 cursor_(0), | 388 capacity_(capacity), |
374 capacity_(capacity) { | 389 num_blocks_(0), |
375 if (FLAG_trace_timeline) { | 390 block_cursor_(0) { |
376 // 32-bit: 262,144 bytes per isolate. | 391 // Capacity must be a multiple of TimelineEventBlock::kBlockSize |
377 // 64-bit: 393,216 bytes per isolate. | 392 ASSERT((capacity % TimelineEventBlock::kBlockSize) == 0); |
378 // NOTE: Internal isolates (vm and service) do not have a timeline | 393 // Allocate blocks array. |
379 // event buffer. | 394 num_blocks_ = capacity / TimelineEventBlock::kBlockSize; |
380 OS::Print("TimelineEventRingRecorder is %" Pd " bytes (%" Pd " events)\n", | 395 blocks_ = |
381 SizeForCapacity(capacity), | 396 reinterpret_cast<TimelineEventBlock**>( |
382 capacity); | 397 calloc(num_blocks_, sizeof(TimelineEventBlock*))); |
| 398 // Allocate each block. |
| 399 for (intptr_t i = 0; i < num_blocks_; i++) { |
| 400 blocks_[i] = new TimelineEventBlock(i); |
383 } | 401 } |
384 events_ = | 402 // Chain blocks together. |
385 reinterpret_cast<TimelineEvent*>(calloc(capacity, sizeof(TimelineEvent))); | 403 for (intptr_t i = 0; i < num_blocks_ - 1; i++) { |
| 404 blocks_[i]->set_next(blocks_[i + 1]); |
| 405 } |
386 const Array& array = Array::Handle(Array::New(capacity, Heap::kOld)); | 406 const Array& array = Array::Handle(Array::New(capacity, Heap::kOld)); |
387 event_objects_ = array.raw(); | 407 event_objects_ = array.raw(); |
388 } | 408 } |
389 | 409 |
390 | 410 |
391 TimelineEventRingRecorder::~TimelineEventRingRecorder() { | 411 TimelineEventRingRecorder::~TimelineEventRingRecorder() { |
392 for (intptr_t i = 0; i < capacity_; i++) { | 412 // Delete all blocks. |
393 // Clear any extra data. | 413 for (intptr_t i = 0; i < num_blocks_; i++) { |
394 events_[i].Reset(); | 414 TimelineEventBlock* block = blocks_[i]; |
| 415 delete block; |
395 } | 416 } |
396 free(events_); | 417 free(blocks_); |
397 event_objects_ = Array::null(); | 418 event_objects_ = Array::null(); |
398 } | 419 } |
399 | 420 |
400 | 421 |
401 void TimelineEventRingRecorder::PrintJSONEvents(JSONArray* events) const { | 422 void TimelineEventRingRecorder::PrintJSONEvents(JSONArray* events) const { |
402 for (intptr_t i = 0; i < capacity_; i++) { | 423 // TODO(johnmccutchan): This output needs to start with the oldest block |
403 if (events_[i].IsValid()) { | 424 // first. |
404 events->AddValue(&events_[i]); | 425 for (intptr_t block_idx = 0; block_idx < num_blocks_; block_idx++) { |
| 426 TimelineEventBlock* block = blocks_[block_idx]; |
| 427 if (block->IsEmpty()) { |
| 428 // Skip empty blocks. |
| 429 continue; |
| 430 } |
| 431 for (intptr_t event_idx = 0; event_idx < block->length(); event_idx++) { |
| 432 TimelineEvent* event = block->At(event_idx); |
| 433 if (event->IsValid()) { |
| 434 events->AddValue(event); |
| 435 } |
405 } | 436 } |
406 } | 437 } |
407 } | 438 } |
408 | 439 |
409 | 440 |
410 void TimelineEventRingRecorder::PrintJSON(JSONStream* js) { | 441 void TimelineEventRingRecorder::PrintJSON(JSONStream* js) { |
| 442 MutexLocker ml(&lock_); |
411 JSONObject topLevel(js); | 443 JSONObject topLevel(js); |
412 topLevel.AddProperty("type", "_Timeline"); | 444 topLevel.AddProperty("type", "_Timeline"); |
413 { | 445 { |
414 JSONArray events(&topLevel, "traceEvents"); | 446 JSONArray events(&topLevel, "traceEvents"); |
415 PrintJSONMeta(&events); | 447 PrintJSONMeta(&events); |
416 PrintJSONEvents(&events); | 448 PrintJSONEvents(&events); |
417 } | 449 } |
418 } | 450 } |
419 | 451 |
420 | 452 |
421 intptr_t TimelineEventRingRecorder::GetNextIndex() { | 453 TimelineEventBlock* TimelineEventRingRecorder::GetNewBlock() { |
422 uintptr_t cursor = AtomicOperations::FetchAndIncrement(&cursor_); | 454 MutexLocker ml(&lock_); |
423 return cursor % capacity_; | 455 return GetNewBlockLocked(); |
424 } | 456 } |
425 | 457 |
426 | 458 |
| 459 TimelineEventBlock* TimelineEventRingRecorder::GetNewBlockLocked() { |
| 460 if (block_cursor_ == num_blocks_) { |
| 461 block_cursor_ = 0; |
| 462 } |
| 463 TimelineEventBlock* block = blocks_[block_cursor_++]; |
| 464 block->Reset(); |
| 465 return block; |
| 466 } |
| 467 |
| 468 |
427 void TimelineEventRingRecorder::VisitObjectPointers( | 469 void TimelineEventRingRecorder::VisitObjectPointers( |
428 ObjectPointerVisitor* visitor) { | 470 ObjectPointerVisitor* visitor) { |
429 visitor->VisitPointer(reinterpret_cast<RawObject**>(&event_objects_)); | 471 visitor->VisitPointer(reinterpret_cast<RawObject**>(&event_objects_)); |
430 } | 472 } |
431 | 473 |
432 | 474 |
433 TimelineEvent* TimelineEventRingRecorder::StartEvent(const Object& obj) { | 475 TimelineEvent* TimelineEventRingRecorder::StartEvent(const Object& obj) { |
434 ASSERT(events_ != NULL); | 476 TimelineEvent* event = StartEvent(); |
435 uintptr_t index = GetNextIndex(); | 477 if (event == NULL) { |
| 478 return NULL; |
| 479 } |
| 480 // Grab the thread's timeline event block which contains |event|. |
| 481 Thread* thread = Thread::Current(); |
| 482 TimelineEventBlock* thread_block = thread->timeline_block(); |
| 483 ASSERT(thread_block != NULL); |
| 484 ASSERT(thread_block->length() > 0); |
| 485 const intptr_t block_index = thread_block->block_index(); |
| 486 const intptr_t event_objects_index = |
| 487 block_index * TimelineEventBlock::kBlockSize + thread_block->length() - 1; |
436 const Array& event_objects = Array::Handle(event_objects_); | 488 const Array& event_objects = Array::Handle(event_objects_); |
437 event_objects.SetAt(index, obj); | 489 event_objects.SetAt(event_objects_index, obj); |
438 return &events_[index]; | 490 return event; |
439 } | 491 } |
440 | 492 |
441 | 493 |
442 TimelineEvent* TimelineEventRingRecorder::StartEvent() { | 494 TimelineEvent* TimelineEventRingRecorder::StartEvent() { |
443 ASSERT(events_ != NULL); | 495 return ThreadBlockStartEvent(); |
444 uintptr_t index = GetNextIndex(); | |
445 return &events_[index]; | |
446 } | 496 } |
447 | 497 |
| 498 |
448 void TimelineEventRingRecorder::CompleteEvent(TimelineEvent* event) { | 499 void TimelineEventRingRecorder::CompleteEvent(TimelineEvent* event) { |
449 ASSERT(events_ != NULL); | |
450 // no-op. | 500 // no-op. |
451 } | 501 } |
452 | 502 |
453 | 503 |
454 TimelineEventStreamingRecorder::TimelineEventStreamingRecorder() { | 504 TimelineEventStreamingRecorder::TimelineEventStreamingRecorder() { |
455 } | 505 } |
456 | 506 |
457 | 507 |
458 TimelineEventStreamingRecorder::~TimelineEventStreamingRecorder() { | 508 TimelineEventStreamingRecorder::~TimelineEventStreamingRecorder() { |
459 } | 509 } |
460 | 510 |
461 | 511 |
462 void TimelineEventStreamingRecorder::PrintJSON(JSONStream* js) { | 512 void TimelineEventStreamingRecorder::PrintJSON(JSONStream* js) { |
463 JSONObject topLevel(js); | 513 JSONObject topLevel(js); |
464 topLevel.AddProperty("type", "_Timeline"); | 514 topLevel.AddProperty("type", "_Timeline"); |
465 { | 515 { |
466 JSONArray events(&topLevel, "traceEvents"); | 516 JSONArray events(&topLevel, "traceEvents"); |
467 PrintJSONMeta(&events); | 517 PrintJSONMeta(&events); |
468 } | 518 } |
469 } | 519 } |
470 | 520 |
| 521 |
471 void TimelineEventStreamingRecorder::VisitObjectPointers( | 522 void TimelineEventStreamingRecorder::VisitObjectPointers( |
472 ObjectPointerVisitor* visitor) { | 523 ObjectPointerVisitor* visitor) { |
473 // no-op. | 524 // no-op. |
474 } | 525 } |
475 | 526 |
476 | 527 |
477 TimelineEvent* TimelineEventStreamingRecorder::StartEvent( | 528 TimelineEvent* TimelineEventStreamingRecorder::StartEvent( |
478 const Object& object) { | 529 const Object& object) { |
479 // The streaming recorder does not track Dart objects. | 530 // The streaming recorder does not track Dart objects. |
480 return StartEvent(); | 531 return StartEvent(); |
481 } | 532 } |
482 | 533 |
483 | 534 |
484 TimelineEvent* TimelineEventStreamingRecorder::StartEvent() { | 535 TimelineEvent* TimelineEventStreamingRecorder::StartEvent() { |
485 TimelineEvent* event = new TimelineEvent(); | 536 TimelineEvent* event = new TimelineEvent(); |
486 return event; | 537 return event; |
487 } | 538 } |
488 | 539 |
489 | 540 |
490 void TimelineEventStreamingRecorder::CompleteEvent(TimelineEvent* event) { | 541 void TimelineEventStreamingRecorder::CompleteEvent(TimelineEvent* event) { |
491 StreamEvent(event); | 542 StreamEvent(event); |
492 delete event; | 543 delete event; |
493 } | 544 } |
494 | 545 |
495 | 546 |
496 TimelineEventEndlessRecorder::TimelineEventEndlessRecorder() | 547 TimelineEventEndlessRecorder::TimelineEventEndlessRecorder() |
497 : head_(NULL) { | 548 : head_(NULL), |
| 549 block_index_(0) { |
498 GetNewBlock(); | 550 GetNewBlock(); |
499 } | 551 } |
500 | 552 |
501 | 553 |
502 void TimelineEventEndlessRecorder::PrintJSON(JSONStream* js) { | 554 void TimelineEventEndlessRecorder::PrintJSON(JSONStream* js) { |
503 MutexLocker ml(&lock_); | 555 MutexLocker ml(&lock_); |
504 JSONObject topLevel(js); | 556 JSONObject topLevel(js); |
505 topLevel.AddProperty("type", "_Timeline"); | 557 topLevel.AddProperty("type", "_Timeline"); |
506 { | 558 { |
507 JSONArray events(&topLevel, "traceEvents"); | 559 JSONArray events(&topLevel, "traceEvents"); |
(...skipping 14 matching lines...) Expand all Loading... |
522 // no-op. | 574 // no-op. |
523 } | 575 } |
524 | 576 |
525 | 577 |
526 TimelineEvent* TimelineEventEndlessRecorder::StartEvent(const Object& object) { | 578 TimelineEvent* TimelineEventEndlessRecorder::StartEvent(const Object& object) { |
527 return StartEvent(); | 579 return StartEvent(); |
528 } | 580 } |
529 | 581 |
530 | 582 |
531 TimelineEvent* TimelineEventEndlessRecorder::StartEvent() { | 583 TimelineEvent* TimelineEventEndlessRecorder::StartEvent() { |
532 // Grab the thread's timeline event block. | 584 return ThreadBlockStartEvent(); |
533 Thread* thread = Thread::Current(); | |
534 TimelineEventBlock* thread_block = thread->timeline_block(); | |
535 if (thread_block == NULL) { | |
536 return NULL; | |
537 } | |
538 ASSERT(thread_block != NULL); | |
539 if (thread_block->IsFull()) { | |
540 // If it is full, request a new block. | |
541 thread_block = GetNewBlock(); | |
542 thread->set_timeline_block(thread_block); | |
543 } | |
544 ASSERT(!thread_block->IsFull()); | |
545 return thread_block->StartEvent(); | |
546 } | 585 } |
547 | 586 |
548 | 587 |
549 void TimelineEventEndlessRecorder::CompleteEvent(TimelineEvent* event) { | 588 void TimelineEventEndlessRecorder::CompleteEvent(TimelineEvent* event) { |
550 // no-op. | 589 // no-op. |
551 } | 590 } |
552 | 591 |
553 | 592 |
554 TimelineEventBlock* TimelineEventEndlessRecorder::GetNewBlockLocked() { | 593 TimelineEventBlock* TimelineEventEndlessRecorder::GetNewBlockLocked() { |
555 TimelineEventBlock* block = new TimelineEventBlock(); | 594 TimelineEventBlock* block = new TimelineEventBlock(block_index_++); |
556 block->set_next(head_); | 595 block->set_next(head_); |
557 head_ = block; | 596 head_ = block; |
558 return head_; | 597 return head_; |
559 } | 598 } |
560 | 599 |
561 | 600 |
562 void TimelineEventEndlessRecorder::PrintJSONEvents(JSONArray* events) const { | 601 void TimelineEventEndlessRecorder::PrintJSONEvents(JSONArray* events) const { |
563 TimelineEventBlock* current = head_; | 602 TimelineEventBlock* current = head_; |
564 while (current != NULL) { | 603 while (current != NULL) { |
565 intptr_t length = current->length(); | 604 intptr_t length = current->length(); |
566 for (intptr_t i = 0; i < length; i++) { | 605 for (intptr_t i = 0; i < length; i++) { |
567 TimelineEvent* event = current->At(i); | 606 TimelineEvent* event = current->At(i); |
568 if (!event->IsValid()) { | 607 if (!event->IsValid()) { |
569 continue; | 608 continue; |
570 } | 609 } |
571 events->AddValue(event); | 610 events->AddValue(event); |
572 } | 611 } |
573 current = current->next(); | 612 current = current->next(); |
574 } | 613 } |
575 } | 614 } |
576 | 615 |
577 | 616 |
578 TimelineEventBlock::TimelineEventBlock() | 617 TimelineEventBlock::TimelineEventBlock(intptr_t block_index) |
579 : next_(NULL), | 618 : next_(NULL), |
580 length_(0) { | 619 length_(0), |
| 620 block_index_(block_index) { |
581 } | 621 } |
582 | 622 |
583 | 623 |
| 624 TimelineEventBlock::~TimelineEventBlock() { |
| 625 Reset(); |
| 626 } |
| 627 |
| 628 |
584 TimelineEvent* TimelineEventBlock::StartEvent() { | 629 TimelineEvent* TimelineEventBlock::StartEvent() { |
585 ASSERT(!IsFull()); | 630 ASSERT(!IsFull()); |
586 return &events_[length_++]; | 631 return &events_[length_++]; |
587 } | 632 } |
588 | 633 |
589 | 634 |
590 ThreadId TimelineEventBlock::thread() const { | 635 ThreadId TimelineEventBlock::thread() const { |
591 ASSERT(length_ > 0); | 636 ASSERT(length_ > 0); |
592 return events_[0].thread(); | 637 return events_[0].thread(); |
593 } | 638 } |
(...skipping 24 matching lines...) Expand all Loading... |
618 if (last_time > At(i)->TimeOrigin()) { | 663 if (last_time > At(i)->TimeOrigin()) { |
619 return false; | 664 return false; |
620 } | 665 } |
621 last_time = At(i)->TimeOrigin(); | 666 last_time = At(i)->TimeOrigin(); |
622 } | 667 } |
623 | 668 |
624 return true; | 669 return true; |
625 } | 670 } |
626 | 671 |
627 | 672 |
| 673 void TimelineEventBlock::Reset() { |
| 674 for (intptr_t i = 0; i < kBlockSize; i++) { |
| 675 // Clear any extra data. |
| 676 events_[i].Reset(); |
| 677 } |
| 678 length_ = 0; |
| 679 } |
| 680 |
| 681 |
628 TimelineEventBlockIterator::TimelineEventBlockIterator( | 682 TimelineEventBlockIterator::TimelineEventBlockIterator( |
629 TimelineEventEndlessRecorder* recorder) | 683 TimelineEventEndlessRecorder* recorder) |
630 : current_(NULL), | 684 : current_(NULL), |
631 recorder_(recorder) { | 685 recorder_(recorder) { |
632 if (recorder_ == NULL) { | 686 if (recorder_ == NULL) { |
633 return; | 687 return; |
634 } | 688 } |
635 recorder->lock_.Lock(); | 689 recorder->lock_.Lock(); |
636 } | 690 } |
637 | 691 |
(...skipping 17 matching lines...) Expand all Loading... |
655 } | 709 } |
656 if (current_ == NULL) { | 710 if (current_ == NULL) { |
657 current_ = recorder_->head_; | 711 current_ = recorder_->head_; |
658 } else { | 712 } else { |
659 current_ = current_->next(); | 713 current_ = current_->next(); |
660 } | 714 } |
661 return current_ != NULL; | 715 return current_ != NULL; |
662 } | 716 } |
663 | 717 |
664 } // namespace dart | 718 } // namespace dart |
OLD | NEW |