| Index: third_party/tcmalloc/chromium/src/memory_region_map.h
 | 
| diff --git a/third_party/tcmalloc/chromium/src/memory_region_map.h b/third_party/tcmalloc/chromium/src/memory_region_map.h
 | 
| index 988ea707375aed124136fe0bb7db105dbb2952a7..be191a90c168364a19b39ead9495b143420e4c67 100644
 | 
| --- a/third_party/tcmalloc/chromium/src/memory_region_map.h
 | 
| +++ b/third_party/tcmalloc/chromium/src/memory_region_map.h
 | 
| @@ -45,6 +45,7 @@
 | 
|  #include "base/spinlock.h"
 | 
|  #include "base/thread_annotations.h"
 | 
|  #include "base/low_level_alloc.h"
 | 
| +#include "heap-profile-stats.h"
 | 
|  
 | 
|  // TODO(maxim): add a unittest:
 | 
|  //  execute a bunch of mmaps and compare memory map what strace logs
 | 
| @@ -72,6 +73,10 @@ class MemoryRegionMap {
 | 
|    // don't take the address of it!
 | 
|    static const int kMaxStackDepth = 32;
 | 
|  
 | 
| +  // Size of the hash table of buckets.  A structure of the bucket table is
 | 
| +  // described in heap-profile-stats.h.
 | 
| +  static const int kHashTableSize = 179999;
 | 
| +
 | 
|   public:
 | 
|    // interface ================================================================
 | 
|  
 | 
| @@ -87,11 +92,14 @@ class MemoryRegionMap {
 | 
|    // are automatically shrunk to "max_stack_depth" when they are recorded.
 | 
|    // Init() can be called more than once w/o harm, largest max_stack_depth
 | 
|    // will be the effective one.
 | 
| +  // When "use_buckets" is true, then counts of mmap and munmap sizes will be
 | 
| +  // recorded with each stack trace.  If Init() is called more than once, then
 | 
| +  // counting will be effective after any call contained "use_buckets" of true.
 | 
|    // It will install mmap, munmap, mremap, sbrk hooks
 | 
|    // and initialize arena_ and our hook and locks, hence one can use
 | 
|    // MemoryRegionMap::Lock()/Unlock() to manage the locks.
 | 
|    // Uses Lock/Unlock inside.
 | 
| -  static void Init(int max_stack_depth);
 | 
| +  static void Init(int max_stack_depth, bool use_buckets);
 | 
|  
 | 
|    // Try to shutdown this module undoing what Init() did.
 | 
|    // Returns true iff could do full shutdown (or it was not attempted).
 | 
| @@ -99,6 +107,10 @@ class MemoryRegionMap {
 | 
|    // the number of Init() calls.
 | 
|    static bool Shutdown();
 | 
|  
 | 
| +  // Return true if MemoryRegionMap is initialized and recording, i.e. when
 | 
| +  // then number of Init() calls are more than the number of Shutdown() calls.
 | 
| +  static bool IsRecordingLocked();
 | 
| +
 | 
|    // Locks to protect our internal data structures.
 | 
|    // These also protect use of arena_ if our Init() has been done.
 | 
|    // The lock is recursive.
 | 
| @@ -214,6 +226,18 @@ class MemoryRegionMap {
 | 
|    // Returns success. Uses Lock/Unlock inside.
 | 
|    static bool FindAndMarkStackRegion(uintptr_t stack_top, Region* result);
 | 
|  
 | 
| +  // Iterate over the buckets which store mmap and munmap counts per stack
 | 
| +  // trace.  It calls "callback" for each bucket, and passes "arg" to it.
 | 
| +  template<class Type>
 | 
| +  static void IterateBuckets(void (*callback)(const HeapProfileBucket*, Type),
 | 
| +                             Type arg);
 | 
| +
 | 
| +  // Get the bucket whose caller stack trace is "key".  The stack trace is
 | 
| +  // used to a depth of "depth" at most.  The requested bucket is created if
 | 
| +  // needed.
 | 
| +  // The bucket table is described in heap-profile-stats.h.
 | 
| +  static HeapProfileBucket* GetBucket(int depth, const void* const key[]);
 | 
| +
 | 
|   private:  // our internal types ==============================================
 | 
|  
 | 
|    // Region comparator for sorting with STL
 | 
| @@ -280,7 +304,7 @@ class MemoryRegionMap {
 | 
|    // simply by acquiring our recursive Lock() before that.
 | 
|    static RegionSet* regions_;
 | 
|  
 | 
| -  // Lock to protect regions_ variable and the data behind.
 | 
| +  // Lock to protect regions_ and buckets_ variables and the data behind.
 | 
|    static SpinLock lock_;
 | 
|    // Lock to protect the recursive lock itself.
 | 
|    static SpinLock owner_lock_;
 | 
| @@ -295,6 +319,30 @@ class MemoryRegionMap {
 | 
|    // Total size of all unmapped pages so far
 | 
|    static int64 unmap_size_;
 | 
|  
 | 
| +  // Bucket hash table which is described in heap-profile-stats.h.
 | 
| +  static HeapProfileBucket** bucket_table_ GUARDED_BY(lock_);
 | 
| +  static int num_buckets_ GUARDED_BY(lock_);
 | 
| +
 | 
| +  // The following members are local to MemoryRegionMap::GetBucket()
 | 
| +  // and MemoryRegionMap::HandleSavedBucketsLocked()
 | 
| +  // and are file-level to ensure that they are initialized at load time.
 | 
| +  //
 | 
| +  // These are used as temporary storage to break the infinite cycle of mmap
 | 
| +  // calling our hook which (sometimes) causes mmap.  It must be a static
 | 
| +  // fixed-size array.  The size 20 is just an expected value for safety.
 | 
| +  // The details are described in memory_region_map.cc.
 | 
| +
 | 
| +  // Number of unprocessed bucket inserts.
 | 
| +  static int saved_buckets_count_ GUARDED_BY(lock_);
 | 
| +
 | 
| +  // Unprocessed inserts (must be big enough to hold all mmaps that can be
 | 
| +  // caused by a GetBucket call).
 | 
| +  // Bucket has no constructor, so that c-tor execution does not interfere
 | 
| +  // with the any-time use of the static memory behind saved_buckets.
 | 
| +  static HeapProfileBucket saved_buckets_[20] GUARDED_BY(lock_);
 | 
| +
 | 
| +  static const void* saved_buckets_keys_[20][kMaxStackDepth] GUARDED_BY(lock_);
 | 
| +
 | 
|    // helpers ==================================================================
 | 
|  
 | 
|    // Helper for FindRegion and FindAndMarkStackRegion:
 | 
| @@ -308,6 +356,11 @@ class MemoryRegionMap {
 | 
|    // by calling insert_func on them.
 | 
|    inline static void HandleSavedRegionsLocked(
 | 
|                         void (*insert_func)(const Region& region));
 | 
| +
 | 
| +  // Restore buckets saved in a tmp static array by GetBucket to the bucket
 | 
| +  // table where all buckets eventually should be.
 | 
| +  static void RestoreSavedBucketsLocked();
 | 
| +
 | 
|    // Wrapper around DoInsertRegionLocked
 | 
|    // that handles the case of recursive allocator calls.
 | 
|    inline static void InsertRegionLocked(const Region& region);
 | 
| @@ -319,6 +372,13 @@ class MemoryRegionMap {
 | 
|    // (called from our munmap/mremap/sbrk hooks).
 | 
|    static void RecordRegionRemoval(const void* start, size_t size);
 | 
|  
 | 
| +  // Record deletion of a memory region of size "size" in a bucket whose
 | 
| +  // caller stack trace is "key".  The stack trace is used to a depth of
 | 
| +  // "depth" at most.
 | 
| +  static void RecordRegionRemovalInBucket(int depth,
 | 
| +                                          const void* const key[],
 | 
| +                                          size_t size);
 | 
| +
 | 
|    // Hooks for MallocHook
 | 
|    static void MmapHook(const void* result,
 | 
|                         const void* start, size_t size,
 | 
| @@ -337,4 +397,16 @@ class MemoryRegionMap {
 | 
|    DISALLOW_COPY_AND_ASSIGN(MemoryRegionMap);
 | 
|  };
 | 
|  
 | 
| +template <class Type>
 | 
| +void MemoryRegionMap::IterateBuckets(
 | 
| +    void (*callback)(const HeapProfileBucket*, Type), Type callback_arg) {
 | 
| +  for (int index = 0; index < kHashTableSize; index++) {
 | 
| +    for (HeapProfileBucket* bucket = bucket_table_[index];
 | 
| +         bucket != NULL;
 | 
| +         bucket = bucket->next) {
 | 
| +      callback(bucket, callback_arg);
 | 
| +    }
 | 
| +  }
 | 
| +}
 | 
| +
 | 
|  #endif  // BASE_MEMORY_REGION_MAP_H_
 | 
| 
 |