diff -r 65cad575ace3 -r bdf136b8ae0e src/hotspot/share/memory/metaspace/metaspaceReport.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/hotspot/share/memory/metaspace/metaspaceReport.cpp Tue Sep 10 09:24:05 2019 +0200 @@ -0,0 +1,400 @@ +/* + * Copyright (c) 2018, 2019 SAP and/or its affiliates. + * Copyright (c) 2018, 2019 Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ +#include "precompiled.hpp" +#include "classfile/classLoaderData.hpp" +#include "classfile/classLoaderDataGraph.hpp" +#include "memory/metaspace/chunkHeaderPool.hpp" +#include "memory/metaspace/chunkManager.hpp" +#include "memory/metaspace/internStat.hpp" +#include "memory/metaspace/metaspaceCommon.hpp" +#include "memory/metaspace/metaspaceEnums.hpp" +#include "memory/metaspace/metaspaceReport.hpp" +#include "memory/metaspace/metaspaceStatistics.hpp" +#include "memory/metaspace/printCLDMetaspaceInfoClosure.hpp" +#include "memory/metaspace/runningCounters.hpp" +#include "memory/metaspace/virtualSpaceList.hpp" +#include "memory/metaspace.hpp" +#include "runtime/os.hpp" + +namespace metaspace { + +static void print_vs(outputStream* out, size_t scale) { + + const size_t reserved_nc = RunningCounters::reserved_words_nonclass(); + const size_t committed_nc = RunningCounters::committed_words_nonclass(); + const int num_nodes_nc = VirtualSpaceList::vslist_nonclass()->num_nodes(); + const size_t reserved_c = RunningCounters::reserved_words_class(); + const size_t committed_c = RunningCounters::committed_words_class(); + const int num_nodes_c = VirtualSpaceList::vslist_class()->num_nodes(); + + if (Metaspace::using_class_space()) { + + out->print(" Non-class space: "); + print_scaled_words(out, reserved_nc, scale, 7); + out->print(" reserved, "); + print_scaled_words_and_percentage(out, committed_nc, reserved_nc, scale, 7); + out->print(" committed, "); + out->print(" %d nodes.", num_nodes_nc); + out->cr(); + out->print(" Class space: "); + print_scaled_words(out, reserved_c, scale, 7); + out->print(" reserved, "); + print_scaled_words_and_percentage(out, committed_c, reserved_c, scale, 7); + out->print(" committed, "); + out->print(" %d nodes.", num_nodes_c); + out->cr(); + out->print(" Both: "); + print_scaled_words(out, reserved_c + reserved_nc, scale, 7); + out->print(" reserved, "); + print_scaled_words_and_percentage(out, committed_c + committed_nc, reserved_c + reserved_nc, scale, 7); + out->print(" committed. "); + out->cr(); + + } else { + assert(committed_c == 0 && reserved_c == 0 && num_nodes_c == 0, "Sanity"); + print_scaled_words(out, reserved_nc, scale, 7); + out->print(" reserved, "); + print_scaled_words_and_percentage(out, committed_nc, reserved_nc, scale, 7); + out->print(" committed, "); + out->print(" %d nodes.", num_nodes_nc); + out->cr(); + } +} + +static void print_settings(outputStream* out, size_t scale) { + out->print("MaxMetaspaceSize: "); + if (MaxMetaspaceSize >= (max_uintx) - (2 * os::vm_page_size())) { + // aka "very big". Default is max_uintx, but due to rounding in arg parsing the real + // value is smaller. + out->print("unlimited"); + } else { + print_human_readable_size(out, MaxMetaspaceSize, scale); + } + out->cr(); + if (Metaspace::using_class_space()) { + out->print("CompressedClassSpaceSize: "); + print_human_readable_size(out, CompressedClassSpaceSize, scale); + } + out->cr(); + out->print("InitialBootClassLoaderMetaspaceSize: "); + print_human_readable_size(out, InitialBootClassLoaderMetaspaceSize, scale); + out->cr(); + Settings::print_on(out); +} + +// This will print out a basic metaspace usage report but +// unlike print_report() is guaranteed not to lock or to walk the CLDG. +void MetaspaceReporter::print_basic_report(outputStream* out, size_t scale) { + + if (!Metaspace::initialized()) { + out->print_cr("Metaspace not yet initialized."); + return; + } + + out->cr(); + out->print_cr("Usage:"); + + if (Metaspace::using_class_space()) { + out->print(" Non-class: "); + } + + // Note: since we want to purely rely on counters, without any locking or walking the CLDG, + // for Usage stats (statistics over in-use chunks) all we can print is the + // used words. We cannot print committed areas, or free/waste areas, of in-use chunks require + // walking. + const size_t used_nc = MetaspaceUtils::used_words(metaspace::NonClassType); + + print_scaled_words(out, used_nc, scale, 5); + out->print(" used."); + out->cr(); + + if (Metaspace::using_class_space()) { + const size_t used_c = MetaspaceUtils::used_words(metaspace::ClassType); + out->print(" Class: "); + print_scaled_words(out, used_c, scale, 5); + out->print(" used."); + out->cr(); + + out->print(" Both: "); + const size_t used = used_nc + used_c; + print_scaled_words(out, used, scale, 5); + out->print(" used."); + out->cr(); + } + + out->cr(); + out->print_cr("Virtual space:"); + + print_vs(out, scale); + + out->cr(); + out->print_cr("Chunk freelists:"); + + if (Metaspace::using_class_space()) { + out->print(" Non-Class: "); + } + print_scaled_words(out, ChunkManager::chunkmanager_nonclass()->total_word_size(), scale); + out->cr(); + if (Metaspace::using_class_space()) { + out->print(" Class: "); + print_scaled_words(out, ChunkManager::chunkmanager_class()->total_word_size(), scale); + out->cr(); + out->print(" Both: "); + print_scaled_words(out, ChunkManager::chunkmanager_nonclass()->total_word_size() + + ChunkManager::chunkmanager_class()->total_word_size(), scale); + out->cr(); + } + + out->cr(); + + // Print basic settings + print_settings(out, scale); + + out->cr(); + +#ifdef ASSERT + out->cr(); + out->print_cr("Internal statistics:"); + out->cr(); + InternalStats::print_on(out); + out->cr(); +#endif +} + +void MetaspaceReporter::print_report(outputStream* out, size_t scale, int flags) { + + if (!Metaspace::initialized()) { + out->print_cr("Metaspace not yet initialized."); + return; + } + + const bool print_loaders = (flags & rf_show_loaders) > 0; + const bool print_classes = (flags & rf_show_classes) > 0; + const bool print_by_chunktype = (flags & rf_break_down_by_chunktype) > 0; + const bool print_by_spacetype = (flags & rf_break_down_by_spacetype) > 0; + + // Some report options require walking the class loader data graph. + metaspace::PrintCLDMetaspaceInfoClosure cl(out, scale, print_loaders, print_classes, print_by_chunktype); + if (print_loaders) { + out->cr(); + out->print_cr("Usage per loader:"); + out->cr(); + } + + ClassLoaderDataGraph::loaded_cld_do(&cl); // collect data and optionally print + + // Print totals, broken up by space type. + if (print_by_spacetype) { + out->cr(); + out->print_cr("Usage per space type:"); + out->cr(); + for (int space_type = (int)metaspace::ZeroMetaspaceType; + space_type < (int)metaspace::MetaspaceTypeCount; space_type ++) + { + uintx num_loaders = cl._num_loaders_by_spacetype[space_type]; + uintx num_classes = cl._num_classes_by_spacetype[space_type]; + out->print("%s - " UINTX_FORMAT " %s", + describe_spacetype((MetaspaceType)space_type), + num_loaders, loaders_plural(num_loaders)); + if (num_classes > 0) { + out->print(", "); + + print_number_of_classes(out, num_classes, cl._num_classes_shared_by_spacetype[space_type]); + out->print(":"); + cl._stats_by_spacetype[space_type].print_on(out, scale, print_by_chunktype); + } else { + out->print("."); + out->cr(); + } + out->cr(); + } + } + + // Print totals for in-use data: + out->cr(); + { + uintx num_loaders = cl._num_loaders; + out->print("Total Usage - " UINTX_FORMAT " %s, ", + num_loaders, loaders_plural(num_loaders)); + print_number_of_classes(out, cl._num_classes, cl._num_classes_shared); + out->print(":"); + cl._stats_total.print_on(out, scale, print_by_chunktype); + out->cr(); + } + + ///////////////////////////////////////////////// + // -- Print Virtual space. + out->cr(); + out->print_cr("Virtual space:"); + + print_vs(out, scale); + + // -- Print VirtualSpaceList details. + if ((flags & rf_show_vslist) > 0) { + out->cr(); + out->print_cr("Virtual space list%s:", Metaspace::using_class_space() ? "s" : ""); + + if (Metaspace::using_class_space()) { + out->print_cr(" Non-Class:"); + } + VirtualSpaceList::vslist_nonclass()->print_on(out); + out->cr(); + if (Metaspace::using_class_space()) { + out->print_cr(" Class:"); + VirtualSpaceList::vslist_class()->print_on(out); + out->cr(); + } + } + out->cr(); + + // -- Print VirtualSpaceList map. +/* Deactivated for now. + if ((flags & rf_show_vsmap) > 0) { + out->cr(); + out->print_cr("Virtual space map:"); + + if (Metaspace::using_class_space()) { + out->print_cr(" Non-Class:"); + } + Metaspace::space_list()->print_map(out); + if (Metaspace::using_class_space()) { + out->print_cr(" Class:"); + Metaspace::class_space_list()->print_map(out); + } + } + out->cr(); +*/ + + //////////// Freelists (ChunkManager) section /////////////////////////// + + out->cr(); + out->print_cr("Chunk freelist%s:", Metaspace::using_class_space() ? "s" : ""); + + cm_stats_t non_class_cm_stat; + cm_stats_t class_cm_stat; + cm_stats_t total_cm_stat; + + ChunkManager::chunkmanager_nonclass()->add_to_statistics(&non_class_cm_stat); + if (Metaspace::using_class_space()) { + ChunkManager::chunkmanager_nonclass()->add_to_statistics(&non_class_cm_stat); + ChunkManager::chunkmanager_class()->add_to_statistics(&class_cm_stat); + total_cm_stat.add(non_class_cm_stat); + total_cm_stat.add(class_cm_stat); + + out->print_cr(" Non-Class:"); + non_class_cm_stat.print_on(out, scale); + out->cr(); + out->print_cr(" Class:"); + class_cm_stat.print_on(out, scale); + out->cr(); + out->print_cr(" Both:"); + total_cm_stat.print_on(out, scale); + out->cr(); + } else { + ChunkManager::chunkmanager_nonclass()->add_to_statistics(&non_class_cm_stat); + non_class_cm_stat.print_on(out, scale); + out->cr(); + } + + //////////// Waste section /////////////////////////// + // As a convenience, print a summary of common waste. + out->cr(); + out->print("Waste (unused committed space):"); + // For all wastages, print percentages from total. As total use the total size of memory committed for metaspace. + const size_t committed_words = RunningCounters::committed_words(); + + out->print("(percentages refer to total committed size "); + print_scaled_words(out, committed_words, scale); + out->print_cr("):"); + + // Print waste for in-use chunks. + in_use_chunk_stats_t ucs_nonclass = cl._stats_total.sm_stats_nonclass.totals(); + in_use_chunk_stats_t ucs_class = cl._stats_total.sm_stats_class.totals(); + const size_t waste_in_chunks_in_use = ucs_nonclass.waste_words + ucs_class.waste_words; + const size_t free_in_chunks_in_use = ucs_nonclass.free_words + ucs_class.free_words; + + out->print(" Waste in chunks in use: "); + print_scaled_words_and_percentage(out, waste_in_chunks_in_use, committed_words, scale, 6); + out->cr(); + out->print(" Free in chunks in use: "); + print_scaled_words_and_percentage(out, free_in_chunks_in_use, committed_words, scale, 6); + out->cr(); + + // Print waste in free chunks. + const size_t committed_in_free_chunks = total_cm_stat.total_committed_word_size(); + out->print(" In free chunks: "); + print_scaled_words_and_percentage(out, committed_in_free_chunks, committed_words, scale, 6); + out->cr(); + + // Print waste in deallocated blocks. + const uintx free_blocks_num = + cl._stats_total.sm_stats_nonclass.free_blocks_num + + cl._stats_total.sm_stats_class.free_blocks_num; + const size_t free_blocks_cap_words = + cl._stats_total.sm_stats_nonclass.free_blocks_word_size + + cl._stats_total.sm_stats_class.free_blocks_word_size; + out->print("Deallocated from chunks in use: "); + print_scaled_words_and_percentage(out, free_blocks_cap_words, committed_words, scale, 6); + out->print(" (" UINTX_FORMAT " blocks)", free_blocks_num); + out->cr(); + + // Print total waste. + const size_t total_waste = + waste_in_chunks_in_use + + free_in_chunks_in_use + + committed_in_free_chunks + + free_blocks_cap_words; + out->print(" -total-: "); + print_scaled_words_and_percentage(out, total_waste, committed_words, scale, 6); + out->cr(); + + // Also print chunk header pool size. + out->cr(); + out->print("chunk header pool: %u items, ", ChunkHeaderPool::pool().used()); + print_scaled_words(out, ChunkHeaderPool::pool().memory_footprint_words(), scale); + out->print("."); + out->cr(); + + // Print internal statistics +#ifdef ASSERT + out->cr(); + out->print_cr("Internal statistics:"); + out->cr(); + InternalStats::print_on(out); + out->cr(); +#endif + + // Print some interesting settings + out->cr(); + out->print_cr("Settings:"); + print_settings(out, scale); + + out->cr(); + out->cr(); + +} // MetaspaceUtils::print_report() + +} // namespace metaspace +