diff options
author | dmikurube@chromium.org <dmikurube@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-06-11 13:53:44 +0000 |
---|---|---|
committer | dmikurube@chromium.org <dmikurube@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-06-11 13:53:44 +0000 |
commit | 10dd3cf13d640453fd390b399d5ff1cf9ccd39db (patch) | |
tree | e317daae586c29f8cfab3cf0658a9569d8f0bde3 /third_party/tcmalloc | |
parent | 38bcf772a1be84732758ed32768079f544a6a155 (diff) | |
download | chromium_src-10dd3cf13d640453fd390b399d5ff1cf9ccd39db.zip chromium_src-10dd3cf13d640453fd390b399d5ff1cf9ccd39db.tar.gz chromium_src-10dd3cf13d640453fd390b399d5ff1cf9ccd39db.tar.bz2 |
Dump heap profiles directly into files from deep-heap-profile.
It enables lower memory usage for the profiler itself and larger files dumped.
BUG=244169
Review URL: https://chromiumcodereview.appspot.com/16105007
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@205534 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'third_party/tcmalloc')
-rw-r--r-- | third_party/tcmalloc/chromium/src/deep-heap-profile.cc | 55 | ||||
-rw-r--r-- | third_party/tcmalloc/chromium/src/deep-heap-profile.h | 47 | ||||
-rw-r--r-- | third_party/tcmalloc/chromium/src/heap-profiler.cc | 29 |
3 files changed, 61 insertions, 70 deletions
diff --git a/third_party/tcmalloc/chromium/src/deep-heap-profile.cc b/third_party/tcmalloc/chromium/src/deep-heap-profile.cc index 8c0128a..06cdda7 100644 --- a/third_party/tcmalloc/chromium/src/deep-heap-profile.cc +++ b/third_party/tcmalloc/chromium/src/deep-heap-profile.cc @@ -198,7 +198,6 @@ DeepHeapProfile::DeepHeapProfile(HeapProfileTable* heap_profile, stats_(), dump_count_(0), filename_prefix_(NULL), - profiler_buffer_(NULL), deep_table_(kHashTableSize, heap_profile->alloc_, heap_profile->dealloc_), heap_profile_(heap_profile) { // Copy filename prefix. @@ -207,24 +206,20 @@ DeepHeapProfile::DeepHeapProfile(HeapProfileTable* heap_profile, 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_); delete memory_residence_info_getter_; } // Global malloc() should not be used in this function. // Use LowLevelAlloc if required. -int DeepHeapProfile::FillOrderedProfile(const char* reason, - char raw_buffer[], - int buffer_size) { - TextBuffer buffer(raw_buffer, buffer_size); - TextBuffer global_buffer(profiler_buffer_, kProfilerBufferSize); +void DeepHeapProfile::DumpOrderedProfile(const char* reason, + char raw_buffer[], + int buffer_size, + RawFD fd) { + TextBuffer buffer(raw_buffer, buffer_size, fd); #ifndef NDEBUG int64 starting_cycles = CycleClock::Now(); @@ -244,7 +239,7 @@ int DeepHeapProfile::FillOrderedProfile(const char* reason, deep_table_.ResetIsLogged(); // Write maps into "|filename_prefix_|.<pid>.maps". - WriteProcMaps(filename_prefix_, kProfilerBufferSize, profiler_buffer_); + WriteProcMaps(filename_prefix_, raw_buffer, buffer_size); } // Reset committed sizes of buckets. @@ -293,18 +288,17 @@ int DeepHeapProfile::FillOrderedProfile(const char* reason, // Fill buffer. deep_table_.UnparseForStats(&buffer); - RAW_DCHECK(buffer.FilledBytes() < buffer_size, ""); + buffer.Flush(); // Write the bucket listing into a .bucket file. - deep_table_.WriteForBucketFile(filename_prefix_, dump_count_, &global_buffer); + deep_table_.WriteForBucketFile( + filename_prefix_, dump_count_, raw_buffer, buffer_size); #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 buffer.FilledBytes(); } int DeepHeapProfile::TextBuffer::Size() { @@ -319,8 +313,9 @@ void DeepHeapProfile::TextBuffer::Clear() { cursor_ = 0; } -void DeepHeapProfile::TextBuffer::Write(RawFD fd) { - RawWrite(fd, buffer_, cursor_); +void DeepHeapProfile::TextBuffer::Flush() { + RawWrite(fd_, buffer_, cursor_); + cursor_ = 0; } // TODO(dmikurube): These Append* functions should not use snprintf. @@ -404,6 +399,8 @@ bool DeepHeapProfile::TextBuffer::ForwardCursor(int appended) { if (appended < 0 || appended >= size_ - cursor_) return false; cursor_ += appended; + if (cursor_ > size_ * 4 / 5) + Flush(); return true; } @@ -535,13 +532,15 @@ void DeepHeapProfile::DeepBucketTable::UnparseForStats(TextBuffer* buffer) { } void DeepHeapProfile::DeepBucketTable::WriteForBucketFile( - const char* prefix, int dump_count, TextBuffer* buffer) { + const char* prefix, int dump_count, char raw_buffer[], int buffer_size) { char filename[100]; snprintf(filename, sizeof(filename), "%s.%05d.%04d.buckets", prefix, getpid(), dump_count); RawFD fd = RawOpenForWriting(filename); RAW_DCHECK(fd != kIllegalRawFD, ""); + TextBuffer buffer(raw_buffer, buffer_size, fd); + for (int i = 0; i < table_size_; i++) { for (DeepBucket* deep_bucket = table_[i]; deep_bucket != NULL; @@ -554,18 +553,12 @@ void DeepHeapProfile::DeepBucketTable::WriteForBucketFile( continue; // Skip small buckets. } - deep_bucket->UnparseForBucketFile(buffer); + deep_bucket->UnparseForBucketFile(&buffer); deep_bucket->is_logged = true; - - // Write to file if buffer 80% full. - if (buffer->FilledBytes() > buffer->Size() * 0.8) { - buffer->Write(fd); - buffer->Clear(); - } } } - buffer->Write(fd); + buffer.Flush(); RawClose(fd); } @@ -964,8 +957,8 @@ DeepHeapProfile::DeepBucket* // static void DeepHeapProfile::WriteProcMaps(const char* prefix, - int buffer_size, - char raw_buffer[]) { + char raw_buffer[], + int buffer_size) { char filename[100]; snprintf(filename, sizeof(filename), "%s.%05d.maps", prefix, static_cast<int>(getpid())); @@ -991,8 +984,10 @@ DeepHeapProfile::DeepHeapProfile(HeapProfileTable* heap_profile, DeepHeapProfile::~DeepHeapProfile() { } -int DeepHeapProfile::FillOrderedProfile(char raw_buffer[], int buffer_size) { - return heap_profile_->FillOrderedProfile(raw_buffer, buffer_size); +int DeepHeapProfile::DumpOrderedProfile(const char* reason, + char raw_buffer[], + int buffer_size, + RawFD fd) { } #endif // USE_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 4a943a1..fcfae61 100644 --- a/third_party/tcmalloc/chromium/src/deep-heap-profile.h +++ b/third_party/tcmalloc/chromium/src/deep-heap-profile.h @@ -7,24 +7,24 @@ // Dai Mikurube // // This file contains a class DeepHeapProfile and its public function -// DeepHeapProfile::FillOrderedProfile() which works as an alternative of -// HeapProfileTable::FillOrderedProfile(). +// DeepHeapProfile::DumpOrderedProfile(). The function works like +// HeapProfileTable::FillOrderedProfile(), but dumps directory to files. // -// DeepHeapProfile::FillOrderedProfile() dumps more detailed information about +// DeepHeapProfile::DumpOrderedProfile() dumps more detailed information about // heap usage, which includes OS-level information such as memory residency and // type information if the type profiler is available. // -// DeepHeapProfile::FillOrderedProfile() uses data stored in HeapProfileTable. -// Any code in DeepHeapProfile runs only when FillOrderedProfile() is called. +// DeepHeapProfile::DumpOrderedProfile() uses data stored in HeapProfileTable. +// Any code in DeepHeapProfile runs only when DumpOrderedProfile() is called. // It has overhead in dumping, but no overhead in logging. // -// It currently works only on Linux. It just delegates to HeapProfileTable in +// It currently works only on Linux including Android. It does nothing in // non-Linux environments. // Note that uint64 is used to represent addresses instead of uintptr_t, and // int is used to represent buffer sizes instead of size_t. // It's for consistency with other TCMalloc functions. ProcMapsIterator uses -// uint64 for addresses, and HeapProfileTable::FillOrderedProfile uses int +// uint64 for addresses, and HeapProfileTable::DumpOrderedProfile uses int // for buffer sizes. #ifndef BASE_DEEP_HEAP_PROFILE_H_ @@ -76,16 +76,14 @@ class DeepHeapProfile { DeepHeapProfile(HeapProfileTable* heap_profile, const char* prefix); ~DeepHeapProfile(); - // Fills deep profile dump into |raw_buffer| of |buffer_size|, and return the - // actual size occupied by the dump in |raw_buffer|. It works as an - // alternative of HeapProfileTable::FillOrderedProfile. |raw_buffer| is not - // terminated by zero. + // Dumps a deep profile into |fd| with using |raw_buffer| of |buffer_size|. // // In addition, a list of buckets is dumped into a ".buckets" file in // descending order of allocated bytes. - int FillOrderedProfile(const char* reason, - char raw_buffer[], - int buffer_size); + void DumpOrderedProfile(const char* reason, + char raw_buffer[], + int buffer_size, + RawFD fd); private: #ifdef USE_DEEP_HEAP_PROFILE @@ -121,20 +119,20 @@ class DeepHeapProfile { static const char* kMapsRegionTypeDict[NUMBER_OF_MAPS_REGION_TYPES]; - // Manages a buffer to keep a dumped text for FillOrderedProfile and other - // functions. + // Manages a buffer to keep a text to be dumped to a file. class TextBuffer { public: - TextBuffer(char *raw_buffer, int size) + TextBuffer(char *raw_buffer, int size, RawFD fd) : buffer_(raw_buffer), size_(size), - cursor_(0) { + cursor_(0), + fd_(fd) { } int Size(); int FilledBytes(); void Clear(); - void Write(RawFD fd); + void Flush(); bool AppendChar(char value); bool AppendString(const char* value, int width); @@ -150,6 +148,7 @@ class DeepHeapProfile { char *buffer_; int size_; int cursor_; + RawFD fd_; DISALLOW_COPY_AND_ASSIGN(TextBuffer); }; @@ -188,13 +187,14 @@ class DeepHeapProfile { #endif bool is_mmap); - // Writes stats of the hash table to |buffer| for FillOrderedProfile. + // Writes stats of the hash table to |buffer| for DumpOrderedProfile. void UnparseForStats(TextBuffer* buffer); // Writes all buckets for a bucket file with using |buffer|. void WriteForBucketFile(const char* prefix, int dump_count, - TextBuffer* buffer); + char raw_buffer[], + int buffer_size); // Resets 'committed_size' members in DeepBucket objects. void ResetCommittedSize(); @@ -296,8 +296,8 @@ class DeepHeapProfile { // Writes reformatted /proc/<pid>/maps into a file "|prefix|.<pid>.maps" // with using |raw_buffer| of |buffer_size|. static void WriteProcMaps(const char* prefix, - int buffer_size, - char raw_buffer[]); + char raw_buffer[], + int buffer_size); MemoryResidenceInfoGetterInterface* memory_residence_info_getter_; @@ -307,7 +307,6 @@ class DeepHeapProfile { 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. DeepBucketTable deep_table_; #endif // USE_DEEP_HEAP_PROFILE diff --git a/third_party/tcmalloc/chromium/src/heap-profiler.cc b/third_party/tcmalloc/chromium/src/heap-profiler.cc index e08b0fc..47130e8b 100644 --- a/third_party/tcmalloc/chromium/src/heap-profiler.cc +++ b/third_party/tcmalloc/chromium/src/heap-profiler.cc @@ -178,7 +178,7 @@ static SpinLock heap_lock(SpinLock::LINKER_INITIALIZED); // Simple allocator for heap profiler's internal memory //---------------------------------------------------------------------- -static LowLevelAlloc::Arena* heap_profiler_memory; +static LowLevelAlloc::Arena *heap_profiler_memory; static void* ProfilerMalloc(size_t bytes) { return LowLevelAlloc::AllocWithArena(bytes, heap_profiler_memory); @@ -188,11 +188,7 @@ static void ProfilerFree(void* p) { } // We use buffers of this size in DoGetHeapProfile. -// The size is 1 << 20 in the original google-perftools. Changed it to -// 5 << 20 since a larger buffer is requried for deeper profiling in Chromium. -// The buffer is allocated only when the environment variable HEAPPROFILE is -// specified to dump heap information. -static const int kProfileBufferSize = 5 << 20; +static const int kProfileBufferSize = 1 << 20; // This is a last-ditch buffer we use in DumpProfileLocked in case we // can't allocate more memory from ProfilerMalloc. We expect this @@ -225,7 +221,7 @@ static DeepHeapProfile* deep_profile = NULL; // deep memory profiler //---------------------------------------------------------------------- // Input must be a buffer of size at least 1MB. -static char* DoGetHeapProfileLocked(const char* reason, char* buf, int buflen) { +static char* DoGetHeapProfileLocked(char* buf, int buflen) { // We used to be smarter about estimating the required memory and // then capping it to 1MB and generating the profile into that. if (buf == NULL || buflen < 1) @@ -236,11 +232,7 @@ static char* DoGetHeapProfileLocked(const char* reason, char* buf, int buflen) { if (is_on) { HeapProfileTable::Stats const stats = heap_profile->total(); (void)stats; // avoid an unused-variable warning in non-debug mode. - if (deep_profile) { - bytes_written = deep_profile->FillOrderedProfile(reason, buf, buflen - 1); - } else { - bytes_written = heap_profile->FillOrderedProfile(buf, buflen - 1); - } + bytes_written = heap_profile->FillOrderedProfile(buf, buflen - 1); // FillOrderedProfile should not reduce the set of active mmap-ed regions, // hence MemoryRegionMap will let us remove everything we've added above: RAW_DCHECK(stats.Equivalent(heap_profile->total()), ""); @@ -257,7 +249,7 @@ extern "C" char* GetHeapProfile() { // Use normal malloc: we return the profile to the user to free it: char* buffer = reinterpret_cast<char*>(malloc(kProfileBufferSize)); SpinLockHolder l(&heap_lock); - return DoGetHeapProfileLocked(/* reason */ NULL, buffer, kProfileBufferSize); + return DoGetHeapProfileLocked(buffer, kProfileBufferSize); } // defined below @@ -298,9 +290,14 @@ static void DumpProfileLocked(const char* reason) { reinterpret_cast<char*>(ProfilerMalloc(kProfileBufferSize)); } - char* profile = DoGetHeapProfileLocked(reason, global_profiler_buffer, - kProfileBufferSize); - RawWrite(fd, profile, strlen(profile)); + if (deep_profile) { + deep_profile->DumpOrderedProfile(reason, global_profiler_buffer, + kProfileBufferSize, fd); + } else { + char* profile = DoGetHeapProfileLocked(global_profiler_buffer, + kProfileBufferSize); + RawWrite(fd, profile, strlen(profile)); + } RawClose(fd); #if defined(TYPE_PROFILING) |