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

Side by Side Diff: base/test/scoped_memory_usage.cc

Issue 2440393002: [tracing] Implement composable memory usage estimators. (Closed)
Patch Set: Created 4 years, 1 month 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
« no previous file with comments | « base/test/scoped_memory_usage.h ('k') | base/trace_event/estimate_memory_usage.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright 2016 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "base/test/scoped_memory_usage.h"
6
7 #include <memory>
8 #include <unordered_map>
9
10 #include "base/allocator/allocator_shim.h"
11 #include "base/logging.h"
12 #include "base/memory/ptr_util.h"
13 #include "base/threading/thread_local_storage.h"
14 #include "testing/gtest/include/gtest/gtest.h"
15
16 namespace base {
17 namespace test {
18
19 namespace {
20
21 // Unshimmed API
22
23 void* UnshimmedAlloc(size_t size) {
24 auto& dispatch = allocator::AllocatorDispatch::default_dispatch;
25 return dispatch.alloc_function(&dispatch, size);
26 }
27
28 void UnshimmedFree(void* ptr) {
29 auto& dispatch = allocator::AllocatorDispatch::default_dispatch;
30 dispatch.free_function(&dispatch, ptr);
31 }
32
33 #define USING_UNSHIMMED_NEW() \
34 void* operator new (size_t size) { return UnshimmedAlloc(size); } \
35 void* operator new[] (size_t size) { return UnshimmedAlloc(size); } \
36 void operator delete (void* ptr) { UnshimmedFree(ptr); } \
37 void operator delete[] (void* ptr) { UnshimmedFree(ptr); }
38
39 template <class T>
40 struct unshimmed_allocator: std::allocator<T> {
41 typedef std::allocator<T> base;
42
43 using typename base::size_type;
44 using typename base::difference_type;
45 using typename base::pointer;
46 using typename base::const_pointer;
47 using typename base::reference;
48 using typename base::const_reference;
49 using typename base::value_type;
50
51 using base::construct;
52 using base::destroy;
53
54 template <class U>
55 struct rebind {
56 typedef unshimmed_allocator<U> other;
57 };
58
59 unshimmed_allocator() noexcept {}
60
61 template <class U>
62 unshimmed_allocator(const unshimmed_allocator<U>&) noexcept {}
63
64 pointer allocate(size_type count, const void* hint = 0) {
65 return static_cast<pointer>(UnshimmedAlloc(count * sizeof(T)));
66 }
67
68 void deallocate(pointer ptr, size_type) noexcept {
69 UnshimmedFree(ptr);
70 }
71 };
72
73 template <
74 class Key,
75 class T,
76 class Hash = std::hash<Key>,
77 class KeyEqual = std::equal_to<Key>>
78 using unshimmed_unordered_map = std::unordered_map<
79 Key, T, Hash, KeyEqual, unshimmed_allocator<std::pair<const Key, T>>>;
80
81 // ThreadAllocationRegister
82
83 class ThreadAllocationRegister {
84 public:
85 USING_UNSHIMMED_NEW();
86
87 ThreadAllocationRegister(): total_size_(0) {}
88
89 size_t total_size() const { return total_size_; }
90
91 void Register(void* ptr, size_t size) {
92 EXPECT_TRUE(allocations_.insert({ptr, size}).second);
93 total_size_ += size;
94 }
95
96 void Remove(void* ptr) {
97 auto allocation = allocations_.find(ptr);
98 if (allocation != allocations_.end()) {
99 total_size_ -= allocation->second;
100 allocations_.erase(allocation);
101 }
102 }
103
104 private:
105 unshimmed_unordered_map<void*, size_t> allocations_;
106 size_t total_size_;
107 };
108
109 ThreadLocalStorage::StaticSlot g_thread_allocation_register = TLS_INITIALIZER;
110
111 void InstallThreadAllocationRegister() {
112 CHECK(g_thread_allocation_register.initialized());
113 EXPECT_EQ(nullptr, g_thread_allocation_register.Get());
114 g_thread_allocation_register.Set(new ThreadAllocationRegister());
115 }
116
117 void UninstallThreadAllocationRegister() {
118 CHECK(g_thread_allocation_register.initialized());
119 EXPECT_NE(nullptr, g_thread_allocation_register.Get());
120 auto* allocation_register = static_cast<ThreadAllocationRegister*>(
121 g_thread_allocation_register.Get());
122 g_thread_allocation_register.Set(nullptr);
123 delete allocation_register;
124 }
125
126 ThreadAllocationRegister* GetThreadAllocationRegister() {
127 CHECK(g_thread_allocation_register.initialized());
128 return static_cast<ThreadAllocationRegister*>(
129 g_thread_allocation_register.Get());
130 }
131
132 // AllocatorDispatch
133
134 void RegisterAllocation(void* ptr, size_t size) {
135 if (!ptr) {
136 return;
137 }
138 if (auto* allocation_register = GetThreadAllocationRegister()) {
139 allocation_register->Register(ptr, size);
140 }
141 }
142
143 void RemoveAllocation(void* ptr) {
144 if (!ptr) {
145 return;
146 }
147 if (auto* allocation_register = GetThreadAllocationRegister()) {
148 allocation_register->Remove(ptr);
149 }
150 }
151
152 void* HookAlloc(const allocator::AllocatorDispatch* self, size_t size) {
153 auto* next = self->next;
154 void* ptr = next->alloc_function(next, size);
155 RegisterAllocation(ptr, size);
156 return ptr;
157 }
158
159 void* HookAllocZeroInitialized(const allocator::AllocatorDispatch* self,
160 size_t n, size_t size) {
161 const allocator::AllocatorDispatch* const next = self->next;
162 void* ptr = next->alloc_zero_initialized_function(next, n, size);
163 RegisterAllocation(ptr, n * size);
164 return ptr;
165 }
166
167 void* HookAllocAligned(const allocator::AllocatorDispatch* self,
168 size_t alignment, size_t size) {
169 const allocator::AllocatorDispatch* const next = self->next;
170 void* ptr = next->alloc_aligned_function(next, alignment, size);
171 RegisterAllocation(ptr, size);
172 return ptr;
173 }
174
175 void* HookRealloc(const allocator::AllocatorDispatch* self,
176 void* ptr, size_t new_size) {
177 const allocator::AllocatorDispatch* const next = self->next;
178 void* new_ptr = next->realloc_function(next, ptr, new_size);
179 RemoveAllocation(ptr);
180 if (new_size != 0) {
181 RegisterAllocation(new_ptr, new_size);
182 }
183 return new_ptr;
184 }
185
186 void HookFree(const allocator::AllocatorDispatch* self, void* ptr) {
187 RemoveAllocation(ptr);
188 const allocator::AllocatorDispatch* const next = self->next;
189 next->free_function(next, ptr);
190 }
191
192 size_t HookGetSizeEstimate(const allocator::AllocatorDispatch* self,
193 void* ptr) {
194 const allocator::AllocatorDispatch* const next = self->next;
195 return next->get_size_estimate_function(next, ptr);
196 }
197
198 allocator::AllocatorDispatch g_allocator_hooks = {
199 &HookAlloc, /* alloc_function */
200 &HookAllocZeroInitialized,/* alloc_zero_initialized_function */
201 &HookAllocAligned, /* alloc_aligned_function */
202 &HookRealloc, /* realloc_function */
203 &HookFree, /* free_function */
204 &HookGetSizeEstimate, /* get_size_estimate_function */
205 nullptr, /* next */
206 };
207
208 } // namespace
209
210 ScopedMemoryUsage::ScopedMemoryUsage() {
211 InstallThreadAllocationRegister();
212 }
213
214 ScopedMemoryUsage::~ScopedMemoryUsage() {
215 UninstallThreadAllocationRegister();
216 }
217
218 size_t ScopedMemoryUsage::Usage() const {
219 return GetThreadAllocationRegister()->total_size();
220 }
221
222 void ScopedMemoryUsage::Initialize() {
223 if (g_thread_allocation_register.initialized()) {
224 return;
225 }
226
227 g_thread_allocation_register.Initialize([](void* allocation_register) {
228 delete static_cast<ThreadAllocationRegister*>(allocation_register);
229 });
230
231 allocator::InsertAllocatorDispatch(&g_allocator_hooks);
232 }
233
234 } // namespace test
235 } // namespace base
OLDNEW
« no previous file with comments | « base/test/scoped_memory_usage.h ('k') | base/trace_event/estimate_memory_usage.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698