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