Mercurial > hg > truffle
annotate src/share/vm/services/mallocTracker.hpp @ 21048:013a466838b9
Merge.
author | Doug Simon <doug.simon@oracle.com> |
---|---|
date | Mon, 20 Apr 2015 19:36:37 +0200 |
parents | ec2c6fdd1ce6 |
children |
rev | line source |
---|---|
20360 | 1 /* |
2 * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. | |
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
4 * | |
5 * This code is free software; you can redistribute it and/or modify it | |
6 * under the terms of the GNU General Public License version 2 only, as | |
7 * published by the Free Software Foundation. | |
8 * | |
9 * This code is distributed in the hope that it will be useful, but WITHOUT | |
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
12 * version 2 for more details (a copy is included in the LICENSE file that | |
13 * accompanied this code). | |
14 * | |
15 * You should have received a copy of the GNU General Public License version | |
16 * 2 along with this work; if not, write to the Free Software Foundation, | |
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
18 * | |
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |
20 * or visit www.oracle.com if you need additional information or have any | |
21 * questions. | |
22 * | |
23 */ | |
24 | |
25 #ifndef SHARE_VM_SERVICES_MALLOC_TRACKER_HPP | |
26 #define SHARE_VM_SERVICES_MALLOC_TRACKER_HPP | |
27 | |
28 #if INCLUDE_NMT | |
29 | |
30 #include "memory/allocation.hpp" | |
31 #include "runtime/atomic.hpp" | |
32 #include "services/nmtCommon.hpp" | |
33 #include "utilities/nativeCallStack.hpp" | |
34 | |
35 /* | |
36 * This counter class counts memory allocation and deallocation, | |
37 * records total memory allocation size and number of allocations. | |
38 * The counters are updated atomically. | |
39 */ | |
40 class MemoryCounter VALUE_OBJ_CLASS_SPEC { | |
41 private: | |
42 size_t _count; | |
43 size_t _size; | |
44 | |
45 DEBUG_ONLY(size_t _peak_count;) | |
46 DEBUG_ONLY(size_t _peak_size; ) | |
47 | |
48 public: | |
49 MemoryCounter() : _count(0), _size(0) { | |
50 DEBUG_ONLY(_peak_count = 0;) | |
51 DEBUG_ONLY(_peak_size = 0;) | |
52 } | |
53 | |
54 inline void allocate(size_t sz) { | |
55 Atomic::add(1, (volatile MemoryCounterType*)&_count); | |
56 if (sz > 0) { | |
57 Atomic::add((MemoryCounterType)sz, (volatile MemoryCounterType*)&_size); | |
58 DEBUG_ONLY(_peak_size = MAX2(_peak_size, _size)); | |
59 } | |
60 DEBUG_ONLY(_peak_count = MAX2(_peak_count, _count);) | |
61 } | |
62 | |
63 inline void deallocate(size_t sz) { | |
64 assert(_count > 0, "Negative counter"); | |
65 assert(_size >= sz, "Negative size"); | |
66 Atomic::add(-1, (volatile MemoryCounterType*)&_count); | |
67 if (sz > 0) { | |
68 Atomic::add(-(MemoryCounterType)sz, (volatile MemoryCounterType*)&_size); | |
69 } | |
70 } | |
71 | |
72 inline void resize(long sz) { | |
73 if (sz != 0) { | |
74 Atomic::add((MemoryCounterType)sz, (volatile MemoryCounterType*)&_size); | |
75 DEBUG_ONLY(_peak_size = MAX2(_size, _peak_size);) | |
76 } | |
77 } | |
78 | |
79 inline size_t count() const { return _count; } | |
80 inline size_t size() const { return _size; } | |
81 DEBUG_ONLY(inline size_t peak_count() const { return _peak_count; }) | |
82 DEBUG_ONLY(inline size_t peak_size() const { return _peak_size; }) | |
83 | |
84 }; | |
85 | |
86 /* | |
87 * Malloc memory used by a particular subsystem. | |
88 * It includes the memory acquired through os::malloc() | |
89 * call and arena's backing memory. | |
90 */ | |
91 class MallocMemory VALUE_OBJ_CLASS_SPEC { | |
92 private: | |
93 MemoryCounter _malloc; | |
94 MemoryCounter _arena; | |
95 | |
96 public: | |
97 MallocMemory() { } | |
98 | |
99 inline void record_malloc(size_t sz) { | |
100 _malloc.allocate(sz); | |
101 } | |
102 | |
103 inline void record_free(size_t sz) { | |
104 _malloc.deallocate(sz); | |
105 } | |
106 | |
107 inline void record_new_arena() { | |
108 _arena.allocate(0); | |
109 } | |
110 | |
111 inline void record_arena_free() { | |
112 _arena.deallocate(0); | |
113 } | |
114 | |
115 inline void record_arena_size_change(long sz) { | |
116 _arena.resize(sz); | |
117 } | |
118 | |
119 inline size_t malloc_size() const { return _malloc.size(); } | |
120 inline size_t malloc_count() const { return _malloc.count();} | |
121 inline size_t arena_size() const { return _arena.size(); } | |
122 inline size_t arena_count() const { return _arena.count(); } | |
123 | |
124 DEBUG_ONLY(inline const MemoryCounter& malloc_counter() const { return _malloc; }) | |
125 DEBUG_ONLY(inline const MemoryCounter& arena_counter() const { return _arena; }) | |
126 }; | |
127 | |
128 class MallocMemorySummary; | |
129 | |
130 // A snapshot of malloc'd memory, includes malloc memory | |
131 // usage by types and memory used by tracking itself. | |
132 class MallocMemorySnapshot : public ResourceObj { | |
133 friend class MallocMemorySummary; | |
134 | |
135 private: | |
136 MallocMemory _malloc[mt_number_of_types]; | |
137 MemoryCounter _tracking_header; | |
138 | |
139 | |
140 public: | |
141 inline MallocMemory* by_type(MEMFLAGS flags) { | |
142 int index = NMTUtil::flag_to_index(flags); | |
143 return &_malloc[index]; | |
144 } | |
145 | |
146 inline MallocMemory* by_index(int index) { | |
147 assert(index >= 0, "Index out of bound"); | |
148 assert(index < mt_number_of_types, "Index out of bound"); | |
149 return &_malloc[index]; | |
150 } | |
151 | |
152 inline MemoryCounter* malloc_overhead() { | |
153 return &_tracking_header; | |
154 } | |
155 | |
156 // Total malloc'd memory amount | |
157 size_t total() const; | |
158 // Total malloc'd memory used by arenas | |
159 size_t total_arena() const; | |
160 | |
20366 | 161 inline size_t thread_count() const { |
162 MallocMemorySnapshot* s = const_cast<MallocMemorySnapshot*>(this); | |
163 return s->by_type(mtThreadStack)->malloc_count(); | |
20360 | 164 } |
165 | |
166 void copy_to(MallocMemorySnapshot* s) { | |
167 s->_tracking_header = _tracking_header; | |
168 for (int index = 0; index < mt_number_of_types; index ++) { | |
169 s->_malloc[index] = _malloc[index]; | |
170 } | |
171 } | |
172 | |
173 // Make adjustment by subtracting chunks used by arenas | |
174 // from total chunks to get total free chunk size | |
175 void make_adjustment(); | |
176 }; | |
177 | |
178 /* | |
179 * This class is for collecting malloc statistics at summary level | |
180 */ | |
181 class MallocMemorySummary : AllStatic { | |
182 private: | |
183 // Reserve memory for placement of MallocMemorySnapshot object | |
184 static size_t _snapshot[CALC_OBJ_SIZE_IN_TYPE(MallocMemorySnapshot, size_t)]; | |
185 | |
186 public: | |
187 static void initialize(); | |
188 | |
189 static inline void record_malloc(size_t size, MEMFLAGS flag) { | |
190 as_snapshot()->by_type(flag)->record_malloc(size); | |
191 } | |
192 | |
193 static inline void record_free(size_t size, MEMFLAGS flag) { | |
194 as_snapshot()->by_type(flag)->record_free(size); | |
195 } | |
196 | |
197 static inline void record_new_arena(MEMFLAGS flag) { | |
198 as_snapshot()->by_type(flag)->record_new_arena(); | |
199 } | |
200 | |
201 static inline void record_arena_free(MEMFLAGS flag) { | |
202 as_snapshot()->by_type(flag)->record_arena_free(); | |
203 } | |
204 | |
205 static inline void record_arena_size_change(long size, MEMFLAGS flag) { | |
206 as_snapshot()->by_type(flag)->record_arena_size_change(size); | |
207 } | |
208 | |
209 static void snapshot(MallocMemorySnapshot* s) { | |
210 as_snapshot()->copy_to(s); | |
211 s->make_adjustment(); | |
212 } | |
213 | |
214 // Record memory used by malloc tracking header | |
215 static inline void record_new_malloc_header(size_t sz) { | |
216 as_snapshot()->malloc_overhead()->allocate(sz); | |
217 } | |
218 | |
219 static inline void record_free_malloc_header(size_t sz) { | |
220 as_snapshot()->malloc_overhead()->deallocate(sz); | |
221 } | |
222 | |
223 // The memory used by malloc tracking headers | |
224 static inline size_t tracking_overhead() { | |
225 return as_snapshot()->malloc_overhead()->size(); | |
226 } | |
227 | |
228 static MallocMemorySnapshot* as_snapshot() { | |
229 return (MallocMemorySnapshot*)_snapshot; | |
230 } | |
231 }; | |
232 | |
233 | |
234 /* | |
235 * Malloc tracking header. | |
236 * To satisfy malloc alignment requirement, NMT uses 2 machine words for tracking purpose, | |
237 * which ensures 8-bytes alignment on 32-bit systems and 16-bytes on 64-bit systems (Product build). | |
238 */ | |
239 | |
240 class MallocHeader VALUE_OBJ_CLASS_SPEC { | |
241 #ifdef _LP64 | |
20630
787c9c28311f
8058251: assert(_count > 0) failed: Negative counter when running runtime/NMT/MallocTrackingVerify.java
ctornqvi
parents:
20553
diff
changeset
|
242 size_t _size : 64; |
20360 | 243 size_t _flags : 8; |
244 size_t _pos_idx : 16; | |
245 size_t _bucket_idx: 40; | |
20642
ec2c6fdd1ce6
8062870: src/share/vm/services/mallocTracker.hpp:64 assert(_count > 0) failed: Negative counter
coleenp
parents:
20630
diff
changeset
|
246 #define MAX_MALLOCSITE_TABLE_SIZE right_n_bits(40) |
ec2c6fdd1ce6
8062870: src/share/vm/services/mallocTracker.hpp:64 assert(_count > 0) failed: Negative counter
coleenp
parents:
20630
diff
changeset
|
247 #define MAX_BUCKET_LENGTH right_n_bits(16) |
20360 | 248 #else |
20630
787c9c28311f
8058251: assert(_count > 0) failed: Negative counter when running runtime/NMT/MallocTrackingVerify.java
ctornqvi
parents:
20553
diff
changeset
|
249 size_t _size : 32; |
20360 | 250 size_t _flags : 8; |
251 size_t _pos_idx : 8; | |
252 size_t _bucket_idx: 16; | |
20642
ec2c6fdd1ce6
8062870: src/share/vm/services/mallocTracker.hpp:64 assert(_count > 0) failed: Negative counter
coleenp
parents:
20630
diff
changeset
|
253 #define MAX_MALLOCSITE_TABLE_SIZE right_n_bits(16) |
ec2c6fdd1ce6
8062870: src/share/vm/services/mallocTracker.hpp:64 assert(_count > 0) failed: Negative counter
coleenp
parents:
20630
diff
changeset
|
254 #define MAX_BUCKET_LENGTH right_n_bits(8) |
20360 | 255 #endif // _LP64 |
256 | |
257 public: | |
20630
787c9c28311f
8058251: assert(_count > 0) failed: Negative counter when running runtime/NMT/MallocTrackingVerify.java
ctornqvi
parents:
20553
diff
changeset
|
258 MallocHeader(size_t size, MEMFLAGS flags, const NativeCallStack& stack, NMT_TrackingLevel level) { |
20360 | 259 assert(sizeof(MallocHeader) == sizeof(void*) * 2, |
260 "Wrong header size"); | |
261 | |
20630
787c9c28311f
8058251: assert(_count > 0) failed: Negative counter when running runtime/NMT/MallocTrackingVerify.java
ctornqvi
parents:
20553
diff
changeset
|
262 if (level == NMT_minimal) { |
787c9c28311f
8058251: assert(_count > 0) failed: Negative counter when running runtime/NMT/MallocTrackingVerify.java
ctornqvi
parents:
20553
diff
changeset
|
263 return; |
787c9c28311f
8058251: assert(_count > 0) failed: Negative counter when running runtime/NMT/MallocTrackingVerify.java
ctornqvi
parents:
20553
diff
changeset
|
264 } |
787c9c28311f
8058251: assert(_count > 0) failed: Negative counter when running runtime/NMT/MallocTrackingVerify.java
ctornqvi
parents:
20553
diff
changeset
|
265 |
20360 | 266 _flags = flags; |
267 set_size(size); | |
20630
787c9c28311f
8058251: assert(_count > 0) failed: Negative counter when running runtime/NMT/MallocTrackingVerify.java
ctornqvi
parents:
20553
diff
changeset
|
268 if (level == NMT_detail) { |
787c9c28311f
8058251: assert(_count > 0) failed: Negative counter when running runtime/NMT/MallocTrackingVerify.java
ctornqvi
parents:
20553
diff
changeset
|
269 size_t bucket_idx; |
787c9c28311f
8058251: assert(_count > 0) failed: Negative counter when running runtime/NMT/MallocTrackingVerify.java
ctornqvi
parents:
20553
diff
changeset
|
270 size_t pos_idx; |
787c9c28311f
8058251: assert(_count > 0) failed: Negative counter when running runtime/NMT/MallocTrackingVerify.java
ctornqvi
parents:
20553
diff
changeset
|
271 if (record_malloc_site(stack, size, &bucket_idx, &pos_idx)) { |
787c9c28311f
8058251: assert(_count > 0) failed: Negative counter when running runtime/NMT/MallocTrackingVerify.java
ctornqvi
parents:
20553
diff
changeset
|
272 assert(bucket_idx <= MAX_MALLOCSITE_TABLE_SIZE, "Overflow bucket index"); |
787c9c28311f
8058251: assert(_count > 0) failed: Negative counter when running runtime/NMT/MallocTrackingVerify.java
ctornqvi
parents:
20553
diff
changeset
|
273 assert(pos_idx <= MAX_BUCKET_LENGTH, "Overflow bucket position index"); |
787c9c28311f
8058251: assert(_count > 0) failed: Negative counter when running runtime/NMT/MallocTrackingVerify.java
ctornqvi
parents:
20553
diff
changeset
|
274 _bucket_idx = bucket_idx; |
787c9c28311f
8058251: assert(_count > 0) failed: Negative counter when running runtime/NMT/MallocTrackingVerify.java
ctornqvi
parents:
20553
diff
changeset
|
275 _pos_idx = pos_idx; |
787c9c28311f
8058251: assert(_count > 0) failed: Negative counter when running runtime/NMT/MallocTrackingVerify.java
ctornqvi
parents:
20553
diff
changeset
|
276 } |
20360 | 277 } |
20630
787c9c28311f
8058251: assert(_count > 0) failed: Negative counter when running runtime/NMT/MallocTrackingVerify.java
ctornqvi
parents:
20553
diff
changeset
|
278 |
20360 | 279 MallocMemorySummary::record_malloc(size, flags); |
280 MallocMemorySummary::record_new_malloc_header(sizeof(MallocHeader)); | |
281 } | |
282 | |
283 inline size_t size() const { return _size; } | |
284 inline MEMFLAGS flags() const { return (MEMFLAGS)_flags; } | |
285 bool get_stack(NativeCallStack& stack) const; | |
286 | |
287 // Cleanup tracking information before the memory is released. | |
288 void release() const; | |
289 | |
290 private: | |
291 inline void set_size(size_t size) { | |
292 _size = size; | |
293 } | |
294 bool record_malloc_site(const NativeCallStack& stack, size_t size, | |
295 size_t* bucket_idx, size_t* pos_idx) const; | |
296 }; | |
297 | |
298 | |
299 // Main class called from MemTracker to track malloc activities | |
300 class MallocTracker : AllStatic { | |
301 public: | |
302 // Initialize malloc tracker for specific tracking level | |
303 static bool initialize(NMT_TrackingLevel level); | |
304 | |
305 static bool transition(NMT_TrackingLevel from, NMT_TrackingLevel to); | |
306 | |
307 // malloc tracking header size for specific tracking level | |
308 static inline size_t malloc_header_size(NMT_TrackingLevel level) { | |
309 return (level == NMT_off) ? 0 : sizeof(MallocHeader); | |
310 } | |
311 | |
312 // Parameter name convention: | |
313 // memblock : the beginning address for user data | |
314 // malloc_base: the beginning address that includes malloc tracking header | |
315 // | |
316 // The relationship: | |
317 // memblock = (char*)malloc_base + sizeof(nmt header) | |
318 // | |
319 | |
320 // Record malloc on specified memory block | |
321 static void* record_malloc(void* malloc_base, size_t size, MEMFLAGS flags, | |
322 const NativeCallStack& stack, NMT_TrackingLevel level); | |
323 | |
324 // Record free on specified memory block | |
325 static void* record_free(void* memblock); | |
326 | |
327 // Offset memory address to header address | |
328 static inline void* get_base(void* memblock); | |
329 static inline void* get_base(void* memblock, NMT_TrackingLevel level) { | |
330 if (memblock == NULL || level == NMT_off) return memblock; | |
331 return (char*)memblock - malloc_header_size(level); | |
332 } | |
333 | |
334 // Get memory size | |
335 static inline size_t get_size(void* memblock) { | |
336 MallocHeader* header = malloc_header(memblock); | |
337 return header->size(); | |
338 } | |
339 | |
340 // Get memory type | |
341 static inline MEMFLAGS get_flags(void* memblock) { | |
342 MallocHeader* header = malloc_header(memblock); | |
343 return header->flags(); | |
344 } | |
345 | |
346 // Get header size | |
347 static inline size_t get_header_size(void* memblock) { | |
348 return (memblock == NULL) ? 0 : sizeof(MallocHeader); | |
349 } | |
350 | |
351 static inline void record_new_arena(MEMFLAGS flags) { | |
352 MallocMemorySummary::record_new_arena(flags); | |
353 } | |
354 | |
355 static inline void record_arena_free(MEMFLAGS flags) { | |
356 MallocMemorySummary::record_arena_free(flags); | |
357 } | |
358 | |
359 static inline void record_arena_size_change(int size, MEMFLAGS flags) { | |
360 MallocMemorySummary::record_arena_size_change(size, flags); | |
361 } | |
362 private: | |
363 static inline MallocHeader* malloc_header(void *memblock) { | |
364 assert(memblock != NULL, "NULL pointer"); | |
365 MallocHeader* header = (MallocHeader*)((char*)memblock - sizeof(MallocHeader)); | |
366 return header; | |
367 } | |
368 }; | |
369 | |
370 #endif // INCLUDE_NMT | |
371 | |
372 | |
373 #endif //SHARE_VM_SERVICES_MALLOC_TRACKER_HPP |