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: Maxim Lifantsev 325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifndef BASE_MEMORY_REGION_MAP_H_ 355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define BASE_MEMORY_REGION_MAP_H_ 365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <config.h> 385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifdef HAVE_PTHREAD 405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <pthread.h> 415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <stddef.h> 435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <set> 445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/stl_allocator.h" 455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/spinlock.h" 465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/thread_annotations.h" 475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/low_level_alloc.h" 482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "heap-profile-stats.h" 495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// TODO(maxim): add a unittest: 515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// execute a bunch of mmaps and compare memory map what strace logs 525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// execute a bunch of mmap/munmup and compare memory map with 535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// own accounting of what those mmaps generated 545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Thread-safe class to collect and query the map of all memory regions 565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// in a process that have been created with mmap, munmap, mremap, sbrk. 575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// For each memory region, we keep track of (and provide to users) 585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// the stack trace that allocated that memory region. 595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// The recorded stack trace depth is bounded by 605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// a user-supplied max_stack_depth parameter of Init(). 615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// After initialization with Init() 625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// (which can happened even before global object constructor execution) 635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// we collect the map by installing and monitoring MallocHook-s 645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// to mmap, munmap, mremap, sbrk. 655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// At any time one can query this map via provided interface. 665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// For more details on the design of MemoryRegionMap 675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// see the comment at the top of our .cc file. 685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class MemoryRegionMap { 695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private: 705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Max call stack recording depth supported by Init(). Set it to be 715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // high enough for all our clients. Note: we do not define storage 725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // for this (doing that requires special handling in windows), so 735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // don't take the address of it! 745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static const int kMaxStackDepth = 32; 755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Size of the hash table of buckets. A structure of the bucket table is 772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // described in heap-profile-stats.h. 782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) static const int kHashTableSize = 179999; 792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public: 815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // interface ================================================================ 825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Every client of MemoryRegionMap must call Init() before first use, 845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // and Shutdown() after last use. This allows us to reference count 855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // this (singleton) class properly. MemoryRegionMap assumes it's the 865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // only client of MallocHooks, so a client can only register other 875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // MallocHooks after calling Init() and must unregister them before 885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // calling Shutdown(). 895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Initialize this module to record memory allocation stack traces. 915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Stack traces that have more than "max_stack_depth" frames 925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // are automatically shrunk to "max_stack_depth" when they are recorded. 935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Init() can be called more than once w/o harm, largest max_stack_depth 945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // will be the effective one. 952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // When "use_buckets" is true, then counts of mmap and munmap sizes will be 962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // recorded with each stack trace. If Init() is called more than once, then 972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // counting will be effective after any call contained "use_buckets" of true. 985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // It will install mmap, munmap, mremap, sbrk hooks 995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // and initialize arena_ and our hook and locks, hence one can use 1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // MemoryRegionMap::Lock()/Unlock() to manage the locks. 1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Uses Lock/Unlock inside. 1022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) static void Init(int max_stack_depth, bool use_buckets); 1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Try to shutdown this module undoing what Init() did. 1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Returns true iff could do full shutdown (or it was not attempted). 1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Full shutdown is attempted when the number of Shutdown() calls equals 1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // the number of Init() calls. 1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static bool Shutdown(); 1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Return true if MemoryRegionMap is initialized and recording, i.e. when 1112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // then number of Init() calls are more than the number of Shutdown() calls. 1122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) static bool IsRecordingLocked(); 1132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Locks to protect our internal data structures. 1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // These also protect use of arena_ if our Init() has been done. 1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The lock is recursive. 1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static void Lock() EXCLUSIVE_LOCK_FUNCTION(lock_); 1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static void Unlock() UNLOCK_FUNCTION(lock_); 1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Returns true when the lock is held by this thread (for use in RAW_CHECK-s). 1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static bool LockIsHeld(); 1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Locker object that acquires the MemoryRegionMap::Lock 1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // for the duration of its lifetime (a C++ scope). 1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) class LockHolder { 1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public: 1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LockHolder() { Lock(); } 1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ~LockHolder() { Unlock(); } 1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private: 1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DISALLOW_COPY_AND_ASSIGN(LockHolder); 1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) }; 1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // A memory region that we know about through malloc_hook-s. 1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // This is essentially an interface through which MemoryRegionMap 1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // exports the collected data to its clients. Thread-compatible. 1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) struct Region { 1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) uintptr_t start_addr; // region start address 1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) uintptr_t end_addr; // region end address 1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int call_stack_depth; // number of caller stack frames that we saved 1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const void* call_stack[kMaxStackDepth]; // caller address stack array 1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // filled to call_stack_depth size 1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool is_stack; // does this region contain a thread's stack: 1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // a user of MemoryRegionMap supplies this info 1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Convenience accessor for call_stack[0], 1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // i.e. (the program counter of) the immediate caller 1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // of this region's allocation function, 1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // but it also returns NULL when call_stack_depth is 0, 1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // i.e whe we weren't able to get the call stack. 1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // This usually happens in recursive calls, when the stack-unwinder 1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // calls mmap() which in turn calls the stack-unwinder. 1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) uintptr_t caller() const { 1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return reinterpret_cast<uintptr_t>(call_stack_depth >= 1 1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ? call_stack[0] : NULL); 1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Return true iff this region overlaps region x. 1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool Overlaps(const Region& x) const { 1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return start_addr < x.end_addr && end_addr > x.start_addr; 1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private: // helpers for MemoryRegionMap 1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) friend class MemoryRegionMap; 1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The ways we create Region-s: 1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void Create(const void* start, size_t size) { 1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) start_addr = reinterpret_cast<uintptr_t>(start); 1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) end_addr = start_addr + size; 1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) is_stack = false; // not a stack till marked such 1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) call_stack_depth = 0; 1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) AssertIsConsistent(); 1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void set_call_stack_depth(int depth) { 1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) RAW_DCHECK(call_stack_depth == 0, ""); // only one such set is allowed 1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) call_stack_depth = depth; 1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) AssertIsConsistent(); 1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The ways we modify Region-s: 1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void set_is_stack() { is_stack = true; } 1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void set_start_addr(uintptr_t addr) { 1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) start_addr = addr; 1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) AssertIsConsistent(); 1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void set_end_addr(uintptr_t addr) { 1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) end_addr = addr; 1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) AssertIsConsistent(); 1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Verifies that *this contains consistent data, crashes if not the case. 1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void AssertIsConsistent() const { 1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) RAW_DCHECK(start_addr < end_addr, ""); 1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) RAW_DCHECK(call_stack_depth >= 0 && 1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) call_stack_depth <= kMaxStackDepth, ""); 1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Post-default construction helper to make a Region suitable 1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // for searching in RegionSet regions_. 1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void SetRegionSetKey(uintptr_t addr) { 2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // make sure *this has no usable data: 2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (DEBUG_MODE) memset(this, 0xFF, sizeof(*this)); 2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) end_addr = addr; 2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Note: call_stack[kMaxStackDepth] as a member lets us make Region 2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // a simple self-contained struct with correctly behaving bit-vise copying. 2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // This simplifies the code of this module but wastes some memory: 2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // in most-often use case of this module (leak checking) 2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // only one call_stack element out of kMaxStackDepth is actually needed. 2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Making the storage for call_stack variable-sized, 2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // substantially complicates memory management for the Region-s: 2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // as they need to be created and manipulated for some time 2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // w/o any memory allocations, yet are also given out to the users. 2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) }; 2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Find the region that covers addr and write its data into *result if found, 2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // in which case *result gets filled so that it stays fully functional 2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // even when the underlying region gets removed from MemoryRegionMap. 2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Returns success. Uses Lock/Unlock inside. 2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static bool FindRegion(uintptr_t addr, Region* result); 2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Find the region that contains stack_top, mark that region as 2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // a stack region, and write its data into *result if found, 2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // in which case *result gets filled so that it stays fully functional 2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // even when the underlying region gets removed from MemoryRegionMap. 2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Returns success. Uses Lock/Unlock inside. 2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static bool FindAndMarkStackRegion(uintptr_t stack_top, Region* result); 2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Iterate over the buckets which store mmap and munmap counts per stack 2302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // trace. It calls "callback" for each bucket, and passes "arg" to it. 2312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) template<class Type> 2322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) static void IterateBuckets(void (*callback)(const HeapProfileBucket*, Type), 2332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) Type arg); 2342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Get the bucket whose caller stack trace is "key". The stack trace is 2362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // used to a depth of "depth" at most. The requested bucket is created if 2372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // needed. 2382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // The bucket table is described in heap-profile-stats.h. 2392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) static HeapProfileBucket* GetBucket(int depth, const void* const key[]); 2402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private: // our internal types ============================================== 2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Region comparator for sorting with STL 2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) struct RegionCmp { 2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool operator()(const Region& x, const Region& y) const { 2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return x.end_addr < y.end_addr; 2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) }; 2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We allocate STL objects in our own arena. 2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) struct MyAllocator { 2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static void *Allocate(size_t n) { 2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return LowLevelAlloc::AllocWithArena(n, arena_); 2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static void Free(const void *p, size_t /* n */) { 2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LowLevelAlloc::Free(const_cast<void*>(p)); 2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) }; 2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Set of the memory regions 2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) typedef std::set<Region, RegionCmp, 2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) STL_Allocator<Region, MyAllocator> > RegionSet; 2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public: // more in-depth interface ========================================== 2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // STL iterator with values of Region 2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) typedef RegionSet::const_iterator RegionIterator; 2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Return the begin/end iterators to all the regions. 2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // These need Lock/Unlock protection around their whole usage (loop). 2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Even when the same thread causes modifications during such a loop 2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // (which are permitted due to recursive locking) 2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // the loop iterator will still be valid as long as its region 2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // has not been deleted, but EndRegionLocked should be 2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // re-evaluated whenever the set of regions has changed. 2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static RegionIterator BeginRegionLocked(); 2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static RegionIterator EndRegionLocked(); 2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Return the accumulated sizes of mapped and unmapped regions. 2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static int64 MapSize() { return map_size_; } 2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static int64 UnmapSize() { return unmap_size_; } 2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Effectively private type from our .cc ================================= 2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // public to let us declare global objects: 2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) union RegionSetRep; 2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private: 2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // representation =========================================================== 2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Counter of clients of this module that have called Init(). 2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static int client_count_; 2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Maximal number of caller stack frames to save (>= 0). 2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static int max_stack_depth_; 2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Arena used for our allocations in regions_. 2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static LowLevelAlloc::Arena* arena_; 2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Set of the mmap/sbrk/mremap-ed memory regions 3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // To be accessed *only* when Lock() is held. 3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Hence we protect the non-recursive lock used inside of arena_ 3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // with our recursive Lock(). This lets a user prevent deadlocks 3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // when threads are stopped by ListAllProcessThreads at random spots 3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // simply by acquiring our recursive Lock() before that. 3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static RegionSet* regions_; 3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Lock to protect regions_ and buckets_ variables and the data behind. 3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static SpinLock lock_; 3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Lock to protect the recursive lock itself. 3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static SpinLock owner_lock_; 3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Recursion count for the recursive lock. 3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static int recursion_count_; 3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The thread id of the thread that's inside the recursive lock. 3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static pthread_t lock_owner_tid_; 3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Total size of all mapped pages so far 3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static int64 map_size_; 3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Total size of all unmapped pages so far 3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static int64 unmap_size_; 3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Bucket hash table which is described in heap-profile-stats.h. 3232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) static HeapProfileBucket** bucket_table_ GUARDED_BY(lock_); 3242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) static int num_buckets_ GUARDED_BY(lock_); 3252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 3262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // The following members are local to MemoryRegionMap::GetBucket() 3272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // and MemoryRegionMap::HandleSavedBucketsLocked() 3282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // and are file-level to ensure that they are initialized at load time. 3292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // 3302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // These are used as temporary storage to break the infinite cycle of mmap 3312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // calling our hook which (sometimes) causes mmap. It must be a static 3322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // fixed-size array. The size 20 is just an expected value for safety. 3332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // The details are described in memory_region_map.cc. 3342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 3352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Number of unprocessed bucket inserts. 3362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) static int saved_buckets_count_ GUARDED_BY(lock_); 3372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 3382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Unprocessed inserts (must be big enough to hold all mmaps that can be 3392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // caused by a GetBucket call). 3402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Bucket has no constructor, so that c-tor execution does not interfere 3412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // with the any-time use of the static memory behind saved_buckets. 3422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) static HeapProfileBucket saved_buckets_[20] GUARDED_BY(lock_); 3432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 3442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) static const void* saved_buckets_keys_[20][kMaxStackDepth] GUARDED_BY(lock_); 3452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // helpers ================================================================== 3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Helper for FindRegion and FindAndMarkStackRegion: 3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // returns the region covering 'addr' or NULL; assumes our lock_ is held. 3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static const Region* DoFindRegionLocked(uintptr_t addr); 3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Verifying wrapper around regions_->insert(region) 3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // To be called to do InsertRegionLocked's work only! 3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) inline static void DoInsertRegionLocked(const Region& region); 3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Handle regions saved by InsertRegionLocked into a tmp static array 3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // by calling insert_func on them. 3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) inline static void HandleSavedRegionsLocked( 3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void (*insert_func)(const Region& region)); 3592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 3602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Restore buckets saved in a tmp static array by GetBucket to the bucket 3612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // table where all buckets eventually should be. 3622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) static void RestoreSavedBucketsLocked(); 3632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 364b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) // Initialize RegionSet regions_. 365b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) inline static void InitRegionSetLocked(); 366b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Wrapper around DoInsertRegionLocked 3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // that handles the case of recursive allocator calls. 3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) inline static void InsertRegionLocked(const Region& region); 3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Record addition of a memory region at address "start" of size "size" 3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // (called from our mmap/mremap/sbrk hooks). 3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static void RecordRegionAddition(const void* start, size_t size); 3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Record deletion of a memory region at address "start" of size "size" 3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // (called from our munmap/mremap/sbrk hooks). 3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static void RecordRegionRemoval(const void* start, size_t size); 3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Record deletion of a memory region of size "size" in a bucket whose 3792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // caller stack trace is "key". The stack trace is used to a depth of 3802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // "depth" at most. 3812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) static void RecordRegionRemovalInBucket(int depth, 3822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const void* const key[], 3832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) size_t size); 3842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Hooks for MallocHook 3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static void MmapHook(const void* result, 3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const void* start, size_t size, 3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int prot, int flags, 3895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int fd, off_t offset); 3905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static void MunmapHook(const void* ptr, size_t size); 3915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static void MremapHook(const void* result, const void* old_addr, 3925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) size_t old_size, size_t new_size, int flags, 3935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const void* new_addr); 3945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static void SbrkHook(const void* result, ptrdiff_t increment); 3955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Log all memory regions; Useful for debugging only. 3975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Assumes Lock() is held 3985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static void LogAllLocked(); 3995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DISALLOW_COPY_AND_ASSIGN(MemoryRegionMap); 4015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)template <class Type> 4042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void MemoryRegionMap::IterateBuckets( 4052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) void (*callback)(const HeapProfileBucket*, Type), Type callback_arg) { 4062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) for (int index = 0; index < kHashTableSize; index++) { 4072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) for (HeapProfileBucket* bucket = bucket_table_[index]; 4082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) bucket != NULL; 4092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) bucket = bucket->next) { 4102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) callback(bucket, callback_arg); 4112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 4122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 4132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 4142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 4155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif // BASE_MEMORY_REGION_MAP_H_ 416