summaryrefslogtreecommitdiff
path: root/src/tcmalloc.cc
diff options
context:
space:
mode:
authorcsilvers <csilvers@6b5cf1ce-ec42-a296-1ba9-69fdba395a50>2011-10-18 20:57:45 +0000
committercsilvers <csilvers@6b5cf1ce-ec42-a296-1ba9-69fdba395a50>2011-10-18 20:57:45 +0000
commita6076edd177d59e67207753b799ce047a3663cb0 (patch)
tree5b3bce7c1fbc9277d82d62379000acbf32374a73 /src/tcmalloc.cc
parentc2eedce2a718913ed6264ac8e96571c233761e3b (diff)
downloadgperftools-a6076edd177d59e67207753b799ce047a3663cb0.tar.gz
* Get the deallocation stack trace outside the lock (sean)
* Make PageHeap dynamically allocated for leak checks (maxim) * BUGFIX: Fix probing of nm -f behavior in pprof (dpeng) * PORTING: Add "support" for MIPS cycletimer * BUGFIX: Fix a race with the CentralFreeList lock (sanjay) * Allow us to compile on OS X 10.6 and run on 10.5 (raltherr) * Support /pprof/censusprofile url arguments (rajatjain) * Die in configure when g++ is't installed (csilvers) * Change IgnoreObject to return its argument (nlewycky) * Update malloc-hook files to support more CPUs * Move stack trace collecting out of the mutex (taylorc) * BUGFIX: write our own strstr to avoid libc problems (csilvers) * use simple callgrind compression facility in pprof * print an error message when we can't run pprof to symbolize (csilvers) git-svn-id: http://gperftools.googlecode.com/svn/trunk@120 6b5cf1ce-ec42-a296-1ba9-69fdba395a50
Diffstat (limited to 'src/tcmalloc.cc')
-rw-r--r--src/tcmalloc.cc122
1 files changed, 89 insertions, 33 deletions
diff --git a/src/tcmalloc.cc b/src/tcmalloc.cc
index 263db81..8700a6f 100644
--- a/src/tcmalloc.cc
+++ b/src/tcmalloc.cc
@@ -162,6 +162,10 @@ using STL_NAMESPACE::vector;
#endif
using tcmalloc::AlignmentForSize;
+using tcmalloc::kLog;
+using tcmalloc::kCrash;
+using tcmalloc::kCrashWithStats;
+using tcmalloc::Log;
using tcmalloc::PageHeap;
using tcmalloc::PageHeapAllocator;
using tcmalloc::SizeMap;
@@ -279,16 +283,18 @@ static int tc_new_mode = 0; // See tc_set_new_mode().
// required) kind of exception handling for these routines.
namespace {
void InvalidFree(void* ptr) {
- CRASH("Attempt to free invalid pointer: %p\n", ptr);
+ Log(kCrash, __FILE__, __LINE__, "Attempt to free invalid pointer", ptr);
}
size_t InvalidGetSizeForRealloc(void* old_ptr) {
- CRASH("Attempt to realloc invalid pointer: %p\n", old_ptr);
+ Log(kCrash, __FILE__, __LINE__,
+ "Attempt to realloc invalid pointer", old_ptr);
return 0;
}
size_t InvalidGetAllocatedSize(void* ptr) {
- CRASH("Attempt to get the size of an invalid pointer: %p\n", ptr);
+ Log(kCrash, __FILE__, __LINE__,
+ "Attempt to get the size of an invalid pointer", ptr);
return 0;
}
} // unnamed namespace
@@ -303,7 +309,9 @@ struct TCMallocStats {
};
// Get stats into "r". Also get per-size-class counts if class_count != NULL
-static void ExtractStats(TCMallocStats* r, uint64_t* class_count) {
+static void ExtractStats(TCMallocStats* r, uint64_t* class_count,
+ PageHeap::SmallSpanStats* small_spans,
+ PageHeap::LargeSpanStats* large_spans) {
r->central_bytes = 0;
r->transfer_bytes = 0;
for (int cl = 0; cl < kNumClasses; ++cl) {
@@ -324,14 +332,30 @@ static void ExtractStats(TCMallocStats* r, uint64_t* class_count) {
ThreadCache::GetThreadStats(&r->thread_bytes, class_count);
r->metadata_bytes = tcmalloc::metadata_system_bytes();
r->pageheap = Static::pageheap()->stats();
+ if (small_spans != NULL) {
+ Static::pageheap()->GetSmallSpanStats(small_spans);
+ }
+ if (large_spans != NULL) {
+ Static::pageheap()->GetLargeSpanStats(large_spans);
+ }
}
}
+static double PagesToMiB(uint64_t pages) {
+ return (pages << kPageShift) / 1048576.0;
+}
+
// WRITE stats to "out"
static void DumpStats(TCMalloc_Printer* out, int level) {
TCMallocStats stats;
uint64_t class_count[kNumClasses];
- ExtractStats(&stats, (level >= 2 ? class_count : NULL));
+ PageHeap::SmallSpanStats small;
+ PageHeap::LargeSpanStats large;
+ if (level >= 2) {
+ ExtractStats(&stats, class_count, &small, &large);
+ } else {
+ ExtractStats(&stats, NULL, NULL, NULL);
+ }
static const double MiB = 1048576.0;
@@ -404,8 +428,48 @@ static void DumpStats(TCMalloc_Printer* out, int level) {
}
}
- SpinLockHolder h(Static::pageheap_lock());
- Static::pageheap()->Dump(out);
+ // append page heap info
+ int nonempty_sizes = 0;
+ for (int s = 0; s < kMaxPages; s++) {
+ if (small.normal_length[s] + small.returned_length[s] > 0) {
+ nonempty_sizes++;
+ }
+ }
+ out->printf("------------------------------------------------\n");
+ out->printf("PageHeap: %d sizes; %6.1f MiB free; %6.1f MiB unmapped\n",
+ nonempty_sizes, stats.pageheap.free_bytes / MiB,
+ stats.pageheap.unmapped_bytes / MiB);
+ out->printf("------------------------------------------------\n");
+ uint64_t total_normal = 0;
+ uint64_t total_returned = 0;
+ for (int s = 0; s < kMaxPages; s++) {
+ const int n_length = small.normal_length[s];
+ const int r_length = small.returned_length[s];
+ if (n_length + r_length > 0) {
+ uint64_t n_pages = s * n_length;
+ uint64_t r_pages = s * r_length;
+ total_normal += n_pages;
+ total_returned += r_pages;
+ out->printf("%6u pages * %6u spans ~ %6.1f MiB; %6.1f MiB cum"
+ "; unmapped: %6.1f MiB; %6.1f MiB cum\n",
+ s,
+ (n_length + r_length),
+ PagesToMiB(n_pages + r_pages),
+ PagesToMiB(total_normal + total_returned),
+ PagesToMiB(r_pages),
+ PagesToMiB(total_returned));
+ }
+ }
+
+ total_normal += large.normal_pages;
+ total_returned += large.returned_pages;
+ out->printf(">255 large * %6u spans ~ %6.1f MiB; %6.1f MiB cum"
+ "; unmapped: %6.1f MiB; %6.1f MiB cum\n",
+ static_cast<unsigned int>(large.spans),
+ PagesToMiB(large.normal_pages + large.returned_pages),
+ PagesToMiB(total_normal + total_returned),
+ PagesToMiB(large.returned_pages),
+ PagesToMiB(total_returned));
}
}
@@ -435,8 +499,9 @@ static void** DumpHeapGrowthStackTraces() {
void** result = new void*[needed_slots];
if (result == NULL) {
- MESSAGE("tcmalloc: allocation failed for stack trace slots",
- needed_slots * sizeof(*result));
+ Log(kLog, __FILE__, __LINE__,
+ "tcmalloc: allocation failed for stack trace slots",
+ needed_slots * sizeof(*result));
return NULL;
}
@@ -562,7 +627,7 @@ class TCMallocImplementation : public MallocExtension {
if (strcmp(name, "generic.current_allocated_bytes") == 0) {
TCMallocStats stats;
- ExtractStats(&stats, NULL);
+ ExtractStats(&stats, NULL, NULL, NULL);
*value = stats.pageheap.system_bytes
- stats.thread_bytes
- stats.central_bytes
@@ -574,7 +639,7 @@ class TCMallocImplementation : public MallocExtension {
if (strcmp(name, "generic.heap_size") == 0) {
TCMallocStats stats;
- ExtractStats(&stats, NULL);
+ ExtractStats(&stats, NULL, NULL, NULL);
*value = stats.pageheap.system_bytes;
return true;
}
@@ -608,7 +673,7 @@ class TCMallocImplementation : public MallocExtension {
if (strcmp(name, "tcmalloc.current_total_thread_cache_bytes") == 0) {
TCMallocStats stats;
- ExtractStats(&stats, NULL);
+ ExtractStats(&stats, NULL, NULL, NULL);
*value = stats.thread_bytes;
return true;
}
@@ -763,42 +828,39 @@ class TCMallocImplementation : public MallocExtension {
}
// append page heap info
- int64 page_count_normal[kMaxPages];
- int64 page_count_returned[kMaxPages];
- int64 span_count_normal;
- int64 span_count_returned;
+ PageHeap::SmallSpanStats small;
+ PageHeap::LargeSpanStats large;
{
SpinLockHolder h(Static::pageheap_lock());
- Static::pageheap()->GetClassSizes(page_count_normal,
- page_count_returned,
- &span_count_normal,
- &span_count_returned);
+ Static::pageheap()->GetSmallSpanStats(&small);
+ Static::pageheap()->GetLargeSpanStats(&large);
}
- // spans: mapped
+ // large spans: mapped
MallocExtension::FreeListInfo span_info;
span_info.type = kLargeSpanType;
span_info.max_object_size = (numeric_limits<size_t>::max)();
span_info.min_object_size = kMaxPages << kPageShift;
- span_info.total_bytes_free = span_count_normal << kPageShift;
+ span_info.total_bytes_free = large.normal_pages << kPageShift;
v->push_back(span_info);
- // spans: unmapped
+ // large spans: unmapped
span_info.type = kLargeUnmappedSpanType;
- span_info.total_bytes_free = span_count_returned << kPageShift;
+ span_info.total_bytes_free = large.returned_pages << kPageShift;
v->push_back(span_info);
+ // small spans
for (int s = 1; s < kMaxPages; s++) {
MallocExtension::FreeListInfo i;
i.max_object_size = (s << kPageShift);
i.min_object_size = ((s - 1) << kPageShift);
i.type = kPageHeapType;
- i.total_bytes_free = (s << kPageShift) * page_count_normal[s];
+ i.total_bytes_free = (s << kPageShift) * small.normal_length[s];
v->push_back(i);
i.type = kPageHeapUnmappedType;
- i.total_bytes_free = (s << kPageShift) * page_count_returned[s];
+ i.total_bytes_free = (s << kPageShift) * small.returned_length[s];
v->push_back(i);
}
}
@@ -824,12 +886,6 @@ TCMallocGuard::TCMallocGuard() {
tcmalloc::CheckIfKernelSupportsTLS();
#endif
ReplaceSystemAlloc(); // defined in libc_override_*.h
-#if defined(__APPLE__)
- // To break the recursive call of malloc, as malloc -> TCMALLOC_MESSAGE
- // -> snprintf -> localeconv_l -> malloc, on MacOS.
- char buf[32];
- snprintf(buf, sizeof(buf), "%d", tcmallocguard_refcount);
-#endif
tc_free(tc_malloc(1));
ThreadCache::InitTSD();
tc_free(tc_malloc(1));
@@ -1255,7 +1311,7 @@ inline int do_mallopt(int cmd, int value) {
#ifdef HAVE_STRUCT_MALLINFO
inline struct mallinfo do_mallinfo() {
TCMallocStats stats;
- ExtractStats(&stats, NULL);
+ ExtractStats(&stats, NULL, NULL, NULL);
// Just some of the fields are filled in.
struct mallinfo info;