Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 #include <cstdlib> | 5 #include <cstdlib> |
| 6 | 6 |
| 7 #include "vm/atomic.h" | 7 #include "vm/atomic.h" |
| 8 #include "vm/isolate.h" | 8 #include "vm/isolate.h" |
| 9 #include "vm/json_stream.h" | 9 #include "vm/json_stream.h" |
| 10 #include "vm/lockers.h" | 10 #include "vm/lockers.h" |
| (...skipping 260 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 |
| OLD | NEW |