/* * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2018, SAP and/or its affiliates. * 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/chunkManager.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_nonclass_words = RunningCounters::reserved_words_nonclass(); const size_t committed_nonclass_words = RunningCounters::committed_words_nonclass(); { if (Metaspace::using_class_space()) { out->print(" Non-class space: "); } print_scaled_words(out, reserved_nonclass_words, scale, 7); out->print(" reserved, "); print_scaled_words_and_percentage(out, committed_nonclass_words, reserved_nonclass_words, scale, 7); out->print_cr(" committed "); if (Metaspace::using_class_space()) { const size_t reserved_class_words = RunningCounters::reserved_words_class(); const size_t committed_class_words = RunningCounters::committed_words_class(); out->print(" Class space: "); print_scaled_words(out, reserved_class_words, scale, 7); out->print(" reserved, "); print_scaled_words_and_percentage(out, committed_class_words, reserved_class_words, scale, 7); out->print_cr(" committed "); const size_t reserved_words = reserved_nonclass_words + reserved_class_words; const size_t committed_words = committed_nonclass_words + committed_class_words; out->print(" Both: "); print_scaled_words(out, reserved_words, scale, 7); out->print(" reserved, "); print_scaled_words_and_percentage(out, committed_words, reserved_words, scale, 7); out->print_cr(" committed "); } } } static void print_basic_switches(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(); } // 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: "); } // In its most basic form, we do not require walking the CLDG. Instead, just print the running totals from // MetaspaceUtils. const size_t cap_nc = MetaspaceUtils::capacity_words(metaspace::NonClassType); const size_t overhead_nc = MetaspaceUtils::overhead_words(metaspace::NonClassType); const size_t used_nc = MetaspaceUtils::used_words(metaspace::NonClassType); const size_t free_and_waste_nc = cap_nc - overhead_nc - used_nc; print_scaled_words(out, cap_nc, scale, 5); out->print(" capacity, "); print_scaled_words_and_percentage(out, used_nc, cap_nc, scale, 5); out->print(" used, "); print_scaled_words_and_percentage(out, free_and_waste_nc, cap_nc, scale, 5); out->print(" free+waste, "); print_scaled_words_and_percentage(out, overhead_nc, cap_nc, scale, 5); out->print(" overhead. "); out->cr(); if (Metaspace::using_class_space()) { const size_t cap_c = MetaspaceUtils::capacity_words(metaspace::ClassType); const size_t overhead_c = MetaspaceUtils::overhead_words(metaspace::ClassType); const size_t used_c = MetaspaceUtils::used_words(metaspace::ClassType); const size_t free_and_waste_c = cap_c - overhead_c - used_c; out->print(" Class: "); print_scaled_words(out, cap_c, scale, 5); out->print(" capacity, "); print_scaled_words_and_percentage(out, used_c, cap_c, scale, 5); out->print(" used, "); print_scaled_words_and_percentage(out, free_and_waste_c, cap_c, scale, 5); out->print(" free+waste, "); print_scaled_words_and_percentage(out, overhead_c, cap_c, scale, 5); out->print(" overhead. "); out->cr(); out->print(" Both: "); const size_t cap = cap_nc + cap_c; print_scaled_words(out, cap, scale, 5); out->print(" capacity, "); print_scaled_words_and_percentage(out, used_nc + used_c, cap, scale, 5); out->print(" used, "); print_scaled_words_and_percentage(out, free_and_waste_nc + free_and_waste_c, cap, scale, 5); out->print(" free+waste, "); print_scaled_words_and_percentage(out, overhead_nc + overhead_c, cap, scale, 5); out->print(" overhead. "); 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_basic_switches(out, scale); out->cr(); */ } 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, scale); if (Metaspace::using_class_space()) { out->print_cr(" Class:"); VirtualSpaceList::vslist_class()->print_on(out, scale); } } 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(); */ // -- Print Freelists (ChunkManager) details out->cr(); out->print_cr("Chunk freelist%s:", Metaspace::using_class_space() ? "s" : ""); ChunkManagerStatistics non_class_cm_stat; ChunkManager::chunkmanager_nonclass()->add_to_statistics(&non_class_cm_stat); if (Metaspace::using_class_space()) { out->print_cr(" Non-Class:"); } non_class_cm_stat.print_on(out, scale); if (Metaspace::using_class_space()) { ChunkManagerStatistics class_cm_stat; ChunkManager::chunkmanager_class()->add_to_statistics(&class_cm_stat); out->print_cr(" Class:"); class_cm_stat.print_on(out, scale); } // As a convenience, print a summary of common waste. out->cr(); out->print("Waste "); // 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 space committed but not yet used by any class loader const size_t unused_words_in_vs = 0;// TODO MetaspaceUtils::free_in_vs_bytes() / BytesPerWord; out->print(" Committed unused: "); print_scaled_words_and_percentage(out, unused_words_in_vs, committed_words, scale, 6); out->cr(); // Print waste for in-use chunks. UsedChunksStatistics ucs_nonclass = cl._stats_total.sm_stats[metaspace::NonClassType].totals(); UsedChunksStatistics ucs_class = cl._stats_total.sm_stats[metaspace::ClassType].totals(); UsedChunksStatistics ucs_all; ucs_all.add(ucs_nonclass); ucs_all.add(ucs_class); out->print(" Waste in chunks in use: "); print_scaled_words_and_percentage(out, ucs_all.waste, committed_words, scale, 6); out->cr(); out->print(" Free (committed) in chunks in use: "); print_scaled_words_and_percentage(out, ucs_all.free, committed_words, scale, 6); out->cr(); /* // Print waste in free chunks. const size_t total_capacity_in_free_chunks = Metaspace::chunk_manager_metadata()->free_chunks_total_words() + (Metaspace::using_class_space() ? Metaspace::chunk_manager_class()->free_chunks_total_words() : 0); out->print(" In free chunks: "); print_scaled_words_and_percentage(out, total_capacity_in_free_chunks, committed_words, scale, 6); out->cr(); // Print waste in deallocated blocks. const uintx free_blocks_num = cl._stats_total.nonclass_sm_stats().free_blocks_num() + cl._stats_total.class_sm_stats().free_blocks_num(); const size_t free_blocks_cap_words = cl._stats_total.nonclass_sm_stats().free_blocks_cap_words() + cl._stats_total.class_sm_stats().free_blocks_cap_words(); 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 = ucs_all.waste() + ucs_all.free() + ucs_all.overhead() + total_capacity_in_free_chunks + free_blocks_cap_words + unused_words_in_vs; out->print(" -total-: "); print_scaled_words_and_percentage(out, total_waste, committed_words, scale, 6); out->cr(); */ // Print internal statistics #ifdef ASSERT out->cr(); out->cr(); out->print_cr("Internal statistics:"); out->cr(); out->print_cr("Number of allocations: " UINTX_FORMAT ".", g_internal_statistics.num_allocs); out->print_cr("Number of space births: " UINTX_FORMAT ".", g_internal_statistics.num_metaspace_births); out->print_cr("Number of space deaths: " UINTX_FORMAT ".", g_internal_statistics.num_metaspace_deaths); out->print_cr("Number of virtual space node births: " UINTX_FORMAT ".", g_internal_statistics.num_vsnodes_created); out->print_cr("Number of virtual space node deaths: " UINTX_FORMAT ".", g_internal_statistics.num_vsnodes_purged); out->print_cr("Number of times virtual space nodes were expanded: " UINTX_FORMAT ".", g_internal_statistics.num_committed_space_expanded); out->print_cr("Number of deallocations: " UINTX_FORMAT " (" UINTX_FORMAT " external).", g_internal_statistics.num_deallocs, g_internal_statistics.num_external_deallocs); out->print_cr("Allocations from deallocated blocks: " UINTX_FORMAT ".", g_internal_statistics.num_allocs_from_deallocated_blocks); out->print_cr("Number of chunks added to freelist: " UINTX_FORMAT ".", g_internal_statistics.num_chunks_added_to_freelist); out->print_cr("Number of chunks removed from freelist: " UINTX_FORMAT ".", g_internal_statistics.num_chunks_removed_from_freelist); out->print_cr("Number of chunk merges: " UINTX_FORMAT ", split-ups: " UINTX_FORMAT ".", g_internal_statistics.num_chunk_merges, g_internal_statistics.num_chunk_splits); out->cr(); #endif // Print some interesting settings out->cr(); out->cr(); print_basic_switches(out, scale); out->cr(); out->print("InitialBootClassLoaderMetaspaceSize: "); print_human_readable_size(out, InitialBootClassLoaderMetaspaceSize, scale); out->cr(); out->cr(); } // MetaspaceUtils::print_report() } // namespace metaspace