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