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

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

Issue 1758653003: Add source position information to profile (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: Created 4 years, 9 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
OLDNEW
1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a 2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 #include "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/native_symbol.h" 9 #include "vm/native_symbol.h"
9 #include "vm/object.h" 10 #include "vm/object.h"
10 #include "vm/os.h" 11 #include "vm/os.h"
11 #include "vm/profiler.h" 12 #include "vm/profiler.h"
12 #include "vm/reusable_handles.h" 13 #include "vm/reusable_handles.h"
13 #include "vm/scope_timer.h" 14 #include "vm/scope_timer.h"
14 15
15 namespace dart { 16 namespace dart {
16 17
17 DECLARE_FLAG(int, max_profile_depth); 18 DECLARE_FLAG(int, max_profile_depth);
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after
82 return size; 83 return size;
83 } 84 }
84 85
85 // Array holding code that is being kept around only for the profiler. 86 // Array holding code that is being kept around only for the profiler.
86 const GrowableObjectArray& previous_; 87 const GrowableObjectArray& previous_;
87 // Array holding code that should continue to be kept around for the profiler. 88 // Array holding code that should continue to be kept around for the profiler.
88 const GrowableObjectArray& current_; 89 const GrowableObjectArray& current_;
89 }; 90 };
90 91
91 92
93 ProfileFunctionSourcePosition::ProfileFunctionSourcePosition(
94 TokenPosition token_pos)
95 : token_pos_(token_pos),
96 exclusive_ticks_(0),
97 inclusive_ticks_(0) {
98 }
99
100
101 void ProfileFunctionSourcePosition::Tick(bool exclusive) {
102 if (exclusive) {
103 exclusive_ticks_++;
104 } else {
105 inclusive_ticks_++;
106 }
107 }
108
109
92 ProfileFunction::ProfileFunction(Kind kind, 110 ProfileFunction::ProfileFunction(Kind kind,
93 const char* name, 111 const char* name,
94 const Function& function, 112 const Function& function,
95 const intptr_t table_index) 113 const intptr_t table_index)
96 : kind_(kind), 114 : kind_(kind),
97 name_(name), 115 name_(name),
98 function_(Function::ZoneHandle(function.raw())), 116 function_(Function::ZoneHandle(function.raw())),
99 table_index_(table_index), 117 table_index_(table_index),
100 profile_codes_(0), 118 profile_codes_(0),
119 source_position_ticks_(0),
101 exclusive_ticks_(0), 120 exclusive_ticks_(0),
102 inclusive_ticks_(0), 121 inclusive_ticks_(0),
103 inclusive_serial_(-1) { 122 inclusive_serial_(-1) {
104 ASSERT((kind_ != kDartFunction) || !function_.IsNull()); 123 ASSERT((kind_ != kDartFunction) || !function_.IsNull());
105 ASSERT((kind_ != kDartFunction) || (table_index_ >= 0)); 124 ASSERT((kind_ != kDartFunction) || (table_index_ >= 0));
106 ASSERT(profile_codes_.length() == 0); 125 ASSERT(profile_codes_.length() == 0);
107 } 126 }
108 127
109 128
110 const char* ProfileFunction::Name() const { 129 const char* ProfileFunction::Name() const {
111 if (name_ != NULL) { 130 if (name_ != NULL) {
112 return name_; 131 return name_;
113 } 132 }
114 ASSERT(!function_.IsNull()); 133 ASSERT(!function_.IsNull());
115 const String& func_name = 134 const String& func_name =
116 String::Handle(function_.QualifiedUserVisibleName()); 135 String::Handle(function_.QualifiedUserVisibleName());
117 return func_name.ToCString(); 136 return func_name.ToCString();
118 } 137 }
119 138
120 void ProfileFunction::Tick(bool exclusive, intptr_t inclusive_serial) { 139
140 void ProfileFunction::Tick(bool exclusive,
141 intptr_t inclusive_serial,
142 TokenPosition token_position) {
121 if (exclusive) { 143 if (exclusive) {
122 exclusive_ticks_++; 144 exclusive_ticks_++;
145 TickSourcePosition(token_position, exclusive);
123 } 146 }
124 // Fall through and tick inclusive count too. 147 // Fall through and tick inclusive count too.
125 if (inclusive_serial_ == inclusive_serial) { 148 if (inclusive_serial_ == inclusive_serial) {
126 // Already ticked. 149 // Already ticked.
127 return; 150 return;
128 } 151 }
129 inclusive_serial_ = inclusive_serial; 152 inclusive_serial_ = inclusive_serial;
130 inclusive_ticks_++; 153 inclusive_ticks_++;
154 TickSourcePosition(token_position, false);
131 } 155 }
132 156
133 157
158 void ProfileFunction::TickSourcePosition(TokenPosition token_position,
159 bool exclusive) {
160 for (intptr_t i = 0; i < source_position_ticks_.length(); i++) {
161 ProfileFunctionSourcePosition& position = source_position_ticks_[i];
162 if (position.token_pos() == token_position) {
163 // Found existing position, tick it.
164 position.Tick(exclusive);
165 return;
166 }
167 }
168 // Add new one.
169 ProfileFunctionSourcePosition pfsp(token_position);
170 pfsp.Tick(exclusive);
171 source_position_ticks_.Add(pfsp);
172 }
173
174
134 const char* ProfileFunction::KindToCString(Kind kind) { 175 const char* ProfileFunction::KindToCString(Kind kind) {
135 switch (kind) { 176 switch (kind) {
136 case kDartFunction: 177 case kDartFunction:
137 return "Dart"; 178 return "Dart";
138 case kNativeFunction: 179 case kNativeFunction:
139 return "Native"; 180 return "Native";
140 case kTagFunction: 181 case kTagFunction:
141 return "Tag"; 182 return "Tag";
142 case kStubFunction: 183 case kStubFunction:
143 return "Stub"; 184 return "Stub";
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
182 void ProfileFunction::AddProfileCode(intptr_t code_table_index) { 223 void ProfileFunction::AddProfileCode(intptr_t code_table_index) {
183 for (intptr_t i = 0; i < profile_codes_.length(); i++) { 224 for (intptr_t i = 0; i < profile_codes_.length(); i++) {
184 if (profile_codes_[i] == code_table_index) { 225 if (profile_codes_[i] == code_table_index) {
185 return; 226 return;
186 } 227 }
187 } 228 }
188 profile_codes_.Add(code_table_index); 229 profile_codes_.Add(code_table_index);
189 } 230 }
190 231
191 232
233 bool ProfileFunction::GetSinglePosition(ProfileFunctionSourcePosition* pfsp) {
234 if (pfsp == NULL) {
235 return false;
236 }
237 if (source_position_ticks_.length() != 1) {
238 return false;
239 }
240 *pfsp = source_position_ticks_[0];
241 return true;
242 }
243
244
192 ProfileCodeAddress::ProfileCodeAddress(uword pc) 245 ProfileCodeAddress::ProfileCodeAddress(uword pc)
193 : pc_(pc), 246 : pc_(pc),
194 exclusive_ticks_(0), 247 exclusive_ticks_(0),
195 inclusive_ticks_(0) { 248 inclusive_ticks_(0) {
196 } 249 }
197 250
198 251
199 void ProfileCodeAddress::Tick(bool exclusive) { 252 void ProfileCodeAddress::Tick(bool exclusive) {
200 if (exclusive) { 253 if (exclusive) {
201 exclusive_ticks_++; 254 exclusive_ticks_++;
(...skipping 1179 matching lines...) Expand 10 before | Expand all | Expand 10 after
1381 intptr_t frame_index) { 1434 intptr_t frame_index) {
1382 const uword pc = sample->At(frame_index); 1435 const uword pc = sample->At(frame_index);
1383 ProfileCode* profile_code = GetProfileCode(pc, 1436 ProfileCode* profile_code = GetProfileCode(pc,
1384 sample->timestamp()); 1437 sample->timestamp());
1385 ProfileFunction* function = profile_code->function(); 1438 ProfileFunction* function = profile_code->function();
1386 ASSERT(function != NULL); 1439 ASSERT(function != NULL);
1387 const intptr_t code_index = profile_code->code_table_index(); 1440 const intptr_t code_index = profile_code->code_table_index();
1388 ASSERT(profile_code != NULL); 1441 ASSERT(profile_code != NULL);
1389 const Code& code = Code::ZoneHandle(profile_code->code()); 1442 const Code& code = Code::ZoneHandle(profile_code->code());
1390 GrowableArray<Function*> inlined_functions; 1443 GrowableArray<Function*> inlined_functions;
1444 GrowableArray<TokenPosition> inlined_token_positions;
1445 TokenPosition token_position = TokenPosition::kNoSource;
1391 if (!code.IsNull()) { 1446 if (!code.IsNull()) {
1392 intptr_t offset = pc - code.EntryPoint(); 1447 intptr_t offset = pc - code.EntryPoint();
1393 if (frame_index != 0) { 1448 if (frame_index != 0) {
1394 // The PC of frames below the top frame is a call's return address, 1449 // The PC of frames below the top frame is a call's return address,
1395 // which can belong to a different inlining interval than the call. 1450 // which can belong to a different inlining interval than the call.
1396 offset--; 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--;
1397 } 1456 }
1398 code.GetInlinedFunctionsAt(offset, &inlined_functions); 1457 code.GetInlinedFunctionsAt(offset,
1458 &inlined_functions,
1459 &inlined_token_positions);
1460 token_position = code.GetTokenPositionAt(offset);
1461 if (inlined_functions.length() > 0) {
1462 // The inlined token position table does not include the token position
1463 // of the final call. Insert it at the beginning because the table.
1464 // is reversed.
1465 inlined_token_positions.InsertAt(0, token_position);
1466 }
1467 ASSERT(inlined_functions.length() <= inlined_token_positions.length());
1468 if (FLAG_trace_profiler) {
1469 for (intptr_t i = 0; i < inlined_functions.length(); i++) {
1470 const String& name =
1471 String::Handle(inlined_functions[i]->QualifiedScrubbedName());
1472 THR_Print("InlinedFunction[%" Pd "] = {%s, %s}\n",
1473 i,
1474 name.ToCString(),
1475 inlined_token_positions[i].ToCString());
1476 }
1477 }
1399 } 1478 }
1400 if (code.IsNull() || (inlined_functions.length() == 0)) { 1479 if (code.IsNull() || (inlined_functions.length() == 0)) {
1401 // No inlined functions. 1480 // No inlined functions.
1402 if (inclusive_tree_) { 1481 if (inclusive_tree_) {
1403 current = AppendKind(code, current); 1482 current = AppendKind(code, current);
1404 } 1483 }
1405 current = ProcessFunction(current, 1484 current = ProcessFunction(current,
1406 sample_index, 1485 sample_index,
1407 sample, 1486 sample,
1408 frame_index, 1487 frame_index,
1409 function, 1488 function,
1489 token_position,
1410 code_index); 1490 code_index);
1411 if (!inclusive_tree_) { 1491 if (!inclusive_tree_) {
1412 current = AppendKind(code, current); 1492 current = AppendKind(code, current);
1413 } 1493 }
1414 return current; 1494 return current;
1415 } 1495 }
1416 1496
1417 ASSERT(code.is_optimized()); 1497 ASSERT(code.is_optimized());
1418 1498
1419 if (inclusive_tree_) { 1499 if (inclusive_tree_) {
1420 for (intptr_t i = inlined_functions.length() - 1; i >= 0; i--) { 1500 for (intptr_t i = inlined_functions.length() - 1; i >= 0; i--) {
1421 Function* inlined_function = inlined_functions[i]; 1501 Function* inlined_function = inlined_functions[i];
1422 ASSERT(inlined_function != NULL); 1502 ASSERT(inlined_function != NULL);
1423 ASSERT(!inlined_function->IsNull()); 1503 ASSERT(!inlined_function->IsNull());
1504 TokenPosition inlined_token_position = inlined_token_positions[i];
1424 const bool inliner = i == (inlined_functions.length() - 1); 1505 const bool inliner = i == (inlined_functions.length() - 1);
1425 if (inliner) { 1506 if (inliner) {
1426 current = AppendKind(code, current); 1507 current = AppendKind(code, current);
1427 } 1508 }
1428 current = ProcessInlinedFunction(current, 1509 current = ProcessInlinedFunction(current,
1429 sample_index, 1510 sample_index,
1430 sample, 1511 sample,
1431 frame_index, 1512 frame_index,
1432 inlined_function, 1513 inlined_function,
1514 inlined_token_position,
1433 code_index); 1515 code_index);
1434 if (inliner) { 1516 if (inliner) {
1435 current = AppendKind(kInlineStart, current); 1517 current = AppendKind(kInlineStart, current);
1436 } 1518 }
1437 } 1519 }
1438 current = AppendKind(kInlineFinish, current); 1520 current = AppendKind(kInlineFinish, current);
1439 } else { 1521 } else {
1440 // Append the inlined children. 1522 // Append the inlined children.
1441 current = AppendKind(kInlineFinish, current); 1523 current = AppendKind(kInlineFinish, current);
1442 for (intptr_t i = 0; i < inlined_functions.length(); i++) { 1524 for (intptr_t i = 0; i < inlined_functions.length(); i++) {
1443 Function* inlined_function = inlined_functions[i]; 1525 Function* inlined_function = inlined_functions[i];
1444 ASSERT(inlined_function != NULL); 1526 ASSERT(inlined_function != NULL);
1445 ASSERT(!inlined_function->IsNull()); 1527 ASSERT(!inlined_function->IsNull());
1528 TokenPosition inlined_token_position = inlined_token_positions[i];
1446 const bool inliner = i == (inlined_functions.length() - 1); 1529 const bool inliner = i == (inlined_functions.length() - 1);
1447 if (inliner) { 1530 if (inliner) {
1448 current = AppendKind(kInlineStart, current); 1531 current = AppendKind(kInlineStart, current);
1449 } 1532 }
1450 current = ProcessInlinedFunction(current, 1533 current = ProcessInlinedFunction(current,
1451 sample_index, 1534 sample_index,
1452 sample, 1535 sample,
1453 frame_index + i, 1536 frame_index + i,
1454 inlined_function, 1537 inlined_function,
1538 inlined_token_position,
1455 code_index); 1539 code_index);
1456 if (inliner) { 1540 if (inliner) {
1457 current = AppendKind(code, current); 1541 current = AppendKind(code, current);
1458 } 1542 }
1459 } 1543 }
1460 } 1544 }
1461 1545
1462 return current; 1546 return current;
1463 } 1547 }
1464 1548
1465 ProfileFunctionTrieNode* ProcessInlinedFunction( 1549 ProfileFunctionTrieNode* ProcessInlinedFunction(
1466 ProfileFunctionTrieNode* current, 1550 ProfileFunctionTrieNode* current,
1467 intptr_t sample_index, 1551 intptr_t sample_index,
1468 ProcessedSample* sample, 1552 ProcessedSample* sample,
1469 intptr_t frame_index, 1553 intptr_t frame_index,
1470 Function* inlined_function, 1554 Function* inlined_function,
1555 TokenPosition inlined_token_position,
1471 intptr_t code_index) { 1556 intptr_t code_index) {
1472 ProfileFunctionTable* function_table = profile_->functions_; 1557 ProfileFunctionTable* function_table = profile_->functions_;
1473 ProfileFunction* function = function_table->LookupOrAdd(*inlined_function); 1558 ProfileFunction* function = function_table->LookupOrAdd(*inlined_function);
1474 ASSERT(function != NULL); 1559 ASSERT(function != NULL);
1475 return ProcessFunction(current, 1560 return ProcessFunction(current,
1476 sample_index, 1561 sample_index,
1477 sample, 1562 sample,
1478 frame_index, 1563 frame_index,
1479 function, 1564 function,
1565 inlined_token_position,
1480 code_index); 1566 code_index);
1481 } 1567 }
1482 1568
1483 bool ShouldTickNode(ProcessedSample* sample, intptr_t frame_index) { 1569 bool ShouldTickNode(ProcessedSample* sample, intptr_t frame_index) {
1484 if (frame_index != 0) { 1570 if (frame_index != 0) {
1485 return true; 1571 return true;
1486 } 1572 }
1487 // Only tick the first frame's node, if we are executing OR 1573 // Only tick the first frame's node, if we are executing OR
1488 // vm tags have been emitted. 1574 // vm tags have been emitted.
1489 return IsExecutingFrame(sample, frame_index) || vm_tags_emitted(); 1575 return IsExecutingFrame(sample, frame_index) || vm_tags_emitted();
1490 } 1576 }
1491 1577
1492 ProfileFunctionTrieNode* ProcessFunction(ProfileFunctionTrieNode* current, 1578 ProfileFunctionTrieNode* ProcessFunction(ProfileFunctionTrieNode* current,
1493 intptr_t sample_index, 1579 intptr_t sample_index,
1494 ProcessedSample* sample, 1580 ProcessedSample* sample,
1495 intptr_t frame_index, 1581 intptr_t frame_index,
1496 ProfileFunction* function, 1582 ProfileFunction* function,
1583 TokenPosition token_position,
1497 intptr_t code_index) { 1584 intptr_t code_index) {
1585 if (FLAG_trace_profiler) {
1586 THR_Print("S[%" Pd "]F[%" Pd "] %s %s\n",
1587 sample_index,
1588 frame_index,
1589 function->Name(), token_position.ToCString());
1590 }
1498 if (tick_functions_) { 1591 if (tick_functions_) {
1499 function->Tick(IsExecutingFrame(sample, frame_index), sample_index); 1592 function->Tick(IsExecutingFrame(sample, frame_index),
1593 sample_index,
1594 token_position);
1500 } 1595 }
1501 function->AddProfileCode(code_index); 1596 function->AddProfileCode(code_index);
1502 current = current->GetChild(function->table_index()); 1597 current = current->GetChild(function->table_index());
1503 if (ShouldTickNode(sample, frame_index)) { 1598 if (ShouldTickNode(sample, frame_index)) {
1504 current->Tick(); 1599 current->Tick();
1505 } 1600 }
1506 current->AddCodeObjectIndex(code_index); 1601 current->AddCodeObjectIndex(code_index);
1507 return current; 1602 return current;
1508 } 1603 }
1509 1604
(...skipping 727 matching lines...) Expand 10 before | Expand all | Expand 10 after
2237 ProfileCode* code = profile_->GetCode(current_->table_index()); 2332 ProfileCode* code = profile_->GetCode(current_->table_index());
2238 return code->exclusive_ticks(); 2333 return code->exclusive_ticks();
2239 } else { 2334 } else {
2240 ProfileFunction* func = profile_->GetFunction(current_->table_index()); 2335 ProfileFunction* func = profile_->GetFunction(current_->table_index());
2241 return func->exclusive_ticks(); 2336 return func->exclusive_ticks();
2242 } 2337 }
2243 UNREACHABLE(); 2338 UNREACHABLE();
2244 } 2339 }
2245 2340
2246 2341
2342 const char* ProfileTrieWalker::CurrentToken() {
2343 if (current_ == NULL) {
2344 return NULL;
2345 }
2346 if (code_trie_) {
2347 return NULL;
2348 }
2349 ProfileFunction* func = profile_->GetFunction(current_->table_index());
2350 const Function& function = Function::Handle(func->function());
2351 if (function.IsNull()) {
2352 // No function.
2353 return NULL;
2354 }
2355 const Script& script = Script::Handle(function.script());
2356 if (script.IsNull()) {
2357 // No script.
2358 return NULL;
2359 }
2360 const TokenStream& token_stream = TokenStream::Handle(script.tokens());
2361 if (token_stream.IsNull()) {
2362 // No token position.
2363 return NULL;
2364 }
2365 ProfileFunctionSourcePosition pfsp(TokenPosition::kNoSource);
2366 if (!func->GetSinglePosition(&pfsp)) {
2367 // Not exactly one source position.
2368 return NULL;
2369 }
2370 TokenPosition token_pos = pfsp.token_pos();
2371 if (!token_pos.IsReal() && !token_pos.IsSynthetic()) {
2372 // Not a location in a script.
2373 return NULL;
2374 }
2375 if (token_pos.IsSynthetic()) {
2376 token_pos = token_pos.FromSynthetic();
2377 }
2378 TokenStream::Iterator iterator(token_stream, token_pos);
2379 const String& str = String::Handle(iterator.CurrentLiteral());
2380 if (str.IsNull()) {
2381 return NULL;
2382 }
2383 return str.ToCString();
2384 }
2385
2247 bool ProfileTrieWalker::Down() { 2386 bool ProfileTrieWalker::Down() {
2248 if ((current_ == NULL) || (current_->NumChildren() == 0)) { 2387 if ((current_ == NULL) || (current_->NumChildren() == 0)) {
2249 return false; 2388 return false;
2250 } 2389 }
2251 parent_ = current_; 2390 parent_ = current_;
2252 current_ = current_->At(0); 2391 current_ = current_->At(0);
2253 return true; 2392 return true;
2254 } 2393 }
2255 2394
2256 2395
(...skipping 146 matching lines...) Expand 10 before | Expand all | Expand 10 after
2403 // Disable thread interrupts while processing the buffer. 2542 // Disable thread interrupts while processing the buffer.
2404 DisableThreadInterruptsScope dtis(thread); 2543 DisableThreadInterruptsScope dtis(thread);
2405 2544
2406 ClearProfileVisitor clear_profile(isolate); 2545 ClearProfileVisitor clear_profile(isolate);
2407 sample_buffer->VisitSamples(&clear_profile); 2546 sample_buffer->VisitSamples(&clear_profile);
2408 } 2547 }
2409 2548
2410 #endif // !PRODUCT 2549 #endif // !PRODUCT
2411 2550
2412 } // namespace dart 2551 } // namespace dart
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698