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

Unified Diff: runtime/vm/malloc_hooks.cc

Issue 2829833003: [Fuchsia] Grab the number of malloc'd bytes from jemalloc (Closed)
Patch Set: Fix guards Created 3 years, 8 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
Index: runtime/vm/malloc_hooks.cc
diff --git a/runtime/vm/malloc_hooks.cc b/runtime/vm/malloc_hooks.cc
deleted file mode 100644
index 6502bbb3a06ecfcad03a192cd283c6983a794643..0000000000000000000000000000000000000000
--- a/runtime/vm/malloc_hooks.cc
+++ /dev/null
@@ -1,448 +0,0 @@
-// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-#include "platform/globals.h"
-
-#if defined(DART_USE_TCMALLOC) && !defined(PRODUCT) && \
- !defined(TARGET_ARCH_DBC) && !defined(HOST_OS_FUCHSIA)
-
-#include "vm/malloc_hooks.h"
-
-#include "gperftools/malloc_hook.h"
-
-#include "platform/assert.h"
-#include "vm/hash_map.h"
-#include "vm/json_stream.h"
-#include "vm/os_thread.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 ThreadId* malloc_hook_mutex_owner() {
- return &malloc_hook_mutex_owner_;
- }
- static bool IsLockHeldByCurrentThread() {
- return (malloc_hook_mutex_owner_ == OSThread::GetCurrentThreadId());
- }
-
- 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_;
- static ThreadId malloc_hook_mutex_owner_;
-
- // 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 similar to MutexLocker which tracks which thread
-// currently holds the lock. We use this instead of MutexLocker and
-// mutex->IsOwnedByCurrentThread() since IsOwnedByCurrentThread() is only
-// enabled for debug mode.
-class MallocLocker : public ValueObject {
- public:
- explicit MallocLocker(Mutex* mutex, ThreadId* owner)
- : mutex_(mutex), owner_(owner) {
- ASSERT(owner != NULL);
- mutex_->Lock();
- ASSERT(*owner_ == OSThread::kInvalidThreadId);
- *owner_ = OSThread::GetCurrentThreadId();
- }
-
- virtual ~MallocLocker() {
- ASSERT(*owner_ == OSThread::GetCurrentThreadId());
- *owner_ = OSThread::kInvalidThreadId;
- mutex_->Unlock();
- }
-
- private:
- Mutex* mutex_;
- ThreadId* owner_;
-};
-
-// 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:
- AllocationInfo(uword address, intptr_t allocation_size)
- : sample_(NULL), address_(address), 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, address,
- allocation_size);
- ASSERT(sample_->native_allocation_address() == address_);
- }
- }
-
- Sample* sample() const { return sample_; }
- intptr_t allocation_size() const { return allocation_size_; }
-
- private:
- // Note: sample_ is not owned by AllocationInfo, but by the SampleBuffer
- // created by the profiler. As such, this is only here to track if the sample
- // is still associated with a native allocation, and its fields are never
- // accessed from this class.
- Sample* sample_;
- uword address_;
- 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 : public AllStatic {
- public:
- typedef const void* Key;
- typedef AllocationInfo* Value;
-
- struct Pair {
- Key key;
- Value value;
- 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) {}
- };
-
- static Key KeyOf(Pair kv) { return kv.key; }
- static Value ValueOf(Pair kv) { return kv.value; }
- static intptr_t Hashcode(Key key) { return reinterpret_cast<intptr_t>(key); }
- static bool IsKeyEqual(Pair kv, Key key) { return kv.key == key; }
-};
-
-
-// Map class that will be used to store mappings between ptr -> allocation size.
-class AddressMap : public MallocDirectChainedHashMap<AddressKeyValueTrait> {
- public:
- typedef AddressKeyValueTrait::Key Key;
- typedef AddressKeyValueTrait::Value Value;
- typedef AddressKeyValueTrait::Pair Pair;
-
- virtual ~AddressMap() { Clear(); }
-
- void Insert(const Key& key, const Value& value) {
- Pair pair(key, value);
- MallocDirectChainedHashMap<AddressKeyValueTrait>::Insert(pair);
- }
-
- bool Lookup(const Key& key, Value* value) {
- ASSERT(value != NULL);
- Pair* pair = MallocDirectChainedHashMap<AddressKeyValueTrait>::Lookup(key);
- if (pair == NULL) {
- return false;
- } else {
- *value = pair->value;
- return true;
- }
- }
-
- void Clear() {
- Iterator iter = GetIterator();
- Pair* result = iter.Next();
- while (result != NULL) {
- delete result->value;
- result->value = NULL;
- result = iter.Next();
- }
- MallocDirectChainedHashMap<AddressKeyValueTrait>::Clear();
- }
-};
-
-
-// MallocHooks state / locks.
-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();
-ThreadId MallocHooksState::malloc_hook_mutex_owner_ =
- OSThread::kInvalidThreadId;
-
-// Memory allocation state information.
-intptr_t MallocHooksState::allocation_count_ = 0;
-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() {
- if (!FLAG_enable_malloc_hooks || MallocHooks::Active()) {
- return;
- }
- MallocLocker ml(MallocHooksState::malloc_hook_mutex(),
- MallocHooksState::malloc_hook_mutex_owner());
- ASSERT(!MallocHooksState::Active());
-
- MallocHooksState::Init();
-
- // Register malloc hooks.
- bool success = false;
- success = MallocHook::AddNewHook(&MallocHooksState::RecordAllocHook);
- ASSERT(success);
- success = MallocHook::AddDeleteHook(&MallocHooksState::RecordFreeHook);
- ASSERT(success);
-}
-
-
-void MallocHooks::TearDown() {
- if (!FLAG_enable_malloc_hooks || !MallocHooks::Active()) {
- return;
- }
- MallocLocker ml(MallocHooksState::malloc_hook_mutex(),
- MallocHooksState::malloc_hook_mutex_owner());
- ASSERT(MallocHooksState::Active());
-
- // Remove malloc hooks.
- bool success = false;
- success = MallocHook::RemoveNewHook(&MallocHooksState::RecordAllocHook);
- ASSERT(success);
- success = MallocHook::RemoveDeleteHook(&MallocHooksState::RecordFreeHook);
- ASSERT(success);
-
- MallocHooksState::TearDown();
-}
-
-
-bool MallocHooks::ProfilingEnabled() {
- return MallocHooksState::ProfilingEnabled();
-}
-
-
-bool MallocHooks::stack_trace_collection_enabled() {
- MallocLocker ml(MallocHooksState::malloc_hook_mutex(),
- MallocHooksState::malloc_hook_mutex_owner());
- return MallocHooksState::stack_trace_collection_enabled();
-}
-
-
-void MallocHooks::set_stack_trace_collection_enabled(bool enabled) {
- MallocLocker ml(MallocHooksState::malloc_hook_mutex(),
- MallocHooksState::malloc_hook_mutex_owner());
- MallocHooksState::set_stack_trace_collection_enabled(enabled);
-}
-
-
-void MallocHooks::ResetStats() {
- if (!FLAG_enable_malloc_hooks) {
- return;
- }
- MallocLocker ml(MallocHooksState::malloc_hook_mutex(),
- MallocHooksState::malloc_hook_mutex_owner());
- if (MallocHooksState::Active()) {
- MallocHooksState::ResetStats();
- }
-}
-
-
-bool MallocHooks::Active() {
- if (!FLAG_enable_malloc_hooks) {
- return false;
- }
- MallocLocker ml(MallocHooksState::malloc_hook_mutex(),
- MallocHooksState::malloc_hook_mutex_owner());
-
- return MallocHooksState::Active();
-}
-
-
-void MallocHooks::PrintToJSONObject(JSONObject* jsobj) {
- if (!FLAG_enable_malloc_hooks) {
- return;
- }
- intptr_t allocated_memory = 0;
- intptr_t allocation_count = 0;
- bool add_usage = false;
- // AddProperty may call malloc which would result in an attempt
- // to acquire the lock recursively so we extract the values first
- // and then add the JSON properties.
- {
- MallocLocker ml(MallocHooksState::malloc_hook_mutex(),
- MallocHooksState::malloc_hook_mutex_owner());
- if (MallocHooksState::Active()) {
- allocated_memory = MallocHooksState::heap_allocated_memory_in_bytes();
- allocation_count = MallocHooksState::allocation_count();
- add_usage = true;
- }
- }
- if (add_usage) {
- jsobj->AddProperty("_heapAllocatedMemoryUsage", allocated_memory);
- jsobj->AddProperty("_heapAllocationCount", allocation_count);
- }
-}
-
-
-intptr_t MallocHooks::allocation_count() {
- if (!FLAG_enable_malloc_hooks) {
- return 0;
- }
- MallocLocker ml(MallocHooksState::malloc_hook_mutex(),
- MallocHooksState::malloc_hook_mutex_owner());
- return MallocHooksState::allocation_count();
-}
-
-
-intptr_t MallocHooks::heap_allocated_memory_in_bytes() {
- if (!FLAG_enable_malloc_hooks) {
- return 0;
- }
- MallocLocker ml(MallocHooksState::malloc_hook_mutex(),
- MallocHooksState::malloc_hook_mutex_owner());
- return MallocHooksState::heap_allocated_memory_in_bytes();
-}
-
-
-Sample* MallocHooks::GetSample(const void* ptr) {
- MallocLocker ml(MallocHooksState::malloc_hook_mutex(),
- MallocHooksState::malloc_hook_mutex_owner());
-
- 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 (MallocHooksState::IsLockHeldByCurrentThread() ||
- !MallocHooksState::IsOriginalProcess()) {
- return;
- }
-
- MallocLocker ml(MallocHooksState::malloc_hook_mutex(),
- MallocHooksState::malloc_hook_mutex_owner());
- // Now that we hold the lock, check to make sure everything is still active.
- if ((ptr != NULL) && MallocHooksState::Active()) {
- MallocHooksState::IncrementHeapAllocatedMemoryInBytes(size);
- MallocHooksState::address_map()->Insert(
- ptr, new AllocationInfo(reinterpret_cast<uword>(ptr), size));
- }
-}
-
-
-void MallocHooksState::RecordFreeHook(const void* ptr) {
- if (MallocHooksState::IsLockHeldByCurrentThread() ||
- !MallocHooksState::IsOriginalProcess()) {
- return;
- }
-
- MallocLocker ml(MallocHooksState::malloc_hook_mutex(),
- MallocHooksState::malloc_hook_mutex_owner());
- // Now that we hold the lock, check to make sure everything is still active.
- if ((ptr != NULL) && MallocHooksState::Active()) {
- AllocationInfo* allocation_info = NULL;
- if (MallocHooksState::address_map()->Lookup(ptr, &allocation_info)) {
- MallocHooksState::DecrementHeapAllocatedMemoryInBytes(
- allocation_info->allocation_size());
- const bool result = MallocHooksState::address_map()->Remove(ptr);
- ASSERT(result);
- delete allocation_info;
- }
- }
-}
-
-} // namespace dart
-
-#endif // defined(DART_USE_TCMALLOC) && !defined(PRODUCT) &&
- // !defined(TARGET_ARCH_DBC) && !defined(HOST_OS_FUCHSIA)

Powered by Google App Engine
This is Rietveld 408576698