summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorgman@chromium.org <gman@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-11-09 10:48:44 +0000
committergman@chromium.org <gman@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-11-09 10:48:44 +0000
commit93cf4f34365d9fc2a473a3b4c4c4a0cbea3e29d6 (patch)
tree73096f6070247d7fc08a1bc348bbffa8a965e2df
parent3fb6a6946e7d160f186255d8decd5eb67c011946 (diff)
downloadchromium_src-93cf4f34365d9fc2a473a3b4c4c4a0cbea3e29d6.zip
chromium_src-93cf4f34365d9fc2a473a3b4c4c4a0cbea3e29d6.tar.gz
chromium_src-93cf4f34365d9fc2a473a3b4c4c4a0cbea3e29d6.tar.bz2
Refactor DeepHeapProfile::ProcPagemap for cross platform support
BUG=159993 Review URL: https://chromiumcodereview.appspot.com/11293164 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@166889 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--third_party/tcmalloc/chromium/src/deep-heap-profile.cc267
-rw-r--r--third_party/tcmalloc/chromium/src/deep-heap-profile.h70
2 files changed, 197 insertions, 140 deletions
diff --git a/third_party/tcmalloc/chromium/src/deep-heap-profile.cc b/third_party/tcmalloc/chromium/src/deep-heap-profile.cc
index 19f5390..8535275 100644
--- a/third_party/tcmalloc/chromium/src/deep-heap-profile.cc
+++ b/third_party/tcmalloc/chromium/src/deep-heap-profile.cc
@@ -38,9 +38,158 @@ static const char kProcSelfMapsHeader[] = "\nMAPPED_LIBRARIES:\n";
static const char kVirtualLabel[] = "virtual";
static const char kCommittedLabel[] = "committed";
+namespace {
+
+#if defined(__linux__)
+
+// Implements MemoryResidenceInfoGetterInterface for Linux.
+class MemoryInfoGetterLinux :
+ public DeepHeapProfile::MemoryResidenceInfoGetterInterface {
+ public:
+ MemoryInfoGetterLinux(): fd_(kIllegalRawFD) {}
+ virtual ~MemoryInfoGetterLinux() {}
+
+ // Opens /proc/<pid>/pagemap and stores its file descriptor.
+ // It keeps open while the process is running.
+ //
+ // Note that file descriptors need to be refreshed after fork.
+ virtual void Initialize();
+
+ // Returns the number of resident (including swapped) bytes of the given
+ // memory region from |first_address| to |last_address| inclusive.
+ virtual size_t CommittedSize(uint64 first_address, uint64 last_address) const;
+
+ private:
+ struct State {
+ bool is_committed; // Currently, we use only this
+ bool is_present;
+ bool is_swapped;
+ bool is_shared;
+ bool is_mmap;
+ };
+
+ // Seeks to the offset of the open pagemap file.
+ // It returns true if succeeded.
+ bool Seek(uint64 address) const;
+
+ // Reads a pagemap state from the current offset.
+ // It returns true if succeeded.
+ bool Read(State* state) const;
+
+ RawFD fd_;
+};
+
+void MemoryInfoGetterLinux::Initialize() {
+ char filename[100];
+ snprintf(filename, sizeof(filename), "/proc/%d/pagemap",
+ static_cast<int>(getpid()));
+ fd_ = open(filename, O_RDONLY);
+ RAW_DCHECK(fd_ != -1, "Failed to open /proc/self/pagemap");
+}
+
+size_t MemoryInfoGetterLinux::CommittedSize(
+ uint64 first_address, uint64 last_address) const {
+ int page_size = getpagesize();
+ uint64 page_address = (first_address / page_size) * page_size;
+ size_t committed_size = 0;
+
+ Seek(first_address);
+
+ // Check every page on which the allocation resides.
+ while (page_address <= last_address) {
+ // Read corresponding physical page.
+ State state;
+ // TODO(dmikurube): Read pagemap in bulk for speed.
+ if (Read(&state) == false) {
+ // We can't read the last region (e.g vsyscall).
+#ifndef NDEBUG
+ RAW_LOG(0, "pagemap read failed @ %#llx %"PRId64" bytes",
+ first_address, last_address - first_address + 1);
+#endif
+ return 0;
+ }
+
+ if (state.is_committed) {
+ // Calculate the size of the allocation part in this page.
+ size_t bytes = page_size;
+
+ // If looking at the last page in a given region.
+ if (last_address <= page_address - 1 + page_size) {
+ bytes = last_address - page_address + 1;
+ }
+
+ // If looking at the first page in a given region.
+ if (page_address < first_address) {
+ bytes -= first_address - page_address;
+ }
+
+ committed_size += bytes;
+ }
+ if (page_address > MAX_ADDRESS - page_size) {
+ break;
+ }
+ page_address += page_size;
+ }
+
+ return committed_size;
+}
+
+bool MemoryInfoGetterLinux::Seek(uint64 address) const {
+ int64 index = (address / getpagesize()) * PAGEMAP_BYTES;
+ int64 offset = lseek64(fd_, index, SEEK_SET);
+ RAW_DCHECK(offset == index, "Failed in seeking.");
+ return offset >= 0;
+}
+
+bool MemoryInfoGetterLinux::Read(State* state) const {
+ static const uint64 U64_1 = 1;
+ static const uint64 PFN_FILTER = (U64_1 << 55) - U64_1;
+ static const uint64 PAGE_PRESENT = U64_1 << 63;
+ static const uint64 PAGE_SWAP = U64_1 << 62;
+ static const uint64 PAGE_RESERVED = U64_1 << 61;
+ static const uint64 FLAG_NOPAGE = U64_1 << 20;
+ static const uint64 FLAG_KSM = U64_1 << 21;
+ static const uint64 FLAG_MMAP = U64_1 << 11;
+
+ uint64 pagemap_value;
+ int result = read(fd_, &pagemap_value, PAGEMAP_BYTES);
+ if (result != PAGEMAP_BYTES) {
+ return false;
+ }
+
+ // Check if the page is committed.
+ state->is_committed = (pagemap_value & (PAGE_PRESENT | PAGE_SWAP));
+
+ state->is_present = (pagemap_value & PAGE_PRESENT);
+ state->is_swapped = (pagemap_value & PAGE_SWAP);
+ state->is_shared = false;
+
+ return true;
+}
+
+#endif // defined(__linux__)
+
+} // anonymous namespace
+
+DeepHeapProfile::MemoryResidenceInfoGetterInterface::
+ MemoryResidenceInfoGetterInterface() {}
+
+DeepHeapProfile::MemoryResidenceInfoGetterInterface::
+ ~MemoryResidenceInfoGetterInterface() {}
+
+DeepHeapProfile::MemoryResidenceInfoGetterInterface*
+ DeepHeapProfile::MemoryResidenceInfoGetterInterface::Create() {
+#if defined(__linux__)
+ return new MemoryInfoGetterLinux();
+#else
+ return NULL;
+#endif
+}
+
DeepHeapProfile::DeepHeapProfile(HeapProfileTable* heap_profile,
const char* prefix)
- : pagemap_(),
+ : memory_residence_info_getter_(
+ MemoryResidenceInfoGetterInterface::Create()),
most_recent_pid_(-1),
stats_(),
dump_count_(0),
@@ -62,6 +211,7 @@ DeepHeapProfile::DeepHeapProfile(HeapProfileTable* heap_profile,
DeepHeapProfile::~DeepHeapProfile() {
heap_profile_->dealloc_(profiler_buffer_);
heap_profile_->dealloc_(filename_prefix_);
+ delete memory_residence_info_getter_;
}
// Global malloc() should not be used in this function.
@@ -79,7 +229,7 @@ int DeepHeapProfile::FillOrderedProfile(char raw_buffer[], int buffer_size) {
if (most_recent_pid_ != getpid()) {
most_recent_pid_ = getpid();
- pagemap_.Open();
+ memory_residence_info_getter_->Initialize();
deep_table_.ResetIsLogged();
// Write maps into "|filename_prefix_|.<pid>.maps".
@@ -108,7 +258,7 @@ int DeepHeapProfile::FillOrderedProfile(char raw_buffer[], int buffer_size) {
mmap_list_[i].first_address = 0;
mmap_list_[num_mmap_allocations_ - 1].last_address = 0;
- stats_.SnapshotProcMaps(pagemap_, NULL, 0);
+ stats_.SnapshotProcMaps(memory_residence_info_getter_, NULL, 0);
// TODO(dmikurube): Eliminate dynamic memory allocation caused by snprintf.
// glibc's snprintf internally allocates memory by alloca normally, but it
@@ -118,7 +268,8 @@ int DeepHeapProfile::FillOrderedProfile(char raw_buffer[], int buffer_size) {
stats_.SnapshotAllocations(this);
// Check if committed bytes changed during SnapshotAllocations.
- stats_.SnapshotProcMaps(pagemap_, mmap_list_, mmap_list_length_);
+ stats_.SnapshotProcMaps(
+ memory_residence_info_getter_, mmap_list_, mmap_list_length_);
buffer.AppendString(kProfileHeader, 0);
buffer.AppendString(kProfileVersion, 0);
@@ -237,94 +388,6 @@ bool DeepHeapProfile::TextBuffer::ForwardCursor(int appended) {
return true;
}
-void DeepHeapProfile::ProcPagemap::Open() {
- char filename[100];
- snprintf(filename, sizeof(filename), "/proc/%d/pagemap",
- static_cast<int>(getpid()));
- fd_ = open(filename, O_RDONLY);
- RAW_DCHECK(fd_ != -1, "Failed to open /proc/self/pagemap");
-}
-
-size_t DeepHeapProfile::ProcPagemap::CommittedSize(
- uint64 first_address, uint64 last_address) const {
- int page_size = getpagesize();
- uint64 page_address = (first_address / page_size) * page_size;
- size_t committed_size = 0;
-
- Seek(first_address);
-
- // Check every page on which the allocation resides.
- while (page_address <= last_address) {
- // Read corresponding physical page.
- State state;
- // TODO(dmikurube): Read pagemap in bulk for speed.
- if (Read(&state) == false) {
- // We can't read the last region (e.g vsyscall).
-#ifndef NDEBUG
- RAW_LOG(0, "pagemap read failed @ %#llx %"PRId64" bytes",
- first_address, last_address - first_address + 1);
-#endif
- return 0;
- }
-
- if (state.is_committed) {
- // Calculate the size of the allocation part in this page.
- size_t bytes = page_size;
-
- // If looking at the last page in a given region.
- if (last_address <= page_address - 1 + page_size) {
- bytes = last_address - page_address + 1;
- }
-
- // If looking at the first page in a given region.
- if (page_address < first_address) {
- bytes -= first_address - page_address;
- }
-
- committed_size += bytes;
- }
- if (page_address > MAX_ADDRESS - page_size) {
- break;
- }
- page_address += page_size;
- }
-
- return committed_size;
-}
-
-bool DeepHeapProfile::ProcPagemap::Seek(uint64 address) const {
- int64 index = (address / getpagesize()) * PAGEMAP_BYTES;
- int64 offset = lseek64(fd_, index, SEEK_SET);
- RAW_DCHECK(offset == index, "Failed in seeking.");
- return offset >= 0;
-}
-
-bool DeepHeapProfile::ProcPagemap::Read(State* state) const {
- static const uint64 U64_1 = 1;
- static const uint64 PFN_FILTER = (U64_1 << 55) - U64_1;
- static const uint64 PAGE_PRESENT = U64_1 << 63;
- static const uint64 PAGE_SWAP = U64_1 << 62;
- static const uint64 PAGE_RESERVED = U64_1 << 61;
- static const uint64 FLAG_NOPAGE = U64_1 << 20;
- static const uint64 FLAG_KSM = U64_1 << 21;
- static const uint64 FLAG_MMAP = U64_1 << 11;
-
- uint64 pagemap_value;
- int result = read(fd_, &pagemap_value, PAGEMAP_BYTES);
- if (result != PAGEMAP_BYTES) {
- return false;
- }
-
- // Check if the page is committed.
- state->is_committed = (pagemap_value & (PAGE_PRESENT | PAGE_SWAP));
-
- state->is_present = (pagemap_value & PAGE_PRESENT);
- state->is_swapped = (pagemap_value & PAGE_SWAP);
- state->is_shared = false;
-
- return true;
-}
-
void DeepHeapProfile::DeepBucket::UnparseForStats(TextBuffer* buffer) {
buffer->AppendInt64(bucket->alloc_size - bucket->free_size, 10);
buffer->AppendChar(' ');
@@ -529,9 +592,12 @@ void DeepHeapProfile::RegionStats::Initialize() {
}
void DeepHeapProfile::RegionStats::Record(
- const ProcPagemap& pagemap, uint64 first_address, uint64 last_address) {
+ const MemoryResidenceInfoGetterInterface* memory_residence_info_getter,
+ uint64 first_address,
+ uint64 last_address) {
virtual_bytes_ += static_cast<size_t>(last_address - first_address + 1);
- committed_bytes_ += pagemap.CommittedSize(first_address, last_address);
+ committed_bytes_ += memory_residence_info_getter->CommittedSize(first_address,
+ last_address);
}
void DeepHeapProfile::RegionStats::Unparse(const char* name,
@@ -546,7 +612,7 @@ void DeepHeapProfile::RegionStats::Unparse(const char* name,
// TODO(dmikurube): Eliminate dynamic memory allocation caused by snprintf.
void DeepHeapProfile::GlobalStats::SnapshotProcMaps(
- const ProcPagemap& pagemap,
+ const MemoryResidenceInfoGetterInterface* memory_residence_info_getter,
MMapListEntry* mmap_list,
int mmap_list_length) {
ProcMapsIterator::Buffer iterator_buffer;
@@ -584,7 +650,8 @@ void DeepHeapProfile::GlobalStats::SnapshotProcMaps(
} else {
type = OTHER;
}
- all_[type].Record(pagemap, first_address, last_address);
+ all_[type].Record(
+ memory_residence_info_getter, first_address, last_address);
// TODO(dmikurube): Stop double-counting pagemap.
// Counts nonprofiled memory regions in /proc/<pid>/maps.
@@ -613,7 +680,9 @@ void DeepHeapProfile::GlobalStats::SnapshotProcMaps(
if (last_address_of_nonprofiled + 1 > cursor) {
nonprofiled_[type].Record(
- pagemap, cursor, last_address_of_nonprofiled);
+ memory_residence_info_getter,
+ cursor,
+ last_address_of_nonprofiled);
cursor = last_address_of_nonprofiled + 1;
}
} while (mmap_list_index < mmap_list_length &&
@@ -695,7 +764,7 @@ void DeepHeapProfile::GlobalStats::RecordAlloc(const void* pointer,
AllocValue* alloc_value,
DeepHeapProfile* deep_profile) {
uint64 address = reinterpret_cast<uintptr_t>(pointer);
- size_t committed = deep_profile->pagemap_.CommittedSize(
+ size_t committed = deep_profile->memory_residence_info_getter_->CommittedSize(
address, address + alloc_value->bytes - 1);
DeepBucket* deep_bucket = deep_profile->deep_table_.Lookup(
@@ -714,7 +783,7 @@ void DeepHeapProfile::GlobalStats::RecordMMap(const void* pointer,
AllocValue* alloc_value,
DeepHeapProfile* deep_profile) {
uint64 address = reinterpret_cast<uintptr_t>(pointer);
- size_t committed = deep_profile->pagemap_.CommittedSize(
+ size_t committed = deep_profile->memory_residence_info_getter_->CommittedSize(
address, address + alloc_value->bytes - 1);
DeepBucket* deep_bucket = deep_profile->deep_table_.Lookup(
diff --git a/third_party/tcmalloc/chromium/src/deep-heap-profile.h b/third_party/tcmalloc/chromium/src/deep-heap-profile.h
index bdaa935..121c5b8 100644
--- a/third_party/tcmalloc/chromium/src/deep-heap-profile.h
+++ b/third_party/tcmalloc/chromium/src/deep-heap-profile.h
@@ -45,6 +45,26 @@
class DeepHeapProfile {
public:
+ // Defines an interface for getting info about memory residence.
+ class MemoryResidenceInfoGetterInterface {
+ public:
+ virtual ~MemoryResidenceInfoGetterInterface();
+
+ // Initializes the instance.
+ virtual void Initialize() = 0;
+
+ // Returns the number of resident (including swapped) bytes of the given
+ // memory region from |first_address| to |last_address| inclusive.
+ virtual size_t CommittedSize(
+ uint64 first_address, uint64 last_address) const = 0;
+
+ // Creates a new platform specific MemoryResidenceInfoGetterInterface.
+ static MemoryResidenceInfoGetterInterface* Create();
+
+ protected:
+ MemoryResidenceInfoGetterInterface();
+ };
+
// Constructs a DeepHeapProfile instance. It works as a wrapper of
// HeapProfileTable.
//
@@ -128,40 +148,6 @@ class DeepHeapProfile {
DISALLOW_COPY_AND_ASSIGN(TextBuffer);
};
- class ProcPagemap {
- public:
- ProcPagemap(): fd_(kIllegalRawFD) {}
-
- // Opens /proc/<pid>/pagemap and stores its file descriptor.
- // It keeps open while the process is running.
- //
- // Note that file descriptors need to be refreshed after fork.
- void Open();
-
- // Returns the number of resident (including swapped) bytes of the given
- // memory region from |first_address| to |last_address| inclusive.
- size_t CommittedSize(uint64 first_address, uint64 last_address) const;
-
- private:
- struct State {
- bool is_committed; // Currently, we use only this
- bool is_present;
- bool is_swapped;
- bool is_shared;
- bool is_mmap;
- };
-
- // Seeks to the offset of the open pagemap file.
- // It returns true if succeeded.
- bool Seek(uint64 address) const;
-
- // Reads a pagemap state from the current offset.
- // It returns true if succeeded.
- bool Read(State* state) const;
-
- RawFD fd_;
- };
-
struct MMapListEntry {
uint64 first_address;
uint64 last_address;
@@ -240,9 +226,10 @@ class DeepHeapProfile {
// Updates itself to contain the tallies of 'virtual_bytes' and
// 'committed_bytes' in the region from |first_adress| to |last_address|
// inclusive.
- void Record(const ProcPagemap& pagemap,
- uint64 first_address,
- uint64 last_address);
+ void Record(
+ const MemoryResidenceInfoGetterInterface* memory_residence_info_getter,
+ uint64 first_address,
+ uint64 last_address);
// Writes stats of the region into |buffer| with |name|.
void Unparse(const char* name, TextBuffer* buffer);
@@ -268,9 +255,10 @@ class DeepHeapProfile {
class GlobalStats {
public:
// Snapshots and calculates global stats from /proc/<pid>/maps and pagemap.
- void SnapshotProcMaps(const ProcPagemap& pagemap,
- MMapListEntry* mmap_list,
- int mmap_list_length);
+ void SnapshotProcMaps(
+ const MemoryResidenceInfoGetterInterface* memory_residence_info_getter,
+ MMapListEntry* mmap_list,
+ int mmap_list_length);
// Snapshots allocations by malloc and mmap.
void SnapshotAllocations(DeepHeapProfile* deep_profile);
@@ -321,7 +309,7 @@ class DeepHeapProfile {
AllocValue* alloc_value,
DeepHeapProfile* deep_profile);
- ProcPagemap pagemap_;
+ MemoryResidenceInfoGetterInterface* memory_residence_info_getter_;
// Process ID of the last dump. This can change by fork.
pid_t most_recent_pid_;