8024718: Metaspace performance counters and memory pools should report the same data
Reviewed-by: stefank, dholmes, coleenp
--- a/hotspot/src/share/vm/memory/metaspaceCounters.cpp Wed Sep 18 00:08:00 2013 +0000
+++ b/hotspot/src/share/vm/memory/metaspaceCounters.cpp Tue Sep 17 20:59:07 2013 +0200
@@ -65,26 +65,25 @@
MetaspacePerfCounters* MetaspaceCounters::_perf_counters = NULL;
-size_t MetaspaceCounters::calculate_capacity() {
- // The total capacity is the sum of
- // 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 total_capacity = MetaspaceAux::allocated_capacity_bytes()
- + MetaspaceAux::free_bytes() + MetaspaceAux::free_chunks_total_bytes();
- return total_capacity;
+size_t MetaspaceCounters::used() {
+ return MetaspaceAux::allocated_used_bytes();
+}
+
+size_t MetaspaceCounters::capacity() {
+ return MetaspaceAux::committed_bytes();
+}
+
+size_t MetaspaceCounters::max_capacity() {
+ return MetaspaceAux::reserved_bytes();
}
void MetaspaceCounters::initialize_performance_counters() {
if (UsePerfData) {
assert(_perf_counters == NULL, "Should only be initialized once");
- size_t min_capacity = MetaspaceAux::min_chunk_size_bytes();
- size_t capacity = calculate_capacity();
- size_t max_capacity = MetaspaceAux::reserved_bytes();
- size_t used = MetaspaceAux::allocated_used_bytes();
-
- _perf_counters = new MetaspacePerfCounters("metaspace", min_capacity, capacity, max_capacity, used);
+ size_t min_capacity = 0;
+ _perf_counters = new MetaspacePerfCounters("metaspace", min_capacity,
+ capacity(), max_capacity(), used());
}
}
@@ -92,31 +91,29 @@
if (UsePerfData) {
assert(_perf_counters != NULL, "Should be initialized");
- size_t capacity = calculate_capacity();
- size_t max_capacity = MetaspaceAux::reserved_bytes();
- size_t used = MetaspaceAux::allocated_used_bytes();
-
- _perf_counters->update(capacity, max_capacity, used);
+ _perf_counters->update(capacity(), max_capacity(), used());
}
}
MetaspacePerfCounters* CompressedClassSpaceCounters::_perf_counters = NULL;
-size_t CompressedClassSpaceCounters::calculate_capacity() {
- return MetaspaceAux::allocated_capacity_bytes(_class_type) +
- MetaspaceAux::free_bytes(_class_type) +
- MetaspaceAux::free_chunks_total_bytes(_class_type);
+size_t CompressedClassSpaceCounters::used() {
+ return MetaspaceAux::allocated_used_bytes(Metaspace::ClassType);
+}
+
+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() {
if (UsePerfData && UseCompressedClassPointers) {
assert(_perf_counters != NULL, "Should be initialized");
- size_t capacity = calculate_capacity();
- 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);
+ _perf_counters->update(capacity(), max_capacity(), used());
}
}
@@ -126,12 +123,9 @@
const char* ns = "compressedclassspace";
if (UseCompressedClassPointers) {
- size_t min_capacity = MetaspaceAux::min_chunk_size_bytes();
- size_t capacity = calculate_capacity();
- size_t max_capacity = MetaspaceAux::reserved_bytes(_class_type);
- size_t used = MetaspaceAux::allocated_used_bytes(_class_type);
-
- _perf_counters = new MetaspacePerfCounters(ns, min_capacity, capacity, max_capacity, used);
+ size_t min_capacity = 0;
+ _perf_counters = new MetaspacePerfCounters(ns, min_capacity, capacity(),
+ max_capacity(), used());
} else {
_perf_counters = new MetaspacePerfCounters(ns, 0, 0, 0, 0);
}
--- a/hotspot/src/share/vm/memory/metaspaceCounters.hpp Wed Sep 18 00:08:00 2013 +0000
+++ b/hotspot/src/share/vm/memory/metaspaceCounters.hpp Tue Sep 17 20:59:07 2013 +0200
@@ -25,13 +25,15 @@
#ifndef SHARE_VM_MEMORY_METASPACECOUNTERS_HPP
#define SHARE_VM_MEMORY_METASPACECOUNTERS_HPP
-#include "memory/metaspace.hpp"
+#include "memory/allocation.hpp"
class MetaspacePerfCounters;
class MetaspaceCounters: public AllStatic {
static MetaspacePerfCounters* _perf_counters;
- static size_t calculate_capacity();
+ static size_t used();
+ static size_t capacity();
+ static size_t max_capacity();
public:
static void initialize_performance_counters();
@@ -40,8 +42,9 @@
class CompressedClassSpaceCounters: public AllStatic {
static MetaspacePerfCounters* _perf_counters;
- static size_t calculate_capacity();
- static const Metaspace::MetadataType _class_type = Metaspace::ClassType;
+ static size_t used();
+ static size_t capacity();
+ static size_t max_capacity();
public:
static void initialize_performance_counters();
--- a/hotspot/src/share/vm/services/memoryPool.cpp Wed Sep 18 00:08:00 2013 +0000
+++ b/hotspot/src/share/vm/services/memoryPool.cpp Tue Sep 17 20:59:07 2013 +0200
@@ -260,10 +260,10 @@
}
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() {
- 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());
}
@@ -271,26 +271,19 @@
return MetaspaceAux::allocated_used_bytes();
}
-size_t MetaspacePool::capacity_in_bytes() const {
- return MetaspaceAux::allocated_capacity_bytes();
-}
-
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() :
- 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() {
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() {
- 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());
}
--- a/hotspot/src/share/vm/services/memoryPool.hpp Wed Sep 18 00:08:00 2013 +0000
+++ b/hotspot/src/share/vm/services/memoryPool.hpp Tue Sep 17 20:59:07 2013 +0200
@@ -224,7 +224,6 @@
class MetaspacePool : public MemoryPool {
size_t calculate_max_size() const;
- size_t capacity_in_bytes() const;
public:
MetaspacePool();
MemoryUsage get_memory_usage();
@@ -232,7 +231,6 @@
};
class CompressedKlassSpacePool : public MemoryPool {
- size_t capacity_in_bytes() const;
public:
CompressedKlassSpacePool();
MemoryUsage get_memory_usage();
--- a/hotspot/src/share/vm/services/memoryUsage.hpp Wed Sep 18 00:08:00 2013 +0000
+++ b/hotspot/src/share/vm/services/memoryUsage.hpp Tue Sep 17 20:59:07 2013 +0200
@@ -63,10 +63,12 @@
size_t committed() const { return _committed; }
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) {
// In the 64-bit vm, a size_t can overflow a jlong (which is signed).
jlong ret;
- if (val == (size_t)-1) {
+ if (val == undefined_size()) {
ret = -1L;
} else {
NOT_LP64(ret = val;)
--- a/hotspot/test/gc/metaspace/TestMetaspaceMemoryPool.java Wed Sep 18 00:08:00 2013 +0000
+++ b/hotspot/test/gc/metaspace/TestMetaspaceMemoryPool.java Tue Sep 17 20:59:07 2013 +0200
@@ -22,18 +22,15 @@
*/
import java.util.List;
-import java.lang.management.ManagementFactory;
-import java.lang.management.MemoryManagerMXBean;
-import java.lang.management.MemoryPoolMXBean;
-import java.lang.management.MemoryUsage;
-
-import java.lang.management.RuntimeMXBean;
-import java.lang.management.ManagementFactory;
+import java.lang.management.*;
+import com.oracle.java.testlibrary.*;
+import static com.oracle.java.testlibrary.Asserts.*;
/* @test TestMetaspaceMemoryPool
* @bug 8000754
* @summary Tests that a MemoryPoolMXBeans is created for metaspace and that a
* MemoryManagerMXBean is created.
+ * @library /testlibrary
* @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:+UseCompressedClassPointers TestMetaspaceMemoryPool
@@ -42,35 +39,18 @@
public class TestMetaspaceMemoryPool {
public static void main(String[] args) {
verifyThatMetaspaceMemoryManagerExists();
- verifyMemoryPool(getMemoryPool("Metaspace"), isFlagDefined("MaxMetaspaceSize"));
- if (runsOn64bit()) {
- if (usesCompressedOops()) {
+ boolean isMetaspaceMaxDefined = InputArguments.containsPrefix("-XX:MaxMetaspaceSize");
+ verifyMemoryPool(getMemoryPool("Metaspace"), isMetaspaceMaxDefined);
+
+ if (Platform.is64bit()) {
+ if (InputArguments.contains("-XX:+UseCompressedOops")) {
MemoryPoolMXBean cksPool = getMemoryPool("Compressed Class Space");
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() {
List<MemoryManagerMXBean> managers = ManagementFactory.getMemoryManagerMXBeans();
for (MemoryManagerMXBean manager : managers) {
@@ -95,32 +75,19 @@
private static void verifyMemoryPool(MemoryPoolMXBean pool, boolean isMaxDefined) {
MemoryUsage mu = pool.getUsage();
- assertDefined(mu.getInit(), "init");
- assertDefined(mu.getUsed(), "used");
- assertDefined(mu.getCommitted(), "committed");
+ long init = mu.getInit();
+ long used = mu.getUsed();
+ long committed = mu.getCommitted();
+ long max = mu.getMax();
+
+ assertGTE(init, 0L);
+ assertGTE(used, init);
+ assertGTE(committed, used);
if (isMaxDefined) {
- assertDefined(mu.getMax(), "max");
+ assertGTE(max, committed);
} else {
- assertUndefined(mu.getMax(), "max");
- }
- }
-
- 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);
+ assertEQ(max, -1L);
}
}
}
--- a/hotspot/test/gc/metaspace/TestMetaspacePerfCounters.java Wed Sep 18 00:08:00 2013 +0000
+++ b/hotspot/test/gc/metaspace/TestMetaspacePerfCounters.java Tue Sep 17 20:59:07 2013 +0200
@@ -61,10 +61,15 @@
}
private static void checkPerfCounters(String ns) throws Exception {
- for (PerfCounter counter : countersInNamespace(ns)) {
- String msg = "Expected " + counter.getName() + " to be larger than 0";
- assertGT(counter.longValue(), 0L, msg);
- }
+ long minCapacity = getMinCapacity(ns);
+ long maxCapacity = getMaxCapacity(ns);
+ 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 {
@@ -75,12 +80,10 @@
}
private static void checkUsedIncreasesWhenLoadingClass(String ns) throws Exception {
- PerfCounter used = PerfCounters.findByName(ns + ".used");
-
- long before = used.longValue();
+ long before = getUsed(ns);
fooClass = compileAndLoad("Foo", "public class Foo { }");
System.gc();
- long after = used.longValue();
+ long after = getUsed(ns);
assertGT(after, before);
}
@@ -101,4 +104,20 @@
private static boolean isUsingCompressedClassPointers() {
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();
+ }
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/gc/metaspace/TestPerfCountersAndMemoryPools.java Tue Sep 17 20:59:07 2013 +0200
@@ -0,0 +1,86 @@
+/*
+ * 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();
+ }
+}
--- a/hotspot/test/testlibrary/com/oracle/java/testlibrary/InputArguments.java Wed Sep 18 00:08:00 2013 +0000
+++ b/hotspot/test/testlibrary/com/oracle/java/testlibrary/InputArguments.java Tue Sep 17 20:59:07 2013 +0200
@@ -41,6 +41,9 @@
/**
* 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.
* @return {@code true} if the given argument is an input argument,
* otherwise {@code false}.
@@ -48,4 +51,26 @@
public static boolean contains(String 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;
+ }
}