1 // Copyright (c) 2012, Google Inc. 2 // All rights reserved. 3 // 4 // Redistribution and use in source and binary forms, with or without 5 // modification, are permitted provided that the following conditions are 6 // met: 7 // 8 // * Redistributions of source code must retain the above copyright 9 // notice, this list of conditions and the following disclaimer. 10 // * Redistributions in binary form must reproduce the above 11 // copyright notice, this list of conditions and the following disclaimer 12 // in the documentation and/or other materials provided with the 13 // distribution. 14 // * Neither the name of Google Inc. nor the names of its 15 // contributors may be used to endorse or promote products derived from 16 // this software without specific prior written permission. 17 // 18 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 30 // --- 31 // Author: Sanjay Ghemawat <opensource (at) google.com> 32 33 #include <config.h> 34 #include <assert.h> 35 #include <string.h> 36 #include <stdio.h> 37 #if defined HAVE_STDINT_H 38 #include <stdint.h> 39 #elif defined HAVE_INTTYPES_H 40 #include <inttypes.h> 41 #else 42 #include <sys/types.h> 43 #endif 44 #include <string> 45 #include "base/dynamic_annotations.h" 46 #include "base/sysinfo.h" // for FillProcSelfMaps 47 #ifndef NO_HEAP_CHECK 48 #include "gperftools/heap-checker.h" 49 #endif 50 #include "gperftools/malloc_extension.h" 51 #include "gperftools/malloc_extension_c.h" 52 #include "maybe_threads.h" 53 54 #ifdef USE_TCMALLOC 55 // Note that malloc_extension can be used without tcmalloc if gperftools' 56 // heap-profiler is enabled without the tcmalloc memory allocator. 57 #include "thread_cache.h" 58 #endif 59 60 using STL_NAMESPACE::string; 61 using STL_NAMESPACE::vector; 62 63 static void DumpAddressMap(string* result) { 64 *result += "\nMAPPED_LIBRARIES:\n"; 65 // We keep doubling until we get a fit 66 const size_t old_resultlen = result->size(); 67 for (int amap_size = 10240; amap_size < 10000000; amap_size *= 2) { 68 result->resize(old_resultlen + amap_size); 69 bool wrote_all = false; 70 const int bytes_written = 71 tcmalloc::FillProcSelfMaps(&((*result)[old_resultlen]), amap_size, 72 &wrote_all); 73 if (wrote_all) { // we fit! 74 (*result)[old_resultlen + bytes_written] = '\0'; 75 result->resize(old_resultlen + bytes_written); 76 return; 77 } 78 } 79 result->reserve(old_resultlen); // just don't print anything 80 } 81 82 // Note: this routine is meant to be called before threads are spawned. 83 void MallocExtension::Initialize() { 84 static bool initialize_called = false; 85 86 if (initialize_called) return; 87 initialize_called = true; 88 89 #ifdef __GLIBC__ 90 // GNU libc++ versions 3.3 and 3.4 obey the environment variables 91 // GLIBCPP_FORCE_NEW and GLIBCXX_FORCE_NEW respectively. Setting 92 // one of these variables forces the STL default allocator to call 93 // new() or delete() for each allocation or deletion. Otherwise 94 // the STL allocator tries to avoid the high cost of doing 95 // allocations by pooling memory internally. However, tcmalloc 96 // does allocations really fast, especially for the types of small 97 // items one sees in STL, so it's better off just using us. 98 // TODO: control whether we do this via an environment variable? 99 setenv("GLIBCPP_FORCE_NEW", "1", false /* no overwrite*/); 100 setenv("GLIBCXX_FORCE_NEW", "1", false /* no overwrite*/); 101 102 // Now we need to make the setenv 'stick', which it may not do since 103 // the env is flakey before main() is called. But luckily stl only 104 // looks at this env var the first time it tries to do an alloc, and 105 // caches what it finds. So we just cause an stl alloc here. 106 string dummy("I need to be allocated"); 107 dummy += "!"; // so the definition of dummy isn't optimized out 108 #endif /* __GLIBC__ */ 109 } 110 111 // SysAllocator implementation 112 SysAllocator::~SysAllocator() {} 113 114 // Default implementation -- does nothing 115 MallocExtension::~MallocExtension() { } 116 bool MallocExtension::VerifyAllMemory() { return true; } 117 bool MallocExtension::VerifyNewMemory(const void* p) { return true; } 118 bool MallocExtension::VerifyArrayNewMemory(const void* p) { return true; } 119 bool MallocExtension::VerifyMallocMemory(const void* p) { return true; } 120 121 bool MallocExtension::GetNumericProperty(const char* property, size_t* value) { 122 return false; 123 } 124 125 bool MallocExtension::SetNumericProperty(const char* property, size_t value) { 126 return false; 127 } 128 129 void MallocExtension::GetStats(char* buffer, int length) { 130 assert(length > 0); 131 buffer[0] = '\0'; 132 } 133 134 bool MallocExtension::MallocMemoryStats(int* blocks, size_t* total, 135 int histogram[kMallocHistogramSize]) { 136 *blocks = 0; 137 *total = 0; 138 memset(histogram, 0, sizeof(*histogram) * kMallocHistogramSize); 139 return true; 140 } 141 142 void** MallocExtension::ReadStackTraces(int* sample_period) { 143 return NULL; 144 } 145 146 void** MallocExtension::ReadHeapGrowthStackTraces() { 147 return NULL; 148 } 149 150 void MallocExtension::MarkThreadIdle() { 151 // Default implementation does nothing 152 } 153 154 void MallocExtension::MarkThreadBusy() { 155 // Default implementation does nothing 156 } 157 158 SysAllocator* MallocExtension::GetSystemAllocator() { 159 return NULL; 160 } 161 162 void MallocExtension::SetSystemAllocator(SysAllocator *a) { 163 // Default implementation does nothing 164 } 165 166 void MallocExtension::ReleaseToSystem(size_t num_bytes) { 167 // Default implementation does nothing 168 } 169 170 void MallocExtension::ReleaseFreeMemory() { 171 ReleaseToSystem(static_cast<size_t>(-1)); // SIZE_T_MAX 172 } 173 174 void MallocExtension::SetMemoryReleaseRate(double rate) { 175 // Default implementation does nothing 176 } 177 178 double MallocExtension::GetMemoryReleaseRate() { 179 return -1.0; 180 } 181 182 size_t MallocExtension::GetEstimatedAllocatedSize(size_t size) { 183 return size; 184 } 185 186 size_t MallocExtension::GetAllocatedSize(const void* p) { 187 assert(GetOwnership(p) != kNotOwned); 188 return 0; 189 } 190 191 MallocExtension::Ownership MallocExtension::GetOwnership(const void* p) { 192 return kUnknownOwnership; 193 } 194 195 void MallocExtension::GetFreeListSizes( 196 vector<MallocExtension::FreeListInfo>* v) { 197 v->clear(); 198 } 199 200 // The current malloc extension object. 201 202 static pthread_once_t module_init = PTHREAD_ONCE_INIT; 203 static MallocExtension* current_instance = NULL; 204 205 static void InitModule() { 206 current_instance = new MallocExtension; 207 #ifndef NO_HEAP_CHECK 208 HeapLeakChecker::IgnoreObject(current_instance); 209 #endif 210 } 211 212 MallocExtension* MallocExtension::instance() { 213 perftools_pthread_once(&module_init, InitModule); 214 return current_instance; 215 } 216 217 void MallocExtension::Register(MallocExtension* implementation) { 218 perftools_pthread_once(&module_init, InitModule); 219 // When running under valgrind, our custom malloc is replaced with 220 // valgrind's one and malloc extensions will not work. (Note: 221 // callers should be responsible for checking that they are the 222 // malloc that is really being run, before calling Register. This 223 // is just here as an extra sanity check.) 224 if (!RunningOnValgrind()) { 225 current_instance = implementation; 226 } 227 } 228 229 unsigned int MallocExtension::GetBytesAllocatedOnCurrentThread() { 230 // This function is added in Chromium for profiling. 231 #ifdef USE_TCMALLOC 232 // Note that malloc_extension can be used without tcmalloc if gperftools' 233 // heap-profiler is enabled without the tcmalloc memory allocator. 234 return tcmalloc::ThreadCache::GetBytesAllocatedOnCurrentThread(); 235 #else 236 return 0; 237 #endif 238 } 239 240 // ----------------------------------------------------------------------- 241 // Heap sampling support 242 // ----------------------------------------------------------------------- 243 244 namespace { 245 246 // Accessors 247 uintptr_t Count(void** entry) { 248 return reinterpret_cast<uintptr_t>(entry[0]); 249 } 250 uintptr_t Size(void** entry) { 251 return reinterpret_cast<uintptr_t>(entry[1]); 252 } 253 uintptr_t Depth(void** entry) { 254 return reinterpret_cast<uintptr_t>(entry[2]); 255 } 256 void* PC(void** entry, int i) { 257 return entry[3+i]; 258 } 259 260 void PrintCountAndSize(MallocExtensionWriter* writer, 261 uintptr_t count, uintptr_t size) { 262 char buf[100]; 263 snprintf(buf, sizeof(buf), 264 "%6" PRIu64 ": %8" PRIu64 " [%6" PRIu64 ": %8" PRIu64 "] @", 265 static_cast<uint64>(count), 266 static_cast<uint64>(size), 267 static_cast<uint64>(count), 268 static_cast<uint64>(size)); 269 writer->append(buf, strlen(buf)); 270 } 271 272 void PrintHeader(MallocExtensionWriter* writer, 273 const char* label, void** entries) { 274 // Compute the total count and total size 275 uintptr_t total_count = 0; 276 uintptr_t total_size = 0; 277 for (void** entry = entries; Count(entry) != 0; entry += 3 + Depth(entry)) { 278 total_count += Count(entry); 279 total_size += Size(entry); 280 } 281 282 const char* const kTitle = "heap profile: "; 283 writer->append(kTitle, strlen(kTitle)); 284 PrintCountAndSize(writer, total_count, total_size); 285 writer->append(" ", 1); 286 writer->append(label, strlen(label)); 287 writer->append("\n", 1); 288 } 289 290 void PrintStackEntry(MallocExtensionWriter* writer, void** entry) { 291 PrintCountAndSize(writer, Count(entry), Size(entry)); 292 293 for (int i = 0; i < Depth(entry); i++) { 294 char buf[32]; 295 snprintf(buf, sizeof(buf), " %p", PC(entry, i)); 296 writer->append(buf, strlen(buf)); 297 } 298 writer->append("\n", 1); 299 } 300 301 } 302 303 void MallocExtension::GetHeapSample(MallocExtensionWriter* writer) { 304 int sample_period = 0; 305 void** entries = ReadStackTraces(&sample_period); 306 if (entries == NULL) { 307 const char* const kErrorMsg = 308 "This malloc implementation does not support sampling.\n" 309 "As of 2005/01/26, only tcmalloc supports sampling, and\n" 310 "you are probably running a binary that does not use\n" 311 "tcmalloc.\n"; 312 writer->append(kErrorMsg, strlen(kErrorMsg)); 313 return; 314 } 315 316 char label[32]; 317 sprintf(label, "heap_v2/%d", sample_period); 318 PrintHeader(writer, label, entries); 319 for (void** entry = entries; Count(entry) != 0; entry += 3 + Depth(entry)) { 320 PrintStackEntry(writer, entry); 321 } 322 delete[] entries; 323 324 DumpAddressMap(writer); 325 } 326 327 void MallocExtension::GetHeapGrowthStacks(MallocExtensionWriter* writer) { 328 void** entries = ReadHeapGrowthStackTraces(); 329 if (entries == NULL) { 330 const char* const kErrorMsg = 331 "This malloc implementation does not support " 332 "ReadHeapGrowthStackTraces().\n" 333 "As of 2005/09/27, only tcmalloc supports this, and you\n" 334 "are probably running a binary that does not use tcmalloc.\n"; 335 writer->append(kErrorMsg, strlen(kErrorMsg)); 336 return; 337 } 338 339 // Do not canonicalize the stack entries, so that we get a 340 // time-ordered list of stack traces, which may be useful if the 341 // client wants to focus on the latest stack traces. 342 PrintHeader(writer, "growth", entries); 343 for (void** entry = entries; Count(entry) != 0; entry += 3 + Depth(entry)) { 344 PrintStackEntry(writer, entry); 345 } 346 delete[] entries; 347 348 DumpAddressMap(writer); 349 } 350 351 void MallocExtension::Ranges(void* arg, RangeFunction func) { 352 // No callbacks by default 353 } 354 355 // These are C shims that work on the current instance. 356 357 #define C_SHIM(fn, retval, paramlist, arglist) \ 358 extern "C" PERFTOOLS_DLL_DECL retval MallocExtension_##fn paramlist { \ 359 return MallocExtension::instance()->fn arglist; \ 360 } 361 362 C_SHIM(VerifyAllMemory, int, (void), ()); 363 C_SHIM(VerifyNewMemory, int, (const void* p), (p)); 364 C_SHIM(VerifyArrayNewMemory, int, (const void* p), (p)); 365 C_SHIM(VerifyMallocMemory, int, (const void* p), (p)); 366 C_SHIM(MallocMemoryStats, int, 367 (int* blocks, size_t* total, int histogram[kMallocHistogramSize]), 368 (blocks, total, histogram)); 369 370 C_SHIM(GetStats, void, 371 (char* buffer, int buffer_length), (buffer, buffer_length)); 372 C_SHIM(GetNumericProperty, int, 373 (const char* property, size_t* value), (property, value)); 374 C_SHIM(SetNumericProperty, int, 375 (const char* property, size_t value), (property, value)); 376 377 C_SHIM(MarkThreadIdle, void, (void), ()); 378 C_SHIM(MarkThreadBusy, void, (void), ()); 379 C_SHIM(ReleaseFreeMemory, void, (void), ()); 380 C_SHIM(ReleaseToSystem, void, (size_t num_bytes), (num_bytes)); 381 C_SHIM(GetEstimatedAllocatedSize, size_t, (size_t size), (size)); 382 C_SHIM(GetAllocatedSize, size_t, (const void* p), (p)); 383 384 // Can't use the shim here because of the need to translate the enums. 385 extern "C" 386 MallocExtension_Ownership MallocExtension_GetOwnership(const void* p) { 387 return static_cast<MallocExtension_Ownership>( 388 MallocExtension::instance()->GetOwnership(p)); 389 } 390