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

Side by Side Diff: runtime/vm/malloc_hooks.cc

Issue 2623613003: Implemented basic heap memory allocation tracking in MallocHooks using hooks registered with tcmall… (Closed)
Patch Set: Implemented basic heap memory allocation tracking in MallocHooks using hooks registered with tcmall… Created 3 years, 11 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 unified diff | Download patch
OLDNEW
1 // Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a 2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 #if defined(DART_USE_TCMALLOC) 5 #include "platform/globals.h"
6
7 #if defined(DART_USE_TCMALLOC) && !defined(PRODUCT)
6 8
7 #include "vm/malloc_hooks.h" 9 #include "vm/malloc_hooks.h"
8 10
11 #include "gperftools/malloc_hook.h"
12
13 #include "platform/assert.h"
14 #include "vm/hash_map.h"
15 #include "vm/lockers.h"
16
9 namespace dart { 17 namespace dart {
10 18
11 void MallocHooks::Init() { 19 // A locker-type class to automatically grab and release the
12 // TODO(bkonyi): Implement 20 // in_malloc_hook_flag_.
21 class MallocHookScope {
22 public:
23 static void InitMallocHookFlag() {
24 ASSERT(in_malloc_hook_flag_ == kUnsetThreadLocalKey);
25 in_malloc_hook_flag_ = OSThread::CreateThreadLocal();
26 OSThread::SetThreadLocal(in_malloc_hook_flag_, 0);
27 }
28
29 static void DestroyMallocHookFlag() {
30 ASSERT(in_malloc_hook_flag_ != kUnsetThreadLocalKey);
31 OSThread::DeleteThreadLocal(in_malloc_hook_flag_);
32 in_malloc_hook_flag_ = kUnsetThreadLocalKey;
33 }
34
35 MallocHookScope() {
36 ASSERT(in_malloc_hook_flag_ != kUnsetThreadLocalKey);
37 OSThread::SetThreadLocal(in_malloc_hook_flag_, 1);
38 }
39
40 ~MallocHookScope() {
41 ASSERT(in_malloc_hook_flag_ != kUnsetThreadLocalKey);
42 OSThread::SetThreadLocal(in_malloc_hook_flag_, 0);
43 }
44
45 static bool IsInHook() {
46 ASSERT(in_malloc_hook_flag_ != kUnsetThreadLocalKey);
47 return OSThread::GetThreadLocal(in_malloc_hook_flag_);
48 }
49
50 private:
51 static ThreadLocalKey in_malloc_hook_flag_;
52
53 DISALLOW_ALLOCATION();
54 DISALLOW_COPY_AND_ASSIGN(MallocHookScope);
55 };
56
57
58 // Custom key/value trait specifically for address/size pairs. Unlike
59 // RawPointerKeyValueTrait, the default value is -1 as 0 can be a valid entry.
60 class AddressKeyValueTrait {
61 public:
62 typedef const void* Key;
63 typedef intptr_t Value;
64
65 struct Pair {
66 Key key;
67 Value value;
68 Pair() : key(NULL), value(-1) {}
69 Pair(const Key key, const Value& value) : key(key), value(value) {}
70 Pair(const Pair& other) : key(other.key), value(other.value) {}
71 };
72
73 static Key KeyOf(Pair kv) { return kv.key; }
74 static Value ValueOf(Pair kv) { return kv.value; }
75 static intptr_t Hashcode(Key key) { return reinterpret_cast<intptr_t>(key); }
76 static bool IsKeyEqual(Pair kv, Key key) { return kv.key == key; }
77 };
78
79
80 // Map class that will be used to store mappings between ptr -> allocation size.
81 class AddressMap : public MallocDirectChainedHashMap<AddressKeyValueTrait> {
82 public:
83 typedef AddressKeyValueTrait::Key Key;
84 typedef AddressKeyValueTrait::Value Value;
85 typedef AddressKeyValueTrait::Pair Pair;
86
87 inline void Insert(const Key& key, const Value& value) {
88 Pair pair(key, value);
89 MallocDirectChainedHashMap<AddressKeyValueTrait>::Insert(pair);
90 }
91
92 inline bool Lookup(const Key& key, Value* value) {
93 ASSERT(value != NULL);
94 Pair* pair = MallocDirectChainedHashMap<AddressKeyValueTrait>::Lookup(key);
95 if (pair == NULL) {
96 return false;
97 } else {
98 *value = pair->value;
99 return true;
100 }
101 }
102 };
103
104
105 class MallocHooksState {
106 public:
107 static void RecordAllocHook(const void* ptr, size_t size);
108 static void RecordFreeHook(const void* ptr);
109
110 static bool initialized() { return initialized_; }
111 static void set_initialized() { initialized_ = true; }
112
113 static Mutex* malloc_hook_mutex() { return malloc_hook_mutex_; }
114
115 static intptr_t allocation_count() { return allocation_count_; }
116
117 static intptr_t heap_allocated_memory_in_bytes() {
118 return heap_allocated_memory_in_bytes_;
119 }
120
121 static void IncrementHeapAllocatedMemoryInBytes(intptr_t size) {
122 ASSERT(size >= 0);
123 heap_allocated_memory_in_bytes_ += size;
124 ++allocation_count_;
125 }
126
127 static void DecrementHeapAllocatedMemoryInBytes(intptr_t size) {
128 ASSERT(size >= 0);
129 ASSERT(heap_allocated_memory_in_bytes_ >= size);
130 heap_allocated_memory_in_bytes_ -= size;
131 --allocation_count_;
132 ASSERT(allocation_count_ >= 0);
133 }
134
135 static AddressMap* address_map() { return &address_map_; }
136
137 static void ResetStats() {
138 allocation_count_ = 0;
139 heap_allocated_memory_in_bytes_ = 0;
140 address_map_.Clear();
141 }
142
143 static void Reset() {
144 initialized_ = false;
145 ResetStats();
146 }
147
148 private:
149 static bool initialized_;
150 static Mutex* malloc_hook_mutex_;
151 static intptr_t allocation_count_;
152 static intptr_t heap_allocated_memory_in_bytes_;
153 static AddressMap address_map_;
154
155 private:
156 DISALLOW_ALLOCATION();
157 DISALLOW_COPY_AND_ASSIGN(MallocHooksState);
158 };
159
160
161 // MallocHooks state / locks.
162 ThreadLocalKey MallocHookScope::in_malloc_hook_flag_ = kUnsetThreadLocalKey;
163 bool MallocHooksState::initialized_ = false;
164 Mutex* MallocHooksState::malloc_hook_mutex_ = new Mutex();
165
166 // Memory allocation state information.
167 intptr_t MallocHooksState::allocation_count_ = 0;
168 intptr_t MallocHooksState::heap_allocated_memory_in_bytes_ = 0;
169 AddressMap MallocHooksState::address_map_;
170
171
172 void MallocHooks::InitOnce() {
173 MutexLocker ml(MallocHooksState::malloc_hook_mutex());
174 ASSERT(!MallocHooksState::initialized());
175
176 MallocHookScope::InitMallocHookFlag();
177 MallocHooksState::set_initialized();
178
179 // Register malloc hooks.
180 bool success = false;
181 success = MallocHook::AddNewHook(&MallocHooksState::RecordAllocHook);
182 ASSERT(success);
183 success = MallocHook::AddDeleteHook(&MallocHooksState::RecordFreeHook);
184 ASSERT(success);
185 }
186
187
188 void MallocHooks::TearDown() {
189 MutexLocker ml(MallocHooksState::malloc_hook_mutex());
190 ASSERT(MallocHooksState::initialized());
191
192 // Remove malloc hooks.
193 bool success = false;
194 success = MallocHook::RemoveNewHook(&MallocHooksState::RecordAllocHook);
195 ASSERT(success);
196 success = MallocHook::RemoveDeleteHook(&MallocHooksState::RecordFreeHook);
197 ASSERT(success);
198
199 MallocHooksState::Reset();
200 MallocHookScope::DestroyMallocHookFlag();
201 }
202
203
204 void MallocHooks::ResetStats() {
205 MutexLocker ml(MallocHooksState::malloc_hook_mutex());
206 ASSERT(MallocHooksState::initialized());
207
208 MallocHooksState::ResetStats();
209 }
210
211
212 intptr_t MallocHooks::allocation_count() {
213 MutexLocker ml(MallocHooksState::malloc_hook_mutex());
214 return MallocHooksState::allocation_count();
215 }
216
217
218 intptr_t MallocHooks::heap_allocated_memory_in_bytes() {
219 MutexLocker ml(MallocHooksState::malloc_hook_mutex());
220 return MallocHooksState::heap_allocated_memory_in_bytes();
221 }
222
223
224 void MallocHooksState::RecordAllocHook(const void* ptr, size_t size) {
225 if (MallocHookScope::IsInHook()) {
226 return;
227 }
228
229 // Set the malloc hook flag before grabbing the mutex to avoid calling hooks
230 // again.
231 MallocHookScope mhs;
232 MutexLocker ml(MallocHooksState::malloc_hook_mutex());
233 ASSERT(MallocHooksState::initialized());
234
235 if (ptr != NULL) {
236 MallocHooksState::IncrementHeapAllocatedMemoryInBytes(size);
237 MallocHooksState::address_map()->Insert(ptr, size);
238 }
239 }
240
241
242 void MallocHooksState::RecordFreeHook(const void* ptr) {
243 if (MallocHookScope::IsInHook()) {
244 return;
245 }
246
247 // Set the malloc hook flag before grabbing the mutex to avoid calling hooks
248 // again.
249 MallocHookScope mhs;
250 MutexLocker ml(MallocHooksState::malloc_hook_mutex());
251 ASSERT(MallocHooksState::initialized());
252
253 if (ptr != NULL) {
254 intptr_t size = 0;
255 if (MallocHooksState::address_map()->Lookup(ptr, &size)) {
256 MallocHooksState::DecrementHeapAllocatedMemoryInBytes(size);
257 MallocHooksState::address_map()->Remove(ptr);
258 }
259 }
13 } 260 }
14 261
15 } // namespace dart 262 } // namespace dart
16 263
17 #endif // defined(DART_USE_TCMALLOC) 264 #endif // defined(DART_USE_TCMALLOC) && !defined(PRODUCT)
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698