Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(238)

Side by Side Diff: runtime/vm/timeline.cc

Issue 1395803002: Stop holding onto TimelineEvents (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: Created 5 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « runtime/vm/timeline.h ('k') | runtime/vm/timeline_test.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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"
(...skipping 260 matching lines...) Expand 10 before | Expand all | Expand 10 after
271 int64_t micros) { 271 int64_t micros) {
272 Init(kEnd, label); 272 Init(kEnd, label);
273 timestamp0_ = micros; 273 timestamp0_ = micros;
274 } 274 }
275 275
276 276
277 void TimelineEvent::SetNumArguments(intptr_t length) { 277 void TimelineEvent::SetNumArguments(intptr_t length) {
278 // Cannot call this twice. 278 // Cannot call this twice.
279 ASSERT(arguments_ == NULL); 279 ASSERT(arguments_ == NULL);
280 ASSERT(arguments_length_ == 0); 280 ASSERT(arguments_length_ == 0);
281 if (length == 0) {
282 return;
283 }
281 arguments_length_ = length; 284 arguments_length_ = length;
282 arguments_ = reinterpret_cast<TimelineEventArgument*>( 285 arguments_ = reinterpret_cast<TimelineEventArgument*>(
283 calloc(sizeof(TimelineEventArgument), length)); 286 calloc(sizeof(TimelineEventArgument), length));
284 } 287 }
285 288
286 289
287 void TimelineEvent::SetArgument(intptr_t i, const char* name, char* argument) { 290 void TimelineEvent::SetArgument(intptr_t i, const char* name, char* argument) {
288 ASSERT(i >= 0); 291 ASSERT(i >= 0);
289 ASSERT(i < arguments_length_); 292 ASSERT(i < arguments_length_);
290 arguments_[i].name = name; 293 arguments_[i].name = name;
(...skipping 20 matching lines...) Expand all
311 } 314 }
312 315
313 316
314 void TimelineEvent::CopyArgument(intptr_t i, 317 void TimelineEvent::CopyArgument(intptr_t i,
315 const char* name, 318 const char* name,
316 const char* argument) { 319 const char* argument) {
317 SetArgument(i, name, strdup(argument)); 320 SetArgument(i, name, strdup(argument));
318 } 321 }
319 322
320 323
324 void TimelineEvent::StealArguments(intptr_t arguments_length,
325 TimelineEventArgument* arguments) {
326 if (arguments_length == 0) {
327 return;
328 }
329 SetNumArguments(arguments_length);
330 for (intptr_t i = 0; i < arguments_length; i++) {
331 SetArgument(i, arguments[i].name, arguments[i].value);
332 // Steal.
333 arguments[i].name = NULL;
334 arguments[i].value = NULL;
335 }
turnidge 2015/10/08 17:59:19 Perhaps you could steal the whole arguments array
Cutch 2015/10/08 20:08:10 Done.
336 }
337
338
321 void TimelineEvent::Complete() { 339 void TimelineEvent::Complete() {
322 TimelineEventRecorder* recorder = Timeline::recorder(); 340 TimelineEventRecorder* recorder = Timeline::recorder();
323 if (recorder != NULL) { 341 if (recorder != NULL) {
324 recorder->CompleteEvent(this); 342 recorder->CompleteEvent(this);
325 } 343 }
326 } 344 }
327 345
328 346
329 void TimelineEvent::FreeArguments() { 347 void TimelineEvent::FreeArguments() {
330 if (arguments_ == NULL) { 348 if (arguments_ == NULL) {
(...skipping 129 matching lines...) Expand 10 before | Expand all | Expand 10 after
460 } 478 }
461 ASSERT(name_ != NULL); 479 ASSERT(name_ != NULL);
462 TimelineEvent* event = recorder->StartEvent(); 480 TimelineEvent* event = recorder->StartEvent();
463 if (event != NULL) { 481 if (event != NULL) {
464 event->StreamInit(this); 482 event->StreamInit(this);
465 } 483 }
466 return event; 484 return event;
467 } 485 }
468 486
469 487
488 void TimelineDurationScope::Init() {
489 ASSERT(enabled_ == false);
490 ASSERT(label_ != NULL);
491 ASSERT(stream_ != NULL);
492 if (!stream_->Enabled()) {
493 // Stream is not enabled, do nothing.
494 return;
495 }
496 TimelineEvent* event = stream_->StartEvent();
497 if (event == NULL) {
498 return;
499 }
500 enabled_ = true;
501 event->Begin(label_);
502 event->Complete();
503 }
504
505 void TimelineDurationScope::FreeArguments() {
506 if (arguments_ == NULL) {
507 return;
508 }
509 for (intptr_t i = 0; i < arguments_length_; i++) {
510 free(arguments_[i].value);
511 }
512 free(arguments_);
513 arguments_ = NULL;
514 arguments_length_ = 0;
515 }
516
517
518 TimelineDurationScope::~TimelineDurationScope() {
519 if (!enabled_) {
520 FreeArguments();
521 return;
522 }
523 TimelineEvent* event = stream_->StartEvent();
524 if (event == NULL) {
525 FreeArguments();
526 return;
527 }
528 event->End(label_);
529 event->StealArguments(arguments_length_, arguments_);
turnidge 2015/10/08 17:59:19 If StealArguments steals the whole array, follow t
Cutch 2015/10/08 20:08:10 Done.
530 event->Complete();
531 FreeArguments();
532 }
533
534
535 void TimelineDurationScope::SetNumArguments(intptr_t length) {
536 if (!enabled()) {
537 return;
538 }
539 ASSERT(arguments_ == NULL);
540 ASSERT(arguments_length_ == 0);
541 arguments_length_ = length;
turnidge 2015/10/08 17:59:19 You could choose to guard the allocation of argume
Cutch 2015/10/08 20:08:10 Done.
542 arguments_ = reinterpret_cast<TimelineEventArgument*>(
543 calloc(sizeof(TimelineEventArgument), length));
544 }
545
546
547 // |name| must be a compile time constant. Takes ownership of |argumentp|.
548 void TimelineDurationScope::SetArgument(intptr_t i,
549 const char* name,
550 char* argument) {
551 if (!enabled()) {
552 return;
553 }
554 ASSERT(i >= 0);
555 ASSERT(i < arguments_length_);
556 arguments_[i].name = name;
557 arguments_[i].value = argument;
558 }
559
560
561 // |name| must be a compile time constant. Copies |argument|.
562 void TimelineDurationScope::CopyArgument(intptr_t i,
563 const char* name,
564 const char* argument) {
565 if (!enabled()) {
566 return;
567 }
568 SetArgument(i, name, strdup(argument));
569 }
570
571
470 void TimelineDurationScope::FormatArgument(intptr_t i, 572 void TimelineDurationScope::FormatArgument(intptr_t i,
471 const char* name, 573 const char* name,
472 const char* fmt, ...) { 574 const char* fmt, ...) {
473 if (event_ == NULL) { 575 if (!enabled()) {
474 return; 576 return;
475 } 577 }
476 va_list args; 578 va_list args;
477 va_start(args, fmt); 579 va_start(args, fmt);
478 intptr_t len = OS::VSNPrint(NULL, 0, fmt, args); 580 intptr_t len = OS::VSNPrint(NULL, 0, fmt, args);
479 va_end(args); 581 va_end(args);
480 582
481 char* buffer = reinterpret_cast<char*>(malloc(len + 1)); 583 char* buffer = reinterpret_cast<char*>(malloc(len + 1));
482 va_list args2; 584 va_list args2;
483 va_start(args2, fmt); 585 va_start(args2, fmt);
484 OS::VSNPrint(buffer, (len + 1), fmt, args2); 586 OS::VSNPrint(buffer, (len + 1), fmt, args2);
485 va_end(args2); 587 va_end(args2);
486 588
487 event_->SetArgument(i, name, buffer); 589 SetArgument(i, name, buffer);
488 } 590 }
489 591
490 592
491 TimelineEventFilter::TimelineEventFilter() { 593 TimelineEventFilter::TimelineEventFilter() {
492 } 594 }
493 595
494 596
495 TimelineEventFilter::~TimelineEventFilter() { 597 TimelineEventFilter::~TimelineEventFilter() {
496 } 598 }
497 599
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after
538 640
539 641
540 void TimelineEventRecorder::PrintJSONMeta(JSONArray* events) const { 642 void TimelineEventRecorder::PrintJSONMeta(JSONArray* events) const {
541 } 643 }
542 644
543 645
544 TimelineEvent* TimelineEventRecorder::ThreadBlockStartEvent() { 646 TimelineEvent* TimelineEventRecorder::ThreadBlockStartEvent() {
545 // Grab the current thread. 647 // Grab the current thread.
546 Thread* thread = Thread::Current(); 648 Thread* thread = Thread::Current();
547 ASSERT(thread != NULL); 649 ASSERT(thread != NULL);
548 // We are accessing the thread's timeline block- so take the lock. 650 ASSERT(thread->isolate() != NULL);
549 MutexLocker ml(thread->timeline_block_lock()); 651 Mutex* thread_block_lock = thread->timeline_block_lock();
550 652 ASSERT(thread_block_lock != NULL);
551 if (thread->isolate() == NULL) { 653 // We are accessing the thread's timeline block- so take the lock here.
552 // Non-isolate thread case. This should be infrequent. 654 // This lock will be held until the call to |CompleteEvent| is made.
553 return GlobalBlockStartEvent(); 655 thread_block_lock->Lock();
554 }
555 656
556 TimelineEventBlock* thread_block = thread->timeline_block(); 657 TimelineEventBlock* thread_block = thread->timeline_block();
557 658
558 if ((thread_block != NULL) && thread_block->IsFull()) { 659 if ((thread_block != NULL) && thread_block->IsFull()) {
559 MutexLocker ml(&lock_); 660 MutexLocker ml(&lock_);
560 // Thread has a block and it is full: 661 // Thread has a block and it is full:
561 // 1) Mark it as finished. 662 // 1) Mark it as finished.
562 thread_block->Finish(); 663 thread_block->Finish();
563 // 2) Allocate a new block. 664 // 2) Allocate a new block.
564 thread_block = GetNewBlockLocked(thread->isolate()); 665 thread_block = GetNewBlockLocked(thread->isolate());
565 thread->set_timeline_block(thread_block); 666 thread->set_timeline_block(thread_block);
566 } else if (thread_block == NULL) { 667 } else if (thread_block == NULL) {
567 MutexLocker ml(&lock_); 668 MutexLocker ml(&lock_);
568 // Thread has no block. Attempt to allocate one. 669 // Thread has no block. Attempt to allocate one.
569 thread_block = GetNewBlockLocked(thread->isolate()); 670 thread_block = GetNewBlockLocked(thread->isolate());
570 thread->set_timeline_block(thread_block); 671 thread->set_timeline_block(thread_block);
571 } 672 }
572 if (thread_block != NULL) { 673 if (thread_block != NULL) {
674 // NOTE: We are exiting this function with the thread's block lock held.
573 ASSERT(!thread_block->IsFull()); 675 ASSERT(!thread_block->IsFull());
574 return thread_block->StartEvent(); 676 return thread_block->StartEvent();
575 } 677 }
678 // Drop lock here as no event is being handed out.
679 thread_block_lock->Unlock();
576 return NULL; 680 return NULL;
577 } 681 }
578 682
579 683
580
581 TimelineEvent* TimelineEventRecorder::GlobalBlockStartEvent() { 684 TimelineEvent* TimelineEventRecorder::GlobalBlockStartEvent() {
582 MutexLocker ml(&lock_); 685 // Take recorder lock. This lock will be held until the call to
686 // |CompleteEvent| is made.
687 lock_.Lock();
583 if (FLAG_trace_timeline) { 688 if (FLAG_trace_timeline) {
584 OS::Print("GlobalBlockStartEvent in block %p for thread %" Px "\n", 689 OS::Print("GlobalBlockStartEvent in block %p for thread %" Px "\n",
585 global_block_, OSThread::CurrentCurrentThreadIdAsIntPtr()); 690 global_block_, OSThread::CurrentCurrentThreadIdAsIntPtr());
586 } 691 }
587 if ((global_block_ != NULL) && global_block_->IsFull()) { 692 if ((global_block_ != NULL) && global_block_->IsFull()) {
588 // Global block is full. 693 // Global block is full.
589 global_block_->Finish(); 694 global_block_->Finish();
590 global_block_ = NULL; 695 global_block_ = NULL;
591 } 696 }
592 if (global_block_ == NULL) { 697 if (global_block_ == NULL) {
593 // Allocate a new block. 698 // Allocate a new block.
594 global_block_ = GetNewBlockLocked(NULL); 699 global_block_ = GetNewBlockLocked(NULL);
595 ASSERT(global_block_ != NULL); 700 ASSERT(global_block_ != NULL);
596 } 701 }
597 if (global_block_ != NULL) { 702 if (global_block_ != NULL) {
703 // NOTE: We are exiting this function with the recorder's lock held.
598 ASSERT(!global_block_->IsFull()); 704 ASSERT(!global_block_->IsFull());
599 return global_block_->StartEvent(); 705 return global_block_->StartEvent();
600 } 706 }
707 // Drop lock here as no event is being handed out.
708 lock_.Unlock();
601 return NULL; 709 return NULL;
602 } 710 }
603 711
604 712
713 void TimelineEventRecorder::ThreadBlockCompleteEvent(TimelineEvent* event) {
714 // Grab the current thread.
715 Thread* thread = Thread::Current();
716 ASSERT(thread != NULL);
717 ASSERT(thread->isolate() != NULL);
718 // This event came from the isolate's thread local block. Unlock the
719 // thread's block lock.
720 Mutex* thread_block_lock = thread->timeline_block_lock();
721 ASSERT(thread_block_lock != NULL);
722 thread_block_lock->Unlock();
723 }
724
725
726 void TimelineEventRecorder::GlobalBlockCompleteEvent(TimelineEvent* event) {
727 // This event came from the global block, unlock the recorder's lock now
728 // that the event is filled.
729 lock_.Unlock();
730 }
731
732
605 // Trims the ']' character. 733 // Trims the ']' character.
606 static void TrimOutput(char* output, 734 static void TrimOutput(char* output,
607 intptr_t* output_length) { 735 intptr_t* output_length) {
608 ASSERT(output != NULL); 736 ASSERT(output != NULL);
609 ASSERT(output_length != NULL); 737 ASSERT(output_length != NULL);
610 ASSERT(*output_length >= 2); 738 ASSERT(*output_length >= 2);
611 // We expect the first character to be the opening of an array. 739 // We expect the first character to be the opening of an array.
612 ASSERT(output[0] == '['); 740 ASSERT(output[0] == '[');
613 // We expect the last character to be the closing of an array. 741 // We expect the last character to be the closing of an array.
614 ASSERT(output[*output_length - 1] == ']'); 742 ASSERT(output[*output_length - 1] == ']');
(...skipping 247 matching lines...) Expand 10 before | Expand all | Expand 10 after
862 if (block->LowerTimeBound() < earliest_time) { 990 if (block->LowerTimeBound() < earliest_time) {
863 earliest_time = block->LowerTimeBound(); 991 earliest_time = block->LowerTimeBound();
864 earliest_index = block_idx; 992 earliest_index = block_idx;
865 } 993 }
866 } 994 }
867 return earliest_index; 995 return earliest_index;
868 } 996 }
869 997
870 998
871 TimelineEvent* TimelineEventRingRecorder::StartEvent() { 999 TimelineEvent* TimelineEventRingRecorder::StartEvent() {
1000 // Grab the current thread.
1001 Thread* thread = Thread::Current();
1002 ASSERT(thread != NULL);
1003 if (thread->isolate() == NULL) {
1004 // Non-isolate thread case. This should be infrequent.
1005 return GlobalBlockStartEvent();
1006 }
872 return ThreadBlockStartEvent(); 1007 return ThreadBlockStartEvent();
873 } 1008 }
874 1009
875 1010
876 void TimelineEventRingRecorder::CompleteEvent(TimelineEvent* event) { 1011 void TimelineEventRingRecorder::CompleteEvent(TimelineEvent* event) {
877 // no-op. 1012 if (event == NULL) {
1013 return;
1014 }
1015 Thread* thread = Thread::Current();
1016 ASSERT(thread != NULL);
1017 if (thread->isolate() == NULL) {
1018 GlobalBlockCompleteEvent(event);
1019 } else {
1020 ThreadBlockCompleteEvent(event);
1021 }
878 } 1022 }
879 1023
880 1024
881 TimelineEventStreamingRecorder::TimelineEventStreamingRecorder() { 1025 TimelineEventStreamingRecorder::TimelineEventStreamingRecorder() {
882 } 1026 }
883 1027
884 1028
885 TimelineEventStreamingRecorder::~TimelineEventStreamingRecorder() { 1029 TimelineEventStreamingRecorder::~TimelineEventStreamingRecorder() {
886 } 1030 }
887 1031
(...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after
989 dart_events_[dart_events_cursor_++] = dart_event; 1133 dart_events_[dart_events_cursor_++] = dart_event;
990 } 1134 }
991 1135
992 1136
993 TimelineEventBlock* TimelineEventEndlessRecorder::GetHeadBlockLocked() { 1137 TimelineEventBlock* TimelineEventEndlessRecorder::GetHeadBlockLocked() {
994 return head_; 1138 return head_;
995 } 1139 }
996 1140
997 1141
998 TimelineEvent* TimelineEventEndlessRecorder::StartEvent() { 1142 TimelineEvent* TimelineEventEndlessRecorder::StartEvent() {
1143 // Grab the current thread.
1144 Thread* thread = Thread::Current();
1145 ASSERT(thread != NULL);
1146 if (thread->isolate() == NULL) {
1147 // Non-isolate thread case. This should be infrequent.
1148 return GlobalBlockStartEvent();
1149 }
999 return ThreadBlockStartEvent(); 1150 return ThreadBlockStartEvent();
1000 } 1151 }
1001 1152
1002 1153
1003 void TimelineEventEndlessRecorder::CompleteEvent(TimelineEvent* event) { 1154 void TimelineEventEndlessRecorder::CompleteEvent(TimelineEvent* event) {
1004 // no-op. 1155 if (event == NULL) {
1156 return;
1157 }
1158 Thread* thread = Thread::Current();
1159 ASSERT(thread != NULL);
1160 if (thread->isolate() == NULL) {
1161 GlobalBlockCompleteEvent(event);
1162 } else {
1163 ThreadBlockCompleteEvent(event);
1164 }
1005 } 1165 }
1006 1166
1007 1167
1008 TimelineEventBlock* TimelineEventEndlessRecorder::GetNewBlockLocked( 1168 TimelineEventBlock* TimelineEventEndlessRecorder::GetNewBlockLocked(
1009 Isolate* isolate) { 1169 Isolate* isolate) {
1010 TimelineEventBlock* block = new TimelineEventBlock(block_index_++); 1170 TimelineEventBlock* block = new TimelineEventBlock(block_index_++);
1011 block->set_next(head_); 1171 block->set_next(head_);
1012 block->Open(isolate); 1172 block->Open(isolate);
1013 head_ = block; 1173 head_ = block;
1014 if (FLAG_trace_timeline) { 1174 if (FLAG_trace_timeline) {
(...skipping 258 matching lines...) Expand 10 before | Expand all | Expand 10 after
1273 // If an isolate was specified, skip events from other isolates. 1433 // If an isolate was specified, skip events from other isolates.
1274 continue; 1434 continue;
1275 } 1435 }
1276 ASSERT(event->event_as_json() != NULL); 1436 ASSERT(event->event_as_json() != NULL);
1277 result = zone->ConcatStrings(result, event->event_as_json()); 1437 result = zone->ConcatStrings(result, event->event_as_json());
1278 } 1438 }
1279 return result; 1439 return result;
1280 } 1440 }
1281 1441
1282 } // namespace dart 1442 } // namespace dart
OLDNEW
« no previous file with comments | « runtime/vm/timeline.h ('k') | runtime/vm/timeline_test.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698