summaryrefslogtreecommitdiffstats
path: root/third_party
diff options
context:
space:
mode:
authordmikurube@chromium.org <dmikurube@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-04-13 11:44:49 +0000
committerdmikurube@chromium.org <dmikurube@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-04-13 11:44:49 +0000
commitc46965928ecaedf3f96e3d8f203fac8f6b2125ed (patch)
tree1e383463bdceed4ea8fdc7d252296ea5e2ada39b /third_party
parent5571d642d81495e2fc958abe2e320604a044b1ef (diff)
downloadchromium_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')
-rw-r--r--third_party/tcmalloc/chromium/src/deep-heap-profile.cc201
-rw-r--r--third_party/tcmalloc/chromium/src/deep-heap-profile.h74
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_;