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

Side by Side Diff: base/debug/scoped_heap_usage.cc

Issue 2163783003: Implement a ScopedThreadHeapUsage class to allow profiling per-thread heap usage. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@shim-default
Patch Set: Improve comments, fix cosmetic problems. Created 4 years, 5 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
(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/debug/scoped_heap_usage.h"
6
7 #include <malloc.h>
8 #include <stdint.h>
9 // TODO(siggi): DO NOT SUBMIT
10 #include <windows.h>
11
12 #include "base/allocator/allocator_shim.h"
13 #include "base/lazy_instance.h"
14 #include "base/threading/thread_local.h"
15
16 namespace base {
17 namespace debug {
18
19 namespace {
20
21 using base::allocator::AllocatorDispatch;
22
23 base::LazyInstance<base::ThreadLocalPointer<ScopedHeapUsage::AllocatorUsage>>::
24 Leaky g_thread_allocator_usage = LAZY_INSTANCE_INITIALIZER;
25
26 // Forward declared as it needs to delegate memory allocation to the next
27 // lower shim.
28 ScopedHeapUsage::AllocatorUsage* GetOrCreateThreadUsage();
29
30 // DO NOT SUBMIT.
31 // This functionality needs to be exposed on the heap shims. Note that under the
32 // linux libc, it appears the heap doesn't keep track of the user size, but
33 // instead allows querying the actual user size of the allocation with
chrisha 2016/07/21 14:23:30 Did you mean: s/actual user size/actual size/
Sigurður Ásgeirsson 2016/08/19 18:21:49 Done.
34 // malloc_usable_size. I'm not sure how best to deal with this.
chrisha 2016/07/21 14:23:31 Maybe by making allocated and freed track actual b
Primiano Tucci (use gerrit) 2016/07/21 15:59:20 So the problem here is that on other platforms mal
Sigurður Ásgeirsson 2016/08/19 18:21:49 Yeah - I think this'll be platform dependent enoug
Sigurður Ásgeirsson 2016/08/19 18:21:49 Side-tracking of individual allocs is a no-go for
35 size_t GetAllocSize(void* ptr) {
36 if (ptr == nullptr)
37 return 0U;
38
39 HANDLE heap_handle = reinterpret_cast<HANDLE>(_get_heap_handle());
40 return ::HeapSize(heap_handle, 0, ptr);
41 }
42
43 size_t EstimateOverhead(size_t size) {
Primiano Tucci (use gerrit) 2016/07/21 15:59:20 this is going to be very tricky on tcmalloc (Linux
Sigurður Ásgeirsson 2016/08/19 18:21:49 Yeah, it doesn't have to be very accurate though.
44 // TODO(siggi): Less Windows specific!
45 const size_t kHeaderSize = 8;
46 #if defined(ARCH_CPU_64_BITS)
47 const size_t kAllocationGranularity = 16;
48 #else
49 const size_t kAllocationGranularity = 8;
50 #endif
51 size_t overhead = 0;
52 if (size % kAllocationGranularity != 0)
53 overhead = kAllocationGranularity - (size % kAllocationGranularity);
54
55 // This is a lower-bound estimate on the Windows heap overhead.
56 return kHeaderSize + overhead;
57 }
58
59 void RecordAlloc(size_t size) {
60 ScopedHeapUsage::AllocatorUsage* usage = GetOrCreateThreadUsage();
61 if (usage == nullptr)
62 return;
63
64 usage->alloc_ops++;
65 usage->alloc_bytes += size;
66 usage->alloc_overhead_bytes += EstimateOverhead(size);
67
68 uint64_t allocated_bytes = usage->alloc_bytes - usage->free_bytes;
69 if (allocated_bytes > usage->max_allocated_bytes)
70 usage->max_allocated_bytes = allocated_bytes;
71 }
72
73 void RecordFree(size_t size) {
74 ScopedHeapUsage::AllocatorUsage* usage = GetOrCreateThreadUsage();
75 if (usage == nullptr)
76 return;
77
78 usage->free_ops++;
79 usage->free_bytes += size;
80 }
81
82 void* AllocFn(const AllocatorDispatch* self, size_t size) {
83 void* ret = self->next->alloc_function(self, size);
84 if (ret != nullptr)
85 RecordAlloc(size);
86
87 return ret;
88 }
89
90 void* AllocZeroInitializedFn(const AllocatorDispatch* self,
91 size_t n,
92 size_t size) {
93 void* ret = self->next->alloc_zero_initialized_function(self, n, size);
94 if (ret != nullptr)
95 RecordAlloc(n * size);
96
97 return ret;
98 }
99
100 void* AllocAlignedFn(const AllocatorDispatch* self,
101 size_t alignment,
102 size_t size) {
103 void* ret = self->next->alloc_aligned_function(self, alignment, size);
104 if (ret != nullptr)
105 RecordAlloc(size);
106
107 return ret;
108 }
109
110 void* ReallocFn(const AllocatorDispatch* self, void* address, size_t size) {
111 if (address != nullptr)
112 RecordFree(GetAllocSize(address));
113
114 void* ret = self->next->realloc_function(self, address, size);
115 if (ret != nullptr)
116 RecordAlloc(size);
117
118 return ret;
119 }
120
121 void FreeFn(const AllocatorDispatch* self, void* address) {
122 size_t alloc_size = GetAllocSize(address);
123 self->next->free_function(self, address);
124 RecordFree(alloc_size);
125 }
126
127 // The dispatch for the heap interept used.
128 AllocatorDispatch allocator_dispatch = {
129 &AllocFn, &AllocZeroInitializedFn, &AllocAlignedFn, &ReallocFn, &FreeFn,
130 nullptr};
131
132 ScopedHeapUsage::AllocatorUsage* GetOrCreateThreadUsage() {
133 using AllocatorUsage = ScopedHeapUsage::AllocatorUsage;
134
135 base::ThreadLocalPointer<AllocatorUsage>& usage_tls =
136 g_thread_allocator_usage.Get();
Primiano Tucci (use gerrit) 2016/07/21 15:59:20 Isn't this going to re-enter (either the lazy inst
Sigurður Ásgeirsson 2016/08/19 18:21:49 I haven't seen it reenter, but obviously I haven't
137
138 AllocatorUsage* usage = usage_tls.Get();
139 if (usage == nullptr) {
140 CHECK(allocator_dispatch.next != nullptr);
Primiano Tucci (use gerrit) 2016/07/21 15:59:20 no need for this check, if this is null will crash
Sigurður Ásgeirsson 2016/08/19 18:21:49 Acknowledged.
141
142 // Delegate the memory allocation to the next lower heap shim to avoid
143 // infinite recursion.
144 const AllocatorDispatch* next = allocator_dispatch.next;
145 usage = reinterpret_cast<AllocatorUsage*>(
146 next->alloc_function(next, sizeof(AllocatorUsage)));
Primiano Tucci (use gerrit) 2016/07/21 15:59:20 you could just use alloc_zero_initialized_function
Sigurður Ásgeirsson 2016/08/19 18:21:49 Done.
147 memset(usage, 0, sizeof(AllocatorUsage));
148 usage_tls.Set(usage);
Primiano Tucci (use gerrit) 2016/07/21 15:59:20 so the problem here is that you are leaking one "u
Sigurður Ásgeirsson 2016/08/19 18:21:49 Done.
149 }
150
151 return usage;
152 }
153
154 } // namespace
155
156 ScopedHeapUsage::ScopedHeapUsage() : thread_usage_(GetOrCreateThreadUsage()) {
157 if (thread_usage_ != nullptr) {
158 usage_at_creation_ = *thread_usage_;
159 // Reset the max allocation tally for this scope.
160 thread_usage_->max_allocated_bytes = 0U;
161 } else {
chrisha 2016/07/21 14:23:31 Shouldn't thread_usage_ always be non-null at this
Primiano Tucci (use gerrit) 2016/07/21 15:59:20 +1
Sigurður Ásgeirsson 2016/08/19 18:21:49 Done.
Sigurður Ásgeirsson 2016/08/19 18:21:49 Done.
162 // TODO(siggi): Is this even a good idea?
163 usage_at_creation_ = AllocatorUsage();
164 }
165 }
166
167 ScopedHeapUsage::~ScopedHeapUsage() {
168 if (thread_usage_ != nullptr &&
169 usage_at_creation_.max_allocated_bytes >
170 thread_usage_->max_allocated_bytes) {
171 // Restore the outer scope's max allocation tally, as it's larger than
172 // our scope's max.
chrisha 2016/07/21 14:23:30 This mechanism requires that scopes be properly ne
Primiano Tucci (use gerrit) 2016/07/21 15:59:20 maybe you can have a global Atomic32 g_scoped_heap
Sigurður Ásgeirsson 2016/08/19 18:21:49 I'd prefer to just document this problem away, but
Sigurður Ásgeirsson 2016/08/19 18:21:49 Acknowledged.
173 thread_usage_->max_allocated_bytes = usage_at_creation_.max_allocated_bytes;
174 }
175 }
176
177 ScopedHeapUsage::AllocatorUsage ScopedHeapUsage::Now() {
178 AllocatorUsage* usage = GetOrCreateThreadUsage();
179 if (usage == nullptr)
chrisha 2016/07/21 14:23:30 Can this even be null?
Sigurður Ásgeirsson 2016/08/19 18:21:49 Done.
180 return AllocatorUsage();
181
182 return *usage;
183 }
184
185 void ScopedHeapUsage::Initialize() {
186 InsertAllocatorDispatch(&allocator_dispatch);
187 }
188
189 void ScopedHeapUsage::TearDownForTesting() {
190 RemoveAllocatorDispatchForTesting(&allocator_dispatch);
191 }
192
193 } // namespace debug
194 } // namespace base
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698