1 /*
2  * Copyright (c) 2012, 2019, 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 #include "precompiled.hpp"
25 
26 #include "memory/allocation.hpp"
27 #include "services/mallocTracker.hpp"
28 #include "services/memReporter.hpp"
29 #include "services/threadStackTracker.hpp"
30 #include "services/virtualMemoryTracker.hpp"
31 #include "utilities/globalDefinitions.hpp"
32 
reserved_total(const MallocMemory * malloc,const VirtualMemory * vm) const33 size_t MemReporterBase::reserved_total(const MallocMemory* malloc, const VirtualMemory* vm) const {
34   return malloc->malloc_size() + malloc->arena_size() + vm->reserved();
35 }
36 
committed_total(const MallocMemory * malloc,const VirtualMemory * vm) const37 size_t MemReporterBase::committed_total(const MallocMemory* malloc, const VirtualMemory* vm) const {
38   return malloc->malloc_size() + malloc->arena_size() + vm->committed();
39 }
40 
print_total(size_t reserved,size_t committed) const41 void MemReporterBase::print_total(size_t reserved, size_t committed) const {
42   const char* scale = current_scale();
43   output()->print("reserved=" SIZE_FORMAT "%s, committed=" SIZE_FORMAT "%s",
44     amount_in_current_scale(reserved), scale, amount_in_current_scale(committed), scale);
45 }
46 
print_malloc(size_t amount,size_t count,MEMFLAGS flag) const47 void MemReporterBase::print_malloc(size_t amount, size_t count, MEMFLAGS flag) const {
48   const char* scale = current_scale();
49   outputStream* out = output();
50   const char* alloc_type = (flag == mtThreadStack) ? "" : "malloc=";
51 
52   if (flag != mtNone) {
53     out->print("(%s" SIZE_FORMAT "%s type=%s", alloc_type,
54       amount_in_current_scale(amount), scale, NMTUtil::flag_to_name(flag));
55   } else {
56     out->print("(%s" SIZE_FORMAT "%s", alloc_type,
57       amount_in_current_scale(amount), scale);
58   }
59 
60   if (count > 0) {
61     out->print(" #" SIZE_FORMAT "", count);
62   }
63 
64   out->print(")");
65 }
66 
print_virtual_memory(size_t reserved,size_t committed) const67 void MemReporterBase::print_virtual_memory(size_t reserved, size_t committed) const {
68   const char* scale = current_scale();
69   output()->print("(mmap: reserved=" SIZE_FORMAT "%s, committed=" SIZE_FORMAT "%s)",
70     amount_in_current_scale(reserved), scale, amount_in_current_scale(committed), scale);
71 }
72 
print_malloc_line(size_t amount,size_t count) const73 void MemReporterBase::print_malloc_line(size_t amount, size_t count) const {
74   output()->print("%28s", " ");
75   print_malloc(amount, count);
76   output()->print_cr(" ");
77 }
78 
print_virtual_memory_line(size_t reserved,size_t committed) const79 void MemReporterBase::print_virtual_memory_line(size_t reserved, size_t committed) const {
80   output()->print("%28s", " ");
81   print_virtual_memory(reserved, committed);
82   output()->print_cr(" ");
83 }
84 
print_arena_line(size_t amount,size_t count) const85 void MemReporterBase::print_arena_line(size_t amount, size_t count) const {
86   const char* scale = current_scale();
87   output()->print_cr("%27s (arena=" SIZE_FORMAT "%s #" SIZE_FORMAT ")", " ",
88     amount_in_current_scale(amount), scale, count);
89 }
90 
print_virtual_memory_region(const char * type,address base,size_t size) const91 void MemReporterBase::print_virtual_memory_region(const char* type, address base, size_t size) const {
92   const char* scale = current_scale();
93   output()->print("[" PTR_FORMAT " - " PTR_FORMAT "] %s " SIZE_FORMAT "%s",
94     p2i(base), p2i(base + size), type, amount_in_current_scale(size), scale);
95 }
96 
97 
report()98 void MemSummaryReporter::report() {
99   const char* scale = current_scale();
100   outputStream* out = output();
101   size_t total_reserved_amount = _malloc_snapshot->total() +
102     _vm_snapshot->total_reserved();
103   size_t total_committed_amount = _malloc_snapshot->total() +
104     _vm_snapshot->total_committed();
105 
106   // Overall total
107   out->print_cr("\nNative Memory Tracking:\n");
108   out->print("Total: ");
109   print_total(total_reserved_amount, total_committed_amount);
110   out->print("\n");
111 
112   // Summary by memory type
113   for (int index = 0; index < mt_number_of_types; index ++) {
114     MEMFLAGS flag = NMTUtil::index_to_flag(index);
115     // thread stack is reported as part of thread category
116     if (flag == mtThreadStack) continue;
117     MallocMemory* malloc_memory = _malloc_snapshot->by_type(flag);
118     VirtualMemory* virtual_memory = _vm_snapshot->by_type(flag);
119 
120     report_summary_of_type(flag, malloc_memory, virtual_memory);
121   }
122 }
123 
report_summary_of_type(MEMFLAGS flag,MallocMemory * malloc_memory,VirtualMemory * virtual_memory)124 void MemSummaryReporter::report_summary_of_type(MEMFLAGS flag,
125   MallocMemory*  malloc_memory, VirtualMemory* virtual_memory) {
126 
127   size_t reserved_amount  = reserved_total (malloc_memory, virtual_memory);
128   size_t committed_amount = committed_total(malloc_memory, virtual_memory);
129 
130   // Count thread's native stack in "Thread" category
131   if (flag == mtThread) {
132     if (ThreadStackTracker::track_as_vm()) {
133       const VirtualMemory* thread_stack_usage =
134         (const VirtualMemory*)_vm_snapshot->by_type(mtThreadStack);
135       reserved_amount  += thread_stack_usage->reserved();
136       committed_amount += thread_stack_usage->committed();
137     } else {
138       const MallocMemory* thread_stack_usage =
139         (const MallocMemory*)_malloc_snapshot->by_type(mtThreadStack);
140       reserved_amount += thread_stack_usage->malloc_size();
141       committed_amount += thread_stack_usage->malloc_size();
142     }
143   } else if (flag == mtNMT) {
144     // Count malloc headers in "NMT" category
145     reserved_amount  += _malloc_snapshot->malloc_overhead()->size();
146     committed_amount += _malloc_snapshot->malloc_overhead()->size();
147   }
148 
149   if (amount_in_current_scale(reserved_amount) > 0) {
150     outputStream* out   = output();
151     const char*   scale = current_scale();
152     out->print("-%26s (", NMTUtil::flag_to_name(flag));
153     print_total(reserved_amount, committed_amount);
154     out->print_cr(")");
155 
156     if (flag == mtClass) {
157       // report class count
158       out->print_cr("%27s (classes #" SIZE_FORMAT ")",
159         " ", (_instance_class_count + _array_class_count));
160       out->print_cr("%27s (  instance classes #" SIZE_FORMAT ", array classes #" SIZE_FORMAT ")",
161         " ", _instance_class_count, _array_class_count);
162     } else if (flag == mtThread) {
163       if (ThreadStackTracker::track_as_vm()) {
164         const VirtualMemory* thread_stack_usage =
165          _vm_snapshot->by_type(mtThreadStack);
166         // report thread count
167         out->print_cr("%27s (thread #" SIZE_FORMAT ")", " ", ThreadStackTracker::thread_count());
168         out->print("%27s (stack: ", " ");
169         print_total(thread_stack_usage->reserved(), thread_stack_usage->committed());
170       } else {
171         MallocMemory* thread_stack_memory = _malloc_snapshot->by_type(mtThreadStack);
172         const char* scale = current_scale();
173         // report thread count
174         assert(ThreadStackTracker::thread_count() == 0, "Not used");
175         out->print_cr("%27s (thread #" SIZE_FORMAT ")", " ", thread_stack_memory->malloc_count());
176         out->print("%27s (Stack: " SIZE_FORMAT "%s", " ",
177           amount_in_current_scale(thread_stack_memory->malloc_size()), scale);
178       }
179       out->print_cr(")");
180     }
181 
182      // report malloc'd memory
183     if (amount_in_current_scale(malloc_memory->malloc_size()) > 0) {
184       // We don't know how many arena chunks are in used, so don't report the count
185       size_t count = (flag == mtChunk) ? 0 : malloc_memory->malloc_count();
186       print_malloc_line(malloc_memory->malloc_size(), count);
187     }
188 
189     if (amount_in_current_scale(virtual_memory->reserved()) > 0) {
190       print_virtual_memory_line(virtual_memory->reserved(), virtual_memory->committed());
191     }
192 
193     if (amount_in_current_scale(malloc_memory->arena_size()) > 0) {
194       print_arena_line(malloc_memory->arena_size(), malloc_memory->arena_count());
195     }
196 
197     if (flag == mtNMT &&
198       amount_in_current_scale(_malloc_snapshot->malloc_overhead()->size()) > 0) {
199       out->print_cr("%27s (tracking overhead=" SIZE_FORMAT "%s)", " ",
200         amount_in_current_scale(_malloc_snapshot->malloc_overhead()->size()), scale);
201     } else if (flag == mtClass) {
202       // Metadata information
203       report_metadata(Metaspace::NonClassType);
204       if (Metaspace::using_class_space()) {
205         report_metadata(Metaspace::ClassType);
206       }
207     }
208     out->print_cr(" ");
209   }
210 }
211 
report_metadata(Metaspace::MetadataType type) const212 void MemSummaryReporter::report_metadata(Metaspace::MetadataType type) const {
213   assert(type == Metaspace::NonClassType || type == Metaspace::ClassType,
214     "Invalid metadata type");
215   const char* name = (type == Metaspace::NonClassType) ?
216     "Metadata:   " : "Class space:";
217 
218   outputStream* out = output();
219   const char* scale = current_scale();
220   size_t committed   = MetaspaceUtils::committed_bytes(type);
221   size_t used = MetaspaceUtils::used_bytes(type);
222   size_t free = (MetaspaceUtils::capacity_bytes(type) - used)
223               + MetaspaceUtils::free_chunks_total_bytes(type)
224               + MetaspaceUtils::free_in_vs_bytes(type);
225 
226   assert(committed >= used + free, "Sanity");
227   size_t waste = committed - (used + free);
228 
229   out->print_cr("%27s (  %s)", " ", name);
230   out->print("%27s (    ", " ");
231   print_total(MetaspaceUtils::reserved_bytes(type), committed);
232   out->print_cr(")");
233   out->print_cr("%27s (    used=" SIZE_FORMAT "%s)", " ", amount_in_current_scale(used), scale);
234   out->print_cr("%27s (    free=" SIZE_FORMAT "%s)", " ", amount_in_current_scale(free), scale);
235   out->print_cr("%27s (    waste=" SIZE_FORMAT "%s =%2.2f%%)", " ", amount_in_current_scale(waste),
236     scale, ((float)waste * 100)/committed);
237 }
238 
report_detail()239 void MemDetailReporter::report_detail() {
240   // Start detail report
241   outputStream* out = output();
242   out->print_cr("Details:\n");
243 
244   report_malloc_sites();
245   report_virtual_memory_allocation_sites();
246 }
247 
report_malloc_sites()248 void MemDetailReporter::report_malloc_sites() {
249   MallocSiteIterator         malloc_itr = _baseline.malloc_sites(MemBaseline::by_size);
250   if (malloc_itr.is_empty()) return;
251 
252   outputStream* out = output();
253 
254   const MallocSite* malloc_site;
255   while ((malloc_site = malloc_itr.next()) != NULL) {
256     // Don't report if size is too small
257     if (amount_in_current_scale(malloc_site->size()) == 0)
258       continue;
259 
260     const NativeCallStack* stack = malloc_site->call_stack();
261     stack->print_on(out);
262     out->print("%29s", " ");
263     MEMFLAGS flag = malloc_site->flag();
264     assert((flag >= 0 && flag < (int)mt_number_of_types) && flag != mtNone,
265       "Must have a valid memory type");
266     print_malloc(malloc_site->size(), malloc_site->count(),flag);
267     out->print_cr("\n");
268   }
269 }
270 
report_virtual_memory_allocation_sites()271 void MemDetailReporter::report_virtual_memory_allocation_sites()  {
272   VirtualMemorySiteIterator  virtual_memory_itr =
273     _baseline.virtual_memory_sites(MemBaseline::by_size);
274 
275   if (virtual_memory_itr.is_empty()) return;
276 
277   outputStream* out = output();
278   const VirtualMemoryAllocationSite*  virtual_memory_site;
279 
280   while ((virtual_memory_site = virtual_memory_itr.next()) != NULL) {
281     // Don't report if size is too small
282     if (amount_in_current_scale(virtual_memory_site->reserved()) == 0)
283       continue;
284 
285     const NativeCallStack* stack = virtual_memory_site->call_stack();
286     stack->print_on(out);
287     out->print("%28s (", " ");
288     print_total(virtual_memory_site->reserved(), virtual_memory_site->committed());
289     MEMFLAGS flag = virtual_memory_site->flag();
290     if (flag != mtNone) {
291       out->print(" Type=%s", NMTUtil::flag_to_name(flag));
292     }
293     out->print_cr(")\n");
294   }
295 }
296 
297 
report_virtual_memory_map()298 void MemDetailReporter::report_virtual_memory_map() {
299   // Virtual memory map always in base address order
300   VirtualMemoryAllocationIterator itr = _baseline.virtual_memory_allocations();
301   const ReservedMemoryRegion* rgn;
302 
303   output()->print_cr("Virtual memory map:");
304   while ((rgn = itr.next()) != NULL) {
305     report_virtual_memory_region(rgn);
306   }
307 }
308 
report_virtual_memory_region(const ReservedMemoryRegion * reserved_rgn)309 void MemDetailReporter::report_virtual_memory_region(const ReservedMemoryRegion* reserved_rgn) {
310   assert(reserved_rgn != NULL, "NULL pointer");
311 
312   // Don't report if size is too small
313   if (amount_in_current_scale(reserved_rgn->size()) == 0) return;
314 
315   outputStream* out = output();
316   const char* scale = current_scale();
317   const NativeCallStack*  stack = reserved_rgn->call_stack();
318   bool all_committed = reserved_rgn->size() == reserved_rgn->committed_size();
319   const char* region_type = (all_committed ? "reserved and committed" : "reserved");
320   out->print_cr(" ");
321   print_virtual_memory_region(region_type, reserved_rgn->base(), reserved_rgn->size());
322   out->print(" for %s", NMTUtil::flag_to_name(reserved_rgn->flag()));
323   if (stack->is_empty()) {
324     out->print_cr(" ");
325   } else {
326     out->print_cr(" from");
327     stack->print_on(out, 4);
328   }
329 
330   if (all_committed) {
331     CommittedRegionIterator itr = reserved_rgn->iterate_committed_regions();
332     const CommittedMemoryRegion* committed_rgn = itr.next();
333     if (committed_rgn->size() == reserved_rgn->size() && committed_rgn->call_stack()->equals(*stack)) {
334       // One region spanning the entire reserved region, with the same stack trace.
335       // Don't print this regions because the "reserved and committed" line above
336       // already indicates that the region is comitted.
337       assert(itr.next() == NULL, "Unexpectedly more than one regions");
338       return;
339     }
340   }
341 
342   CommittedRegionIterator itr = reserved_rgn->iterate_committed_regions();
343   const CommittedMemoryRegion* committed_rgn;
344   while ((committed_rgn = itr.next()) != NULL) {
345     // Don't report if size is too small
346     if (amount_in_current_scale(committed_rgn->size()) == 0) continue;
347     stack = committed_rgn->call_stack();
348     out->print("\n\t");
349     print_virtual_memory_region("committed", committed_rgn->base(), committed_rgn->size());
350     if (stack->is_empty()) {
351       out->print_cr(" ");
352     } else {
353       out->print_cr(" from");
354       stack->print_on(out, 12);
355     }
356   }
357 }
358 
report_diff()359 void MemSummaryDiffReporter::report_diff() {
360   const char* scale = current_scale();
361   outputStream* out = output();
362   out->print_cr("\nNative Memory Tracking:\n");
363 
364   // Overall diff
365   out->print("Total: ");
366   print_virtual_memory_diff(_current_baseline.total_reserved_memory(),
367     _current_baseline.total_committed_memory(), _early_baseline.total_reserved_memory(),
368     _early_baseline.total_committed_memory());
369 
370   out->print_cr("\n");
371 
372   // Summary diff by memory type
373   for (int index = 0; index < mt_number_of_types; index ++) {
374     MEMFLAGS flag = NMTUtil::index_to_flag(index);
375     // thread stack is reported as part of thread category
376     if (flag == mtThreadStack) continue;
377     diff_summary_of_type(flag,
378       _early_baseline.malloc_memory(flag),
379       _early_baseline.virtual_memory(flag),
380       _early_baseline.metaspace_snapshot(),
381       _current_baseline.malloc_memory(flag),
382       _current_baseline.virtual_memory(flag),
383       _current_baseline.metaspace_snapshot());
384   }
385 }
386 
print_malloc_diff(size_t current_amount,size_t current_count,size_t early_amount,size_t early_count,MEMFLAGS flags) const387 void MemSummaryDiffReporter::print_malloc_diff(size_t current_amount, size_t current_count,
388     size_t early_amount, size_t early_count, MEMFLAGS flags) const {
389   const char* scale = current_scale();
390   outputStream* out = output();
391   const char* alloc_type = (flags == mtThread) ? "" : "malloc=";
392 
393   out->print("%s" SIZE_FORMAT "%s", alloc_type, amount_in_current_scale(current_amount), scale);
394   // Report type only if it is valid and not under "thread" category
395   if (flags != mtNone && flags != mtThread) {
396     out->print(" type=%s", NMTUtil::flag_to_name(flags));
397   }
398 
399   long amount_diff = diff_in_current_scale(current_amount, early_amount);
400   if (amount_diff != 0) {
401     out->print(" %+ld%s", amount_diff, scale);
402   }
403   if (current_count > 0) {
404     out->print(" #" SIZE_FORMAT "", current_count);
405     if (current_count != early_count) {
406       out->print(" %+d", (int)(current_count - early_count));
407     }
408   }
409 }
410 
print_arena_diff(size_t current_amount,size_t current_count,size_t early_amount,size_t early_count) const411 void MemSummaryDiffReporter::print_arena_diff(size_t current_amount, size_t current_count,
412   size_t early_amount, size_t early_count) const {
413   const char* scale = current_scale();
414   outputStream* out = output();
415   out->print("arena=" SIZE_FORMAT "%s", amount_in_current_scale(current_amount), scale);
416   if (diff_in_current_scale(current_amount, early_amount) != 0) {
417     out->print(" %+ld", diff_in_current_scale(current_amount, early_amount));
418   }
419 
420   out->print(" #" SIZE_FORMAT "", current_count);
421   if (current_count != early_count) {
422     out->print(" %+d", (int)(current_count - early_count));
423   }
424 }
425 
print_virtual_memory_diff(size_t current_reserved,size_t current_committed,size_t early_reserved,size_t early_committed) const426 void MemSummaryDiffReporter::print_virtual_memory_diff(size_t current_reserved, size_t current_committed,
427     size_t early_reserved, size_t early_committed) const {
428   const char* scale = current_scale();
429   outputStream* out = output();
430   out->print("reserved=" SIZE_FORMAT "%s", amount_in_current_scale(current_reserved), scale);
431   long reserved_diff = diff_in_current_scale(current_reserved, early_reserved);
432   if (reserved_diff != 0) {
433     out->print(" %+ld%s", reserved_diff, scale);
434   }
435 
436   out->print(", committed=" SIZE_FORMAT "%s", amount_in_current_scale(current_committed), scale);
437   long committed_diff = diff_in_current_scale(current_committed, early_committed);
438   if (committed_diff != 0) {
439     out->print(" %+ld%s", committed_diff, scale);
440   }
441 }
442 
443 
diff_summary_of_type(MEMFLAGS flag,const MallocMemory * early_malloc,const VirtualMemory * early_vm,const MetaspaceSnapshot * early_ms,const MallocMemory * current_malloc,const VirtualMemory * current_vm,const MetaspaceSnapshot * current_ms) const444 void MemSummaryDiffReporter::diff_summary_of_type(MEMFLAGS flag,
445   const MallocMemory* early_malloc, const VirtualMemory* early_vm,
446   const MetaspaceSnapshot* early_ms,
447   const MallocMemory* current_malloc, const VirtualMemory* current_vm,
448   const MetaspaceSnapshot* current_ms) const {
449 
450   outputStream* out = output();
451   const char* scale = current_scale();
452 
453   // Total reserved and committed memory in current baseline
454   size_t current_reserved_amount  = reserved_total (current_malloc, current_vm);
455   size_t current_committed_amount = committed_total(current_malloc, current_vm);
456 
457   // Total reserved and committed memory in early baseline
458   size_t early_reserved_amount  = reserved_total(early_malloc, early_vm);
459   size_t early_committed_amount = committed_total(early_malloc, early_vm);
460 
461   // Adjust virtual memory total
462   if (flag == mtThread) {
463     const VirtualMemory* early_thread_stack_usage =
464       _early_baseline.virtual_memory(mtThreadStack);
465     const VirtualMemory* current_thread_stack_usage =
466       _current_baseline.virtual_memory(mtThreadStack);
467 
468     early_reserved_amount  += early_thread_stack_usage->reserved();
469     early_committed_amount += early_thread_stack_usage->committed();
470 
471     current_reserved_amount  += current_thread_stack_usage->reserved();
472     current_committed_amount += current_thread_stack_usage->committed();
473   } else if (flag == mtNMT) {
474     early_reserved_amount  += _early_baseline.malloc_tracking_overhead();
475     early_committed_amount += _early_baseline.malloc_tracking_overhead();
476 
477     current_reserved_amount  += _current_baseline.malloc_tracking_overhead();
478     current_committed_amount += _current_baseline.malloc_tracking_overhead();
479   }
480 
481   if (amount_in_current_scale(current_reserved_amount) > 0 ||
482       diff_in_current_scale(current_reserved_amount, early_reserved_amount) != 0) {
483 
484     // print summary line
485     out->print("-%26s (", NMTUtil::flag_to_name(flag));
486     print_virtual_memory_diff(current_reserved_amount, current_committed_amount,
487       early_reserved_amount, early_committed_amount);
488     out->print_cr(")");
489 
490     // detail lines
491     if (flag == mtClass) {
492       // report class count
493       out->print("%27s (classes #" SIZE_FORMAT "", " ", _current_baseline.class_count());
494       int class_count_diff = (int)(_current_baseline.class_count() -
495         _early_baseline.class_count());
496       if (_current_baseline.class_count() != _early_baseline.class_count()) {
497         out->print(" %+d", (int)(_current_baseline.class_count() - _early_baseline.class_count()));
498       }
499       out->print_cr(")");
500 
501       out->print("%27s (  instance classes #" SIZE_FORMAT, " ", _current_baseline.instance_class_count());
502       if (_current_baseline.instance_class_count() != _early_baseline.instance_class_count()) {
503         out->print(" %+d", (int)(_current_baseline.instance_class_count() - _early_baseline.instance_class_count()));
504       }
505       out->print(", array classes #" SIZE_FORMAT, _current_baseline.array_class_count());
506       if (_current_baseline.array_class_count() != _early_baseline.array_class_count()) {
507         out->print(" %+d", (int)(_current_baseline.array_class_count() - _early_baseline.array_class_count()));
508       }
509       out->print_cr(")");
510 
511     } else if (flag == mtThread) {
512       // report thread count
513       out->print("%27s (thread #" SIZE_FORMAT "", " ", _current_baseline.thread_count());
514       int thread_count_diff = (int)(_current_baseline.thread_count() -
515           _early_baseline.thread_count());
516       if (thread_count_diff != 0) {
517         out->print(" %+d", thread_count_diff);
518       }
519       out->print_cr(")");
520 
521       out->print("%27s (stack: ", " ");
522       if (ThreadStackTracker::track_as_vm()) {
523         // report thread stack
524         const VirtualMemory* current_thread_stack =
525           _current_baseline.virtual_memory(mtThreadStack);
526         const VirtualMemory* early_thread_stack =
527           _early_baseline.virtual_memory(mtThreadStack);
528 
529         print_virtual_memory_diff(current_thread_stack->reserved(), current_thread_stack->committed(),
530           early_thread_stack->reserved(), early_thread_stack->committed());
531       } else {
532         const MallocMemory* current_thread_stack =
533           _current_baseline.malloc_memory(mtThreadStack);
534         const MallocMemory* early_thread_stack =
535           _early_baseline.malloc_memory(mtThreadStack);
536 
537         print_malloc_diff(current_thread_stack->malloc_size(), current_thread_stack->malloc_count(),
538           early_thread_stack->malloc_size(), early_thread_stack->malloc_count(), flag);
539       }
540       out->print_cr(")");
541     }
542 
543     // Report malloc'd memory
544     size_t current_malloc_amount = current_malloc->malloc_size();
545     size_t early_malloc_amount   = early_malloc->malloc_size();
546     if (amount_in_current_scale(current_malloc_amount) > 0 ||
547         diff_in_current_scale(current_malloc_amount, early_malloc_amount) != 0) {
548       out->print("%28s(", " ");
549       print_malloc_diff(current_malloc_amount, (flag == mtChunk) ? 0 : current_malloc->malloc_count(),
550         early_malloc_amount, early_malloc->malloc_count(), mtNone);
551       out->print_cr(")");
552     }
553 
554     // Report virtual memory
555     if (amount_in_current_scale(current_vm->reserved()) > 0 ||
556         diff_in_current_scale(current_vm->reserved(), early_vm->reserved()) != 0) {
557       out->print("%27s (mmap: ", " ");
558       print_virtual_memory_diff(current_vm->reserved(), current_vm->committed(),
559         early_vm->reserved(), early_vm->committed());
560       out->print_cr(")");
561     }
562 
563     // Report arena memory
564     if (amount_in_current_scale(current_malloc->arena_size()) > 0 ||
565         diff_in_current_scale(current_malloc->arena_size(), early_malloc->arena_size()) != 0) {
566       out->print("%28s(", " ");
567       print_arena_diff(current_malloc->arena_size(), current_malloc->arena_count(),
568         early_malloc->arena_size(), early_malloc->arena_count());
569       out->print_cr(")");
570     }
571 
572     // Report native memory tracking overhead
573     if (flag == mtNMT) {
574       size_t current_tracking_overhead = amount_in_current_scale(_current_baseline.malloc_tracking_overhead());
575       size_t early_tracking_overhead   = amount_in_current_scale(_early_baseline.malloc_tracking_overhead());
576 
577       out->print("%27s (tracking overhead=" SIZE_FORMAT "%s", " ",
578         amount_in_current_scale(_current_baseline.malloc_tracking_overhead()), scale);
579 
580       long overhead_diff = diff_in_current_scale(_current_baseline.malloc_tracking_overhead(),
581            _early_baseline.malloc_tracking_overhead());
582       if (overhead_diff != 0) {
583         out->print(" %+ld%s", overhead_diff, scale);
584       }
585       out->print_cr(")");
586     } else if (flag == mtClass) {
587       assert(current_ms != NULL && early_ms != NULL, "Sanity");
588       print_metaspace_diff(current_ms, early_ms);
589     }
590     out->print_cr(" ");
591   }
592 }
593 
print_metaspace_diff(const MetaspaceSnapshot * current_ms,const MetaspaceSnapshot * early_ms) const594 void MemSummaryDiffReporter::print_metaspace_diff(const MetaspaceSnapshot* current_ms,
595                                                   const MetaspaceSnapshot* early_ms) const {
596   print_metaspace_diff(Metaspace::NonClassType, current_ms, early_ms);
597   if (Metaspace::using_class_space()) {
598     print_metaspace_diff(Metaspace::ClassType, current_ms, early_ms);
599   }
600 }
601 
print_metaspace_diff(Metaspace::MetadataType type,const MetaspaceSnapshot * current_ms,const MetaspaceSnapshot * early_ms) const602 void MemSummaryDiffReporter::print_metaspace_diff(Metaspace::MetadataType type,
603                                                   const MetaspaceSnapshot* current_ms,
604                                                   const MetaspaceSnapshot* early_ms) const {
605   const char* name = (type == Metaspace::NonClassType) ?
606     "Metadata:   " : "Class space:";
607 
608   outputStream* out = output();
609   const char* scale = current_scale();
610 
611   out->print_cr("%27s (  %s)", " ", name);
612   out->print("%27s (    ", " ");
613   print_virtual_memory_diff(current_ms->reserved_in_bytes(type),
614                             current_ms->committed_in_bytes(type),
615                             early_ms->reserved_in_bytes(type),
616                             early_ms->committed_in_bytes(type));
617   out->print_cr(")");
618 
619   long diff_used = diff_in_current_scale(current_ms->used_in_bytes(type),
620                                          early_ms->used_in_bytes(type));
621   long diff_free = diff_in_current_scale(current_ms->free_in_bytes(type),
622                                          early_ms->free_in_bytes(type));
623 
624   size_t current_waste = current_ms->committed_in_bytes(type)
625     - (current_ms->used_in_bytes(type) + current_ms->free_in_bytes(type));
626   size_t early_waste = early_ms->committed_in_bytes(type)
627     - (early_ms->used_in_bytes(type) + early_ms->free_in_bytes(type));
628   long diff_waste = diff_in_current_scale(current_waste, early_waste);
629 
630   // Diff used
631   out->print("%27s (    used=" SIZE_FORMAT "%s", " ",
632     amount_in_current_scale(current_ms->used_in_bytes(type)), scale);
633   if (diff_used != 0) {
634     out->print(" %+ld%s", diff_used, scale);
635   }
636   out->print_cr(")");
637 
638   // Diff free
639   out->print("%27s (    free=" SIZE_FORMAT "%s", " ",
640     amount_in_current_scale(current_ms->free_in_bytes(type)), scale);
641   if (diff_free != 0) {
642     out->print(" %+ld%s", diff_free, scale);
643   }
644   out->print_cr(")");
645 
646 
647   // Diff waste
648   out->print("%27s (    waste=" SIZE_FORMAT "%s =%2.2f%%", " ",
649     amount_in_current_scale(current_waste), scale,
650     ((float)current_waste * 100) / current_ms->committed_in_bytes(type));
651   if (diff_waste != 0) {
652     out->print(" %+ld%s", diff_waste, scale);
653   }
654   out->print_cr(")");
655 }
656 
report_diff()657 void MemDetailDiffReporter::report_diff() {
658   MemSummaryDiffReporter::report_diff();
659   diff_malloc_sites();
660   diff_virtual_memory_sites();
661 }
662 
diff_malloc_sites() const663 void MemDetailDiffReporter::diff_malloc_sites() const {
664   MallocSiteIterator early_itr = _early_baseline.malloc_sites(MemBaseline::by_site_and_type);
665   MallocSiteIterator current_itr = _current_baseline.malloc_sites(MemBaseline::by_site_and_type);
666 
667   const MallocSite* early_site   = early_itr.next();
668   const MallocSite* current_site = current_itr.next();
669 
670   while (early_site != NULL || current_site != NULL) {
671     if (early_site == NULL) {
672       new_malloc_site(current_site);
673       current_site = current_itr.next();
674     } else if (current_site == NULL) {
675       old_malloc_site(early_site);
676       early_site = early_itr.next();
677     } else {
678       int compVal = current_site->call_stack()->compare(*early_site->call_stack());
679       if (compVal < 0) {
680         new_malloc_site(current_site);
681         current_site = current_itr.next();
682       } else if (compVal > 0) {
683         old_malloc_site(early_site);
684         early_site = early_itr.next();
685       } else {
686         diff_malloc_site(early_site, current_site);
687         early_site   = early_itr.next();
688         current_site = current_itr.next();
689       }
690     }
691   }
692 }
693 
diff_virtual_memory_sites() const694 void MemDetailDiffReporter::diff_virtual_memory_sites() const {
695   VirtualMemorySiteIterator early_itr = _early_baseline.virtual_memory_sites(MemBaseline::by_site);
696   VirtualMemorySiteIterator current_itr = _current_baseline.virtual_memory_sites(MemBaseline::by_site);
697 
698   const VirtualMemoryAllocationSite* early_site   = early_itr.next();
699   const VirtualMemoryAllocationSite* current_site = current_itr.next();
700 
701   while (early_site != NULL || current_site != NULL) {
702     if (early_site == NULL) {
703       new_virtual_memory_site(current_site);
704       current_site = current_itr.next();
705     } else if (current_site == NULL) {
706       old_virtual_memory_site(early_site);
707       early_site = early_itr.next();
708     } else {
709       int compVal = current_site->call_stack()->compare(*early_site->call_stack());
710       if (compVal < 0) {
711         new_virtual_memory_site(current_site);
712         current_site = current_itr.next();
713       } else if (compVal > 0) {
714         old_virtual_memory_site(early_site);
715         early_site = early_itr.next();
716       } else {
717         diff_virtual_memory_site(early_site, current_site);
718         early_site   = early_itr.next();
719         current_site = current_itr.next();
720       }
721     }
722   }
723 }
724 
725 
new_malloc_site(const MallocSite * malloc_site) const726 void MemDetailDiffReporter::new_malloc_site(const MallocSite* malloc_site) const {
727   diff_malloc_site(malloc_site->call_stack(), malloc_site->size(), malloc_site->count(),
728     0, 0, malloc_site->flag());
729 }
730 
old_malloc_site(const MallocSite * malloc_site) const731 void MemDetailDiffReporter::old_malloc_site(const MallocSite* malloc_site) const {
732   diff_malloc_site(malloc_site->call_stack(), 0, 0, malloc_site->size(),
733     malloc_site->count(), malloc_site->flag());
734 }
735 
diff_malloc_site(const MallocSite * early,const MallocSite * current) const736 void MemDetailDiffReporter::diff_malloc_site(const MallocSite* early,
737   const MallocSite* current)  const {
738   if (early->flag() != current->flag()) {
739     // If malloc site type changed, treat it as deallocation of old type and
740     // allocation of new type.
741     old_malloc_site(early);
742     new_malloc_site(current);
743   } else {
744     diff_malloc_site(current->call_stack(), current->size(), current->count(),
745       early->size(), early->count(), early->flag());
746   }
747 }
748 
diff_malloc_site(const NativeCallStack * stack,size_t current_size,size_t current_count,size_t early_size,size_t early_count,MEMFLAGS flags) const749 void MemDetailDiffReporter::diff_malloc_site(const NativeCallStack* stack, size_t current_size,
750   size_t current_count, size_t early_size, size_t early_count, MEMFLAGS flags) const {
751   outputStream* out = output();
752 
753   assert(stack != NULL, "NULL stack");
754 
755   if (diff_in_current_scale(current_size, early_size) == 0) {
756       return;
757   }
758 
759   stack->print_on(out);
760   out->print("%28s (", " ");
761   print_malloc_diff(current_size, current_count,
762     early_size, early_count, flags);
763 
764   out->print_cr(")\n");
765 }
766 
767 
new_virtual_memory_site(const VirtualMemoryAllocationSite * site) const768 void MemDetailDiffReporter::new_virtual_memory_site(const VirtualMemoryAllocationSite* site) const {
769   diff_virtual_memory_site(site->call_stack(), site->reserved(), site->committed(), 0, 0, site->flag());
770 }
771 
old_virtual_memory_site(const VirtualMemoryAllocationSite * site) const772 void MemDetailDiffReporter::old_virtual_memory_site(const VirtualMemoryAllocationSite* site) const {
773   diff_virtual_memory_site(site->call_stack(), 0, 0, site->reserved(), site->committed(), site->flag());
774 }
775 
diff_virtual_memory_site(const VirtualMemoryAllocationSite * early,const VirtualMemoryAllocationSite * current) const776 void MemDetailDiffReporter::diff_virtual_memory_site(const VirtualMemoryAllocationSite* early,
777   const VirtualMemoryAllocationSite* current) const {
778   assert(early->flag() == current->flag(), "Should be the same");
779   diff_virtual_memory_site(current->call_stack(), current->reserved(), current->committed(),
780     early->reserved(), early->committed(), current->flag());
781 }
782 
diff_virtual_memory_site(const NativeCallStack * stack,size_t current_reserved,size_t current_committed,size_t early_reserved,size_t early_committed,MEMFLAGS flag) const783 void MemDetailDiffReporter::diff_virtual_memory_site(const NativeCallStack* stack, size_t current_reserved,
784   size_t current_committed, size_t early_reserved, size_t early_committed, MEMFLAGS flag) const  {
785   outputStream* out = output();
786 
787   // no change
788   if (diff_in_current_scale(current_reserved, early_reserved) == 0 &&
789       diff_in_current_scale(current_committed, early_committed) == 0) {
790     return;
791   }
792 
793   stack->print_on(out);
794   out->print("%28s (mmap: ", " ");
795   print_virtual_memory_diff(current_reserved, current_committed,
796     early_reserved, early_committed);
797 
798   if (flag != mtNone) {
799     out->print(" Type=%s", NMTUtil::flag_to_name(flag));
800   }
801 
802   out->print_cr(")\n");
803  }
804