Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(426)

Unified Diff: runtime/vm/malloc_hooks.cc

Issue 2680213002: Updated MallocHooks to collect stack traces when memory is allocated. (Closed)
Patch Set: Updated MallocHooks to collect stack traces when memory is allocated. Created 3 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « runtime/vm/malloc_hooks.h ('k') | runtime/vm/malloc_hooks_test.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: runtime/vm/malloc_hooks.cc
diff --git a/runtime/vm/malloc_hooks.cc b/runtime/vm/malloc_hooks.cc
index 9e5c6587c3065498c8a757de121770e315e1b03d..30fdaaa79e3dc914d9fb638d77bdb7a457ca2f50 100644
--- a/runtime/vm/malloc_hooks.cc
+++ b/runtime/vm/malloc_hooks.cc
@@ -4,7 +4,8 @@
#include "platform/globals.h"
-#if defined(DART_USE_TCMALLOC) && !defined(PRODUCT)
+#if defined(DART_USE_TCMALLOC) && !defined(PRODUCT) && \
+ !defined(TARGET_ARCH_DBC) && !defined(TARGET_OS_FUCHSIA)
#include "vm/malloc_hooks.h"
@@ -14,9 +15,84 @@
#include "vm/hash_map.h"
#include "vm/json_stream.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 Active() {
+ ASSERT(malloc_hook_mutex()->IsOwnedByCurrentThread());
+ return active_;
+ }
+ static void Init();
+
+ static bool ProfilingEnabled() { return (OSThread::TryCurrent() != NULL); }
+
+ static bool stack_trace_collection_enabled() {
+ return stack_trace_collection_enabled_;
+ }
+
+ static void set_stack_trace_collection_enabled(bool enabled) {
+ stack_trace_collection_enabled_ = enabled;
+ }
+
+ 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(malloc_hook_mutex()->IsOwnedByCurrentThread());
+ ASSERT(size >= 0);
+ heap_allocated_memory_in_bytes_ += size;
+ ++allocation_count_;
+ }
+
+ static void DecrementHeapAllocatedMemoryInBytes(intptr_t size) {
+ ASSERT(malloc_hook_mutex()->IsOwnedByCurrentThread());
+ 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 Mutex* malloc_hook_mutex_;
+
+ // Variables protected by malloc_hook_mutex_.
+ static bool active_;
+ static bool stack_trace_collection_enabled_;
+ static intptr_t allocation_count_;
+ static intptr_t heap_allocated_memory_in_bytes_;
+ static AddressMap* address_map_;
+ // End protected variables.
+
+ static intptr_t original_pid_;
+ static const intptr_t kInvalidPid = -1;
+};
+
// A locker-type class to automatically grab and release the
// in_malloc_hook_flag_.
class MallocHookScope {
@@ -55,18 +131,50 @@ 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 (MallocHooksState::ProfilingEnabled() &&
+ MallocHooksState::stack_trace_collection_enabled()) {
+ sample_ = Profiler::SampleNativeAllocation(kSkipCount);
+ }
+ }
+
+ Sample* sample() const { return sample_; }
+ intptr_t allocation_size() const { return allocation_size_; }
+
+ private:
+ Sample* sample_;
+ intptr_t allocation_size_;
+
+ // The number of frames that are generated by the malloc hooks and collection
+ // of the stack trace. These frames are ignored when collecting the stack
+ // trace for a memory allocation. If this number is incorrect, some tests in
+ // malloc_hook_tests.cc might fail, particularily
+ // StackTraceMallocHookLengthTest. If this value is updated, please make sure
+ // that the MallocHooks test cases pass on all platforms.
+ static const intptr_t kSkipCount = 5;
+};
+
// 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) {}
};
@@ -85,12 +193,14 @@ class AddressMap : public MallocDirectChainedHashMap<AddressKeyValueTrait> {
typedef AddressKeyValueTrait::Value Value;
typedef AddressKeyValueTrait::Pair Pair;
- inline void Insert(const Key& key, const Value& value) {
+ virtual ~AddressMap() { Clear(); }
+
+ void Insert(const Key& key, const Value& value) {
Pair pair(key, value);
MallocDirectChainedHashMap<AddressKeyValueTrait>::Insert(pair);
}
- inline bool Lookup(const Key& key, Value* value) {
+ bool Lookup(const Key& key, Value* value) {
ASSERT(value != NULL);
Pair* pair = MallocDirectChainedHashMap<AddressKeyValueTrait>::Lookup(key);
if (pair == NULL) {
@@ -100,82 +210,24 @@ class AddressMap : public MallocDirectChainedHashMap<AddressKeyValueTrait> {
return true;
}
}
-};
-
-
-class MallocHooksState : public AllStatic {
- public:
- static void RecordAllocHook(const void* ptr, size_t size);
- static void RecordFreeHook(const void* ptr);
-
- static bool Active() { return active_; }
- static void Init() {
- address_map_ = new AddressMap();
- active_ = 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(malloc_hook_mutex()->IsOwnedByCurrentThread());
- ASSERT(size >= 0);
- heap_allocated_memory_in_bytes_ += size;
- ++allocation_count_;
- }
-
- static void DecrementHeapAllocatedMemoryInBytes(intptr_t size) {
- ASSERT(malloc_hook_mutex()->IsOwnedByCurrentThread());
- 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() {
- ASSERT(malloc_hook_mutex()->IsOwnedByCurrentThread());
- allocation_count_ = 0;
- heap_allocated_memory_in_bytes_ = 0;
- address_map_->Clear();
- }
-
- static void TearDown() {
- ASSERT(malloc_hook_mutex()->IsOwnedByCurrentThread());
- active_ = false;
- original_pid_ = kInvalidPid;
- ResetStats();
- delete address_map_;
+ void Clear() {
+ Iterator iter = GetIterator();
+ Pair* result = iter.Next();
+ while (result != NULL) {
+ delete result->value;
+ result->value = NULL;
+ result = iter.Next();
+ }
+ MallocDirectChainedHashMap<AddressKeyValueTrait>::Clear();
}
-
- private:
- static bool active_;
- 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;
};
// MallocHooks state / locks.
ThreadLocalKey MallocHookScope::in_malloc_hook_flag_ = kUnsetThreadLocalKey;
bool MallocHooksState::active_ = false;
+bool MallocHooksState::stack_trace_collection_enabled_ = false;
intptr_t MallocHooksState::original_pid_ = MallocHooksState::kInvalidPid;
Mutex* MallocHooksState::malloc_hook_mutex_ = new Mutex();
@@ -185,6 +237,36 @@ intptr_t MallocHooksState::heap_allocated_memory_in_bytes_ = 0;
AddressMap* MallocHooksState::address_map_ = NULL;
+void MallocHooksState::Init() {
+ address_map_ = new AddressMap();
+ active_ = true;
+#if defined(DEBUG)
+ stack_trace_collection_enabled_ = true;
+#else
+ stack_trace_collection_enabled_ = false;
+#endif // defined(DEBUG)
+ original_pid_ = OS::ProcessId();
+}
+
+
+void MallocHooksState::ResetStats() {
+ ASSERT(malloc_hook_mutex()->IsOwnedByCurrentThread());
+ allocation_count_ = 0;
+ heap_allocated_memory_in_bytes_ = 0;
+ address_map_->Clear();
+}
+
+
+void MallocHooksState::TearDown() {
+ ASSERT(malloc_hook_mutex()->IsOwnedByCurrentThread());
+ active_ = false;
+ original_pid_ = kInvalidPid;
+ ResetStats();
+ delete address_map_;
+ address_map_ = NULL;
+}
+
+
void MallocHooks::InitOnce() {
MutexLocker ml(MallocHooksState::malloc_hook_mutex());
ASSERT(!MallocHooksState::Active());
@@ -217,7 +299,27 @@ void MallocHooks::TearDown() {
}
+bool MallocHooks::ProfilingEnabled() {
+ return MallocHooksState::ProfilingEnabled();
+}
+
+
+bool MallocHooks::stack_trace_collection_enabled() {
+ MutexLocker ml(MallocHooksState::malloc_hook_mutex());
+ return MallocHooksState::stack_trace_collection_enabled();
+}
+
+
+void MallocHooks::set_stack_trace_collection_enabled(bool enabled) {
+ MutexLocker ml(MallocHooksState::malloc_hook_mutex());
+ MallocHooksState::set_stack_trace_collection_enabled(enabled);
+}
+
+
void MallocHooks::ResetStats() {
+ // Set the malloc hook flag before completing the reset since ResetStats()
+ // frees memory.
+ MallocHookScope mhs;
MutexLocker ml(MallocHooksState::malloc_hook_mutex());
if (MallocHooksState::Active()) {
MallocHooksState::ResetStats();
@@ -226,7 +328,7 @@ void MallocHooks::ResetStats() {
bool MallocHooks::Active() {
- ASSERT(MallocHooksState::malloc_hook_mutex()->IsOwnedByCurrentThread());
+ MutexLocker ml(MallocHooksState::malloc_hook_mutex());
return MallocHooksState::Active();
}
@@ -240,7 +342,7 @@ void MallocHooks::PrintToJSONObject(JSONObject* jsobj) {
// and then add the JSON properties.
{
MutexLocker ml(MallocHooksState::malloc_hook_mutex());
- if (Active()) {
+ if (MallocHooksState::Active()) {
allocated_memory = MallocHooksState::heap_allocated_memory_in_bytes();
allocation_count = MallocHooksState::allocation_count();
add_usage = true;
@@ -265,6 +367,21 @@ intptr_t MallocHooks::heap_allocated_memory_in_bytes() {
}
+Sample* MallocHooks::GetSample(const void* ptr) {
+ MutexLocker ml(MallocHooksState::malloc_hook_mutex());
+ ASSERT(MallocHooksState::Active());
+
+ 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::RecordAllocHook(const void* ptr, size_t size) {
if (MallocHookScope::IsInHook() || !MallocHooksState::IsOriginalProcess()) {
return;
@@ -276,7 +393,7 @@ void MallocHooksState::RecordAllocHook(const void* ptr, size_t size) {
MutexLocker ml(MallocHooksState::malloc_hook_mutex());
if ((ptr != NULL) && MallocHooksState::Active()) {
MallocHooksState::IncrementHeapAllocatedMemoryInBytes(size);
- MallocHooksState::address_map()->Insert(ptr, size);
+ MallocHooksState::address_map()->Insert(ptr, new AllocationInfo(size));
}
}
@@ -291,14 +408,17 @@ void MallocHooksState::RecordFreeHook(const void* ptr) {
MallocHookScope mhs;
MutexLocker ml(MallocHooksState::malloc_hook_mutex());
if ((ptr != NULL) && MallocHooksState::Active()) {
- 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;
}
}
}
} // namespace dart
-#endif // defined(DART_USE_TCMALLOC) && !defined(PRODUCT)
+#endif // defined(DART_USE_TCMALLOC) && !defined(PRODUCT) &&
+ // !defined(TARGET_ARCH_DBC) && !defined(TARGET_OS_FUCHSIA)
« no previous file with comments | « runtime/vm/malloc_hooks.h ('k') | runtime/vm/malloc_hooks_test.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698