summaryrefslogtreecommitdiffstats
path: root/third_party/tcmalloc
diff options
context:
space:
mode:
authordmikurube@chromium.org <dmikurube@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-06-11 13:53:44 +0000
committerdmikurube@chromium.org <dmikurube@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-06-11 13:53:44 +0000
commit10dd3cf13d640453fd390b399d5ff1cf9ccd39db (patch)
treee317daae586c29f8cfab3cf0658a9569d8f0bde3 /third_party/tcmalloc
parent38bcf772a1be84732758ed32768079f544a6a155 (diff)
downloadchromium_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.cc55
-rw-r--r--third_party/tcmalloc/chromium/src/deep-heap-profile.h47
-rw-r--r--third_party/tcmalloc/chromium/src/heap-profiler.cc29
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)