Projects
openEuler:24.03:SP1:Everything
openjdk-1.8.0
_service:tar_scm:8189688-NMT-Report-per-class-l...
Sign Up
Log In
Username
Password
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File _service:tar_scm:8189688-NMT-Report-per-class-load-metadata-informati.patch of Package openjdk-1.8.0
From 528a3b6459e34532120f468ba9afb8833d516f5a Mon Sep 17 00:00:00 2001 From: eapen <zhangyipeng7@huawei.com> Date: Thu, 15 Dec 2022 11:38:55 +0800 Subject: [PATCH 19/33] I68TO2: 8189688: NMT: Report per-class load metadata information --- hotspot/src/share/vm/memory/metaspace.cpp | 322 ++++++++++++++++++++++++- hotspot/src/share/vm/memory/metaspace.hpp | 4 + hotspot/src/share/vm/runtime/vm_operations.cpp | 4 + hotspot/src/share/vm/runtime/vm_operations.hpp | 12 + hotspot/src/share/vm/services/nmtDCmd.cpp | 16 +- hotspot/src/share/vm/services/nmtDCmd.hpp | 1 + 6 files changed, 354 insertions(+), 5 deletions(-) diff --git a/hotspot/src/share/vm/memory/metaspace.cpp b/hotspot/src/share/vm/memory/metaspace.cpp index 6c4654b..cf4a112 100644 --- a/hotspot/src/share/vm/memory/metaspace.cpp +++ b/hotspot/src/share/vm/memory/metaspace.cpp @@ -75,6 +75,22 @@ enum ChunkIndex { NumberOfInUseLists = 4 }; +// Helper, returns a descriptive name for the given index. +static const char* chunk_size_name(ChunkIndex index) { + switch (index) { + case SpecializedIndex: + return "specialized"; + case SmallIndex: + return "small"; + case MediumIndex: + return "medium"; + case HumongousIndex: + return "humongous"; + default: + return "Invalid index"; + } +} + enum ChunkSizes { // in words. ClassSpecializedChunk = 128, SpecializedChunk = 128, @@ -89,6 +105,18 @@ static ChunkIndex next_chunk_index(ChunkIndex i) { return (ChunkIndex) (i+1); } +static const char* scale_unit(size_t scale) { + switch(scale) { + case 1: return "BYTES"; + case K: return "KB"; + case M: return "MB"; + case G: return "GB"; + default: + ShouldNotReachHere(); + return NULL; + } +} + volatile intptr_t MetaspaceGC::_capacity_until_GC = 0; uint MetaspaceGC::_shrink_factor = 0; bool MetaspaceGC::_should_concurrent_collect = false; @@ -141,6 +169,18 @@ class ChunkManager : public CHeapObj<mtInternal> { } void verify_free_chunks_count(); + struct ChunkManagerStatistics { + size_t num_by_type[NumberOfFreeLists]; + size_t single_size_by_type[NumberOfFreeLists]; + size_t total_size_by_type[NumberOfFreeLists]; + size_t num_humongous_chunks; + size_t total_size_humongous_chunks; + }; + + void locked_get_statistics(ChunkManagerStatistics* stat) const; + void get_statistics(ChunkManagerStatistics* stat) const; + static void print_statistics(const ChunkManagerStatistics* stat, outputStream* out, size_t scale); + public: ChunkManager(size_t specialized_size, size_t small_size, size_t medium_size) @@ -157,6 +197,9 @@ class ChunkManager : public CHeapObj<mtInternal> { // for special, small, medium, and humongous chunks. ChunkIndex list_index(size_t size); + // Map a given index to the chunk size. + size_t size_by_index(ChunkIndex index) const; + // Remove the chunk from its freelist. It is // expected to be on one of the _free_chunks[] lists. void remove_chunk(Metachunk* chunk); @@ -249,6 +292,10 @@ class ChunkManager : public CHeapObj<mtInternal> { void locked_print_sum_free_chunks(outputStream* st); void print_on(outputStream* st) const; + + // Prints composition for both non-class and (if available) + // class chunk manager. + static void print_all_chunkmanagers(outputStream* out, size_t scale = 1); }; // Used to manage the free list of Metablocks (a block corresponds @@ -1707,7 +1754,6 @@ bool Metadebug::test_metadata_failure() { #endif // ChunkManager methods - size_t ChunkManager::free_chunks_total_words() { return _free_chunks_total; } @@ -1729,6 +1775,12 @@ size_t ChunkManager::free_chunks_count() { return _free_chunks_count; } +size_t ChunkManager::size_by_index(ChunkIndex index) const { + index_bounds_check(index); + assert(index != HumongousIndex, "Do not call for humongous chunks."); + return _free_chunks[index].size(); +} + void ChunkManager::locked_verify_free_chunks_total() { assert_lock_strong(SpaceManager::expand_lock()); assert(sum_free_chunks() == _free_chunks_total, @@ -1918,7 +1970,83 @@ Metachunk* ChunkManager::chunk_freelist_allocate(size_t word_size) { void ChunkManager::print_on(outputStream* out) const { if (PrintFLSStatistics != 0) { - const_cast<ChunkManager *>(this)->humongous_dictionary()->report_statistics(); + _humongous_dictionary.report_statistics(); + } +} + +void ChunkManager::locked_get_statistics(ChunkManagerStatistics* stat) const { + assert_lock_strong(SpaceManager::expand_lock()); + for (ChunkIndex i = ZeroIndex; i < NumberOfFreeLists; i = next_chunk_index(i)) { + stat->num_by_type[i] = num_free_chunks(i); + stat->single_size_by_type[i] = size_by_index(i); + stat->total_size_by_type[i] = size_free_chunks_in_bytes(i); + } + stat->num_humongous_chunks = num_free_chunks(HumongousIndex); + stat->total_size_humongous_chunks = size_free_chunks_in_bytes(HumongousIndex); +} + +void ChunkManager::get_statistics(ChunkManagerStatistics* stat) const { + MutexLockerEx cl(SpaceManager::expand_lock(), + Mutex::_no_safepoint_check_flag); + locked_get_statistics(stat); +} + +void ChunkManager::print_statistics(const ChunkManagerStatistics* stat, outputStream* out, size_t scale) { + size_t total = 0; + assert(scale == 1 || scale == K || scale == M || scale == G, "Invalid scale"); + + const char* unit = scale_unit(scale); + for (ChunkIndex i = ZeroIndex; i < NumberOfFreeLists; i = next_chunk_index(i)) { + out->print(" " SIZE_FORMAT " %s (" SIZE_FORMAT " bytes) chunks, total ", + stat->num_by_type[i], chunk_size_name(i), + stat->single_size_by_type[i]); + if (scale == 1) { + out->print_cr(SIZE_FORMAT " bytes", stat->total_size_by_type[i]); + } else { + out->print_cr("%.2f%s", (float)stat->total_size_by_type[i] / scale, unit); + } + + total += stat->total_size_by_type[i]; + } + + total += stat->total_size_humongous_chunks; + + if (scale == 1) { + out->print_cr(" " SIZE_FORMAT " humongous chunks, total " SIZE_FORMAT " bytes", + stat->num_humongous_chunks, stat->total_size_humongous_chunks); + + out->print_cr(" total size: " SIZE_FORMAT " bytes.", total); + } else { + out->print_cr(" " SIZE_FORMAT " humongous chunks, total %.2f%s", + stat->num_humongous_chunks, + (float)stat->total_size_humongous_chunks / scale, unit); + + out->print_cr(" total size: %.2f%s.", (float)total / scale, unit); + } + +} + +void ChunkManager::print_all_chunkmanagers(outputStream* out, size_t scale) { + assert(scale == 1 || scale == K || scale == M || scale == G, "Invalid scale"); + + // Note: keep lock protection only to retrieving statistics; keep printing + // out of lock protection + ChunkManagerStatistics stat; + out->print_cr("Chunkmanager (non-class):"); + const ChunkManager* const non_class_cm = Metaspace::chunk_manager_metadata(); + if (non_class_cm != NULL) { + non_class_cm->get_statistics(&stat); + ChunkManager::print_statistics(&stat, out, scale); + } else { + out->print_cr("unavailable."); + } + out->print_cr("Chunkmanager (class):"); + const ChunkManager* const class_cm = Metaspace::chunk_manager_class(); + if (class_cm != NULL) { + class_cm->get_statistics(&stat); + ChunkManager::print_statistics(&stat, out, scale); + } else { + out->print_cr("unavailable."); } } @@ -2930,6 +3058,195 @@ void MetaspaceAux::print_waste(outputStream* out) { } } +class MetadataStats VALUE_OBJ_CLASS_SPEC { +private: + size_t _capacity; + size_t _used; + size_t _free; + size_t _waste; + +public: + MetadataStats() : _capacity(0), _used(0), _free(0), _waste(0) { } + MetadataStats(size_t capacity, size_t used, size_t free, size_t waste) + : _capacity(capacity), _used(used), _free(free), _waste(waste) { } + + void add(const MetadataStats& stats) { + _capacity += stats.capacity(); + _used += stats.used(); + _free += stats.free(); + _waste += stats.waste(); + } + + size_t capacity() const { return _capacity; } + size_t used() const { return _used; } + size_t free() const { return _free; } + size_t waste() const { return _waste; } + + void print_on(outputStream* out, size_t scale) const; +}; + + +void MetadataStats::print_on(outputStream* out, size_t scale) const { + const char* unit = scale_unit(scale); + out->print_cr("capacity=%10.2f%s used=%10.2f%s free=%10.2f%s waste=%10.2f%s", + (float)capacity() / scale, unit, + (float)used() / scale, unit, + (float)free() / scale, unit, + (float)waste() / scale, unit); +} + +class PrintCLDMetaspaceInfoClosure : public CLDClosure { +private: + outputStream* _out; + size_t _scale; + + size_t _total_count; + MetadataStats _total_metadata; + MetadataStats _total_class; + + size_t _total_anon_count; + MetadataStats _total_anon_metadata; + MetadataStats _total_anon_class; + +public: + PrintCLDMetaspaceInfoClosure(outputStream* out, size_t scale = K) + : _out(out), _scale(scale), _total_count(0), _total_anon_count(0) { } + + ~PrintCLDMetaspaceInfoClosure() { + print_summary(); + } + + void do_cld(ClassLoaderData* cld) { + assert(SafepointSynchronize::is_at_safepoint(), "Must be at a safepoint"); + + if (cld->is_unloading()) return; + Metaspace* msp = cld->metaspace_or_null(); + if (msp == NULL) { + return; + } + + bool anonymous = false; + if (cld->is_anonymous()) { + _out->print_cr("ClassLoader: for anonymous class"); + anonymous = true; + } else { + ResourceMark rm; + _out->print_cr("ClassLoader: %s", cld->loader_name()); + } + + print_metaspace(msp, anonymous); + _out->cr(); + } + +private: + void print_metaspace(Metaspace* msp, bool anonymous); + void print_summary() const; +}; + +void PrintCLDMetaspaceInfoClosure::print_metaspace(Metaspace* msp, bool anonymous){ + assert(msp != NULL, "Sanity"); + SpaceManager* vsm = msp->vsm(); + const char* unit = scale_unit(_scale); + + size_t capacity = vsm->sum_capacity_in_chunks_in_use() * BytesPerWord; + size_t used = vsm->sum_used_in_chunks_in_use() * BytesPerWord; + size_t free = vsm->sum_free_in_chunks_in_use() * BytesPerWord; + size_t waste = vsm->sum_waste_in_chunks_in_use() * BytesPerWord; + + _total_count ++; + MetadataStats metadata_stats(capacity, used, free, waste); + _total_metadata.add(metadata_stats); + + if (anonymous) { + _total_anon_count ++; + _total_anon_metadata.add(metadata_stats); + } + + _out->print(" Metadata "); + metadata_stats.print_on(_out, _scale); + + if (Metaspace::using_class_space()) { + vsm = msp->class_vsm(); + + capacity = vsm->sum_capacity_in_chunks_in_use() * BytesPerWord; + used = vsm->sum_used_in_chunks_in_use() * BytesPerWord; + free = vsm->sum_free_in_chunks_in_use() * BytesPerWord; + waste = vsm->sum_waste_in_chunks_in_use() * BytesPerWord; + + MetadataStats class_stats(capacity, used, free, waste); + _total_class.add(class_stats); + + if (anonymous) { + _total_anon_class.add(class_stats); + } + + _out->print(" Class data "); + class_stats.print_on(_out, _scale); + } +} + +void PrintCLDMetaspaceInfoClosure::print_summary() const { + const char* unit = scale_unit(_scale); + _out->cr(); + _out->print_cr("Summary:"); + + MetadataStats total; + total.add(_total_metadata); + total.add(_total_class); + + _out->print(" Total class loaders=" SIZE_FORMAT_W(6) " ", _total_count); + total.print_on(_out, _scale); + + _out->print(" Metadata "); + _total_metadata.print_on(_out, _scale); + + if (Metaspace::using_class_space()) { + _out->print(" Class data "); + _total_class.print_on(_out, _scale); + } + _out->cr(); + + MetadataStats total_anon; + total_anon.add(_total_anon_metadata); + total_anon.add(_total_anon_class); + + _out->print("For anonymous classes=" SIZE_FORMAT_W(6) " ", _total_anon_count); + total_anon.print_on(_out, _scale); + + _out->print(" Metadata "); + _total_anon_metadata.print_on(_out, _scale); + + if (Metaspace::using_class_space()) { + _out->print(" Class data "); + _total_anon_class.print_on(_out, _scale); + } +} + +void MetaspaceAux::print_metadata_for_nmt(outputStream* out, size_t scale) { + const char* unit = scale_unit(scale); + out->print_cr("Metaspaces:"); + out->print_cr(" Metadata space: reserved=" SIZE_FORMAT_W(10) "%s committed=" SIZE_FORMAT_W(10) "%s", + reserved_bytes(Metaspace::NonClassType) / scale, unit, + committed_bytes(Metaspace::NonClassType) / scale, unit); + if (Metaspace::using_class_space()) { + out->print_cr(" Class space: reserved=" SIZE_FORMAT_W(10) "%s committed=" SIZE_FORMAT_W(10) "%s", + reserved_bytes(Metaspace::ClassType) / scale, unit, + committed_bytes(Metaspace::ClassType) / scale, unit); + } + + out->cr(); + ChunkManager::print_all_chunkmanagers(out, scale); + + out->cr(); + out->print_cr("Per-classloader metadata:"); + out->cr(); + + PrintCLDMetaspaceInfoClosure cl(out, scale); + ClassLoaderDataGraph::cld_do(&cl); +} + + + // Dump global metaspace things from the end of ClassLoaderDataGraph void MetaspaceAux::dump(outputStream* out) { out->print_cr("All Metaspace:"); @@ -3743,6 +4060,7 @@ void Metaspace::report_metadata_oome(ClassLoaderData* loader_data, size_t word_s loader_data->dump(gclog_or_tty); } MetaspaceAux::dump(gclog_or_tty); + ChunkManager::print_all_chunkmanagers(gclog_or_tty); } bool out_of_compressed_class_space = false; diff --git a/hotspot/src/share/vm/memory/metaspace.hpp b/hotspot/src/share/vm/memory/metaspace.hpp index 122dd4b..ff1b232 100644 --- a/hotspot/src/share/vm/memory/metaspace.hpp +++ b/hotspot/src/share/vm/memory/metaspace.hpp @@ -65,6 +65,7 @@ class MetaspaceTracer; class MetaWord; class Mutex; class outputStream; +class PrintCLDMetaspaceInfoClosure; class SpaceManager; class VirtualSpaceList; @@ -88,6 +89,7 @@ class Metaspace : public CHeapObj<mtClass> { friend class VM_CollectForMetadataAllocation; friend class MetaspaceGC; friend class MetaspaceAux; + friend class PrintCLDMetaspaceInfoClosure; public: enum MetadataType { @@ -372,6 +374,8 @@ class MetaspaceAux : AllStatic { return min_chunk_size_words() * BytesPerWord; } + static void print_metadata_for_nmt(outputStream* out, size_t scale = K); + static bool has_chunk_free_list(Metaspace::MetadataType mdtype); static MetaspaceChunkFreeListSummary chunk_free_list_summary(Metaspace::MetadataType mdtype); diff --git a/hotspot/src/share/vm/runtime/vm_operations.cpp b/hotspot/src/share/vm/runtime/vm_operations.cpp index d401ea6..b42d18f 100644 --- a/hotspot/src/share/vm/runtime/vm_operations.cpp +++ b/hotspot/src/share/vm/runtime/vm_operations.cpp @@ -209,6 +209,10 @@ void VM_PrintJNI::doit() { JNIHandles::print_on(_out); } +void VM_PrintMetadata::doit() { + MetaspaceAux::print_metadata_for_nmt(_out, _scale); +} + VM_FindDeadlocks::~VM_FindDeadlocks() { if (_deadlocks != NULL) { DeadlockCycle* cycle = _deadlocks; diff --git a/hotspot/src/share/vm/runtime/vm_operations.hpp b/hotspot/src/share/vm/runtime/vm_operations.hpp index 3744040..19c33f8 100644 --- a/hotspot/src/share/vm/runtime/vm_operations.hpp +++ b/hotspot/src/share/vm/runtime/vm_operations.hpp @@ -101,6 +101,7 @@ template(ClassLoaderHierarchyOperation) \ template(JFROldObject) \ template(PrintClasses) \ + template(PrintMetadata) \ class VM_Operation: public CHeapObj<mtInternal> { public: @@ -329,6 +330,17 @@ class VM_PrintJNI: public VM_Operation { void doit(); }; +class VM_PrintMetadata : public VM_Operation { + private: + outputStream* _out; + size_t _scale; + public: + VM_PrintMetadata(outputStream* out, size_t scale) : _out(out), _scale(scale) {}; + + VMOp_Type type() const { return VMOp_PrintMetadata; } + void doit(); +}; + class DeadlockCycle; class VM_FindDeadlocks: public VM_Operation { private: diff --git a/hotspot/src/share/vm/services/nmtDCmd.cpp b/hotspot/src/share/vm/services/nmtDCmd.cpp index fcad784..659ca33 100644 --- a/hotspot/src/share/vm/services/nmtDCmd.cpp +++ b/hotspot/src/share/vm/services/nmtDCmd.cpp @@ -24,6 +24,8 @@ #include "precompiled.hpp" #include "runtime/mutexLocker.hpp" +#include "runtime/vmThread.hpp" +#include "runtime/vm_operations.hpp" #include "services/nmtDCmd.hpp" #include "services/memReporter.hpp" #include "services/memTracker.hpp" @@ -38,6 +40,8 @@ NMTDCmd::NMTDCmd(outputStream* output, _detail("detail", "request runtime to report memory allocation >= " "1K by each callsite.", "BOOLEAN", false, "false"), + _metadata("metadata", "request runtime to report metadata information", + "BOOLEAN", false, "false"), _baseline("baseline", "request runtime to baseline current memory usage, " \ "so it can be compared against in later time.", "BOOLEAN", false, "false"), @@ -57,6 +61,7 @@ NMTDCmd::NMTDCmd(outputStream* output, "STRING", false, "KB") { _dcmdparser.add_dcmd_option(&_summary); _dcmdparser.add_dcmd_option(&_detail); + _dcmdparser.add_dcmd_option(&_metadata); _dcmdparser.add_dcmd_option(&_baseline); _dcmdparser.add_dcmd_option(&_summary_diff); _dcmdparser.add_dcmd_option(&_detail_diff); @@ -92,6 +97,7 @@ void NMTDCmd::execute(DCmdSource source, TRAPS) { int nopt = 0; if (_summary.is_set() && _summary.value()) { ++nopt; } if (_detail.is_set() && _detail.value()) { ++nopt; } + if (_metadata.is_set() && _metadata.value()) { ++nopt; } if (_baseline.is_set() && _baseline.value()) { ++nopt; } if (_summary_diff.is_set() && _summary_diff.value()) { ++nopt; } if (_detail_diff.is_set() && _detail_diff.value()) { ++nopt; } @@ -100,7 +106,7 @@ void NMTDCmd::execute(DCmdSource source, TRAPS) { if (nopt > 1) { output()->print_cr("At most one of the following option can be specified: " \ - "summary, detail, baseline, summary.diff, detail.diff, shutdown"); + "summary, detail, metadata, baseline, summary.diff, detail.diff, shutdown"); return; } else if (nopt == 0) { if (_summary.is_set()) { @@ -118,9 +124,13 @@ void NMTDCmd::execute(DCmdSource source, TRAPS) { report(true, scale_unit); } else if (_detail.value()) { if (!check_detail_tracking_level(output())) { - return; - } + return; + } report(false, scale_unit); + } else if (_metadata.value()) { + size_t scale = get_scale(_scale.value()); + VM_PrintMetadata op(output(), scale); + VMThread::execute(&op); } else if (_baseline.value()) { MemBaseline& baseline = MemTracker::get_baseline(); if (!baseline.baseline(MemTracker::tracking_level() != NMT_detail)) { diff --git a/hotspot/src/share/vm/services/nmtDCmd.hpp b/hotspot/src/share/vm/services/nmtDCmd.hpp index df1ab36..bbd1391 100644 --- a/hotspot/src/share/vm/services/nmtDCmd.hpp +++ b/hotspot/src/share/vm/services/nmtDCmd.hpp @@ -39,6 +39,7 @@ class NMTDCmd: public DCmdWithParser { protected: DCmdArgument<bool> _summary; DCmdArgument<bool> _detail; + DCmdArgument<bool> _metadata; DCmdArgument<bool> _baseline; DCmdArgument<bool> _summary_diff; DCmdArgument<bool> _detail_diff; -- 1.8.3.1
Locations
Projects
Search
Status Monitor
Help
Open Build Service
OBS Manuals
API Documentation
OBS Portal
Reporting a Bug
Contact
Mailing List
Forums
Chat (IRC)
Twitter
Open Build Service (OBS)
is an
openSUSE project
.
浙ICP备2022010568号-2