15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2006, Google Inc. 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// All rights reserved. 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Redistribution and use in source and binary forms, with or without 55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// modification, are permitted provided that the following conditions are 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// met: 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// * Redistributions of source code must retain the above copyright 95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// notice, this list of conditions and the following disclaimer. 105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// * Redistributions in binary form must reproduce the above 115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// copyright notice, this list of conditions and the following disclaimer 125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// in the documentation and/or other materials provided with the 135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// distribution. 145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// * Neither the name of Google Inc. nor the names of its 155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// contributors may be used to endorse or promote products derived from 165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// this software without specific prior written permission. 175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// --- 315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Author: Sanjay Ghemawat 325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Maxim Lifantsev (refactoring) 335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifndef BASE_HEAP_PROFILE_TABLE_H_ 365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define BASE_HEAP_PROFILE_TABLE_H_ 375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "addressmap-inl.h" 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/basictypes.h" 405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h" // for RawFD 412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "heap-profile-stats.h" 425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(TYPE_PROFILING) 445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <gperftools/type_profiler_map.h> 455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif // defined(TYPE_PROFILING) 465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Table to maintain a heap profile data inside, 485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// i.e. the set of currently active heap memory allocations. 495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// thread-unsafe and non-reentrant code: 505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// each instance object must be used by one thread 515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// at a time w/o self-recursion. 525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// TODO(maxim): add a unittest for this class. 545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class HeapProfileTable { 555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public: 565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Extension to be used for heap pforile files. 585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static const char kFileExt[]; 595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Longest stack trace we record. 615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static const int kMaxStackDepth = 32; 625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // data types ---------------------------- 645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Profile stats. 662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) typedef HeapProfileStats Stats; 675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Possible marks for MarkCurrentAllocations and MarkUnmarkedAllocations. New 695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // allocations are marked with UNMARKED by default. 705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) enum AllocationMark { 715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) UNMARKED = 0, 725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MARK_ONE, 735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MARK_TWO, 745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MARK_THREE 755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) }; 765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Info we can return about an allocation. 785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) struct AllocInfo { 795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) size_t object_size; // size of the allocation 805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const void* const* call_stack; // call stack that made the allocation call 815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int stack_depth; // depth of call_stack 825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool live; 835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool ignored; 845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) }; 855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Info we return about an allocation context. 875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // An allocation context is a unique caller stack trace 885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // of an allocation operation. 895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) struct AllocContextInfo : public Stats { 905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int stack_depth; // Depth of stack trace 915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const void* const* call_stack; // Stack trace 925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) }; 935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Memory (de)allocator interface we'll use. 955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) typedef void* (*Allocator)(size_t size); 965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) typedef void (*DeAllocator)(void* ptr); 975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // interface --------------------------- 995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) HeapProfileTable(Allocator alloc, DeAllocator dealloc, bool profile_mmap); 1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ~HeapProfileTable(); 1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Collect the stack trace for the function that asked to do the 1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // allocation for passing to RecordAlloc() below. 1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // 1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The stack trace is stored in 'stack'. The stack depth is returned. 1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // 1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // 'skip_count' gives the number of stack frames between this call 1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // and the memory allocation function. 1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static int GetCallerStackTrace(int skip_count, void* stack[kMaxStackDepth]); 1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Record an allocation at 'ptr' of 'bytes' bytes. 'stack_depth' 1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // and 'call_stack' identifying the function that requested the 1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // allocation. They can be generated using GetCallerStackTrace() above. 1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void RecordAlloc(const void* ptr, size_t bytes, 1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int stack_depth, const void* const call_stack[]); 1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Record the deallocation of memory at 'ptr'. 1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void RecordFree(const void* ptr); 1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Return true iff we have recorded an allocation at 'ptr'. 1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If yes, fill *object_size with the allocation byte size. 1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool FindAlloc(const void* ptr, size_t* object_size) const; 1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Same as FindAlloc, but fills all of *info. 1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool FindAllocDetails(const void* ptr, AllocInfo* info) const; 1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Return true iff "ptr" points into a recorded allocation 1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If yes, fill *object_ptr with the actual allocation address 1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // and *object_size with the allocation byte size. 1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // max_size specifies largest currently possible allocation size. 1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool FindInsideAlloc(const void* ptr, size_t max_size, 1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const void** object_ptr, size_t* object_size) const; 1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If "ptr" points to a recorded allocation and it's not marked as live 1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // mark it as live and return true. Else return false. 1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // All allocations start as non-live. 1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool MarkAsLive(const void* ptr); 1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If "ptr" points to a recorded allocation, mark it as "ignored". 1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Ignored objects are treated like other objects, except that they 1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // are skipped in heap checking reports. 1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void MarkAsIgnored(const void* ptr); 1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Mark all currently known allocations with the given AllocationMark. 1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void MarkCurrentAllocations(AllocationMark mark); 1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Mark all unmarked (i.e. marked with AllocationMark::UNMARKED) with the 1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // given mark. 1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void MarkUnmarkedAllocations(AllocationMark mark); 1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Return current total (de)allocation statistics. It doesn't contain 1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // mmap'ed regions. 1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const Stats& total() const { return total_; } 1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Allocation data iteration callback: gets passed object pointer and 1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // fully-filled AllocInfo. 1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) typedef void (*AllocIterator)(const void* ptr, const AllocInfo& info); 1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Iterate over the allocation profile data calling "callback" 1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // for every allocation. 1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void IterateAllocs(AllocIterator callback) const { 1622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) address_map_->Iterate(MapArgsAllocIterator, callback); 1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Callback for iterating through addresses of all allocated objects. Accepts 1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // pointer to user data and object pointer. 1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) typedef void (*AddressIterator)(void* data, const void* ptr); 1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Iterate over the addresses of all allocated objects. 1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void IterateAllocationAddresses(AddressIterator, void* data); 1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Allocation context profile data iteration callback 1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) typedef void (*AllocContextIterator)(const AllocContextInfo& info); 1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Iterate over the allocation context profile data calling "callback" 1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // for every allocation context. Allocation contexts are ordered by the 1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // size of allocated space. 1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void IterateOrderedAllocContexts(AllocContextIterator callback) const; 1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Fill profile data into buffer 'buf' of size 'size' 1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // and return the actual size occupied by the dump in 'buf'. 1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The profile buckets are dumped in the decreasing order 1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // of currently allocated bytes. 1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We do not provision for 0-terminating 'buf'. 1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int FillOrderedProfile(char buf[], int size) const; 1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Cleanup any old profile files matching prefix + ".*" + kFileExt. 1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static void CleanupOldProfiles(const char* prefix); 1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Return a snapshot of the current contents of *this. 1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Caller must call ReleaseSnapshot() on result when no longer needed. 1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The result is only valid while this exists and until 1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // the snapshot is discarded by calling ReleaseSnapshot(). 1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) class Snapshot; 1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Snapshot* TakeSnapshot(); 1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Release a previously taken snapshot. snapshot must not 1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // be used after this call. 1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void ReleaseSnapshot(Snapshot* snapshot); 2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Return a snapshot of every non-live, non-ignored object in *this. 2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If "base" is non-NULL, skip any objects present in "base". 2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // As a side-effect, clears the "live" bit on every live object in *this. 2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Caller must call ReleaseSnapshot() on result when no longer needed. 2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Snapshot* NonLiveSnapshot(Snapshot* base); 2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Dump a list of allocations marked as "live" along with their creation 2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // stack traces and sizes to a file named |file_name|. Together with 2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // MarkCurrentAllocatiosn and MarkUnmarkedAllocations this can be used 2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // to find objects that are created in a certain time span: 2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // 1. Invoke MarkCurrentAllocations(MARK_ONE) to mark the start of the 2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // timespan. 2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // 2. Perform whatever action you suspect allocates memory that is not 2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // correctly freed. 2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // 3. Invoke MarkUnmarkedAllocations(MARK_TWO). 2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // 4. Perform whatever action is supposed to free the memory again. New 2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // allocations are not marked. So all allocations that are marked as 2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // "live" where created during step 2. 2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // 5. Invoke DumpMarkedObjects(MARK_TWO) to get the list of allocations that 2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // were created during step 2, but survived step 4. 2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // 2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Note that this functionality cannot be used if the HeapProfileTable is 2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // used for leak checking (using HeapLeakChecker). 2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void DumpMarkedObjects(AllocationMark mark, const char* file_name); 2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(TYPE_PROFILING) 2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void DumpTypeStatistics(const char* file_name) const; 2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif // defined(TYPE_PROFILING) 2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private: 2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) friend class DeepHeapProfile; 2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // data types ---------------------------- 2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Hash table bucket to hold (de)allocation stats 2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // for a given allocation call stack trace. 2372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) typedef HeapProfileBucket Bucket; 2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Info stored in the address map 2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) struct AllocValue { 2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Access to the stack-trace bucket 2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Bucket* bucket() const { 2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return reinterpret_cast<Bucket*>(bucket_rep & ~uintptr_t(kMask)); 2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // This also does set_live(false). 2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void set_bucket(Bucket* b) { bucket_rep = reinterpret_cast<uintptr_t>(b); } 2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) size_t bytes; // Number of bytes in this allocation 2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Access to the allocation liveness flag (for leak checking) 2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool live() const { return bucket_rep & kLive; } 2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void set_live(bool l) { 2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bucket_rep = (bucket_rep & ~uintptr_t(kLive)) | (l ? kLive : 0); 2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Should this allocation be ignored if it looks like a leak? 2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool ignore() const { return bucket_rep & kIgnore; } 2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void set_ignore(bool r) { 2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bucket_rep = (bucket_rep & ~uintptr_t(kIgnore)) | (r ? kIgnore : 0); 2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) AllocationMark mark() const { 2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return static_cast<AllocationMark>(bucket_rep & uintptr_t(kMask)); 2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void set_mark(AllocationMark mark) { 2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bucket_rep = (bucket_rep & ~uintptr_t(kMask)) | uintptr_t(mark); 2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private: 2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We store a few bits in the bottom bits of bucket_rep. 2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // (Alignment is at least four, so we have at least two bits.) 2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static const int kLive = 1; 2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static const int kIgnore = 2; 2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static const int kMask = kLive | kIgnore; 2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) uintptr_t bucket_rep; 2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) }; 2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // helper for FindInsideAlloc 2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static size_t AllocValueSize(const AllocValue& v) { return v.bytes; } 2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) typedef AddressMap<AllocValue> AllocationMap; 2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Arguments that need to be passed DumpBucketIterator callback below. 2832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) struct BufferArgs { 2842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) BufferArgs(char* buf_arg, int buflen_arg, int bufsize_arg) 2852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) : buf(buf_arg), 2862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) buflen(buflen_arg), 2872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) bufsize(bufsize_arg) { 2882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 2892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) char* buf; 2912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) int buflen; 2922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) int bufsize; 2932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DISALLOW_COPY_AND_ASSIGN(BufferArgs); 2952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) }; 2962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Arguments that need to be passed DumpNonLiveIterator callback below. 2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) struct DumpArgs { 2992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DumpArgs(RawFD fd_arg, Stats* profile_stats_arg) 3002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) : fd(fd_arg), 3012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) profile_stats(profile_stats_arg) { 3022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 3032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) RawFD fd; // file to write to 3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Stats* profile_stats; // stats to update (may be NULL) 3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) }; 3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Arguments that need to be passed DumpMarkedIterator callback below. 3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) struct DumpMarkedArgs { 3102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DumpMarkedArgs(RawFD fd_arg, AllocationMark mark_arg) 3112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) : fd(fd_arg), 3122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) mark(mark_arg) { 3132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 3142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) RawFD fd; // file to write to. 3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) AllocationMark mark; // The mark of the allocations to process. 3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) }; 3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Arguments that need to be passed MarkIterator callback below. 3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) struct MarkArgs { 3212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) MarkArgs(AllocationMark mark_arg, bool mark_all_arg) 3222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) : mark(mark_arg), 3232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) mark_all(mark_all_arg) { 3242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 3252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) AllocationMark mark; // The mark to put on allocations. 3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool mark_all; // True if all allocations should be marked. Otherwise just 3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // mark unmarked allocations. 3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) }; 3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(TYPE_PROFILING) 3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) struct TypeCount { 3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TypeCount(size_t bytes_arg, unsigned int objects_arg) 3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) : bytes(bytes_arg), 3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) objects(objects_arg) { 3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 3382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) size_t bytes; 3392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) unsigned int objects; 3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) }; 3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif // defined(TYPE_PROFILING) 3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) struct AllocationAddressIteratorArgs { 3442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) AllocationAddressIteratorArgs(AddressIterator callback_arg, void* data_arg) 3452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) : callback(callback_arg), 3462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) data(data_arg) { 3472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 3482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) AddressIterator callback; 3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void* data; 3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) }; 3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // helpers ---------------------------- 3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Unparse bucket b and print its portion of profile dump into buf. 3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We return the amount of space in buf that we use. We start printing 3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // at buf + buflen, and promise not to go beyond buf + bufsize. 3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We do not provision for 0-terminating 'buf'. 3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // 3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If profile_stats is non-NULL, we update *profile_stats by 3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // counting bucket b. 3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // 3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // "extra" is appended to the unparsed bucket. Typically it is empty, 3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // but may be set to something like " heapprofile" for the total 3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // bucket to indicate the type of the profile. 3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static int UnparseBucket(const Bucket& b, 3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) char* buf, int buflen, int bufsize, 3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const char* extra, 3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Stats* profile_stats); 3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Get the bucket for the caller stack trace 'key' of depth 'depth' 3722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // creating the bucket if needed. 3732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) Bucket* GetBucket(int depth, const void* const key[]); 3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Helper for IterateAllocs to do callback signature conversion 3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // from AllocationMap::Iterate to AllocIterator. 3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static void MapArgsAllocIterator(const void* ptr, AllocValue* v, 3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) AllocIterator callback) { 3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) AllocInfo info; 3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) info.object_size = v->bytes; 3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) info.call_stack = v->bucket()->stack; 3825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) info.stack_depth = v->bucket()->depth; 3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) info.live = v->live(); 3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) info.ignored = v->ignore(); 3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) callback(ptr, info); 3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Helper to dump a bucket. 3892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) inline static void DumpBucketIterator(const Bucket* bucket, 3902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) BufferArgs* args); 3912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 3925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Helper for IterateAllocationAddresses. 3935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) inline static void AllocationAddressesIterator( 3945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const void* ptr, 3955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) AllocValue* v, 3965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const AllocationAddressIteratorArgs& args); 3975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Helper for MarkCurrentAllocations and MarkUnmarkedAllocations. 3995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) inline static void MarkIterator(const void* ptr, AllocValue* v, 4005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const MarkArgs& args); 4015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Helper for DumpNonLiveProfile to do object-granularity 4035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // heap profile dumping. It gets passed to AllocationMap::Iterate. 4045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) inline static void DumpNonLiveIterator(const void* ptr, AllocValue* v, 4055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const DumpArgs& args); 4065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Helper for DumpMarkedObjects to dump all allocations with a given mark. It 4085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // gets passed to AllocationMap::Iterate. 4095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) inline static void DumpMarkedIterator(const void* ptr, AllocValue* v, 4105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const DumpMarkedArgs& args); 4115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(TYPE_PROFILING) 4135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) inline static void TallyTypesItererator(const void* ptr, 4145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) AllocValue* value, 4155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) AddressMap<TypeCount>* type_size_map); 4165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) inline static void DumpTypesIterator(const void* ptr, 4185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TypeCount* size, 4195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const DumpArgs& args); 4205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif // defined(TYPE_PROFILING) 4215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Helper for IterateOrderedAllocContexts and FillOrderedProfile. 4232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Creates a sorted list of Buckets whose length is num_buckets_. 4245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The caller is responsible for deallocating the returned list. 4255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Bucket** MakeSortedBucketList() const; 4265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Helper for TakeSnapshot. Saves object to snapshot. 4285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static void AddToSnapshot(const void* ptr, AllocValue* v, Snapshot* s); 4295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Arguments passed to AddIfNonLive 4315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) struct AddNonLiveArgs { 4325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Snapshot* dest; 4335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Snapshot* base; 4345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) }; 4355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Helper for NonLiveSnapshot. Adds the object to the destination 4375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // snapshot if it is non-live. 4385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static void AddIfNonLive(const void* ptr, AllocValue* v, 4395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) AddNonLiveArgs* arg); 4405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Write contents of "*allocations" as a heap profile to 4425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // "file_name". "total" must contain the total of all entries in 4435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // "*allocations". 4445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static bool WriteProfile(const char* file_name, 4455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const Bucket& total, 4465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) AllocationMap* allocations); 4475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // data ---------------------------- 4495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Memory (de)allocator that we use. 4515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Allocator alloc_; 4525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DeAllocator dealloc_; 4535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Overall profile stats; we use only the Stats part, 4555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // but make it a Bucket to pass to UnparseBucket. 4565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Bucket total_; 4575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) bool profile_mmap_; 4592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 4605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Bucket hash table for malloc. 4615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We hand-craft one instead of using one of the pre-written 4625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // ones because we do not want to use malloc when operating on the table. 4635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // It is only few lines of code, so no big deal. 4642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) Bucket** bucket_table_; 4652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) int num_buckets_; 4665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Map of all currently allocated objects and mapped regions we know about. 4682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) AllocationMap* address_map_; 4695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DISALLOW_COPY_AND_ASSIGN(HeapProfileTable); 4715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 4725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class HeapProfileTable::Snapshot { 4745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public: 4755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const Stats& total() const { return total_; } 4765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Report anything in this snapshot as a leak. 4785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // May use new/delete for temporary storage. 4795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If should_symbolize is true, will fork (which is not threadsafe) 4805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // to turn addresses into symbol names. Set to false for maximum safety. 4815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Also writes a heap profile to "filename" that contains 4825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // all of the objects in this snapshot. 4835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void ReportLeaks(const char* checker_name, const char* filename, 4845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool should_symbolize); 4855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Report the addresses of all leaked objects. 4875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // May use new/delete for temporary storage. 4885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void ReportIndividualObjects(); 4895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool Empty() const { 4915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return (total_.allocs == 0) && (total_.alloc_size == 0); 4925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private: 4955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) friend class HeapProfileTable; 4965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Total count/size are stored in a Bucket so we can reuse UnparseBucket 4985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Bucket total_; 4995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We share the Buckets managed by the parent table, but have our 5015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // own object->bucket map. 5025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) AllocationMap map_; 5035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Snapshot(Allocator alloc, DeAllocator dealloc) : map_(alloc, dealloc) { 5055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) memset(&total_, 0, sizeof(total_)); 5065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Callback used to populate a Snapshot object with entries found 5095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // in another allocation map. 5105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) inline void Add(const void* ptr, const AllocValue& v) { 5115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) map_.Insert(ptr, v); 5125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) total_.allocs++; 5135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) total_.alloc_size += v.bytes; 5145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Helpers for sorting and generating leak reports 5175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) struct Entry; 5185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) struct ReportState; 5195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static void ReportCallback(const void* ptr, AllocValue* v, ReportState*); 5205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static void ReportObject(const void* ptr, AllocValue* v, char*); 5215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DISALLOW_COPY_AND_ASSIGN(Snapshot); 5235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 5245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif // BASE_HEAP_PROFILE_TABLE_H_ 526