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
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Table to maintain a heap profile data inside,
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// i.e. the set of currently active heap memory allocations.
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// thread-unsafe and non-reentrant code:
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// each instance object must be used by one thread
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// at a time w/o self-recursion.
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// TODO(maxim): add a unittest for this class.
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class HeapProfileTable {
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Extension to be used for heap pforile files.
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static const char kFileExt[];
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Longest stack trace we record.
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static const int kMaxStackDepth = 32;
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // data types ----------------------------
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Profile stats.
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  struct Stats {
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int32 allocs;      // Number of allocation calls
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int32 frees;       // Number of free calls
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int64 alloc_size;  // Total size of all allocated objects so far
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int64 free_size;   // Total size of all freed objects so far
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // semantic equality
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bool Equivalent(const Stats& x) const {
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return allocs - frees == x.allocs - x.frees  &&
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)             alloc_size - free_size == x.alloc_size - x.free_size;
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  };
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Info we can return about an allocation.
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  struct AllocInfo {
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    size_t object_size;  // size of the allocation
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const void* const* call_stack;  // call stack that made the allocation call
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int stack_depth;  // depth of call_stack
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bool live;
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bool ignored;
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  };
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Info we return about an allocation context.
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // An allocation context is a unique caller stack trace
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // of an allocation operation.
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  struct AllocContextInfo : public Stats {
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int stack_depth;                // Depth of stack trace
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const void* const* call_stack;  // Stack trace
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  };
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Memory (de)allocator interface we'll use.
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  typedef void* (*Allocator)(size_t size);
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  typedef void  (*DeAllocator)(void* ptr);
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // interface ---------------------------
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  HeapProfileTable(Allocator alloc, DeAllocator dealloc);
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ~HeapProfileTable();
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Collect the stack trace for the function that asked to do the
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // allocation for passing to RecordAlloc() below.
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The stack trace is stored in 'stack'. The stack depth is returned.
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // 'skip_count' gives the number of stack frames between this call
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // and the memory allocation function.
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static int GetCallerStackTrace(int skip_count, void* stack[kMaxStackDepth]);
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Record an allocation at 'ptr' of 'bytes' bytes.  'stack_depth'
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // and 'call_stack' identifying the function that requested the
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // allocation. They can be generated using GetCallerStackTrace() above.
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void RecordAlloc(const void* ptr, size_t bytes,
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   int stack_depth, const void* const call_stack[]);
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Record the deallocation of memory at 'ptr'.
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void RecordFree(const void* ptr);
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Return true iff we have recorded an allocation at 'ptr'.
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If yes, fill *object_size with the allocation byte size.
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool FindAlloc(const void* ptr, size_t* object_size) const;
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Same as FindAlloc, but fills all of *info.
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool FindAllocDetails(const void* ptr, AllocInfo* info) const;
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Return true iff "ptr" points into a recorded allocation
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If yes, fill *object_ptr with the actual allocation address
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // and *object_size with the allocation byte size.
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // max_size specifies largest currently possible allocation size.
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool FindInsideAlloc(const void* ptr, size_t max_size,
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                       const void** object_ptr, size_t* object_size) const;
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If "ptr" points to a recorded allocation and it's not marked as live
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // mark it as live and return true. Else return false.
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // All allocations start as non-live.
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool MarkAsLive(const void* ptr);
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If "ptr" points to a recorded allocation, mark it as "ignored".
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Ignored objects are treated like other objects, except that they
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // are skipped in heap checking reports.
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void MarkAsIgnored(const void* ptr);
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Return current total (de)allocation statistics.  It doesn't contain
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // mmap'ed regions.
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const Stats& total() const { return total_; }
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Allocation data iteration callback: gets passed object pointer and
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // fully-filled AllocInfo.
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  typedef void (*AllocIterator)(const void* ptr, const AllocInfo& info);
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Iterate over the allocation profile data calling "callback"
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // for every allocation.
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void IterateAllocs(AllocIterator callback) const {
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    alloc_address_map_->Iterate(MapArgsAllocIterator, callback);
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Allocation context profile data iteration callback
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  typedef void (*AllocContextIterator)(const AllocContextInfo& info);
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Iterate over the allocation context profile data calling "callback"
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // for every allocation context. Allocation contexts are ordered by the
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // size of allocated space.
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void IterateOrderedAllocContexts(AllocContextIterator callback) const;
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Fill profile data into buffer 'buf' of size 'size'
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // and return the actual size occupied by the dump in 'buf'.
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The profile buckets are dumped in the decreasing order
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // of currently allocated bytes.
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We do not provision for 0-terminating 'buf'.
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int FillOrderedProfile(char buf[], int size) const;
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Cleanup any old profile files matching prefix + ".*" + kFileExt.
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static void CleanupOldProfiles(const char* prefix);
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Return a snapshot of the current contents of *this.
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Caller must call ReleaseSnapshot() on result when no longer needed.
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The result is only valid while this exists and until
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // the snapshot is discarded by calling ReleaseSnapshot().
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  class Snapshot;
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Snapshot* TakeSnapshot();
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Release a previously taken snapshot.  snapshot must not
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // be used after this call.
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void ReleaseSnapshot(Snapshot* snapshot);
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Return a snapshot of every non-live, non-ignored object in *this.
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If "base" is non-NULL, skip any objects present in "base".
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // As a side-effect, clears the "live" bit on every live object in *this.
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Caller must call ReleaseSnapshot() on result when no longer needed.
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Snapshot* NonLiveSnapshot(Snapshot* base);
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Refresh the internal mmap information from MemoryRegionMap.  Results of
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // FillOrderedProfile and IterateOrderedAllocContexts will contain mmap'ed
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // memory regions as at calling RefreshMMapData.
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void RefreshMMapData();
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Clear the internal mmap information.  Results of FillOrderedProfile and
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // IterateOrderedAllocContexts won't contain mmap'ed memory regions after
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // calling ClearMMapData.
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void ClearMMapData();
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private:
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // data types ----------------------------
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Hash table bucket to hold (de)allocation stats
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // for a given allocation call stack trace.
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  struct Bucket : public Stats {
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    uintptr_t    hash;   // Hash value of the stack trace
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int          depth;  // Depth of stack trace
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const void** stack;  // Stack trace
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Bucket*      next;   // Next entry in hash-table
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  };
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Info stored in the address map
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  struct AllocValue {
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Access to the stack-trace bucket
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Bucket* bucket() const {
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return reinterpret_cast<Bucket*>(bucket_rep & ~uintptr_t(kMask));
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // This also does set_live(false).
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    void set_bucket(Bucket* b) { bucket_rep = reinterpret_cast<uintptr_t>(b); }
2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    size_t  bytes;   // Number of bytes in this allocation
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Access to the allocation liveness flag (for leak checking)
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bool live() const { return bucket_rep & kLive; }
2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    void set_live(bool l) {
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      bucket_rep = (bucket_rep & ~uintptr_t(kLive)) | (l ? kLive : 0);
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Should this allocation be ignored if it looks like a leak?
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bool ignore() const { return bucket_rep & kIgnore; }
2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    void set_ignore(bool r) {
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      bucket_rep = (bucket_rep & ~uintptr_t(kIgnore)) | (r ? kIgnore : 0);
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   private:
2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // We store a few bits in the bottom bits of bucket_rep.
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // (Alignment is at least four, so we have at least two bits.)
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    static const int kLive = 1;
2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    static const int kIgnore = 2;
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    static const int kMask = kLive | kIgnore;
2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    uintptr_t bucket_rep;
2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  };
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // helper for FindInsideAlloc
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static size_t AllocValueSize(const AllocValue& v) { return v.bytes; }
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  typedef AddressMap<AllocValue> AllocationMap;
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Arguments that need to be passed DumpNonLiveIterator callback below.
2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  struct DumpArgs {
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    RawFD fd;  // file to write to
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Stats* profile_stats;  // stats to update (may be NULL)
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DumpArgs(RawFD a, Stats* d)
2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      : fd(a), profile_stats(d) { }
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  };
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // helpers ----------------------------
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Unparse bucket b and print its portion of profile dump into buf.
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We return the amount of space in buf that we use.  We start printing
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // at buf + buflen, and promise not to go beyond buf + bufsize.
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We do not provision for 0-terminating 'buf'.
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If profile_stats is non-NULL, we update *profile_stats by
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // counting bucket b.
2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //
2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // "extra" is appended to the unparsed bucket.  Typically it is empty,
2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // but may be set to something like " heapprofile" for the total
2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // bucket to indicate the type of the profile.
2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static int UnparseBucket(const Bucket& b,
2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           char* buf, int buflen, int bufsize,
2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           const char* extra,
2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           Stats* profile_stats);
2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Deallocate a given allocation map.
2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void DeallocateAllocationMap(AllocationMap* allocation);
2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Deallocate a given bucket table.
2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void DeallocateBucketTable(Bucket** table);
2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Get the bucket for the caller stack trace 'key' of depth 'depth' from a
2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // bucket hash map 'table' creating the bucket if needed.  '*bucket_count'
2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // is incremented both when 'bucket_count' is not NULL and when a new
2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // bucket object is created.
2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Bucket* GetBucket(int depth, const void* const key[], Bucket** table,
2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    int* bucket_count);
2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Helper for IterateAllocs to do callback signature conversion
2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // from AllocationMap::Iterate to AllocIterator.
2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static void MapArgsAllocIterator(const void* ptr, AllocValue* v,
2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                   AllocIterator callback) {
2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    AllocInfo info;
2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    info.object_size = v->bytes;
2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    info.call_stack = v->bucket()->stack;
2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    info.stack_depth = v->bucket()->depth;
2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    info.live = v->live();
2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    info.ignored = v->ignore();
3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    callback(ptr, info);
3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Helper for DumpNonLiveProfile to do object-granularity
3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // heap profile dumping. It gets passed to AllocationMap::Iterate.
3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  inline static void DumpNonLiveIterator(const void* ptr, AllocValue* v,
3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                         const DumpArgs& args);
3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Helper for filling size variables in buckets by zero.
3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  inline static void ZeroBucketCountsIterator(
3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      const void* ptr, AllocValue* v, HeapProfileTable* heap_profile);
3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Helper for IterateOrderedAllocContexts and FillOrderedProfile.
3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Creates a sorted list of Buckets whose length is num_alloc_buckets_ +
3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // num_avaliable_mmap_buckets_.
3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The caller is responsible for deallocating the returned list.
3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Bucket** MakeSortedBucketList() const;
3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Helper for TakeSnapshot.  Saves object to snapshot.
3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static void AddToSnapshot(const void* ptr, AllocValue* v, Snapshot* s);
3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Arguments passed to AddIfNonLive
3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  struct AddNonLiveArgs {
3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Snapshot* dest;
3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Snapshot* base;
3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  };
3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Helper for NonLiveSnapshot.  Adds the object to the destination
3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // snapshot if it is non-live.
3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static void AddIfNonLive(const void* ptr, AllocValue* v,
3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           AddNonLiveArgs* arg);
3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Write contents of "*allocations" as a heap profile to
3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // "file_name".  "total" must contain the total of all entries in
3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // "*allocations".
3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static bool WriteProfile(const char* file_name,
3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           const Bucket& total,
3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           AllocationMap* allocations);
3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // data ----------------------------
3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Memory (de)allocator that we use.
3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Allocator alloc_;
3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DeAllocator dealloc_;
3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Overall profile stats; we use only the Stats part,
3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // but make it a Bucket to pass to UnparseBucket.
3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // It doesn't contain mmap'ed regions.
3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Bucket total_;
3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Bucket hash table for malloc.
3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We hand-craft one instead of using one of the pre-written
3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // ones because we do not want to use malloc when operating on the table.
3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // It is only few lines of code, so no big deal.
3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Bucket** alloc_table_;
3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int num_alloc_buckets_;
3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Bucket hash table for mmap.
3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // This table is filled with the information from MemoryRegionMap by calling
3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // RefreshMMapData.
3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Bucket** mmap_table_;
3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int num_available_mmap_buckets_;
3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Map of all currently allocated objects and mapped regions we know about.
3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  AllocationMap* alloc_address_map_;
3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  AllocationMap* mmap_address_map_;
3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(HeapProfileTable);
3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class HeapProfileTable::Snapshot {
3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const Stats& total() const { return total_; }
3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Report anything in this snapshot as a leak.
3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // May use new/delete for temporary storage.
3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If should_symbolize is true, will fork (which is not threadsafe)
3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // to turn addresses into symbol names.  Set to false for maximum safety.
3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Also writes a heap profile to "filename" that contains
3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // all of the objects in this snapshot.
3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void ReportLeaks(const char* checker_name, const char* filename,
3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   bool should_symbolize);
3825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Report the addresses of all leaked objects.
3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // May use new/delete for temporary storage.
3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void ReportIndividualObjects();
3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool Empty() const {
3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return (total_.allocs == 0) && (total_.alloc_size == 0);
3895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private:
3925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  friend class HeapProfileTable;
3935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Total count/size are stored in a Bucket so we can reuse UnparseBucket
3955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Bucket total_;
3965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We share the Buckets managed by the parent table, but have our
3985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // own object->bucket map.
3995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  AllocationMap map_;
4005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Snapshot(Allocator alloc, DeAllocator dealloc) : map_(alloc, dealloc) {
4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    memset(&total_, 0, sizeof(total_));
4035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Callback used to populate a Snapshot object with entries found
4065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // in another allocation map.
4075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  inline void Add(const void* ptr, const AllocValue& v) {
4085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    map_.Insert(ptr, v);
4095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    total_.allocs++;
4105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    total_.alloc_size += v.bytes;
4115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Helpers for sorting and generating leak reports
4145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  struct Entry;
4155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  struct ReportState;
4165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static void ReportCallback(const void* ptr, AllocValue* v, ReportState*);
4175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static void ReportObject(const void* ptr, AllocValue* v, char*);
4185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(Snapshot);
4205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
4215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif  // BASE_HEAP_PROFILE_TABLE_H_
423