diff options
author | dmikurube@chromium.org <dmikurube@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-04-13 11:44:49 +0000 |
---|---|---|
committer | dmikurube@chromium.org <dmikurube@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-04-13 11:44:49 +0000 |
commit | c46965928ecaedf3f96e3d8f203fac8f6b2125ed (patch) | |
tree | 1e383463bdceed4ea8fdc7d252296ea5e2ada39b /third_party/tcmalloc | |
parent | 5571d642d81495e2fc958abe2e320604a044b1ef (diff) | |
download | chromium_src-c46965928ecaedf3f96e3d8f203fac8f6b2125ed.zip chromium_src-c46965928ecaedf3f96e3d8f203fac8f6b2125ed.tar.gz chromium_src-c46965928ecaedf3f96e3d8f203fac8f6b2125ed.tar.bz2 |
Breakdown nonprofiled memory regions (f.k.a. 'unknown'), and add new policy files.
It breaks down nonprofiled memory regions (f.k.a. 'unknown') with using information
from /proc/(pid)/maps.
'mustbezero' and 'nonprofiled-*' columns show broken down values.
- mustbezero: works as a sentinel value. it should be '0'. tell dmikurube@ if it > 0.
- nonprofiled-absent: works as a sentinel value. should be '0'.
- nonprofiled-anonymous: may be still 'unknown'. no special info from maps.
- nonprofiled-file-exec: is a mapped file here as executable.
- nonprofiled-file-nonexec: is a mapped file here as non-executable.
- nonprofiled-stack: is a stack.
- nonprofiled-other: includes [vdso] and some small portions.
It also removes dmpolicy (an old one) and adds new policy files: policy.l{0-2}.txt.
The new files 'policy.l{0-2}.txt' are recommended instead of 'dmpolicy'.
policy.l0.txt is the roughest, and policy.l2.txt is the finest breakdown.
We can check that summation from 'FROM_HERE_FOR_TOTAL' till 'UNTIL_HERE_FOR_TOTAL'
is equal to 'total-exclude-profiler'.
Finally, dmprof.py is renamed into dmprof like pprof in tcmalloc.
BUG=none
TEST=none
Review URL: http://codereview.chromium.org/9812010
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@132174 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'third_party/tcmalloc')
-rw-r--r-- | third_party/tcmalloc/chromium/src/deep-heap-profile.cc | 201 | ||||
-rw-r--r-- | third_party/tcmalloc/chromium/src/deep-heap-profile.h | 74 |
2 files changed, 219 insertions, 56 deletions
diff --git a/third_party/tcmalloc/chromium/src/deep-heap-profile.cc b/third_party/tcmalloc/chromium/src/deep-heap-profile.cc index 97c874a..dc96f9c 100644 --- a/third_party/tcmalloc/chromium/src/deep-heap-profile.cc +++ b/third_party/tcmalloc/chromium/src/deep-heap-profile.cc @@ -10,6 +10,7 @@ #include "deep-heap-profile.h" #ifdef DEEP_HEAP_PROFILE +#include <algorithm> #include <fcntl.h> #include <sys/stat.h> #include <sys/types.h> @@ -28,7 +29,7 @@ static const uint64 MAX_ADDRESS = kuint64max; // Header strings of the dumped heap profile. static const char kProfileHeader[] = "heap profile: "; -static const char kProfileVersion[] = "DUMP_DEEP_3"; +static const char kProfileVersion[] = "DUMP_DEEP_4"; static const char kGlobalStatsHeader[] = "GLOBAL_STATS:\n"; static const char kMMapStacktraceHeader[] = "MMAP_STACKTRACES:\n"; static const char kAllocStacktraceHeader[] = "MALLOC_STACKTRACES:\n"; @@ -89,8 +90,23 @@ int DeepHeapProfile::FillOrderedProfile(char buffer[], int buffer_size) { ResetCommittedSize(heap_profile_->alloc_table_); ResetCommittedSize(heap_profile_->mmap_table_); - SnapshotGlobalStatsWithoutMalloc(pagemap_fd_, &stats_); - size_t anonymous_committed = stats_.anonymous.committed_bytes(); + // Allocate a list for mmap'ed regions. + num_mmap_allocations_ = 0; + heap_profile_->mmap_address_map_->Iterate(CountMMap, this); + mmap_list_length_ = 0; + mmap_list_ = reinterpret_cast<MMapListEntry*>(heap_profile_->alloc_( + sizeof(MMapListEntry) * num_mmap_allocations_)); + + // Touch all the allocated pages. Touching is required to avoid new page + // commitment while filling the list in SnapshotGlobalStatsWithoutMalloc. + for (int i = 0; + i < num_mmap_allocations_; + i += getpagesize() / 2 / sizeof(MMapListEntry)) + mmap_list_[i].first_address = 0; + mmap_list_[num_mmap_allocations_ - 1].last_address = 0; + + SnapshotGlobalStatsWithoutMalloc(pagemap_fd_, &stats_, NULL, 0); + size_t anonymous_committed = stats_.all[ANONYMOUS].committed_bytes(); // Note: Try to minimize the number of calls to malloc in the following // region, up until we call WriteBucketsToBucketFile(), near the end of this @@ -106,10 +122,11 @@ int DeepHeapProfile::FillOrderedProfile(char buffer[], int buffer_size) { SnapshotAllAllocsWithoutMalloc(); // Check if committed bytes changed during SnapshotAllAllocsWithoutMalloc. - SnapshotGlobalStatsWithoutMalloc(pagemap_fd_, &stats_); + SnapshotGlobalStatsWithoutMalloc(pagemap_fd_, &stats_, + mmap_list_, mmap_list_length_); #ifndef NDEBUG size_t committed_difference = - stats_.anonymous.committed_bytes() - anonymous_committed; + stats_.all[ANONYMOUS].committed_bytes() - anonymous_committed; if (committed_difference != 0) { RAW_LOG(0, "Difference in committed size: %ld", committed_difference); } @@ -179,6 +196,9 @@ int DeepHeapProfile::FillOrderedProfile(char buffer[], int buffer_size) { // Note: Memory snapshots are complete, and malloc may again be used freely. + heap_profile_->dealloc_(mmap_list_); + mmap_list_ = NULL; + // Write the bucket listing into a .bucket file. WriteBucketsToBucketFile(); @@ -276,6 +296,7 @@ size_t DeepHeapProfile::GetCommittedSize( while (page_address <= last_address) { // Read corresponding physical page. PageState state; + // TODO(dmikurube): Read pagemap in bulk for speed. if (ReadProcPagemap(pagemap_fd, &state) == false) { // We can't read the last region (e.g vsyscall). #ifndef NDEBUG @@ -334,18 +355,22 @@ void DeepHeapProfile::WriteMapsToFile(const char* filename_prefix, // ProcMapsIterator uses snprintf internally in construction. // static void DeepHeapProfile::SnapshotGlobalStatsWithoutMalloc(int pagemap_fd, - GlobalStats* stats) { + GlobalStats* stats, + MMapListEntry* mmap_list, + int mmap_list_length) { ProcMapsIterator::Buffer iterator_buffer; ProcMapsIterator iterator(0, &iterator_buffer); uint64 first_address, last_address, offset; int64 unused_inode; char* flags; char* filename; + int mmap_list_index = 0; + enum MapsRegionType type; - stats->total.Initialize(); - stats->file_mapped.Initialize(); - stats->anonymous.Initialize(); - stats->other.Initialize(); + for (int i = 0; i < NUMBER_OF_MAPS_REGION_TYPES; ++i) { + stats->all[i].Initialize(); + stats->nonprofiled[i].Initialize(); + } while (iterator.Next(&first_address, &last_address, &flags, &offset, &unused_inode, &filename)) { @@ -355,14 +380,53 @@ void DeepHeapProfile::SnapshotGlobalStatsWithoutMalloc(int pagemap_fd, continue; // Reading pagemap will fail in [vsyscall]. } - stats->total.Record(pagemap_fd, first_address, last_address); - + type = ABSENT; if (filename[0] == '/') { - stats->file_mapped.Record(pagemap_fd, first_address, last_address); + if (flags[2] == 'x') + type = FILE_EXEC; + else + type = FILE_NONEXEC; } else if (filename[0] == '\0' || filename[0] == '\n') { - stats->anonymous.Record(pagemap_fd, first_address, last_address); + type = ANONYMOUS; + } else if (strcmp(filename, "[stack]") == 0) { + type = STACK; } else { - stats->other.Record(pagemap_fd, first_address, last_address); + type = OTHER; + } + stats->all[type].Record(pagemap_fd, first_address, last_address); + + // TODO(dmikurube): Avoid double-counting of pagemap. + // Counts nonprofiled memory regions in /proc/<pid>/maps. + if (mmap_list != NULL) { + // It assumes that every mmap'ed region is included in one maps line. + uint64 cursor = first_address; + bool first = true; + + do { + if (!first) { + mmap_list[mmap_list_index].type = type; + cursor = mmap_list[mmap_list_index].last_address + 1; + ++mmap_list_index; + } + first = false; + + uint64 last_address_of_nonprofiled; + // If the next mmap entry is away from the current maps line. + if (mmap_list_index >= mmap_list_length || + mmap_list[mmap_list_index].first_address > last_address) { + last_address_of_nonprofiled = last_address; + } else { + last_address_of_nonprofiled = + mmap_list[mmap_list_index].first_address - 1; + } + + if (last_address_of_nonprofiled + 1 > cursor) { + stats->nonprofiled[type].Record( + pagemap_fd, cursor, last_address_of_nonprofiled); + cursor = last_address_of_nonprofiled + 1; + } + } while (mmap_list_index < mmap_list_length && + mmap_list[mmap_list_index].last_address <= last_address); } } } @@ -412,6 +476,19 @@ int DeepHeapProfile::SnapshotBucketTableWithoutMalloc(Bucket** bucket_table, return used_in_buffer; } +// static +bool DeepHeapProfile::ByFirstAddress(const MMapListEntry& a, + const MMapListEntry& b) { + return a.first_address < b.first_address; +} + +// static +void DeepHeapProfile::CountMMap(const void* pointer, + AllocValue* alloc_value, + DeepHeapProfile* deep_profile) { + ++deep_profile->num_mmap_allocations_; +} + void DeepHeapProfile::RecordAlloc(const void* pointer, AllocValue* alloc_value, DeepHeapProfile* deep_profile) { @@ -421,8 +498,8 @@ void DeepHeapProfile::RecordAlloc(const void* pointer, DeepBucket* deep_bucket = deep_profile->GetDeepBucket(alloc_value->bucket()); deep_bucket->committed_size += committed; - deep_profile->stats_.record_malloc.AddToVirtualBytes(alloc_value->bytes); - deep_profile->stats_.record_malloc.AddToCommittedBytes(committed); + deep_profile->stats_.profiled_malloc.AddToVirtualBytes(alloc_value->bytes); + deep_profile->stats_.profiled_malloc.AddToCommittedBytes(committed); } void DeepHeapProfile::RecordMMap(const void* pointer, @@ -434,19 +511,33 @@ void DeepHeapProfile::RecordMMap(const void* pointer, DeepBucket* deep_bucket = deep_profile->GetDeepBucket(alloc_value->bucket()); deep_bucket->committed_size += committed; - deep_profile->stats_.record_mmap.AddToVirtualBytes(alloc_value->bytes); - deep_profile->stats_.record_mmap.AddToCommittedBytes(committed); + deep_profile->stats_.profiled_mmap.AddToVirtualBytes(alloc_value->bytes); + deep_profile->stats_.profiled_mmap.AddToCommittedBytes(committed); + + if (deep_profile->mmap_list_length_ < deep_profile->num_mmap_allocations_) { + deep_profile->mmap_list_[deep_profile->mmap_list_length_].first_address = + address; + deep_profile->mmap_list_[deep_profile->mmap_list_length_].last_address = + address - 1 + alloc_value->bytes; + deep_profile->mmap_list_[deep_profile->mmap_list_length_].type = ABSENT; + ++deep_profile->mmap_list_length_; + } else { + RAW_LOG(0, "Unexpected number of mmap entries: %d/%d", + deep_profile->mmap_list_length_, + deep_profile->num_mmap_allocations_); + } } void DeepHeapProfile::SnapshotAllAllocsWithoutMalloc() { - stats_.record_mmap.Initialize(); - stats_.record_malloc.Initialize(); + stats_.profiled_mmap.Initialize(); + stats_.profiled_malloc.Initialize(); // malloc allocations. heap_profile_->alloc_address_map_->Iterate(RecordAlloc, this); // mmap allocations. heap_profile_->mmap_address_map_->Iterate(RecordMMap, this); + std::sort(mmap_list_, mmap_list_ + mmap_list_length_, ByFirstAddress); } int DeepHeapProfile::FillBucketForBucketFile(const DeepBucket* deep_bucket, @@ -559,7 +650,7 @@ int DeepHeapProfile::UnparseRegionStats(const RegionStats* stats, int buffer_size, char* buffer) { int printed = snprintf(buffer + used_in_buffer, buffer_size - used_in_buffer, - "%15s %10ld %10ld\n", + "%25s %12ld %12ld\n", name, stats->virtual_bytes(), stats->committed_bytes()); if (IsPrintedStringValid(printed, buffer_size, used_in_buffer)) { @@ -573,26 +664,64 @@ int DeepHeapProfile::UnparseRegionStats(const RegionStats* stats, int DeepHeapProfile::UnparseGlobalStats(int used_in_buffer, int buffer_size, char* buffer) { - int printed = snprintf(buffer + used_in_buffer, buffer_size - used_in_buffer, - "%15s %10s %10s\n", "", + RegionStats all_total; + RegionStats nonprofiled_total; + for (int i = 0; i < NUMBER_OF_MAPS_REGION_TYPES; ++i) { + all_total.AddAnotherRegionStat(stats_.all[i]); + nonprofiled_total.AddAnotherRegionStat(stats_.nonprofiled[i]); + } + int printed = snprintf( + buffer + used_in_buffer, buffer_size - used_in_buffer, + "# total (%lu) %c= profiled-mmap (%lu) + nonprofiled-* (%lu)\n", + all_total.committed_bytes(), + all_total.committed_bytes() == + stats_.profiled_mmap.committed_bytes() + + nonprofiled_total.committed_bytes() ? '=' : '!', + stats_.profiled_mmap.committed_bytes(), + nonprofiled_total.committed_bytes()); + if (IsPrintedStringValid(printed, buffer_size, used_in_buffer)) { + return used_in_buffer; + } + used_in_buffer += printed; + + printed = snprintf(buffer + used_in_buffer, buffer_size - used_in_buffer, + "%25s %12s %12s\n", "", kVirtualLabel, kCommittedLabel); if (IsPrintedStringValid(printed, buffer_size, used_in_buffer)) { return used_in_buffer; } used_in_buffer += printed; - used_in_buffer = UnparseRegionStats(&(stats_.total), "total", - used_in_buffer, buffer_size, buffer); - used_in_buffer = UnparseRegionStats(&(stats_.file_mapped), "file mapped", - used_in_buffer, buffer_size, buffer); - used_in_buffer = UnparseRegionStats(&(stats_.anonymous), "anonymous", - used_in_buffer, buffer_size, buffer); - used_in_buffer = UnparseRegionStats(&(stats_.other), "other", - used_in_buffer, buffer_size, buffer); - used_in_buffer = UnparseRegionStats(&(stats_.record_mmap), "mmap", - used_in_buffer, buffer_size, buffer); - used_in_buffer = UnparseRegionStats(&(stats_.record_malloc), "tcmalloc", - used_in_buffer, buffer_size, buffer); + used_in_buffer = UnparseRegionStats(&(all_total), + "total", used_in_buffer, buffer_size, buffer); + used_in_buffer = UnparseRegionStats(&(stats_.all[FILE_EXEC]), + "file-exec", used_in_buffer, buffer_size, buffer); + used_in_buffer = UnparseRegionStats(&(stats_.all[FILE_NONEXEC]), + "file-nonexec", used_in_buffer, buffer_size, buffer); + used_in_buffer = UnparseRegionStats(&(stats_.all[ANONYMOUS]), + "anonymous", used_in_buffer, buffer_size, buffer); + used_in_buffer = UnparseRegionStats(&(stats_.all[STACK]), + "stack", used_in_buffer, buffer_size, buffer); + used_in_buffer = UnparseRegionStats(&(stats_.all[OTHER]), + "other", used_in_buffer, buffer_size, buffer); + used_in_buffer = UnparseRegionStats(&(nonprofiled_total), + "nonprofiled-total", used_in_buffer, buffer_size, buffer); + used_in_buffer = UnparseRegionStats(&(stats_.nonprofiled[ABSENT]), + "nonprofiled-absent", used_in_buffer, buffer_size, buffer); + used_in_buffer = UnparseRegionStats(&(stats_.nonprofiled[ANONYMOUS]), + "nonprofiled-anonymous", used_in_buffer, buffer_size, buffer); + used_in_buffer = UnparseRegionStats(&(stats_.nonprofiled[FILE_EXEC]), + "nonprofiled-file-exec", used_in_buffer, buffer_size, buffer); + used_in_buffer = UnparseRegionStats(&(stats_.nonprofiled[FILE_NONEXEC]), + "nonprofiled-file-nonexec", used_in_buffer, buffer_size, buffer); + used_in_buffer = UnparseRegionStats(&(stats_.nonprofiled[STACK]), + "nonprofiled-stack", used_in_buffer, buffer_size, buffer); + used_in_buffer = UnparseRegionStats(&(stats_.nonprofiled[OTHER]), + "nonprofiled-other", used_in_buffer, buffer_size, buffer); + used_in_buffer = UnparseRegionStats(&(stats_.profiled_mmap), + "profiled-mmap", used_in_buffer, buffer_size, buffer); + used_in_buffer = UnparseRegionStats(&(stats_.profiled_malloc), + "profiled-malloc", used_in_buffer, buffer_size, buffer); return used_in_buffer; } #else // DEEP_HEAP_PROFILE diff --git a/third_party/tcmalloc/chromium/src/deep-heap-profile.h b/third_party/tcmalloc/chromium/src/deep-heap-profile.h index 6638d32..4c65af1 100644 --- a/third_party/tcmalloc/chromium/src/deep-heap-profile.h +++ b/third_party/tcmalloc/chromium/src/deep-heap-profile.h @@ -40,6 +40,31 @@ class DeepHeapProfile { typedef HeapProfileTable::AllocValue AllocValue; typedef HeapProfileTable::Stats Stats; + enum MapsRegionType { + // Bytes of memory which were not recognized with /proc/<pid>/maps. + // This size should be 0. + ABSENT, + + // Bytes of memory which is mapped anonymously. + // Regions which contain nothing in the last column of /proc/<pid>/maps. + ANONYMOUS, + + // Bytes of memory which is mapped to a executable/non-executable file. + // Regions which contain file paths in the last column of /proc/<pid>/maps. + FILE_EXEC, + FILE_NONEXEC, + + // Bytes of memory which is labeled [stack] in /proc/<pid>/maps. + STACK, + + // Bytes of memory which is labeled, but not mapped to any file. + // Regions which contain non-path strings in the last column of + // /proc/<pid>/maps. + OTHER, + + NUMBER_OF_MAPS_REGION_TYPES + }; + // Construct a DeepHeapProfile instance. It works as a wrapper of // HeapProfileTable. // @@ -79,7 +104,7 @@ class DeepHeapProfile { class RegionStats { public: - RegionStats() {} + RegionStats(): virtual_bytes_(0), committed_bytes_(0) {} ~RegionStats() {} // Initialize virtual_bytes and committed_bytes. @@ -104,6 +129,10 @@ class DeepHeapProfile { void AddToCommittedBytes(size_t additional_committed_bytes) { committed_bytes_ += additional_committed_bytes; } + void AddAnotherRegionStat(const RegionStats& other) { + virtual_bytes_ += other.virtual_bytes_; + committed_bytes_ += other.committed_bytes_; + } private: size_t virtual_bytes_; @@ -116,28 +145,20 @@ class DeepHeapProfile { // memory and committed memory. // TODO(dmikurube): These regions should be classified more precisely later // for more detailed analysis. - - // Total bytes of the process memory. - RegionStats total; - - // Total bytes of memory which is mapped to a file. - // Regions which contain file paths in the last column of /proc/<pid>/maps. - RegionStats file_mapped; - - // Total bytes of memory which is mapped anonymously. - // Regions which contain nothing in the last column of /proc/<pid>/maps. - RegionStats anonymous; - - // Total bytes of memory which is labeled, but not mapped to any file. - // Regions which contain non-path strings in the last column of - // /proc/<pid>/maps. - RegionStats other; + RegionStats all[NUMBER_OF_MAPS_REGION_TYPES]; + RegionStats nonprofiled[NUMBER_OF_MAPS_REGION_TYPES]; // Total bytes of mmap'ed regions. - RegionStats record_mmap; + RegionStats profiled_mmap; // Total bytes of malloc'ed regions. - RegionStats record_malloc; + RegionStats profiled_malloc; + }; + + struct MMapListEntry { + uint64 first_address; + uint64 last_address; + MapsRegionType type; }; // Checks if the length of |printed| characters by snprintf is valid. @@ -178,7 +199,9 @@ class DeepHeapProfile { // Compute the global statistics from /proc/self/maps and |pagemap_fd|, and // store the statistics in |stats|. static void SnapshotGlobalStatsWithoutMalloc(int pagemap_fd, - GlobalStats* stats); + GlobalStats* stats, + MMapListEntry* mmap_list, + int mmap_list_length); // Get the DeepBucket object corresponding to the given |bucket|. // DeepBucket is an extension to Bucket which is declared above. @@ -195,6 +218,14 @@ class DeepHeapProfile { int buffer_size, char buffer[]); + static bool ByFirstAddress(const MMapListEntry& a, + const MMapListEntry& b); + + // Count mmap allocations in deep_profile->num_mmap_allocations_. + static void CountMMap(const void* pointer, + AllocValue* alloc_value, + DeepHeapProfile* deep_profile); + // Record both virtual and committed byte counts of malloc and mmap regions // as callback functions for AllocationMap::Iterate(). static void RecordAlloc(const void* pointer, @@ -248,6 +279,9 @@ class DeepHeapProfile { int bucket_id_; DeepBucketMap* deep_bucket_map_; + MMapListEntry* mmap_list_; + int mmap_list_length_; + int num_mmap_allocations_; #endif // DEEP_HEAP_PROFILE HeapProfileTable* heap_profile_; |