memory_region_map.h 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413
  1. // -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
  2. /* Copyright (c) 2006, Google Inc.
  3. * All rights reserved.
  4. *
  5. * Redistribution and use in source and binary forms, with or without
  6. * modification, are permitted provided that the following conditions are
  7. * met:
  8. *
  9. * * Redistributions of source code must retain the above copyright
  10. * notice, this list of conditions and the following disclaimer.
  11. * * Redistributions in binary form must reproduce the above
  12. * copyright notice, this list of conditions and the following disclaimer
  13. * in the documentation and/or other materials provided with the
  14. * distribution.
  15. * * Neither the name of Google Inc. nor the names of its
  16. * contributors may be used to endorse or promote products derived from
  17. * this software without specific prior written permission.
  18. *
  19. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  20. * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  21. * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  22. * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  23. * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  24. * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  25. * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  26. * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  27. * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  28. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  29. * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  30. *
  31. * ---
  32. * Author: Maxim Lifantsev
  33. */
  34. #ifndef BASE_MEMORY_REGION_MAP_H_
  35. #define BASE_MEMORY_REGION_MAP_H_
  36. #include <config.h>
  37. #ifdef HAVE_PTHREAD
  38. #include <pthread.h>
  39. #endif
  40. #include <stddef.h>
  41. #include <set>
  42. #include "base/stl_allocator.h"
  43. #include "base/spinlock.h"
  44. #include "base/thread_annotations.h"
  45. #include "base/low_level_alloc.h"
  46. #include "heap-profile-stats.h"
  47. // TODO(maxim): add a unittest:
  48. // execute a bunch of mmaps and compare memory map what strace logs
  49. // execute a bunch of mmap/munmup and compare memory map with
  50. // own accounting of what those mmaps generated
  51. // Thread-safe class to collect and query the map of all memory regions
  52. // in a process that have been created with mmap, munmap, mremap, sbrk.
  53. // For each memory region, we keep track of (and provide to users)
  54. // the stack trace that allocated that memory region.
  55. // The recorded stack trace depth is bounded by
  56. // a user-supplied max_stack_depth parameter of Init().
  57. // After initialization with Init()
  58. // (which can happened even before global object constructor execution)
  59. // we collect the map by installing and monitoring MallocHook-s
  60. // to mmap, munmap, mremap, sbrk.
  61. // At any time one can query this map via provided interface.
  62. // For more details on the design of MemoryRegionMap
  63. // see the comment at the top of our .cc file.
  64. class MemoryRegionMap {
  65. private:
  66. // Max call stack recording depth supported by Init(). Set it to be
  67. // high enough for all our clients. Note: we do not define storage
  68. // for this (doing that requires special handling in windows), so
  69. // don't take the address of it!
  70. static const int kMaxStackDepth = 32;
  71. // Size of the hash table of buckets. A structure of the bucket table is
  72. // described in heap-profile-stats.h.
  73. static const int kHashTableSize = 179999;
  74. public:
  75. // interface ================================================================
  76. // Every client of MemoryRegionMap must call Init() before first use,
  77. // and Shutdown() after last use. This allows us to reference count
  78. // this (singleton) class properly. MemoryRegionMap assumes it's the
  79. // only client of MallocHooks, so a client can only register other
  80. // MallocHooks after calling Init() and must unregister them before
  81. // calling Shutdown().
  82. // Initialize this module to record memory allocation stack traces.
  83. // Stack traces that have more than "max_stack_depth" frames
  84. // are automatically shrunk to "max_stack_depth" when they are recorded.
  85. // Init() can be called more than once w/o harm, largest max_stack_depth
  86. // will be the effective one.
  87. // When "use_buckets" is true, then counts of mmap and munmap sizes will be
  88. // recorded with each stack trace. If Init() is called more than once, then
  89. // counting will be effective after any call contained "use_buckets" of true.
  90. // It will install mmap, munmap, mremap, sbrk hooks
  91. // and initialize arena_ and our hook and locks, hence one can use
  92. // MemoryRegionMap::Lock()/Unlock() to manage the locks.
  93. // Uses Lock/Unlock inside.
  94. static void Init(int max_stack_depth, bool use_buckets);
  95. // Try to shutdown this module undoing what Init() did.
  96. // Returns true iff could do full shutdown (or it was not attempted).
  97. // Full shutdown is attempted when the number of Shutdown() calls equals
  98. // the number of Init() calls.
  99. static bool Shutdown();
  100. // Return true if MemoryRegionMap is initialized and recording, i.e. when
  101. // then number of Init() calls are more than the number of Shutdown() calls.
  102. static bool IsRecordingLocked();
  103. // Locks to protect our internal data structures.
  104. // These also protect use of arena_ if our Init() has been done.
  105. // The lock is recursive.
  106. static void Lock() EXCLUSIVE_LOCK_FUNCTION(lock_);
  107. static void Unlock() UNLOCK_FUNCTION(lock_);
  108. // Returns true when the lock is held by this thread (for use in RAW_CHECK-s).
  109. static bool LockIsHeld();
  110. // Locker object that acquires the MemoryRegionMap::Lock
  111. // for the duration of its lifetime (a C++ scope).
  112. class LockHolder {
  113. public:
  114. LockHolder() { Lock(); }
  115. ~LockHolder() { Unlock(); }
  116. private:
  117. DISALLOW_COPY_AND_ASSIGN(LockHolder);
  118. };
  119. // A memory region that we know about through malloc_hook-s.
  120. // This is essentially an interface through which MemoryRegionMap
  121. // exports the collected data to its clients. Thread-compatible.
  122. struct Region {
  123. uintptr_t start_addr; // region start address
  124. uintptr_t end_addr; // region end address
  125. int call_stack_depth; // number of caller stack frames that we saved
  126. const void* call_stack[kMaxStackDepth]; // caller address stack array
  127. // filled to call_stack_depth size
  128. bool is_stack; // does this region contain a thread's stack:
  129. // a user of MemoryRegionMap supplies this info
  130. // Convenience accessor for call_stack[0],
  131. // i.e. (the program counter of) the immediate caller
  132. // of this region's allocation function,
  133. // but it also returns NULL when call_stack_depth is 0,
  134. // i.e whe we weren't able to get the call stack.
  135. // This usually happens in recursive calls, when the stack-unwinder
  136. // calls mmap() which in turn calls the stack-unwinder.
  137. uintptr_t caller() const {
  138. return reinterpret_cast<uintptr_t>(call_stack_depth >= 1
  139. ? call_stack[0] : NULL);
  140. }
  141. // Return true iff this region overlaps region x.
  142. bool Overlaps(const Region& x) const {
  143. return start_addr < x.end_addr && end_addr > x.start_addr;
  144. }
  145. private: // helpers for MemoryRegionMap
  146. friend class MemoryRegionMap;
  147. // The ways we create Region-s:
  148. void Create(const void* start, size_t size) {
  149. start_addr = reinterpret_cast<uintptr_t>(start);
  150. end_addr = start_addr + size;
  151. is_stack = false; // not a stack till marked such
  152. call_stack_depth = 0;
  153. AssertIsConsistent();
  154. }
  155. void set_call_stack_depth(int depth) {
  156. RAW_DCHECK(call_stack_depth == 0, ""); // only one such set is allowed
  157. call_stack_depth = depth;
  158. AssertIsConsistent();
  159. }
  160. // The ways we modify Region-s:
  161. void set_is_stack() { is_stack = true; }
  162. void set_start_addr(uintptr_t addr) {
  163. start_addr = addr;
  164. AssertIsConsistent();
  165. }
  166. void set_end_addr(uintptr_t addr) {
  167. end_addr = addr;
  168. AssertIsConsistent();
  169. }
  170. // Verifies that *this contains consistent data, crashes if not the case.
  171. void AssertIsConsistent() const {
  172. RAW_DCHECK(start_addr < end_addr, "");
  173. RAW_DCHECK(call_stack_depth >= 0 &&
  174. call_stack_depth <= kMaxStackDepth, "");
  175. }
  176. // Post-default construction helper to make a Region suitable
  177. // for searching in RegionSet regions_.
  178. void SetRegionSetKey(uintptr_t addr) {
  179. // make sure *this has no usable data:
  180. if (DEBUG_MODE) memset(this, 0xFF, sizeof(*this));
  181. end_addr = addr;
  182. }
  183. // Note: call_stack[kMaxStackDepth] as a member lets us make Region
  184. // a simple self-contained struct with correctly behaving bit-vise copying.
  185. // This simplifies the code of this module but wastes some memory:
  186. // in most-often use case of this module (leak checking)
  187. // only one call_stack element out of kMaxStackDepth is actually needed.
  188. // Making the storage for call_stack variable-sized,
  189. // substantially complicates memory management for the Region-s:
  190. // as they need to be created and manipulated for some time
  191. // w/o any memory allocations, yet are also given out to the users.
  192. };
  193. // Find the region that covers addr and write its data into *result if found,
  194. // in which case *result gets filled so that it stays fully functional
  195. // even when the underlying region gets removed from MemoryRegionMap.
  196. // Returns success. Uses Lock/Unlock inside.
  197. static bool FindRegion(uintptr_t addr, Region* result);
  198. // Find the region that contains stack_top, mark that region as
  199. // a stack region, and write its data into *result if found,
  200. // in which case *result gets filled so that it stays fully functional
  201. // even when the underlying region gets removed from MemoryRegionMap.
  202. // Returns success. Uses Lock/Unlock inside.
  203. static bool FindAndMarkStackRegion(uintptr_t stack_top, Region* result);
  204. // Iterate over the buckets which store mmap and munmap counts per stack
  205. // trace. It calls "callback" for each bucket, and passes "arg" to it.
  206. template<class Type>
  207. static void IterateBuckets(void (*callback)(const HeapProfileBucket*, Type),
  208. Type arg);
  209. // Get the bucket whose caller stack trace is "key". The stack trace is
  210. // used to a depth of "depth" at most. The requested bucket is created if
  211. // needed.
  212. // The bucket table is described in heap-profile-stats.h.
  213. static HeapProfileBucket* GetBucket(int depth, const void* const key[]);
  214. private: // our internal types ==============================================
  215. // Region comparator for sorting with STL
  216. struct RegionCmp {
  217. bool operator()(const Region& x, const Region& y) const {
  218. return x.end_addr < y.end_addr;
  219. }
  220. };
  221. // We allocate STL objects in our own arena.
  222. struct MyAllocator {
  223. static void *Allocate(size_t n) {
  224. return LowLevelAlloc::AllocWithArena(n, arena_);
  225. }
  226. static void Free(const void *p, size_t /* n */) {
  227. LowLevelAlloc::Free(const_cast<void*>(p));
  228. }
  229. };
  230. // Set of the memory regions
  231. typedef std::set<Region, RegionCmp,
  232. STL_Allocator<Region, MyAllocator> > RegionSet;
  233. public: // more in-depth interface ==========================================
  234. // STL iterator with values of Region
  235. typedef RegionSet::const_iterator RegionIterator;
  236. // Return the begin/end iterators to all the regions.
  237. // These need Lock/Unlock protection around their whole usage (loop).
  238. // Even when the same thread causes modifications during such a loop
  239. // (which are permitted due to recursive locking)
  240. // the loop iterator will still be valid as long as its region
  241. // has not been deleted, but EndRegionLocked should be
  242. // re-evaluated whenever the set of regions has changed.
  243. static RegionIterator BeginRegionLocked();
  244. static RegionIterator EndRegionLocked();
  245. // Return the accumulated sizes of mapped and unmapped regions.
  246. static int64 MapSize() { return map_size_; }
  247. static int64 UnmapSize() { return unmap_size_; }
  248. // Effectively private type from our .cc =================================
  249. // public to let us declare global objects:
  250. union RegionSetRep;
  251. private:
  252. // representation ===========================================================
  253. // Counter of clients of this module that have called Init().
  254. static int client_count_;
  255. // Maximal number of caller stack frames to save (>= 0).
  256. static int max_stack_depth_;
  257. // Arena used for our allocations in regions_.
  258. static LowLevelAlloc::Arena* arena_;
  259. // Set of the mmap/sbrk/mremap-ed memory regions
  260. // To be accessed *only* when Lock() is held.
  261. // Hence we protect the non-recursive lock used inside of arena_
  262. // with our recursive Lock(). This lets a user prevent deadlocks
  263. // when threads are stopped by TCMalloc_ListAllProcessThreads at random spots
  264. // simply by acquiring our recursive Lock() before that.
  265. static RegionSet* regions_;
  266. // Lock to protect regions_ and buckets_ variables and the data behind.
  267. static SpinLock lock_;
  268. // Lock to protect the recursive lock itself.
  269. static SpinLock owner_lock_;
  270. // Recursion count for the recursive lock.
  271. static int recursion_count_;
  272. // The thread id of the thread that's inside the recursive lock.
  273. static pthread_t lock_owner_tid_;
  274. // Total size of all mapped pages so far
  275. static int64 map_size_;
  276. // Total size of all unmapped pages so far
  277. static int64 unmap_size_;
  278. // Bucket hash table which is described in heap-profile-stats.h.
  279. static HeapProfileBucket** bucket_table_ GUARDED_BY(lock_);
  280. static int num_buckets_ GUARDED_BY(lock_);
  281. // The following members are local to MemoryRegionMap::GetBucket()
  282. // and MemoryRegionMap::HandleSavedBucketsLocked()
  283. // and are file-level to ensure that they are initialized at load time.
  284. //
  285. // These are used as temporary storage to break the infinite cycle of mmap
  286. // calling our hook which (sometimes) causes mmap. It must be a static
  287. // fixed-size array. The size 20 is just an expected value for safety.
  288. // The details are described in memory_region_map.cc.
  289. // Number of unprocessed bucket inserts.
  290. static int saved_buckets_count_ GUARDED_BY(lock_);
  291. // Unprocessed inserts (must be big enough to hold all mmaps that can be
  292. // caused by a GetBucket call).
  293. // Bucket has no constructor, so that c-tor execution does not interfere
  294. // with the any-time use of the static memory behind saved_buckets.
  295. static HeapProfileBucket saved_buckets_[20] GUARDED_BY(lock_);
  296. static const void* saved_buckets_keys_[20][kMaxStackDepth] GUARDED_BY(lock_);
  297. // helpers ==================================================================
  298. // Helper for FindRegion and FindAndMarkStackRegion:
  299. // returns the region covering 'addr' or NULL; assumes our lock_ is held.
  300. static const Region* DoFindRegionLocked(uintptr_t addr);
  301. // Verifying wrapper around regions_->insert(region)
  302. // To be called to do InsertRegionLocked's work only!
  303. inline static void DoInsertRegionLocked(const Region& region);
  304. // Handle regions saved by InsertRegionLocked into a tmp static array
  305. // by calling insert_func on them.
  306. inline static void HandleSavedRegionsLocked(
  307. void (*insert_func)(const Region& region));
  308. // Restore buckets saved in a tmp static array by GetBucket to the bucket
  309. // table where all buckets eventually should be.
  310. static void RestoreSavedBucketsLocked();
  311. // Wrapper around DoInsertRegionLocked
  312. // that handles the case of recursive allocator calls.
  313. inline static void InsertRegionLocked(const Region& region);
  314. // Record addition of a memory region at address "start" of size "size"
  315. // (called from our mmap/mremap/sbrk hooks).
  316. static void RecordRegionAddition(const void* start, size_t size);
  317. // Record deletion of a memory region at address "start" of size "size"
  318. // (called from our munmap/mremap/sbrk hooks).
  319. static void RecordRegionRemoval(const void* start, size_t size);
  320. // Record deletion of a memory region of size "size" in a bucket whose
  321. // caller stack trace is "key". The stack trace is used to a depth of
  322. // "depth" at most.
  323. static void RecordRegionRemovalInBucket(int depth,
  324. const void* const key[],
  325. size_t size);
  326. // Hooks for MallocHook
  327. static void MmapHook(const void* result,
  328. const void* start, size_t size,
  329. int prot, int flags,
  330. int fd, off_t offset);
  331. static void MunmapHook(const void* ptr, size_t size);
  332. static void MremapHook(const void* result, const void* old_addr,
  333. size_t old_size, size_t new_size, int flags,
  334. const void* new_addr);
  335. static void SbrkHook(const void* result, ptrdiff_t increment);
  336. // Log all memory regions; Useful for debugging only.
  337. // Assumes Lock() is held
  338. static void LogAllLocked();
  339. DISALLOW_COPY_AND_ASSIGN(MemoryRegionMap);
  340. };
  341. template <class Type>
  342. void MemoryRegionMap::IterateBuckets(
  343. void (*callback)(const HeapProfileBucket*, Type), Type callback_arg) {
  344. for (int index = 0; index < kHashTableSize; index++) {
  345. for (HeapProfileBucket* bucket = bucket_table_[index];
  346. bucket != NULL;
  347. bucket = bucket->next) {
  348. callback(bucket, callback_arg);
  349. }
  350. }
  351. }
  352. #endif // BASE_MEMORY_REGION_MAP_H_