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