| Index: third_party/tcmalloc/vendor/src/tcmalloc.cc
|
| diff --git a/third_party/tcmalloc/vendor/src/tcmalloc.cc b/third_party/tcmalloc/vendor/src/tcmalloc.cc
|
| index 263db8199a6a0092c68a3d92a4f498b73cd7c835..095718ec9c75cef37a528df932fbfe252cdc27fe 100644
|
| --- a/third_party/tcmalloc/vendor/src/tcmalloc.cc
|
| +++ b/third_party/tcmalloc/vendor/src/tcmalloc.cc
|
| @@ -87,7 +87,7 @@
|
| // goes from about 1100 ns to about 300 ns.
|
|
|
| #include "config.h"
|
| -#include <google/tcmalloc.h>
|
| +#include <gperftools/tcmalloc.h>
|
|
|
| #include <errno.h> // for ENOMEM, EINVAL, errno
|
| #ifdef HAVE_SYS_CDEFS_H
|
| @@ -111,8 +111,8 @@
|
| #include <new> // for nothrow_t (ptr only), etc
|
| #include <vector> // for vector
|
|
|
| -#include <google/malloc_extension.h>
|
| -#include <google/malloc_hook.h> // for MallocHook
|
| +#include <gperftools/malloc_extension.h>
|
| +#include <gperftools/malloc_hook.h> // for MallocHook
|
| #include "base/basictypes.h" // for int64
|
| #include "base/commandlineflags.h" // for RegisterFlagValidator, etc
|
| #include "base/dynamic_annotations.h" // for RunningOnValgrind
|
| @@ -147,6 +147,9 @@
|
| # define WIN32_DO_PATCHING 1
|
| #endif
|
|
|
| +// Some windows file somewhere (at least on cygwin) #define's small (!)
|
| +#undef small
|
| +
|
| using STL_NAMESPACE::max;
|
| using STL_NAMESPACE::numeric_limits;
|
| using STL_NAMESPACE::vector;
|
| @@ -162,6 +165,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 +286,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);
|
| +size_t InvalidGetSizeForRealloc(const void* 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);
|
| +size_t InvalidGetAllocatedSize(const void* ptr) {
|
| + Log(kCrash, __FILE__, __LINE__,
|
| + "Attempt to get the size of an invalid pointer", ptr);
|
| return 0;
|
| }
|
| } // unnamed namespace
|
| @@ -303,7 +312,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 +335,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 +431,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 +502,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 +630,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 +642,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 +676,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;
|
| }
|
| @@ -689,7 +757,7 @@ class TCMallocImplementation : public MallocExtension {
|
| // This just calls GetSizeWithCallback, but because that's in an
|
| // unnamed namespace, we need to move the definition below it in the
|
| // file.
|
| - virtual size_t GetAllocatedSize(void* ptr);
|
| + virtual size_t GetAllocatedSize(const void* ptr);
|
|
|
| // This duplicates some of the logic in GetSizeWithCallback, but is
|
| // faster. This is important on OS X, where this function is called
|
| @@ -763,42 +831,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 +889,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));
|
| @@ -1036,7 +1095,15 @@ static inline ThreadCache* GetCacheIfPresent() {
|
| // It is used primarily by windows code which wants a specialized callback.
|
| inline void do_free_with_callback(void* ptr, void (*invalid_free_fn)(void*)) {
|
| if (ptr == NULL) return;
|
| - ASSERT(Static::pageheap() != NULL); // Should not call free() before malloc()
|
| + if (Static::pageheap() == NULL) {
|
| + // We called free() before malloc(). This can occur if the
|
| + // (system) malloc() is called before tcmalloc is loaded, and then
|
| + // free() is called after tcmalloc is loaded (and tc_free has
|
| + // replaced free), but before the global constructor has run that
|
| + // sets up the tcmalloc data structures.
|
| + (*invalid_free_fn)(ptr); // Decide how to handle the bad free request
|
| + return;
|
| + }
|
| const PageID p = reinterpret_cast<uintptr_t>(ptr) >> kPageShift;
|
| Span* span = NULL;
|
| size_t cl = Static::pageheap()->GetSizeClassIfCached(p);
|
| @@ -1088,8 +1155,8 @@ inline void do_free(void* ptr) {
|
|
|
| // NOTE: some logic here is duplicated in GetOwnership (above), for
|
| // speed. If you change this function, look at that one too.
|
| -inline size_t GetSizeWithCallback(void* ptr,
|
| - size_t (*invalid_getsize_fn)(void*)) {
|
| +inline size_t GetSizeWithCallback(const void* ptr,
|
| + size_t (*invalid_getsize_fn)(const void*)) {
|
| if (ptr == NULL)
|
| return 0;
|
| const PageID p = reinterpret_cast<uintptr_t>(ptr) >> kPageShift;
|
| @@ -1114,7 +1181,7 @@ inline size_t GetSizeWithCallback(void* ptr,
|
| inline void* do_realloc_with_callback(
|
| void* old_ptr, size_t new_size,
|
| void (*invalid_free_fn)(void*),
|
| - size_t (*invalid_get_size_fn)(void*)) {
|
| + size_t (*invalid_get_size_fn)(const void*)) {
|
| // Get the size of the old entry
|
| const size_t old_size = GetSizeWithCallback(old_ptr, invalid_get_size_fn);
|
|
|
| @@ -1255,7 +1322,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;
|
| @@ -1379,7 +1446,7 @@ void* cpp_memalign(size_t align, size_t size) {
|
| } // end unnamed namespace
|
|
|
| // As promised, the definition of this function, declared above.
|
| -size_t TCMallocImplementation::GetAllocatedSize(void* ptr) {
|
| +size_t TCMallocImplementation::GetAllocatedSize(const void* ptr) {
|
| ASSERT(TCMallocImplementation::GetOwnership(ptr)
|
| != TCMallocImplementation::kNotOwned);
|
| return GetSizeWithCallback(ptr, &InvalidGetAllocatedSize);
|
|
|