Chromium Code Reviews| OLD | NEW |
|---|---|
| 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/utils.h" | 5 #include "platform/utils.h" |
| 6 | 6 |
| 7 #include "vm/allocation.h" | 7 #include "vm/allocation.h" |
| 8 #include "vm/atomic.h" | 8 #include "vm/atomic.h" |
| 9 #include "vm/code_patcher.h" | 9 #include "vm/code_patcher.h" |
| 10 #include "vm/isolate.h" | 10 #include "vm/isolate.h" |
| (...skipping 17 matching lines...) Expand all Loading... | |
| 28 #endif | 28 #endif |
| 29 DEFINE_FLAG(bool, trace_profiled_isolates, false, "Trace profiled isolates."); | 29 DEFINE_FLAG(bool, trace_profiled_isolates, false, "Trace profiled isolates."); |
| 30 DEFINE_FLAG(charp, profile_dir, NULL, | 30 DEFINE_FLAG(charp, profile_dir, NULL, |
| 31 "Enable writing profile data into specified directory."); | 31 "Enable writing profile data into specified directory."); |
| 32 DEFINE_FLAG(int, profile_period, 1000, | 32 DEFINE_FLAG(int, profile_period, 1000, |
| 33 "Time between profiler samples in microseconds. Minimum 250."); | 33 "Time between profiler samples in microseconds. Minimum 250."); |
| 34 DEFINE_FLAG(int, profile_depth, 8, | 34 DEFINE_FLAG(int, profile_depth, 8, |
| 35 "Maximum number stack frames walked. Minimum 1. Maximum 255."); | 35 "Maximum number stack frames walked. Minimum 1. Maximum 255."); |
| 36 DEFINE_FLAG(bool, profile_verify_stack_walk, false, | 36 DEFINE_FLAG(bool, profile_verify_stack_walk, false, |
| 37 "Verify instruction addresses while walking the stack."); | 37 "Verify instruction addresses while walking the stack."); |
| 38 DEFINE_FLAG(bool, profile_native_stack, true, | |
| 39 "Use native stack in profiler."); | |
| 38 | 40 |
| 39 bool Profiler::initialized_ = false; | 41 bool Profiler::initialized_ = false; |
| 40 SampleBuffer* Profiler::sample_buffer_ = NULL; | 42 SampleBuffer* Profiler::sample_buffer_ = NULL; |
| 41 | 43 |
| 42 void Profiler::InitOnce() { | 44 void Profiler::InitOnce() { |
| 43 // Place some sane restrictions on user controlled flags. | 45 // Place some sane restrictions on user controlled flags. |
| 44 SetSamplePeriod(FLAG_profile_period); | 46 SetSamplePeriod(FLAG_profile_period); |
| 45 SetSampleDepth(FLAG_profile_depth); | 47 SetSampleDepth(FLAG_profile_depth); |
| 46 if (!FLAG_profile) { | 48 if (!FLAG_profile) { |
| 47 return; | 49 return; |
| (...skipping 871 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 919 | 921 |
| 920 void VisitSample(Sample* sample) { | 922 void VisitSample(Sample* sample) { |
| 921 int64_t timestamp = sample->timestamp(); | 923 int64_t timestamp = sample->timestamp(); |
| 922 if (timestamp > max_time_) { | 924 if (timestamp > max_time_) { |
| 923 max_time_ = timestamp; | 925 max_time_ = timestamp; |
| 924 } | 926 } |
| 925 if (timestamp < min_time_) { | 927 if (timestamp < min_time_) { |
| 926 min_time_ = timestamp; | 928 min_time_ = timestamp; |
| 927 } | 929 } |
| 928 // Make sure VM tag is created. | 930 // Make sure VM tag is created. |
| 931 if (VMTag::IsNativeEntryTag(sample->vm_tag())) { | |
| 932 CreateTag(VMTag::kNativeTagId); | |
| 933 } else if (VMTag::IsRuntimeEntryTag(sample->vm_tag())) { | |
| 934 CreateTag(VMTag::kRuntimeTagId); | |
| 935 } | |
| 929 CreateTag(sample->vm_tag()); | 936 CreateTag(sample->vm_tag()); |
| 930 // Exclusive tick for bottom frame. | 937 // Exclusive tick for bottom frame. |
| 931 Tick(sample->At(0), true, timestamp); | 938 Tick(sample->At(0), true, timestamp); |
| 932 // Inclusive tick for all frames. | 939 // Inclusive tick for all frames. |
| 933 for (intptr_t i = 0; i < FLAG_profile_depth; i++) { | 940 for (intptr_t i = 0; i < FLAG_profile_depth; i++) { |
| 934 if (sample->At(i) == 0) { | 941 if (sample->At(i) == 0) { |
| 935 break; | 942 break; |
| 936 } | 943 } |
| 937 frames_++; | 944 frames_++; |
| 938 Tick(sample->At(i), false, timestamp); | 945 Tick(sample->At(i), false, timestamp); |
| (...skipping 155 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1094 root_ = new CodeRegionTrieNode(tag_code_table_offset_ + root_index); | 1101 root_ = new CodeRegionTrieNode(tag_code_table_offset_ + root_index); |
| 1095 // Use tags by default. | 1102 // Use tags by default. |
| 1096 set_use_tags(true); | 1103 set_use_tags(true); |
| 1097 } | 1104 } |
| 1098 | 1105 |
| 1099 void VisitSample(Sample* sample) { | 1106 void VisitSample(Sample* sample) { |
| 1100 // Give the root a tick. | 1107 // Give the root a tick. |
| 1101 root_->Tick(); | 1108 root_->Tick(); |
| 1102 CodeRegionTrieNode* current = root_; | 1109 CodeRegionTrieNode* current = root_; |
| 1103 if (use_tags()) { | 1110 if (use_tags()) { |
| 1111 if (VMTag::IsNativeEntryTag(sample->vm_tag())) { | |
| 1112 // Insert a dummy kNativeTagId node. | |
| 1113 intptr_t tag_index = FindTagIndex(VMTag::kNativeTagId); | |
| 1114 current = current->GetChild(tag_index); | |
| 1115 // Give the tag a tick. | |
| 1116 current->Tick(); | |
| 1117 } else if (VMTag::IsRuntimeEntryTag(sample->vm_tag())) { | |
| 1118 // Insert a dummy kRuntimeTagId node. | |
| 1119 intptr_t tag_index = FindTagIndex(VMTag::kRuntimeTagId); | |
| 1120 current = current->GetChild(tag_index); | |
| 1121 // Give the tag a tick. | |
| 1122 current->Tick(); | |
| 1123 } | |
| 1104 intptr_t tag_index = FindTagIndex(sample->vm_tag()); | 1124 intptr_t tag_index = FindTagIndex(sample->vm_tag()); |
| 1105 current = current->GetChild(tag_index); | 1125 current = current->GetChild(tag_index); |
| 1106 // Give the tag a tick. | 1126 // Give the tag a tick. |
| 1107 current->Tick(); | 1127 current->Tick(); |
| 1108 } | 1128 } |
| 1109 // Walk the sampled PCs. | 1129 // Walk the sampled PCs. |
| 1110 for (intptr_t i = 0; i < FLAG_profile_depth; i++) { | 1130 for (intptr_t i = 0; i < FLAG_profile_depth; i++) { |
| 1111 if (sample->At(i) == 0) { | 1131 if (sample->At(i) == 0) { |
| 1112 break; | 1132 break; |
| 1113 } | 1133 } |
| (...skipping 285 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1399 | 1419 |
| 1400 | 1420 |
| 1401 Sample* SampleBuffer::ReserveSample() { | 1421 Sample* SampleBuffer::ReserveSample() { |
| 1402 ASSERT(samples_ != NULL); | 1422 ASSERT(samples_ != NULL); |
| 1403 uintptr_t cursor = AtomicOperations::FetchAndIncrement(&cursor_); | 1423 uintptr_t cursor = AtomicOperations::FetchAndIncrement(&cursor_); |
| 1404 // Map back into sample buffer range. | 1424 // Map back into sample buffer range. |
| 1405 cursor = cursor % capacity_; | 1425 cursor = cursor % capacity_; |
| 1406 return At(cursor); | 1426 return At(cursor); |
| 1407 } | 1427 } |
| 1408 | 1428 |
| 1429 class ProfilerDartStackWalker : public ValueObject { | |
| 1430 public: | |
| 1431 explicit ProfilerDartStackWalker(Sample* sample) | |
| 1432 : sample_(sample), | |
| 1433 frame_iterator_() { | |
| 1434 ASSERT(sample_ != NULL); | |
| 1435 } | |
| 1436 | |
| 1437 ProfilerDartStackWalker(Sample* sample, uword pc, uword fp, uword sp) | |
| 1438 : sample_(sample), | |
| 1439 frame_iterator_(fp, sp, pc) { | |
| 1440 ASSERT(sample_ != NULL); | |
| 1441 } | |
| 1442 | |
| 1443 ProfilerDartStackWalker(Sample* sample, uword fp) | |
| 1444 : sample_(sample), | |
| 1445 frame_iterator_(fp) { | |
| 1446 ASSERT(sample_ != NULL); | |
| 1447 } | |
| 1448 | |
| 1449 int walk() { | |
| 1450 intptr_t frame_index = 0; | |
| 1451 StackFrame* frame = frame_iterator_.NextFrame(); | |
| 1452 while (frame != NULL) { | |
| 1453 sample_->SetAt(frame_index, frame->pc()); | |
| 1454 frame_index++; | |
| 1455 if (frame_index >= FLAG_profile_depth) { | |
| 1456 break; | |
| 1457 } | |
| 1458 frame = frame_iterator_.NextFrame(); | |
| 1459 } | |
| 1460 return frame_index; | |
| 1461 } | |
| 1462 | |
| 1463 private: | |
| 1464 Sample* sample_; | |
| 1465 DartFrameIterator frame_iterator_; | |
| 1466 }; | |
| 1467 | |
| 1409 // Notes on stack frame walking: | 1468 // Notes on stack frame walking: |
| 1410 // | 1469 // |
| 1411 // The sampling profiler will collect up to Sample::kNumStackFrames stack frames | 1470 // The sampling profiler will collect up to Sample::kNumStackFrames stack frames |
| 1412 // The stack frame walking code uses the frame pointer to traverse the stack. | 1471 // The stack frame walking code uses the frame pointer to traverse the stack. |
| 1413 // If the VM is compiled without frame pointers (which is the default on | 1472 // If the VM is compiled without frame pointers (which is the default on |
| 1414 // recent GCC versions with optimizing enabled) the stack walking code may | 1473 // recent GCC versions with optimizing enabled) the stack walking code may |
| 1415 // fail (sometimes leading to a crash). | 1474 // fail (sometimes leading to a crash). |
| 1416 // | 1475 // |
| 1417 class ProfilerSampleStackWalker : public ValueObject { | 1476 class ProfilerNativeStackWalker : public ValueObject { |
| 1418 public: | 1477 public: |
| 1419 ProfilerSampleStackWalker(Sample* sample, | 1478 ProfilerNativeStackWalker(Sample* sample, |
| 1420 uword stack_lower, | 1479 uword stack_lower, |
| 1421 uword stack_upper, | 1480 uword stack_upper, |
| 1422 uword pc, | 1481 uword pc, |
| 1423 uword fp, | 1482 uword fp, |
| 1424 uword sp) | 1483 uword sp) |
| 1425 : sample_(sample), | 1484 : sample_(sample), |
| 1426 stack_upper_(stack_upper), | 1485 stack_upper_(stack_upper), |
| 1427 original_pc_(pc), | 1486 original_pc_(pc), |
| 1428 original_fp_(fp), | 1487 original_fp_(fp), |
| 1429 original_sp_(sp), | 1488 original_sp_(sp), |
| 1430 lower_bound_(stack_lower) { | 1489 lower_bound_(stack_lower) { |
| 1431 ASSERT(sample_ != NULL); | 1490 ASSERT(sample_ != NULL); |
| 1432 } | 1491 } |
| 1433 | 1492 |
| 1434 int walk(Heap* heap, uword vm_tag) { | 1493 int walk(Heap* heap) { |
| 1435 const intptr_t kMaxStep = 0x1000; // 4K. | 1494 const intptr_t kMaxStep = 0x1000; // 4K. |
| 1436 const bool kWalkStack = true; // Walk the stack. | 1495 const bool kWalkStack = true; // Walk the stack. |
| 1437 // Always store the exclusive PC. | 1496 // Always store the exclusive PC. |
| 1438 sample_->SetAt(0, original_pc_); | 1497 sample_->SetAt(0, original_pc_); |
| 1439 // Always store the vm tag. | |
| 1440 sample_->set_vm_tag(vm_tag); | |
| 1441 if (!kWalkStack) { | 1498 if (!kWalkStack) { |
| 1442 // Not walking the stack, only took exclusive sample. | 1499 // Not walking the stack, only took exclusive sample. |
| 1443 return 1; | 1500 return 1; |
| 1444 } | 1501 } |
| 1445 uword* pc = reinterpret_cast<uword*>(original_pc_); | 1502 uword* pc = reinterpret_cast<uword*>(original_pc_); |
| 1446 uword* fp = reinterpret_cast<uword*>(original_fp_); | 1503 uword* fp = reinterpret_cast<uword*>(original_fp_); |
| 1447 uword* previous_fp = fp; | 1504 uword* previous_fp = fp; |
| 1448 if (original_sp_ > original_fp_) { | 1505 if (original_sp_ > original_fp_) { |
| 1449 // Stack pointer should not be above frame pointer. | 1506 // Stack pointer should not be above frame pointer. |
| 1450 return 1; | 1507 return 1; |
| (...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1527 const uword original_fp_; | 1584 const uword original_fp_; |
| 1528 const uword original_sp_; | 1585 const uword original_sp_; |
| 1529 uword lower_bound_; | 1586 uword lower_bound_; |
| 1530 }; | 1587 }; |
| 1531 | 1588 |
| 1532 | 1589 |
| 1533 void Profiler::RecordSampleInterruptCallback( | 1590 void Profiler::RecordSampleInterruptCallback( |
| 1534 const InterruptedThreadState& state, | 1591 const InterruptedThreadState& state, |
| 1535 void* data) { | 1592 void* data) { |
| 1536 Isolate* isolate = reinterpret_cast<Isolate*>(data); | 1593 Isolate* isolate = reinterpret_cast<Isolate*>(data); |
| 1537 if (isolate == NULL) { | 1594 if ((isolate == NULL) || (Dart::vm_isolate() == NULL)) { |
| 1595 return; | |
| 1596 } | |
| 1597 if (isolate == Dart::vm_isolate()) { | |
| 1598 // Never sample the vm_isolate. | |
| 1599 return; | |
| 1600 } | |
|
siva
2014/04/08 16:27:54
Does it make sense to start the profiler before th
Cutch
2014/04/09 17:40:59
Isolate::SetCurrent expects the profiler to have b
siva
2014/04/09 23:28:11
I agree we don't want to make Isolate::SetCurrent
Cutch
2014/04/10 15:30:27
Done.
| |
| 1601 if (!FLAG_profile_native_stack && (isolate->stub_code() == NULL)) { | |
| 1602 // ProfilerDartStackWalker requires stub code setup to be completed. | |
| 1538 return; | 1603 return; |
| 1539 } | 1604 } |
|
siva
2014/04/08 16:27:54
Instead of checking like this wouldn't it be more
Cutch
2014/04/09 17:40:59
See above.
| |
| 1540 VMTagCounters* counters = isolate->vm_tag_counters(); | 1605 VMTagCounters* counters = isolate->vm_tag_counters(); |
| 1541 ASSERT(counters != NULL); | 1606 ASSERT(counters != NULL); |
| 1542 counters->Increment(isolate->vm_tag()); | 1607 counters->Increment(isolate->vm_tag()); |
| 1543 IsolateProfilerData* profiler_data = isolate->profiler_data(); | 1608 IsolateProfilerData* profiler_data = isolate->profiler_data(); |
| 1544 if (profiler_data == NULL) { | 1609 if (profiler_data == NULL) { |
| 1545 return; | 1610 return; |
| 1546 } | 1611 } |
| 1547 SampleBuffer* sample_buffer = profiler_data->sample_buffer(); | 1612 SampleBuffer* sample_buffer = profiler_data->sample_buffer(); |
| 1548 if (sample_buffer == NULL) { | 1613 if (sample_buffer == NULL) { |
| 1549 return; | 1614 return; |
| 1550 } | 1615 } |
| 1551 Sample* sample = sample_buffer->ReserveSample(); | 1616 Sample* sample = sample_buffer->ReserveSample(); |
| 1552 sample->Init(isolate, OS::GetCurrentTimeMicros(), state.tid); | 1617 sample->Init(isolate, OS::GetCurrentTimeMicros(), state.tid); |
| 1553 uword stack_lower = 0; | 1618 sample->set_vm_tag(isolate->vm_tag()); |
| 1554 uword stack_upper = 0; | 1619 if (FLAG_profile_native_stack) { |
| 1555 isolate->GetStackBounds(&stack_lower, &stack_upper); | 1620 // Collect native and Dart frames. |
| 1556 if ((stack_lower == 0) || (stack_upper == 0)) { | 1621 uword stack_lower = 0; |
| 1557 stack_lower = 0; | 1622 uword stack_upper = 0; |
| 1558 stack_upper = 0; | 1623 isolate->GetStackBounds(&stack_lower, &stack_upper); |
| 1624 if ((stack_lower == 0) || (stack_upper == 0)) { | |
| 1625 stack_lower = 0; | |
| 1626 stack_upper = 0; | |
| 1627 } | |
| 1628 ProfilerNativeStackWalker stackWalker(sample, stack_lower, stack_upper, | |
| 1629 state.pc, state.fp, state.sp); | |
| 1630 stackWalker.walk(isolate->heap()); | |
| 1631 } else { | |
| 1632 if (isolate->top_exit_frame_info() != 0) { | |
| 1633 ProfilerDartStackWalker stackWalker(sample); | |
| 1634 stackWalker.walk(); | |
| 1635 } else { | |
| 1636 // TODO(johnmccutchan): StackFrameIterator that is resilient to native | |
| 1637 // frames. | |
|
siva
2014/04/08 16:27:54
what does this TODO mean (for pure Dart frame walk
Cutch
2014/04/09 17:40:59
Slightly misworded but I want to support only coll
| |
| 1638 } | |
| 1559 } | 1639 } |
| 1560 ProfilerSampleStackWalker stackWalker(sample, stack_lower, stack_upper, | |
| 1561 state.pc, state.fp, state.sp); | |
| 1562 stackWalker.walk(isolate->heap(), isolate->vm_tag()); | |
| 1563 } | 1640 } |
| 1564 | 1641 |
| 1565 } // namespace dart | 1642 } // namespace dart |
| OLD | NEW |