Fri, 09 Nov 2012 19:24:31 -0500
8001592: NMT: assertion failed: assert(_amount >= amt) failed: Just check: memBaseline.hpp:180
Summary: Fixed NMT that miscounted arena memory when it is used as value or stack object.
Reviewed-by: acorn, coleenp
1 /*
2 * Copyright (c) 2012, 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 */
25 #ifndef SHARE_VM_SERVICES_MEM_BASELINE_HPP
26 #define SHARE_VM_SERVICES_MEM_BASELINE_HPP
28 #include "memory/allocation.hpp"
29 #include "runtime/mutex.hpp"
30 #include "services/memPtr.hpp"
31 #include "services/memSnapshot.hpp"
33 // compare unsigned number
34 #define UNSIGNED_COMPARE(a, b) ((a > b) ? 1 : ((a == b) ? 0 : -1))
36 /*
37 * MallocCallsitePointer and VMCallsitePointer are used
38 * to baseline memory blocks with their callsite information.
39 * They are only available when detail tracking is turned
40 * on.
41 */
43 /* baselined malloc record aggregated by callsite */
44 class MallocCallsitePointer : public MemPointer {
45 private:
46 size_t _count; // number of malloc invocation from this callsite
47 size_t _amount; // total amount of memory malloc-ed from this callsite
49 public:
50 MallocCallsitePointer() {
51 _count = 0;
52 _amount = 0;
53 }
55 MallocCallsitePointer(address pc) : MemPointer(pc) {
56 _count = 0;
57 _amount = 0;
58 }
60 MallocCallsitePointer& operator=(const MallocCallsitePointer& p) {
61 MemPointer::operator=(p);
62 _count = p.count();
63 _amount = p.amount();
64 return *this;
65 }
67 inline void inc(size_t size) {
68 _count ++;
69 _amount += size;
70 };
72 inline size_t count() const {
73 return _count;
74 }
76 inline size_t amount() const {
77 return _amount;
78 }
79 };
81 // baselined virtual memory record aggregated by callsite
82 class VMCallsitePointer : public MemPointer {
83 private:
84 size_t _count; // number of invocation from this callsite
85 size_t _reserved_amount; // total reserved amount
86 size_t _committed_amount; // total committed amount
88 public:
89 VMCallsitePointer() {
90 _count = 0;
91 _reserved_amount = 0;
92 _committed_amount = 0;
93 }
95 VMCallsitePointer(address pc) : MemPointer(pc) {
96 _count = 0;
97 _reserved_amount = 0;
98 _committed_amount = 0;
99 }
101 VMCallsitePointer& operator=(const VMCallsitePointer& p) {
102 MemPointer::operator=(p);
103 _count = p.count();
104 _reserved_amount = p.reserved_amount();
105 _committed_amount = p.committed_amount();
106 return *this;
107 }
109 inline void inc(size_t reserved, size_t committed) {
110 _count ++;
111 _reserved_amount += reserved;
112 _committed_amount += committed;
113 }
115 inline size_t count() const {
116 return _count;
117 }
119 inline size_t reserved_amount() const {
120 return _reserved_amount;
121 }
123 inline size_t committed_amount() const {
124 return _committed_amount;
125 }
126 };
128 // maps a memory type flag to readable name
129 typedef struct _memType2Name {
130 MEMFLAGS _flag;
131 const char* _name;
132 } MemType2Name;
135 // This class aggregates malloc'd records by memory type
136 class MallocMem : public _ValueObj {
137 private:
138 MEMFLAGS _type;
140 size_t _count;
141 size_t _amount;
143 public:
144 MallocMem() {
145 _type = mtNone;
146 _count = 0;
147 _amount = 0;
148 }
150 MallocMem(MEMFLAGS flags) {
151 assert(HAS_VALID_MEMORY_TYPE(flags), "no type");
152 _type = FLAGS_TO_MEMORY_TYPE(flags);
153 _count = 0;
154 _amount = 0;
155 }
157 inline void set_type(MEMFLAGS flag) {
158 _type = flag;
159 }
161 inline void clear() {
162 _count = 0;
163 _amount = 0;
164 _type = mtNone;
165 }
167 MallocMem& operator=(const MallocMem& m) {
168 assert(_type == m.type(), "different type");
169 _count = m.count();
170 _amount = m.amount();
171 return *this;
172 }
174 inline void inc(size_t amt) {
175 _amount += amt;
176 _count ++;
177 }
179 inline void reduce(size_t amt) {
180 assert(_amount >= amt, "Just check");
181 _amount -= amt;
182 }
184 inline void overwrite_counter(size_t count) {
185 _count = count;
186 }
188 inline MEMFLAGS type() const {
189 return _type;
190 }
192 inline bool is_type(MEMFLAGS flags) const {
193 return FLAGS_TO_MEMORY_TYPE(flags) == _type;
194 }
196 inline size_t count() const {
197 return _count;
198 }
200 inline size_t amount() const {
201 return _amount;
202 }
203 };
205 // This class records live arena's memory usage
206 class ArenaMem : public MallocMem {
207 public:
208 ArenaMem(MEMFLAGS typeflag): MallocMem(typeflag) {
209 }
210 ArenaMem() { }
211 };
213 // This class aggregates virtual memory by its memory type
214 class VMMem : public _ValueObj {
215 private:
216 MEMFLAGS _type;
218 size_t _count;
219 size_t _reserved_amount;
220 size_t _committed_amount;
222 public:
223 VMMem() {
224 _type = mtNone;
225 _count = 0;
226 _reserved_amount = 0;
227 _committed_amount = 0;
228 }
230 VMMem(MEMFLAGS flags) {
231 assert(HAS_VALID_MEMORY_TYPE(flags), "no type");
232 _type = FLAGS_TO_MEMORY_TYPE(flags);
233 _count = 0;
234 _reserved_amount = 0;
235 _committed_amount = 0;
236 }
238 inline void clear() {
239 _type = mtNone;
240 _count = 0;
241 _reserved_amount = 0;
242 _committed_amount = 0;
243 }
245 inline void set_type(MEMFLAGS flags) {
246 _type = FLAGS_TO_MEMORY_TYPE(flags);
247 }
249 VMMem& operator=(const VMMem& m) {
250 assert(_type == m.type(), "different type");
252 _count = m.count();
253 _reserved_amount = m.reserved_amount();
254 _committed_amount = m.committed_amount();
255 return *this;
256 }
259 inline MEMFLAGS type() const {
260 return _type;
261 }
263 inline bool is_type(MEMFLAGS flags) const {
264 return FLAGS_TO_MEMORY_TYPE(flags) == _type;
265 }
267 inline void inc(size_t reserved_amt, size_t committed_amt) {
268 _reserved_amount += reserved_amt;
269 _committed_amount += committed_amt;
270 _count ++;
271 }
273 inline size_t count() const {
274 return _count;
275 }
277 inline size_t reserved_amount() const {
278 return _reserved_amount;
279 }
281 inline size_t committed_amount() const {
282 return _committed_amount;
283 }
284 };
288 #define NUMBER_OF_MEMORY_TYPE (mt_number_of_types + 1)
290 class BaselineReporter;
291 class BaselineComparisonReporter;
293 /*
294 * This class baselines current memory snapshot.
295 * A memory baseline summarizes memory usage by memory type,
296 * aggregates memory usage by callsites when detail tracking
297 * is on.
298 */
299 class MemBaseline : public _ValueObj {
300 friend class BaselineReporter;
301 friend class BaselineComparisonReporter;
303 private:
304 // overall summaries
305 size_t _total_malloced;
306 size_t _total_vm_reserved;
307 size_t _total_vm_committed;
308 size_t _number_of_classes;
309 size_t _number_of_threads;
311 // if it has properly baselined
312 bool _baselined;
314 // we categorize memory into three categories within the memory type
315 MallocMem _malloc_data[NUMBER_OF_MEMORY_TYPE];
316 VMMem _vm_data[NUMBER_OF_MEMORY_TYPE];
317 ArenaMem _arena_data[NUMBER_OF_MEMORY_TYPE];
319 // memory records that aggregate memory usage by callsites.
320 // only available when detail tracking is on.
321 MemPointerArray* _malloc_cs;
322 MemPointerArray* _vm_cs;
323 // virtual memory map
324 MemPointerArray* _vm_map;
326 private:
327 static MemType2Name MemType2NameMap[NUMBER_OF_MEMORY_TYPE];
329 private:
330 // should not use copy constructor
331 MemBaseline(MemBaseline& copy) { ShouldNotReachHere(); }
333 public:
334 // create a memory baseline
335 MemBaseline();
337 virtual ~MemBaseline();
339 inline bool baselined() const {
340 return _baselined;
341 }
343 MemBaseline& operator=(const MemBaseline& other);
345 // reset the baseline for reuse
346 void clear();
348 // baseline the snapshot
349 bool baseline(MemSnapshot& snapshot, bool summary_only = true);
351 bool baseline(const MemPointerArray* malloc_records,
352 const MemPointerArray* vm_records,
353 bool summary_only = true);
355 // total malloc'd memory of specified memory type
356 inline size_t malloc_amount(MEMFLAGS flag) const {
357 return _malloc_data[flag2index(flag)].amount();
358 }
359 // number of malloc'd memory blocks of specified memory type
360 inline size_t malloc_count(MEMFLAGS flag) const {
361 return _malloc_data[flag2index(flag)].count();
362 }
363 // total memory used by arenas of specified memory type
364 inline size_t arena_amount(MEMFLAGS flag) const {
365 return _arena_data[flag2index(flag)].amount();
366 }
367 // number of arenas of specified memory type
368 inline size_t arena_count(MEMFLAGS flag) const {
369 return _arena_data[flag2index(flag)].count();
370 }
371 // total reserved memory of specified memory type
372 inline size_t reserved_amount(MEMFLAGS flag) const {
373 return _vm_data[flag2index(flag)].reserved_amount();
374 }
375 // total committed memory of specified memory type
376 inline size_t committed_amount(MEMFLAGS flag) const {
377 return _vm_data[flag2index(flag)].committed_amount();
378 }
379 // total memory (malloc'd + mmap'd + arena) of specified
380 // memory type
381 inline size_t total_amount(MEMFLAGS flag) const {
382 int index = flag2index(flag);
383 return _malloc_data[index].amount() +
384 _vm_data[index].reserved_amount() +
385 _arena_data[index].amount();
386 }
388 /* overall summaries */
390 // total malloc'd memory in snapshot
391 inline size_t total_malloc_amount() const {
392 return _total_malloced;
393 }
394 // total mmap'd memory in snapshot
395 inline size_t total_reserved_amount() const {
396 return _total_vm_reserved;
397 }
398 // total committed memory in snapshot
399 inline size_t total_committed_amount() const {
400 return _total_vm_committed;
401 }
402 // number of loaded classes
403 inline size_t number_of_classes() const {
404 return _number_of_classes;
405 }
406 // number of running threads
407 inline size_t number_of_threads() const {
408 return _number_of_threads;
409 }
410 // lookup human readable name of a memory type
411 static const char* type2name(MEMFLAGS type);
413 private:
414 // convert memory flag to the index to mapping table
415 int flag2index(MEMFLAGS flag) const;
417 // reset baseline values
418 void reset();
420 // summarize the records in global snapshot
421 bool baseline_malloc_summary(const MemPointerArray* malloc_records);
422 bool baseline_vm_summary(const MemPointerArray* vm_records);
423 bool baseline_malloc_details(const MemPointerArray* malloc_records);
424 bool baseline_vm_details(const MemPointerArray* vm_records);
426 // print a line of malloc'd memory aggregated by callsite
427 void print_malloc_callsite(outputStream* st, address pc, size_t size,
428 size_t count, int diff_amt, int diff_count) const;
429 // print a line of mmap'd memory aggregated by callsite
430 void print_vm_callsite(outputStream* st, address pc, size_t rsz,
431 size_t csz, int diff_rsz, int diff_csz) const;
433 // sorting functions for raw records
434 static int malloc_sort_by_pc(const void* p1, const void* p2);
435 static int malloc_sort_by_addr(const void* p1, const void* p2);
437 private:
438 // sorting functions for baselined records
439 static int bl_malloc_sort_by_size(const void* p1, const void* p2);
440 static int bl_vm_sort_by_size(const void* p1, const void* p2);
441 static int bl_malloc_sort_by_pc(const void* p1, const void* p2);
442 static int bl_vm_sort_by_pc(const void* p1, const void* p2);
443 };
446 #endif // SHARE_VM_SERVICES_MEM_BASELINE_HPP