OLD | NEW |
---|---|
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 // --- | 5 // --- |
6 // Author: Sainbayar Sukhbaatar | 6 // Author: Sainbayar Sukhbaatar |
7 // Dai Mikurube | 7 // Dai Mikurube |
8 // | 8 // |
9 | 9 |
10 #include "deep-heap-profile.h" | 10 #include "deep-heap-profile.h" |
11 | 11 |
12 #ifdef DEEP_HEAP_PROFILE | 12 #ifdef DEEP_HEAP_PROFILE |
13 #include <algorithm> | 13 #include <algorithm> |
14 #include <fcntl.h> | 14 #include <fcntl.h> |
15 #include <sys/stat.h> | 15 #include <sys/stat.h> |
16 #include <sys/types.h> | 16 #include <sys/types.h> |
17 #ifdef HAVE_UNISTD_H | 17 #ifdef HAVE_UNISTD_H |
18 #include <unistd.h> // for getpagesize and getpid | 18 #include <unistd.h> // for getpagesize and getpid |
19 #endif // HAVE_UNISTD_H | 19 #endif // HAVE_UNISTD_H |
20 | 20 |
21 #include "base/cycleclock.h" | 21 #include "base/cycleclock.h" |
22 #include "base/low_level_alloc.h" | 22 #include "base/low_level_alloc.h" |
23 #include "base/sysinfo.h" | 23 #include "base/sysinfo.h" |
24 #include "internal_logging.h" // for ASSERT, etc | 24 #include "internal_logging.h" // for ASSERT, etc |
25 #include "memory_region_map.h" | |
25 | 26 |
26 static const int kProfilerBufferSize = 1 << 20; | 27 static const int kProfilerBufferSize = 1 << 20; |
27 static const int kHashTableSize = 179999; // Same as heap-profile-table.cc. | 28 static const int kHashTableSize = 179999; // Same as heap-profile-table.cc. |
28 | 29 |
29 static const int PAGEMAP_BYTES = 8; | 30 static const int PAGEMAP_BYTES = 8; |
30 static const uint64 MAX_ADDRESS = kuint64max; | 31 static const uint64 MAX_ADDRESS = kuint64max; |
31 | 32 |
32 // Tag strings in heap profile dumps. | 33 // Tag strings in heap profile dumps. |
33 static const char kProfileHeader[] = "heap profile: "; | 34 static const char kProfileHeader[] = "heap profile: "; |
34 static const char kProfileVersion[] = "DUMP_DEEP_6"; | 35 static const char kProfileVersion[] = "DUMP_DEEP_6"; |
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
104 uint64 page_address = (first_address / page_size) * page_size; | 105 uint64 page_address = (first_address / page_size) * page_size; |
105 size_t committed_size = 0; | 106 size_t committed_size = 0; |
106 | 107 |
107 Seek(first_address); | 108 Seek(first_address); |
108 | 109 |
109 // Check every page on which the allocation resides. | 110 // Check every page on which the allocation resides. |
110 while (page_address <= last_address) { | 111 while (page_address <= last_address) { |
111 // Read corresponding physical page. | 112 // Read corresponding physical page. |
112 State state; | 113 State state; |
113 // TODO(dmikurube): Read pagemap in bulk for speed. | 114 // TODO(dmikurube): Read pagemap in bulk for speed. |
115 // TODO(dmikurube): Consider using mincore(2). | |
Alexander Potapenko
2013/03/07 06:08:25
Just wondering - how can mincore help you?
Dai Mikurube (NOT FULLTIME)
2013/03/07 17:14:24
This function is reading /proc/$PID/pagemap, which
| |
114 if (Read(&state) == false) { | 116 if (Read(&state) == false) { |
115 // We can't read the last region (e.g vsyscall). | 117 // We can't read the last region (e.g vsyscall). |
116 #ifndef NDEBUG | 118 #ifndef NDEBUG |
117 RAW_LOG(0, "pagemap read failed @ %#llx %"PRId64" bytes", | 119 RAW_LOG(0, "pagemap read failed @ %#llx %"PRId64" bytes", |
118 first_address, last_address - first_address + 1); | 120 first_address, last_address - first_address + 1); |
119 #endif | 121 #endif |
120 return 0; | 122 return 0; |
121 } | 123 } |
122 | 124 |
123 if (state.is_committed) { | 125 if (state.is_committed) { |
(...skipping 119 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
243 memory_residence_info_getter_->Initialize(); | 245 memory_residence_info_getter_->Initialize(); |
244 deep_table_.ResetIsLogged(); | 246 deep_table_.ResetIsLogged(); |
245 | 247 |
246 // Write maps into "|filename_prefix_|.<pid>.maps". | 248 // Write maps into "|filename_prefix_|.<pid>.maps". |
247 WriteProcMaps(filename_prefix_, kProfilerBufferSize, profiler_buffer_); | 249 WriteProcMaps(filename_prefix_, kProfilerBufferSize, profiler_buffer_); |
248 } | 250 } |
249 | 251 |
250 // Reset committed sizes of buckets. | 252 // Reset committed sizes of buckets. |
251 deep_table_.ResetCommittedSize(); | 253 deep_table_.ResetCommittedSize(); |
252 | 254 |
253 // Allocate a list for mmap'ed regions. | 255 // Record committed sizes. |
254 num_mmap_allocations_ = 0; | 256 stats_.SnapshotAllocations(this); |
255 if (heap_profile_->mmap_address_map_) { | |
256 heap_profile_->mmap_address_map_->Iterate(CountMMap, this); | |
257 | |
258 mmap_list_length_ = 0; | |
259 mmap_list_ = reinterpret_cast<MMapListEntry*>(heap_profile_->alloc_( | |
260 sizeof(MMapListEntry) * num_mmap_allocations_)); | |
261 | |
262 // Touch all the allocated pages. Touching is required to avoid new page | |
263 // commitment while filling the list in SnapshotProcMaps. | |
264 for (int i = 0; | |
265 i < num_mmap_allocations_; | |
266 i += getpagesize() / 2 / sizeof(MMapListEntry)) | |
267 mmap_list_[i].first_address = 0; | |
268 mmap_list_[num_mmap_allocations_ - 1].last_address = 0; | |
269 } | |
270 | |
271 stats_.SnapshotProcMaps(memory_residence_info_getter_, NULL, 0, NULL); | |
272 | 257 |
273 // TODO(dmikurube): Eliminate dynamic memory allocation caused by snprintf. | 258 // TODO(dmikurube): Eliminate dynamic memory allocation caused by snprintf. |
274 // glibc's snprintf internally allocates memory by alloca normally, but it | 259 // glibc's snprintf internally allocates memory by alloca normally, but it |
275 // allocates memory by malloc if large memory is required. | 260 // allocates memory by malloc if large memory is required. |
276 | 261 |
277 // Record committed sizes. | |
278 stats_.SnapshotAllocations(this); | |
279 | |
280 buffer.AppendString(kProfileHeader, 0); | 262 buffer.AppendString(kProfileHeader, 0); |
281 buffer.AppendString(kProfileVersion, 0); | 263 buffer.AppendString(kProfileVersion, 0); |
282 buffer.AppendString("\n", 0); | 264 buffer.AppendString("\n", 0); |
283 | 265 |
284 // Fill buffer with the global stats. | 266 // Fill buffer with the global stats. |
285 buffer.AppendString(kMMapListHeader, 0); | 267 buffer.AppendString(kMMapListHeader, 0); |
286 | 268 |
287 // Check if committed bytes changed during SnapshotAllocations. | 269 stats_.SnapshotMaps(memory_residence_info_getter_, this, &buffer); |
288 stats_.SnapshotProcMaps(memory_residence_info_getter_, | |
289 mmap_list_, | |
290 mmap_list_length_, | |
291 &buffer); | |
292 | 270 |
293 // Fill buffer with the global stats. | 271 // Fill buffer with the global stats. |
294 buffer.AppendString(kGlobalStatsHeader, 0); | 272 buffer.AppendString(kGlobalStatsHeader, 0); |
295 | 273 |
296 stats_.Unparse(&buffer); | 274 stats_.Unparse(&buffer); |
297 | 275 |
298 buffer.AppendString(kStacktraceHeader, 0); | 276 buffer.AppendString(kStacktraceHeader, 0); |
299 buffer.AppendString(kVirtualLabel, 10); | 277 buffer.AppendString(kVirtualLabel, 10); |
300 buffer.AppendChar(' '); | 278 buffer.AppendChar(' '); |
301 buffer.AppendString(kCommittedLabel, 10); | 279 buffer.AppendString(kCommittedLabel, 10); |
302 buffer.AppendString("\n", 0); | 280 buffer.AppendString("\n", 0); |
303 | 281 |
304 // Fill buffer. | 282 // Fill buffer. |
305 deep_table_.UnparseForStats(&buffer); | 283 deep_table_.UnparseForStats(&buffer); |
306 | 284 |
307 RAW_DCHECK(buffer.FilledBytes() < buffer_size, ""); | 285 RAW_DCHECK(buffer.FilledBytes() < buffer_size, ""); |
308 | 286 |
309 heap_profile_->dealloc_(mmap_list_); | |
310 mmap_list_ = NULL; | |
311 | |
312 // Write the bucket listing into a .bucket file. | 287 // Write the bucket listing into a .bucket file. |
313 deep_table_.WriteForBucketFile(filename_prefix_, dump_count_, &global_buffer); | 288 deep_table_.WriteForBucketFile(filename_prefix_, dump_count_, &global_buffer); |
314 | 289 |
315 #ifndef NDEBUG | 290 #ifndef NDEBUG |
316 int64 elapsed_cycles = CycleClock::Now() - starting_cycles; | 291 int64 elapsed_cycles = CycleClock::Now() - starting_cycles; |
317 double elapsed_seconds = elapsed_cycles / CyclesPerSecond(); | 292 double elapsed_seconds = elapsed_cycles / CyclesPerSecond(); |
318 RAW_LOG(0, "Time spent on DeepProfiler: %.3f sec\n", elapsed_seconds); | 293 RAW_LOG(0, "Time spent on DeepProfiler: %.3f sec\n", elapsed_seconds); |
319 #endif | 294 #endif |
320 | 295 |
321 return buffer.FilledBytes(); | 296 return buffer.FilledBytes(); |
(...skipping 300 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
622 TextBuffer* buffer) { | 597 TextBuffer* buffer) { |
623 buffer->AppendString(name, 25); | 598 buffer->AppendString(name, 25); |
624 buffer->AppendChar(' '); | 599 buffer->AppendChar(' '); |
625 buffer->AppendLong(virtual_bytes_, 12); | 600 buffer->AppendLong(virtual_bytes_, 12); |
626 buffer->AppendChar(' '); | 601 buffer->AppendChar(' '); |
627 buffer->AppendLong(committed_bytes_, 12); | 602 buffer->AppendLong(committed_bytes_, 12); |
628 buffer->AppendString("\n", 0); | 603 buffer->AppendString("\n", 0); |
629 } | 604 } |
630 | 605 |
631 // TODO(dmikurube): Eliminate dynamic memory allocation caused by snprintf. | 606 // TODO(dmikurube): Eliminate dynamic memory allocation caused by snprintf. |
632 void DeepHeapProfile::GlobalStats::SnapshotProcMaps( | 607 void DeepHeapProfile::GlobalStats::SnapshotMaps( |
633 const MemoryResidenceInfoGetterInterface* memory_residence_info_getter, | 608 const MemoryResidenceInfoGetterInterface* memory_residence_info_getter, |
634 MMapListEntry* mmap_list, | 609 DeepHeapProfile* deep_profile, |
635 int mmap_list_length, | |
636 TextBuffer* mmap_dump_buffer) { | 610 TextBuffer* mmap_dump_buffer) { |
637 ProcMapsIterator::Buffer iterator_buffer; | 611 ProcMapsIterator::Buffer procmaps_iter_buffer; |
638 ProcMapsIterator iterator(0, &iterator_buffer); | 612 ProcMapsIterator procmaps_iter(0, &procmaps_iter_buffer); |
639 uint64 first_address, last_address, offset; | 613 uint64 first_address, last_address, offset; |
640 int64 inode; | 614 int64 inode; |
641 char* flags; | 615 char* flags; |
642 char* filename; | 616 char* filename; |
643 int mmap_list_index = 0; | |
644 enum MapsRegionType type; | 617 enum MapsRegionType type; |
645 | |
646 for (int i = 0; i < NUMBER_OF_MAPS_REGION_TYPES; ++i) { | 618 for (int i = 0; i < NUMBER_OF_MAPS_REGION_TYPES; ++i) { |
647 all_[i].Initialize(); | 619 all_[i].Initialize(); |
648 unhooked_[i].Initialize(); | 620 unhooked_[i].Initialize(); |
649 } | 621 } |
622 profiled_mmap_.Initialize(); | |
650 | 623 |
651 size_t unhooked_arena_size = LowLevelAlloc::GetSizeOfUnhookedArena(); | 624 size_t unhooked_arena_size = LowLevelAlloc::GetSizeOfUnhookedArena(); |
652 unhooked_arena_.Initialize(); | 625 unhooked_arena_.Initialize(); |
653 unhooked_arena_.AddToVirtualBytes(unhooked_arena_size); | 626 unhooked_arena_.AddToVirtualBytes(unhooked_arena_size); |
654 unhooked_arena_.AddToCommittedBytes(unhooked_arena_size); | 627 unhooked_arena_.AddToCommittedBytes(unhooked_arena_size); |
655 | 628 |
656 while (iterator.Next(&first_address, &last_address, | 629 MemoryRegionMap::Lock(); |
657 &flags, &offset, &inode, &filename)) { | 630 MemoryRegionMap::RegionIterator mmap_iter = |
631 MemoryRegionMap::BeginRegionLocked(); | |
632 | |
633 while (procmaps_iter.Next(&first_address, &last_address, | |
634 &flags, &offset, &inode, &filename)) { | |
658 if (mmap_dump_buffer) { | 635 if (mmap_dump_buffer) { |
659 char buffer[1024]; | 636 char buffer[1024]; |
660 int written = iterator.FormatLine(buffer, sizeof(buffer), | 637 int written = procmaps_iter.FormatLine(buffer, sizeof(buffer), |
661 first_address, last_address, flags, | 638 first_address, last_address, flags, |
662 offset, inode, filename, 0); | 639 offset, inode, filename, 0); |
663 mmap_dump_buffer->AppendString(buffer, 0); | 640 mmap_dump_buffer->AppendString(buffer, 0); |
664 } | 641 } |
665 | 642 |
666 // 'last_address' should be the last inclusive address of the region. | 643 // 'last_address' should be the last inclusive address of the region. |
667 last_address -= 1; | 644 last_address -= 1; |
668 if (strcmp("[vsyscall]", filename) == 0) { | 645 if (strcmp("[vsyscall]", filename) == 0) { |
669 continue; // Reading pagemap will fail in [vsyscall]. | 646 continue; // Reading pagemap will fail in [vsyscall]. |
670 } | 647 } |
671 | 648 |
672 type = ABSENT; | 649 type = ABSENT; |
673 if (filename[0] == '/') { | 650 if (filename[0] == '/') { |
674 if (flags[2] == 'x') | 651 if (flags[2] == 'x') |
675 type = FILE_EXEC; | 652 type = FILE_EXEC; |
676 else | 653 else |
677 type = FILE_NONEXEC; | 654 type = FILE_NONEXEC; |
678 } else if (filename[0] == '\0' || filename[0] == '\n') { | 655 } else if (filename[0] == '\0' || filename[0] == '\n') { |
679 type = ANONYMOUS; | 656 type = ANONYMOUS; |
680 } else if (strcmp(filename, "[stack]") == 0) { | 657 } else if (strcmp(filename, "[stack]") == 0) { |
681 type = STACK; | 658 type = STACK; |
682 } else { | 659 } else { |
683 type = OTHER; | 660 type = OTHER; |
684 } | 661 } |
685 all_[type].Record( | 662 all_[type].Record( |
686 memory_residence_info_getter, first_address, last_address); | 663 memory_residence_info_getter, first_address, last_address); |
687 | 664 |
688 // TODO(dmikurube): Stop double-counting pagemap. | 665 // TODO(dmikurube): Stop double-counting pagemap. |
689 // Counts unhooked memory regions in /proc/<pid>/maps. | 666 // Counts unhooked memory regions in /proc/<pid>/maps. |
690 if (mmap_list != NULL) { | 667 if (MemoryRegionMap::IsWorking()) { |
691 // It assumes that every mmap'ed region is included in one maps line. | 668 // It assumes that every mmap'ed region is included in one maps line. |
692 uint64 cursor = first_address; | 669 uint64 cursor = first_address; |
693 bool first = true; | 670 bool first = true; |
694 | 671 |
695 do { | 672 do { |
673 Bucket* bucket = NULL; | |
674 DeepBucket* deep_bucket = NULL; | |
696 if (!first) { | 675 if (!first) { |
697 mmap_list[mmap_list_index].type = type; | 676 size_t committed = deep_profile->memory_residence_info_getter_-> |
698 cursor = mmap_list[mmap_list_index].last_address + 1; | 677 CommittedSize(mmap_iter->start_addr, mmap_iter->end_addr - 1); |
699 ++mmap_list_index; | 678 // TODO(dmikurube): Store a reference to the bucket in region. |
679 Bucket* bucket = MemoryRegionMap::GetBucket( | |
680 mmap_iter->call_stack_depth, mmap_iter->call_stack); | |
681 DeepBucket* deep_bucket = NULL; | |
682 if (bucket != NULL) { | |
683 deep_bucket = deep_profile->deep_table_.Lookup( | |
684 bucket, | |
685 #if defined(TYPE_PROFILING) | |
686 NULL, | |
687 #endif | |
688 /* is_mmap */ true); | |
689 } | |
690 | |
691 if (deep_bucket != NULL) | |
692 deep_bucket->committed_size += committed; | |
693 profiled_mmap_.AddToVirtualBytes( | |
694 mmap_iter->end_addr - mmap_iter->start_addr); | |
695 profiled_mmap_.AddToCommittedBytes(committed); | |
696 | |
697 cursor = mmap_iter->end_addr; | |
698 ++mmap_iter; | |
699 // Don't break here even if mmap_iter == EndRegionLocked(). | |
700 } | 700 } |
701 first = false; | 701 first = false; |
702 | 702 |
703 uint64 last_address_of_unhooked; | 703 uint64 last_address_of_unhooked; |
704 // If the next mmap entry is away from the current maps line. | 704 // If the next mmap entry is away from the current maps line. |
705 if (mmap_list_index >= mmap_list_length || | 705 if (mmap_iter == MemoryRegionMap::EndRegionLocked() || |
706 mmap_list[mmap_list_index].first_address > last_address) { | 706 mmap_iter->start_addr > last_address) { |
707 last_address_of_unhooked = last_address; | 707 last_address_of_unhooked = last_address; |
708 } else { | 708 } else { |
709 last_address_of_unhooked = | 709 last_address_of_unhooked = mmap_iter->start_addr - 1; |
710 mmap_list[mmap_list_index].first_address - 1; | |
711 } | 710 } |
712 | 711 |
713 if (last_address_of_unhooked + 1 > cursor) { | 712 if (last_address_of_unhooked + 1 > cursor) { |
714 uint64 committed_size = unhooked_[type].Record( | 713 uint64 committed_size = unhooked_[type].Record( |
715 memory_residence_info_getter, | 714 memory_residence_info_getter, |
716 cursor, | 715 cursor, |
717 last_address_of_unhooked); | 716 last_address_of_unhooked); |
718 if (mmap_dump_buffer) { | 717 if (mmap_dump_buffer) { |
719 mmap_dump_buffer->AppendString(" ", 0); | 718 mmap_dump_buffer->AppendString(" ", 0); |
720 mmap_dump_buffer->AppendPtr(cursor, 0); | 719 mmap_dump_buffer->AppendPtr(cursor, 0); |
721 mmap_dump_buffer->AppendString(" - ", 0); | 720 mmap_dump_buffer->AppendString(" - ", 0); |
722 mmap_dump_buffer->AppendPtr(last_address_of_unhooked + 1, 0); | 721 mmap_dump_buffer->AppendPtr(last_address_of_unhooked + 1, 0); |
723 mmap_dump_buffer->AppendString(" unhooked ", 0); | 722 mmap_dump_buffer->AppendString(" unhooked ", 0); |
724 mmap_dump_buffer->AppendString(kMapsRegionTypeDict[type], 0); | 723 mmap_dump_buffer->AppendString(kMapsRegionTypeDict[type], 0); |
725 mmap_dump_buffer->AppendString(" ", 0); | 724 mmap_dump_buffer->AppendString(" ", 0); |
726 mmap_dump_buffer->AppendInt64(committed_size, 0); | 725 mmap_dump_buffer->AppendInt64(committed_size, 0); |
727 mmap_dump_buffer->AppendString("\n", 0); | 726 mmap_dump_buffer->AppendString("\n", 0); |
728 } | 727 } |
729 cursor = last_address_of_unhooked + 1; | 728 cursor = last_address_of_unhooked + 1; |
730 } | 729 } |
731 | 730 |
732 if (mmap_list_index < mmap_list_length && | 731 if (mmap_iter != MemoryRegionMap::EndRegionLocked() && |
733 mmap_list[mmap_list_index].first_address <= last_address && | 732 mmap_iter->start_addr <= last_address && |
734 mmap_dump_buffer) { | 733 mmap_dump_buffer) { |
735 bool trailing = | 734 bool trailing = mmap_iter->start_addr < first_address; |
736 mmap_list[mmap_list_index].first_address < first_address; | 735 bool continued = mmap_iter->end_addr - 1 > last_address; |
737 bool continued = | |
738 mmap_list[mmap_list_index].last_address > last_address; | |
739 mmap_dump_buffer->AppendString(trailing ? " (" : " ", 0); | 736 mmap_dump_buffer->AppendString(trailing ? " (" : " ", 0); |
740 mmap_dump_buffer->AppendPtr( | 737 mmap_dump_buffer->AppendPtr(mmap_iter->start_addr, 0); |
741 mmap_list[mmap_list_index].first_address, 0); | |
742 mmap_dump_buffer->AppendString(trailing ? ")" : " ", 0); | 738 mmap_dump_buffer->AppendString(trailing ? ")" : " ", 0); |
743 mmap_dump_buffer->AppendString("-", 0); | 739 mmap_dump_buffer->AppendString("-", 0); |
744 mmap_dump_buffer->AppendString(continued ? "(" : " ", 0); | 740 mmap_dump_buffer->AppendString(continued ? "(" : " ", 0); |
745 mmap_dump_buffer->AppendPtr( | 741 mmap_dump_buffer->AppendPtr(mmap_iter->end_addr, 0); |
746 mmap_list[mmap_list_index].last_address + 1, 0); | |
747 mmap_dump_buffer->AppendString(continued ? ")" : " ", 0); | 742 mmap_dump_buffer->AppendString(continued ? ")" : " ", 0); |
748 mmap_dump_buffer->AppendString(" hooked ", 0); | 743 mmap_dump_buffer->AppendString(" hooked ", 0); |
749 mmap_dump_buffer->AppendString(kMapsRegionTypeDict[type], 0); | 744 mmap_dump_buffer->AppendString(kMapsRegionTypeDict[type], 0); |
750 mmap_dump_buffer->AppendString(" @ ", 0); | 745 mmap_dump_buffer->AppendString(" @ ", 0); |
751 mmap_dump_buffer->AppendInt( | 746 if (deep_bucket != NULL) |
752 mmap_list[mmap_list_index].deep_bucket->id, 0); | 747 mmap_dump_buffer->AppendInt(deep_bucket->id, 0); |
748 else | |
749 mmap_dump_buffer->AppendInt(0, 0); | |
753 mmap_dump_buffer->AppendString("\n", 0); | 750 mmap_dump_buffer->AppendString("\n", 0); |
754 } | 751 } |
755 } while (mmap_list_index < mmap_list_length && | 752 } while (mmap_iter != MemoryRegionMap::EndRegionLocked() && |
756 mmap_list[mmap_list_index].last_address <= last_address); | 753 mmap_iter->end_addr - 1 <= last_address); |
757 } | 754 } |
758 } | 755 } |
756 MemoryRegionMap::Unlock(); | |
759 } | 757 } |
760 | 758 |
761 void DeepHeapProfile::GlobalStats::SnapshotAllocations( | 759 void DeepHeapProfile::GlobalStats::SnapshotAllocations( |
762 DeepHeapProfile* deep_profile) { | 760 DeepHeapProfile* deep_profile) { |
763 profiled_mmap_.Initialize(); | |
764 profiled_malloc_.Initialize(); | 761 profiled_malloc_.Initialize(); |
765 | 762 |
766 // malloc allocations. | 763 deep_profile->heap_profile_->address_map_->Iterate(RecordAlloc, deep_profile); |
767 deep_profile->heap_profile_->alloc_address_map_->Iterate(RecordAlloc, | |
768 deep_profile); | |
769 | |
770 // mmap allocations. | |
771 if (deep_profile->heap_profile_->mmap_address_map_) { | |
772 deep_profile->heap_profile_->mmap_address_map_->Iterate(RecordMMap, | |
773 deep_profile); | |
774 std::sort(deep_profile->mmap_list_, | |
775 deep_profile->mmap_list_ + deep_profile->mmap_list_length_, | |
776 ByFirstAddress); | |
777 } | |
778 } | 764 } |
779 | 765 |
780 void DeepHeapProfile::GlobalStats::Unparse(TextBuffer* buffer) { | 766 void DeepHeapProfile::GlobalStats::Unparse(TextBuffer* buffer) { |
781 RegionStats all_total; | 767 RegionStats all_total; |
782 RegionStats unhooked_total; | 768 RegionStats unhooked_total; |
783 for (int i = 0; i < NUMBER_OF_MAPS_REGION_TYPES; ++i) { | 769 for (int i = 0; i < NUMBER_OF_MAPS_REGION_TYPES; ++i) { |
784 all_total.AddAnotherRegionStat(all_[i]); | 770 all_total.AddAnotherRegionStat(all_[i]); |
785 unhooked_total.AddAnotherRegionStat(unhooked_[i]); | 771 unhooked_total.AddAnotherRegionStat(unhooked_[i]); |
786 } | 772 } |
787 | 773 |
(...skipping 29 matching lines...) Expand all Loading... | |
817 unhooked_[FILE_EXEC].Unparse("nonprofiled-file-exec", buffer); | 803 unhooked_[FILE_EXEC].Unparse("nonprofiled-file-exec", buffer); |
818 unhooked_[FILE_NONEXEC].Unparse("nonprofiled-file-nonexec", buffer); | 804 unhooked_[FILE_NONEXEC].Unparse("nonprofiled-file-nonexec", buffer); |
819 unhooked_[STACK].Unparse("nonprofiled-stack", buffer); | 805 unhooked_[STACK].Unparse("nonprofiled-stack", buffer); |
820 unhooked_[OTHER].Unparse("nonprofiled-other", buffer); | 806 unhooked_[OTHER].Unparse("nonprofiled-other", buffer); |
821 profiled_mmap_.Unparse("profiled-mmap", buffer); | 807 profiled_mmap_.Unparse("profiled-mmap", buffer); |
822 profiled_malloc_.Unparse("profiled-malloc", buffer); | 808 profiled_malloc_.Unparse("profiled-malloc", buffer); |
823 unhooked_arena_.Unparse("unhooked-arena", buffer); | 809 unhooked_arena_.Unparse("unhooked-arena", buffer); |
824 } | 810 } |
825 | 811 |
826 // static | 812 // static |
827 bool DeepHeapProfile::GlobalStats::ByFirstAddress(const MMapListEntry& a, | |
828 const MMapListEntry& b) { | |
829 return a.first_address < b.first_address; | |
830 } | |
831 | |
832 // static | |
833 void DeepHeapProfile::GlobalStats::RecordAlloc(const void* pointer, | 813 void DeepHeapProfile::GlobalStats::RecordAlloc(const void* pointer, |
834 AllocValue* alloc_value, | 814 AllocValue* alloc_value, |
835 DeepHeapProfile* deep_profile) { | 815 DeepHeapProfile* deep_profile) { |
836 uint64 address = reinterpret_cast<uintptr_t>(pointer); | 816 uint64 address = reinterpret_cast<uintptr_t>(pointer); |
837 size_t committed = deep_profile->memory_residence_info_getter_->CommittedSize( | 817 size_t committed = deep_profile->memory_residence_info_getter_->CommittedSize( |
838 address, address + alloc_value->bytes - 1); | 818 address, address + alloc_value->bytes - 1); |
839 | 819 |
840 DeepBucket* deep_bucket = deep_profile->deep_table_.Lookup( | 820 DeepBucket* deep_bucket = deep_profile->deep_table_.Lookup( |
841 alloc_value->bucket(), | 821 alloc_value->bucket(), |
842 #if defined(TYPE_PROFILING) | 822 #if defined(TYPE_PROFILING) |
843 LookupType(pointer), | 823 LookupType(pointer), |
844 #endif | 824 #endif |
845 /* is_mmap */ false); | 825 /* is_mmap */ false); |
846 deep_bucket->committed_size += committed; | 826 deep_bucket->committed_size += committed; |
847 deep_profile->stats_.profiled_malloc_.AddToVirtualBytes(alloc_value->bytes); | 827 deep_profile->stats_.profiled_malloc_.AddToVirtualBytes(alloc_value->bytes); |
848 deep_profile->stats_.profiled_malloc_.AddToCommittedBytes(committed); | 828 deep_profile->stats_.profiled_malloc_.AddToCommittedBytes(committed); |
849 } | 829 } |
850 | 830 |
851 // static | 831 // static |
852 void DeepHeapProfile::GlobalStats::RecordMMap(const void* pointer, | |
853 AllocValue* alloc_value, | |
854 DeepHeapProfile* deep_profile) { | |
855 uint64 address = reinterpret_cast<uintptr_t>(pointer); | |
856 size_t committed = deep_profile->memory_residence_info_getter_->CommittedSize( | |
857 address, address + alloc_value->bytes - 1); | |
858 | |
859 DeepBucket* deep_bucket = deep_profile->deep_table_.Lookup( | |
860 alloc_value->bucket(), | |
861 #if defined(TYPE_PROFILING) | |
862 NULL, | |
863 #endif | |
864 /* is_mmap */ true); | |
865 deep_bucket->committed_size += committed; | |
866 deep_profile->stats_.profiled_mmap_.AddToVirtualBytes(alloc_value->bytes); | |
867 deep_profile->stats_.profiled_mmap_.AddToCommittedBytes(committed); | |
868 | |
869 if (deep_profile->mmap_list_length_ < deep_profile->num_mmap_allocations_) { | |
870 deep_profile->mmap_list_[deep_profile->mmap_list_length_].first_address = | |
871 address; | |
872 deep_profile->mmap_list_[deep_profile->mmap_list_length_].last_address = | |
873 address - 1 + alloc_value->bytes; | |
874 deep_profile->mmap_list_[deep_profile->mmap_list_length_].type = ABSENT; | |
875 deep_profile->mmap_list_[deep_profile->mmap_list_length_].deep_bucket = | |
876 deep_bucket; | |
877 ++deep_profile->mmap_list_length_; | |
878 } else { | |
879 RAW_LOG(0, "Unexpected number of mmap entries: %d/%d", | |
880 deep_profile->mmap_list_length_, | |
881 deep_profile->num_mmap_allocations_); | |
882 } | |
883 } | |
884 | |
885 // static | |
886 void DeepHeapProfile::WriteProcMaps(const char* prefix, | 832 void DeepHeapProfile::WriteProcMaps(const char* prefix, |
887 int buffer_size, | 833 int buffer_size, |
888 char raw_buffer[]) { | 834 char raw_buffer[]) { |
889 char filename[100]; | 835 char filename[100]; |
890 snprintf(filename, sizeof(filename), | 836 snprintf(filename, sizeof(filename), |
891 "%s.%05d.maps", prefix, static_cast<int>(getpid())); | 837 "%s.%05d.maps", prefix, static_cast<int>(getpid())); |
892 | 838 |
893 RawFD fd = RawOpenForWriting(filename); | 839 RawFD fd = RawOpenForWriting(filename); |
894 RAW_DCHECK(fd != kIllegalRawFD, ""); | 840 RAW_DCHECK(fd != kIllegalRawFD, ""); |
895 | 841 |
896 int length; | 842 int length; |
897 bool wrote_all; | 843 bool wrote_all; |
898 length = tcmalloc::FillProcSelfMaps(raw_buffer, buffer_size, &wrote_all); | 844 length = tcmalloc::FillProcSelfMaps(raw_buffer, buffer_size, &wrote_all); |
899 RAW_DCHECK(wrote_all, ""); | 845 RAW_DCHECK(wrote_all, ""); |
900 RAW_DCHECK(length <= buffer_size, ""); | 846 RAW_DCHECK(length <= buffer_size, ""); |
901 RawWrite(fd, raw_buffer, length); | 847 RawWrite(fd, raw_buffer, length); |
902 RawClose(fd); | 848 RawClose(fd); |
903 } | 849 } |
904 | |
905 // static | |
906 void DeepHeapProfile::CountMMap(const void* pointer, | |
907 AllocValue* alloc_value, | |
908 DeepHeapProfile* deep_profile) { | |
909 ++deep_profile->num_mmap_allocations_; | |
910 } | |
911 #else // DEEP_HEAP_PROFILE | 850 #else // DEEP_HEAP_PROFILE |
912 | 851 |
913 DeepHeapProfile::DeepHeapProfile(HeapProfileTable* heap_profile, | 852 DeepHeapProfile::DeepHeapProfile(HeapProfileTable* heap_profile, |
914 const char* prefix) | 853 const char* prefix) |
915 : heap_profile_(heap_profile) { | 854 : heap_profile_(heap_profile) { |
916 } | 855 } |
917 | 856 |
918 DeepHeapProfile::~DeepHeapProfile() { | 857 DeepHeapProfile::~DeepHeapProfile() { |
919 } | 858 } |
920 | 859 |
921 int DeepHeapProfile::FillOrderedProfile(char raw_buffer[], int buffer_size) { | 860 int DeepHeapProfile::FillOrderedProfile(char raw_buffer[], int buffer_size) { |
922 return heap_profile_->FillOrderedProfile(raw_buffer, buffer_size); | 861 return heap_profile_->FillOrderedProfile(raw_buffer, buffer_size); |
923 } | 862 } |
924 | 863 |
925 #endif // DEEP_HEAP_PROFILE | 864 #endif // DEEP_HEAP_PROFILE |
OLD | NEW |