diff options
author | Kyle Suarez <ksuarz@gmail.com> | 2016-03-25 10:18:21 -0400 |
---|---|---|
committer | Kyle Suarez <kyle.suarez@mongodb.com> | 2016-07-18 11:19:14 -0400 |
commit | 475099387db16d73f5113aa7ef6b28e5e71bc3f9 (patch) | |
tree | 79a5e34feed7e00fd16a3487a78ace79a1b5fff8 /src | |
parent | 9c32789ac1301d2314f606b026239b45123e0ef7 (diff) | |
download | mongo-475099387db16d73f5113aa7ef6b28e5e71bc3f9.tar.gz |
SERVER-23069 improve tcmalloc freelist stats
Walks the size classes in TCMalloc's central freelist, exposing interesting
statistics via a callback.
serverStatus() now includes this information in lieu of the TCMalloc dump stats
text block.
(cherry picked from commit a1d9d2251734bc4077255ae33e17f5a210697839)
Diffstat (limited to 'src')
-rw-r--r-- | src/mongo/util/SConscript | 3 | ||||
-rw-r--r-- | src/mongo/util/tcmalloc_server_status_section.cpp | 40 | ||||
-rw-r--r-- | src/third_party/gperftools-2.2/src/central_freelist.h | 6 | ||||
-rw-r--r-- | src/third_party/gperftools-2.2/src/gperftools/malloc_extension.h | 17 | ||||
-rw-r--r-- | src/third_party/gperftools-2.2/src/malloc_extension.cc | 8 | ||||
-rw-r--r-- | src/third_party/gperftools-2.2/src/tcmalloc.cc | 25 |
6 files changed, 94 insertions, 5 deletions
diff --git a/src/mongo/util/SConscript b/src/mongo/util/SConscript index 46dd06bc900..3f6660779d4 100644 --- a/src/mongo/util/SConscript +++ b/src/mongo/util/SConscript @@ -248,7 +248,8 @@ if env['MONGO_ALLOCATOR'] == 'tcmalloc': # level configure check, though its effects should still be scoped just to these files. tcmspEnv.Append( CPPDEFINES=[ - 'MONGO_HAVE_GPERFTOOLS_GET_THREAD_CACHE_SIZE' + 'MONGO_HAVE_GPERFTOOLS_GET_THREAD_CACHE_SIZE', + 'MONGO_HAVE_GPERFTOOLS_SIZE_CLASS_STATS' ] ) diff --git a/src/mongo/util/tcmalloc_server_status_section.cpp b/src/mongo/util/tcmalloc_server_status_section.cpp index fe4522345d9..5b277e5d826 100644 --- a/src/mongo/util/tcmalloc_server_status_section.cpp +++ b/src/mongo/util/tcmalloc_server_status_section.cpp @@ -111,6 +111,7 @@ public: } { BSONObjBuilder sub(builder.subobjStart("tcmalloc")); + appendNumericPropertyIfAvailable( sub, "pageheap_free_bytes", "tcmalloc.pageheap_free_bytes"); appendNumericPropertyIfAvailable( @@ -122,6 +123,16 @@ public: "tcmalloc.current_total_thread_cache_bytes"); // Not including tcmalloc.slack_bytes since it is deprecated. + // Calculate total free bytes, *excluding the page heap* + size_t central, transfer, thread; + if (MallocExtension::instance()->GetNumericProperty("tcmalloc.central_cache_free_bytes", + ¢ral) && + MallocExtension::instance()->GetNumericProperty( + "tcmalloc.transfer_cache_free_bytes", &transfer) && + MallocExtension::instance()->GetNumericProperty("tcmalloc.thread_cache_free_bytes", + &thread)) { + sub.appendNumber("total_free_bytes", central + transfer + thread); + } appendNumericPropertyIfAvailable( sub, "central_cache_free_bytes", "tcmalloc.central_cache_free_bytes"); appendNumericPropertyIfAvailable( @@ -130,11 +141,14 @@ public: sub, "thread_cache_free_bytes", "tcmalloc.thread_cache_free_bytes"); appendNumericPropertyIfAvailable( sub, "aggressive_memory_decommit", "tcmalloc.aggressive_memory_decommit"); - } - char buffer[4096]; - MallocExtension::instance()->GetStats(buffer, sizeof(buffer)); - builder.append("formattedString", buffer); +#if MONGO_HAVE_GPERFTOOLS_SIZE_CLASS_STATS + // Size class information + BSONArrayBuilder arr; + MallocExtension::instance()->SizeClasses(&arr, appendSizeClassInfo); + sub.append("size_classes", arr.arr()); +#endif + } return builder.obj(); } @@ -147,6 +161,24 @@ private: if (MallocExtension::instance()->GetNumericProperty(property, &value)) builder.appendNumber(bsonName, value); } + +#if MONGO_HAVE_GPERFTOOLS_SIZE_CLASS_STATS + static void appendSizeClassInfo(void* bsonarr_builder, const base::MallocSizeClass* stats) { + BSONArrayBuilder* builder = reinterpret_cast<BSONArrayBuilder*>(bsonarr_builder); + BSONObjBuilder doc; + + doc.appendNumber("bytes_per_object", stats->bytes_per_obj); + doc.appendNumber("pages_per_span", stats->pages_per_span); + doc.appendNumber("num_spans", stats->num_spans); + doc.appendNumber("num_thread_objs", stats->num_thread_objs); + doc.appendNumber("num_central_objs", stats->num_central_objs); + doc.appendNumber("num_transfer_objs", stats->num_transfer_objs); + doc.appendNumber("free_bytes", stats->free_bytes); + doc.appendNumber("allocated_bytes", stats->alloc_bytes); + + builder->append(doc.obj()); + } +#endif } tcmallocServerStatusSection; } } diff --git a/src/third_party/gperftools-2.2/src/central_freelist.h b/src/third_party/gperftools-2.2/src/central_freelist.h index 4148680d20a..4085ee41b98 100644 --- a/src/third_party/gperftools-2.2/src/central_freelist.h +++ b/src/third_party/gperftools-2.2/src/central_freelist.h @@ -74,6 +74,12 @@ class CentralFreeList { // Returns the number of free objects in the transfer cache. int tc_length(); + // Returns the number of spans in both the empty and nonempty freelists. + int spans() { + SpinLockHolder h(&lock_); + return num_spans_; + } + // Returns the memory overhead (internal fragmentation) attributable // to the freelist. This is memory lost when the size of elements // in a freelist doesn't exactly divide the page-size (an 8192-byte diff --git a/src/third_party/gperftools-2.2/src/gperftools/malloc_extension.h b/src/third_party/gperftools-2.2/src/gperftools/malloc_extension.h index f331f5f2e49..06138f880fd 100644 --- a/src/third_party/gperftools-2.2/src/gperftools/malloc_extension.h +++ b/src/third_party/gperftools-2.2/src/gperftools/malloc_extension.h @@ -69,6 +69,7 @@ typedef std::string MallocExtensionWriter; namespace base { struct MallocRange; +struct MallocSizeClass; } // Interface to a pluggable system allocator. @@ -395,6 +396,11 @@ class PERFTOOLS_DLL_DECL MallocExtension { // Like ReadStackTraces(), but returns stack traces that caused growth // in the address space size. virtual void** ReadHeapGrowthStackTraces(); + + // Invokes func(arg, classinfo) for every size class. + // *classinfo is filled in with information about the size class. + typedef void (SizeClassFunction)(void*, const base::MallocSizeClass*); + virtual void SizeClasses(void* arg, SizeClassFunction func); }; namespace base { @@ -420,6 +426,17 @@ struct MallocRange { // - age when allocated (for inuse) or freed (if not in use) }; +struct MallocSizeClass { + size_t bytes_per_obj; + size_t pages_per_span; + size_t num_spans; + size_t num_thread_objs; + size_t num_central_objs; + size_t num_transfer_objs; + size_t free_bytes; + size_t alloc_bytes; +}; + } // namespace base #endif // BASE_MALLOC_EXTENSION_H_ diff --git a/src/third_party/gperftools-2.2/src/malloc_extension.cc b/src/third_party/gperftools-2.2/src/malloc_extension.cc index 9126efbeaa7..6fdb0437918 100644 --- a/src/third_party/gperftools-2.2/src/malloc_extension.cc +++ b/src/third_party/gperftools-2.2/src/malloc_extension.cc @@ -118,6 +118,7 @@ bool MallocExtension::GetNumericProperty(const char* property, size_t* value) { return false; } + bool MallocExtension::SetNumericProperty(const char* property, size_t value) { return false; } @@ -345,6 +346,10 @@ void MallocExtension::Ranges(void* arg, RangeFunction func) { // No callbacks by default } +void MallocExtension::SizeClasses(void* arg, SizeClassFunction func) { + // Do nothing by default +} + // These are C shims that work on the current instance. #define C_SHIM(fn, retval, paramlist, arglist) \ @@ -366,6 +371,9 @@ C_SHIM(GetNumericProperty, int, (const char* property, size_t* value), (property, value)); C_SHIM(SetNumericProperty, int, (const char* property, size_t value), (property, value)); +C_SHIM(SizeClasses, void, + (void* arg, void (func)(void*, const base::MallocSizeClass*)), + (arg, func)); C_SHIM(MarkThreadIdle, void, (void), ()); C_SHIM(MarkThreadBusy, void, (void), ()); diff --git a/src/third_party/gperftools-2.2/src/tcmalloc.cc b/src/third_party/gperftools-2.2/src/tcmalloc.cc index 82024b336c1..0bc8baa5fd8 100644 --- a/src/third_party/gperftools-2.2/src/tcmalloc.cc +++ b/src/third_party/gperftools-2.2/src/tcmalloc.cc @@ -623,6 +623,31 @@ class TCMallocImplementation : public MallocExtension { IterateOverRanges(arg, func); } + virtual void SizeClasses(void* arg, SizeClassFunction func) { + TCMallocStats global_stats; + base::MallocSizeClass stats; + uint64_t class_count[kNumClasses]; + ExtractStats(&global_stats, class_count, NULL, NULL); + + for (int cl = 0; cl < kNumClasses; cl++) { + uint64_t central_objs = Static::central_cache()[cl].length(); + uint64_t transfer_objs = Static::central_cache()[cl].tc_length(); + uint64_t num_spans = Static::central_cache()[cl].spans(); + uint64_t pages_per_span = Static::sizemap()->class_to_pages(cl); + + stats.bytes_per_obj = Static::sizemap()->ByteSizeForClass(cl); + stats.pages_per_span = pages_per_span; + stats.num_spans = num_spans; + stats.num_central_objs = central_objs; + stats.num_transfer_objs = transfer_objs; + stats.num_thread_objs = class_count[cl] - central_objs - transfer_objs; + stats.free_bytes = class_count[cl] * Static::sizemap()->ByteSizeForClass(cl); + stats.alloc_bytes = (num_spans * pages_per_span) << kPageShift; + + func(arg, &stats); + } + } + virtual bool GetNumericProperty(const char* name, size_t* value) { ASSERT(name != NULL); |