diff options
author | dmikurube@chromium.org <dmikurube@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-03-16 17:20:10 +0000 |
---|---|---|
committer | dmikurube@chromium.org <dmikurube@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-03-16 17:20:10 +0000 |
commit | 856ff54b27138c316bd5433a20eeb527032e1608 (patch) | |
tree | cae500fb1b23bc37ac29bc31898761a368e58792 /third_party | |
parent | e6093fdce87b685f7fb9213f5a174c6c50caff76 (diff) | |
download | chromium_src-856ff54b27138c316bd5433a20eeb527032e1608.zip chromium_src-856ff54b27138c316bd5433a20eeb527032e1608.tar.gz chromium_src-856ff54b27138c316bd5433a20eeb527032e1608.tar.bz2 |
Revert 127171 - Experiment for a deeper heap profile dumper to check impact for performance.
This change will be reverted soon.
BUG=114301
TEST=none
Review URL: https://chromiumcodereview.appspot.com/9701097
TBR=dmikurube@chromium.org
Review URL: https://chromiumcodereview.appspot.com/9706107
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@127194 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'third_party')
4 files changed, 1 insertions, 874 deletions
diff --git a/third_party/tcmalloc/chromium/src/deep-heap-profile.cc b/third_party/tcmalloc/chromium/src/deep-heap-profile.cc deleted file mode 100644 index bc18a0c..0000000 --- a/third_party/tcmalloc/chromium/src/deep-heap-profile.cc +++ /dev/null @@ -1,600 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// --- -// Author: Sainbayar Sukhbaatar -// Dai Mikurube -// - -#include "deep-heap-profile.h" - -#ifdef DEEP_HEAP_PROFILE -#include <fcntl.h> -#include <sys/stat.h> -#include <sys/types.h> -#ifdef HAVE_UNISTD_H -#include <unistd.h> // for getpagesize and getpid -#endif // HAVE_UNISTD_H - -#include "base/cycleclock.h" -#include "base/sysinfo.h" - -static const int kProfilerBufferSize = 1 << 20; -static const int kHashTableSize = 179999; // The same as heap-profile-table.cc. - -static const int PAGEMAP_BYTES = 8; -static const uint64 TOP_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 kGlobalStatsHeader[] = "GLOBAL_STATS:\n"; -static const char kMMapStacktraceHeader[] = "MMAP_STACKTRACES:\n"; -static const char kAllocStacktraceHeader[] = "MALLOC_STACKTRACES:\n"; -static const char kProcSelfMapsHeader[] = "\nMAPPED_LIBRARIES:\n"; - -DeepHeapProfile::DeepHeapProfile(HeapProfileTable* heap_profile, - const char* prefix) - : pagemap_fd_(-1), - most_recent_pid_(-1), - stats_(), - dump_count_(0), - filename_prefix_(NULL), - profiler_buffer_(NULL), - bucket_id_(0), - heap_profile_(heap_profile) { - deep_bucket_map_ = new(heap_profile_->alloc_(sizeof(DeepBucketMap))) - DeepBucketMap(heap_profile_->alloc_, heap_profile_->dealloc_); - - // Copy filename prefix. - const int prefix_length = strlen(prefix); - filename_prefix_ = - reinterpret_cast<char*>(heap_profile_->alloc_(prefix_length + 1)); - memcpy(filename_prefix_, prefix, prefix_length); - filename_prefix_[prefix_length] = '\0'; - - profiler_buffer_ = - reinterpret_cast<char*>(heap_profile_->alloc_(kProfilerBufferSize)); -} - -DeepHeapProfile::~DeepHeapProfile() { - heap_profile_->dealloc_(profiler_buffer_); - heap_profile_->dealloc_(filename_prefix_); - deep_bucket_map_->~DeepBucketMap(); - heap_profile_->dealloc_(deep_bucket_map_); -} - -int DeepHeapProfile::FillOrderedProfile(char buffer[], int buffer_size) { -#ifndef NDEBUG - int64 starting_cycles = CycleClock::Now(); -#endif - ++dump_count_; - - // Re-open files in /proc/pid/ if the process is newly forked one. - if (most_recent_pid_ != getpid()) { - most_recent_pid_ = getpid(); - pagemap_fd_ = OpenProcPagemap(); - - deep_bucket_map_->Iterate(ClearIsLogged, this); - - // Write maps into a .maps file with using the global buffer. - WriteMapsToFile(filename_prefix_, kProfilerBufferSize, profiler_buffer_); - } - - // Reset committed sizes of buckets. - ResetCommittedSize(heap_profile_->alloc_table_); - ResetCommittedSize(heap_profile_->mmap_table_); - - SnapshotGlobalStatsWithoutMalloc(pagemap_fd_, &stats_); - size_t anonymous_committed = stats_.anonymous.committed_bytes(); - - // Note: Least malloc from here. malloc here may cause a gap in the observed - // size from actual memory allocation. The size of the gap is the size of - // allocated memory at maximum. It doesn't cause violation. - // TODO(dmikurube): Eliminate dynamic memory allocation caused by snprintf. - // glibc's snprintf internally allocates memory by alloca normally, but it - // allocates memory by malloc if large memory is required. - - // Record committed sizes. - SnapshotAllAllocsWithoutMalloc(); - - // Check if committed bytes changed during SnapshotAllAllocsWithoutMalloc. - SnapshotGlobalStatsWithoutMalloc(pagemap_fd_, &stats_); -#ifndef NDEBUG - size_t committed_difference = - stats_.anonymous.committed_bytes() - anonymous_committed; - if (committed_difference != 0) { - RAW_LOG(0, "Difference in committed size: %ld", committed_difference); - } -#endif - - // Start filling buffer with the ordered profile. - int printed = snprintf(buffer, buffer_size, - "%s%s\n", kProfileHeader, kProfileVersion); - if (printed < 0 || printed >= buffer_size) { - return 0; - } - int used_in_buffer = printed; - - // Fill buffer with the global stats. - printed = snprintf(buffer + used_in_buffer, buffer_size - used_in_buffer, - kGlobalStatsHeader); - if (printed < 0 || printed >= buffer_size - used_in_buffer) { - return used_in_buffer; - } - used_in_buffer += printed; - - used_in_buffer = UnparseGlobalStats(used_in_buffer, buffer_size, buffer); - - // Fill buffer with the header for buckets of mmap'ed regions. - printed = snprintf(buffer + used_in_buffer, buffer_size - used_in_buffer, - kMMapStacktraceHeader); - if (printed < 0 || 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, - "%10s %10s\n", "virtual", "committed"); - if (printed < 0 || printed >= buffer_size - used_in_buffer) { - return used_in_buffer; - } - used_in_buffer += printed; - - // Fill buffer with stack trace buckets of mmap'ed regions. - used_in_buffer = SnapshotBucketTableWithoutMalloc(heap_profile_->mmap_table_, - used_in_buffer, - buffer_size, - buffer); - - // Fill buffer with the header for buckets of allocated regions. - printed = snprintf(buffer + used_in_buffer, buffer_size - used_in_buffer, - kAllocStacktraceHeader); - if (printed < 0 || 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, - "%10s %10s\n", "virtual", "committed"); - if (printed < 0 || printed >= buffer_size - used_in_buffer) { - return used_in_buffer; - } - used_in_buffer += printed; - - // Fill buffer with stack trace buckets of allocated regions. - used_in_buffer = SnapshotBucketTableWithoutMalloc(heap_profile_->alloc_table_, - used_in_buffer, - buffer_size, - buffer); - - RAW_DCHECK(used_in_buffer < buffer_size, ""); - - // Note: Least malloc until here. - - // Write the bucket listing into a .bucket file. - WriteBucketsToBucketFile(); - -#ifndef NDEBUG - int64 elapsed_cycles = CycleClock::Now() - starting_cycles; - double elapsed_seconds = elapsed_cycles / CyclesPerSecond(); - RAW_LOG(0, "Time spent on DeepProfiler: %.3f sec\n", elapsed_seconds); -#endif - - return used_in_buffer; -} - -void DeepHeapProfile::RegionStats::Initialize() { - virtual_bytes_ = 0; - committed_bytes_ = 0; -} - -void DeepHeapProfile::RegionStats::Record( - int pagemap_fd, uint64 first_address, uint64 last_address) { - virtual_bytes_ += static_cast<size_t>(last_address - first_address + 1); - committed_bytes_ += GetCommittedSize(pagemap_fd, first_address, last_address); -} - -// TODO(dmikurube): Avoid calling ClearIsLogged to rewrite buckets by add a -// reference to a previous file in a .heap file. -// static -void DeepHeapProfile::ClearIsLogged(const void* pointer, - DeepHeapProfile::DeepBucket* deep_bucket, - DeepHeapProfile* deep_profile) { - deep_bucket->is_logged = false; -} - -// static -int DeepHeapProfile::OpenProcPagemap() { - char filename[100]; - snprintf(filename, sizeof(filename), "/proc/%d/pagemap", getpid()); - int pagemap_fd = open(filename, O_RDONLY); - RAW_DCHECK(pagemap_fd != -1, "Failed to open /proc/self/pagemap"); - return pagemap_fd; -} - -// static -bool DeepHeapProfile::SeekProcPagemap(int pagemap_fd, uint64 address) { - static int page_size = 0; - if (!page_size) page_size = getpagesize(); - int64 index = (address / page_size) * PAGEMAP_BYTES; - int64 offset = lseek64(pagemap_fd, index, SEEK_SET); - RAW_DCHECK(offset == index, ""); - return offset >= 0; -} - -// static -bool DeepHeapProfile::ReadProcPagemap(int pagemap_fd, PageState* state) { - 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(pagemap_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; -} - -// static -size_t DeepHeapProfile::GetCommittedSize( - int pagemap_fd, uint64 first_address, uint64 last_address) { - static int page_size = 0; - if (!page_size) page_size = getpagesize(); - uint64 page_address = (first_address / page_size) * page_size; - size_t committed_size = 0; - - SeekProcPagemap(pagemap_fd, first_address); - - // Check every page on which the allocation resides. - while (page_address <= last_address) { - // Read corresponding physical page. - PageState state; - if (ReadProcPagemap(pagemap_fd, &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 > TOP_ADDRESS - page_size) { - break; - } - page_address += page_size; - } - - return committed_size; -} - -// static -void DeepHeapProfile::WriteMapsToFile(const char* filename_prefix, - int buffer_size, - char buffer[]) { - char filename[100]; - snprintf(filename, sizeof(filename), - "%s.%05d.maps", filename_prefix, getpid()); - - RawFD maps_fd = RawOpenForWriting(filename); - RAW_DCHECK(maps_fd != kIllegalRawFD, ""); - - int map_length; - bool wrote_all; - map_length = tcmalloc::FillProcSelfMaps(buffer, buffer_size, &wrote_all); - RAW_DCHECK(wrote_all, ""); - RAW_DCHECK(map_length <= buffer_size, ""); - RawWrite(maps_fd, buffer, map_length); - RawClose(maps_fd); -} - -// TODO(dmikurube): Eliminate dynamic memory allocation caused by snprintf. -// ProcMapsIterator uses snprintf internally in construction. -// static -void DeepHeapProfile::SnapshotGlobalStatsWithoutMalloc(int pagemap_fd, - GlobalStats* stats) { - ProcMapsIterator::Buffer iterator_buffer; - ProcMapsIterator iterator(0, &iterator_buffer); - uint64 first_address, last_address, offset; - int64 inode; - char* flags; - char* filename; - - stats->total.Initialize(); - stats->file_mapped.Initialize(); - stats->anonymous.Initialize(); - stats->other.Initialize(); - - while (iterator.Next(&first_address, &last_address, - &flags, &offset, &inode, &filename)) { - // 'last_address' should be the last inclusive address of the region. - last_address -= 1; - if (strcmp("[vsyscall]", filename) == 0) { - continue; // Reading pagemap will fail in [vsyscall]. - } - - stats->total.Record(pagemap_fd, first_address, last_address); - - if (filename[0] == '/') { - stats->file_mapped.Record(pagemap_fd, first_address, last_address); - } else if (filename[0] == '\0' || filename[0] == '\n') { - stats->anonymous.Record(pagemap_fd, first_address, last_address); - } else { - stats->other.Record(pagemap_fd, first_address, last_address); - } - } -} - -DeepHeapProfile::DeepBucket* DeepHeapProfile::GetDeepBucket(Bucket* bucket) { - DeepBucket* found = deep_bucket_map_->FindMutable(bucket); - if (found != NULL) - return found; - - DeepBucket created; - created.bucket = bucket; - created.committed_size = 0; - created.id = (bucket_id_++); - created.is_logged = false; - deep_bucket_map_->Insert(bucket, created); - return deep_bucket_map_->FindMutable(bucket); -} - -void DeepHeapProfile::ResetCommittedSize(Bucket** bucket_table) { - for (int i = 0; i < kHashTableSize; i++) { - for (Bucket* bucket = bucket_table[i]; - bucket != NULL; - bucket = bucket->next) { - DeepBucket* deep_bucket = GetDeepBucket(bucket); - deep_bucket->committed_size = 0; - } - } -} - -// TODO(dmikurube): Eliminate dynamic memory allocation caused by snprintf. -int DeepHeapProfile::SnapshotBucketTableWithoutMalloc(Bucket** bucket_table, - int used_in_buffer, - int buffer_size, - char buffer[]) { - for (int i = 0; i < kHashTableSize; i++) { - for (Bucket* bucket = bucket_table[i]; - bucket != NULL; - bucket = bucket->next) { - if (bucket->alloc_size - bucket->free_size == 0) { - continue; // Skip empty buckets. - } - const DeepBucket* deep_bucket = GetDeepBucket(bucket); - used_in_buffer = UnparseBucket( - *deep_bucket, "", used_in_buffer, buffer_size, buffer, NULL); - } - } - return used_in_buffer; -} - -void DeepHeapProfile::RecordAlloc(const void* pointer, - AllocValue* alloc_value, - DeepHeapProfile* deep_profile) { - uint64 address = reinterpret_cast<uintptr_t>(pointer); - size_t committed = GetCommittedSize(deep_profile->pagemap_fd_, - address, address + alloc_value->bytes - 1); - - 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); -} - -void DeepHeapProfile::RecordMMap(const void* pointer, - AllocValue* alloc_value, - DeepHeapProfile* deep_profile) { - uint64 address = reinterpret_cast<uintptr_t>(pointer); - size_t committed = GetCommittedSize(deep_profile->pagemap_fd_, - address, address + alloc_value->bytes - 1); - - 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); -} - -void DeepHeapProfile::SnapshotAllAllocsWithoutMalloc() { - stats_.record_mmap.Initialize(); - stats_.record_malloc.Initialize(); - - // malloc allocations. - heap_profile_->alloc_address_map_->Iterate(RecordAlloc, this); - - // mmap allocations. - heap_profile_->mmap_address_map_->Iterate(RecordMMap, this); -} - -int DeepHeapProfile::FillBucketForBucketFile(const DeepBucket* deep_bucket, - int buffer_size, - char buffer[]) { - const Bucket* bucket = deep_bucket->bucket; - int printed = snprintf(buffer, buffer_size, "%05d", deep_bucket->id); - if (printed < 0 || printed >= buffer_size) { - return 0; - } - int used_in_buffer = printed; - - for (int depth = 0; depth < bucket->depth; depth++) { - printed = snprintf(buffer + used_in_buffer, buffer_size - used_in_buffer, - " 0x%08" PRIxPTR, - reinterpret_cast<uintptr_t>(bucket->stack[depth])); - if (printed < 0 || 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, - "\n"); - if (printed < 0 || printed >= buffer_size - used_in_buffer) { - return used_in_buffer; - } - used_in_buffer += printed; - - return used_in_buffer; -} - -void DeepHeapProfile::WriteBucketsTableToBucketFile(Bucket** bucket_table, - RawFD bucket_fd) { - // We will use the global buffer here. - char* buffer = profiler_buffer_; - int buffer_size = kProfilerBufferSize; - int used_in_buffer = 0; - - for (int i = 0; i < kHashTableSize; i++) { - for (Bucket* bucket = bucket_table[i]; - bucket != NULL; - bucket = bucket->next) { - DeepBucket* deep_bucket = GetDeepBucket(bucket); - if (deep_bucket->is_logged) { - continue; // Skip the bucket if it is already logged. - } - if (bucket->alloc_size - bucket->free_size <= 64) { - continue; // Skip small buckets. - } - - used_in_buffer += FillBucketForBucketFile( - deep_bucket, buffer_size - used_in_buffer, buffer + used_in_buffer); - deep_bucket->is_logged = true; - - // Write to file if buffer 80% full. - if (used_in_buffer > buffer_size * 0.8) { - RawWrite(bucket_fd, buffer, used_in_buffer); - used_in_buffer = 0; - } - } - } - - RawWrite(bucket_fd, buffer, used_in_buffer); -} - -void DeepHeapProfile::WriteBucketsToBucketFile() { - char filename[100]; - snprintf(filename, sizeof(filename), - "%s.%05d.%04d.buckets", filename_prefix_, getpid(), dump_count_); - RawFD bucket_fd = RawOpenForWriting(filename); - RAW_DCHECK(bucket_fd != kIllegalRawFD, ""); - - WriteBucketsTableToBucketFile(heap_profile_->alloc_table_, bucket_fd); - WriteBucketsTableToBucketFile(heap_profile_->mmap_table_, bucket_fd); - - RawClose(bucket_fd); -} - -int DeepHeapProfile::UnparseBucket(const DeepBucket& deep_bucket, - const char* extra, - int used_in_buffer, - int buffer_size, - char* buffer, - Stats* profile_stats) { - const Bucket& bucket = *deep_bucket.bucket; - if (profile_stats != NULL) { - profile_stats->allocs += bucket.allocs; - profile_stats->alloc_size += bucket.alloc_size; - profile_stats->frees += bucket.frees; - profile_stats->free_size += bucket.free_size; - } - - int printed = snprintf(buffer + used_in_buffer, buffer_size - used_in_buffer, - "%10"PRId64" %10"PRId64" %6d %6d @%s %d\n", - bucket.alloc_size - bucket.free_size, - deep_bucket.committed_size, - bucket.allocs, bucket.frees, extra, deep_bucket.id); - // If it looks like the snprintf failed, ignore the fact we printed anything. - if (printed < 0 || printed >= buffer_size - used_in_buffer) { - return used_in_buffer; - } - used_in_buffer += printed; - - return used_in_buffer; -} - -int DeepHeapProfile::UnparseRegionStats(const RegionStats* stats, - const char* name, - int used_in_buffer, - int buffer_size, - char* buffer) { - int printed = snprintf(buffer + used_in_buffer, buffer_size - used_in_buffer, - "%15s %10ld %10ld\n", - name, stats->virtual_bytes(), - stats->committed_bytes()); - if (printed < 0 || printed >= buffer_size - used_in_buffer) { - return used_in_buffer; - } - used_in_buffer += printed; - - return used_in_buffer; -} - -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", "", "virtual", "committed"); - if (printed < 0 || 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); - return used_in_buffer; -} -#else // DEEP_HEAP_PROFILE - -DeepHeapProfile::DeepHeapProfile(HeapProfileTable* heap_profile, - const char* prefix) - : heap_profile_(heap_profile) { -} - -DeepHeapProfile::~DeepHeapProfile() { -} - -int DeepHeapProfile::FillOrderedProfile(char buffer[], int buffer_size) { - return heap_profile_->FillOrderedProfile(buffer, buffer_size); -} - -#endif // 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 deleted file mode 100644 index c3249f3..0000000 --- a/third_party/tcmalloc/chromium/src/deep-heap-profile.h +++ /dev/null @@ -1,249 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// --- -// Author: Sainbayar Sukhbaatar -// Dai Mikurube -// -// This file contains a class DeepHeapProfile and its public function -// DeepHeapProfile::FillOrderedProfile() which works as an alternative of -// HeapProfileTable::FillOrderedProfile(). -// -// DeepHeapProfile::FillOrderedProfile() dumps more detailed information about -// heap usage, which includes OS-level information such as whether the memory -// block is actually in memory, or not. DeepHeapProfile::FillOrderedProfile() -// uses logged data in HeapProfileTable as one of its data sources. -// DeepHeapProfile works only when its FillOrderedProfile() is called. It has -// overhead when dumping, but no overhead when logging. -// -// It currently works only on Linux. It just delegates to HeapProfileTable in -// non-Linux environments. - - -#ifndef BASE_DEEP_HEAP_PROFILE_H_ -#define BASE_DEEP_HEAP_PROFILE_H_ - -#include "config.h" - -#if defined(__linux__) -#define DEEP_HEAP_PROFILE 1 -#endif - -#include "addressmap-inl.h" -#include "heap-profile-table.h" - -class DeepHeapProfile { - public: - typedef HeapProfileTable::Bucket Bucket; - typedef HeapProfileTable::AllocationMap AllocationMap; - typedef HeapProfileTable::AllocValue AllocValue; - typedef HeapProfileTable::Stats Stats; - - // Construct a DeepHeapProfile instance. It works as a wrapper of - // HeapProfileTable. - // - // |heap_profile| is a pointer to HeapProfileTable. DeepHeapProfile reads - // data in |heap_profile| and forwards operations to |heap_profile| if - // DeepHeapProfile is not available (non-Linux). - // |prefix| is a prefix of dumped file names. - DeepHeapProfile(HeapProfileTable* heap_profile, const char* prefix); - ~DeepHeapProfile(); - - // Fill deep profile data into |buffer| of |size|, and return the actual - // size occupied by the dump in |buffer|. It works as an alternative - // of HeapProfileTable::FillOrderedProfile. - // - // The profile buckets are dumped in the decreasing order of currently - // allocated bytes. We do not provision for 0-terminating |buffer|. - int FillOrderedProfile(char buffer[], int buffer_size); - - private: -#ifdef DEEP_HEAP_PROFILE - struct DeepBucket { - Bucket* bucket; - size_t committed_size; - int id; // Unique ID of the bucket. - bool is_logged; // True if the stracktrace is logged to a file. - }; - - typedef AddressMap<DeepBucket> DeepBucketMap; - - struct PageState { - bool is_committed; // Currently, we use only this - bool is_present; - bool is_swapped; - bool is_shared; - bool is_mmap; - }; - - class RegionStats { - public: - // Initialize virtual_bytes and committed_bytes. - void Initialize(); - - // Update the RegionStats to include the tallies of virtual_bytes and - // committed_bytes in the region from |first_adress| to |last_address| - // inclusive. - void Record(int pagemap_fd, uint64 first_address, uint64 last_address); - - size_t virtual_bytes() const { return virtual_bytes_; } - size_t committed_bytes() const { return committed_bytes_; } - void set_virtual_bytes(size_t virtual_bytes) { - virtual_bytes_ = virtual_bytes; - } - void set_committed_bytes(size_t committed_bytes) { - committed_bytes_ = committed_bytes; - } - void AddToVirtualBytes(size_t additional_virtual_bytes) { - virtual_bytes_ += additional_virtual_bytes; - } - void AddToCommittedBytes(size_t additional_committed_bytes) { - committed_bytes_ += additional_committed_bytes; - } - - private: - size_t virtual_bytes_; - size_t committed_bytes_; - }; - - struct GlobalStats { - // All RegionStats members in this class contain the bytes of virtual - // 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; - - // Total bytes of mmap'ed regions. - RegionStats record_mmap; - - // Total bytes of malloc'ed regions. - RegionStats record_malloc; - }; - - // Clear the is_logged flag in a DeepBucket object as a callback function - // for DeepBucketMap::Iterate(). - static void ClearIsLogged(const void* pointer, - DeepBucket* db, - DeepHeapProfile* deep_profile); - - // Open /proc/pid/pagemap and return its file descriptor. - // File descriptors need to be refreshed after each fork. - static int OpenProcPagemap(); - - // Seek to the offset of the open pagemap file pagemap_fd. - // It returns true if succeeded. Otherwise, it returns false. - static bool SeekProcPagemap(int pagemap_fd, uint64 address); - - // Read a pagemap state from the current pagemap_fd offset. - // It returns true if succeeded. Otherwise, it returns false. - static bool ReadProcPagemap(int pagemap_fd, PageState* state); - - // Returns the number of resident (including swapped) bytes of the memory - // region starting at |first_address| and ending at |last_address| inclusive. - static size_t GetCommittedSize(int pagemap_fd, - uint64 first_address, - uint64 last_address); - - // Write re-formatted /proc/self/maps into a file which has |filename_prefix| - // with using |buffer| of size |buffer_size|. - static void WriteMapsToFile(const char* filename_prefix, - int buffer_size, - char buffer[]); - - // 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); - - // Get the DeepBucket object corresponding to the given |bucket|. - // DeepBucket is an extension to Bucket which is declared above. - DeepBucket* GetDeepBucket(Bucket* bucket); - - // Reset committed_size member variables in DeepBucket objects to 0. - void ResetCommittedSize(Bucket** bucket_table); - - // Fill bucket data in |bucket_table| into buffer |buffer| of size - // |buffer_size|, and return the size occupied by the bucket data in - // |buffer|. |bucket_length| is the offset for |buffer| to start filling. - int SnapshotBucketTableWithoutMalloc(Bucket** bucket_table, - int used_in_buffer, - int buffer_size, - char buffer[]); - - // Record both virtual and committed byte counts of malloc and mmap regions - // as callback functions for AllocationMap::Iterate(). - static void RecordAlloc(const void* pointer, - AllocValue* alloc_value, - DeepHeapProfile* deep_profile); - static void RecordMMap(const void* pointer, - AllocValue* alloc_value, - DeepHeapProfile* deep_profile); - void SnapshotAllAllocsWithoutMalloc(); - - // Fill a bucket (a bucket id and its corresponding calling stack) into - // |buffer| of size |buffer_size|. - int FillBucketForBucketFile(const DeepBucket* deep_bucket, - int buffer_size, - char buffer[]); - - // Write a |bucket_table| into a file of |bucket_fd|. - void WriteBucketsTableToBucketFile(Bucket** bucket_table, RawFD bucket_fd); - - // Write both malloc and mmap bucket tables into a "bucket file". - void WriteBucketsToBucketFile(); - - // Fill a |deep_bucket| and its corresponding bucket into |buffer| from the - // offset |used_in_buffer|. Add the sizes to |profile_stats| if it's not - // NULL. - static int UnparseBucket(const DeepBucket& deep_bucket, - const char* extra, - int used_in_buffer, - int buffer_size, - char* buffer, - Stats* profile_stats); - - // Fill statistics of a region into |buffer|. - static int UnparseRegionStats(const RegionStats* stats, - const char* name, - int used_in_buffer, - int buffer_size, - char* buffer); - - // Fill global statistics into |buffer|. - int UnparseGlobalStats(int used_in_buffer, int buffer_size, char* buffer); - - int pagemap_fd_; // File descriptor of /proc/self/pagemap. - - // Process ID of the last dump. This could change by fork. - pid_t most_recent_pid_; - GlobalStats stats_; // Stats about total memory. - int dump_count_; // The number of dumps. - char* filename_prefix_; // Output file prefix. - char* profiler_buffer_; // Buffer we use many times. - - int bucket_id_; - DeepBucketMap* deep_bucket_map_; -#endif // DEEP_HEAP_PROFILE - - HeapProfileTable* heap_profile_; - - DISALLOW_COPY_AND_ASSIGN(DeepHeapProfile); -}; - -#endif // BASE_DEEP_HEAP_PROFILE_H_ diff --git a/third_party/tcmalloc/chromium/src/heap-profile-table.h b/third_party/tcmalloc/chromium/src/heap-profile-table.h index 447943d..abd3184 100644 --- a/third_party/tcmalloc/chromium/src/heap-profile-table.h +++ b/third_party/tcmalloc/chromium/src/heap-profile-table.h @@ -198,7 +198,6 @@ class HeapProfileTable { void ClearMMapData(); private: - friend class DeepHeapProfile; // data types ---------------------------- diff --git a/third_party/tcmalloc/chromium/src/heap-profiler.cc b/third_party/tcmalloc/chromium/src/heap-profiler.cc index 85d1aad..166afde 100644 --- a/third_party/tcmalloc/chromium/src/heap-profiler.cc +++ b/third_party/tcmalloc/chromium/src/heap-profiler.cc @@ -68,7 +68,6 @@ #include "base/spinlock.h" #include "base/low_level_alloc.h" #include "base/sysinfo.h" // for GetUniquePathFromEnv() -#include "deep-heap-profile.h" #include "heap-profile-table.h" #include "memory_region_map.h" @@ -122,9 +121,6 @@ DEFINE_bool(only_mmap_profile, EnvToBool("HEAP_PROFILE_ONLY_MMAP", false), "If heap-profiling is on, only profile mmap, mremap, and sbrk; " "do not profile malloc/new/etc"); -DEFINE_bool(deep_heap_profile, - EnvToBool("DEEP_HEAP_PROFILE", false), - "If heap-profiling is on, profile deeper (only on Linux)"); //---------------------------------------------------------------------- @@ -183,7 +179,6 @@ static int64 high_water_mark = 0; // In-use-bytes at last high-water dump static int64 last_dump_time = 0; // The time of the last dump static HeapProfileTable* heap_profile = NULL; // the heap profile table -static DeepHeapProfile* deep_profile = NULL; // deep memory profiler //---------------------------------------------------------------------- // Profile generation @@ -202,11 +197,7 @@ static char* DoGetHeapProfileLocked(char* buf, int buflen) { if (FLAGS_mmap_profile) { heap_profile->RefreshMMapData(); } - if (deep_profile) { - bytes_written = deep_profile->FillOrderedProfile(buf, buflen - 1); - } else { - bytes_written = heap_profile->FillOrderedProfile(buf, buflen - 1); - } + bytes_written = heap_profile->FillOrderedProfile(buf, buflen - 1); if (FLAGS_mmap_profile) { heap_profile->ClearMMapData(); } @@ -475,13 +466,6 @@ extern "C" void HeapProfilerStart(const char* prefix) { high_water_mark = 0; last_dump_time = 0; - if (FLAGS_deep_heap_profile) { - // Initialize deep memory profiler - RAW_VLOG(0, "[%d] Starting a deep memory profiler", getpid()); - deep_profile = new(ProfilerMalloc(sizeof(DeepHeapProfile))) - DeepHeapProfile(heap_profile, prefix); - } - // We do not reset dump_count so if the user does a sequence of // HeapProfilerStart/HeapProfileStop, we will get a continuous // sequence of profiles. @@ -523,13 +507,6 @@ extern "C" void HeapProfilerStop() { RAW_CHECK(MallocHook::RemoveMunmapHook(&MunmapHook), ""); } - if (deep_profile) { - // free deep memory profiler - deep_profile->~DeepHeapProfile(); - ProfilerFree(deep_profile); - deep_profile = NULL; - } - // free profile heap_profile->~HeapProfileTable(); ProfilerFree(heap_profile); |