| 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())); |
| 309 Function& func = Function::Handle(); | 339 Function& func = Function::Handle(); |
| 310 ASSERT(!code.IsNull()); | 340 ASSERT(!code.IsNull()); |
| 311 func ^= code.function(); | 341 func ^= code.function(); |
| 312 if (func.IsNull()) { | 342 if (func.IsNull()) { |
| 313 if (name() == NULL) { | 343 if (name() == NULL) { |
| 314 GenerateAndSetSymbolName("Stub"); | 344 const char* stub_name = StubCode::NameOfStub(start()); |
| 345 GenerateAndSetSymbolName(stub_name == NULL ? "Stub" : stub_name); |
| 315 } | 346 } |
| 316 obj.AddPropertyF("start", "%" Px "", start()); | 347 obj.AddPropertyF("start", "%" Px "", start()); |
| 317 obj.AddPropertyF("end", "%" Px "", end()); | 348 obj.AddPropertyF("end", "%" Px "", end()); |
| 318 obj.AddProperty("name", name()); | 349 obj.AddProperty("name", name()); |
| 319 } else { | 350 } else { |
| 320 obj.AddProperty("code", code, !full); | 351 obj.AddProperty("code", code, !full); |
| 321 } | 352 } |
| 322 } else if (kind() == kCollectedCode) { | 353 } else if (kind() == kCollectedCode) { |
| 323 if (name() == NULL) { | 354 if (name() == NULL) { |
| 324 GenerateAndSetSymbolName("Collected"); | 355 GenerateAndSetSymbolName("Collected"); |
| 325 } | 356 } |
| 326 obj.AddPropertyF("start", "%" Px "", start()); | 357 obj.AddPropertyF("start", "%" Px "", start()); |
| 327 obj.AddPropertyF("end", "%" Px "", end()); | 358 obj.AddPropertyF("end", "%" Px "", end()); |
| 328 obj.AddProperty("name", name()); | 359 obj.AddProperty("name", name()); |
| 329 } else { | 360 } else { |
| 330 ASSERT(kind() == kNativeCode); | 361 ASSERT(kind() == kNativeCode); |
| 331 if (name() == NULL) { | 362 if (name() == NULL) { |
| 332 GenerateAndSetSymbolName("Native"); | 363 GenerateAndSetSymbolName("Native"); |
| 333 } | 364 } |
| 334 obj.AddPropertyF("start", "%" Px "", start()); | 365 obj.AddPropertyF("start", "%" Px "", start()); |
| 335 obj.AddPropertyF("end", "%" Px "", end()); | 366 obj.AddPropertyF("end", "%" Px "", end()); |
| 336 obj.AddProperty("name", name()); | 367 obj.AddProperty("name", name()); |
| 337 } | 368 } |
| 338 { | 369 { |
| 339 JSONArray ticks(&obj, "ticks"); | 370 JSONArray ticks(&obj, "ticks"); |
| 340 for (intptr_t i = 0; i < address_table_->length(); i++) { | 371 for (intptr_t i = 0; i < address_table_->length(); i++) { |
| 341 const AddressEntry& entry = (*address_table_)[i]; | 372 const AddressEntry& entry = (*address_table_)[i]; |
| 342 ticks.AddValueF("%" Px "", entry.pc); | 373 ticks.AddValueF("%" Px "", entry.pc); |
| 343 ticks.AddValueF("%" Pd "", entry.ticks); | 374 ticks.AddValueF("%" Pd "", entry.exclusive_ticks); |
| 375 ticks.AddValueF("%" Pd "", entry.inclusive_ticks); |
| 376 } |
| 377 } |
| 378 { |
| 379 JSONArray callers(&obj, "callers"); |
| 380 for (intptr_t i = 0; i < callers_table_->length(); i++) { |
| 381 const CallEntry& entry = (*callers_table_)[i]; |
| 382 callers.AddValueF("%" Pd "", entry.code_table_index); |
| 383 callers.AddValueF("%" Pd "", entry.count); |
| 384 } |
| 385 } |
| 386 { |
| 387 JSONArray callees(&obj, "callees"); |
| 388 for (intptr_t i = 0; i < callees_table_->length(); i++) { |
| 389 const CallEntry& entry = (*callees_table_)[i]; |
| 390 callees.AddValueF("%" Pd "", entry.code_table_index); |
| 391 callees.AddValueF("%" Pd "", entry.count); |
| 344 } | 392 } |
| 345 } | 393 } |
| 346 } | 394 } |
| 347 | 395 |
| 348 private: | 396 private: |
| 397 void AddCallEntry(ZoneGrowableArray<CallEntry>* table, intptr_t index) { |
| 398 const intptr_t length = table->length(); |
| 399 intptr_t i = 0; |
| 400 for (; i < length; i++) { |
| 401 CallEntry& entry = (*table)[i]; |
| 402 if (entry.code_table_index == index) { |
| 403 entry.count++; |
| 404 return; |
| 405 } |
| 406 if (entry.code_table_index > index) { |
| 407 break; |
| 408 } |
| 409 } |
| 410 CallEntry entry; |
| 411 entry.code_table_index = index; |
| 412 entry.count = 1; |
| 413 if (i < length) { |
| 414 table->InsertAt(i, entry); |
| 415 } else { |
| 416 table->Add(entry); |
| 417 } |
| 418 } |
| 419 |
| 349 void GenerateAndSetSymbolName(const char* prefix) { | 420 void GenerateAndSetSymbolName(const char* prefix) { |
| 350 const intptr_t kBuffSize = 512; | 421 const intptr_t kBuffSize = 512; |
| 351 char buff[kBuffSize]; | 422 char buff[kBuffSize]; |
| 352 OS::SNPrint(&buff[0], kBuffSize-1, "%s [%" Px ", %" Px ")", | 423 OS::SNPrint(&buff[0], kBuffSize-1, "%s [%" Px ", %" Px ")", |
| 353 prefix, start(), end()); | 424 prefix, start(), end()); |
| 354 SetName(buff); | 425 SetName(buff); |
| 355 } | 426 } |
| 356 | 427 |
| 357 Kind kind_; | 428 Kind kind_; |
| 358 uword start_; | 429 uword start_; |
| 359 uword end_; | 430 uword end_; |
| 360 intptr_t inclusive_ticks_; | 431 intptr_t inclusive_ticks_; |
| 361 intptr_t exclusive_ticks_; | 432 intptr_t exclusive_ticks_; |
| 433 intptr_t inclusive_tick_serial_; |
| 362 const char* name_; | 434 const char* name_; |
| 363 ZoneGrowableArray<AddressEntry>* address_table_; | 435 ZoneGrowableArray<AddressEntry>* address_table_; |
| 364 | 436 ZoneGrowableArray<CallEntry>* callers_table_; |
| 437 ZoneGrowableArray<CallEntry>* callees_table_; |
| 365 DISALLOW_COPY_AND_ASSIGN(CodeRegion); | 438 DISALLOW_COPY_AND_ASSIGN(CodeRegion); |
| 366 }; | 439 }; |
| 367 | 440 |
| 368 | 441 |
| 369 class ScopeStopwatch : public ValueObject { | 442 class ScopeStopwatch : public ValueObject { |
| 370 public: | 443 public: |
| 371 explicit ScopeStopwatch(const char* name) : name_(name) { | 444 explicit ScopeStopwatch(const char* name) : name_(name) { |
| 372 start_ = OS::GetCurrentTimeMillis(); | 445 start_ = OS::GetCurrentTimeMillis(); |
| 373 } | 446 } |
| 374 | 447 |
| (...skipping 21 matching lines...) Expand all Loading... |
| 396 class ProfilerCodeRegionTable : public ValueObject { | 469 class ProfilerCodeRegionTable : public ValueObject { |
| 397 public: | 470 public: |
| 398 explicit ProfilerCodeRegionTable(Isolate* isolate) : | 471 explicit ProfilerCodeRegionTable(Isolate* isolate) : |
| 399 heap_(isolate->heap()), | 472 heap_(isolate->heap()), |
| 400 code_region_table_(new ZoneGrowableArray<CodeRegion*>(64)) { | 473 code_region_table_(new ZoneGrowableArray<CodeRegion*>(64)) { |
| 401 } | 474 } |
| 402 | 475 |
| 403 ~ProfilerCodeRegionTable() { | 476 ~ProfilerCodeRegionTable() { |
| 404 } | 477 } |
| 405 | 478 |
| 406 void AddTick(uword pc, bool exclusive, bool tick_address) { | 479 void AddTick(uword pc, bool exclusive, intptr_t serial) { |
| 407 intptr_t index = FindIndex(pc); | 480 intptr_t index = FindIndex(pc); |
| 408 if (index < 0) { | 481 if (index < 0) { |
| 409 CodeRegion* code_region = CreateCodeRegion(pc); | 482 CodeRegion* code_region = CreateCodeRegion(pc); |
| 410 ASSERT(code_region != NULL); | 483 ASSERT(code_region != NULL); |
| 411 index = InsertCodeRegion(code_region); | 484 index = InsertCodeRegion(code_region); |
| 412 } | 485 } |
| 413 ASSERT(index >= 0); | 486 ASSERT(index >= 0); |
| 414 ASSERT(index < code_region_table_->length()); | 487 ASSERT(index < code_region_table_->length()); |
| 415 (*code_region_table_)[index]->AddTick(exclusive); | 488 |
| 416 if (tick_address) { | 489 // Update code object counters. |
| 417 (*code_region_table_)[index]->AddTickAtAddress(pc); | 490 (*code_region_table_)[index]->AddTickAtAddress(pc, exclusive, serial); |
| 418 } | |
| 419 } | 491 } |
| 420 | 492 |
| 421 intptr_t Length() const { return code_region_table_->length(); } | 493 intptr_t Length() const { return code_region_table_->length(); } |
| 422 | 494 |
| 423 CodeRegion* At(intptr_t idx) { | 495 CodeRegion* At(intptr_t idx) { |
| 424 return (*code_region_table_)[idx]; | 496 return (*code_region_table_)[idx]; |
| 425 } | 497 } |
| 426 | 498 |
| 499 intptr_t FindIndex(uword pc) const { |
| 500 intptr_t index = FindRegionIndex(pc, &CompareLowerBound); |
| 501 const CodeRegion* code_region = NULL; |
| 502 if (index == code_region_table_->length()) { |
| 503 // Not present. |
| 504 return -1; |
| 505 } |
| 506 code_region = (*code_region_table_)[index]; |
| 507 if (code_region->contains(pc)) { |
| 508 // Found at index. |
| 509 return index; |
| 510 } |
| 511 return -1; |
| 512 } |
| 513 |
| 427 #if defined(DEBUG) | 514 #if defined(DEBUG) |
| 428 void Verify() { | 515 void Verify() { |
| 429 VerifyOrder(); | 516 VerifyOrder(); |
| 430 VerifyOverlap(); | 517 VerifyOverlap(); |
| 431 } | 518 } |
| 432 #endif | 519 #endif |
| 433 | 520 |
| 434 private: | 521 private: |
| 435 intptr_t FindRegionIndex(uword pc, RegionCompare comparator) { | 522 intptr_t FindRegionIndex(uword pc, RegionCompare comparator) const { |
| 436 ASSERT(comparator != NULL); | 523 ASSERT(comparator != NULL); |
| 437 intptr_t count = code_region_table_->length(); | 524 intptr_t count = code_region_table_->length(); |
| 438 intptr_t first = 0; | 525 intptr_t first = 0; |
| 439 while (count > 0) { | 526 while (count > 0) { |
| 440 intptr_t it = first; | 527 intptr_t it = first; |
| 441 intptr_t step = count / 2; | 528 intptr_t step = count / 2; |
| 442 it += step; | 529 it += step; |
| 443 const CodeRegion* code_region = (*code_region_table_)[it]; | 530 const CodeRegion* code_region = (*code_region_table_)[it]; |
| 444 if (comparator(pc, code_region->start(), code_region->end())) { | 531 if (comparator(pc, code_region->start(), code_region->end())) { |
| 445 first = ++it; | 532 first = ++it; |
| 446 count -= (step + 1); | 533 count -= (step + 1); |
| 447 } else { | 534 } else { |
| 448 count = step; | 535 count = step; |
| 449 } | 536 } |
| 450 } | 537 } |
| 451 return first; | 538 return first; |
| 452 } | 539 } |
| 453 | 540 |
| 454 static bool CompareUpperBound(uword pc, uword start, uword end) { | 541 static bool CompareUpperBound(uword pc, uword start, uword end) { |
| 455 return pc >= end; | 542 return pc >= end; |
| 456 } | 543 } |
| 457 | 544 |
| 458 static bool CompareLowerBound(uword pc, uword start, uword end) { | 545 static bool CompareLowerBound(uword pc, uword start, uword end) { |
| 459 return end <= pc; | 546 return end <= pc; |
| 460 } | 547 } |
| 461 | 548 |
| 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) { | 549 CodeRegion* CreateCodeRegion(uword pc) { |
| 478 Code& code = Code::Handle(Code::LookupCode(pc)); | 550 Code& code = Code::Handle(Code::LookupCode(pc)); |
| 479 if (!code.IsNull()) { | 551 if (!code.IsNull()) { |
| 480 return new CodeRegion(CodeRegion::kDartCode, code.EntryPoint(), | 552 return new CodeRegion(CodeRegion::kDartCode, code.EntryPoint(), |
| 481 code.EntryPoint() + code.Size()); | 553 code.EntryPoint() + code.Size()); |
| 482 } | 554 } |
| 483 if (heap_->CodeContains(pc)) { | 555 if (heap_->CodeContains(pc)) { |
| 484 const intptr_t kDartCodeAlignment = 0x10; | 556 const intptr_t kDartCodeAlignment = 0x10; |
| 485 const intptr_t kDartCodeAlignmentMask = ~(kDartCodeAlignment - 1); | 557 const intptr_t kDartCodeAlignmentMask = ~(kDartCodeAlignment - 1); |
| 486 return new CodeRegion(CodeRegion::kCollectedCode, pc, | 558 return new CodeRegion(CodeRegion::kCollectedCode, pc, |
| (...skipping 113 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 600 | 672 |
| 601 class CodeRegionTableBuilder : public SampleVisitor { | 673 class CodeRegionTableBuilder : public SampleVisitor { |
| 602 public: | 674 public: |
| 603 CodeRegionTableBuilder(Isolate* isolate, | 675 CodeRegionTableBuilder(Isolate* isolate, |
| 604 ProfilerCodeRegionTable* code_region_table) | 676 ProfilerCodeRegionTable* code_region_table) |
| 605 : SampleVisitor(isolate), code_region_table_(code_region_table) { | 677 : SampleVisitor(isolate), code_region_table_(code_region_table) { |
| 606 frames_ = 0; | 678 frames_ = 0; |
| 607 } | 679 } |
| 608 | 680 |
| 609 void VisitSample(Sample* sample) { | 681 void VisitSample(Sample* sample) { |
| 610 code_region_table_->AddTick(sample->At(0), true, false); | 682 // Give the bottom frame an exclusive tick. |
| 611 // Give all frames an inclusive tick and tick the address. | 683 code_region_table_->AddTick(sample->At(0), true, -1); |
| 684 // Give all frames (including the bottom) an inclusive tick. |
| 612 for (intptr_t i = 0; i < FLAG_profile_depth; i++) { | 685 for (intptr_t i = 0; i < FLAG_profile_depth; i++) { |
| 613 if (sample->At(i) == 0) { | 686 if (sample->At(i) == 0) { |
| 614 break; | 687 break; |
| 615 } | 688 } |
| 616 frames_++; | 689 frames_++; |
| 617 code_region_table_->AddTick(sample->At(i), false, true); | 690 code_region_table_->AddTick(sample->At(i), false, visited()); |
| 618 } | 691 } |
| 619 } | 692 } |
| 620 | 693 |
| 621 intptr_t frames() const { return frames_; } | 694 intptr_t frames() const { return frames_; } |
| 695 |
| 622 private: | 696 private: |
| 623 intptr_t frames_; | 697 intptr_t frames_; |
| 624 ProfilerCodeRegionTable* code_region_table_; | 698 ProfilerCodeRegionTable* code_region_table_; |
| 625 }; | 699 }; |
| 626 | 700 |
| 627 | 701 |
| 702 class CodeRegionTableCallersBuilder : public SampleVisitor { |
| 703 public: |
| 704 CodeRegionTableCallersBuilder(Isolate* isolate, |
| 705 ProfilerCodeRegionTable* code_region_table) |
| 706 : SampleVisitor(isolate), code_region_table_(code_region_table) { |
| 707 ASSERT(code_region_table_ != NULL); |
| 708 } |
| 709 |
| 710 void VisitSample(Sample* sample) { |
| 711 intptr_t current_index = code_region_table_->FindIndex(sample->At(0)); |
| 712 ASSERT(current_index != -1); |
| 713 CodeRegion* current = code_region_table_->At(current_index); |
| 714 intptr_t caller_index = -1; |
| 715 CodeRegion* caller = NULL; |
| 716 intptr_t callee_index = -1; |
| 717 CodeRegion* callee = NULL; |
| 718 for (intptr_t i = 1; i < FLAG_profile_depth; i++) { |
| 719 if (sample->At(i) == 0) { |
| 720 break; |
| 721 } |
| 722 caller_index = code_region_table_->FindIndex(sample->At(i)); |
| 723 ASSERT(caller_index != -1); |
| 724 caller = code_region_table_->At(caller_index); |
| 725 current->AddCaller(caller_index); |
| 726 if (callee != NULL) { |
| 727 current->AddCallee(callee_index); |
| 728 } |
| 729 // Move cursors. |
| 730 callee_index = current_index; |
| 731 callee = current; |
| 732 current_index = caller_index; |
| 733 current = caller; |
| 734 } |
| 735 } |
| 736 |
| 737 private: |
| 738 ProfilerCodeRegionTable* code_region_table_; |
| 739 }; |
| 740 |
| 628 void Profiler::PrintToJSONStream(Isolate* isolate, JSONStream* stream, | 741 void Profiler::PrintToJSONStream(Isolate* isolate, JSONStream* stream, |
| 629 bool full) { | 742 bool full) { |
| 630 ASSERT(isolate == Isolate::Current()); | 743 ASSERT(isolate == Isolate::Current()); |
| 631 // Disable profile interrupts while processing the buffer. | 744 // Disable profile interrupts while processing the buffer. |
| 632 EndExecution(isolate); | 745 EndExecution(isolate); |
| 633 MutexLocker profiler_data_lock(isolate->profiler_data_mutex()); | 746 MutexLocker profiler_data_lock(isolate->profiler_data_mutex()); |
| 634 IsolateProfilerData* profiler_data = isolate->profiler_data(); | 747 IsolateProfilerData* profiler_data = isolate->profiler_data(); |
| 635 if (profiler_data == NULL) { | 748 if (profiler_data == NULL) { |
| 636 JSONObject error(stream); | 749 JSONObject error(stream); |
| 637 error.AddProperty("type", "Error"); | 750 error.AddProperty("type", "Error"); |
| 638 error.AddProperty("text", "Isolate does not have profiling enabled."); | 751 error.AddProperty("text", "Isolate does not have profiling enabled."); |
| 639 return; | 752 return; |
| 640 } | 753 } |
| 641 SampleBuffer* sample_buffer = profiler_data->sample_buffer(); | 754 SampleBuffer* sample_buffer = profiler_data->sample_buffer(); |
| 642 ASSERT(sample_buffer != NULL); | 755 ASSERT(sample_buffer != NULL); |
| 643 { | 756 { |
| 644 StackZone zone(isolate); | 757 StackZone zone(isolate); |
| 645 { | 758 { |
| 646 // Build code region table. | 759 // Build code region table. |
| 647 ProfilerCodeRegionTable code_region_table(isolate); | 760 ProfilerCodeRegionTable code_region_table(isolate); |
| 648 CodeRegionTableBuilder builder(isolate, &code_region_table); | 761 CodeRegionTableBuilder builder(isolate, &code_region_table); |
| 762 CodeRegionTableCallersBuilder build_callers(isolate, &code_region_table); |
| 649 { | 763 { |
| 650 ScopeStopwatch sw("CodeTableBuild"); | 764 ScopeStopwatch sw("CodeTableBuild"); |
| 651 sample_buffer->VisitSamples(&builder); | 765 sample_buffer->VisitSamples(&builder); |
| 652 } | 766 } |
| 653 #if defined(DEBUG) | 767 #if defined(DEBUG) |
| 654 code_region_table.Verify(); | 768 code_region_table.Verify(); |
| 655 #endif | 769 #endif |
| 770 { |
| 771 ScopeStopwatch sw("CodeTableCallersBuild"); |
| 772 sample_buffer->VisitSamples(&build_callers); |
| 773 } |
| 656 // Number of samples we processed. | 774 // Number of samples we processed. |
| 657 intptr_t samples = builder.visited(); | 775 intptr_t samples = builder.visited(); |
| 658 intptr_t frames = builder.frames(); | 776 intptr_t frames = builder.frames(); |
| 659 if (FLAG_trace_profiled_isolates) { | 777 if (FLAG_trace_profiled_isolates) { |
| 660 OS::Print("%" Pd " frames produced %" Pd " code objects.\n", | 778 OS::Print("%" Pd " frames produced %" Pd " code objects.\n", |
| 661 frames, code_region_table.Length()); | 779 frames, code_region_table.Length()); |
| 662 } | 780 } |
| 663 { | 781 { |
| 664 ScopeStopwatch sw("CodeTableStream"); | 782 ScopeStopwatch sw("CodeTableStream"); |
| 665 // Serialize to JSON. | 783 // Serialize to JSON. |
| 666 JSONObject obj(stream); | 784 JSONObject obj(stream); |
| 667 obj.AddProperty("type", "Profile"); | 785 obj.AddProperty("type", "Profile"); |
| 668 obj.AddProperty("samples", samples); | 786 obj.AddProperty("samples", samples); |
| 669 JSONArray codes(&obj, "codes"); | 787 JSONArray codes(&obj, "codes"); |
| 670 for (intptr_t i = 0; i < code_region_table.Length(); i++) { | 788 for (intptr_t i = 0; i < code_region_table.Length(); i++) { |
| 671 CodeRegion* region = code_region_table.At(i); | 789 CodeRegion* region = code_region_table.At(i); |
| 672 ASSERT(region != NULL); | 790 ASSERT(region != NULL); |
| 673 region->PrintToJSONArray(&codes, false); | 791 region->PrintToJSONArray(&codes, full); |
| 674 } | 792 } |
| 675 } | 793 } |
| 676 } | 794 } |
| 677 } | 795 } |
| 678 // Enable profile interrupts. | 796 // Enable profile interrupts. |
| 679 BeginExecution(isolate); | 797 BeginExecution(isolate); |
| 680 } | 798 } |
| 681 | 799 |
| 682 | 800 |
| 683 void Profiler::WriteProfile(Isolate* isolate) { | 801 void Profiler::WriteProfile(Isolate* isolate) { |
| (...skipping 189 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 873 stack_lower = 0; | 991 stack_lower = 0; |
| 874 stack_upper = 0; | 992 stack_upper = 0; |
| 875 } | 993 } |
| 876 ProfilerSampleStackWalker stackWalker(sample, stack_lower, stack_upper, | 994 ProfilerSampleStackWalker stackWalker(sample, stack_lower, stack_upper, |
| 877 state.pc, state.fp, state.sp); | 995 state.pc, state.fp, state.sp); |
| 878 stackWalker.walk(); | 996 stackWalker.walk(); |
| 879 } | 997 } |
| 880 | 998 |
| 881 | 999 |
| 882 } // namespace dart | 1000 } // namespace dart |
| OLD | NEW |