8201572: Improve Metaspace Statistics

Reviewed-by: adinn, zgu
This commit is contained in:
Thomas Stuefe 2018-04-24 18:06:32 +02:00
parent 4fc0229dcb
commit d9b3c3203e
23 changed files with 1746 additions and 870 deletions

View File

@ -110,6 +110,9 @@ enum ChunkIndex {
size_t get_size_for_nonhumongous_chunktype(ChunkIndex chunk_type, bool is_class);
ChunkIndex get_chunk_type_by_size(size_t size, bool is_class);
ChunkIndex next_chunk_index(ChunkIndex i);
ChunkIndex prev_chunk_index(ChunkIndex i);
// Returns a descriptive name for a chunk type.
const char* chunk_size_name(ChunkIndex index);
@ -184,7 +187,7 @@ class Metachunk : public Metabase<Metachunk> {
// Alignment of each allocation in the chunks.
static size_t object_alignment();
// Size of the Metachunk header, including alignment.
// Size of the Metachunk header, in words, including alignment.
static size_t overhead();
Metachunk(ChunkIndex chunktype, bool is_class, size_t word_size, VirtualSpaceNode* container);

File diff suppressed because it is too large Load Diff

View File

@ -68,6 +68,11 @@ class SpaceManager;
class VirtualSpaceList;
class CollectedHeap;
namespace metaspace {
namespace internals {
class ClassLoaderMetaspaceStatistics;
}}
// Metaspaces each have a SpaceManager and allocations
// are done by the SpaceManager. Allocations are done
// out of the current Metachunk. When the current Metachunk
@ -94,10 +99,12 @@ class Metaspace : public AllStatic {
MetadataTypeCount
};
enum MetaspaceType {
StandardMetaspaceType,
BootMetaspaceType,
AnonymousMetaspaceType,
ReflectionMetaspaceType
ZeroMetaspaceType = 0,
StandardMetaspaceType = ZeroMetaspaceType,
BootMetaspaceType = StandardMetaspaceType + 1,
AnonymousMetaspaceType = BootMetaspaceType + 1,
ReflectionMetaspaceType = AnonymousMetaspaceType + 1,
MetaspaceTypeCount
};
private:
@ -193,7 +200,6 @@ class Metaspace : public AllStatic {
static MetaWord* allocate(ClassLoaderData* loader_data, size_t word_size,
MetaspaceObj::Type type, TRAPS);
void deallocate(MetaWord* ptr, size_t byte_size, bool is_class);
static bool contains(const void* ptr);
static bool contains_non_shared(const void* ptr);
@ -238,96 +244,97 @@ class ClassLoaderMetaspace : public CHeapObj<mtClass> {
void initialize_first_chunk(Metaspace::MetaspaceType type, Metaspace::MetadataType mdtype);
Metachunk* get_initialization_chunk(Metaspace::MetaspaceType type, Metaspace::MetadataType mdtype);
const Metaspace::MetaspaceType _space_type;
Mutex* const _lock;
SpaceManager* _vsm;
SpaceManager* vsm() const { return _vsm; }
SpaceManager* _class_vsm;
SpaceManager* vsm() const { return _vsm; }
SpaceManager* class_vsm() const { return _class_vsm; }
SpaceManager* get_space_manager(Metaspace::MetadataType mdtype) {
assert(mdtype != Metaspace::MetadataTypeCount, "MetadaTypeCount can't be used as mdtype");
return mdtype == Metaspace::ClassType ? class_vsm() : vsm();
}
Mutex* lock() const { return _lock; }
MetaWord* expand_and_allocate(size_t size, Metaspace::MetadataType mdtype);
size_t class_chunk_size(size_t word_size);
// Adds to the given statistic object. Must be locked with CLD metaspace lock.
void add_to_statistics_locked(metaspace::internals::ClassLoaderMetaspaceStatistics* out) const;
public:
ClassLoaderMetaspace(Mutex* lock, Metaspace::MetaspaceType type);
~ClassLoaderMetaspace();
Metaspace::MetaspaceType space_type() const { return _space_type; }
// Allocate space for metadata of type mdtype. This is space
// within a Metachunk and is used by
// allocate(ClassLoaderData*, size_t, bool, MetadataType, TRAPS)
MetaWord* allocate(size_t word_size, Metaspace::MetadataType mdtype);
size_t used_words_slow(Metaspace::MetadataType mdtype) const;
size_t free_words_slow(Metaspace::MetadataType mdtype) const;
size_t capacity_words_slow(Metaspace::MetadataType mdtype) const;
size_t used_bytes_slow(Metaspace::MetadataType mdtype) const;
size_t capacity_bytes_slow(Metaspace::MetadataType mdtype) const;
size_t allocated_blocks_bytes() const;
size_t allocated_chunks_bytes() const;
void deallocate(MetaWord* ptr, size_t byte_size, bool is_class);
void dump(outputStream* const out) const;
void print_on(outputStream* st) const;
// Debugging support
void verify();
// Adds to the given statistic object. Will lock with CLD metaspace lock.
void add_to_statistics(metaspace::internals::ClassLoaderMetaspaceStatistics* out) const;
}; // ClassLoaderMetaspace
class MetaspaceUtils : AllStatic {
// Spacemanager updates running counters.
friend class SpaceManager;
// Running counters for statistics concerning in-use chunks.
// Note: capacity = used + free + waste + overhead. Note that we do not
// count free and waste. Their sum can be deduces from the three other values.
// For more details, one should call print_report() from within a safe point.
static size_t _capacity_words [Metaspace:: MetadataTypeCount];
static size_t _overhead_words [Metaspace:: MetadataTypeCount];
static volatile size_t _used_words [Metaspace:: MetadataTypeCount];
// Atomically decrement or increment in-use statistic counters
static void dec_capacity(Metaspace::MetadataType mdtype, size_t words);
static void inc_capacity(Metaspace::MetadataType mdtype, size_t words);
static void dec_used(Metaspace::MetadataType mdtype, size_t words);
static void inc_used(Metaspace::MetadataType mdtype, size_t words);
static void dec_overhead(Metaspace::MetadataType mdtype, size_t words);
static void inc_overhead(Metaspace::MetadataType mdtype, size_t words);
// Getters for the in-use counters.
static size_t capacity_words(Metaspace::MetadataType mdtype) { return _capacity_words[mdtype]; }
static size_t used_words(Metaspace::MetadataType mdtype) { return _used_words[mdtype]; }
static size_t overhead_words(Metaspace::MetadataType mdtype) { return _overhead_words[mdtype]; }
static size_t free_chunks_total_words(Metaspace::MetadataType mdtype);
// These methods iterate over the classloader data graph
// for the given Metaspace type. These are slow.
static size_t used_bytes_slow(Metaspace::MetadataType mdtype);
static size_t free_bytes_slow(Metaspace::MetadataType mdtype);
static size_t capacity_bytes_slow(Metaspace::MetadataType mdtype);
static size_t capacity_bytes_slow();
// Helper for print_xx_report.
static void print_vs(outputStream* out, size_t scale);
// Running sum of space in all Metachunks that has been
// allocated to a Metaspace. This is used instead of
// iterating over all the classloaders. One for each
// type of Metadata
static size_t _capacity_words[Metaspace:: MetadataTypeCount];
// Running sum of space in all Metachunks that
// are being used for metadata. One for each
// type of Metadata.
static volatile size_t _used_words[Metaspace:: MetadataTypeCount];
public:
public:
// Decrement and increment _allocated_capacity_words
static void dec_capacity(Metaspace::MetadataType type, size_t words);
static void inc_capacity(Metaspace::MetadataType type, size_t words);
// Decrement and increment _allocated_used_words
static void dec_used(Metaspace::MetadataType type, size_t words);
static void inc_used(Metaspace::MetadataType type, size_t words);
// Total of space allocated to metadata in all Metaspaces.
// This sums the space used in each Metachunk by
// iterating over the classloader data graph
static size_t used_bytes_slow() {
return used_bytes_slow(Metaspace::ClassType) +
used_bytes_slow(Metaspace::NonClassType);
}
// Collect used metaspace statistics. This involves walking the CLDG. The resulting
// output will be the accumulated values for all live metaspaces.
// Note: method does not do any locking.
static void collect_statistics(metaspace::internals::ClassLoaderMetaspaceStatistics* out);
// Used by MetaspaceCounters
static size_t free_chunks_total_words();
static size_t free_chunks_total_bytes();
static size_t free_chunks_total_bytes(Metaspace::MetadataType mdtype);
static size_t capacity_words(Metaspace::MetadataType mdtype) {
return _capacity_words[mdtype];
}
static size_t capacity_words() {
return capacity_words(Metaspace::NonClassType) +
capacity_words(Metaspace::ClassType);
@ -339,9 +346,6 @@ class MetaspaceUtils : AllStatic {
return capacity_words() * BytesPerWord;
}
static size_t used_words(Metaspace::MetadataType mdtype) {
return _used_words[mdtype];
}
static size_t used_words() {
return used_words(Metaspace::NonClassType) +
used_words(Metaspace::ClassType);
@ -353,8 +357,9 @@ class MetaspaceUtils : AllStatic {
return used_words() * BytesPerWord;
}
static size_t free_bytes();
static size_t free_bytes(Metaspace::MetadataType mdtype);
// Space committed but yet unclaimed by any class loader.
static size_t free_in_vs_bytes();
static size_t free_in_vs_bytes(Metaspace::MetadataType mdtype);
static size_t reserved_bytes(Metaspace::MetadataType mdtype);
static size_t reserved_bytes() {
@ -373,7 +378,29 @@ class MetaspaceUtils : AllStatic {
return min_chunk_size_words() * BytesPerWord;
}
static void print_metadata_for_nmt(outputStream* out, size_t scale = K);
// Flags for print_report().
enum ReportFlag {
// Show usage by class loader.
rf_show_loaders = (1 << 0),
// Breaks report down by chunk type (small, medium, ...).
rf_break_down_by_chunktype = (1 << 1),
// Breaks report down by space type (anonymous, reflection, ...).
rf_break_down_by_spacetype = (1 << 2),
// Print details about the underlying virtual spaces.
rf_show_vslist = (1 << 3),
// Print metaspace map.
rf_show_vsmap = (1 << 4)
};
// This will print out a basic metaspace usage report but
// unlike print_report() is guaranteed not to lock or to walk the CLDG.
static void print_basic_report(outputStream* st, size_t scale);
// Prints a report about the current metaspace state.
// Optional parts can be enabled via flags.
// Function will walk the CLDG and will lock the expand lock; if that is not
// convenient, use print_basic_report() instead.
static void print_report(outputStream* out, size_t scale = 0, int flags = 0);
static bool has_chunk_free_list(Metaspace::MetadataType mdtype);
static MetaspaceChunkFreeListSummary chunk_free_list_summary(Metaspace::MetadataType mdtype);
@ -381,20 +408,13 @@ class MetaspaceUtils : AllStatic {
// Print change in used metadata.
static void print_metaspace_change(size_t prev_metadata_used);
static void print_on(outputStream * out);
static void print_on(outputStream * out, Metaspace::MetadataType mdtype);
static void print_class_waste(outputStream* out);
static void print_waste(outputStream* out);
// Prints an ASCII representation of the given space.
static void print_metaspace_map(outputStream* out, Metaspace::MetadataType mdtype);
static void dump(outputStream* out);
static void verify_free_chunks();
// Checks that the values returned by allocated_capacity_bytes() and
// capacity_bytes_slow() are the same.
static void verify_capacity();
static void verify_used();
// Check internal counters (capacity, used).
static void verify_metrics();
};

View File

@ -0,0 +1,132 @@
/*
* Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2018, SAP 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 "memory/metaspace/metaspaceCommon.hpp"
#include "utilities/globalDefinitions.hpp"
#include "utilities/ostream.hpp"
namespace metaspace {
namespace internals {
// Print a size, in words, scaled.
void print_scaled_words(outputStream* st, size_t word_size, size_t scale, int width) {
print_human_readable_size(st, word_size * sizeof(MetaWord), scale, width);
}
// Convenience helper: prints a size value and a percentage.
void print_scaled_words_and_percentage(outputStream* st, size_t word_size, size_t compare_word_size, size_t scale, int width) {
print_scaled_words(st, word_size, scale, width);
st->print(" (");
print_percentage(st, compare_word_size, word_size);
st->print(")");
}
// Print a human readable size.
// byte_size: size, in bytes, to be printed.
// scale: one of 1 (byte-wise printing), sizeof(word) (word-size printing), K, M, G (scaled by KB, MB, GB respectively,
// or 0, which means the best scale is choosen dynamically.
// width: printing width.
void print_human_readable_size(outputStream* st, size_t byte_size, size_t scale, int width) {
if (scale == 0) {
// Dynamic mode. Choose scale for this value.
if (byte_size == 0) {
// Zero values are printed as bytes.
scale = 1;
} else {
if (byte_size >= G) {
scale = G;
} else if (byte_size >= M) {
scale = M;
} else if (byte_size >= K) {
scale = K;
} else {
scale = 1;
}
}
return print_human_readable_size(st, byte_size, scale, width);
}
#ifdef ASSERT
assert(scale == 1 || scale == BytesPerWord || scale == K || scale == M || scale == G, "Invalid scale");
// Special case: printing wordsize should only be done with word-sized values
if (scale == BytesPerWord) {
assert(byte_size % BytesPerWord == 0, "not word sized");
}
#endif
if (scale == 1) {
st->print("%*" PRIuPTR " bytes", width, byte_size);
} else if (scale == BytesPerWord) {
st->print("%*" PRIuPTR " words", width, byte_size / BytesPerWord);
} else {
const char* display_unit = "";
switch(scale) {
case 1: display_unit = "bytes"; break;
case BytesPerWord: display_unit = "words"; break;
case K: display_unit = "KB"; break;
case M: display_unit = "MB"; break;
case G: display_unit = "GB"; break;
default:
ShouldNotReachHere();
}
float display_value = (float) byte_size / scale;
// Since we use width to display a number with two trailing digits, increase it a bit.
width += 3;
// Prevent very small but non-null values showing up as 0.00.
if (byte_size > 0 && display_value < 0.01f) {
st->print("%*s %s", width, "<0.01", display_unit);
} else {
st->print("%*.2f %s", width, display_value, display_unit);
}
}
}
// Prints a percentage value. Values smaller than 1% but not 0 are displayed as "<1%", values
// larger than 99% but not 100% are displayed as ">100%".
void print_percentage(outputStream* st, size_t total, size_t part) {
if (total == 0) {
st->print(" ?%%");
} else if (part == 0) {
st->print(" 0%%");
} else if (part == total) {
st->print("100%%");
} else {
// Note: clearly print very-small-but-not-0% and very-large-but-not-100% percentages.
float p = ((float)part / total) * 100.0f;
if (p < 1.0f) {
st->print(" <1%%");
} else if (p > 99.0f){
st->print(">99%%");
} else {
st->print("%3.0f%%", p);
}
}
}
} // namespace internals
} // namespace metaspace

View File

@ -0,0 +1,56 @@
/*
* Copyright (c) 2018, 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.
*
*/
#ifndef SHARE_MEMORY_METASPACE_METASPACECOMMON_HPP_
#define SHARE_MEMORY_METASPACE_METASPACECOMMON_HPP_
#include "utilities/globalDefinitions.hpp"
class outputStream;
namespace metaspace {
namespace internals {
// Print a size, in words, scaled.
void print_scaled_words(outputStream* st, size_t word_size, size_t scale = 0, int width = -1);
// Convenience helper: prints a size value and a percentage.
void print_scaled_words_and_percentage(outputStream* st, size_t word_size, size_t compare_word_size, size_t scale = 0, int width = -1);
// Print a human readable size.
// byte_size: size, in bytes, to be printed.
// scale: one of 1 (byte-wise printing), sizeof(word) (word-size printing), K, M, G (scaled by KB, MB, GB respectively,
// or 0, which means the best scale is choosen dynamically.
// width: printing width.
void print_human_readable_size(outputStream* st, size_t byte_size, size_t scale = 0, int width = -1);
// Prints a percentage value. Values smaller than 1% but not 0 are displayed as "<1%", values
// larger than 99% but not 100% are displayed as ">100%".
void print_percentage(outputStream* st, size_t total, size_t part);
} // namespace internals
} // namespace metaspace
#endif /* SHARE_MEMORY_METASPACE_METASPACESTATISTICS_HPP_ */

View File

@ -0,0 +1,100 @@
/*
* Copyright (c) 2018, 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 "memory/metaspace.hpp"
#include "memory/metaspace/metaspaceDCmd.hpp"
#include "memory/resourceArea.hpp"
#include "services/diagnosticCommand.hpp"
#include "services/nmtCommon.hpp"
namespace metaspace {
MetaspaceDCmd::MetaspaceDCmd(outputStream* output, bool heap)
: DCmdWithParser(output, heap)
, _basic("basic", "Prints a basic summary (does not need a safepoint).", "BOOLEAN", false, "false")
, _show_loaders("show-loaders", "Shows usage by class loader.", "BOOLEAN", false, "false")
, _by_chunktype("by-chunktype", "Break down numbers by chunk type.", "BOOLEAN", false, "false")
, _by_spacetype("by-spacetype", "Break down numbers by loader type.", "BOOLEAN", false, "false")
, _show_vslist("vslist", "Shows details about the underlying virtual space.", "BOOLEAN", false, "false")
, _show_vsmap("vsmap", "Shows chunk composition of the underlying virtual spaces", "BOOLEAN", false, "false")
, _scale("scale", "Memory usage in which to scale. Valid values are: 1, KB, MB or GB (fixed scale) "
"or \"dynamic\" for a dynamically choosen scale.",
"STRING", false, "dynamic")
{
_dcmdparser.add_dcmd_option(&_basic);
_dcmdparser.add_dcmd_option(&_show_loaders);
_dcmdparser.add_dcmd_option(&_by_chunktype);
_dcmdparser.add_dcmd_option(&_by_spacetype);
_dcmdparser.add_dcmd_option(&_show_vslist);
_dcmdparser.add_dcmd_option(&_show_vsmap);
_dcmdparser.add_dcmd_option(&_scale);
}
int MetaspaceDCmd::num_arguments() {
ResourceMark rm;
MetaspaceDCmd* dcmd = new MetaspaceDCmd(NULL, false);
if (dcmd != NULL) {
DCmdMark mark(dcmd);
return dcmd->_dcmdparser.num_arguments();
} else {
return 0;
}
}
void MetaspaceDCmd::execute(DCmdSource source, TRAPS) {
// Parse scale value.
const char* scale_value = _scale.value();
size_t scale = 0;
if (scale_value != NULL) {
if (strcasecmp("dynamic", scale_value) == 0) {
scale = 0;
} else {
scale = NMTUtil::scale_from_name(scale_value);
if (scale == 0) {
output()->print_cr("Invalid scale: \"%s\". Will use dynamic scaling.", scale_value);
}
}
}
if (_basic.value() == true) {
if (_show_loaders.value() || _by_chunktype.value() || _by_spacetype.value() ||
_show_vslist.value() || _show_vsmap.value()) {
// Basic mode. Just print essentials. Does not need to be at a safepoint.
output()->print_cr("In basic mode, additional arguments are ignored.");
}
MetaspaceUtils::print_basic_report(output(), scale);
} else {
// Full mode. Requires safepoint.
int flags = 0;
if (_show_loaders.value()) flags |= MetaspaceUtils::rf_show_loaders;
if (_by_chunktype.value()) flags |= MetaspaceUtils::rf_break_down_by_chunktype;
if (_by_spacetype.value()) flags |= MetaspaceUtils::rf_break_down_by_spacetype;
if (_show_vslist.value()) flags |= MetaspaceUtils::rf_show_vslist;
if (_show_vsmap.value()) flags |= MetaspaceUtils::rf_show_vsmap;
VM_PrintMetadata op(output(), scale, flags);
VMThread::execute(&op);
}
}
} // namespace metaspace

View File

@ -21,16 +21,44 @@
* questions.
*
*/
#include "precompiled.hpp"
#include "memory/metaspace.hpp"
#ifndef SHARE_MEMORY_METASPACE_METASPACEDCMD_HPP_
#define SHARE_MEMORY_METASPACE_METASPACEDCMD_HPP_
#include "services/diagnosticCommand.hpp"
MetaspaceDCmd::MetaspaceDCmd(outputStream* output, bool heap): DCmd(output, heap) {
}
class outputStream;
void MetaspaceDCmd::execute(DCmdSource source, TRAPS) {
const size_t scale = 1 * K;
VM_PrintMetadata op(output(), scale);
VMThread::execute(&op);
}
namespace metaspace {
class MetaspaceDCmd : public DCmdWithParser {
DCmdArgument<bool> _basic;
DCmdArgument<bool> _show_loaders;
DCmdArgument<bool> _by_spacetype;
DCmdArgument<bool> _by_chunktype;
DCmdArgument<bool> _show_vslist;
DCmdArgument<bool> _show_vsmap;
DCmdArgument<char*> _scale;
public:
MetaspaceDCmd(outputStream* output, bool heap);
static const char* name() {
return "VM.metaspace";
}
static const char* description() {
return "Prints the statistics for the metaspace";
}
static const char* impact() {
return "Medium: Depends on number of classes loaded.";
}
static const JavaPermission permission() {
JavaPermission p = {"java.lang.management.ManagementPermission",
"monitor", NULL};
return p;
}
static int num_arguments();
virtual void execute(DCmdSource source, TRAPS);
};
} // namespace metaspace
#endif /* SHARE_MEMORY_METASPACE_METASPACESTATISTICS_HPP_ */

View File

@ -0,0 +1,278 @@
/*
* Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2018, SAP 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 "memory/metachunk.hpp"
#include "memory/metaspace/metaspaceCommon.hpp"
#include "memory/metaspace/metaspaceStatistics.hpp"
#include "utilities/debug.hpp"
#include "utilities/globalDefinitions.hpp"
#include "utilities/ostream.hpp"
namespace metaspace {
namespace internals {
// FreeChunksStatistics methods
FreeChunksStatistics::FreeChunksStatistics()
: _num(0), _cap(0)
{}
void FreeChunksStatistics::reset() {
_num = 0; _cap = 0;
}
void FreeChunksStatistics::add(uintx n, size_t s) {
_num += n; _cap += s;
}
void FreeChunksStatistics::add(const FreeChunksStatistics& other) {
_num += other._num;
_cap += other._cap;
}
void FreeChunksStatistics::print_on(outputStream* st, size_t scale) const {
st->print(UINTX_FORMAT, _num);
st->print(" chunks, total capacity ");
print_scaled_words(st, _cap, scale);
}
// ChunkManagerStatistics methods
void ChunkManagerStatistics::reset() {
for (ChunkIndex i = ZeroIndex; i < NumberOfInUseLists; i = next_chunk_index(i)) {
_chunk_stats[i].reset();
}
}
size_t ChunkManagerStatistics::total_capacity() const {
return _chunk_stats[SpecializedIndex].cap() +
_chunk_stats[SmallIndex].cap() +
_chunk_stats[MediumIndex].cap() +
_chunk_stats[HumongousIndex].cap();
}
void ChunkManagerStatistics::print_on(outputStream* st, size_t scale) const {
FreeChunksStatistics totals;
for (ChunkIndex i = ZeroIndex; i < NumberOfInUseLists; i = next_chunk_index(i)) {
st->cr();
st->print("%12s chunks: ", chunk_size_name(i));
if (_chunk_stats[i].num() > 0) {
st->print(UINTX_FORMAT_W(4) ", capacity ", _chunk_stats[i].num());
print_scaled_words(st, _chunk_stats[i].cap(), scale);
} else {
st->print("(none)");
}
totals.add(_chunk_stats[i]);
}
st->cr();
st->print("%19s: " UINTX_FORMAT_W(4) ", capacity=", "Total", totals.num());
print_scaled_words(st, totals.cap(), scale);
st->cr();
}
// UsedChunksStatistics methods
UsedChunksStatistics::UsedChunksStatistics()
: _num(0), _cap(0), _used(0), _free(0), _waste(0), _overhead(0)
{}
void UsedChunksStatistics::reset() {
_num = 0;
_cap = _overhead = _used = _free = _waste = 0;
}
void UsedChunksStatistics::add(const UsedChunksStatistics& other) {
_num += other._num;
_cap += other._cap;
_used += other._used;
_free += other._free;
_waste += other._waste;
_overhead += other._overhead;
DEBUG_ONLY(check_sanity());
}
void UsedChunksStatistics::print_on(outputStream* st, size_t scale) const {
int col = st->position();
st->print(UINTX_FORMAT_W(4) " chunk%s, ", _num, _num != 1 ? "s" : "");
if (_num > 0) {
col += 14; st->fill_to(col);
print_scaled_words(st, _cap, scale, 5);
st->print(" capacity, ");
col += 18; st->fill_to(col);
print_scaled_words_and_percentage(st, _used, _cap, scale, 5);
st->print(" used, ");
col += 20; st->fill_to(col);
print_scaled_words_and_percentage(st, _free, _cap, scale, 5);
st->print(" free, ");
col += 20; st->fill_to(col);
print_scaled_words_and_percentage(st, _waste, _cap, scale, 5);
st->print(" waste, ");
col += 20; st->fill_to(col);
print_scaled_words_and_percentage(st, _overhead, _cap, scale, 5);
st->print(" overhead");
}
DEBUG_ONLY(check_sanity());
}
#ifdef ASSERT
void UsedChunksStatistics::check_sanity() const {
assert(_overhead == (Metachunk::overhead() * _num), "Sanity: Overhead.");
assert(_cap == _used + _free + _waste + _overhead, "Sanity: Capacity.");
}
#endif
// SpaceManagerStatistics methods
SpaceManagerStatistics::SpaceManagerStatistics() { reset(); }
void SpaceManagerStatistics::reset() {
for (int i = 0; i < NumberOfInUseLists; i ++) {
_chunk_stats[i].reset();
_free_blocks_num = 0; _free_blocks_cap_words = 0;
}
}
void SpaceManagerStatistics::add_free_blocks_info(uintx num, size_t cap) {
_free_blocks_num += num;
_free_blocks_cap_words += cap;
}
void SpaceManagerStatistics::add(const SpaceManagerStatistics& other) {
for (ChunkIndex i = ZeroIndex; i < NumberOfInUseLists; i = next_chunk_index(i)) {
_chunk_stats[i].add(other._chunk_stats[i]);
}
_free_blocks_num += other._free_blocks_num;
_free_blocks_cap_words += other._free_blocks_cap_words;
}
// Returns total chunk statistics over all chunk types.
UsedChunksStatistics SpaceManagerStatistics::totals() const {
UsedChunksStatistics stat;
for (ChunkIndex i = ZeroIndex; i < NumberOfInUseLists; i = next_chunk_index(i)) {
stat.add(_chunk_stats[i]);
}
return stat;
}
void SpaceManagerStatistics::print_on(outputStream* st, size_t scale, bool detailed) const {
streamIndentor sti(st);
if (detailed) {
st->cr_indent();
st->print("Usage by chunk type:");
{
streamIndentor sti2(st);
for (ChunkIndex i = ZeroIndex; i < NumberOfInUseLists; i = next_chunk_index(i)) {
st->cr_indent();
st->print("%15s: ", chunk_size_name(i));
if (_chunk_stats[i].num() == 0) {
st->print(" (none)");
} else {
_chunk_stats[i].print_on(st, scale);
}
}
st->cr_indent();
st->print("%15s: ", "-total-");
totals().print_on(st, scale);
}
if (_free_blocks_num > 0) {
st->cr_indent();
st->print("deallocated: " UINTX_FORMAT " blocks with ", _free_blocks_num);
print_scaled_words(st, _free_blocks_cap_words, scale);
}
} else {
totals().print_on(st, scale);
st->print(", ");
st->print("deallocated: " UINTX_FORMAT " blocks with ", _free_blocks_num);
print_scaled_words(st, _free_blocks_cap_words, scale);
}
}
// ClassLoaderMetaspaceStatistics methods
ClassLoaderMetaspaceStatistics::ClassLoaderMetaspaceStatistics() { reset(); }
void ClassLoaderMetaspaceStatistics::reset() {
nonclass_sm_stats().reset();
if (Metaspace::using_class_space()) {
class_sm_stats().reset();
}
}
// Returns total space manager statistics for both class and non-class metaspace
SpaceManagerStatistics ClassLoaderMetaspaceStatistics::totals() const {
SpaceManagerStatistics stats;
stats.add(nonclass_sm_stats());
if (Metaspace::using_class_space()) {
stats.add(class_sm_stats());
}
return stats;
}
void ClassLoaderMetaspaceStatistics::add(const ClassLoaderMetaspaceStatistics& other) {
nonclass_sm_stats().add(other.nonclass_sm_stats());
if (Metaspace::using_class_space()) {
class_sm_stats().add(other.class_sm_stats());
}
}
void ClassLoaderMetaspaceStatistics::print_on(outputStream* st, size_t scale, bool detailed) const {
streamIndentor sti(st);
st->cr_indent();
if (Metaspace::using_class_space()) {
st->print("Non-Class: ");
}
nonclass_sm_stats().print_on(st, scale, detailed);
if (detailed) {
st->cr();
}
if (Metaspace::using_class_space()) {
st->cr_indent();
st->print(" Class: ");
class_sm_stats().print_on(st, scale, detailed);
if (detailed) {
st->cr();
}
st->cr_indent();
st->print(" Both: ");
totals().print_on(st, scale, detailed);
if (detailed) {
st->cr();
}
}
st->cr();
}
} // end namespace internals
} // end namespace metaspace

View File

@ -0,0 +1,189 @@
/*
* Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2018, SAP 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.
*
*/
#ifndef SHARE_MEMORY_METASPACE_METASPACESTATISTICS_HPP_
#define SHARE_MEMORY_METASPACE_METASPACESTATISTICS_HPP_
#include "utilities/globalDefinitions.hpp"
#include "memory/metachunk.hpp" // for ChunkIndex enum
#include "memory/metaspace.hpp" // for MetadataType enum
class outputStream;
namespace metaspace {
namespace internals {
// Contains statistics for a number of free chunks.
class FreeChunksStatistics {
uintx _num; // Number of chunks
size_t _cap; // Total capacity, in words
public:
FreeChunksStatistics();
void reset();
uintx num() const { return _num; }
size_t cap() const { return _cap; }
void add(uintx n, size_t s);
void add(const FreeChunksStatistics& other);
void print_on(outputStream* st, size_t scale) const;
}; // end: FreeChunksStatistics
// Contains statistics for a ChunkManager.
class ChunkManagerStatistics {
FreeChunksStatistics _chunk_stats[NumberOfInUseLists];
public:
// Free chunk statistics, by chunk index.
const FreeChunksStatistics& chunk_stats(ChunkIndex index) const { return _chunk_stats[index]; }
FreeChunksStatistics& chunk_stats(ChunkIndex index) { return _chunk_stats[index]; }
void reset();
size_t total_capacity() const;
void print_on(outputStream* st, size_t scale) const;
}; // ChunkManagerStatistics
// Contains statistics for a number of chunks in use.
// Each chunk has a used and free portion; however, there are current chunks (serving
// potential future metaspace allocations) and non-current chunks. Unused portion of the
// former is counted as free, unused portion of the latter counts as waste.
class UsedChunksStatistics {
uintx _num; // Number of chunks
size_t _cap; // Total capacity in words.
size_t _used; // Total used area, in words
size_t _free; // Total free area (unused portions of current chunks), in words
size_t _waste; // Total waste area (unused portions of non-current chunks), in words
size_t _overhead; // Total sum of chunk overheads, in words.
public:
UsedChunksStatistics();
void reset();
uintx num() const { return _num; }
// Total capacity, in words
size_t cap() const { return _cap; }
// Total used area, in words
size_t used() const { return _used; }
// Total free area (unused portions of current chunks), in words
size_t free() const { return _free; }
// Total waste area (unused portions of non-current chunks), in words
size_t waste() const { return _waste; }
// Total area spent in overhead (chunk headers), in words
size_t overhead() const { return _overhead; }
void add_num(uintx n) { _num += n; }
void add_cap(size_t s) { _cap += s; }
void add_used(size_t s) { _used += s; }
void add_free(size_t s) { _free += s; }
void add_waste(size_t s) { _waste += s; }
void add_overhead(size_t s) { _overhead += s; }
void add(const UsedChunksStatistics& other);
void print_on(outputStream* st, size_t scale) const;
#ifdef ASSERT
void check_sanity() const;
#endif
}; // UsedChunksStatistics
// Class containing statistics for one or more space managers.
class SpaceManagerStatistics {
UsedChunksStatistics _chunk_stats[NumberOfInUseLists];
uintx _free_blocks_num;
size_t _free_blocks_cap_words;
public:
SpaceManagerStatistics();
// Chunk statistics by chunk index
const UsedChunksStatistics& chunk_stats(ChunkIndex index) const { return _chunk_stats[index]; }
UsedChunksStatistics& chunk_stats(ChunkIndex index) { return _chunk_stats[index]; }
uintx free_blocks_num () const { return _free_blocks_num; }
size_t free_blocks_cap_words () const { return _free_blocks_cap_words; }
void reset();
void add_free_blocks_info(uintx num, size_t cap);
// Returns total chunk statistics over all chunk types.
UsedChunksStatistics totals() const;
void add(const SpaceManagerStatistics& other);
void print_on(outputStream* st, size_t scale, bool detailed) const;
}; // SpaceManagerStatistics
class ClassLoaderMetaspaceStatistics {
SpaceManagerStatistics _sm_stats[Metaspace::MetadataTypeCount];
public:
ClassLoaderMetaspaceStatistics();
const SpaceManagerStatistics& sm_stats(Metaspace::MetadataType mdType) const { return _sm_stats[mdType]; }
SpaceManagerStatistics& sm_stats(Metaspace::MetadataType mdType) { return _sm_stats[mdType]; }
const SpaceManagerStatistics& nonclass_sm_stats() const { return sm_stats(Metaspace::NonClassType); }
SpaceManagerStatistics& nonclass_sm_stats() { return sm_stats(Metaspace::NonClassType); }
const SpaceManagerStatistics& class_sm_stats() const { return sm_stats(Metaspace::ClassType); }
SpaceManagerStatistics& class_sm_stats() { return sm_stats(Metaspace::ClassType); }
void reset();
void add(const ClassLoaderMetaspaceStatistics& other);
// Returns total space manager statistics for both class and non-class metaspace
SpaceManagerStatistics totals() const;
void print_on(outputStream* st, size_t scale, bool detailed) const;
}; // ClassLoaderMetaspaceStatistics
} // namespace internals
} // namespace metaspace
#endif /* SHARE_MEMORY_METASPACE_METASPACESTATISTICS_HPP_ */

View File

@ -235,7 +235,7 @@ void VM_PrintJNI::doit() {
}
void VM_PrintMetadata::doit() {
MetaspaceUtils::print_metadata_for_nmt(_out, _scale);
MetaspaceUtils::print_report(_out, _scale, _flags);
}
VM_FindDeadlocks::~VM_FindDeadlocks() {

View File

@ -391,10 +391,14 @@ class VM_PrintJNI: public VM_Operation {
class VM_PrintMetadata : public VM_Operation {
private:
outputStream* _out;
size_t _scale;
outputStream* const _out;
const size_t _scale;
const int _flags;
public:
VM_PrintMetadata(outputStream* out, size_t scale) : _out(out), _scale(scale) {};
VM_PrintMetadata(outputStream* out, size_t scale, int flags)
: _out(out), _scale(scale), _flags(flags)
{};
VMOp_Type type() const { return VMOp_PrintMetadata; }
void doit();

View File

@ -29,6 +29,7 @@
#include "compiler/compileBroker.hpp"
#include "compiler/directivesParser.hpp"
#include "gc/shared/vmGCOperations.hpp"
#include "memory/metaspace/metaspaceDCmd.hpp"
#include "memory/resourceArea.hpp"
#include "oops/objArrayOop.inline.hpp"
#include "oops/oop.inline.hpp"
@ -90,7 +91,7 @@ void DCmdRegistrant::register_dcmds(){
DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<ClassHierarchyDCmd>(full_export, true, false));
DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<SymboltableDCmd>(full_export, true, false));
DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<StringtableDCmd>(full_export, true, false));
DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<MetaspaceDCmd>(full_export, true, false));
DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<metaspace::MetaspaceDCmd>(full_export, true, false));
#if INCLUDE_JVMTI // Both JVMTI and SERVICES have to be enabled to have this dcmd
DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<JVMTIAgentLoadDCmd>(full_export, true, false));
#endif // INCLUDE_JVMTI

View File

@ -866,25 +866,4 @@ public:
virtual void execute(DCmdSource source, TRAPS);
};
class MetaspaceDCmd : public DCmd {
public:
MetaspaceDCmd(outputStream* output, bool heap);
static const char* name() {
return "VM.metaspace";
}
static const char* description() {
return "Prints the statistics for the metaspace";
}
static const char* impact() {
return "Medium: Depends on number of classes loaded.";
}
static const JavaPermission permission() {
JavaPermission p = {"java.lang.management.ManagementPermission",
"monitor", NULL};
return p;
}
static int num_arguments() { return 0; }
virtual void execute(DCmdSource source, TRAPS);
};
#endif // SHARE_VM_SERVICES_DIAGNOSTICCOMMAND_HPP

View File

@ -201,7 +201,7 @@ void MemSummaryReporter::report_metadata(Metaspace::MetadataType type) const {
size_t used = MetaspaceUtils::used_bytes(type);
size_t free = (MetaspaceUtils::capacity_bytes(type) - used)
+ MetaspaceUtils::free_chunks_total_bytes(type)
+ MetaspaceUtils::free_bytes(type);
+ MetaspaceUtils::free_in_vs_bytes(type);
assert(committed >= used + free, "Sanity");
size_t waste = committed - (used + free);

View File

@ -177,10 +177,12 @@ void MemTracker::report(bool summary_only, outputStream* output) {
} else {
MemDetailReporter rpt(baseline, output);
rpt.report();
output->print("Metaspace:");
// Metadata reporting requires a safepoint, so avoid it if VM is not in good state.
assert(!VMError::fatal_error_in_progress(), "Do not report metadata in error report");
VM_PrintMetadata vmop(output, K);
VM_PrintMetadata vmop(output, K,
MetaspaceUtils::rf_show_loaders |
MetaspaceUtils::rf_break_down_by_spacetype);
VMThread::execute(&vmop);
}
}

View File

@ -23,6 +23,7 @@
*/
#include "precompiled.hpp"
#include "services/nmtCommon.hpp"
#include "utilities/globalDefinitions.hpp"
const char* NMTUtil::_memory_type_names[] = {
"Java Heap",
@ -59,14 +60,13 @@ const char* NMTUtil::scale_name(size_t scale) {
size_t NMTUtil::scale_from_name(const char* scale) {
assert(scale != NULL, "Null pointer check");
if (strncmp(scale, "KB", 2) == 0 ||
strncmp(scale, "kb", 2) == 0) {
if (strcasecmp(scale, "1") == 0 || strcasecmp(scale, "b") == 0) {
return 1;
} else if (strcasecmp(scale, "kb") == 0 || strcasecmp(scale, "k") == 0) {
return K;
} else if (strncmp(scale, "MB", 2) == 0 ||
strncmp(scale, "mb", 2) == 0) {
} else if (strcasecmp(scale, "mb") == 0 || strcasecmp(scale, "m") == 0) {
return M;
} else if (strncmp(scale, "GB", 2) == 0 ||
strncmp(scale, "gb", 2) == 0) {
} else if (strcasecmp(scale, "gb") == 0 || strcasecmp(scale, "g") == 0) {
return G;
} else {
return 0; // Invalid value

View File

@ -617,7 +617,7 @@ void MetaspaceSnapshot::snapshot(Metaspace::MetadataType type, MetaspaceSnapshot
size_t free_in_bytes = (MetaspaceUtils::capacity_bytes(type) - MetaspaceUtils::used_bytes(type))
+ MetaspaceUtils::free_chunks_total_bytes(type)
+ MetaspaceUtils::free_bytes(type);
+ MetaspaceUtils::free_in_vs_bytes(type);
mss._free_in_bytes[type] = free_in_bytes;
}

View File

@ -206,6 +206,10 @@ void outputStream::cr() {
this->write("\n", 1);
}
void outputStream::cr_indent() {
cr(); indent();
}
void outputStream::stamp() {
if (! _stamp.is_updated()) {
_stamp.update(); // start at 0 on first call to stamp()

View File

@ -102,8 +102,10 @@ class outputStream : public ResourceObj {
void put(char ch);
void sp(int count = 1);
void cr();
void cr_indent();
void bol() { if (_position > 0) cr(); }
// Time stamp
TimeStamp& time_stamp() { return _stamp; }
void stamp();
@ -152,7 +154,6 @@ class streamIndentor : public StackObj {
~streamIndentor() { _str->dec(_amount); }
};
// advisory locking for the shared tty stream:
class ttyLocker: StackObj {
friend class ttyUnlocker;

View File

@ -862,6 +862,13 @@ void VMError::report(outputStream* st, bool _verbose) {
st->cr();
}
STEP("printing metaspace information")
if (_verbose && Universe::is_fully_initialized()) {
st->print_cr("Metaspace:");
MetaspaceUtils::print_basic_report(st, 0);
}
STEP("printing code cache information")
if (_verbose && Universe::is_fully_initialized()) {
@ -1046,6 +1053,13 @@ void VMError::print_vm_info(outputStream* st) {
st->cr();
}
// STEP("printing metaspace information")
if (Universe::is_fully_initialized()) {
st->print_cr("Metaspace:");
MetaspaceUtils::print_basic_report(st, 0);
}
// STEP("printing code cache information")
if (Universe::is_fully_initialized()) {

View File

@ -27,7 +27,7 @@
# It also contains test-suite configuration information.
# The list of keywords supported in this test suite
keys=cte_test jcmd nmt regression gc stress
keys=cte_test jcmd nmt regression gc stress metaspace
groups=TEST.groups

View File

@ -0,0 +1,126 @@
/*
* Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2018, SAP 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.
*/
import jdk.test.lib.process.ProcessTools;
import jdk.test.lib.process.OutputAnalyzer;
import jdk.test.lib.JDKToolFinder;
/*
* @test
* @key metaspace jcmd
* @summary Test the VM.metaspace command
* @library /test/lib
* @modules java.base/jdk.internal.misc
* java.management
* @run main/othervm -XX:MaxMetaspaceSize=201M -XX:+VerifyMetaspace -XX:+UseCompressedClassPointers PrintMetaspaceDcmd with-compressed-class-space
* @run main/othervm -XX:MaxMetaspaceSize=201M -XX:+VerifyMetaspace -XX:-UseCompressedClassPointers PrintMetaspaceDcmd without-compressed-class-space
*/
public class PrintMetaspaceDcmd {
// Run jcmd VM.metaspace against a VM with CompressedClassPointers on.
// The report should detail Non-Class and Class portions separately.
private static void doTheTest(boolean usesCompressedClassSpace) throws Exception {
ProcessBuilder pb = new ProcessBuilder();
OutputAnalyzer output;
// Grab my own PID
String pid = Long.toString(ProcessTools.getProcessId());
pb.command(new String[] { JDKToolFinder.getJDKTool("jcmd"), pid, "VM.metaspace", "basic"});
output = new OutputAnalyzer(pb.start());
output.shouldHaveExitValue(0);
if (usesCompressedClassSpace) {
output.shouldContain("Non-Class:");
output.shouldContain("Class:");
}
output.shouldContain("Virtual space:");
output.shouldContain("Chunk freelists:");
pb.command(new String[] { JDKToolFinder.getJDKTool("jcmd"), pid, "VM.metaspace"});
output = new OutputAnalyzer(pb.start());
output.shouldHaveExitValue(0);
if (usesCompressedClassSpace) {
output.shouldContain("Non-Class:");
output.shouldContain("Class:");
}
output.shouldContain("Virtual space:");
output.shouldContain("Chunk freelist");
output.shouldContain("Waste");
output.shouldMatch("MaxMetaspaceSize:.*201.00.*MB");
pb.command(new String[] { JDKToolFinder.getJDKTool("jcmd"), pid, "VM.metaspace", "show-loaders"});
output = new OutputAnalyzer(pb.start());
output.shouldHaveExitValue(0);
output.shouldMatch("ClassLoaderData.*for <bootloader>");
pb.command(new String[] { JDKToolFinder.getJDKTool("jcmd"), pid, "VM.metaspace", "by-chunktype"});
output = new OutputAnalyzer(pb.start());
output.shouldHaveExitValue(0);
output.shouldContain("specialized:");
output.shouldContain("small:");
output.shouldContain("medium:");
output.shouldContain("humongous:");
pb.command(new String[] { JDKToolFinder.getJDKTool("jcmd"), pid, "VM.metaspace", "vslist"});
output = new OutputAnalyzer(pb.start());
output.shouldHaveExitValue(0);
output.shouldContain("Virtual space list");
output.shouldMatch("node.*reserved.*committed.*used.*");
pb.command(new String[] { JDKToolFinder.getJDKTool("jcmd"), pid, "VM.metaspace", "vsmap"});
output = new OutputAnalyzer(pb.start());
output.shouldHaveExitValue(0);
output.shouldContain("Virtual space map:");
output.shouldContain("HHHHHHHHHHH");
// Test with different scales
pb.command(new String[] { JDKToolFinder.getJDKTool("jcmd"), pid, "VM.metaspace", "scale=G"});
output = new OutputAnalyzer(pb.start());
output.shouldHaveExitValue(0);
output.shouldMatch("MaxMetaspaceSize:.*0.2.*GB");
pb.command(new String[] { JDKToolFinder.getJDKTool("jcmd"), pid, "VM.metaspace", "scale=K"});
output = new OutputAnalyzer(pb.start());
output.shouldHaveExitValue(0);
output.shouldMatch("MaxMetaspaceSize:.*205824.00 KB");
pb.command(new String[] { JDKToolFinder.getJDKTool("jcmd"), pid, "VM.metaspace", "scale=1"});
output = new OutputAnalyzer(pb.start());
output.shouldHaveExitValue(0);
output.shouldMatch("MaxMetaspaceSize:.*210763776 bytes");
}
public static void main(String args[]) throws Exception {
boolean testForCompressedClassSpace = false;
if (args[0].equals("with-compressed-class-space")) {
testForCompressedClassSpace = true;
} else if (args[0].equals("without-compressed-class-space")) {
testForCompressedClassSpace = false;
} else {
throw new IllegalArgumentException("Invalid argument: " + args[0]);
}
doTheTest(testForCompressedClassSpace);
}
}

View File

@ -46,6 +46,10 @@ public class PrintNMTStatistics {
OutputAnalyzer output_detail = new OutputAnalyzer(pb.start());
output_detail.shouldContain("Virtual memory map:");
output_detail.shouldContain("Details:");
// PrintNMTStatistics also prints out metaspace statistics as a convenience.
output_detail.shouldContain("Metaspace:");
output_detail.shouldHaveExitValue(0);
// Make sure memory reserved for Module processing is recorded.