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 204 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
215 // (NULL if no need for dumping yet) | 215 // (NULL if no need for dumping yet) |
216 static int dump_count = 0; // How many dumps so far | 216 static int dump_count = 0; // How many dumps so far |
217 static int64 last_dump_alloc = 0; // alloc_size when did we last dump | 217 static int64 last_dump_alloc = 0; // alloc_size when did we last dump |
218 static int64 last_dump_free = 0; // free_size when did we last dump | 218 static int64 last_dump_free = 0; // free_size when did we last dump |
219 static int64 high_water_mark = 0; // In-use-bytes at last high-water dump | 219 static int64 high_water_mark = 0; // In-use-bytes at last high-water dump |
220 static int64 last_dump_time = 0; // The time of the last dump | 220 static int64 last_dump_time = 0; // The time of the last dump |
221 | 221 |
222 static HeapProfileTable* heap_profile = NULL; // the heap profile table | 222 static HeapProfileTable* heap_profile = NULL; // the heap profile table |
223 static DeepHeapProfile* deep_profile = NULL; // deep memory profiler | 223 static DeepHeapProfile* deep_profile = NULL; // deep memory profiler |
224 | 224 |
| 225 // Callback an appplication can use to generate its own "stacks". |
| 226 static PseudoStackGenerator pseudo_stack_generator = NULL; |
| 227 |
225 //---------------------------------------------------------------------- | 228 //---------------------------------------------------------------------- |
226 // Profile generation | 229 // Profile generation |
227 //---------------------------------------------------------------------- | 230 //---------------------------------------------------------------------- |
228 | 231 |
229 // Input must be a buffer of size at least 1MB. | 232 // Input must be a buffer of size at least 1MB. |
230 static char* DoGetHeapProfileLocked(char* buf, int buflen) { | 233 static char* DoGetHeapProfileLocked(char* buf, int buflen) { |
231 // We used to be smarter about estimating the required memory and | 234 // We used to be smarter about estimating the required memory and |
232 // then capping it to 1MB and generating the profile into that. | 235 // then capping it to 1MB and generating the profile into that. |
233 if (buf == NULL || buflen < 1) | 236 if (buf == NULL || buflen < 1) |
234 return NULL; | 237 return NULL; |
(...skipping 132 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
367 if (inuse_bytes > high_water_mark) | 370 if (inuse_bytes > high_water_mark) |
368 high_water_mark = inuse_bytes; | 371 high_water_mark = inuse_bytes; |
369 } | 372 } |
370 } | 373 } |
371 } | 374 } |
372 | 375 |
373 // Record an allocation in the profile. | 376 // Record an allocation in the profile. |
374 static void RecordAlloc(const void* ptr, size_t bytes, int skip_count) { | 377 static void RecordAlloc(const void* ptr, size_t bytes, int skip_count) { |
375 // Take the stack trace outside the critical section. | 378 // Take the stack trace outside the critical section. |
376 void* stack[HeapProfileTable::kMaxStackDepth]; | 379 void* stack[HeapProfileTable::kMaxStackDepth]; |
377 int depth = HeapProfileTable::GetCallerStackTrace(skip_count + 1, stack); | 380 // If using pseudo-stacks then use a callback to get the stack, otherwise |
| 381 // use normal stack unwinding. |
| 382 int depth = pseudo_stack_generator ? |
| 383 (*pseudo_stack_generator)(stack) : |
| 384 HeapProfileTable::GetCallerStackTrace(skip_count + 1, stack); |
378 SpinLockHolder l(&heap_lock); | 385 SpinLockHolder l(&heap_lock); |
379 if (is_on) { | 386 if (is_on) { |
380 heap_profile->RecordAlloc(ptr, bytes, depth, stack); | 387 heap_profile->RecordAlloc(ptr, bytes, depth, stack); |
381 MaybeDumpProfileLocked(); | 388 MaybeDumpProfileLocked(); |
382 } | 389 } |
383 } | 390 } |
384 | 391 |
385 // Record a deallocation in the profile. | 392 // Record a deallocation in the profile. |
386 static void RecordFree(const void* ptr) { | 393 static void RecordFree(const void* ptr) { |
387 SpinLockHolder l(&heap_lock); | 394 SpinLockHolder l(&heap_lock); |
(...skipping 147 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
535 // We do not reset dump_count so if the user does a sequence of | 542 // We do not reset dump_count so if the user does a sequence of |
536 // HeapProfilerStart/HeapProfileStop, we will get a continuous | 543 // HeapProfilerStart/HeapProfileStop, we will get a continuous |
537 // sequence of profiles. | 544 // sequence of profiles. |
538 | 545 |
539 if (FLAGS_only_mmap_profile == false) { | 546 if (FLAGS_only_mmap_profile == false) { |
540 // Now set the hooks that capture new/delete and malloc/free. | 547 // Now set the hooks that capture new/delete and malloc/free. |
541 RAW_CHECK(MallocHook::AddNewHook(&NewHook), ""); | 548 RAW_CHECK(MallocHook::AddNewHook(&NewHook), ""); |
542 RAW_CHECK(MallocHook::AddDeleteHook(&DeleteHook), ""); | 549 RAW_CHECK(MallocHook::AddDeleteHook(&DeleteHook), ""); |
543 } | 550 } |
544 | 551 |
545 // Copy filename prefix | 552 // Copy filename prefix if provided. |
546 RAW_DCHECK(filename_prefix == NULL, ""); | 553 if (prefix) { |
547 const int prefix_length = strlen(prefix); | 554 RAW_DCHECK(filename_prefix == NULL, ""); |
548 filename_prefix = reinterpret_cast<char*>(ProfilerMalloc(prefix_length + 1)); | 555 const int prefix_length = strlen(prefix); |
549 memcpy(filename_prefix, prefix, prefix_length); | 556 filename_prefix = |
550 filename_prefix[prefix_length] = '\0'; | 557 reinterpret_cast<char*>(ProfilerMalloc(prefix_length + 1)); |
| 558 memcpy(filename_prefix, prefix, prefix_length); |
| 559 filename_prefix[prefix_length] = '\0'; |
| 560 } |
| 561 } |
| 562 |
| 563 extern "C" void HeapProfilerWithPseudoStackStart( |
| 564 PseudoStackGenerator callback) { |
| 565 { |
| 566 // Ensure the callback is set before allocations can be recorded. |
| 567 SpinLockHolder l(&heap_lock); |
| 568 pseudo_stack_generator = callback; |
| 569 } |
| 570 HeapProfilerStart(NULL); |
551 } | 571 } |
552 | 572 |
553 extern "C" void IterateAllocatedObjects(AddressVisitor visitor, void* data) { | 573 extern "C" void IterateAllocatedObjects(AddressVisitor visitor, void* data) { |
554 SpinLockHolder l(&heap_lock); | 574 SpinLockHolder l(&heap_lock); |
555 | 575 |
556 if (!is_on) return; | 576 if (!is_on) return; |
557 | 577 |
558 heap_profile->IterateAllocationAddresses(visitor, data); | 578 heap_profile->IterateAllocationAddresses(visitor, data); |
559 } | 579 } |
560 | 580 |
(...skipping 108 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
669 | 689 |
670 // class used for finalization -- dumps the heap-profile at program exit | 690 // class used for finalization -- dumps the heap-profile at program exit |
671 struct HeapProfileEndWriter { | 691 struct HeapProfileEndWriter { |
672 ~HeapProfileEndWriter() { HeapProfilerDump("Exiting"); } | 692 ~HeapProfileEndWriter() { HeapProfilerDump("Exiting"); } |
673 }; | 693 }; |
674 | 694 |
675 // We want to make sure tcmalloc is up and running before starting the profiler | 695 // We want to make sure tcmalloc is up and running before starting the profiler |
676 static const TCMallocGuard tcmalloc_initializer; | 696 static const TCMallocGuard tcmalloc_initializer; |
677 REGISTER_MODULE_INITIALIZER(heapprofiler, HeapProfilerInit()); | 697 REGISTER_MODULE_INITIALIZER(heapprofiler, HeapProfilerInit()); |
678 static HeapProfileEndWriter heap_profile_end_writer; | 698 static HeapProfileEndWriter heap_profile_end_writer; |
OLD | NEW |