Home | History | Annotate | Download | only in src
      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 #include "thread_cache.h"
     54 
     55 using STL_NAMESPACE::string;
     56 using STL_NAMESPACE::vector;
     57 
     58 static void DumpAddressMap(string* result) {
     59   *result += "\nMAPPED_LIBRARIES:\n";
     60   // We keep doubling until we get a fit
     61   const size_t old_resultlen = result->size();
     62   for (int amap_size = 10240; amap_size < 10000000; amap_size *= 2) {
     63     result->resize(old_resultlen + amap_size);
     64     bool wrote_all = false;
     65     const int bytes_written =
     66         tcmalloc::FillProcSelfMaps(&((*result)[old_resultlen]), amap_size,
     67                                    &wrote_all);
     68     if (wrote_all) {   // we fit!
     69       (*result)[old_resultlen + bytes_written] = '\0';
     70       result->resize(old_resultlen + bytes_written);
     71       return;
     72     }
     73   }
     74   result->reserve(old_resultlen);   // just don't print anything
     75 }
     76 
     77 // Note: this routine is meant to be called before threads are spawned.
     78 void MallocExtension::Initialize() {
     79   static bool initialize_called = false;
     80 
     81   if (initialize_called) return;
     82   initialize_called = true;
     83 
     84 #ifdef __GLIBC__
     85   // GNU libc++ versions 3.3 and 3.4 obey the environment variables
     86   // GLIBCPP_FORCE_NEW and GLIBCXX_FORCE_NEW respectively.  Setting
     87   // one of these variables forces the STL default allocator to call
     88   // new() or delete() for each allocation or deletion.  Otherwise
     89   // the STL allocator tries to avoid the high cost of doing
     90   // allocations by pooling memory internally.  However, tcmalloc
     91   // does allocations really fast, especially for the types of small
     92   // items one sees in STL, so it's better off just using us.
     93   // TODO: control whether we do this via an environment variable?
     94   setenv("GLIBCPP_FORCE_NEW", "1", false /* no overwrite*/);
     95   setenv("GLIBCXX_FORCE_NEW", "1", false /* no overwrite*/);
     96 
     97   // Now we need to make the setenv 'stick', which it may not do since
     98   // the env is flakey before main() is called.  But luckily stl only
     99   // looks at this env var the first time it tries to do an alloc, and
    100   // caches what it finds.  So we just cause an stl alloc here.
    101   string dummy("I need to be allocated");
    102   dummy += "!";         // so the definition of dummy isn't optimized out
    103 #endif  /* __GLIBC__ */
    104 }
    105 
    106 // SysAllocator implementation
    107 SysAllocator::~SysAllocator() {}
    108 
    109 // Default implementation -- does nothing
    110 MallocExtension::~MallocExtension() { }
    111 bool MallocExtension::VerifyAllMemory() { return true; }
    112 bool MallocExtension::VerifyNewMemory(const void* p) { return true; }
    113 bool MallocExtension::VerifyArrayNewMemory(const void* p) { return true; }
    114 bool MallocExtension::VerifyMallocMemory(const void* p) { return true; }
    115 
    116 bool MallocExtension::GetNumericProperty(const char* property, size_t* value) {
    117   return false;
    118 }
    119 
    120 bool MallocExtension::SetNumericProperty(const char* property, size_t value) {
    121   return false;
    122 }
    123 
    124 void MallocExtension::GetStats(char* buffer, int length) {
    125   assert(length > 0);
    126   buffer[0] = '\0';
    127 }
    128 
    129 bool MallocExtension::MallocMemoryStats(int* blocks, size_t* total,
    130                                        int histogram[kMallocHistogramSize]) {
    131   *blocks = 0;
    132   *total = 0;
    133   memset(histogram, 0, sizeof(*histogram) * kMallocHistogramSize);
    134   return true;
    135 }
    136 
    137 void** MallocExtension::ReadStackTraces(int* sample_period) {
    138   return NULL;
    139 }
    140 
    141 void** MallocExtension::ReadHeapGrowthStackTraces() {
    142   return NULL;
    143 }
    144 
    145 void MallocExtension::MarkThreadIdle() {
    146   // Default implementation does nothing
    147 }
    148 
    149 void MallocExtension::MarkThreadBusy() {
    150   // Default implementation does nothing
    151 }
    152 
    153 SysAllocator* MallocExtension::GetSystemAllocator() {
    154   return NULL;
    155 }
    156 
    157 void MallocExtension::SetSystemAllocator(SysAllocator *a) {
    158   // Default implementation does nothing
    159 }
    160 
    161 void MallocExtension::ReleaseToSystem(size_t num_bytes) {
    162   // Default implementation does nothing
    163 }
    164 
    165 void MallocExtension::ReleaseFreeMemory() {
    166   ReleaseToSystem(static_cast<size_t>(-1));   // SIZE_T_MAX
    167 }
    168 
    169 void MallocExtension::SetMemoryReleaseRate(double rate) {
    170   // Default implementation does nothing
    171 }
    172 
    173 double MallocExtension::GetMemoryReleaseRate() {
    174   return -1.0;
    175 }
    176 
    177 size_t MallocExtension::GetEstimatedAllocatedSize(size_t size) {
    178   return size;
    179 }
    180 
    181 size_t MallocExtension::GetAllocatedSize(const void* p) {
    182   assert(GetOwnership(p) != kNotOwned);
    183   return 0;
    184 }
    185 
    186 MallocExtension::Ownership MallocExtension::GetOwnership(const void* p) {
    187   return kUnknownOwnership;
    188 }
    189 
    190 void MallocExtension::GetFreeListSizes(
    191     vector<MallocExtension::FreeListInfo>* v) {
    192   v->clear();
    193 }
    194 
    195 // The current malloc extension object.
    196 
    197 static pthread_once_t module_init = PTHREAD_ONCE_INIT;
    198 static MallocExtension* current_instance = NULL;
    199 
    200 static void InitModule() {
    201   current_instance = new MallocExtension;
    202 #ifndef NO_HEAP_CHECK
    203   HeapLeakChecker::IgnoreObject(current_instance);
    204 #endif
    205 }
    206 
    207 MallocExtension* MallocExtension::instance() {
    208   perftools_pthread_once(&module_init, InitModule);
    209   return current_instance;
    210 }
    211 
    212 void MallocExtension::Register(MallocExtension* implementation) {
    213   perftools_pthread_once(&module_init, InitModule);
    214   // When running under valgrind, our custom malloc is replaced with
    215   // valgrind's one and malloc extensions will not work.  (Note:
    216   // callers should be responsible for checking that they are the
    217   // malloc that is really being run, before calling Register.  This
    218   // is just here as an extra sanity check.)
    219   if (!RunningOnValgrind()) {
    220     current_instance = implementation;
    221   }
    222 }
    223 
    224 unsigned int MallocExtension::GetBytesAllocatedOnCurrentThread() {
    225   return tcmalloc::ThreadCache::GetBytesAllocatedOnCurrentThread();
    226 }
    227 
    228 // -----------------------------------------------------------------------
    229 // Heap sampling support
    230 // -----------------------------------------------------------------------
    231 
    232 namespace {
    233 
    234 // Accessors
    235 uintptr_t Count(void** entry) {
    236   return reinterpret_cast<uintptr_t>(entry[0]);
    237 }
    238 uintptr_t Size(void** entry) {
    239   return reinterpret_cast<uintptr_t>(entry[1]);
    240 }
    241 uintptr_t Depth(void** entry) {
    242   return reinterpret_cast<uintptr_t>(entry[2]);
    243 }
    244 void* PC(void** entry, int i) {
    245   return entry[3+i];
    246 }
    247 
    248 void PrintCountAndSize(MallocExtensionWriter* writer,
    249                        uintptr_t count, uintptr_t size) {
    250   char buf[100];
    251   snprintf(buf, sizeof(buf),
    252            "%6" PRIu64 ": %8" PRIu64 " [%6" PRIu64 ": %8" PRIu64 "] @",
    253            static_cast<uint64>(count),
    254            static_cast<uint64>(size),
    255            static_cast<uint64>(count),
    256            static_cast<uint64>(size));
    257   writer->append(buf, strlen(buf));
    258 }
    259 
    260 void PrintHeader(MallocExtensionWriter* writer,
    261                  const char* label, void** entries) {
    262   // Compute the total count and total size
    263   uintptr_t total_count = 0;
    264   uintptr_t total_size = 0;
    265   for (void** entry = entries; Count(entry) != 0; entry += 3 + Depth(entry)) {
    266     total_count += Count(entry);
    267     total_size += Size(entry);
    268   }
    269 
    270   const char* const kTitle = "heap profile: ";
    271   writer->append(kTitle, strlen(kTitle));
    272   PrintCountAndSize(writer, total_count, total_size);
    273   writer->append(" ", 1);
    274   writer->append(label, strlen(label));
    275   writer->append("\n", 1);
    276 }
    277 
    278 void PrintStackEntry(MallocExtensionWriter* writer, void** entry) {
    279   PrintCountAndSize(writer, Count(entry), Size(entry));
    280 
    281   for (int i = 0; i < Depth(entry); i++) {
    282     char buf[32];
    283     snprintf(buf, sizeof(buf), " %p", PC(entry, i));
    284     writer->append(buf, strlen(buf));
    285   }
    286   writer->append("\n", 1);
    287 }
    288 
    289 }
    290 
    291 void MallocExtension::GetHeapSample(MallocExtensionWriter* writer) {
    292   int sample_period = 0;
    293   void** entries = ReadStackTraces(&sample_period);
    294   if (entries == NULL) {
    295     const char* const kErrorMsg =
    296         "This malloc implementation does not support sampling.\n"
    297         "As of 2005/01/26, only tcmalloc supports sampling, and\n"
    298         "you are probably running a binary that does not use\n"
    299         "tcmalloc.\n";
    300     writer->append(kErrorMsg, strlen(kErrorMsg));
    301     return;
    302   }
    303 
    304   char label[32];
    305   sprintf(label, "heap_v2/%d", sample_period);
    306   PrintHeader(writer, label, entries);
    307   for (void** entry = entries; Count(entry) != 0; entry += 3 + Depth(entry)) {
    308     PrintStackEntry(writer, entry);
    309   }
    310   delete[] entries;
    311 
    312   DumpAddressMap(writer);
    313 }
    314 
    315 void MallocExtension::GetHeapGrowthStacks(MallocExtensionWriter* writer) {
    316   void** entries = ReadHeapGrowthStackTraces();
    317   if (entries == NULL) {
    318     const char* const kErrorMsg =
    319         "This malloc implementation does not support "
    320         "ReadHeapGrowthStackTraces().\n"
    321         "As of 2005/09/27, only tcmalloc supports this, and you\n"
    322         "are probably running a binary that does not use tcmalloc.\n";
    323     writer->append(kErrorMsg, strlen(kErrorMsg));
    324     return;
    325   }
    326 
    327   // Do not canonicalize the stack entries, so that we get a
    328   // time-ordered list of stack traces, which may be useful if the
    329   // client wants to focus on the latest stack traces.
    330   PrintHeader(writer, "growth", entries);
    331   for (void** entry = entries; Count(entry) != 0; entry += 3 + Depth(entry)) {
    332     PrintStackEntry(writer, entry);
    333   }
    334   delete[] entries;
    335 
    336   DumpAddressMap(writer);
    337 }
    338 
    339 void MallocExtension::Ranges(void* arg, RangeFunction func) {
    340   // No callbacks by default
    341 }
    342 
    343 // These are C shims that work on the current instance.
    344 
    345 #define C_SHIM(fn, retval, paramlist, arglist)          \
    346   extern "C" PERFTOOLS_DLL_DECL retval MallocExtension_##fn paramlist {    \
    347     return MallocExtension::instance()->fn arglist;     \
    348   }
    349 
    350 C_SHIM(VerifyAllMemory, int, (void), ());
    351 C_SHIM(VerifyNewMemory, int, (const void* p), (p));
    352 C_SHIM(VerifyArrayNewMemory, int, (const void* p), (p));
    353 C_SHIM(VerifyMallocMemory, int, (const void* p), (p));
    354 C_SHIM(MallocMemoryStats, int,
    355        (int* blocks, size_t* total, int histogram[kMallocHistogramSize]),
    356        (blocks, total, histogram));
    357 
    358 C_SHIM(GetStats, void,
    359        (char* buffer, int buffer_length), (buffer, buffer_length));
    360 C_SHIM(GetNumericProperty, int,
    361        (const char* property, size_t* value), (property, value));
    362 C_SHIM(SetNumericProperty, int,
    363        (const char* property, size_t value), (property, value));
    364 
    365 C_SHIM(MarkThreadIdle, void, (void), ());
    366 C_SHIM(MarkThreadBusy, void, (void), ());
    367 C_SHIM(ReleaseFreeMemory, void, (void), ());
    368 C_SHIM(ReleaseToSystem, void, (size_t num_bytes), (num_bytes));
    369 C_SHIM(GetEstimatedAllocatedSize, size_t, (size_t size), (size));
    370 C_SHIM(GetAllocatedSize, size_t, (const void* p), (p));
    371 
    372 // Can't use the shim here because of the need to translate the enums.
    373 extern "C"
    374 MallocExtension_Ownership MallocExtension_GetOwnership(const void* p) {
    375   return static_cast<MallocExtension_Ownership>(
    376       MallocExtension::instance()->GetOwnership(p));
    377 }
    378