Index: runtime/vm/malloc_hooks.cc |
diff --git a/runtime/vm/malloc_hooks.cc b/runtime/vm/malloc_hooks.cc |
index 849f8d5d56928ed4bb812cf0128808426c730578..ef7137e5db25c451e6f6c92640aee663cfb00648 100644 |
--- a/runtime/vm/malloc_hooks.cc |
+++ b/runtime/vm/malloc_hooks.cc |
@@ -13,9 +13,69 @@ |
#include "platform/assert.h" |
#include "vm/hash_map.h" |
#include "vm/lockers.h" |
+#include "vm/profiler.h" |
namespace dart { |
+class AddressMap; |
+ |
+// MallocHooksState contains all of the state related to the configuration of |
+// the malloc hooks, allocation information, and locks. |
+class MallocHooksState : public AllStatic { |
+ public: |
+ static void RecordAllocHook(const void* ptr, size_t size); |
+ static void RecordFreeHook(const void* ptr); |
+ |
+ static bool initialized() { return initialized_; } |
+ static void Init(); |
+ |
+ static bool stack_trace_collection_enabled() { |
+ return OSThread::DoesCurrentThreadExist(); |
+ } |
+ |
+ static bool IsOriginalProcess() { |
+ ASSERT(original_pid_ != kInvalidPid); |
+ return original_pid_ == OS::ProcessId(); |
+ } |
+ |
+ static Mutex* malloc_hook_mutex() { return malloc_hook_mutex_; } |
+ |
+ static intptr_t allocation_count() { return allocation_count_; } |
+ |
+ static intptr_t heap_allocated_memory_in_bytes() { |
+ return heap_allocated_memory_in_bytes_; |
+ } |
+ |
+ static void IncrementHeapAllocatedMemoryInBytes(intptr_t size) { |
+ ASSERT(size >= 0); |
+ heap_allocated_memory_in_bytes_ += size; |
+ ++allocation_count_; |
+ } |
+ |
+ static void DecrementHeapAllocatedMemoryInBytes(intptr_t size) { |
+ ASSERT(size >= 0); |
+ ASSERT(heap_allocated_memory_in_bytes_ >= size); |
+ heap_allocated_memory_in_bytes_ -= size; |
+ --allocation_count_; |
+ ASSERT(allocation_count_ >= 0); |
+ } |
+ |
+ static AddressMap* address_map() { return address_map_; } |
+ |
+ static void ResetStats(); |
+ static void TearDown(); |
+ |
+ private: |
+ static bool initialized_; |
+ static intptr_t original_pid_; |
+ static Mutex* malloc_hook_mutex_; |
+ static intptr_t allocation_count_; |
+ static intptr_t heap_allocated_memory_in_bytes_; |
+ static AddressMap* address_map_; |
+ |
+ static const intptr_t kInvalidPid = -1; |
+}; |
+ |
// A locker-type class to automatically grab and release the |
// in_malloc_hook_flag_. |
class MallocHookScope { |
@@ -27,7 +87,6 @@ class MallocHookScope { |
} |
static void DestroyMallocHookFlag() { |
- ASSERT(in_malloc_hook_flag_ != kUnsetThreadLocalKey); |
OSThread::DeleteThreadLocal(in_malloc_hook_flag_); |
in_malloc_hook_flag_ = kUnsetThreadLocalKey; |
} |
@@ -54,18 +113,41 @@ class MallocHookScope { |
DISALLOW_COPY_AND_ASSIGN(MallocHookScope); |
}; |
+// AllocationInfo contains all information related to a given allocation |
+// including: |
+// -Allocation size in bytes |
+// -Stack trace corresponding to the location of allocation, if applicable |
+class AllocationInfo { |
+ public: |
+ explicit AllocationInfo(intptr_t allocation_size) |
+ : sample_(NULL), allocation_size_(allocation_size) { |
+ // Stack trace collection is disabled when we are in the process of creating |
+ // the first OSThread in order to prevent deadlocks. |
+ if (OSThread::DoesCurrentThreadExist()) { |
+ sample_ = Profiler::NativeSampleAllocation(); |
Cutch
2017/02/08 00:28:53
Naming nit:
This should be SampleNativeAllocation
bkonyi
2017/02/08 01:37:05
Done.
|
+ } |
+ } |
+ |
+ Sample* sample() const { return sample_; } |
+ intptr_t allocation_size() const { return allocation_size_; } |
+ |
+ private: |
+ Sample* sample_; |
+ intptr_t allocation_size_; |
+}; |
+ |
// Custom key/value trait specifically for address/size pairs. Unlike |
// RawPointerKeyValueTrait, the default value is -1 as 0 can be a valid entry. |
-class AddressKeyValueTrait { |
+class AddressKeyValueTrait : public AllStatic { |
public: |
typedef const void* Key; |
- typedef intptr_t Value; |
+ typedef AllocationInfo* Value; |
struct Pair { |
Key key; |
Value value; |
- Pair() : key(NULL), value(-1) {} |
+ Pair() : key(NULL), value(NULL) {} |
Pair(const Key key, const Value& value) : key(key), value(value) {} |
Pair(const Pair& other) : key(other.key), value(other.value) {} |
}; |
@@ -84,6 +166,8 @@ class AddressMap : public MallocDirectChainedHashMap<AddressKeyValueTrait> { |
typedef AddressKeyValueTrait::Value Value; |
typedef AddressKeyValueTrait::Pair Pair; |
+ ~AddressMap() { Clear(); } |
+ |
inline void Insert(const Key& key, const Value& value) { |
Cutch
2017/02/08 00:28:53
These are declared inline in this source file. No
bkonyi
2017/02/08 01:37:05
Acknowledged. Will be fixed in patch 3.
bkonyi
2017/02/09 21:22:46
Done.
|
Pair pair(key, value); |
MallocDirectChainedHashMap<AddressKeyValueTrait>::Insert(pair); |
@@ -99,75 +183,16 @@ class AddressMap : public MallocDirectChainedHashMap<AddressKeyValueTrait> { |
return true; |
} |
} |
-}; |
- |
- |
-class MallocHooksState { |
- public: |
- static void RecordAllocHook(const void* ptr, size_t size); |
- static void RecordFreeHook(const void* ptr); |
- static bool initialized() { return initialized_; } |
- static void Init() { |
- address_map_ = new AddressMap(); |
- initialized_ = true; |
- original_pid_ = OS::ProcessId(); |
- } |
- |
- static bool IsOriginalProcess() { |
- ASSERT(original_pid_ != kInvalidPid); |
- return original_pid_ == OS::ProcessId(); |
- } |
- |
- static Mutex* malloc_hook_mutex() { return malloc_hook_mutex_; } |
- |
- static intptr_t allocation_count() { return allocation_count_; } |
- |
- static intptr_t heap_allocated_memory_in_bytes() { |
- return heap_allocated_memory_in_bytes_; |
- } |
- |
- static void IncrementHeapAllocatedMemoryInBytes(intptr_t size) { |
- ASSERT(size >= 0); |
- heap_allocated_memory_in_bytes_ += size; |
- ++allocation_count_; |
- } |
- |
- static void DecrementHeapAllocatedMemoryInBytes(intptr_t size) { |
- ASSERT(size >= 0); |
- ASSERT(heap_allocated_memory_in_bytes_ >= size); |
- heap_allocated_memory_in_bytes_ -= size; |
- --allocation_count_; |
- ASSERT(allocation_count_ >= 0); |
- } |
- |
- static AddressMap* address_map() { return address_map_; } |
- |
- static void ResetStats() { |
- allocation_count_ = 0; |
- heap_allocated_memory_in_bytes_ = 0; |
- address_map_->Clear(); |
- } |
- |
- static void TearDown() { |
- initialized_ = false; |
- original_pid_ = kInvalidPid; |
- ResetStats(); |
- delete address_map_; |
+ inline void Clear() { |
+ Iterator iter = GetIterator(); |
+ Pair* result = iter.Next(); |
+ while (result != NULL) { |
+ delete result->value; |
+ result = iter.Next(); |
+ } |
+ MallocDirectChainedHashMap<AddressKeyValueTrait>::Clear(); |
} |
- |
- private: |
- static bool initialized_; |
- static intptr_t original_pid_; |
- static Mutex* malloc_hook_mutex_; |
- static intptr_t allocation_count_; |
- static intptr_t heap_allocated_memory_in_bytes_; |
- static AddressMap* address_map_; |
- |
- static const intptr_t kInvalidPid = -1; |
- |
- DISALLOW_ALLOCATION(); |
- DISALLOW_COPY_AND_ASSIGN(MallocHooksState); |
}; |
@@ -215,7 +240,15 @@ void MallocHooks::TearDown() { |
} |
+bool MallocHooks::stack_trace_collection_enabled() { |
+ return MallocHooksState::stack_trace_collection_enabled(); |
+} |
+ |
+ |
void MallocHooks::ResetStats() { |
+ // Set the malloc hook flag before completing the reset since ResetStats() |
+ // frees memory. |
+ MallocHookScope mhs; |
zra
2017/02/08 17:42:55
If this is a fix for an existing bug, we should pu
bkonyi
2017/02/09 21:22:46
This isn't a fix for an existing bug since ResetSt
|
MutexLocker ml(MallocHooksState::malloc_hook_mutex()); |
ASSERT(MallocHooksState::initialized()); |
@@ -240,6 +273,43 @@ intptr_t MallocHooks::heap_allocated_memory_in_bytes() { |
} |
+Sample* MallocHooks::GetSample(const void* ptr) { |
+ MutexLocker ml(MallocHooksState::malloc_hook_mutex()); |
+ ASSERT(MallocHooksState::initialized()); |
+ |
+ if (ptr != NULL) { |
+ AllocationInfo* allocation_info = NULL; |
+ if (MallocHooksState::address_map()->Lookup(ptr, &allocation_info)) { |
+ ASSERT(allocation_info != NULL); |
+ return allocation_info->sample(); |
+ } |
+ } |
+ return NULL; |
+} |
+ |
+ |
+void MallocHooksState::Init() { |
+ address_map_ = new AddressMap(); |
+ initialized_ = true; |
+ original_pid_ = OS::ProcessId(); |
+} |
+ |
+ |
+void MallocHooksState::ResetStats() { |
+ allocation_count_ = 0; |
+ heap_allocated_memory_in_bytes_ = 0; |
+ address_map_->Clear(); |
+} |
+ |
+ |
+void MallocHooksState::TearDown() { |
+ initialized_ = false; |
+ original_pid_ = kInvalidPid; |
+ ResetStats(); |
+ delete address_map_; |
+} |
+ |
+ |
void MallocHooksState::RecordAllocHook(const void* ptr, size_t size) { |
if (MallocHookScope::IsInHook() || !MallocHooksState::IsOriginalProcess()) { |
return; |
@@ -253,7 +323,7 @@ void MallocHooksState::RecordAllocHook(const void* ptr, size_t size) { |
if (ptr != NULL) { |
MallocHooksState::IncrementHeapAllocatedMemoryInBytes(size); |
- MallocHooksState::address_map()->Insert(ptr, size); |
+ MallocHooksState::address_map()->Insert(ptr, new AllocationInfo(size)); |
} |
} |
@@ -270,10 +340,12 @@ void MallocHooksState::RecordFreeHook(const void* ptr) { |
ASSERT(MallocHooksState::initialized()); |
if (ptr != NULL) { |
- intptr_t size = 0; |
- if (MallocHooksState::address_map()->Lookup(ptr, &size)) { |
- MallocHooksState::DecrementHeapAllocatedMemoryInBytes(size); |
+ AllocationInfo* allocation_info = NULL; |
+ if (MallocHooksState::address_map()->Lookup(ptr, &allocation_info)) { |
+ MallocHooksState::DecrementHeapAllocatedMemoryInBytes( |
+ allocation_info->allocation_size()); |
MallocHooksState::address_map()->Remove(ptr); |
+ delete allocation_info; |
} |
} |
} |