| OLD | NEW |
| 1 // Copyright 2013 the V8 project authors. All rights reserved. | 1 // Copyright 2013 the V8 project authors. All rights reserved. |
| 2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
| 3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
| 4 // met: | 4 // met: |
| 5 // | 5 // |
| 6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
| 7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
| 8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
| 9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
| 10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
| (...skipping 413 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 424 int to_entry_info_index = | 424 int to_entry_info_index = |
| 425 static_cast<int>(reinterpret_cast<intptr_t>(to_entry->value)); | 425 static_cast<int>(reinterpret_cast<intptr_t>(to_entry->value)); |
| 426 entries_.at(to_entry_info_index).addr = NULL; | 426 entries_.at(to_entry_info_index).addr = NULL; |
| 427 } | 427 } |
| 428 int from_entry_info_index = | 428 int from_entry_info_index = |
| 429 static_cast<int>(reinterpret_cast<intptr_t>(from_value)); | 429 static_cast<int>(reinterpret_cast<intptr_t>(from_value)); |
| 430 entries_.at(from_entry_info_index).addr = to; | 430 entries_.at(from_entry_info_index).addr = to; |
| 431 // Size of an object can change during its life, so to keep information | 431 // Size of an object can change during its life, so to keep information |
| 432 // about the object in entries_ consistent, we have to adjust size when the | 432 // about the object in entries_ consistent, we have to adjust size when the |
| 433 // object is migrated. | 433 // object is migrated. |
| 434 if (FLAG_heap_profiler_trace_objects) { | |
| 435 PrintF("Move object from %p to %p old size %6d new size %6d\n", | |
| 436 from, | |
| 437 to, | |
| 438 entries_.at(from_entry_info_index).size, | |
| 439 object_size); | |
| 440 } | |
| 441 entries_.at(from_entry_info_index).size = object_size; | 434 entries_.at(from_entry_info_index).size = object_size; |
| 442 to_entry->value = from_value; | 435 to_entry->value = from_value; |
| 443 } | 436 } |
| 444 } | 437 } |
| 445 | 438 |
| 446 | 439 |
| 447 void HeapObjectsMap::NewObject(Address addr, int size) { | 440 void HeapObjectsMap::NewObject(Address addr, int size) { |
| 448 if (FLAG_heap_profiler_trace_objects) { | |
| 449 PrintF("New object : %p %6d. Next address is %p\n", | |
| 450 addr, | |
| 451 size, | |
| 452 addr + size); | |
| 453 } | |
| 454 ASSERT(addr != NULL); | 441 ASSERT(addr != NULL); |
| 455 FindOrAddEntry(addr, size, false); | 442 FindOrAddEntry(addr, size, false); |
| 456 } | 443 } |
| 457 | 444 |
| 458 | 445 |
| 459 void HeapObjectsMap::UpdateObjectSize(Address addr, int size) { | 446 void HeapObjectsMap::UpdateObjectSize(Address addr, int size) { |
| 460 FindOrAddEntry(addr, size, false); | 447 FindOrAddEntry(addr, size, false); |
| 461 } | 448 } |
| 462 | 449 |
| 463 | 450 |
| (...skipping 12 matching lines...) Expand all Loading... |
| 476 unsigned int size, | 463 unsigned int size, |
| 477 bool accessed) { | 464 bool accessed) { |
| 478 ASSERT(static_cast<uint32_t>(entries_.length()) > entries_map_.occupancy()); | 465 ASSERT(static_cast<uint32_t>(entries_.length()) > entries_map_.occupancy()); |
| 479 HashMap::Entry* entry = entries_map_.Lookup(addr, ComputePointerHash(addr), | 466 HashMap::Entry* entry = entries_map_.Lookup(addr, ComputePointerHash(addr), |
| 480 true); | 467 true); |
| 481 if (entry->value != NULL) { | 468 if (entry->value != NULL) { |
| 482 int entry_index = | 469 int entry_index = |
| 483 static_cast<int>(reinterpret_cast<intptr_t>(entry->value)); | 470 static_cast<int>(reinterpret_cast<intptr_t>(entry->value)); |
| 484 EntryInfo& entry_info = entries_.at(entry_index); | 471 EntryInfo& entry_info = entries_.at(entry_index); |
| 485 entry_info.accessed = accessed; | 472 entry_info.accessed = accessed; |
| 486 if (FLAG_heap_profiler_trace_objects) { | |
| 487 PrintF("Update object size : %p with old size %d and new size %d\n", | |
| 488 addr, | |
| 489 entry_info.size, | |
| 490 size); | |
| 491 } | |
| 492 entry_info.size = size; | 473 entry_info.size = size; |
| 493 return entry_info.id; | 474 return entry_info.id; |
| 494 } | 475 } |
| 495 entry->value = reinterpret_cast<void*>(entries_.length()); | 476 entry->value = reinterpret_cast<void*>(entries_.length()); |
| 496 SnapshotObjectId id = next_id_; | 477 SnapshotObjectId id = next_id_; |
| 497 next_id_ += kObjectIdStep; | 478 next_id_ += kObjectIdStep; |
| 498 entries_.Add(EntryInfo(id, addr, size, accessed)); | 479 entries_.Add(EntryInfo(id, addr, size, accessed)); |
| 499 ASSERT(static_cast<uint32_t>(entries_.length()) > entries_map_.occupancy()); | 480 ASSERT(static_cast<uint32_t>(entries_.length()) > entries_map_.occupancy()); |
| 500 return id; | 481 return id; |
| 501 } | 482 } |
| 502 | 483 |
| 503 | 484 |
| 504 void HeapObjectsMap::StopHeapObjectsTracking() { | 485 void HeapObjectsMap::StopHeapObjectsTracking() { |
| 505 time_intervals_.Clear(); | 486 time_intervals_.Clear(); |
| 506 } | 487 } |
| 507 | 488 |
| 508 | 489 |
| 509 void HeapObjectsMap::UpdateHeapObjectsMap() { | 490 void HeapObjectsMap::UpdateHeapObjectsMap() { |
| 510 if (FLAG_heap_profiler_trace_objects) { | |
| 511 PrintF("Begin HeapObjectsMap::UpdateHeapObjectsMap. map has %d entries.\n", | |
| 512 entries_map_.occupancy()); | |
| 513 } | |
| 514 heap_->CollectAllGarbage(Heap::kMakeHeapIterableMask, | 491 heap_->CollectAllGarbage(Heap::kMakeHeapIterableMask, |
| 515 "HeapSnapshotsCollection::UpdateHeapObjectsMap"); | 492 "HeapSnapshotsCollection::UpdateHeapObjectsMap"); |
| 516 HeapIterator iterator(heap_); | 493 HeapIterator iterator(heap_); |
| 517 for (HeapObject* obj = iterator.next(); | 494 for (HeapObject* obj = iterator.next(); |
| 518 obj != NULL; | 495 obj != NULL; |
| 519 obj = iterator.next()) { | 496 obj = iterator.next()) { |
| 520 FindOrAddEntry(obj->address(), obj->Size()); | 497 FindOrAddEntry(obj->address(), obj->Size()); |
| 521 if (FLAG_heap_profiler_trace_objects) { | |
| 522 PrintF("Update object : %p %6d. Next address is %p\n", | |
| 523 obj->address(), | |
| 524 obj->Size(), | |
| 525 obj->address() + obj->Size()); | |
| 526 } | |
| 527 } | 498 } |
| 528 RemoveDeadEntries(); | 499 RemoveDeadEntries(); |
| 529 if (FLAG_heap_profiler_trace_objects) { | |
| 530 PrintF("End HeapObjectsMap::UpdateHeapObjectsMap. map has %d entries.\n", | |
| 531 entries_map_.occupancy()); | |
| 532 } | |
| 533 } | 500 } |
| 534 | 501 |
| 535 | 502 |
| 536 namespace { | |
| 537 | |
| 538 | |
| 539 struct HeapObjectInfo { | |
| 540 HeapObjectInfo(HeapObject* obj, size_t expected_size) | |
| 541 : obj(obj), | |
| 542 expected_size(expected_size) { | |
| 543 } | |
| 544 | |
| 545 HeapObject* obj; | |
| 546 int expected_size; | |
| 547 | |
| 548 bool IsValid() const { return expected_size == obj->Size(); } | |
| 549 | |
| 550 void Print() const { | |
| 551 if (expected_size == 0) { | |
| 552 PrintF("Untracked object : %p %6d. Next address is %p\n", | |
| 553 obj->address(), | |
| 554 obj->Size(), | |
| 555 obj->address() + obj->Size()); | |
| 556 } else if (obj->Size() != expected_size) { | |
| 557 PrintF("Wrong size %6d: %p %6d. Next address is %p\n", | |
| 558 expected_size, | |
| 559 obj->address(), | |
| 560 obj->Size(), | |
| 561 obj->address() + obj->Size()); | |
| 562 } else { | |
| 563 PrintF("Good object : %p %6d. Next address is %p\n", | |
| 564 obj->address(), | |
| 565 expected_size, | |
| 566 obj->address() + obj->Size()); | |
| 567 } | |
| 568 } | |
| 569 }; | |
| 570 | |
| 571 | |
| 572 static int comparator(const HeapObjectInfo* a, const HeapObjectInfo* b) { | |
| 573 return a->obj - b->obj; | |
| 574 } | |
| 575 | |
| 576 | |
| 577 } // namespace | |
| 578 | |
| 579 | |
| 580 int HeapObjectsMap::FindUntrackedObjects() { | 503 int HeapObjectsMap::FindUntrackedObjects() { |
| 581 List<HeapObjectInfo> heap_objects(1000); | |
| 582 | |
| 583 HeapIterator iterator(heap_); | 504 HeapIterator iterator(heap_); |
| 584 int untracked = 0; | 505 int untracked = 0; |
| 585 for (HeapObject* obj = iterator.next(); | 506 for (HeapObject* obj = iterator.next(); |
| 586 obj != NULL; | 507 obj != NULL; |
| 587 obj = iterator.next()) { | 508 obj = iterator.next()) { |
| 588 HashMap::Entry* entry = entries_map_.Lookup( | 509 HashMap::Entry* entry = entries_map_.Lookup( |
| 589 obj->address(), ComputePointerHash(obj->address()), false); | 510 obj->address(), ComputePointerHash(obj->address()), false); |
| 590 if (entry == NULL) { | 511 if (entry == NULL) { |
| 591 ++untracked; | 512 untracked++; |
| 592 if (FLAG_heap_profiler_trace_objects) { | |
| 593 heap_objects.Add(HeapObjectInfo(obj, 0)); | |
| 594 } | |
| 595 } else { | 513 } else { |
| 596 int entry_index = static_cast<int>( | 514 int entry_index = static_cast<int>( |
| 597 reinterpret_cast<intptr_t>(entry->value)); | 515 reinterpret_cast<intptr_t>(entry->value)); |
| 598 EntryInfo& entry_info = entries_.at(entry_index); | 516 EntryInfo& entry_info = entries_.at(entry_index); |
| 599 if (FLAG_heap_profiler_trace_objects) { | 517 CHECK_EQ(obj->Size(), static_cast<int>(entry_info.size)); |
| 600 heap_objects.Add(HeapObjectInfo(obj, | |
| 601 static_cast<int>(entry_info.size))); | |
| 602 if (obj->Size() != static_cast<int>(entry_info.size)) | |
| 603 ++untracked; | |
| 604 } else { | |
| 605 CHECK_EQ(obj->Size(), static_cast<int>(entry_info.size)); | |
| 606 } | |
| 607 } | 518 } |
| 608 } | 519 } |
| 609 if (FLAG_heap_profiler_trace_objects) { | |
| 610 PrintF("\nBegin HeapObjectsMap::FindUntrackedObjects. %d entries in map.\n", | |
| 611 entries_map_.occupancy()); | |
| 612 heap_objects.Sort(comparator); | |
| 613 int last_printed_object = -1; | |
| 614 bool print_next_object = false; | |
| 615 for (int i = 0; i < heap_objects.length(); ++i) { | |
| 616 const HeapObjectInfo& object_info = heap_objects[i]; | |
| 617 if (!object_info.IsValid()) { | |
| 618 ++untracked; | |
| 619 if (last_printed_object != i - 1) { | |
| 620 if (i > 0) { | |
| 621 PrintF("%d objects were skipped\n", i - 1 - last_printed_object); | |
| 622 heap_objects[i - 1].Print(); | |
| 623 } | |
| 624 } | |
| 625 object_info.Print(); | |
| 626 last_printed_object = i; | |
| 627 print_next_object = true; | |
| 628 } else if (print_next_object) { | |
| 629 object_info.Print(); | |
| 630 print_next_object = false; | |
| 631 last_printed_object = i; | |
| 632 } | |
| 633 } | |
| 634 if (last_printed_object < heap_objects.length() - 1) { | |
| 635 PrintF("Last %d objects were skipped\n", | |
| 636 heap_objects.length() - 1 - last_printed_object); | |
| 637 } | |
| 638 PrintF("End HeapObjectsMap::FindUntrackedObjects. %d entries in map.\n\n", | |
| 639 entries_map_.occupancy()); | |
| 640 } | |
| 641 return untracked; | 520 return untracked; |
| 642 } | 521 } |
| 643 | 522 |
| 644 | 523 |
| 645 SnapshotObjectId HeapObjectsMap::PushHeapObjectsStats(OutputStream* stream) { | 524 SnapshotObjectId HeapObjectsMap::PushHeapObjectsStats(OutputStream* stream) { |
| 646 UpdateHeapObjectsMap(); | 525 UpdateHeapObjectsMap(); |
| 647 time_intervals_.Add(TimeInterval(next_id_)); | 526 time_intervals_.Add(TimeInterval(next_id_)); |
| 648 int prefered_chunk_size = stream->GetChunkSize(); | 527 int prefered_chunk_size = stream->GetChunkSize(); |
| 649 List<v8::HeapStatsUpdate> stats_buffer; | 528 List<v8::HeapStatsUpdate> stats_buffer; |
| 650 ASSERT(!entries_.is_empty()); | 529 ASSERT(!entries_.is_empty()); |
| (...skipping 2215 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2866 writer_->AddString("\"<dummy>\""); | 2745 writer_->AddString("\"<dummy>\""); |
| 2867 for (int i = 1; i < sorted_strings.length(); ++i) { | 2746 for (int i = 1; i < sorted_strings.length(); ++i) { |
| 2868 writer_->AddCharacter(','); | 2747 writer_->AddCharacter(','); |
| 2869 SerializeString(sorted_strings[i]); | 2748 SerializeString(sorted_strings[i]); |
| 2870 if (writer_->aborted()) return; | 2749 if (writer_->aborted()) return; |
| 2871 } | 2750 } |
| 2872 } | 2751 } |
| 2873 | 2752 |
| 2874 | 2753 |
| 2875 } } // namespace v8::internal | 2754 } } // namespace v8::internal |
| OLD | NEW |