| 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 144 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 155 if (!FLAG_profile) { | 155 if (!FLAG_profile) { |
| 156 return; | 156 return; |
| 157 } | 157 } |
| 158 ASSERT(initialized_); | 158 ASSERT(initialized_); |
| 159 ThreadInterrupter::Unregister(); | 159 ThreadInterrupter::Unregister(); |
| 160 } | 160 } |
| 161 | 161 |
| 162 | 162 |
| 163 struct AddressEntry { | 163 struct AddressEntry { |
| 164 uword pc; | 164 uword pc; |
| 165 intptr_t ticks; | 165 intptr_t exclusive_ticks; |
| 166 intptr_t inclusive_ticks; |
| 167 |
| 168 void tick(bool exclusive) { |
| 169 if (exclusive) { |
| 170 exclusive_ticks++; |
| 171 } else { |
| 172 inclusive_ticks++; |
| 173 } |
| 174 } |
| 175 }; |
| 176 |
| 177 struct CallEntry { |
| 178 intptr_t code_table_index; |
| 179 intptr_t count; |
| 166 }; | 180 }; |
| 167 | 181 |
| 168 typedef bool (*RegionCompare)(uword pc, uword region_start, uword region_end); | 182 typedef bool (*RegionCompare)(uword pc, uword region_start, uword region_end); |
| 169 | 183 |
| 170 // A region of code. Each region is a kind of code (Dart, Collected, or Native). | 184 // A region of code. Each region is a kind of code (Dart, Collected, or Native). |
| 171 class CodeRegion : public ZoneAllocated { | 185 class CodeRegion : public ZoneAllocated { |
| 172 public: | 186 public: |
| 173 enum Kind { | 187 enum Kind { |
| 174 kDartCode, | 188 kDartCode, |
| 175 kCollectedCode, | 189 kCollectedCode, |
| 176 kNativeCode | 190 kNativeCode |
| 177 }; | 191 }; |
| 178 | 192 |
| 179 CodeRegion(Kind kind, uword start, uword end) : | 193 CodeRegion(Kind kind, uword start, uword end) : |
| 180 kind_(kind), | 194 kind_(kind), |
| 181 start_(start), | 195 start_(start), |
| 182 end_(end), | 196 end_(end), |
| 183 inclusive_ticks_(0), | 197 inclusive_ticks_(0), |
| 184 exclusive_ticks_(0), | 198 exclusive_ticks_(0), |
| 185 name_(NULL), | 199 name_(NULL), |
| 186 address_table_(new ZoneGrowableArray<AddressEntry>()) { | 200 address_table_(new ZoneGrowableArray<AddressEntry>()), |
| 201 callers_table_(new ZoneGrowableArray<CallEntry>()), |
| 202 callees_table_(new ZoneGrowableArray<CallEntry>()) { |
| 187 ASSERT(start_ < end_); | 203 ASSERT(start_ < end_); |
| 188 } | 204 } |
| 189 | 205 |
| 190 ~CodeRegion() { | 206 ~CodeRegion() { |
| 191 } | 207 } |
| 192 | 208 |
| 193 uword start() const { return start_; } | 209 uword start() const { return start_; } |
| 194 void set_start(uword start) { | 210 void set_start(uword start) { |
| 195 start_ = start; | 211 start_ = start; |
| 196 } | 212 } |
| (...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 251 return "Dart"; | 267 return "Dart"; |
| 252 case kCollectedCode: | 268 case kCollectedCode: |
| 253 return "Collected"; | 269 return "Collected"; |
| 254 case kNativeCode: | 270 case kNativeCode: |
| 255 return "Native"; | 271 return "Native"; |
| 256 } | 272 } |
| 257 UNREACHABLE(); | 273 UNREACHABLE(); |
| 258 return NULL; | 274 return NULL; |
| 259 } | 275 } |
| 260 | 276 |
| 261 void AddTick(bool exclusive) { | |
| 262 if (exclusive) { | |
| 263 exclusive_ticks_++; | |
| 264 } else { | |
| 265 inclusive_ticks_++; | |
| 266 } | |
| 267 } | |
| 268 | |
| 269 void DebugPrint() const { | 277 void DebugPrint() const { |
| 270 printf("%s [%" Px ", %" Px ") %s\n", KindToCString(kind_), start(), end(), | 278 printf("%s [%" Px ", %" Px ") %s\n", KindToCString(kind_), start(), end(), |
| 271 name_); | 279 name_); |
| 272 } | 280 } |
| 273 | 281 |
| 274 void AddTickAtAddress(uword pc) { | 282 void AddTickAtAddress(uword pc, bool exclusive, intptr_t serial) { |
| 283 // Assert that exclusive ticks are never passed a valid serial number. |
| 284 ASSERT((exclusive && (serial == -1)) || (!exclusive && (serial != -1))); |
| 285 if (!exclusive && (inclusive_tick_serial_ == serial)) { |
| 286 // We've already given this code object an inclusive tick for this sample. |
| 287 return; |
| 288 } |
| 289 // Tick the code object. |
| 290 if (exclusive) { |
| 291 exclusive_ticks_++; |
| 292 } else { |
| 293 // Mark the last serial we ticked the inclusive count. |
| 294 inclusive_tick_serial_ = serial; |
| 295 inclusive_ticks_++; |
| 296 } |
| 297 // Tick the address entry. |
| 275 const intptr_t length = address_table_->length(); | 298 const intptr_t length = address_table_->length(); |
| 276 intptr_t i = 0; | 299 intptr_t i = 0; |
| 277 for (; i < length; i++) { | 300 for (; i < length; i++) { |
| 278 AddressEntry& entry = (*address_table_)[i]; | 301 AddressEntry& entry = (*address_table_)[i]; |
| 279 if (entry.pc == pc) { | 302 if (entry.pc == pc) { |
| 280 entry.ticks++; | 303 entry.tick(exclusive); |
| 281 return; | 304 return; |
| 282 } | 305 } |
| 283 if (entry.pc > pc) { | 306 if (entry.pc > pc) { |
| 284 break; | 307 break; |
| 285 } | 308 } |
| 286 } | 309 } |
| 287 AddressEntry entry; | 310 AddressEntry entry; |
| 288 entry.pc = pc; | 311 entry.pc = pc; |
| 289 entry.ticks = 1; | 312 entry.tick(exclusive); |
| 290 if (i < length) { | 313 if (i < length) { |
| 291 // Insert at i. | 314 // Insert at i. |
| 292 address_table_->InsertAt(i, entry); | 315 address_table_->InsertAt(i, entry); |
| 293 } else { | 316 } else { |
| 294 // Add to end. | 317 // Add to end. |
| 295 address_table_->Add(entry); | 318 address_table_->Add(entry); |
| 296 } | 319 } |
| 297 } | 320 } |
| 298 | 321 |
| 322 void AddCaller(intptr_t index) { |
| 323 AddCallEntry(callers_table_, index); |
| 324 } |
| 325 |
| 326 void AddCallee(intptr_t index) { |
| 327 AddCallEntry(callees_table_, index); |
| 328 } |
| 299 | 329 |
| 300 void PrintToJSONArray(JSONArray* events, bool full) { | 330 void PrintToJSONArray(JSONArray* events, bool full) { |
| 301 JSONObject obj(events); | 331 JSONObject obj(events); |
| 302 obj.AddProperty("type", "ProfileCode"); | 332 obj.AddProperty("type", "ProfileCode"); |
| 303 obj.AddProperty("kind", KindToCString(kind())); | 333 obj.AddProperty("kind", KindToCString(kind())); |
| 304 obj.AddPropertyF("inclusive_ticks", "%" Pd "", inclusive_ticks()); | 334 obj.AddPropertyF("inclusive_ticks", "%" Pd "", inclusive_ticks()); |
| 305 obj.AddPropertyF("exclusive_ticks", "%" Pd "", exclusive_ticks()); | 335 obj.AddPropertyF("exclusive_ticks", "%" Pd "", exclusive_ticks()); |
| 306 if (kind() == kDartCode) { | 336 if (kind() == kDartCode) { |
| 307 // Look up code in Dart heap. | 337 // Look up code in Dart heap. |
| 308 Code& code = Code::Handle(Code::LookupCode(start())); | 338 Code& code = Code::Handle(Code::LookupCode(start())); |
| (...skipping 24 matching lines...) Expand all Loading... |
| 333 } | 363 } |
| 334 obj.AddPropertyF("start", "%" Px "", start()); | 364 obj.AddPropertyF("start", "%" Px "", start()); |
| 335 obj.AddPropertyF("end", "%" Px "", end()); | 365 obj.AddPropertyF("end", "%" Px "", end()); |
| 336 obj.AddProperty("name", name()); | 366 obj.AddProperty("name", name()); |
| 337 } | 367 } |
| 338 { | 368 { |
| 339 JSONArray ticks(&obj, "ticks"); | 369 JSONArray ticks(&obj, "ticks"); |
| 340 for (intptr_t i = 0; i < address_table_->length(); i++) { | 370 for (intptr_t i = 0; i < address_table_->length(); i++) { |
| 341 const AddressEntry& entry = (*address_table_)[i]; | 371 const AddressEntry& entry = (*address_table_)[i]; |
| 342 ticks.AddValueF("%" Px "", entry.pc); | 372 ticks.AddValueF("%" Px "", entry.pc); |
| 343 ticks.AddValueF("%" Pd "", entry.ticks); | 373 ticks.AddValueF("%" Pd "", entry.exclusive_ticks); |
| 374 ticks.AddValueF("%" Pd "", entry.inclusive_ticks); |
| 375 } |
| 376 } |
| 377 { |
| 378 JSONArray callers(&obj, "callers"); |
| 379 for (intptr_t i = 0; i < callers_table_->length(); i++) { |
| 380 const CallEntry& entry = (*callers_table_)[i]; |
| 381 callers.AddValueF("%" Pd "", entry.code_table_index); |
| 382 callers.AddValueF("%" Pd "", entry.count); |
| 383 } |
| 384 } |
| 385 { |
| 386 JSONArray callees(&obj, "callees"); |
| 387 for (intptr_t i = 0; i < callees_table_->length(); i++) { |
| 388 const CallEntry& entry = (*callees_table_)[i]; |
| 389 callees.AddValueF("%" Pd "", entry.code_table_index); |
| 390 callees.AddValueF("%" Pd "", entry.count); |
| 344 } | 391 } |
| 345 } | 392 } |
| 346 } | 393 } |
| 347 | 394 |
| 348 private: | 395 private: |
| 396 void AddCallEntry(ZoneGrowableArray<CallEntry>* table, intptr_t index) { |
| 397 const intptr_t length = table->length(); |
| 398 intptr_t i = 0; |
| 399 for (; i < length; i++) { |
| 400 CallEntry& entry = (*table)[i]; |
| 401 if (entry.code_table_index == index) { |
| 402 entry.count++; |
| 403 return; |
| 404 } |
| 405 if (entry.code_table_index > index) { |
| 406 break; |
| 407 } |
| 408 } |
| 409 CallEntry entry; |
| 410 entry.code_table_index = index; |
| 411 entry.count = 1; |
| 412 if (i < length) { |
| 413 table->InsertAt(i, entry); |
| 414 } else { |
| 415 table->Add(entry); |
| 416 } |
| 417 } |
| 418 |
| 349 void GenerateAndSetSymbolName(const char* prefix) { | 419 void GenerateAndSetSymbolName(const char* prefix) { |
| 350 const intptr_t kBuffSize = 512; | 420 const intptr_t kBuffSize = 512; |
| 351 char buff[kBuffSize]; | 421 char buff[kBuffSize]; |
| 352 OS::SNPrint(&buff[0], kBuffSize-1, "%s [%" Px ", %" Px ")", | 422 OS::SNPrint(&buff[0], kBuffSize-1, "%s [%" Px ", %" Px ")", |
| 353 prefix, start(), end()); | 423 prefix, start(), end()); |
| 354 SetName(buff); | 424 SetName(buff); |
| 355 } | 425 } |
| 356 | 426 |
| 357 Kind kind_; | 427 Kind kind_; |
| 358 uword start_; | 428 uword start_; |
| 359 uword end_; | 429 uword end_; |
| 360 intptr_t inclusive_ticks_; | 430 intptr_t inclusive_ticks_; |
| 361 intptr_t exclusive_ticks_; | 431 intptr_t exclusive_ticks_; |
| 432 intptr_t inclusive_tick_serial_; |
| 362 const char* name_; | 433 const char* name_; |
| 363 ZoneGrowableArray<AddressEntry>* address_table_; | 434 ZoneGrowableArray<AddressEntry>* address_table_; |
| 364 | 435 ZoneGrowableArray<CallEntry>* callers_table_; |
| 436 ZoneGrowableArray<CallEntry>* callees_table_; |
| 365 DISALLOW_COPY_AND_ASSIGN(CodeRegion); | 437 DISALLOW_COPY_AND_ASSIGN(CodeRegion); |
| 366 }; | 438 }; |
| 367 | 439 |
| 368 | 440 |
| 369 class ScopeStopwatch : public ValueObject { | 441 class ScopeStopwatch : public ValueObject { |
| 370 public: | 442 public: |
| 371 explicit ScopeStopwatch(const char* name) : name_(name) { | 443 explicit ScopeStopwatch(const char* name) : name_(name) { |
| 372 start_ = OS::GetCurrentTimeMillis(); | 444 start_ = OS::GetCurrentTimeMillis(); |
| 373 } | 445 } |
| 374 | 446 |
| (...skipping 21 matching lines...) Expand all Loading... |
| 396 class ProfilerCodeRegionTable : public ValueObject { | 468 class ProfilerCodeRegionTable : public ValueObject { |
| 397 public: | 469 public: |
| 398 explicit ProfilerCodeRegionTable(Isolate* isolate) : | 470 explicit ProfilerCodeRegionTable(Isolate* isolate) : |
| 399 heap_(isolate->heap()), | 471 heap_(isolate->heap()), |
| 400 code_region_table_(new ZoneGrowableArray<CodeRegion*>(64)) { | 472 code_region_table_(new ZoneGrowableArray<CodeRegion*>(64)) { |
| 401 } | 473 } |
| 402 | 474 |
| 403 ~ProfilerCodeRegionTable() { | 475 ~ProfilerCodeRegionTable() { |
| 404 } | 476 } |
| 405 | 477 |
| 406 void AddTick(uword pc, bool exclusive, bool tick_address) { | 478 void AddTick(uword pc, bool exclusive, intptr_t serial) { |
| 407 intptr_t index = FindIndex(pc); | 479 intptr_t index = FindIndex(pc); |
| 408 if (index < 0) { | 480 if (index < 0) { |
| 409 CodeRegion* code_region = CreateCodeRegion(pc); | 481 CodeRegion* code_region = CreateCodeRegion(pc); |
| 410 ASSERT(code_region != NULL); | 482 ASSERT(code_region != NULL); |
| 411 index = InsertCodeRegion(code_region); | 483 index = InsertCodeRegion(code_region); |
| 412 } | 484 } |
| 413 ASSERT(index >= 0); | 485 ASSERT(index >= 0); |
| 414 ASSERT(index < code_region_table_->length()); | 486 ASSERT(index < code_region_table_->length()); |
| 415 (*code_region_table_)[index]->AddTick(exclusive); | 487 |
| 416 if (tick_address) { | 488 // Update code object counters. |
| 417 (*code_region_table_)[index]->AddTickAtAddress(pc); | 489 (*code_region_table_)[index]->AddTickAtAddress(pc, exclusive, serial); |
| 418 } | |
| 419 } | 490 } |
| 420 | 491 |
| 421 intptr_t Length() const { return code_region_table_->length(); } | 492 intptr_t Length() const { return code_region_table_->length(); } |
| 422 | 493 |
| 423 CodeRegion* At(intptr_t idx) { | 494 CodeRegion* At(intptr_t idx) { |
| 424 return (*code_region_table_)[idx]; | 495 return (*code_region_table_)[idx]; |
| 425 } | 496 } |
| 426 | 497 |
| 498 intptr_t FindIndex(uword pc) const { |
| 499 intptr_t index = FindRegionIndex(pc, &CompareLowerBound); |
| 500 const CodeRegion* code_region = NULL; |
| 501 if (index == code_region_table_->length()) { |
| 502 // Not present. |
| 503 return -1; |
| 504 } |
| 505 code_region = (*code_region_table_)[index]; |
| 506 if (code_region->contains(pc)) { |
| 507 // Found at index. |
| 508 return index; |
| 509 } |
| 510 return -1; |
| 511 } |
| 512 |
| 427 #if defined(DEBUG) | 513 #if defined(DEBUG) |
| 428 void Verify() { | 514 void Verify() { |
| 429 VerifyOrder(); | 515 VerifyOrder(); |
| 430 VerifyOverlap(); | 516 VerifyOverlap(); |
| 431 } | 517 } |
| 432 #endif | 518 #endif |
| 433 | 519 |
| 434 private: | 520 private: |
| 435 intptr_t FindRegionIndex(uword pc, RegionCompare comparator) { | 521 intptr_t FindRegionIndex(uword pc, RegionCompare comparator) const { |
| 436 ASSERT(comparator != NULL); | 522 ASSERT(comparator != NULL); |
| 437 intptr_t count = code_region_table_->length(); | 523 intptr_t count = code_region_table_->length(); |
| 438 intptr_t first = 0; | 524 intptr_t first = 0; |
| 439 while (count > 0) { | 525 while (count > 0) { |
| 440 intptr_t it = first; | 526 intptr_t it = first; |
| 441 intptr_t step = count / 2; | 527 intptr_t step = count / 2; |
| 442 it += step; | 528 it += step; |
| 443 const CodeRegion* code_region = (*code_region_table_)[it]; | 529 const CodeRegion* code_region = (*code_region_table_)[it]; |
| 444 if (comparator(pc, code_region->start(), code_region->end())) { | 530 if (comparator(pc, code_region->start(), code_region->end())) { |
| 445 first = ++it; | 531 first = ++it; |
| 446 count -= (step + 1); | 532 count -= (step + 1); |
| 447 } else { | 533 } else { |
| 448 count = step; | 534 count = step; |
| 449 } | 535 } |
| 450 } | 536 } |
| 451 return first; | 537 return first; |
| 452 } | 538 } |
| 453 | 539 |
| 454 static bool CompareUpperBound(uword pc, uword start, uword end) { | 540 static bool CompareUpperBound(uword pc, uword start, uword end) { |
| 455 return pc >= end; | 541 return pc >= end; |
| 456 } | 542 } |
| 457 | 543 |
| 458 static bool CompareLowerBound(uword pc, uword start, uword end) { | 544 static bool CompareLowerBound(uword pc, uword start, uword end) { |
| 459 return end <= pc; | 545 return end <= pc; |
| 460 } | 546 } |
| 461 | 547 |
| 462 intptr_t FindIndex(uword pc) { | |
| 463 intptr_t index = FindRegionIndex(pc, &CompareLowerBound); | |
| 464 const CodeRegion* code_region = NULL; | |
| 465 if (index == code_region_table_->length()) { | |
| 466 // Not present. | |
| 467 return -1; | |
| 468 } | |
| 469 code_region = (*code_region_table_)[index]; | |
| 470 if (code_region->contains(pc)) { | |
| 471 // Found at index. | |
| 472 return index; | |
| 473 } | |
| 474 return -1; | |
| 475 } | |
| 476 | |
| 477 CodeRegion* CreateCodeRegion(uword pc) { | 548 CodeRegion* CreateCodeRegion(uword pc) { |
| 478 Code& code = Code::Handle(Code::LookupCode(pc)); | 549 Code& code = Code::Handle(Code::LookupCode(pc)); |
| 479 if (!code.IsNull()) { | 550 if (!code.IsNull()) { |
| 480 return new CodeRegion(CodeRegion::kDartCode, code.EntryPoint(), | 551 return new CodeRegion(CodeRegion::kDartCode, code.EntryPoint(), |
| 481 code.EntryPoint() + code.Size()); | 552 code.EntryPoint() + code.Size()); |
| 482 } | 553 } |
| 483 if (heap_->CodeContains(pc)) { | 554 if (heap_->CodeContains(pc)) { |
| 484 const intptr_t kDartCodeAlignment = 0x10; | 555 const intptr_t kDartCodeAlignment = 0x10; |
| 485 const intptr_t kDartCodeAlignmentMask = ~(kDartCodeAlignment - 1); | 556 const intptr_t kDartCodeAlignmentMask = ~(kDartCodeAlignment - 1); |
| 486 return new CodeRegion(CodeRegion::kCollectedCode, pc, | 557 return new CodeRegion(CodeRegion::kCollectedCode, pc, |
| (...skipping 113 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 600 | 671 |
| 601 class CodeRegionTableBuilder : public SampleVisitor { | 672 class CodeRegionTableBuilder : public SampleVisitor { |
| 602 public: | 673 public: |
| 603 CodeRegionTableBuilder(Isolate* isolate, | 674 CodeRegionTableBuilder(Isolate* isolate, |
| 604 ProfilerCodeRegionTable* code_region_table) | 675 ProfilerCodeRegionTable* code_region_table) |
| 605 : SampleVisitor(isolate), code_region_table_(code_region_table) { | 676 : SampleVisitor(isolate), code_region_table_(code_region_table) { |
| 606 frames_ = 0; | 677 frames_ = 0; |
| 607 } | 678 } |
| 608 | 679 |
| 609 void VisitSample(Sample* sample) { | 680 void VisitSample(Sample* sample) { |
| 610 code_region_table_->AddTick(sample->At(0), true, false); | 681 // Give the bottom frame an exclusive tick. |
| 611 // Give all frames an inclusive tick and tick the address. | 682 code_region_table_->AddTick(sample->At(0), true, -1); |
| 683 // Give all frames (including the bottom) an inclusive tick. |
| 612 for (intptr_t i = 0; i < FLAG_profile_depth; i++) { | 684 for (intptr_t i = 0; i < FLAG_profile_depth; i++) { |
| 613 if (sample->At(i) == 0) { | 685 if (sample->At(i) == 0) { |
| 614 break; | 686 break; |
| 615 } | 687 } |
| 616 frames_++; | 688 frames_++; |
| 617 code_region_table_->AddTick(sample->At(i), false, true); | 689 code_region_table_->AddTick(sample->At(i), false, visited()); |
| 618 } | 690 } |
| 619 } | 691 } |
| 620 | 692 |
| 621 intptr_t frames() const { return frames_; } | 693 intptr_t frames() const { return frames_; } |
| 694 |
| 622 private: | 695 private: |
| 623 intptr_t frames_; | 696 intptr_t frames_; |
| 624 ProfilerCodeRegionTable* code_region_table_; | 697 ProfilerCodeRegionTable* code_region_table_; |
| 625 }; | 698 }; |
| 626 | 699 |
| 627 | 700 |
| 701 class CodeRegionTableCallersBuilder : public SampleVisitor { |
| 702 public: |
| 703 CodeRegionTableCallersBuilder(Isolate* isolate, |
| 704 ProfilerCodeRegionTable* code_region_table) |
| 705 : SampleVisitor(isolate), code_region_table_(code_region_table) { |
| 706 ASSERT(code_region_table_ != NULL); |
| 707 } |
| 708 |
| 709 void VisitSample(Sample* sample) { |
| 710 intptr_t current_index = code_region_table_->FindIndex(sample->At(0)); |
| 711 ASSERT(current_index != -1); |
| 712 CodeRegion* current = code_region_table_->At(current_index); |
| 713 intptr_t caller_index = -1; |
| 714 CodeRegion* caller = NULL; |
| 715 intptr_t callee_index = -1; |
| 716 CodeRegion* callee = NULL; |
| 717 for (intptr_t i = 1; i < FLAG_profile_depth; i++) { |
| 718 if (sample->At(i) == 0) { |
| 719 break; |
| 720 } |
| 721 caller_index = code_region_table_->FindIndex(sample->At(i)); |
| 722 ASSERT(caller_index != -1); |
| 723 caller = code_region_table_->At(caller_index); |
| 724 current->AddCaller(caller_index); |
| 725 if (callee != NULL) { |
| 726 current->AddCallee(callee_index); |
| 727 } |
| 728 // Move cursors. |
| 729 callee_index = current_index; |
| 730 callee = current; |
| 731 current_index = caller_index; |
| 732 current = caller; |
| 733 } |
| 734 } |
| 735 |
| 736 private: |
| 737 ProfilerCodeRegionTable* code_region_table_; |
| 738 }; |
| 739 |
| 628 void Profiler::PrintToJSONStream(Isolate* isolate, JSONStream* stream, | 740 void Profiler::PrintToJSONStream(Isolate* isolate, JSONStream* stream, |
| 629 bool full) { | 741 bool full) { |
| 630 ASSERT(isolate == Isolate::Current()); | 742 ASSERT(isolate == Isolate::Current()); |
| 631 // Disable profile interrupts while processing the buffer. | 743 // Disable profile interrupts while processing the buffer. |
| 632 EndExecution(isolate); | 744 EndExecution(isolate); |
| 633 MutexLocker profiler_data_lock(isolate->profiler_data_mutex()); | 745 MutexLocker profiler_data_lock(isolate->profiler_data_mutex()); |
| 634 IsolateProfilerData* profiler_data = isolate->profiler_data(); | 746 IsolateProfilerData* profiler_data = isolate->profiler_data(); |
| 635 if (profiler_data == NULL) { | 747 if (profiler_data == NULL) { |
| 636 JSONObject error(stream); | 748 JSONObject error(stream); |
| 637 error.AddProperty("type", "Error"); | 749 error.AddProperty("type", "Error"); |
| 638 error.AddProperty("text", "Isolate does not have profiling enabled."); | 750 error.AddProperty("text", "Isolate does not have profiling enabled."); |
| 639 return; | 751 return; |
| 640 } | 752 } |
| 641 SampleBuffer* sample_buffer = profiler_data->sample_buffer(); | 753 SampleBuffer* sample_buffer = profiler_data->sample_buffer(); |
| 642 ASSERT(sample_buffer != NULL); | 754 ASSERT(sample_buffer != NULL); |
| 643 { | 755 { |
| 644 StackZone zone(isolate); | 756 StackZone zone(isolate); |
| 645 { | 757 { |
| 646 // Build code region table. | 758 // Build code region table. |
| 647 ProfilerCodeRegionTable code_region_table(isolate); | 759 ProfilerCodeRegionTable code_region_table(isolate); |
| 648 CodeRegionTableBuilder builder(isolate, &code_region_table); | 760 CodeRegionTableBuilder builder(isolate, &code_region_table); |
| 761 CodeRegionTableCallersBuilder build_callers(isolate, &code_region_table); |
| 649 { | 762 { |
| 650 ScopeStopwatch sw("CodeTableBuild"); | 763 ScopeStopwatch sw("CodeTableBuild"); |
| 651 sample_buffer->VisitSamples(&builder); | 764 sample_buffer->VisitSamples(&builder); |
| 652 } | 765 } |
| 653 #if defined(DEBUG) | 766 #if defined(DEBUG) |
| 654 code_region_table.Verify(); | 767 code_region_table.Verify(); |
| 655 #endif | 768 #endif |
| 769 { |
| 770 ScopeStopwatch sw("CodeTableCallersBuild"); |
| 771 sample_buffer->VisitSamples(&build_callers); |
| 772 } |
| 656 // Number of samples we processed. | 773 // Number of samples we processed. |
| 657 intptr_t samples = builder.visited(); | 774 intptr_t samples = builder.visited(); |
| 658 intptr_t frames = builder.frames(); | 775 intptr_t frames = builder.frames(); |
| 659 if (FLAG_trace_profiled_isolates) { | 776 if (FLAG_trace_profiled_isolates) { |
| 660 OS::Print("%" Pd " frames produced %" Pd " code objects.\n", | 777 OS::Print("%" Pd " frames produced %" Pd " code objects.\n", |
| 661 frames, code_region_table.Length()); | 778 frames, code_region_table.Length()); |
| 662 } | 779 } |
| 663 { | 780 { |
| 664 ScopeStopwatch sw("CodeTableStream"); | 781 ScopeStopwatch sw("CodeTableStream"); |
| 665 // Serialize to JSON. | 782 // Serialize to JSON. |
| (...skipping 207 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 873 stack_lower = 0; | 990 stack_lower = 0; |
| 874 stack_upper = 0; | 991 stack_upper = 0; |
| 875 } | 992 } |
| 876 ProfilerSampleStackWalker stackWalker(sample, stack_lower, stack_upper, | 993 ProfilerSampleStackWalker stackWalker(sample, stack_lower, stack_upper, |
| 877 state.pc, state.fp, state.sp); | 994 state.pc, state.fp, state.sp); |
| 878 stackWalker.walk(); | 995 stackWalker.walk(); |
| 879 } | 996 } |
| 880 | 997 |
| 881 | 998 |
| 882 } // namespace dart | 999 } // namespace dart |
| OLD | NEW |