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