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_ |