| OLD | NEW |
| 1 // Copyright (c) 2005, Google Inc. | 1 // Copyright (c) 2005, Google Inc. |
| 2 // All rights reserved. | 2 // All rights reserved. |
| 3 // | 3 // |
| 4 // Redistribution and use in source and binary forms, with or without | 4 // Redistribution and use in source and binary forms, with or without |
| 5 // modification, are permitted provided that the following conditions are | 5 // modification, are permitted provided that the following conditions are |
| 6 // met: | 6 // met: |
| 7 // | 7 // |
| 8 // * Redistributions of source code must retain the above copyright | 8 // * Redistributions of source code must retain the above copyright |
| 9 // notice, this list of conditions and the following disclaimer. | 9 // notice, this list of conditions and the following disclaimer. |
| 10 // * Redistributions in binary form must reproduce the above | 10 // * Redistributions in binary form must reproduce the above |
| (...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 100 "If non-zero, dump heap profiling information once every " | 100 "If non-zero, dump heap profiling information once every " |
| 101 "specified number of bytes deallocated by the program " | 101 "specified number of bytes deallocated by the program " |
| 102 "since the last dump."); | 102 "since the last dump."); |
| 103 // We could also add flags that report whenever inuse_bytes changes by | 103 // We could also add flags that report whenever inuse_bytes changes by |
| 104 // X or -X, but there hasn't been a need for that yet, so we haven't. | 104 // X or -X, but there hasn't been a need for that yet, so we haven't. |
| 105 DEFINE_int64(heap_profile_inuse_interval, | 105 DEFINE_int64(heap_profile_inuse_interval, |
| 106 EnvToInt64("HEAP_PROFILE_INUSE_INTERVAL", 100 << 20 /*100MB*/), | 106 EnvToInt64("HEAP_PROFILE_INUSE_INTERVAL", 100 << 20 /*100MB*/), |
| 107 "If non-zero, dump heap profiling information whenever " | 107 "If non-zero, dump heap profiling information whenever " |
| 108 "the high-water memory usage mark increases by the specified " | 108 "the high-water memory usage mark increases by the specified " |
| 109 "number of bytes."); | 109 "number of bytes."); |
| 110 DEFINE_int64(heap_profile_time_interval, |
| 111 EnvToInt64("HEAP_PROFILE_TIME_INTERVAL", 0), |
| 112 "If non-zero, dump heap profiling information once every " |
| 113 "specified number of seconds since the last dump."); |
| 110 DEFINE_bool(mmap_log, | 114 DEFINE_bool(mmap_log, |
| 111 EnvToBool("HEAP_PROFILE_MMAP_LOG", false), | 115 EnvToBool("HEAP_PROFILE_MMAP_LOG", false), |
| 112 "Should mmap/munmap calls be logged?"); | 116 "Should mmap/munmap calls be logged?"); |
| 113 DEFINE_bool(mmap_profile, | 117 DEFINE_bool(mmap_profile, |
| 114 EnvToBool("HEAP_PROFILE_MMAP", false), | 118 EnvToBool("HEAP_PROFILE_MMAP", false), |
| 115 "If heap-profiling is on, also profile mmap, mremap, and sbrk)"); | 119 "If heap-profiling is on, also profile mmap, mremap, and sbrk)"); |
| 116 DEFINE_bool(only_mmap_profile, | 120 DEFINE_bool(only_mmap_profile, |
| 117 EnvToBool("HEAP_PROFILE_ONLY_MMAP", false), | 121 EnvToBool("HEAP_PROFILE_ONLY_MMAP", false), |
| 118 "If heap-profiling is on, only profile mmap, mremap, and sbrk; " | 122 "If heap-profiling is on, only profile mmap, mremap, and sbrk; " |
| 119 "do not profile malloc/new/etc"); | 123 "do not profile malloc/new/etc"); |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 161 | 165 |
| 162 // Access to all of these is protected by heap_lock. | 166 // Access to all of these is protected by heap_lock. |
| 163 static bool is_on = false; // If are on as a subsytem. | 167 static bool is_on = false; // If are on as a subsytem. |
| 164 static bool dumping = false; // Dumping status to prevent recursion | 168 static bool dumping = false; // Dumping status to prevent recursion |
| 165 static char* filename_prefix = NULL; // Prefix used for profile file names | 169 static char* filename_prefix = NULL; // Prefix used for profile file names |
| 166 // (NULL if no need for dumping yet) | 170 // (NULL if no need for dumping yet) |
| 167 static int dump_count = 0; // How many dumps so far | 171 static int dump_count = 0; // How many dumps so far |
| 168 static int64 last_dump_alloc = 0; // alloc_size when did we last dump | 172 static int64 last_dump_alloc = 0; // alloc_size when did we last dump |
| 169 static int64 last_dump_free = 0; // free_size when did we last dump | 173 static int64 last_dump_free = 0; // free_size when did we last dump |
| 170 static int64 high_water_mark = 0; // In-use-bytes at last high-water dump | 174 static int64 high_water_mark = 0; // In-use-bytes at last high-water dump |
| 175 static int64 last_dump_time = 0; // The time of the last dump |
| 171 | 176 |
| 172 static HeapProfileTable* heap_profile = NULL; // the heap profile table | 177 static HeapProfileTable* heap_profile = NULL; // the heap profile table |
| 173 | 178 |
| 174 //---------------------------------------------------------------------- | 179 //---------------------------------------------------------------------- |
| 175 // Profile generation | 180 // Profile generation |
| 176 //---------------------------------------------------------------------- | 181 //---------------------------------------------------------------------- |
| 177 | 182 |
| 178 // Input must be a buffer of size at least 1MB. | 183 // Input must be a buffer of size at least 1MB. |
| 179 static char* DoGetHeapProfileLocked(char* buf, int buflen) { | 184 static char* DoGetHeapProfileLocked(char* buf, int buflen) { |
| 180 // We used to be smarter about estimating the required memory and | 185 // We used to be smarter about estimating the required memory and |
| (...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 257 //---------------------------------------------------------------------- | 262 //---------------------------------------------------------------------- |
| 258 | 263 |
| 259 // Dump a profile after either an allocation or deallocation, if | 264 // Dump a profile after either an allocation or deallocation, if |
| 260 // the memory use has changed enough since the last dump. | 265 // the memory use has changed enough since the last dump. |
| 261 static void MaybeDumpProfileLocked() { | 266 static void MaybeDumpProfileLocked() { |
| 262 if (!dumping) { | 267 if (!dumping) { |
| 263 const HeapProfileTable::Stats& total = heap_profile->total(); | 268 const HeapProfileTable::Stats& total = heap_profile->total(); |
| 264 const int64 inuse_bytes = total.alloc_size - total.free_size; | 269 const int64 inuse_bytes = total.alloc_size - total.free_size; |
| 265 bool need_to_dump = false; | 270 bool need_to_dump = false; |
| 266 char buf[128]; | 271 char buf[128]; |
| 272 int64 current_time = time(NULL); |
| 267 if (FLAGS_heap_profile_allocation_interval > 0 && | 273 if (FLAGS_heap_profile_allocation_interval > 0 && |
| 268 total.alloc_size >= | 274 total.alloc_size >= |
| 269 last_dump_alloc + FLAGS_heap_profile_allocation_interval) { | 275 last_dump_alloc + FLAGS_heap_profile_allocation_interval) { |
| 270 snprintf(buf, sizeof(buf), ("%"PRId64" MB allocated cumulatively, " | 276 snprintf(buf, sizeof(buf), ("%"PRId64" MB allocated cumulatively, " |
| 271 "%"PRId64" MB currently in use"), | 277 "%"PRId64" MB currently in use"), |
| 272 total.alloc_size >> 20, inuse_bytes >> 20); | 278 total.alloc_size >> 20, inuse_bytes >> 20); |
| 273 need_to_dump = true; | 279 need_to_dump = true; |
| 274 } else if (FLAGS_heap_profile_deallocation_interval > 0 && | 280 } else if (FLAGS_heap_profile_deallocation_interval > 0 && |
| 275 total.free_size >= | 281 total.free_size >= |
| 276 last_dump_free + FLAGS_heap_profile_deallocation_interval) { | 282 last_dump_free + FLAGS_heap_profile_deallocation_interval) { |
| 277 snprintf(buf, sizeof(buf), ("%"PRId64" MB freed cumulatively, " | 283 snprintf(buf, sizeof(buf), ("%"PRId64" MB freed cumulatively, " |
| 278 "%"PRId64" MB currently in use"), | 284 "%"PRId64" MB currently in use"), |
| 279 total.free_size >> 20, inuse_bytes >> 20); | 285 total.free_size >> 20, inuse_bytes >> 20); |
| 280 need_to_dump = true; | 286 need_to_dump = true; |
| 281 } else if (FLAGS_heap_profile_inuse_interval > 0 && | 287 } else if (FLAGS_heap_profile_inuse_interval > 0 && |
| 282 inuse_bytes > | 288 inuse_bytes > |
| 283 high_water_mark + FLAGS_heap_profile_inuse_interval) { | 289 high_water_mark + FLAGS_heap_profile_inuse_interval) { |
| 284 snprintf(buf, sizeof(buf), "%"PRId64" MB currently in use", | 290 snprintf(buf, sizeof(buf), "%"PRId64" MB currently in use", |
| 285 inuse_bytes >> 20); | 291 inuse_bytes >> 20); |
| 286 need_to_dump = true; | 292 need_to_dump = true; |
| 293 } else if (FLAGS_heap_profile_time_interval > 0 && |
| 294 current_time - last_dump_time >= |
| 295 FLAGS_heap_profile_time_interval) { |
| 296 snprintf(buf, sizeof(buf), "%d sec since the last dump", |
| 297 current_time - last_dump_time); |
| 298 need_to_dump = true; |
| 299 last_dump_time = current_time; |
| 287 } | 300 } |
| 288 if (need_to_dump) { | 301 if (need_to_dump) { |
| 289 DumpProfileLocked(buf); | 302 DumpProfileLocked(buf); |
| 290 | 303 |
| 291 last_dump_alloc = total.alloc_size; | 304 last_dump_alloc = total.alloc_size; |
| 292 last_dump_free = total.free_size; | 305 last_dump_free = total.free_size; |
| 293 if (inuse_bytes > high_water_mark) | 306 if (inuse_bytes > high_water_mark) |
| 294 high_water_mark = inuse_bytes; | 307 high_water_mark = inuse_bytes; |
| 295 } | 308 } |
| 296 } | 309 } |
| (...skipping 140 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 437 // heap profile even if the application runs out of memory. | 450 // heap profile even if the application runs out of memory. |
| 438 global_profiler_buffer = | 451 global_profiler_buffer = |
| 439 reinterpret_cast<char*>(ProfilerMalloc(kProfileBufferSize)); | 452 reinterpret_cast<char*>(ProfilerMalloc(kProfileBufferSize)); |
| 440 | 453 |
| 441 heap_profile = new(ProfilerMalloc(sizeof(HeapProfileTable))) | 454 heap_profile = new(ProfilerMalloc(sizeof(HeapProfileTable))) |
| 442 HeapProfileTable(ProfilerMalloc, ProfilerFree); | 455 HeapProfileTable(ProfilerMalloc, ProfilerFree); |
| 443 | 456 |
| 444 last_dump_alloc = 0; | 457 last_dump_alloc = 0; |
| 445 last_dump_free = 0; | 458 last_dump_free = 0; |
| 446 high_water_mark = 0; | 459 high_water_mark = 0; |
| 460 last_dump_time = 0; |
| 447 | 461 |
| 448 // We do not reset dump_count so if the user does a sequence of | 462 // We do not reset dump_count so if the user does a sequence of |
| 449 // HeapProfilerStart/HeapProfileStop, we will get a continuous | 463 // HeapProfilerStart/HeapProfileStop, we will get a continuous |
| 450 // sequence of profiles. | 464 // sequence of profiles. |
| 451 | 465 |
| 452 if (FLAGS_only_mmap_profile == false) { | 466 if (FLAGS_only_mmap_profile == false) { |
| 453 // Now set the hooks that capture new/delete and malloc/free. | 467 // Now set the hooks that capture new/delete and malloc/free. |
| 454 RAW_CHECK(MallocHook::AddNewHook(&NewHook), ""); | 468 RAW_CHECK(MallocHook::AddNewHook(&NewHook), ""); |
| 455 RAW_CHECK(MallocHook::AddDeleteHook(&DeleteHook), ""); | 469 RAW_CHECK(MallocHook::AddDeleteHook(&DeleteHook), ""); |
| 456 } | 470 } |
| (...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 543 | 557 |
| 544 // class used for finalization -- dumps the heap-profile at program exit | 558 // class used for finalization -- dumps the heap-profile at program exit |
| 545 struct HeapProfileEndWriter { | 559 struct HeapProfileEndWriter { |
| 546 ~HeapProfileEndWriter() { HeapProfilerDump("Exiting"); } | 560 ~HeapProfileEndWriter() { HeapProfilerDump("Exiting"); } |
| 547 }; | 561 }; |
| 548 | 562 |
| 549 // We want to make sure tcmalloc is up and running before starting the profiler | 563 // We want to make sure tcmalloc is up and running before starting the profiler |
| 550 static const TCMallocGuard tcmalloc_initializer; | 564 static const TCMallocGuard tcmalloc_initializer; |
| 551 REGISTER_MODULE_INITIALIZER(heapprofiler, HeapProfilerInit()); | 565 REGISTER_MODULE_INITIALIZER(heapprofiler, HeapProfilerInit()); |
| 552 static HeapProfileEndWriter heap_profile_end_writer; | 566 static HeapProfileEndWriter heap_profile_end_writer; |
| OLD | NEW |