6197
|
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 */
|
|
24
|
|
25 #ifndef SHARE_VM_SERVICES_MEM_BASELINE_HPP
|
|
26 #define SHARE_VM_SERVICES_MEM_BASELINE_HPP
|
|
27
|
|
28 #include "memory/allocation.hpp"
|
|
29 #include "runtime/mutex.hpp"
|
|
30 #include "services/memPtr.hpp"
|
|
31 #include "services/memSnapshot.hpp"
|
|
32
|
|
33 // compare unsigned number
|
|
34 #define UNSIGNED_COMPARE(a, b) ((a > b) ? 1 : ((a == b) ? 0 : -1))
|
|
35
|
|
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 */
|
|
42
|
|
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
|
|
48
|
|
49 public:
|
|
50 MallocCallsitePointer() {
|
|
51 _count = 0;
|
|
52 _amount = 0;
|
|
53 }
|
|
54
|
|
55 MallocCallsitePointer(address pc) : MemPointer(pc) {
|
|
56 _count = 0;
|
|
57 _amount = 0;
|
|
58 }
|
|
59
|
|
60 MallocCallsitePointer& operator=(const MallocCallsitePointer& p) {
|
|
61 MemPointer::operator=(p);
|
|
62 _count = p.count();
|
|
63 _amount = p.amount();
|
|
64 return *this;
|
|
65 }
|
|
66
|
|
67 inline void inc(size_t size) {
|
|
68 _count ++;
|
|
69 _amount += size;
|
|
70 };
|
|
71
|
|
72 inline size_t count() const {
|
|
73 return _count;
|
|
74 }
|
|
75
|
|
76 inline size_t amount() const {
|
|
77 return _amount;
|
|
78 }
|
|
79 };
|
|
80
|
|
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
|
|
87
|
|
88 public:
|
|
89 VMCallsitePointer() {
|
|
90 _count = 0;
|
|
91 _reserved_amount = 0;
|
|
92 _committed_amount = 0;
|
|
93 }
|
|
94
|
|
95 VMCallsitePointer(address pc) : MemPointer(pc) {
|
|
96 _count = 0;
|
|
97 _reserved_amount = 0;
|
|
98 _committed_amount = 0;
|
|
99 }
|
|
100
|
|
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 }
|
|
108
|
|
109 inline void inc(size_t reserved, size_t committed) {
|
|
110 _count ++;
|
|
111 _reserved_amount += reserved;
|
|
112 _committed_amount += committed;
|
|
113 }
|
|
114
|
|
115 inline size_t count() const {
|
|
116 return _count;
|
|
117 }
|
|
118
|
|
119 inline size_t reserved_amount() const {
|
|
120 return _reserved_amount;
|
|
121 }
|
|
122
|
|
123 inline size_t committed_amount() const {
|
|
124 return _committed_amount;
|
|
125 }
|
|
126 };
|
|
127
|
|
128 // maps a memory type flag to readable name
|
|
129 typedef struct _memType2Name {
|
|
130 MEMFLAGS _flag;
|
|
131 const char* _name;
|
|
132 } MemType2Name;
|
|
133
|
|
134
|
|
135 // This class aggregates malloc'd records by memory type
|
|
136 class MallocMem : public _ValueObj {
|
|
137 private:
|
|
138 MEMFLAGS _type;
|
|
139
|
|
140 size_t _count;
|
|
141 size_t _amount;
|
|
142
|
|
143 public:
|
|
144 MallocMem() {
|
|
145 _type = mtNone;
|
|
146 _count = 0;
|
|
147 _amount = 0;
|
|
148 }
|
|
149
|
|
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 }
|
|
156
|
|
157 inline void set_type(MEMFLAGS flag) {
|
|
158 _type = flag;
|
|
159 }
|
|
160
|
|
161 inline void clear() {
|
|
162 _count = 0;
|
|
163 _amount = 0;
|
|
164 _type = mtNone;
|
|
165 }
|
|
166
|
|
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 }
|
|
173
|
|
174 inline void inc(size_t amt) {
|
|
175 _amount += amt;
|
|
176 _count ++;
|
|
177 }
|
|
178
|
|
179 inline void reduce(size_t amt) {
|
|
180 assert(_amount >= amt, "Just check");
|
|
181 _amount -= amt;
|
|
182 }
|
|
183
|
|
184 inline void overwrite_counter(size_t count) {
|
|
185 _count = count;
|
|
186 }
|
|
187
|
|
188 inline MEMFLAGS type() const {
|
|
189 return _type;
|
|
190 }
|
|
191
|
|
192 inline bool is_type(MEMFLAGS flags) const {
|
|
193 return FLAGS_TO_MEMORY_TYPE(flags) == _type;
|
|
194 }
|
|
195
|
|
196 inline size_t count() const {
|
|
197 return _count;
|
|
198 }
|
|
199
|
|
200 inline size_t amount() const {
|
|
201 return _amount;
|
|
202 }
|
|
203 };
|
|
204
|
|
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 };
|
|
212
|
|
213 // This class aggregates virtual memory by its memory type
|
|
214 class VMMem : public _ValueObj {
|
|
215 private:
|
|
216 MEMFLAGS _type;
|
|
217
|
|
218 size_t _count;
|
|
219 size_t _reserved_amount;
|
|
220 size_t _committed_amount;
|
|
221
|
|
222 public:
|
|
223 VMMem() {
|
|
224 _type = mtNone;
|
|
225 _count = 0;
|
|
226 _reserved_amount = 0;
|
|
227 _committed_amount = 0;
|
|
228 }
|
|
229
|
|
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 }
|
|
237
|
|
238 inline void clear() {
|
|
239 _type = mtNone;
|
|
240 _count = 0;
|
|
241 _reserved_amount = 0;
|
|
242 _committed_amount = 0;
|
|
243 }
|
|
244
|
|
245 inline void set_type(MEMFLAGS flags) {
|
|
246 _type = FLAGS_TO_MEMORY_TYPE(flags);
|
|
247 }
|
|
248
|
|
249 VMMem& operator=(const VMMem& m) {
|
|
250 assert(_type == m.type(), "different type");
|
|
251
|
|
252 _count = m.count();
|
|
253 _reserved_amount = m.reserved_amount();
|
|
254 _committed_amount = m.committed_amount();
|
|
255 return *this;
|
|
256 }
|
|
257
|
|
258
|
|
259 inline MEMFLAGS type() const {
|
|
260 return _type;
|
|
261 }
|
|
262
|
|
263 inline bool is_type(MEMFLAGS flags) const {
|
|
264 return FLAGS_TO_MEMORY_TYPE(flags) == _type;
|
|
265 }
|
|
266
|
|
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 }
|
|
272
|
|
273 inline size_t count() const {
|
|
274 return _count;
|
|
275 }
|
|
276
|
|
277 inline size_t reserved_amount() const {
|
|
278 return _reserved_amount;
|
|
279 }
|
|
280
|
|
281 inline size_t committed_amount() const {
|
|
282 return _committed_amount;
|
|
283 }
|
|
284 };
|
|
285
|
|
286
|
|
287
|
|
288 #define NUMBER_OF_MEMORY_TYPE (mt_number_of_types + 1)
|
|
289
|
|
290 class BaselineReporter;
|
|
291 class BaselineComparisonReporter;
|
|
292
|
|
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;
|
|
302
|
|
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;
|
|
310
|
|
311 // if it has properly baselined
|
|
312 bool _baselined;
|
|
313
|
|
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];
|
|
318
|
|
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
|
|
324 private:
|
|
325 static MemType2Name MemType2NameMap[NUMBER_OF_MEMORY_TYPE];
|
|
326
|
|
327 private:
|
|
328 // should not use copy constructor
|
|
329 MemBaseline(MemBaseline& copy) { ShouldNotReachHere(); }
|
|
330
|
|
331 public:
|
|
332 // create a memory baseline
|
|
333 MemBaseline();
|
|
334
|
|
335 virtual ~MemBaseline();
|
|
336
|
|
337 inline bool baselined() const {
|
|
338 return _baselined;
|
|
339 }
|
|
340
|
|
341 MemBaseline& operator=(const MemBaseline& other);
|
|
342
|
|
343 // reset the baseline for reuse
|
|
344 void clear();
|
|
345
|
|
346 // baseline the snapshot
|
|
347 bool baseline(MemSnapshot& snapshot, bool summary_only = true);
|
|
348
|
|
349 bool baseline(const MemPointerArray* malloc_records,
|
|
350 const MemPointerArray* vm_records,
|
|
351 bool summary_only = true);
|
|
352
|
|
353 // total malloc'd memory of specified memory type
|
|
354 inline size_t malloc_amount(MEMFLAGS flag) const {
|
|
355 return _malloc_data[flag2index(flag)].amount();
|
|
356 }
|
|
357 // number of malloc'd memory blocks of specified memory type
|
|
358 inline size_t malloc_count(MEMFLAGS flag) const {
|
|
359 return _malloc_data[flag2index(flag)].count();
|
|
360 }
|
|
361 // total memory used by arenas of specified memory type
|
|
362 inline size_t arena_amount(MEMFLAGS flag) const {
|
|
363 return _arena_data[flag2index(flag)].amount();
|
|
364 }
|
|
365 // number of arenas of specified memory type
|
|
366 inline size_t arena_count(MEMFLAGS flag) const {
|
|
367 return _arena_data[flag2index(flag)].count();
|
|
368 }
|
|
369 // total reserved memory of specified memory type
|
|
370 inline size_t reserved_amount(MEMFLAGS flag) const {
|
|
371 return _vm_data[flag2index(flag)].reserved_amount();
|
|
372 }
|
|
373 // total committed memory of specified memory type
|
|
374 inline size_t committed_amount(MEMFLAGS flag) const {
|
|
375 return _vm_data[flag2index(flag)].committed_amount();
|
|
376 }
|
|
377 // total memory (malloc'd + mmap'd + arena) of specified
|
|
378 // memory type
|
|
379 inline size_t total_amount(MEMFLAGS flag) const {
|
|
380 int index = flag2index(flag);
|
|
381 return _malloc_data[index].amount() +
|
|
382 _vm_data[index].reserved_amount() +
|
|
383 _arena_data[index].amount();
|
|
384 }
|
|
385
|
|
386 /* overall summaries */
|
|
387
|
|
388 // total malloc'd memory in snapshot
|
|
389 inline size_t total_malloc_amount() const {
|
|
390 return _total_malloced;
|
|
391 }
|
|
392 // total mmap'd memory in snapshot
|
|
393 inline size_t total_reserved_amount() const {
|
|
394 return _total_vm_reserved;
|
|
395 }
|
|
396 // total committed memory in snapshot
|
|
397 inline size_t total_committed_amount() const {
|
|
398 return _total_vm_committed;
|
|
399 }
|
|
400 // number of loaded classes
|
|
401 inline size_t number_of_classes() const {
|
|
402 return _number_of_classes;
|
|
403 }
|
|
404 // number of running threads
|
|
405 inline size_t number_of_threads() const {
|
|
406 return _number_of_threads;
|
|
407 }
|
|
408 // lookup human readable name of a memory type
|
|
409 static const char* type2name(MEMFLAGS type);
|
|
410
|
|
411 private:
|
|
412 // convert memory flag to the index to mapping table
|
|
413 int flag2index(MEMFLAGS flag) const;
|
|
414
|
|
415 // reset baseline values
|
|
416 void reset();
|
|
417
|
|
418 // summarize the records in global snapshot
|
|
419 bool baseline_malloc_summary(const MemPointerArray* malloc_records);
|
|
420 bool baseline_vm_summary(const MemPointerArray* vm_records);
|
|
421 bool baseline_malloc_details(const MemPointerArray* malloc_records);
|
|
422 bool baseline_vm_details(const MemPointerArray* vm_records);
|
|
423
|
|
424 // print a line of malloc'd memory aggregated by callsite
|
|
425 void print_malloc_callsite(outputStream* st, address pc, size_t size,
|
|
426 size_t count, int diff_amt, int diff_count) const;
|
|
427 // print a line of mmap'd memory aggregated by callsite
|
|
428 void print_vm_callsite(outputStream* st, address pc, size_t rsz,
|
|
429 size_t csz, int diff_rsz, int diff_csz) const;
|
|
430
|
|
431 // sorting functions for raw records
|
|
432 static int malloc_sort_by_pc(const void* p1, const void* p2);
|
|
433 static int malloc_sort_by_addr(const void* p1, const void* p2);
|
|
434
|
|
435 static int vm_sort_by_pc(const void* p1, const void* p2);
|
|
436 static int vm_sort_by_addr(const void* p1, const void* p2);
|
|
437
|
|
438 private:
|
|
439 // sorting functions for baselined records
|
|
440 static int bl_malloc_sort_by_size(const void* p1, const void* p2);
|
|
441 static int bl_vm_sort_by_size(const void* p1, const void* p2);
|
|
442 static int bl_malloc_sort_by_pc(const void* p1, const void* p2);
|
|
443 static int bl_vm_sort_by_pc(const void* p1, const void* p2);
|
|
444 };
|
|
445
|
|
446
|
|
447 #endif // SHARE_VM_SERVICES_MEM_BASELINE_HPP
|