提交 7eb73d98 编写于 作者: E ehelin

8024718: Metaspace performance counters and memory pools should report the same data

Reviewed-by: stefank, dholmes, coleenp
上级 2230ab03
...@@ -65,26 +65,25 @@ class MetaspacePerfCounters: public CHeapObj<mtInternal> { ...@@ -65,26 +65,25 @@ class MetaspacePerfCounters: public CHeapObj<mtInternal> {
MetaspacePerfCounters* MetaspaceCounters::_perf_counters = NULL; MetaspacePerfCounters* MetaspaceCounters::_perf_counters = NULL;
size_t MetaspaceCounters::calculate_capacity() { size_t MetaspaceCounters::used() {
// The total capacity is the sum of return MetaspaceAux::allocated_used_bytes();
// 1) capacity of Metachunks in use by all Metaspaces }
// 2) unused space at the end of each Metachunk
// 3) space in the freelist size_t MetaspaceCounters::capacity() {
size_t total_capacity = MetaspaceAux::allocated_capacity_bytes() return MetaspaceAux::committed_bytes();
+ MetaspaceAux::free_bytes() + MetaspaceAux::free_chunks_total_bytes(); }
return total_capacity;
size_t MetaspaceCounters::max_capacity() {
return MetaspaceAux::reserved_bytes();
} }
void MetaspaceCounters::initialize_performance_counters() { void MetaspaceCounters::initialize_performance_counters() {
if (UsePerfData) { if (UsePerfData) {
assert(_perf_counters == NULL, "Should only be initialized once"); assert(_perf_counters == NULL, "Should only be initialized once");
size_t min_capacity = MetaspaceAux::min_chunk_size_bytes(); size_t min_capacity = 0;
size_t capacity = calculate_capacity(); _perf_counters = new MetaspacePerfCounters("metaspace", min_capacity,
size_t max_capacity = MetaspaceAux::reserved_bytes(); capacity(), max_capacity(), used());
size_t used = MetaspaceAux::allocated_used_bytes();
_perf_counters = new MetaspacePerfCounters("metaspace", min_capacity, capacity, max_capacity, used);
} }
} }
...@@ -92,31 +91,29 @@ void MetaspaceCounters::update_performance_counters() { ...@@ -92,31 +91,29 @@ void MetaspaceCounters::update_performance_counters() {
if (UsePerfData) { if (UsePerfData) {
assert(_perf_counters != NULL, "Should be initialized"); assert(_perf_counters != NULL, "Should be initialized");
size_t capacity = calculate_capacity(); _perf_counters->update(capacity(), max_capacity(), used());
size_t max_capacity = MetaspaceAux::reserved_bytes();
size_t used = MetaspaceAux::allocated_used_bytes();
_perf_counters->update(capacity, max_capacity, used);
} }
} }
MetaspacePerfCounters* CompressedClassSpaceCounters::_perf_counters = NULL; MetaspacePerfCounters* CompressedClassSpaceCounters::_perf_counters = NULL;
size_t CompressedClassSpaceCounters::calculate_capacity() { size_t CompressedClassSpaceCounters::used() {
return MetaspaceAux::allocated_capacity_bytes(_class_type) + return MetaspaceAux::allocated_used_bytes(Metaspace::ClassType);
MetaspaceAux::free_bytes(_class_type) + }
MetaspaceAux::free_chunks_total_bytes(_class_type);
size_t CompressedClassSpaceCounters::capacity() {
return MetaspaceAux::committed_bytes(Metaspace::ClassType);
}
size_t CompressedClassSpaceCounters::max_capacity() {
return MetaspaceAux::reserved_bytes(Metaspace::ClassType);
} }
void CompressedClassSpaceCounters::update_performance_counters() { void CompressedClassSpaceCounters::update_performance_counters() {
if (UsePerfData && UseCompressedClassPointers) { if (UsePerfData && UseCompressedClassPointers) {
assert(_perf_counters != NULL, "Should be initialized"); assert(_perf_counters != NULL, "Should be initialized");
size_t capacity = calculate_capacity(); _perf_counters->update(capacity(), max_capacity(), used());
size_t max_capacity = MetaspaceAux::reserved_bytes(_class_type);
size_t used = MetaspaceAux::allocated_used_bytes(_class_type);
_perf_counters->update(capacity, max_capacity, used);
} }
} }
...@@ -126,12 +123,9 @@ void CompressedClassSpaceCounters::initialize_performance_counters() { ...@@ -126,12 +123,9 @@ void CompressedClassSpaceCounters::initialize_performance_counters() {
const char* ns = "compressedclassspace"; const char* ns = "compressedclassspace";
if (UseCompressedClassPointers) { if (UseCompressedClassPointers) {
size_t min_capacity = MetaspaceAux::min_chunk_size_bytes(); size_t min_capacity = 0;
size_t capacity = calculate_capacity(); _perf_counters = new MetaspacePerfCounters(ns, min_capacity, capacity(),
size_t max_capacity = MetaspaceAux::reserved_bytes(_class_type); max_capacity(), used());
size_t used = MetaspaceAux::allocated_used_bytes(_class_type);
_perf_counters = new MetaspacePerfCounters(ns, min_capacity, capacity, max_capacity, used);
} else { } else {
_perf_counters = new MetaspacePerfCounters(ns, 0, 0, 0, 0); _perf_counters = new MetaspacePerfCounters(ns, 0, 0, 0, 0);
} }
......
...@@ -25,13 +25,15 @@ ...@@ -25,13 +25,15 @@
#ifndef SHARE_VM_MEMORY_METASPACECOUNTERS_HPP #ifndef SHARE_VM_MEMORY_METASPACECOUNTERS_HPP
#define SHARE_VM_MEMORY_METASPACECOUNTERS_HPP #define SHARE_VM_MEMORY_METASPACECOUNTERS_HPP
#include "memory/metaspace.hpp" #include "memory/allocation.hpp"
class MetaspacePerfCounters; class MetaspacePerfCounters;
class MetaspaceCounters: public AllStatic { class MetaspaceCounters: public AllStatic {
static MetaspacePerfCounters* _perf_counters; static MetaspacePerfCounters* _perf_counters;
static size_t calculate_capacity(); static size_t used();
static size_t capacity();
static size_t max_capacity();
public: public:
static void initialize_performance_counters(); static void initialize_performance_counters();
...@@ -40,8 +42,9 @@ class MetaspaceCounters: public AllStatic { ...@@ -40,8 +42,9 @@ class MetaspaceCounters: public AllStatic {
class CompressedClassSpaceCounters: public AllStatic { class CompressedClassSpaceCounters: public AllStatic {
static MetaspacePerfCounters* _perf_counters; static MetaspacePerfCounters* _perf_counters;
static size_t calculate_capacity(); static size_t used();
static const Metaspace::MetadataType _class_type = Metaspace::ClassType; static size_t capacity();
static size_t max_capacity();
public: public:
static void initialize_performance_counters(); static void initialize_performance_counters();
......
...@@ -260,10 +260,10 @@ MemoryUsage CodeHeapPool::get_memory_usage() { ...@@ -260,10 +260,10 @@ MemoryUsage CodeHeapPool::get_memory_usage() {
} }
MetaspacePool::MetaspacePool() : MetaspacePool::MetaspacePool() :
MemoryPool("Metaspace", NonHeap, capacity_in_bytes(), calculate_max_size(), true, false) { } MemoryPool("Metaspace", NonHeap, 0, calculate_max_size(), true, false) { }
MemoryUsage MetaspacePool::get_memory_usage() { MemoryUsage MetaspacePool::get_memory_usage() {
size_t committed = align_size_down_(capacity_in_bytes(), os::vm_page_size()); size_t committed = MetaspaceAux::committed_bytes();
return MemoryUsage(initial_size(), used_in_bytes(), committed, max_size()); return MemoryUsage(initial_size(), used_in_bytes(), committed, max_size());
} }
...@@ -271,26 +271,19 @@ size_t MetaspacePool::used_in_bytes() { ...@@ -271,26 +271,19 @@ size_t MetaspacePool::used_in_bytes() {
return MetaspaceAux::allocated_used_bytes(); return MetaspaceAux::allocated_used_bytes();
} }
size_t MetaspacePool::capacity_in_bytes() const {
return MetaspaceAux::allocated_capacity_bytes();
}
size_t MetaspacePool::calculate_max_size() const { size_t MetaspacePool::calculate_max_size() const {
return FLAG_IS_CMDLINE(MaxMetaspaceSize) ? MaxMetaspaceSize : max_uintx; return FLAG_IS_CMDLINE(MaxMetaspaceSize) ? MaxMetaspaceSize :
MemoryUsage::undefined_size();
} }
CompressedKlassSpacePool::CompressedKlassSpacePool() : CompressedKlassSpacePool::CompressedKlassSpacePool() :
MemoryPool("Compressed Class Space", NonHeap, capacity_in_bytes(), CompressedClassSpaceSize, true, false) { } MemoryPool("Compressed Class Space", NonHeap, 0, CompressedClassSpaceSize, true, false) { }
size_t CompressedKlassSpacePool::used_in_bytes() { size_t CompressedKlassSpacePool::used_in_bytes() {
return MetaspaceAux::allocated_used_bytes(Metaspace::ClassType); return MetaspaceAux::allocated_used_bytes(Metaspace::ClassType);
} }
size_t CompressedKlassSpacePool::capacity_in_bytes() const {
return MetaspaceAux::allocated_capacity_bytes(Metaspace::ClassType);
}
MemoryUsage CompressedKlassSpacePool::get_memory_usage() { MemoryUsage CompressedKlassSpacePool::get_memory_usage() {
size_t committed = align_size_down_(capacity_in_bytes(), os::vm_page_size()); size_t committed = MetaspaceAux::committed_bytes(Metaspace::ClassType);
return MemoryUsage(initial_size(), used_in_bytes(), committed, max_size()); return MemoryUsage(initial_size(), used_in_bytes(), committed, max_size());
} }
...@@ -224,7 +224,6 @@ public: ...@@ -224,7 +224,6 @@ public:
class MetaspacePool : public MemoryPool { class MetaspacePool : public MemoryPool {
size_t calculate_max_size() const; size_t calculate_max_size() const;
size_t capacity_in_bytes() const;
public: public:
MetaspacePool(); MetaspacePool();
MemoryUsage get_memory_usage(); MemoryUsage get_memory_usage();
...@@ -232,7 +231,6 @@ class MetaspacePool : public MemoryPool { ...@@ -232,7 +231,6 @@ class MetaspacePool : public MemoryPool {
}; };
class CompressedKlassSpacePool : public MemoryPool { class CompressedKlassSpacePool : public MemoryPool {
size_t capacity_in_bytes() const;
public: public:
CompressedKlassSpacePool(); CompressedKlassSpacePool();
MemoryUsage get_memory_usage(); MemoryUsage get_memory_usage();
......
...@@ -63,10 +63,12 @@ public: ...@@ -63,10 +63,12 @@ public:
size_t committed() const { return _committed; } size_t committed() const { return _committed; }
size_t max_size() const { return _maxSize; } size_t max_size() const { return _maxSize; }
static size_t undefined_size() { return (size_t) -1; }
inline static jlong convert_to_jlong(size_t val) { inline static jlong convert_to_jlong(size_t val) {
// In the 64-bit vm, a size_t can overflow a jlong (which is signed). // In the 64-bit vm, a size_t can overflow a jlong (which is signed).
jlong ret; jlong ret;
if (val == (size_t)-1) { if (val == undefined_size()) {
ret = -1L; ret = -1L;
} else { } else {
NOT_LP64(ret = val;) NOT_LP64(ret = val;)
......
...@@ -22,18 +22,15 @@ ...@@ -22,18 +22,15 @@
*/ */
import java.util.List; import java.util.List;
import java.lang.management.ManagementFactory; import java.lang.management.*;
import java.lang.management.MemoryManagerMXBean; import com.oracle.java.testlibrary.*;
import java.lang.management.MemoryPoolMXBean; import static com.oracle.java.testlibrary.Asserts.*;
import java.lang.management.MemoryUsage;
import java.lang.management.RuntimeMXBean;
import java.lang.management.ManagementFactory;
/* @test TestMetaspaceMemoryPool /* @test TestMetaspaceMemoryPool
* @bug 8000754 * @bug 8000754
* @summary Tests that a MemoryPoolMXBeans is created for metaspace and that a * @summary Tests that a MemoryPoolMXBeans is created for metaspace and that a
* MemoryManagerMXBean is created. * MemoryManagerMXBean is created.
* @library /testlibrary
* @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:-UseCompressedOops TestMetaspaceMemoryPool * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:-UseCompressedOops TestMetaspaceMemoryPool
* @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:-UseCompressedOops -XX:MaxMetaspaceSize=60m TestMetaspaceMemoryPool * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:-UseCompressedOops -XX:MaxMetaspaceSize=60m TestMetaspaceMemoryPool
* @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:+UseCompressedOops -XX:+UseCompressedClassPointers TestMetaspaceMemoryPool * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:+UseCompressedOops -XX:+UseCompressedClassPointers TestMetaspaceMemoryPool
...@@ -42,35 +39,18 @@ import java.lang.management.ManagementFactory; ...@@ -42,35 +39,18 @@ import java.lang.management.ManagementFactory;
public class TestMetaspaceMemoryPool { public class TestMetaspaceMemoryPool {
public static void main(String[] args) { public static void main(String[] args) {
verifyThatMetaspaceMemoryManagerExists(); verifyThatMetaspaceMemoryManagerExists();
verifyMemoryPool(getMemoryPool("Metaspace"), isFlagDefined("MaxMetaspaceSize"));
if (runsOn64bit()) { boolean isMetaspaceMaxDefined = InputArguments.containsPrefix("-XX:MaxMetaspaceSize");
if (usesCompressedOops()) { verifyMemoryPool(getMemoryPool("Metaspace"), isMetaspaceMaxDefined);
if (Platform.is64bit()) {
if (InputArguments.contains("-XX:+UseCompressedOops")) {
MemoryPoolMXBean cksPool = getMemoryPool("Compressed Class Space"); MemoryPoolMXBean cksPool = getMemoryPool("Compressed Class Space");
verifyMemoryPool(cksPool, true); verifyMemoryPool(cksPool, true);
} }
} }
} }
private static boolean runsOn64bit() {
return !System.getProperty("sun.arch.data.model").equals("32");
}
private static boolean usesCompressedOops() {
return isFlagDefined("+UseCompressedOops");
}
private static boolean isFlagDefined(String name) {
RuntimeMXBean runtimeMxBean = ManagementFactory.getRuntimeMXBean();
List<String> args = runtimeMxBean.getInputArguments();
for (String arg : args) {
if (arg.startsWith("-XX:" + name)) {
return true;
}
}
return false;
}
private static void verifyThatMetaspaceMemoryManagerExists() { private static void verifyThatMetaspaceMemoryManagerExists() {
List<MemoryManagerMXBean> managers = ManagementFactory.getMemoryManagerMXBeans(); List<MemoryManagerMXBean> managers = ManagementFactory.getMemoryManagerMXBeans();
for (MemoryManagerMXBean manager : managers) { for (MemoryManagerMXBean manager : managers) {
...@@ -95,32 +75,19 @@ public class TestMetaspaceMemoryPool { ...@@ -95,32 +75,19 @@ public class TestMetaspaceMemoryPool {
private static void verifyMemoryPool(MemoryPoolMXBean pool, boolean isMaxDefined) { private static void verifyMemoryPool(MemoryPoolMXBean pool, boolean isMaxDefined) {
MemoryUsage mu = pool.getUsage(); MemoryUsage mu = pool.getUsage();
assertDefined(mu.getInit(), "init"); long init = mu.getInit();
assertDefined(mu.getUsed(), "used"); long used = mu.getUsed();
assertDefined(mu.getCommitted(), "committed"); long committed = mu.getCommitted();
long max = mu.getMax();
assertGTE(init, 0L);
assertGTE(used, init);
assertGTE(committed, used);
if (isMaxDefined) { if (isMaxDefined) {
assertDefined(mu.getMax(), "max"); assertGTE(max, committed);
} else { } else {
assertUndefined(mu.getMax(), "max"); assertEQ(max, -1L);
}
}
private static void assertDefined(long value, String name) {
assertTrue(value != -1, "Expected " + name + " to be defined");
}
private static void assertUndefined(long value, String name) {
assertEquals(value, -1, "Expected " + name + " to be undefined");
}
private static void assertEquals(long actual, long expected, String msg) {
assertTrue(actual == expected, msg);
}
private static void assertTrue(boolean condition, String msg) {
if (!condition) {
throw new RuntimeException(msg);
} }
} }
} }
...@@ -61,10 +61,15 @@ public class TestMetaspacePerfCounters { ...@@ -61,10 +61,15 @@ public class TestMetaspacePerfCounters {
} }
private static void checkPerfCounters(String ns) throws Exception { private static void checkPerfCounters(String ns) throws Exception {
for (PerfCounter counter : countersInNamespace(ns)) { long minCapacity = getMinCapacity(ns);
String msg = "Expected " + counter.getName() + " to be larger than 0"; long maxCapacity = getMaxCapacity(ns);
assertGT(counter.longValue(), 0L, msg); long capacity = getCapacity(ns);
} long used = getUsed(ns);
assertGTE(minCapacity, 0L);
assertGTE(used, minCapacity);
assertGTE(capacity, used);
assertGTE(maxCapacity, capacity);
} }
private static void checkEmptyPerfCounters(String ns) throws Exception { private static void checkEmptyPerfCounters(String ns) throws Exception {
...@@ -75,12 +80,10 @@ public class TestMetaspacePerfCounters { ...@@ -75,12 +80,10 @@ public class TestMetaspacePerfCounters {
} }
private static void checkUsedIncreasesWhenLoadingClass(String ns) throws Exception { private static void checkUsedIncreasesWhenLoadingClass(String ns) throws Exception {
PerfCounter used = PerfCounters.findByName(ns + ".used"); long before = getUsed(ns);
long before = used.longValue();
fooClass = compileAndLoad("Foo", "public class Foo { }"); fooClass = compileAndLoad("Foo", "public class Foo { }");
System.gc(); System.gc();
long after = used.longValue(); long after = getUsed(ns);
assertGT(after, before); assertGT(after, before);
} }
...@@ -101,4 +104,20 @@ public class TestMetaspacePerfCounters { ...@@ -101,4 +104,20 @@ public class TestMetaspacePerfCounters {
private static boolean isUsingCompressedClassPointers() { private static boolean isUsingCompressedClassPointers() {
return Platform.is64bit() && InputArguments.contains("-XX:+UseCompressedClassPointers"); return Platform.is64bit() && InputArguments.contains("-XX:+UseCompressedClassPointers");
} }
private static long getMinCapacity(String ns) throws Exception {
return PerfCounters.findByName(ns + ".minCapacity").longValue();
}
private static long getCapacity(String ns) throws Exception {
return PerfCounters.findByName(ns + ".capacity").longValue();
}
private static long getMaxCapacity(String ns) throws Exception {
return PerfCounters.findByName(ns + ".maxCapacity").longValue();
}
private static long getUsed(String ns) throws Exception {
return PerfCounters.findByName(ns + ".used").longValue();
}
} }
/*
* Copyright (c) 2013, 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.
*/
import java.util.List;
import java.lang.management.*;
import com.oracle.java.testlibrary.*;
import static com.oracle.java.testlibrary.Asserts.*;
/* @test TestPerfCountersAndMemoryPools
* @bug 8023476
* @summary Tests that a MemoryPoolMXBeans and PerfCounters for metaspace
* report the same data.
* @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:-UseCompressedOops -XX:-UseCompressedKlassPointers -XX:+UseSerialGC -XX:+UsePerfData TestPerfCountersAndMemoryPools
* @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:+UseCompressedOops -XX:+UseCompressedKlassPointers -XX:+UseSerialGC -XX:+UsePerfData TestPerfCountersAndMemoryPools
*/
public class TestPerfCountersAndMemoryPools {
public static void main(String[] args) throws Exception {
checkMemoryUsage("Metaspace", "sun.gc.metaspace");
if (InputArguments.contains("-XX:+UseCompressedKlassPointers") && Platform.is64bit()) {
checkMemoryUsage("Compressed Class Space", "sun.gc.compressedclassspace");
}
}
private static MemoryUsage getMemoryUsage(String memoryPoolName) {
List<MemoryPoolMXBean> pools = ManagementFactory.getMemoryPoolMXBeans();
for (MemoryPoolMXBean pool : pools) {
if (pool.getName().equals(memoryPoolName)) {
return pool.getUsage();
}
}
throw new RuntimeException("Excpted to find a memory pool with name " +
memoryPoolName);
}
private static void checkMemoryUsage(String memoryPoolName, String perfNS)
throws Exception {
// Need to do a gc before each comparison to update the perf counters
System.gc();
MemoryUsage mu = getMemoryUsage(memoryPoolName);
assertEQ(getMinCapacity(perfNS), mu.getInit());
System.gc();
mu = getMemoryUsage(memoryPoolName);
assertEQ(getUsed(perfNS), mu.getUsed());
System.gc();
mu = getMemoryUsage(memoryPoolName);
assertEQ(getCapacity(perfNS), mu.getCommitted());
}
private static long getMinCapacity(String ns) throws Exception {
return PerfCounters.findByName(ns + ".minCapacity").longValue();
}
private static long getCapacity(String ns) throws Exception {
return PerfCounters.findByName(ns + ".capacity").longValue();
}
private static long getUsed(String ns) throws Exception {
return PerfCounters.findByName(ns + ".used").longValue();
}
}
...@@ -41,6 +41,9 @@ public class InputArguments { ...@@ -41,6 +41,9 @@ public class InputArguments {
/** /**
* Returns true if {@code arg} is an input argument to the VM. * Returns true if {@code arg} is an input argument to the VM.
* *
* This is useful for checking boolean flags such as -XX:+UseSerialGC or
* -XX:-UsePerfData.
*
* @param arg The name of the argument. * @param arg The name of the argument.
* @return {@code true} if the given argument is an input argument, * @return {@code true} if the given argument is an input argument,
* otherwise {@code false}. * otherwise {@code false}.
...@@ -48,4 +51,26 @@ public class InputArguments { ...@@ -48,4 +51,26 @@ public class InputArguments {
public static boolean contains(String arg) { public static boolean contains(String arg) {
return args.contains(arg); return args.contains(arg);
} }
/**
* Returns true if {@code prefix} is the start of an input argument to the
* VM.
*
* This is useful for checking if flags describing a quantity, such as
* -XX:+MaxMetaspaceSize=100m, is set without having to know the quantity.
* To check if the flag -XX:MaxMetaspaceSize is set, use
* {@code InputArguments.containsPrefix("-XX:MaxMetaspaceSize")}.
*
* @param prefix The start of the argument.
* @return {@code true} if the given argument is the start of an input
* argument, otherwise {@code false}.
*/
public static boolean containsPrefix(String prefix) {
for (String arg : args) {
if (arg.startsWith(prefix)) {
return true;
}
}
return false;
}
} }
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册