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

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

Issue 864173008: Split profiler.cc into profiler.cc and profiler_service.cc (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 5 years, 10 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 | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2013, 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 "platform/address_sanitizer.h" 5 #include "platform/address_sanitizer.h"
6 #include "platform/memory_sanitizer.h" 6 #include "platform/memory_sanitizer.h"
7 #include "platform/utils.h" 7 #include "platform/utils.h"
8 8
9 #include "vm/allocation.h" 9 #include "vm/allocation.h"
10 #include "vm/atomic.h" 10 #include "vm/atomic.h"
(...skipping 155 matching lines...) Expand 10 before | Expand all | Expand 10 after
166 return; 166 return;
167 } 167 }
168 if (!FLAG_profile) { 168 if (!FLAG_profile) {
169 return; 169 return;
170 } 170 }
171 ASSERT(initialized_); 171 ASSERT(initialized_);
172 ThreadInterrupter::Unregister(); 172 ThreadInterrupter::Unregister();
173 } 173 }
174 174
175 175
176 class ScopeStopwatch : public ValueObject {
177 public:
178 explicit ScopeStopwatch(const char* name) : name_(name) {
179 start_ = FLAG_trace_profiler ? OS::GetCurrentTimeMillis() : 0;
180 }
181
182 int64_t GetElapsed() const {
183 int64_t end = OS::GetCurrentTimeMillis();
184 ASSERT(end >= start_);
185 return end - start_;
186 }
187
188 ~ScopeStopwatch() {
189 if (FLAG_trace_profiler) {
190 int64_t elapsed = GetElapsed();
191 OS::Print("%s took %" Pd64 " millis.\n", name_, elapsed);
192 }
193 }
194
195 private:
196 const char* name_;
197 int64_t start_;
198 };
199
200
201 struct AddressEntry {
202 uword pc;
203 intptr_t exclusive_ticks;
204 intptr_t inclusive_ticks;
205
206 void tick(bool exclusive) {
207 if (exclusive) {
208 exclusive_ticks++;
209 } else {
210 inclusive_ticks++;
211 }
212 }
213 };
214
215
216 struct CallEntry {
217 intptr_t code_table_index;
218 intptr_t count;
219 };
220
221
222 typedef bool (*RegionCompare)(uword pc, uword region_start, uword region_end);
223
224
225 class CodeRegionTrieNode : public ZoneAllocated {
226 public:
227 explicit CodeRegionTrieNode(intptr_t code_region_index)
228 : code_region_index_(code_region_index),
229 count_(0),
230 children_(new ZoneGrowableArray<CodeRegionTrieNode*>()) {
231 }
232
233 void Tick() {
234 ASSERT(code_region_index_ >= 0);
235 count_++;
236 }
237
238 intptr_t count() const {
239 ASSERT(code_region_index_ >= 0);
240 return count_;
241 }
242
243 intptr_t code_region_index() const {
244 return code_region_index_;
245 }
246
247 ZoneGrowableArray<CodeRegionTrieNode*>& children() const {
248 return *children_;
249 }
250
251 CodeRegionTrieNode* GetChild(intptr_t child_code_region_index) {
252 const intptr_t length = children_->length();
253 intptr_t i = 0;
254 while (i < length) {
255 CodeRegionTrieNode* child = (*children_)[i];
256 if (child->code_region_index() == child_code_region_index) {
257 return child;
258 }
259 if (child->code_region_index() > child_code_region_index) {
260 break;
261 }
262 i++;
263 }
264 // Add new CodeRegion, sorted by CodeRegionTable index.
265 CodeRegionTrieNode* child = new CodeRegionTrieNode(child_code_region_index);
266 if (i < length) {
267 // Insert at i.
268 children_->InsertAt(i, child);
269 } else {
270 // Add to end.
271 children_->Add(child);
272 }
273 return child;
274 }
275
276 // Sort this's children and (recursively) all descendants by count.
277 // This should only be called after the trie is completely built.
278 void SortByCount() {
279 children_->Sort(CodeRegionTrieNodeCompare);
280 ZoneGrowableArray<CodeRegionTrieNode*>& kids = children();
281 intptr_t child_count = kids.length();
282 // Recurse.
283 for (intptr_t i = 0; i < child_count; i++) {
284 kids[i]->SortByCount();
285 }
286 }
287
288 void PrintToJSONArray(JSONArray* array) const {
289 ASSERT(array != NULL);
290 // Write CodeRegion index.
291 array->AddValue(code_region_index_);
292 // Write count.
293 array->AddValue(count_);
294 // Write number of children.
295 ZoneGrowableArray<CodeRegionTrieNode*>& kids = children();
296 intptr_t child_count = kids.length();
297 array->AddValue(child_count);
298 // Recurse.
299 for (intptr_t i = 0; i < child_count; i++) {
300 kids[i]->PrintToJSONArray(array);
301 }
302 }
303
304 private:
305 static int CodeRegionTrieNodeCompare(CodeRegionTrieNode* const* a,
306 CodeRegionTrieNode* const* b) {
307 ASSERT(a != NULL);
308 ASSERT(b != NULL);
309 return (*b)->count() - (*a)->count();
310 }
311
312 const intptr_t code_region_index_;
313 intptr_t count_;
314 ZoneGrowableArray<CodeRegionTrieNode*>* children_;
315 };
316
317
318 // A contiguous address region that holds code. Each CodeRegion has a "kind"
319 // which describes the type of code contained inside the region. Each
320 // region covers the following interval: [start, end).
321 class CodeRegion : public ZoneAllocated {
322 public:
323 enum Kind {
324 kDartCode, // Live Dart code.
325 kCollectedCode, // Dead Dart code.
326 kNativeCode, // Native code.
327 kReusedCode, // Dead Dart code that has been reused by new kDartCode.
328 kTagCode, // A special kind of code representing a tag.
329 };
330
331 CodeRegion(Kind kind, uword start, uword end, int64_t timestamp)
332 : kind_(kind),
333 start_(start),
334 end_(end),
335 inclusive_ticks_(0),
336 exclusive_ticks_(0),
337 inclusive_tick_serial_(0),
338 name_(NULL),
339 compile_timestamp_(timestamp),
340 creation_serial_(0),
341 address_table_(new ZoneGrowableArray<AddressEntry>()),
342 callers_table_(new ZoneGrowableArray<CallEntry>()),
343 callees_table_(new ZoneGrowableArray<CallEntry>()) {
344 ASSERT(start_ < end_);
345 }
346
347
348 uword start() const { return start_; }
349 void set_start(uword start) {
350 start_ = start;
351 }
352
353 uword end() const { return end_; }
354 void set_end(uword end) {
355 end_ = end;
356 }
357
358 void AdjustExtent(uword start, uword end) {
359 if (start < start_) {
360 start_ = start;
361 }
362 if (end > end_) {
363 end_ = end;
364 }
365 ASSERT(start_ < end_);
366 }
367
368 bool contains(uword pc) const {
369 return (pc >= start_) && (pc < end_);
370 }
371
372 bool overlaps(const CodeRegion* other) const {
373 ASSERT(other != NULL);
374 return other->contains(start_) ||
375 other->contains(end_ - 1) ||
376 contains(other->start()) ||
377 contains(other->end() - 1);
378 }
379
380 intptr_t creation_serial() const { return creation_serial_; }
381 void set_creation_serial(intptr_t serial) {
382 creation_serial_ = serial;
383 }
384 int64_t compile_timestamp() const { return compile_timestamp_; }
385 void set_compile_timestamp(int64_t timestamp) {
386 compile_timestamp_ = timestamp;
387 }
388
389 intptr_t inclusive_ticks() const { return inclusive_ticks_; }
390 void set_inclusive_ticks(intptr_t inclusive_ticks) {
391 inclusive_ticks_ = inclusive_ticks;
392 }
393
394 intptr_t exclusive_ticks() const { return exclusive_ticks_; }
395 void set_exclusive_ticks(intptr_t exclusive_ticks) {
396 exclusive_ticks_ = exclusive_ticks;
397 }
398
399 const char* name() const { return name_; }
400 void SetName(const char* name) {
401 if (name == NULL) {
402 name_ = NULL;
403 }
404 intptr_t len = strlen(name);
405 name_ = Isolate::Current()->current_zone()->Alloc<const char>(len + 1);
406 strncpy(const_cast<char*>(name_), name, len);
407 const_cast<char*>(name_)[len] = '\0';
408 }
409
410 Kind kind() const { return kind_; }
411
412 static const char* KindToCString(Kind kind) {
413 switch (kind) {
414 case kDartCode:
415 return "Dart";
416 case kCollectedCode:
417 return "Collected";
418 case kNativeCode:
419 return "Native";
420 case kReusedCode:
421 return "Overwritten";
422 case kTagCode:
423 return "Tag";
424 }
425 UNREACHABLE();
426 return NULL;
427 }
428
429 void DebugPrint() const {
430 OS::Print("%s [%" Px ", %" Px ") %" Pd " %" Pd64 "\n",
431 KindToCString(kind_),
432 start(),
433 end(),
434 creation_serial_,
435 compile_timestamp_);
436 }
437
438 void Tick(uword pc, bool exclusive, intptr_t serial) {
439 // Assert that exclusive ticks are never passed a valid serial number.
440 ASSERT((exclusive && (serial == -1)) || (!exclusive && (serial != -1)));
441 if (!exclusive && (inclusive_tick_serial_ == serial)) {
442 // We've already given this code object an inclusive tick for this sample.
443 return;
444 }
445 // Tick the code object.
446 if (exclusive) {
447 exclusive_ticks_++;
448 } else {
449 inclusive_ticks_++;
450 // Mark the last serial we ticked the inclusive count.
451 inclusive_tick_serial_ = serial;
452 }
453 TickAddress(pc, exclusive);
454 }
455
456 void AddCaller(intptr_t index, intptr_t count) {
457 AddCallEntry(callers_table_, index, count);
458 }
459
460 void AddCallee(intptr_t index, intptr_t count) {
461 AddCallEntry(callees_table_, index, count);
462 }
463
464 void PrintNativeCode(JSONObject* profile_code_obj) {
465 ASSERT(kind() == kNativeCode);
466 JSONObject obj(profile_code_obj, "code");
467 obj.AddProperty("type", "@Code");
468 obj.AddProperty("kind", "Native");
469 obj.AddProperty("name", name());
470 obj.AddPropertyF("start", "%" Px "", start());
471 obj.AddPropertyF("end", "%" Px "", end());
472 obj.AddPropertyF("id", "code/native-%" Px "", start());
473 {
474 // Generate a fake function entry.
475 JSONObject func(&obj, "function");
476 func.AddProperty("type", "@Function");
477 func.AddPropertyF("id", "functions/native-%" Px "", start());
478 func.AddProperty("name", name());
479 func.AddProperty("kind", "Native");
480 }
481 }
482
483 void PrintCollectedCode(JSONObject* profile_code_obj) {
484 ASSERT(kind() == kCollectedCode);
485 JSONObject obj(profile_code_obj, "code");
486 obj.AddProperty("type", "@Code");
487 obj.AddProperty("kind", "Collected");
488 obj.AddProperty("name", name());
489 obj.AddPropertyF("start", "%" Px "", start());
490 obj.AddPropertyF("end", "%" Px "", end());
491 obj.AddPropertyF("id", "code/collected-%" Px "", start());
492 {
493 // Generate a fake function entry.
494 JSONObject func(&obj, "function");
495 func.AddProperty("type", "@Function");
496 obj.AddPropertyF("id", "functions/collected-%" Px "", start());
497 func.AddProperty("name", name());
498 func.AddProperty("kind", "Collected");
499 }
500 }
501
502 void PrintOverwrittenCode(JSONObject* profile_code_obj) {
503 ASSERT(kind() == kReusedCode);
504 JSONObject obj(profile_code_obj, "code");
505 obj.AddProperty("type", "@Code");
506 obj.AddProperty("kind", "Reused");
507 obj.AddProperty("name", name());
508 obj.AddPropertyF("start", "%" Px "", start());
509 obj.AddPropertyF("end", "%" Px "", end());
510 obj.AddPropertyF("id", "code/reused-%" Px "", start());
511 {
512 // Generate a fake function entry.
513 JSONObject func(&obj, "function");
514 func.AddProperty("type", "@Function");
515 obj.AddPropertyF("id", "functions/reused-%" Px "", start());
516 func.AddProperty("name", name());
517 func.AddProperty("kind", "Reused");
518 }
519 }
520
521 void PrintTagCode(JSONObject* profile_code_obj) {
522 ASSERT(kind() == kTagCode);
523 JSONObject obj(profile_code_obj, "code");
524 obj.AddProperty("type", "@Code");
525 obj.AddProperty("kind", "Tag");
526 obj.AddPropertyF("id", "code/tag-%" Px "", start());
527 obj.AddProperty("name", name());
528 obj.AddPropertyF("start", "%" Px "", start());
529 obj.AddPropertyF("end", "%" Px "", end());
530 {
531 // Generate a fake function entry.
532 JSONObject func(&obj, "function");
533 func.AddProperty("type", "@Function");
534 func.AddProperty("kind", "Tag");
535 obj.AddPropertyF("id", "functions/tag-%" Px "", start());
536 func.AddProperty("name", name());
537 }
538 }
539
540 void PrintToJSONArray(Isolate* isolate, JSONArray* events, bool full) {
541 JSONObject obj(events);
542 obj.AddProperty("kind", KindToCString(kind()));
543 obj.AddPropertyF("inclusive_ticks", "%" Pd "", inclusive_ticks());
544 obj.AddPropertyF("exclusive_ticks", "%" Pd "", exclusive_ticks());
545 if (kind() == kDartCode) {
546 // Look up code in Dart heap.
547 Code& code = Code::Handle(isolate);
548 code ^= Code::LookupCode(start());
549 if (code.IsNull()) {
550 // Code is a stub in the Vm isolate.
551 code ^= Code::LookupCodeInVmIsolate(start());
552 }
553 ASSERT(!code.IsNull());
554 obj.AddProperty("code", code, !full);
555 } else if (kind() == kCollectedCode) {
556 if (name() == NULL) {
557 // Lazily set generated name.
558 GenerateAndSetSymbolName("[Collected]");
559 }
560 PrintCollectedCode(&obj);
561 } else if (kind() == kReusedCode) {
562 if (name() == NULL) {
563 // Lazily set generated name.
564 GenerateAndSetSymbolName("[Reused]");
565 }
566 PrintOverwrittenCode(&obj);
567 } else if (kind() == kTagCode) {
568 if (name() == NULL) {
569 if (UserTags::IsUserTag(start())) {
570 const char* tag_name = UserTags::TagName(start());
571 ASSERT(tag_name != NULL);
572 SetName(tag_name);
573 } else if (VMTag::IsVMTag(start()) ||
574 VMTag::IsRuntimeEntryTag(start()) ||
575 VMTag::IsNativeEntryTag(start())) {
576 const char* tag_name = VMTag::TagName(start());
577 ASSERT(tag_name != NULL);
578 SetName(tag_name);
579 } else {
580 ASSERT(start() == 0);
581 SetName("root");
582 }
583 }
584 PrintTagCode(&obj);
585 } else {
586 ASSERT(kind() == kNativeCode);
587 if (name() == NULL) {
588 // Lazily set generated name.
589 GenerateAndSetSymbolName("[Native]");
590 }
591 PrintNativeCode(&obj);
592 }
593 {
594 JSONArray ticks(&obj, "ticks");
595 for (intptr_t i = 0; i < address_table_->length(); i++) {
596 const AddressEntry& entry = (*address_table_)[i];
597 ticks.AddValueF("%" Px "", entry.pc);
598 ticks.AddValueF("%" Pd "", entry.exclusive_ticks);
599 ticks.AddValueF("%" Pd "", entry.inclusive_ticks);
600 }
601 }
602 {
603 JSONArray callers(&obj, "callers");
604 for (intptr_t i = 0; i < callers_table_->length(); i++) {
605 const CallEntry& entry = (*callers_table_)[i];
606 callers.AddValueF("%" Pd "", entry.code_table_index);
607 callers.AddValueF("%" Pd "", entry.count);
608 }
609 }
610 {
611 JSONArray callees(&obj, "callees");
612 for (intptr_t i = 0; i < callees_table_->length(); i++) {
613 const CallEntry& entry = (*callees_table_)[i];
614 callees.AddValueF("%" Pd "", entry.code_table_index);
615 callees.AddValueF("%" Pd "", entry.count);
616 }
617 }
618 }
619
620 private:
621 void TickAddress(uword pc, bool exclusive) {
622 const intptr_t length = address_table_->length();
623 intptr_t i = 0;
624 for (; i < length; i++) {
625 AddressEntry& entry = (*address_table_)[i];
626 if (entry.pc == pc) {
627 // Tick the address entry.
628 entry.tick(exclusive);
629 return;
630 }
631 if (entry.pc > pc) {
632 break;
633 }
634 }
635 // New address, add entry.
636 AddressEntry entry;
637 entry.pc = pc;
638 entry.exclusive_ticks = 0;
639 entry.inclusive_ticks = 0;
640 entry.tick(exclusive);
641 if (i < length) {
642 // Insert at i.
643 address_table_->InsertAt(i, entry);
644 } else {
645 // Add to end.
646 address_table_->Add(entry);
647 }
648 }
649
650
651 void AddCallEntry(ZoneGrowableArray<CallEntry>* table, intptr_t index,
652 intptr_t count) {
653 const intptr_t length = table->length();
654 intptr_t i = 0;
655 for (; i < length; i++) {
656 CallEntry& entry = (*table)[i];
657 if (entry.code_table_index == index) {
658 entry.count += count;
659 return;
660 }
661 if (entry.code_table_index > index) {
662 break;
663 }
664 }
665 CallEntry entry;
666 entry.code_table_index = index;
667 entry.count = count;
668 if (i < length) {
669 table->InsertAt(i, entry);
670 } else {
671 table->Add(entry);
672 }
673 }
674
675 void GenerateAndSetSymbolName(const char* prefix) {
676 const intptr_t kBuffSize = 512;
677 char buff[kBuffSize];
678 OS::SNPrint(&buff[0], kBuffSize-1, "%s [%" Px ", %" Px ")",
679 prefix, start(), end());
680 SetName(buff);
681 }
682
683 // CodeRegion kind.
684 const Kind kind_;
685 // CodeRegion start address.
686 uword start_;
687 // CodeRegion end address.
688 uword end_;
689 // Inclusive ticks.
690 intptr_t inclusive_ticks_;
691 // Exclusive ticks.
692 intptr_t exclusive_ticks_;
693 // Inclusive tick serial number, ensures that each CodeRegion is only given
694 // a single inclusive tick per sample.
695 intptr_t inclusive_tick_serial_;
696 // Name of code region.
697 const char* name_;
698 // The compilation timestamp associated with this code region.
699 int64_t compile_timestamp_;
700 // Serial number at which this CodeRegion was created.
701 intptr_t creation_serial_;
702 ZoneGrowableArray<AddressEntry>* address_table_;
703 ZoneGrowableArray<CallEntry>* callers_table_;
704 ZoneGrowableArray<CallEntry>* callees_table_;
705 DISALLOW_COPY_AND_ASSIGN(CodeRegion);
706 };
707
708
709 // A sorted table of CodeRegions. Does not allow for overlap.
710 class CodeRegionTable : public ValueObject {
711 public:
712 enum TickResult {
713 kTicked = 0, // CodeRegion found and ticked.
714 kNotFound = -1, // No CodeRegion found.
715 kNewerCode = -2, // CodeRegion found but it was compiled after sample.
716 };
717
718 CodeRegionTable() :
719 code_region_table_(new ZoneGrowableArray<CodeRegion*>(64)) {
720 }
721
722 // Ticks the CodeRegion containing pc if it is alive at timestamp.
723 TickResult Tick(uword pc, bool exclusive, intptr_t serial,
724 int64_t timestamp) {
725 intptr_t index = FindIndex(pc);
726 if (index < 0) {
727 // Not found.
728 return kNotFound;
729 }
730 ASSERT(index < code_region_table_->length());
731 CodeRegion* region = At(index);
732 if (region->compile_timestamp() > timestamp) {
733 // Compiled after tick.
734 return kNewerCode;
735 }
736 region->Tick(pc, exclusive, serial);
737 return kTicked;
738 }
739
740 // Table length.
741 intptr_t Length() const { return code_region_table_->length(); }
742
743 // Get the CodeRegion at index.
744 CodeRegion* At(intptr_t index) const {
745 return (*code_region_table_)[index];
746 }
747
748 // Find the table index to the CodeRegion containing pc.
749 // Returns < 0 if not found.
750 intptr_t FindIndex(uword pc) const {
751 intptr_t index = FindRegionIndex(pc, &CompareLowerBound);
752 const CodeRegion* code_region = NULL;
753 if (index == code_region_table_->length()) {
754 // Not present.
755 return -1;
756 }
757 code_region = At(index);
758 if (code_region->contains(pc)) {
759 // Found at index.
760 return index;
761 }
762 return -2;
763 }
764
765 // Insert code_region into the table. Returns the table index where the
766 // CodeRegion was inserted. Will merge with an overlapping CodeRegion if
767 // one is present.
768 intptr_t InsertCodeRegion(CodeRegion* code_region) {
769 const uword start = code_region->start();
770 const uword end = code_region->end();
771 const intptr_t length = code_region_table_->length();
772 if (length == 0) {
773 code_region_table_->Add(code_region);
774 return length;
775 }
776 // Determine the correct place to insert or merge code_region into table.
777 intptr_t lo = FindRegionIndex(start, &CompareLowerBound);
778 intptr_t hi = FindRegionIndex(end - 1, &CompareUpperBound);
779 // TODO(johnmccutchan): Simplify below logic.
780 if ((lo == length) && (hi == length)) {
781 lo = length - 1;
782 }
783 if (lo == length) {
784 CodeRegion* region = At(hi);
785 if (region->overlaps(code_region)) {
786 HandleOverlap(region, code_region, start, end);
787 return hi;
788 }
789 code_region_table_->Add(code_region);
790 return length;
791 } else if (hi == length) {
792 CodeRegion* region = At(lo);
793 if (region->overlaps(code_region)) {
794 HandleOverlap(region, code_region, start, end);
795 return lo;
796 }
797 code_region_table_->Add(code_region);
798 return length;
799 } else if (lo == hi) {
800 CodeRegion* region = At(lo);
801 if (region->overlaps(code_region)) {
802 HandleOverlap(region, code_region, start, end);
803 return lo;
804 }
805 code_region_table_->InsertAt(lo, code_region);
806 return lo;
807 } else {
808 CodeRegion* region = At(lo);
809 if (region->overlaps(code_region)) {
810 HandleOverlap(region, code_region, start, end);
811 return lo;
812 }
813 region = At(hi);
814 if (region->overlaps(code_region)) {
815 HandleOverlap(region, code_region, start, end);
816 return hi;
817 }
818 code_region_table_->InsertAt(hi, code_region);
819 return hi;
820 }
821 UNREACHABLE();
822 }
823
824 #if defined(DEBUG)
825 void Verify() {
826 VerifyOrder();
827 VerifyOverlap();
828 }
829 #endif
830
831 void DebugPrint() {
832 OS::Print("Dumping CodeRegionTable:\n");
833 for (intptr_t i = 0; i < code_region_table_->length(); i++) {
834 CodeRegion* region = At(i);
835 region->DebugPrint();
836 }
837 }
838
839 private:
840 intptr_t FindRegionIndex(uword pc, RegionCompare comparator) const {
841 ASSERT(comparator != NULL);
842 intptr_t count = code_region_table_->length();
843 intptr_t first = 0;
844 while (count > 0) {
845 intptr_t it = first;
846 intptr_t step = count / 2;
847 it += step;
848 const CodeRegion* code_region = At(it);
849 if (comparator(pc, code_region->start(), code_region->end())) {
850 first = ++it;
851 count -= (step + 1);
852 } else {
853 count = step;
854 }
855 }
856 return first;
857 }
858
859 static bool CompareUpperBound(uword pc, uword start, uword end) {
860 return pc >= end;
861 }
862
863 static bool CompareLowerBound(uword pc, uword start, uword end) {
864 return end <= pc;
865 }
866
867 void HandleOverlap(CodeRegion* region, CodeRegion* code_region,
868 uword start, uword end) {
869 // We should never see overlapping Dart code regions.
870 ASSERT(region->kind() != CodeRegion::kDartCode);
871 // We should never see overlapping Tag code regions.
872 ASSERT(region->kind() != CodeRegion::kTagCode);
873 // When code regions overlap, they should be of the same kind.
874 ASSERT(region->kind() == code_region->kind());
875 region->AdjustExtent(start, end);
876 }
877
878 #if defined(DEBUG)
879 void VerifyOrder() {
880 const intptr_t length = code_region_table_->length();
881 if (length == 0) {
882 return;
883 }
884 uword last = (*code_region_table_)[0]->end();
885 for (intptr_t i = 1; i < length; i++) {
886 CodeRegion* a = (*code_region_table_)[i];
887 ASSERT(last <= a->start());
888 last = a->end();
889 }
890 }
891
892 void VerifyOverlap() {
893 const intptr_t length = code_region_table_->length();
894 for (intptr_t i = 0; i < length; i++) {
895 CodeRegion* a = (*code_region_table_)[i];
896 for (intptr_t j = i+1; j < length; j++) {
897 CodeRegion* b = (*code_region_table_)[j];
898 ASSERT(!a->contains(b->start()) &&
899 !a->contains(b->end() - 1) &&
900 !b->contains(a->start()) &&
901 !b->contains(a->end() - 1));
902 }
903 }
904 }
905 #endif
906
907 ZoneGrowableArray<CodeRegion*>* code_region_table_;
908 };
909
910
911 class FixTopFrameVisitor : public SampleVisitor {
912 public:
913 explicit FixTopFrameVisitor(Isolate* isolate)
914 : SampleVisitor(isolate),
915 vm_isolate_(Dart::vm_isolate()) {
916 }
917
918 void VisitSample(Sample* sample) {
919 if (sample->processed()) {
920 // Already processed.
921 return;
922 }
923 REUSABLE_CODE_HANDLESCOPE(isolate());
924 // Mark that we've processed this sample.
925 sample->set_processed(true);
926 // Lookup code object for leaf frame.
927 Code& code = reused_code_handle.Handle();
928 code = FindCodeForPC(sample->At(0));
929 sample->set_leaf_frame_is_dart(!code.IsNull());
930 if (sample->pc_marker() == 0) {
931 // No pc marker. Nothing to do.
932 return;
933 }
934 if (!code.IsNull() && (code.compile_timestamp() > sample->timestamp())) {
935 // Code compiled after sample. Ignore.
936 return;
937 }
938 if (sample->leaf_frame_is_dart()) {
939 CheckForMissingDartFrame(code, sample);
940 }
941 }
942
943 private:
944 void CheckForMissingDartFrame(const Code& code, Sample* sample) const {
945 // Some stubs (and intrinsics) do not push a frame onto the stack leaving
946 // the frame pointer in the caller.
947 //
948 // PC -> STUB
949 // FP -> DART3 <-+
950 // DART2 <-| <- TOP FRAME RETURN ADDRESS.
951 // DART1 <-|
952 // .....
953 //
954 // In this case, traversing the linked stack frames will not collect a PC
955 // inside DART3. The stack will incorrectly be: STUB, DART2, DART1.
956 // In Dart code, after pushing the FP onto the stack, an IP in the current
957 // function is pushed onto the stack as well. This stack slot is called
958 // the PC marker. We can use the PC marker to insert DART3 into the stack
959 // so that it will correctly be: STUB, DART3, DART2, DART1. Note the
960 // inserted PC may not accurately reflect the true return address from STUB.
961 ASSERT(!code.IsNull());
962 if (sample->sp() == sample->fp()) {
963 // Haven't pushed pc marker yet.
964 return;
965 }
966 uword pc_marker = sample->pc_marker();
967 if (code.ContainsInstructionAt(pc_marker)) {
968 // PC marker is in the same code as pc, no missing frame.
969 return;
970 }
971 if (!ContainedInDartCodeHeaps(pc_marker)) {
972 // Not a valid PC marker.
973 return;
974 }
975 sample->InsertCallerForTopFrame(pc_marker);
976 }
977
978 bool ContainedInDartCodeHeaps(uword pc) const {
979 return isolate()->heap()->CodeContains(pc) ||
980 vm_isolate()->heap()->CodeContains(pc);
981 }
982
983 Isolate* vm_isolate() const {
984 return vm_isolate_;
985 }
986
987 RawCode* FindCodeForPC(uword pc) const {
988 // Check current isolate for pc.
989 if (isolate()->heap()->CodeContains(pc)) {
990 return Code::LookupCode(pc);
991 }
992 // Check VM isolate for pc.
993 if (vm_isolate()->heap()->CodeContains(pc)) {
994 return Code::LookupCodeInVmIsolate(pc);
995 }
996 return Code::null();
997 }
998
999 Isolate* vm_isolate_;
1000 };
1001
1002
1003 class CodeRegionTableBuilder : public SampleVisitor {
1004 public:
1005 CodeRegionTableBuilder(Isolate* isolate,
1006 CodeRegionTable* live_code_table,
1007 CodeRegionTable* dead_code_table,
1008 CodeRegionTable* tag_code_table)
1009 : SampleVisitor(isolate),
1010 live_code_table_(live_code_table),
1011 dead_code_table_(dead_code_table),
1012 tag_code_table_(tag_code_table),
1013 isolate_(isolate),
1014 vm_isolate_(Dart::vm_isolate()) {
1015 ASSERT(live_code_table_ != NULL);
1016 ASSERT(dead_code_table_ != NULL);
1017 ASSERT(tag_code_table_ != NULL);
1018 frames_ = 0;
1019 min_time_ = kMaxInt64;
1020 max_time_ = 0;
1021 ASSERT(isolate_ != NULL);
1022 ASSERT(vm_isolate_ != NULL);
1023 }
1024
1025 void VisitSample(Sample* sample) {
1026 int64_t timestamp = sample->timestamp();
1027 if (timestamp > max_time_) {
1028 max_time_ = timestamp;
1029 }
1030 if (timestamp < min_time_) {
1031 min_time_ = timestamp;
1032 }
1033 // Make sure VM tag is created.
1034 if (VMTag::IsNativeEntryTag(sample->vm_tag())) {
1035 CreateTag(VMTag::kNativeTagId);
1036 } else if (VMTag::IsRuntimeEntryTag(sample->vm_tag())) {
1037 CreateTag(VMTag::kRuntimeTagId);
1038 }
1039 CreateTag(sample->vm_tag());
1040 // Make sure user tag is created.
1041 CreateUserTag(sample->user_tag());
1042 // Exclusive tick for bottom frame if we aren't sampled from an exit frame.
1043 if (!sample->exit_frame_sample()) {
1044 Tick(sample->At(0), true, timestamp);
1045 }
1046 // Inclusive tick for all frames.
1047 for (intptr_t i = 0; i < FLAG_profile_depth; i++) {
1048 if (sample->At(i) == 0) {
1049 break;
1050 }
1051 frames_++;
1052 Tick(sample->At(i), false, timestamp);
1053 }
1054 }
1055
1056 intptr_t frames() const { return frames_; }
1057
1058 intptr_t TimeDeltaMicros() const {
1059 return static_cast<intptr_t>(max_time_ - min_time_);
1060 }
1061 int64_t max_time() const { return max_time_; }
1062
1063 private:
1064 void CreateTag(uword tag) {
1065 intptr_t index = tag_code_table_->FindIndex(tag);
1066 if (index >= 0) {
1067 // Already created.
1068 return;
1069 }
1070 CodeRegion* region = new CodeRegion(CodeRegion::kTagCode,
1071 tag,
1072 tag + 1,
1073 0);
1074 index = tag_code_table_->InsertCodeRegion(region);
1075 ASSERT(index >= 0);
1076 region->set_creation_serial(visited());
1077 }
1078
1079 void CreateUserTag(uword tag) {
1080 if (tag == 0) {
1081 // None set.
1082 return;
1083 }
1084 intptr_t index = tag_code_table_->FindIndex(tag);
1085 if (index >= 0) {
1086 // Already created.
1087 return;
1088 }
1089 CodeRegion* region = new CodeRegion(CodeRegion::kTagCode,
1090 tag,
1091 tag + 1,
1092 0);
1093 index = tag_code_table_->InsertCodeRegion(region);
1094 ASSERT(index >= 0);
1095 region->set_creation_serial(visited());
1096 }
1097
1098 void Tick(uword pc, bool exclusive, int64_t timestamp) {
1099 CodeRegionTable::TickResult r;
1100 intptr_t serial = exclusive ? -1 : visited();
1101 r = live_code_table_->Tick(pc, exclusive, serial, timestamp);
1102 if (r == CodeRegionTable::kTicked) {
1103 // Live code found and ticked.
1104 return;
1105 }
1106 if (r == CodeRegionTable::kNewerCode) {
1107 // Code has been overwritten by newer code.
1108 // Update shadow table of dead code regions.
1109 r = dead_code_table_->Tick(pc, exclusive, serial, timestamp);
1110 ASSERT(r != CodeRegionTable::kNewerCode);
1111 if (r == CodeRegionTable::kTicked) {
1112 // Dead code found and ticked.
1113 return;
1114 }
1115 ASSERT(r == CodeRegionTable::kNotFound);
1116 CreateAndTickDeadCodeRegion(pc, exclusive, serial);
1117 return;
1118 }
1119 // Create new live CodeRegion.
1120 ASSERT(r == CodeRegionTable::kNotFound);
1121 CodeRegion* region = CreateCodeRegion(pc);
1122 region->set_creation_serial(visited());
1123 intptr_t index = live_code_table_->InsertCodeRegion(region);
1124 ASSERT(index >= 0);
1125 region = live_code_table_->At(index);
1126 if (region->compile_timestamp() <= timestamp) {
1127 region->Tick(pc, exclusive, serial);
1128 return;
1129 }
1130 // We have created a new code region but it's for a CodeRegion
1131 // compiled after the sample.
1132 ASSERT(region->kind() == CodeRegion::kDartCode);
1133 CreateAndTickDeadCodeRegion(pc, exclusive, serial);
1134 }
1135
1136 void CreateAndTickDeadCodeRegion(uword pc, bool exclusive, intptr_t serial) {
1137 // Need to create dead code.
1138 CodeRegion* region = new CodeRegion(CodeRegion::kReusedCode,
1139 pc,
1140 pc + 1,
1141 0);
1142 intptr_t index = dead_code_table_->InsertCodeRegion(region);
1143 region->set_creation_serial(visited());
1144 ASSERT(index >= 0);
1145 dead_code_table_->At(index)->Tick(pc, exclusive, serial);
1146 }
1147
1148 CodeRegion* CreateCodeRegion(uword pc) {
1149 const intptr_t kDartCodeAlignment = OS::PreferredCodeAlignment();
1150 const intptr_t kDartCodeAlignmentMask = ~(kDartCodeAlignment - 1);
1151 Code& code = Code::Handle(isolate_);
1152 // Check current isolate for pc.
1153 if (isolate_->heap()->CodeContains(pc)) {
1154 code ^= Code::LookupCode(pc);
1155 if (!code.IsNull()) {
1156 return new CodeRegion(CodeRegion::kDartCode, code.EntryPoint(),
1157 code.EntryPoint() + code.Size(),
1158 code.compile_timestamp());
1159 }
1160 return new CodeRegion(CodeRegion::kCollectedCode, pc,
1161 (pc & kDartCodeAlignmentMask) + kDartCodeAlignment,
1162 0);
1163 }
1164 // Check VM isolate for pc.
1165 if (vm_isolate_->heap()->CodeContains(pc)) {
1166 code ^= Code::LookupCodeInVmIsolate(pc);
1167 if (!code.IsNull()) {
1168 return new CodeRegion(CodeRegion::kDartCode, code.EntryPoint(),
1169 code.EntryPoint() + code.Size(),
1170 code.compile_timestamp());
1171 }
1172 return new CodeRegion(CodeRegion::kCollectedCode, pc,
1173 (pc & kDartCodeAlignmentMask) + kDartCodeAlignment,
1174 0);
1175 }
1176 // Check NativeSymbolResolver for pc.
1177 uintptr_t native_start = 0;
1178 char* native_name = NativeSymbolResolver::LookupSymbolName(pc,
1179 &native_start);
1180 if (native_name == NULL) {
1181 // No native name found.
1182 return new CodeRegion(CodeRegion::kNativeCode, pc, pc + 1, 0);
1183 }
1184 ASSERT(pc >= native_start);
1185 CodeRegion* code_region =
1186 new CodeRegion(CodeRegion::kNativeCode, native_start, pc + 1, 0);
1187 code_region->SetName(native_name);
1188 free(native_name);
1189 return code_region;
1190 }
1191
1192 intptr_t frames_;
1193 int64_t min_time_;
1194 int64_t max_time_;
1195 CodeRegionTable* live_code_table_;
1196 CodeRegionTable* dead_code_table_;
1197 CodeRegionTable* tag_code_table_;
1198 Isolate* isolate_;
1199 Isolate* vm_isolate_;
1200 };
1201
1202
1203 class CodeRegionExclusiveTrieBuilder : public SampleVisitor {
1204 public:
1205 CodeRegionExclusiveTrieBuilder(Isolate* isolate,
1206 CodeRegionTable* live_code_table,
1207 CodeRegionTable* dead_code_table,
1208 CodeRegionTable* tag_code_table)
1209 : SampleVisitor(isolate),
1210 live_code_table_(live_code_table),
1211 dead_code_table_(dead_code_table),
1212 tag_code_table_(tag_code_table) {
1213 ASSERT(live_code_table_ != NULL);
1214 ASSERT(dead_code_table_ != NULL);
1215 ASSERT(tag_code_table_ != NULL);
1216 dead_code_table_offset_ = live_code_table_->Length();
1217 tag_code_table_offset_ = dead_code_table_offset_ +
1218 dead_code_table_->Length();
1219 intptr_t root_index = tag_code_table_->FindIndex(0);
1220 // Verify that the "0" tag does not exist.
1221 ASSERT(root_index < 0);
1222 // Insert the dummy tag CodeRegion that is used for the Trie root.
1223 CodeRegion* region = new CodeRegion(CodeRegion::kTagCode, 0, 1, 0);
1224 root_index = tag_code_table_->InsertCodeRegion(region);
1225 ASSERT(root_index >= 0);
1226 region->set_creation_serial(0);
1227 root_ = new CodeRegionTrieNode(tag_code_table_offset_ + root_index);
1228 set_tag_order(Profiler::kUserVM);
1229 }
1230
1231 void VisitSample(Sample* sample) {
1232 // Give the root a tick.
1233 root_->Tick();
1234 CodeRegionTrieNode* current = root_;
1235 current = ProcessTags(sample, current);
1236 // Walk the sampled PCs.
1237 for (intptr_t i = 0; i < FLAG_profile_depth; i++) {
1238 if (sample->At(i) == 0) {
1239 break;
1240 }
1241 intptr_t index = FindFinalIndex(sample->At(i), sample->timestamp());
1242 current = current->GetChild(index);
1243 current->Tick();
1244 }
1245 }
1246
1247 CodeRegionTrieNode* root() const {
1248 return root_;
1249 }
1250
1251 Profiler::TagOrder tag_order() const {
1252 return tag_order_;
1253 }
1254
1255 void set_tag_order(Profiler::TagOrder tag_order) {
1256 tag_order_ = tag_order;
1257 }
1258
1259 private:
1260 CodeRegionTrieNode* ProcessUserTags(Sample* sample,
1261 CodeRegionTrieNode* current) {
1262 intptr_t user_tag_index = FindTagIndex(sample->user_tag());
1263 if (user_tag_index >= 0) {
1264 current = current->GetChild(user_tag_index);
1265 // Give the tag a tick.
1266 current->Tick();
1267 }
1268 return current;
1269 }
1270
1271 CodeRegionTrieNode* ProcessVMTags(Sample* sample,
1272 CodeRegionTrieNode* current) {
1273 if (VMTag::IsNativeEntryTag(sample->vm_tag())) {
1274 // Insert a dummy kNativeTagId node.
1275 intptr_t tag_index = FindTagIndex(VMTag::kNativeTagId);
1276 current = current->GetChild(tag_index);
1277 // Give the tag a tick.
1278 current->Tick();
1279 } else if (VMTag::IsRuntimeEntryTag(sample->vm_tag())) {
1280 // Insert a dummy kRuntimeTagId node.
1281 intptr_t tag_index = FindTagIndex(VMTag::kRuntimeTagId);
1282 current = current->GetChild(tag_index);
1283 // Give the tag a tick.
1284 current->Tick();
1285 }
1286 intptr_t tag_index = FindTagIndex(sample->vm_tag());
1287 current = current->GetChild(tag_index);
1288 // Give the tag a tick.
1289 current->Tick();
1290 return current;
1291 }
1292
1293 CodeRegionTrieNode* ProcessTags(Sample* sample, CodeRegionTrieNode* current) {
1294 // None.
1295 if (tag_order() == Profiler::kNoTags) {
1296 return current;
1297 }
1298 // User first.
1299 if ((tag_order() == Profiler::kUserVM) ||
1300 (tag_order() == Profiler::kUser)) {
1301 current = ProcessUserTags(sample, current);
1302 // Only user.
1303 if (tag_order() == Profiler::kUser) {
1304 return current;
1305 }
1306 return ProcessVMTags(sample, current);
1307 }
1308 // VM first.
1309 ASSERT((tag_order() == Profiler::kVMUser) ||
1310 (tag_order() == Profiler::kVM));
1311 current = ProcessVMTags(sample, current);
1312 // Only VM.
1313 if (tag_order() == Profiler::kVM) {
1314 return current;
1315 }
1316 return ProcessUserTags(sample, current);
1317 }
1318
1319 intptr_t FindTagIndex(uword tag) const {
1320 if (tag == 0) {
1321 return -1;
1322 }
1323 intptr_t index = tag_code_table_->FindIndex(tag);
1324 if (index <= 0) {
1325 return -1;
1326 }
1327 ASSERT(index >= 0);
1328 ASSERT((tag_code_table_->At(index))->contains(tag));
1329 return tag_code_table_offset_ + index;
1330 }
1331
1332 intptr_t FindFinalIndex(uword pc, int64_t timestamp) const {
1333 intptr_t index = live_code_table_->FindIndex(pc);
1334 ASSERT(index >= 0);
1335 CodeRegion* region = live_code_table_->At(index);
1336 ASSERT(region->contains(pc));
1337 if (region->compile_timestamp() > timestamp) {
1338 // Overwritten code, find in dead code table.
1339 index = dead_code_table_->FindIndex(pc);
1340 ASSERT(index >= 0);
1341 region = dead_code_table_->At(index);
1342 ASSERT(region->contains(pc));
1343 ASSERT(region->compile_timestamp() <= timestamp);
1344 return index + dead_code_table_offset_;
1345 }
1346 ASSERT(region->compile_timestamp() <= timestamp);
1347 return index;
1348 }
1349
1350 Profiler::TagOrder tag_order_;
1351 CodeRegionTrieNode* root_;
1352 CodeRegionTable* live_code_table_;
1353 CodeRegionTable* dead_code_table_;
1354 CodeRegionTable* tag_code_table_;
1355 intptr_t dead_code_table_offset_;
1356 intptr_t tag_code_table_offset_;
1357 };
1358
1359
1360 class CodeRegionTableCallersBuilder {
1361 public:
1362 CodeRegionTableCallersBuilder(CodeRegionTrieNode* exclusive_root,
1363 CodeRegionTable* live_code_table,
1364 CodeRegionTable* dead_code_table,
1365 CodeRegionTable* tag_code_table)
1366 : exclusive_root_(exclusive_root),
1367 live_code_table_(live_code_table),
1368 dead_code_table_(dead_code_table),
1369 tag_code_table_(tag_code_table) {
1370 ASSERT(exclusive_root_ != NULL);
1371 ASSERT(live_code_table_ != NULL);
1372 ASSERT(dead_code_table_ != NULL);
1373 ASSERT(tag_code_table_ != NULL);
1374 dead_code_table_offset_ = live_code_table_->Length();
1375 tag_code_table_offset_ = dead_code_table_offset_ +
1376 dead_code_table_->Length();
1377 }
1378
1379 void Build() {
1380 ProcessNode(exclusive_root_);
1381 }
1382
1383 private:
1384 void ProcessNode(CodeRegionTrieNode* parent) {
1385 const ZoneGrowableArray<CodeRegionTrieNode*>& children = parent->children();
1386 intptr_t parent_index = parent->code_region_index();
1387 ASSERT(parent_index >= 0);
1388 CodeRegion* parent_region = At(parent_index);
1389 ASSERT(parent_region != NULL);
1390 for (intptr_t i = 0; i < children.length(); i++) {
1391 CodeRegionTrieNode* node = children[i];
1392 ProcessNode(node);
1393 intptr_t index = node->code_region_index();
1394 ASSERT(index >= 0);
1395 CodeRegion* region = At(index);
1396 ASSERT(region != NULL);
1397 region->AddCallee(parent_index, node->count());
1398 parent_region->AddCaller(index, node->count());
1399 }
1400 }
1401
1402 CodeRegion* At(intptr_t final_index) {
1403 ASSERT(final_index >= 0);
1404 if (final_index < dead_code_table_offset_) {
1405 return live_code_table_->At(final_index);
1406 } else if (final_index < tag_code_table_offset_) {
1407 return dead_code_table_->At(final_index - dead_code_table_offset_);
1408 } else {
1409 return tag_code_table_->At(final_index - tag_code_table_offset_);
1410 }
1411 }
1412
1413 CodeRegionTrieNode* exclusive_root_;
1414 CodeRegionTable* live_code_table_;
1415 CodeRegionTable* dead_code_table_;
1416 CodeRegionTable* tag_code_table_;
1417 intptr_t dead_code_table_offset_;
1418 intptr_t tag_code_table_offset_;
1419 };
1420
1421
1422 void Profiler::PrintJSON(Isolate* isolate, JSONStream* stream,
1423 bool full, TagOrder tag_order) {
1424 ASSERT(isolate == Isolate::Current());
1425 // Disable profile interrupts while processing the buffer.
1426 EndExecution(isolate);
1427 MutexLocker profiler_data_lock(isolate->profiler_data_mutex());
1428 IsolateProfilerData* profiler_data = isolate->profiler_data();
1429 if (profiler_data == NULL) {
1430 JSONObject error(stream);
1431 error.AddProperty("type", "Error");
1432 error.AddProperty("text", "Isolate does not have profiling enabled.");
1433 return;
1434 }
1435 SampleBuffer* sample_buffer = profiler_data->sample_buffer();
1436 ASSERT(sample_buffer != NULL);
1437 {
1438 StackZone zone(isolate);
1439 {
1440 // Live code holds Dart, Native, and Collected CodeRegions.
1441 CodeRegionTable live_code_table;
1442 // Dead code holds Overwritten CodeRegions.
1443 CodeRegionTable dead_code_table;
1444 // Tag code holds Tag CodeRegions.
1445 CodeRegionTable tag_code_table;
1446 CodeRegionTableBuilder builder(isolate,
1447 &live_code_table,
1448 &dead_code_table,
1449 &tag_code_table);
1450 {
1451 ScopeStopwatch sw("FixTopFrame");
1452 // Preprocess samples and fix the caller when the top PC is in a
1453 // stub or intrinsic without a frame.
1454 FixTopFrameVisitor fixTopFrame(isolate);
1455 sample_buffer->VisitSamples(&fixTopFrame);
1456 }
1457 {
1458 // Build CodeRegion tables.
1459 ScopeStopwatch sw("CodeRegionTableBuilder");
1460 sample_buffer->VisitSamples(&builder);
1461 }
1462 intptr_t samples = builder.visited();
1463 intptr_t frames = builder.frames();
1464 if (FLAG_trace_profiler) {
1465 intptr_t total_live_code_objects = live_code_table.Length();
1466 intptr_t total_dead_code_objects = dead_code_table.Length();
1467 intptr_t total_tag_code_objects = tag_code_table.Length();
1468 OS::Print("Processed %" Pd " frames\n", frames);
1469 OS::Print("CodeTables: live=%" Pd " dead=%" Pd " tag=%" Pd "\n",
1470 total_live_code_objects,
1471 total_dead_code_objects,
1472 total_tag_code_objects);
1473 }
1474 #if defined(DEBUG)
1475 live_code_table.Verify();
1476 dead_code_table.Verify();
1477 tag_code_table.Verify();
1478 if (FLAG_trace_profiler) {
1479 OS::Print("CodeRegionTables verified to be ordered and not overlap.\n");
1480 }
1481 #endif
1482 CodeRegionExclusiveTrieBuilder build_trie(isolate,
1483 &live_code_table,
1484 &dead_code_table,
1485 &tag_code_table);
1486 build_trie.set_tag_order(tag_order);
1487 {
1488 // Build CodeRegion trie.
1489 ScopeStopwatch sw("CodeRegionExclusiveTrieBuilder");
1490 sample_buffer->VisitSamples(&build_trie);
1491 build_trie.root()->SortByCount();
1492 }
1493 CodeRegionTableCallersBuilder build_callers(build_trie.root(),
1494 &live_code_table,
1495 &dead_code_table,
1496 &tag_code_table);
1497 {
1498 // Build CodeRegion callers.
1499 ScopeStopwatch sw("CodeRegionTableCallersBuilder");
1500 build_callers.Build();
1501 }
1502 {
1503 ScopeStopwatch sw("CodeTableStream");
1504 // Serialize to JSON.
1505 JSONObject obj(stream);
1506 obj.AddProperty("type", "CpuProfile");
1507 obj.AddProperty("id", "profile");
1508 obj.AddProperty("samples", samples);
1509 obj.AddProperty("depth", static_cast<intptr_t>(FLAG_profile_depth));
1510 obj.AddProperty("period", static_cast<intptr_t>(FLAG_profile_period));
1511 obj.AddProperty("timeSpan",
1512 MicrosecondsToSeconds(builder.TimeDeltaMicros()));
1513 {
1514 JSONArray exclusive_trie(&obj, "exclusive_trie");
1515 CodeRegionTrieNode* root = build_trie.root();
1516 ASSERT(root != NULL);
1517 root->PrintToJSONArray(&exclusive_trie);
1518 }
1519 JSONArray codes(&obj, "codes");
1520 for (intptr_t i = 0; i < live_code_table.Length(); i++) {
1521 CodeRegion* region = live_code_table.At(i);
1522 ASSERT(region != NULL);
1523 region->PrintToJSONArray(isolate, &codes, full);
1524 }
1525 for (intptr_t i = 0; i < dead_code_table.Length(); i++) {
1526 CodeRegion* region = dead_code_table.At(i);
1527 ASSERT(region != NULL);
1528 region->PrintToJSONArray(isolate, &codes, full);
1529 }
1530 for (intptr_t i = 0; i < tag_code_table.Length(); i++) {
1531 CodeRegion* region = tag_code_table.At(i);
1532 ASSERT(region != NULL);
1533 region->PrintToJSONArray(isolate, &codes, full);
1534 }
1535 }
1536 }
1537 }
1538 // Enable profile interrupts.
1539 BeginExecution(isolate);
1540 }
1541
1542
1543 IsolateProfilerData::IsolateProfilerData(SampleBuffer* sample_buffer, 176 IsolateProfilerData::IsolateProfilerData(SampleBuffer* sample_buffer,
1544 bool own_sample_buffer) { 177 bool own_sample_buffer) {
1545 ASSERT(sample_buffer != NULL); 178 ASSERT(sample_buffer != NULL);
1546 sample_buffer_ = sample_buffer; 179 sample_buffer_ = sample_buffer;
1547 own_sample_buffer_ = own_sample_buffer; 180 own_sample_buffer_ = own_sample_buffer;
1548 block_count_ = 0; 181 block_count_ = 0;
1549 } 182 }
1550 183
1551 184
1552 IsolateProfilerData::~IsolateProfilerData() { 185 IsolateProfilerData::~IsolateProfilerData() {
(...skipping 528 matching lines...) Expand 10 before | Expand all | Expand 10 after
2081 state.pc, 714 state.pc,
2082 state.fp, 715 state.fp,
2083 sp); 716 sp);
2084 stackWalker.walk(); 717 stackWalker.walk();
2085 #endif 718 #endif
2086 } 719 }
2087 } 720 }
2088 } 721 }
2089 722
2090 } // namespace dart 723 } // namespace dart
OLDNEW
« no previous file with comments | « runtime/vm/profiler.h ('k') | runtime/vm/profiler_service.h » ('j') | runtime/vm/scope_timer.h » ('J')

Powered by Google App Engine
This is Rietveld 408576698