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

Reviewed-by: stefank, dholmes, coleenp
This commit is contained in:
Erik Helin 2013-09-17 20:59:07 +02:00
parent c00f905a5f
commit 2cab7ea037
9 changed files with 201 additions and 114 deletions

View File

@ -65,26 +65,25 @@ class MetaspacePerfCounters: public CHeapObj<mtInternal> {
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 @@ void MetaspaceCounters::update_performance_counters() {
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 @@ void CompressedClassSpaceCounters::initialize_performance_counters() {
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);
}

View File

@ -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 MetaspaceCounters: public AllStatic {
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();

View File

@ -260,10 +260,10 @@ MemoryUsage CodeHeapPool::get_memory_usage() {
}
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 @@ size_t MetaspacePool::used_in_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 {
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());
}

View File

@ -224,7 +224,6 @@ public:
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 MetaspacePool : public MemoryPool {
};
class CompressedKlassSpacePool : public MemoryPool {
size_t capacity_in_bytes() const;
public:
CompressedKlassSpacePool();
MemoryUsage get_memory_usage();

View File

@ -63,10 +63,12 @@ public:
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;)

View File

@ -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 @@ import java.lang.management.ManagementFactory;
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 @@ public class TestMetaspaceMemoryPool {
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);
}
}
}

View File

@ -61,10 +61,15 @@ public class TestMetaspacePerfCounters {
}
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 @@ public class TestMetaspacePerfCounters {
}
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 @@ public class TestMetaspacePerfCounters {
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();
}
}

View File

@ -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();
}
}

View File

@ -41,6 +41,9 @@ public class InputArguments {
/**
* 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 class InputArguments {
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;
}
}