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 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) { |
| 283 // Tick the code object. | |
| 284 if (exclusive) { | |
| 285 exclusive_ticks_++; | |
| 286 } else { | |
| 287 inclusive_ticks_++; | |
| 288 } | |
| 289 // Tick the address entry. | |
| 275 const intptr_t length = address_table_->length(); | 290 const intptr_t length = address_table_->length(); |
| 276 intptr_t i = 0; | 291 intptr_t i = 0; |
| 277 for (; i < length; i++) { | 292 for (; i < length; i++) { |
| 278 AddressEntry& entry = (*address_table_)[i]; | 293 AddressEntry& entry = (*address_table_)[i]; |
| 279 if (entry.pc == pc) { | 294 if (entry.pc == pc) { |
| 280 entry.ticks++; | 295 entry.tick(exclusive); |
| 281 return; | 296 return; |
| 282 } | 297 } |
| 283 if (entry.pc > pc) { | 298 if (entry.pc > pc) { |
| 284 break; | 299 break; |
| 285 } | 300 } |
| 286 } | 301 } |
| 287 AddressEntry entry; | 302 AddressEntry entry; |
| 288 entry.pc = pc; | 303 entry.pc = pc; |
| 289 entry.ticks = 1; | 304 entry.tick(exclusive); |
| 290 if (i < length) { | 305 if (i < length) { |
| 291 // Insert at i. | 306 // Insert at i. |
| 292 address_table_->InsertAt(i, entry); | 307 address_table_->InsertAt(i, entry); |
| 293 } else { | 308 } else { |
| 294 // Add to end. | 309 // Add to end. |
| 295 address_table_->Add(entry); | 310 address_table_->Add(entry); |
| 296 } | 311 } |
| 297 } | 312 } |
| 298 | 313 |
| 314 void AddCaller(intptr_t index) { | |
| 315 const intptr_t length = callers_table_->length(); | |
| 316 intptr_t i = 0; | |
| 317 for (; i < length; i++) { | |
| 318 CallEntry& entry = (*callers_table_)[i]; | |
| 319 if (entry.code_table_index == index) { | |
| 320 entry.count++; | |
| 321 return; | |
| 322 } | |
| 323 if (entry.code_table_index > index) { | |
| 324 break; | |
| 325 } | |
| 326 } | |
| 327 CallEntry entry; | |
| 328 entry.code_table_index = index; | |
| 329 entry.count = 1; | |
| 330 if (i < length) { | |
| 331 callers_table_->InsertAt(i, entry); | |
| 332 } else { | |
| 333 callers_table_->Add(entry); | |
| 334 } | |
| 335 } | |
| 336 | |
| 337 void AddCallee(intptr_t index) { | |
| 338 const intptr_t length = callees_table_->length(); | |
| 339 intptr_t i = 0; | |
| 340 for (; i < length; i++) { | |
| 341 CallEntry& entry = (*callees_table_)[i]; | |
| 342 if (entry.code_table_index == index) { | |
| 343 entry.count++; | |
| 344 return; | |
| 345 } | |
| 346 if (entry.code_table_index > index) { | |
| 347 break; | |
| 348 } | |
| 349 } | |
| 350 CallEntry entry; | |
| 351 entry.code_table_index = index; | |
| 352 entry.count = 1; | |
| 353 if (i < length) { | |
| 354 callees_table_->InsertAt(i, entry); | |
| 355 } else { | |
| 356 callees_table_->Add(entry); | |
| 357 } | |
| 358 } | |
|
siva
2014/02/21 22:23:48
These two functions are identical except for the t
Cutch
2014/02/24 15:18:56
Done.
| |
| 299 | 359 |
| 300 void PrintToJSONArray(JSONArray* events, bool full) { | 360 void PrintToJSONArray(JSONArray* events, bool full) { |
| 301 JSONObject obj(events); | 361 JSONObject obj(events); |
| 302 obj.AddProperty("type", "ProfileCode"); | 362 obj.AddProperty("type", "ProfileCode"); |
| 303 obj.AddProperty("kind", KindToCString(kind())); | 363 obj.AddProperty("kind", KindToCString(kind())); |
| 304 obj.AddPropertyF("inclusive_ticks", "%" Pd "", inclusive_ticks()); | 364 obj.AddPropertyF("inclusive_ticks", "%" Pd "", inclusive_ticks()); |
| 305 obj.AddPropertyF("exclusive_ticks", "%" Pd "", exclusive_ticks()); | 365 obj.AddPropertyF("exclusive_ticks", "%" Pd "", exclusive_ticks()); |
| 306 if (kind() == kDartCode) { | 366 if (kind() == kDartCode) { |
| 307 // Look up code in Dart heap. | 367 // Look up code in Dart heap. |
| 308 Code& code = Code::Handle(Code::LookupCode(start())); | 368 Code& code = Code::Handle(Code::LookupCode(start())); |
| (...skipping 24 matching lines...) Expand all Loading... | |
| 333 } | 393 } |
| 334 obj.AddPropertyF("start", "%" Px "", start()); | 394 obj.AddPropertyF("start", "%" Px "", start()); |
| 335 obj.AddPropertyF("end", "%" Px "", end()); | 395 obj.AddPropertyF("end", "%" Px "", end()); |
| 336 obj.AddProperty("name", name()); | 396 obj.AddProperty("name", name()); |
| 337 } | 397 } |
| 338 { | 398 { |
| 339 JSONArray ticks(&obj, "ticks"); | 399 JSONArray ticks(&obj, "ticks"); |
| 340 for (intptr_t i = 0; i < address_table_->length(); i++) { | 400 for (intptr_t i = 0; i < address_table_->length(); i++) { |
| 341 const AddressEntry& entry = (*address_table_)[i]; | 401 const AddressEntry& entry = (*address_table_)[i]; |
| 342 ticks.AddValueF("%" Px "", entry.pc); | 402 ticks.AddValueF("%" Px "", entry.pc); |
| 343 ticks.AddValueF("%" Pd "", entry.ticks); | 403 ticks.AddValueF("%" Pd "", entry.exclusive_ticks); |
| 404 ticks.AddValueF("%" Pd "", entry.inclusive_ticks); | |
| 405 } | |
| 406 } | |
| 407 { | |
| 408 JSONArray callers(&obj, "callers"); | |
| 409 for (intptr_t i = 0; i < callers_table_->length(); i++) { | |
| 410 const CallEntry& entry = (*callers_table_)[i]; | |
| 411 callers.AddValueF("%" Pd "", entry.code_table_index); | |
| 412 callers.AddValueF("%" Pd "", entry.count); | |
| 413 } | |
| 414 } | |
| 415 { | |
| 416 JSONArray callers(&obj, "callees"); | |
|
siva
2014/02/21 22:23:48
name the variable callees instead of callers to ma
Cutch
2014/02/24 15:18:56
Done.
| |
| 417 for (intptr_t i = 0; i < callees_table_->length(); i++) { | |
| 418 const CallEntry& entry = (*callees_table_)[i]; | |
| 419 callers.AddValueF("%" Pd "", entry.code_table_index); | |
| 420 callers.AddValueF("%" Pd "", entry.count); | |
| 344 } | 421 } |
| 345 } | 422 } |
| 346 } | 423 } |
| 347 | 424 |
| 348 private: | 425 private: |
| 349 void GenerateAndSetSymbolName(const char* prefix) { | 426 void GenerateAndSetSymbolName(const char* prefix) { |
| 350 const intptr_t kBuffSize = 512; | 427 const intptr_t kBuffSize = 512; |
| 351 char buff[kBuffSize]; | 428 char buff[kBuffSize]; |
| 352 OS::SNPrint(&buff[0], kBuffSize-1, "%s [%" Px ", %" Px ")", | 429 OS::SNPrint(&buff[0], kBuffSize-1, "%s [%" Px ", %" Px ")", |
| 353 prefix, start(), end()); | 430 prefix, start(), end()); |
| 354 SetName(buff); | 431 SetName(buff); |
| 355 } | 432 } |
| 356 | 433 |
| 357 Kind kind_; | 434 Kind kind_; |
| 358 uword start_; | 435 uword start_; |
| 359 uword end_; | 436 uword end_; |
| 360 intptr_t inclusive_ticks_; | 437 intptr_t inclusive_ticks_; |
| 361 intptr_t exclusive_ticks_; | 438 intptr_t exclusive_ticks_; |
| 362 const char* name_; | 439 const char* name_; |
| 363 ZoneGrowableArray<AddressEntry>* address_table_; | 440 ZoneGrowableArray<AddressEntry>* address_table_; |
| 364 | 441 ZoneGrowableArray<CallEntry>* callers_table_; |
| 442 ZoneGrowableArray<CallEntry>* callees_table_; | |
| 365 DISALLOW_COPY_AND_ASSIGN(CodeRegion); | 443 DISALLOW_COPY_AND_ASSIGN(CodeRegion); |
| 366 }; | 444 }; |
| 367 | 445 |
| 368 | 446 |
| 369 class ScopeStopwatch : public ValueObject { | 447 class ScopeStopwatch : public ValueObject { |
| 370 public: | 448 public: |
| 371 explicit ScopeStopwatch(const char* name) : name_(name) { | 449 explicit ScopeStopwatch(const char* name) : name_(name) { |
| 372 start_ = OS::GetCurrentTimeMillis(); | 450 start_ = OS::GetCurrentTimeMillis(); |
| 373 } | 451 } |
| 374 | 452 |
| (...skipping 14 matching lines...) Expand all Loading... | |
| 389 const char* name_; | 467 const char* name_; |
| 390 intptr_t start_; | 468 intptr_t start_; |
| 391 }; | 469 }; |
| 392 | 470 |
| 393 | 471 |
| 394 // All code regions. Code region tables are built on demand when a profile | 472 // All code regions. Code region tables are built on demand when a profile |
| 395 // is requested (through the service or on isolate shutdown). | 473 // is requested (through the service or on isolate shutdown). |
| 396 class ProfilerCodeRegionTable : public ValueObject { | 474 class ProfilerCodeRegionTable : public ValueObject { |
| 397 public: | 475 public: |
| 398 explicit ProfilerCodeRegionTable(Isolate* isolate) : | 476 explicit ProfilerCodeRegionTable(Isolate* isolate) : |
| 477 inclusive_ticks_(0), | |
| 478 exclusive_ticks_(0), | |
| 399 heap_(isolate->heap()), | 479 heap_(isolate->heap()), |
| 400 code_region_table_(new ZoneGrowableArray<CodeRegion*>(64)) { | 480 code_region_table_(new ZoneGrowableArray<CodeRegion*>(64)) { |
| 401 } | 481 } |
| 402 | 482 |
| 403 ~ProfilerCodeRegionTable() { | 483 ~ProfilerCodeRegionTable() { |
| 404 } | 484 } |
| 405 | 485 |
| 406 void AddTick(uword pc, bool exclusive, bool tick_address) { | 486 void AddTick(uword pc, bool exclusive) { |
| 407 intptr_t index = FindIndex(pc); | 487 intptr_t index = FindIndex(pc); |
| 408 if (index < 0) { | 488 if (index < 0) { |
| 409 CodeRegion* code_region = CreateCodeRegion(pc); | 489 CodeRegion* code_region = CreateCodeRegion(pc); |
| 410 ASSERT(code_region != NULL); | 490 ASSERT(code_region != NULL); |
| 411 index = InsertCodeRegion(code_region); | 491 index = InsertCodeRegion(code_region); |
| 412 } | 492 } |
| 413 ASSERT(index >= 0); | 493 ASSERT(index >= 0); |
| 414 ASSERT(index < code_region_table_->length()); | 494 ASSERT(index < code_region_table_->length()); |
| 415 (*code_region_table_)[index]->AddTick(exclusive); | 495 |
| 416 if (tick_address) { | 496 // Update global counters. |
| 417 (*code_region_table_)[index]->AddTickAtAddress(pc); | 497 if (exclusive) { |
| 498 exclusive_ticks_++; | |
| 499 } else { | |
| 500 inclusive_ticks_++; | |
| 418 } | 501 } |
| 502 | |
| 503 // Update code object counters. | |
| 504 (*code_region_table_)[index]->AddTickAtAddress(pc, exclusive); | |
| 419 } | 505 } |
| 420 | 506 |
| 421 intptr_t Length() const { return code_region_table_->length(); } | 507 intptr_t Length() const { return code_region_table_->length(); } |
| 422 | 508 |
| 423 CodeRegion* At(intptr_t idx) { | 509 CodeRegion* At(intptr_t idx) { |
| 424 return (*code_region_table_)[idx]; | 510 return (*code_region_table_)[idx]; |
| 425 } | 511 } |
| 426 | 512 |
| 513 intptr_t exclusive_ticks() const { return exclusive_ticks_; } | |
| 514 | |
| 515 intptr_t inclusive_ticks() const { return inclusive_ticks_; } | |
| 516 | |
| 517 intptr_t FindIndex(uword pc) { | |
|
siva
2014/02/21 22:23:48
const function too?
Cutch
2014/02/24 15:18:56
Done.
| |
| 518 intptr_t index = FindRegionIndex(pc, &CompareLowerBound); | |
| 519 const CodeRegion* code_region = NULL; | |
| 520 if (index == code_region_table_->length()) { | |
| 521 // Not present. | |
| 522 return -1; | |
| 523 } | |
| 524 code_region = (*code_region_table_)[index]; | |
| 525 if (code_region->contains(pc)) { | |
| 526 // Found at index. | |
| 527 return index; | |
| 528 } | |
| 529 return -1; | |
| 530 } | |
| 531 | |
| 427 #if defined(DEBUG) | 532 #if defined(DEBUG) |
| 428 void Verify() { | 533 void Verify() { |
| 429 VerifyOrder(); | 534 VerifyOrder(); |
| 430 VerifyOverlap(); | 535 VerifyOverlap(); |
| 431 } | 536 } |
| 432 #endif | 537 #endif |
| 433 | 538 |
| 434 private: | 539 private: |
| 435 intptr_t FindRegionIndex(uword pc, RegionCompare comparator) { | 540 intptr_t FindRegionIndex(uword pc, RegionCompare comparator) { |
| 436 ASSERT(comparator != NULL); | 541 ASSERT(comparator != NULL); |
| (...skipping 15 matching lines...) Expand all Loading... | |
| 452 } | 557 } |
| 453 | 558 |
| 454 static bool CompareUpperBound(uword pc, uword start, uword end) { | 559 static bool CompareUpperBound(uword pc, uword start, uword end) { |
| 455 return pc >= end; | 560 return pc >= end; |
| 456 } | 561 } |
| 457 | 562 |
| 458 static bool CompareLowerBound(uword pc, uword start, uword end) { | 563 static bool CompareLowerBound(uword pc, uword start, uword end) { |
| 459 return end <= pc; | 564 return end <= pc; |
| 460 } | 565 } |
| 461 | 566 |
| 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) { | 567 CodeRegion* CreateCodeRegion(uword pc) { |
| 478 Code& code = Code::Handle(Code::LookupCode(pc)); | 568 Code& code = Code::Handle(Code::LookupCode(pc)); |
| 479 if (!code.IsNull()) { | 569 if (!code.IsNull()) { |
| 480 return new CodeRegion(CodeRegion::kDartCode, code.EntryPoint(), | 570 return new CodeRegion(CodeRegion::kDartCode, code.EntryPoint(), |
| 481 code.EntryPoint() + code.Size()); | 571 code.EntryPoint() + code.Size()); |
| 482 } | 572 } |
| 483 if (heap_->CodeContains(pc)) { | 573 if (heap_->CodeContains(pc)) { |
| 484 const intptr_t kDartCodeAlignment = 0x10; | 574 const intptr_t kDartCodeAlignment = 0x10; |
| 485 const intptr_t kDartCodeAlignmentMask = ~(kDartCodeAlignment - 1); | 575 const intptr_t kDartCodeAlignmentMask = ~(kDartCodeAlignment - 1); |
| 486 return new CodeRegion(CodeRegion::kCollectedCode, pc, | 576 return new CodeRegion(CodeRegion::kCollectedCode, pc, |
| (...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 586 CodeRegion* b = (*code_region_table_)[j]; | 676 CodeRegion* b = (*code_region_table_)[j]; |
| 587 ASSERT(!a->contains(b->start()) && | 677 ASSERT(!a->contains(b->start()) && |
| 588 !a->contains(b->end() - 1) && | 678 !a->contains(b->end() - 1) && |
| 589 !b->contains(a->start()) && | 679 !b->contains(a->start()) && |
| 590 !b->contains(a->end() - 1)); | 680 !b->contains(a->end() - 1)); |
| 591 } | 681 } |
| 592 } | 682 } |
| 593 } | 683 } |
| 594 #endif | 684 #endif |
| 595 | 685 |
| 686 intptr_t inclusive_ticks_; | |
| 687 intptr_t exclusive_ticks_; | |
| 596 Heap* heap_; | 688 Heap* heap_; |
| 597 ZoneGrowableArray<CodeRegion*>* code_region_table_; | 689 ZoneGrowableArray<CodeRegion*>* code_region_table_; |
| 598 }; | 690 }; |
| 599 | 691 |
| 600 | 692 |
| 601 class CodeRegionTableBuilder : public SampleVisitor { | 693 class CodeRegionTableBuilder : public SampleVisitor { |
| 602 public: | 694 public: |
| 603 CodeRegionTableBuilder(Isolate* isolate, | 695 CodeRegionTableBuilder(Isolate* isolate, |
| 604 ProfilerCodeRegionTable* code_region_table) | 696 ProfilerCodeRegionTable* code_region_table) |
| 605 : SampleVisitor(isolate), code_region_table_(code_region_table) { | 697 : SampleVisitor(isolate), code_region_table_(code_region_table) { |
| 606 frames_ = 0; | 698 frames_ = 0; |
| 607 } | 699 } |
| 608 | 700 |
| 609 void VisitSample(Sample* sample) { | 701 void VisitSample(Sample* sample) { |
| 610 code_region_table_->AddTick(sample->At(0), true, false); | 702 // Give the bottom frame an exclusive tick. |
| 611 // Give all frames an inclusive tick and tick the address. | 703 code_region_table_->AddTick(sample->At(0), true); |
| 704 // Give all frames (including the bottom) an inclusive tick. | |
| 612 for (intptr_t i = 0; i < FLAG_profile_depth; i++) { | 705 for (intptr_t i = 0; i < FLAG_profile_depth; i++) { |
| 613 if (sample->At(i) == 0) { | 706 if (sample->At(i) == 0) { |
| 614 break; | 707 break; |
| 615 } | 708 } |
| 616 frames_++; | 709 frames_++; |
| 617 code_region_table_->AddTick(sample->At(i), false, true); | 710 code_region_table_->AddTick(sample->At(i), false); |
| 618 } | 711 } |
| 619 } | 712 } |
| 620 | 713 |
| 621 intptr_t frames() const { return frames_; } | 714 intptr_t frames() const { return frames_; } |
| 715 | |
| 622 private: | 716 private: |
| 623 intptr_t frames_; | 717 intptr_t frames_; |
| 624 ProfilerCodeRegionTable* code_region_table_; | 718 ProfilerCodeRegionTable* code_region_table_; |
| 625 }; | 719 }; |
| 626 | 720 |
| 627 | 721 |
| 722 class CodeRegionTableCallersBuilder : public SampleVisitor { | |
| 723 public: | |
| 724 CodeRegionTableCallersBuilder(Isolate* isolate, | |
| 725 ProfilerCodeRegionTable* code_region_table) | |
| 726 : SampleVisitor(isolate), code_region_table_(code_region_table) { | |
| 727 ASSERT(code_region_table_ != NULL); | |
| 728 } | |
| 729 | |
| 730 void VisitSample(Sample* sample) { | |
| 731 intptr_t current_index = code_region_table_->FindIndex(sample->At(0)); | |
| 732 ASSERT(current_index != -1); | |
| 733 CodeRegion* current = code_region_table_->At(current_index); | |
| 734 intptr_t caller_index = -1; | |
| 735 CodeRegion* caller = NULL; | |
| 736 intptr_t callee_index = -1; | |
| 737 CodeRegion* callee = NULL; | |
| 738 for (intptr_t i = 1; i < FLAG_profile_depth; i++) { | |
| 739 if (sample->At(i) == 0) { | |
| 740 break; | |
| 741 } | |
| 742 caller_index = code_region_table_->FindIndex(sample->At(i)); | |
| 743 ASSERT(caller_index != -1); | |
| 744 caller = code_region_table_->At(caller_index); | |
| 745 current->AddCaller(caller_index); | |
| 746 if (callee != NULL) { | |
| 747 current->AddCallee(callee_index); | |
| 748 } | |
| 749 // Move cursors. | |
| 750 callee_index = current_index; | |
| 751 callee = current; | |
| 752 current_index = caller_index; | |
| 753 current = caller; | |
| 754 } | |
| 755 } | |
| 756 | |
| 757 private: | |
| 758 ProfilerCodeRegionTable* code_region_table_; | |
| 759 }; | |
| 760 | |
| 628 void Profiler::PrintToJSONStream(Isolate* isolate, JSONStream* stream, | 761 void Profiler::PrintToJSONStream(Isolate* isolate, JSONStream* stream, |
| 629 bool full) { | 762 bool full) { |
| 630 ASSERT(isolate == Isolate::Current()); | 763 ASSERT(isolate == Isolate::Current()); |
| 631 // Disable profile interrupts while processing the buffer. | 764 // Disable profile interrupts while processing the buffer. |
| 632 EndExecution(isolate); | 765 EndExecution(isolate); |
| 633 MutexLocker profiler_data_lock(isolate->profiler_data_mutex()); | 766 MutexLocker profiler_data_lock(isolate->profiler_data_mutex()); |
| 634 IsolateProfilerData* profiler_data = isolate->profiler_data(); | 767 IsolateProfilerData* profiler_data = isolate->profiler_data(); |
| 635 if (profiler_data == NULL) { | 768 if (profiler_data == NULL) { |
| 636 JSONObject error(stream); | 769 JSONObject error(stream); |
| 637 error.AddProperty("type", "Error"); | 770 error.AddProperty("type", "Error"); |
| 638 error.AddProperty("text", "Isolate does not have profiling enabled."); | 771 error.AddProperty("text", "Isolate does not have profiling enabled."); |
| 639 return; | 772 return; |
| 640 } | 773 } |
| 641 SampleBuffer* sample_buffer = profiler_data->sample_buffer(); | 774 SampleBuffer* sample_buffer = profiler_data->sample_buffer(); |
| 642 ASSERT(sample_buffer != NULL); | 775 ASSERT(sample_buffer != NULL); |
| 643 { | 776 { |
| 644 StackZone zone(isolate); | 777 StackZone zone(isolate); |
| 645 { | 778 { |
| 646 // Build code region table. | 779 // Build code region table. |
| 647 ProfilerCodeRegionTable code_region_table(isolate); | 780 ProfilerCodeRegionTable code_region_table(isolate); |
| 648 CodeRegionTableBuilder builder(isolate, &code_region_table); | 781 CodeRegionTableBuilder builder(isolate, &code_region_table); |
| 782 CodeRegionTableCallersBuilder build_callers(isolate, &code_region_table); | |
| 649 { | 783 { |
| 650 ScopeStopwatch sw("CodeTableBuild"); | 784 ScopeStopwatch sw("CodeTableBuild"); |
| 651 sample_buffer->VisitSamples(&builder); | 785 sample_buffer->VisitSamples(&builder); |
| 652 } | 786 } |
| 653 #if defined(DEBUG) | 787 #if defined(DEBUG) |
| 654 code_region_table.Verify(); | 788 code_region_table.Verify(); |
| 655 #endif | 789 #endif |
| 790 { | |
| 791 ScopeStopwatch sw("CodeTableCallersBuild"); | |
| 792 sample_buffer->VisitSamples(&build_callers); | |
| 793 } | |
| 656 // Number of samples we processed. | 794 // Number of samples we processed. |
| 657 intptr_t samples = builder.visited(); | |
| 658 intptr_t frames = builder.frames(); | 795 intptr_t frames = builder.frames(); |
| 659 if (FLAG_trace_profiled_isolates) { | 796 if (FLAG_trace_profiled_isolates) { |
| 660 OS::Print("%" Pd " frames produced %" Pd " code objects.\n", | 797 OS::Print("%" Pd " frames produced %" Pd " code objects.\n", |
| 661 frames, code_region_table.Length()); | 798 frames, code_region_table.Length()); |
| 662 } | 799 } |
| 663 { | 800 { |
| 664 ScopeStopwatch sw("CodeTableStream"); | 801 ScopeStopwatch sw("CodeTableStream"); |
| 665 // Serialize to JSON. | 802 // Serialize to JSON. |
| 666 JSONObject obj(stream); | 803 JSONObject obj(stream); |
| 667 obj.AddProperty("type", "Profile"); | 804 obj.AddProperty("type", "Profile"); |
| 668 obj.AddProperty("samples", samples); | 805 obj.AddProperty("exclusive_ticks", code_region_table.exclusive_ticks()); |
| 806 obj.AddProperty("inclusive_ticks", code_region_table.inclusive_ticks()); | |
| 669 JSONArray codes(&obj, "codes"); | 807 JSONArray codes(&obj, "codes"); |
| 670 for (intptr_t i = 0; i < code_region_table.Length(); i++) { | 808 for (intptr_t i = 0; i < code_region_table.Length(); i++) { |
| 671 CodeRegion* region = code_region_table.At(i); | 809 CodeRegion* region = code_region_table.At(i); |
| 672 ASSERT(region != NULL); | 810 ASSERT(region != NULL); |
| 673 region->PrintToJSONArray(&codes, false); | 811 region->PrintToJSONArray(&codes, false); |
| 674 } | 812 } |
| 675 } | 813 } |
| 676 } | 814 } |
| 677 } | 815 } |
| 678 // Enable profile interrupts. | 816 // Enable profile interrupts. |
| (...skipping 194 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 873 stack_lower = 0; | 1011 stack_lower = 0; |
| 874 stack_upper = 0; | 1012 stack_upper = 0; |
| 875 } | 1013 } |
| 876 ProfilerSampleStackWalker stackWalker(sample, stack_lower, stack_upper, | 1014 ProfilerSampleStackWalker stackWalker(sample, stack_lower, stack_upper, |
| 877 state.pc, state.fp, state.sp); | 1015 state.pc, state.fp, state.sp); |
| 878 stackWalker.walk(); | 1016 stackWalker.walk(); |
| 879 } | 1017 } |
| 880 | 1018 |
| 881 | 1019 |
| 882 } // namespace dart | 1020 } // namespace dart |
| OLD | NEW |