diff options
author | csilvers <csilvers@6b5cf1ce-ec42-a296-1ba9-69fdba395a50> | 2011-10-18 20:57:45 +0000 |
---|---|---|
committer | csilvers <csilvers@6b5cf1ce-ec42-a296-1ba9-69fdba395a50> | 2011-10-18 20:57:45 +0000 |
commit | a6076edd177d59e67207753b799ce047a3663cb0 (patch) | |
tree | 5b3bce7c1fbc9277d82d62379000acbf32374a73 /src/tcmalloc.cc | |
parent | c2eedce2a718913ed6264ac8e96571c233761e3b (diff) | |
download | gperftools-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.cc | 122 |
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; |