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 "vm/profiler_service.h" | 5 #include "vm/profiler_service.h" |
6 | 6 |
7 #include "vm/growable_array.h" | 7 #include "vm/growable_array.h" |
8 #include "vm/log.h" | 8 #include "vm/log.h" |
9 #include "vm/native_symbol.h" | 9 #include "vm/native_symbol.h" |
10 #include "vm/object.h" | 10 #include "vm/object.h" |
(...skipping 139 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
150 return; | 150 return; |
151 } | 151 } |
152 inclusive_serial_ = inclusive_serial; | 152 inclusive_serial_ = inclusive_serial; |
153 inclusive_ticks_++; | 153 inclusive_ticks_++; |
154 TickSourcePosition(token_position, false); | 154 TickSourcePosition(token_position, false); |
155 } | 155 } |
156 | 156 |
157 | 157 |
158 void ProfileFunction::TickSourcePosition(TokenPosition token_position, | 158 void ProfileFunction::TickSourcePosition(TokenPosition token_position, |
159 bool exclusive) { | 159 bool exclusive) { |
160 for (intptr_t i = 0; i < source_position_ticks_.length(); i++) { | 160 intptr_t i = 0; |
| 161 for (; i < source_position_ticks_.length(); i++) { |
161 ProfileFunctionSourcePosition& position = source_position_ticks_[i]; | 162 ProfileFunctionSourcePosition& position = source_position_ticks_[i]; |
162 if (position.token_pos() == token_position) { | 163 if (position.token_pos().value() == token_position.value()) { |
| 164 if (FLAG_trace_profiler) { |
| 165 OS::Print("Ticking source position %s %s\n", |
| 166 exclusive ? "exclusive" : "inclusive", |
| 167 token_position.ToCString()); |
| 168 } |
163 // Found existing position, tick it. | 169 // Found existing position, tick it. |
164 position.Tick(exclusive); | 170 position.Tick(exclusive); |
165 return; | 171 return; |
166 } | 172 } |
| 173 if (position.token_pos().value() > token_position.value()) { |
| 174 break; |
| 175 } |
167 } | 176 } |
168 // Add new one. | 177 |
| 178 // Add new one, sorted by token position value. |
169 ProfileFunctionSourcePosition pfsp(token_position); | 179 ProfileFunctionSourcePosition pfsp(token_position); |
| 180 if (FLAG_trace_profiler) { |
| 181 OS::Print("Ticking source position %s %s\n", |
| 182 exclusive ? "exclusive" : "inclusive", |
| 183 token_position.ToCString()); |
| 184 } |
170 pfsp.Tick(exclusive); | 185 pfsp.Tick(exclusive); |
171 source_position_ticks_.Add(pfsp); | 186 |
| 187 if (i < source_position_ticks_.length()) { |
| 188 source_position_ticks_.InsertAt(i, pfsp); |
| 189 } else { |
| 190 source_position_ticks_.Add(pfsp); |
| 191 } |
172 } | 192 } |
173 | 193 |
174 | 194 |
175 const char* ProfileFunction::KindToCString(Kind kind) { | 195 const char* ProfileFunction::KindToCString(Kind kind) { |
176 switch (kind) { | 196 switch (kind) { |
177 case kDartFunction: | 197 case kDartFunction: |
178 return "Dart"; | 198 return "Dart"; |
179 case kNativeFunction: | 199 case kNativeFunction: |
180 return "Native"; | 200 return "Native"; |
181 case kTagFunction: | 201 case kTagFunction: |
(...skipping 1238 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1420 } | 1440 } |
1421 | 1441 |
1422 // Truncated tag. | 1442 // Truncated tag. |
1423 if (sample->truncated()) { | 1443 if (sample->truncated()) { |
1424 current = AppendTruncatedTag(current); | 1444 current = AppendTruncatedTag(current); |
1425 InclusiveTickTruncatedTag(); | 1445 InclusiveTickTruncatedTag(); |
1426 } | 1446 } |
1427 } | 1447 } |
1428 } | 1448 } |
1429 | 1449 |
| 1450 intptr_t OffsetForPC(uword pc, |
| 1451 const Code& code, |
| 1452 ProcessedSample* sample, |
| 1453 intptr_t frame_index) { |
| 1454 intptr_t offset = pc - code.EntryPoint(); |
| 1455 if (frame_index != 0) { |
| 1456 // The PC of frames below the top frame is a call's return address, |
| 1457 // which can belong to a different inlining interval than the call. |
| 1458 offset--; |
| 1459 } else if (sample->IsAllocationSample()) { |
| 1460 // Allocation samples skip the top frame, so the top frame's pc is |
| 1461 // also a call's return address. |
| 1462 offset--; |
| 1463 } else if (!sample->first_frame_executing()) { |
| 1464 // If the first frame wasn't executing code (i.e. we started to collect |
| 1465 // the stack trace at an exit frame), the top frame's pc is also a |
| 1466 // call's return address. |
| 1467 offset--; |
| 1468 } |
| 1469 return offset; |
| 1470 } |
| 1471 |
1430 ProfileFunctionTrieNode* ProcessFrame( | 1472 ProfileFunctionTrieNode* ProcessFrame( |
1431 ProfileFunctionTrieNode* current, | 1473 ProfileFunctionTrieNode* current, |
1432 intptr_t sample_index, | 1474 intptr_t sample_index, |
1433 ProcessedSample* sample, | 1475 ProcessedSample* sample, |
1434 intptr_t frame_index) { | 1476 intptr_t frame_index) { |
1435 const uword pc = sample->At(frame_index); | 1477 const uword pc = sample->At(frame_index); |
1436 ProfileCode* profile_code = GetProfileCode(pc, | 1478 ProfileCode* profile_code = GetProfileCode(pc, |
1437 sample->timestamp()); | 1479 sample->timestamp()); |
1438 ProfileFunction* function = profile_code->function(); | 1480 ProfileFunction* function = profile_code->function(); |
1439 ASSERT(function != NULL); | 1481 ASSERT(function != NULL); |
1440 const intptr_t code_index = profile_code->code_table_index(); | 1482 const intptr_t code_index = profile_code->code_table_index(); |
1441 ASSERT(profile_code != NULL); | 1483 ASSERT(profile_code != NULL); |
1442 const Code& code = Code::ZoneHandle(profile_code->code()); | 1484 const Code& code = Code::ZoneHandle(profile_code->code()); |
1443 GrowableArray<Function*> inlined_functions; | 1485 GrowableArray<Function*> inlined_functions; |
1444 GrowableArray<TokenPosition> inlined_token_positions; | 1486 GrowableArray<TokenPosition> inlined_token_positions; |
1445 TokenPosition token_position = TokenPosition::kNoSource; | 1487 TokenPosition token_position = TokenPosition::kNoSource; |
1446 if (!code.IsNull()) { | 1488 if (!code.IsNull()) { |
1447 intptr_t offset = pc - code.EntryPoint(); | 1489 const intptr_t offset = OffsetForPC(pc, code, sample, frame_index); |
1448 if (frame_index != 0) { | |
1449 // The PC of frames below the top frame is a call's return address, | |
1450 // which can belong to a different inlining interval than the call. | |
1451 offset--; | |
1452 } else if (sample->IsAllocationSample()) { | |
1453 // Allocation samples skip the top frame, so the top frame's pc is | |
1454 // also a call's return address. | |
1455 offset--; | |
1456 } else if (!sample->first_frame_executing()) { | |
1457 // If the first frame wasn't executing code (i.e. we started to collect | |
1458 // the stack trace at an exit frame), the top frame's pc is also a | |
1459 // call's return address. | |
1460 offset--; | |
1461 } | |
1462 code.GetInlinedFunctionsAt(offset, | 1490 code.GetInlinedFunctionsAt(offset, |
1463 &inlined_functions, | 1491 &inlined_functions, |
1464 &inlined_token_positions); | 1492 &inlined_token_positions); |
1465 token_position = code.GetTokenPositionAt(offset); | 1493 token_position = code.GetTokenPositionAt(offset); |
1466 if (inlined_functions.length() > 0) { | 1494 if (inlined_functions.length() > 0) { |
1467 // The inlined token position table does not include the token position | 1495 // The inlined token position table does not include the token position |
1468 // of the final call. Insert it at the beginning because the table. | 1496 // of the final call. Insert it at the beginning because the table. |
1469 // is reversed. | 1497 // is reversed. |
1470 inlined_token_positions.InsertAt(0, token_position); | 1498 inlined_token_positions.InsertAt(0, token_position); |
1471 } | 1499 } |
(...skipping 108 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1580 return IsExecutingFrame(sample, frame_index) || vm_tags_emitted(); | 1608 return IsExecutingFrame(sample, frame_index) || vm_tags_emitted(); |
1581 } | 1609 } |
1582 | 1610 |
1583 ProfileFunctionTrieNode* ProcessFunction(ProfileFunctionTrieNode* current, | 1611 ProfileFunctionTrieNode* ProcessFunction(ProfileFunctionTrieNode* current, |
1584 intptr_t sample_index, | 1612 intptr_t sample_index, |
1585 ProcessedSample* sample, | 1613 ProcessedSample* sample, |
1586 intptr_t frame_index, | 1614 intptr_t frame_index, |
1587 ProfileFunction* function, | 1615 ProfileFunction* function, |
1588 TokenPosition token_position, | 1616 TokenPosition token_position, |
1589 intptr_t code_index) { | 1617 intptr_t code_index) { |
1590 if (FLAG_trace_profiler) { | |
1591 THR_Print("S[%" Pd "]F[%" Pd "] %s %s\n", | |
1592 sample_index, | |
1593 frame_index, | |
1594 function->Name(), token_position.ToCString()); | |
1595 } | |
1596 if (tick_functions_) { | 1618 if (tick_functions_) { |
| 1619 if (FLAG_trace_profiler) { |
| 1620 THR_Print("S[%" Pd "]F[%" Pd "] %s %s 0x%" Px "\n", |
| 1621 sample_index, |
| 1622 frame_index, |
| 1623 function->Name(), |
| 1624 token_position.ToCString(), |
| 1625 sample->At(frame_index)); |
| 1626 } |
1597 function->Tick(IsExecutingFrame(sample, frame_index), | 1627 function->Tick(IsExecutingFrame(sample, frame_index), |
1598 sample_index, | 1628 sample_index, |
1599 token_position); | 1629 token_position); |
1600 } | 1630 } |
1601 function->AddProfileCode(code_index); | 1631 function->AddProfileCode(code_index); |
1602 current = current->GetChild(function->table_index()); | 1632 current = current->GetChild(function->table_index()); |
1603 if (ShouldTickNode(sample, frame_index)) { | 1633 if (ShouldTickNode(sample, frame_index)) { |
1604 current->Tick(); | 1634 current->Tick(); |
1605 } | 1635 } |
1606 current->AddCodeObjectIndex(code_index); | 1636 current->AddCodeObjectIndex(code_index); |
(...skipping 494 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2101 | 2131 |
2102 void Profile::Build(Thread* thread, | 2132 void Profile::Build(Thread* thread, |
2103 SampleFilter* filter, | 2133 SampleFilter* filter, |
2104 TagOrder tag_order, | 2134 TagOrder tag_order, |
2105 intptr_t extra_tags) { | 2135 intptr_t extra_tags) { |
2106 ProfileBuilder builder(thread, filter, tag_order, extra_tags, this); | 2136 ProfileBuilder builder(thread, filter, tag_order, extra_tags, this); |
2107 builder.Build(); | 2137 builder.Build(); |
2108 } | 2138 } |
2109 | 2139 |
2110 | 2140 |
| 2141 intptr_t Profile::NumFunctions() const { |
| 2142 return functions_->length(); |
| 2143 } |
| 2144 |
2111 ProfileFunction* Profile::GetFunction(intptr_t index) { | 2145 ProfileFunction* Profile::GetFunction(intptr_t index) { |
2112 ASSERT(functions_ != NULL); | 2146 ASSERT(functions_ != NULL); |
2113 return functions_->At(index); | 2147 return functions_->At(index); |
2114 } | 2148 } |
2115 | 2149 |
2116 | 2150 |
2117 ProfileCode* Profile::GetCode(intptr_t index) { | 2151 ProfileCode* Profile::GetCode(intptr_t index) { |
2118 ASSERT(live_code_ != NULL); | 2152 ASSERT(live_code_ != NULL); |
2119 ASSERT(dead_code_ != NULL); | 2153 ASSERT(dead_code_ != NULL); |
2120 ASSERT(tag_code_ != NULL); | 2154 ASSERT(tag_code_ != NULL); |
(...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2217 | 2251 |
2218 ProfileTrieNode* trie = sample->timeline_trie(); | 2252 ProfileTrieNode* trie = sample->timeline_trie(); |
2219 ASSERT(trie->frame_id() != -1); | 2253 ASSERT(trie->frame_id() != -1); |
2220 event.AddPropertyF("sf", "%" Pd "-%" Pd, | 2254 event.AddPropertyF("sf", "%" Pd "-%" Pd, |
2221 isolate_id, trie->frame_id()); | 2255 isolate_id, trie->frame_id()); |
2222 } | 2256 } |
2223 } | 2257 } |
2224 } | 2258 } |
2225 | 2259 |
2226 | 2260 |
| 2261 ProfileFunction* Profile::FindFunction(const Function& function) { |
| 2262 const intptr_t index = functions_->LookupIndex(function); |
| 2263 if (index < 0) { |
| 2264 return NULL; |
| 2265 } |
| 2266 return functions_->At(index); |
| 2267 } |
| 2268 |
| 2269 |
2227 void Profile::PrintProfileJSON(JSONStream* stream) { | 2270 void Profile::PrintProfileJSON(JSONStream* stream) { |
2228 ScopeTimer sw("Profile::PrintProfileJSON", FLAG_trace_profiler); | 2271 ScopeTimer sw("Profile::PrintProfileJSON", FLAG_trace_profiler); |
2229 JSONObject obj(stream); | 2272 JSONObject obj(stream); |
2230 obj.AddProperty("type", "_CpuProfile"); | 2273 obj.AddProperty("type", "_CpuProfile"); |
2231 PrintHeaderJSON(&obj); | 2274 PrintHeaderJSON(&obj); |
2232 { | 2275 { |
2233 JSONArray codes(&obj, "codes"); | 2276 JSONArray codes(&obj, "codes"); |
2234 for (intptr_t i = 0; i < live_code_->length(); i++) { | 2277 for (intptr_t i = 0; i < live_code_->length(); i++) { |
2235 ProfileCode* code = live_code_->At(i); | 2278 ProfileCode* code = live_code_->At(i); |
2236 ASSERT(code != NULL); | 2279 ASSERT(code != NULL); |
(...skipping 310 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2547 // Disable thread interrupts while processing the buffer. | 2590 // Disable thread interrupts while processing the buffer. |
2548 DisableThreadInterruptsScope dtis(thread); | 2591 DisableThreadInterruptsScope dtis(thread); |
2549 | 2592 |
2550 ClearProfileVisitor clear_profile(isolate); | 2593 ClearProfileVisitor clear_profile(isolate); |
2551 sample_buffer->VisitSamples(&clear_profile); | 2594 sample_buffer->VisitSamples(&clear_profile); |
2552 } | 2595 } |
2553 | 2596 |
2554 #endif // !PRODUCT | 2597 #endif // !PRODUCT |
2555 | 2598 |
2556 } // namespace dart | 2599 } // namespace dart |
OLD | NEW |