00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033 #include "config.h"
00034 #include <assert.h>
00035 #include <string.h>
00036 #include <stdio.h>
00037 #if defined HAVE_STDINT_H
00038 #include <stdint.h>
00039 #elif defined HAVE_INTTYPES_H
00040 #include <inttypes.h>
00041 #else
00042 #include <sys/types.h>
00043 #endif
00044 #include <string>
00045 #include HASH_SET_H // defined in config.h
00046 #include "google/malloc_extension.h"
00047 #include "maybe_threads.h"
00048
00049 using STL_NAMESPACE::string;
00050
00051
00052 void MallocExtension::Initialize() {
00053 static bool initialize_called = false;
00054
00055 if (initialize_called) return;
00056 initialize_called = true;
00057
00058 #ifdef __GLIBC__
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068 setenv("GLIBCPP_FORCE_NEW", "1", false );
00069 setenv("GLIBCXX_FORCE_NEW", "1", false );
00070
00071
00072
00073
00074
00075 string dummy("I need to be allocated");
00076 dummy += "!";
00077 #endif
00078 }
00079
00080
00081 MallocExtension::~MallocExtension() { }
00082 bool MallocExtension::VerifyAllMemory() { return true; }
00083 bool MallocExtension::VerifyNewMemory(void* p) { return true; }
00084 bool MallocExtension::VerifyArrayNewMemory(void* p) { return true; }
00085 bool MallocExtension::VerifyMallocMemory(void* p) { return true; }
00086
00087 bool MallocExtension::GetNumericProperty(const char* property, size_t* value) {
00088 return false;
00089 }
00090
00091 bool MallocExtension::SetNumericProperty(const char* property, size_t value) {
00092 return false;
00093 }
00094
00095 void MallocExtension::GetStats(char* buffer, int length) {
00096 assert(length > 0);
00097 buffer[0] = '\0';
00098 }
00099
00100 bool MallocExtension::MallocMemoryStats(int* blocks, size_t* total,
00101 int histogram[kMallocHistogramSize]) {
00102 *blocks = 0;
00103 *total = 0;
00104 memset(histogram, 0, sizeof(histogram));
00105 return true;
00106 }
00107
00108 void** MallocExtension::ReadStackTraces() {
00109 return NULL;
00110 }
00111
00112 void** MallocExtension::ReadHeapGrowthStackTraces() {
00113 return NULL;
00114 }
00115
00116 void MallocExtension::MarkThreadIdle() {
00117
00118 }
00119
00120 void MallocExtension::ReleaseFreeMemory() {
00121
00122 }
00123
00124
00125
00126
00127
00128 static pthread_once_t module_init = PTHREAD_ONCE_INIT;
00129 static MallocExtension* default_instance = NULL;
00130 static MallocExtension* current_instance = NULL;
00131
00132 static void InitModule() {
00133 default_instance = new MallocExtension;
00134 current_instance = default_instance;
00135 }
00136
00137 MallocExtension* MallocExtension::instance() {
00138 perftools_pthread_once(&module_init, InitModule);
00139 return current_instance;
00140 }
00141
00142 void MallocExtension::Register(MallocExtension* implementation) {
00143 perftools_pthread_once(&module_init, InitModule);
00144 current_instance = implementation;
00145 }
00146
00147
00148
00149
00150
00151 namespace {
00152
00153
00154 uintptr_t Count(void** entry) {
00155 return reinterpret_cast<uintptr_t>(entry[0]);
00156 }
00157 uintptr_t Size(void** entry) {
00158 return reinterpret_cast<uintptr_t>(entry[1]);
00159 }
00160 uintptr_t Depth(void** entry) {
00161 return reinterpret_cast<uintptr_t>(entry[2]);
00162 }
00163 void* PC(void** entry, int i) {
00164 return entry[3+i];
00165 }
00166
00167
00168 struct StackTraceHash {
00169 size_t operator()(void** entry) const {
00170 uintptr_t h = 0;
00171 for (int i = 0; i < Depth(entry); i++) {
00172 h += reinterpret_cast<uintptr_t>(PC(entry, i));
00173 h += h << 10;
00174 h ^= h >> 6;
00175 }
00176 h += h << 3;
00177 h ^= h >> 11;
00178 return h;
00179 }
00180
00181 bool operator()(void** entry1, void** entry2) const {
00182 if (Depth(entry1) != Depth(entry2))
00183 return Depth(entry1) < Depth(entry2);
00184 for (int i = 0; i < Depth(entry1); i++) {
00185 if (PC(entry1, i) != PC(entry2, i)) {
00186 return PC(entry1, i) < PC(entry2, i);
00187 }
00188 }
00189 return false;
00190 }
00191
00192
00193 static const size_t bucket_size = 4;
00194 static const size_t min_buckets = 8;
00195 };
00196
00197 struct StackTraceEqual {
00198 bool operator()(void** entry1, void** entry2) const {
00199 if (Depth(entry1) != Depth(entry2)) return false;
00200 for (int i = 0; i < Depth(entry1); i++) {
00201 if (PC(entry1, i) != PC(entry2, i)) {
00202 return false;
00203 }
00204 }
00205 return true;
00206 }
00207 };
00208
00209 #ifdef WIN32
00210 typedef HASH_NAMESPACE::hash_set<void**, StackTraceHash> StackTraceTable;
00211 #else
00212 typedef HASH_NAMESPACE::hash_set<void**, StackTraceHash, StackTraceEqual> StackTraceTable;
00213 #endif
00214
00215 void PrintHeader(string* result, const char* label, void** entries) {
00216
00217 uintptr_t total_count = 0;
00218 uintptr_t total_size = 0;
00219 for (void** entry = entries; Count(entry) != 0; entry += 3 + Depth(entry)) {
00220 total_count += Count(entry);
00221 total_size += Size(entry);
00222 }
00223
00224 char buf[200];
00225 snprintf(buf, sizeof(buf),
00226 "heap profile: %6lld: %8lld [%6lld: %8lld] @ %s\n",
00227 static_cast<long long>(total_count),
00228 static_cast<long long>(total_size),
00229 static_cast<long long>(total_count),
00230 static_cast<long long>(total_size),
00231 label);
00232 *result += buf;
00233 }
00234
00235 void PrintStackEntry(string* result, void** entry) {
00236 char buf[100];
00237 snprintf(buf, sizeof(buf), "%6d: %8d [%6d: %8d] @",
00238 int(Count(entry)), int(Size(entry)),
00239 int(Count(entry)), int(Size(entry)));
00240 *result += buf;
00241 for (int i = 0; i < Depth(entry); i++) {
00242 snprintf(buf, sizeof(buf), " %p", PC(entry, i));
00243 *result += buf;
00244 }
00245 *result += "\n";
00246 }
00247
00248 }
00249
00250 void MallocExtension::GetHeapSample(string* result) {
00251 void** entries = ReadStackTraces();
00252 if (entries == NULL) {
00253 *result += "This malloc implementation does not support sampling.\n"
00254 "As of 2005/01/26, only tcmalloc supports sampling, and you\n"
00255 "are probably running a binary that does not use tcmalloc.\n";
00256 return;
00257 }
00258
00259
00260 StackTraceTable table;
00261 for (void** entry = entries; Count(entry) != 0; entry += 3 + Depth(entry)) {
00262 StackTraceTable::iterator iter = table.find(entry);
00263 if (iter == table.end()) {
00264
00265 table.insert(entry);
00266 } else {
00267 void** canonical = *iter;
00268 canonical[0] = reinterpret_cast<void*>(Count(canonical) + Count(entry));
00269 canonical[1] = reinterpret_cast<void*>(Size(canonical) + Size(entry));
00270 }
00271 }
00272
00273 PrintHeader(result, "heap", entries);
00274 for (StackTraceTable::iterator iter = table.begin();
00275 iter != table.end();
00276 ++iter) {
00277 PrintStackEntry(result, *iter);
00278 }
00279
00280
00281
00282 delete[] entries;
00283 }
00284
00285 void MallocExtension::GetHeapGrowthStacks(string* result) {
00286 void** entries = ReadHeapGrowthStackTraces();
00287 if (entries == NULL) {
00288 *result += "This malloc implementation does not support "
00289 "ReadHeapGrowthStackTraces().\n"
00290 "As of 2005/09/27, only tcmalloc supports this, and you\n"
00291 "are probably running a binary that does not use tcmalloc.\n";
00292 return;
00293 }
00294
00295
00296
00297
00298
00299 PrintHeader(result, "growth", entries);
00300 for (void** entry = entries; Count(entry) != 0; entry += 3 + Depth(entry)) {
00301 PrintStackEntry(result, entry);
00302 }
00303 delete[] entries;
00304
00305
00306
00307 }