diff --git a/src/share/vm/gc_implementation/g1/g1MonitoringSupport.cpp b/src/share/vm/gc_implementation/g1/g1MonitoringSupport.cpp index 16839dcb29a96d8c26f120a4329b69c50ecea5fa..01bb43bef455f7f4287f829e6c8fa664b49c590b 100644 --- a/src/share/vm/gc_implementation/g1/g1MonitoringSupport.cpp +++ b/src/share/vm/gc_implementation/g1/g1MonitoringSupport.cpp @@ -262,6 +262,7 @@ void G1MonitoringSupport::update_sizes() { old_collection_counters()->update_all(); young_collection_counters()->update_all(); MetaspaceCounters::update_performance_counters(); + CompressedClassSpaceCounters::update_performance_counters(); } } diff --git a/src/share/vm/gc_implementation/parallelScavenge/parallelScavengeHeap.cpp b/src/share/vm/gc_implementation/parallelScavenge/parallelScavengeHeap.cpp index d5b6c0540055a9164e6af23fe3dc8c95ecff0f3c..e5d5229d30ca7e5a5ce63e5aa3d7899f634d72f2 100644 --- a/src/share/vm/gc_implementation/parallelScavenge/parallelScavengeHeap.cpp +++ b/src/share/vm/gc_implementation/parallelScavenge/parallelScavengeHeap.cpp @@ -216,6 +216,7 @@ void ParallelScavengeHeap::update_counters() { young_gen()->update_counters(); old_gen()->update_counters(); MetaspaceCounters::update_performance_counters(); + CompressedClassSpaceCounters::update_performance_counters(); } size_t ParallelScavengeHeap::capacity() const { diff --git a/src/share/vm/memory/genCollectedHeap.cpp b/src/share/vm/memory/genCollectedHeap.cpp index 2faed4cc8182b0c33420a4f6984fb90380e923b8..e0f82c02d86136bd22e2d5baa65cd4787125d719 100644 --- a/src/share/vm/memory/genCollectedHeap.cpp +++ b/src/share/vm/memory/genCollectedHeap.cpp @@ -1211,6 +1211,7 @@ void GenCollectedHeap::gc_epilogue(bool full) { } MetaspaceCounters::update_performance_counters(); + CompressedClassSpaceCounters::update_performance_counters(); always_do_update_barrier = UseConcMarkSweepGC; }; diff --git a/src/share/vm/memory/metaspace.cpp b/src/share/vm/memory/metaspace.cpp index e5871ae7a840a4c87881d41d4729ac0175e473d5..f654a13878cd04de75076fc832056e7b932fa9ae 100644 --- a/src/share/vm/memory/metaspace.cpp +++ b/src/share/vm/memory/metaspace.cpp @@ -2480,16 +2480,13 @@ void SpaceManager::mangle_freed_chunks() { size_t MetaspaceAux::_allocated_capacity_words[] = {0, 0}; size_t MetaspaceAux::_allocated_used_words[] = {0, 0}; +size_t MetaspaceAux::free_bytes(Metaspace::MetadataType mdtype) { + VirtualSpaceList* list = Metaspace::get_space_list(mdtype); + return list == NULL ? 0 : list->free_bytes(); +} + size_t MetaspaceAux::free_bytes() { - size_t result = 0; - if (Metaspace::using_class_space() && - (Metaspace::class_space_list() != NULL)) { - result = result + Metaspace::class_space_list()->free_bytes(); - } - if (Metaspace::space_list() != NULL) { - result = result + Metaspace::space_list()->free_bytes(); - } - return result; + return free_bytes(Metaspace::ClassType) + free_bytes(Metaspace::NonClassType); } void MetaspaceAux::dec_capacity(Metaspace::MetadataType mdtype, size_t words) { @@ -2571,23 +2568,18 @@ size_t MetaspaceAux::capacity_bytes_slow(Metaspace::MetadataType mdtype) { } size_t MetaspaceAux::reserved_in_bytes(Metaspace::MetadataType mdtype) { - if (mdtype == Metaspace::ClassType) { - return Metaspace::using_class_space() ? - Metaspace::class_space_list()->virtual_space_total() * BytesPerWord : 0; - } else { - return Metaspace::space_list()->virtual_space_total() * BytesPerWord; - } + VirtualSpaceList* list = Metaspace::get_space_list(mdtype); + return list == NULL ? 0 : list->virtual_space_total(); } size_t MetaspaceAux::min_chunk_size() { return Metaspace::first_chunk_word_size(); } size_t MetaspaceAux::free_chunks_total(Metaspace::MetadataType mdtype) { - if ((mdtype == Metaspace::ClassType) && !Metaspace::using_class_space()) { + VirtualSpaceList* list = Metaspace::get_space_list(mdtype); + if (list == NULL) { return 0; } - ChunkManager* chunk = (mdtype == Metaspace::ClassType) ? - Metaspace::class_space_list()->chunk_manager() : - Metaspace::space_list()->chunk_manager(); + ChunkManager* chunk = list->chunk_manager(); chunk->slow_verify(); return chunk->free_chunks_total(); } diff --git a/src/share/vm/memory/metaspace.hpp b/src/share/vm/memory/metaspace.hpp index 3d620357beeb02b724ac68ca44d8bfb37e305d7e..88f089494d39baebd97e6fe11ec02f2d83b03f72 100644 --- a/src/share/vm/memory/metaspace.hpp +++ b/src/share/vm/memory/metaspace.hpp @@ -136,6 +136,10 @@ class Metaspace : public CHeapObj { static VirtualSpaceList* space_list() { return _space_list; } static VirtualSpaceList* class_space_list() { return _class_space_list; } + static VirtualSpaceList* get_space_list(MetadataType mdtype) { + assert(mdtype != MetadataTypeCount, "MetadaTypeCount can't be used as mdtype"); + return mdtype == ClassType ? class_space_list() : space_list(); + } // This is used by DumpSharedSpaces only, where only _vsm is used. So we will // maintain a single list for now. @@ -218,7 +222,6 @@ class Metaspace : public CHeapObj { class MetaspaceAux : AllStatic { static size_t free_chunks_total(Metaspace::MetadataType mdtype); - static size_t free_chunks_total_in_bytes(Metaspace::MetadataType mdtype); public: // Statistics for class space and data space in metaspace. @@ -262,6 +265,7 @@ class MetaspaceAux : AllStatic { // Used by MetaspaceCounters static size_t free_chunks_total(); static size_t free_chunks_total_in_bytes(); + static size_t free_chunks_total_in_bytes(Metaspace::MetadataType mdtype); static size_t allocated_capacity_words(Metaspace::MetadataType mdtype) { return _allocated_capacity_words[mdtype]; @@ -294,6 +298,7 @@ class MetaspaceAux : AllStatic { } static size_t free_bytes(); + static size_t free_bytes(Metaspace::MetadataType mdtype); // Total capacity in all Metaspaces static size_t capacity_bytes_slow() { diff --git a/src/share/vm/memory/metaspaceCounters.cpp b/src/share/vm/memory/metaspaceCounters.cpp index b2be29bca2f0566a04818fe8bda28c9b1b2628a1..eb7bebd28b6a06ab628f78e31eedb84438f18bf2 100644 --- a/src/share/vm/memory/metaspaceCounters.cpp +++ b/src/share/vm/memory/metaspaceCounters.cpp @@ -25,11 +25,47 @@ #include "precompiled.hpp" #include "memory/metaspaceCounters.hpp" #include "memory/resourceArea.hpp" +#include "runtime/globals.hpp" +#include "runtime/perfData.hpp" #include "utilities/exceptions.hpp" -MetaspaceCounters* MetaspaceCounters::_metaspace_counters = NULL; +class MetaspacePerfCounters: public CHeapObj { + friend class VMStructs; + PerfVariable* _capacity; + PerfVariable* _used; + PerfVariable* _max_capacity; -size_t MetaspaceCounters::calc_total_capacity() { + PerfVariable* create_variable(const char *ns, const char *name, size_t value, TRAPS) { + const char *path = PerfDataManager::counter_name(ns, name); + return PerfDataManager::create_variable(SUN_GC, path, PerfData::U_Bytes, value, THREAD); + } + + void create_constant(const char *ns, const char *name, size_t value, TRAPS) { + const char *path = PerfDataManager::counter_name(ns, name); + PerfDataManager::create_constant(SUN_GC, path, PerfData::U_Bytes, value, THREAD); + } + + public: + MetaspacePerfCounters(const char* ns, size_t min_capacity, size_t curr_capacity, size_t max_capacity, size_t used) { + EXCEPTION_MARK; + ResourceMark rm; + + create_constant(ns, "minCapacity", min_capacity, THREAD); + _capacity = create_variable(ns, "capacity", curr_capacity, THREAD); + _max_capacity = create_variable(ns, "maxCapacity", max_capacity, THREAD); + _used = create_variable(ns, "used", used, THREAD); + } + + void update(size_t capacity, size_t max_capacity, size_t used) { + _capacity->set_value(capacity); + _max_capacity->set_value(max_capacity); + _used->set_value(used); + } +}; + +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 @@ -39,95 +75,65 @@ size_t MetaspaceCounters::calc_total_capacity() { return total_capacity; } -MetaspaceCounters::MetaspaceCounters() : - _capacity(NULL), - _used(NULL), - _max_capacity(NULL) { +void MetaspaceCounters::initialize_performance_counters() { if (UsePerfData) { + assert(_perf_counters == NULL, "Should only be initialized once"); + size_t min_capacity = MetaspaceAux::min_chunk_size(); + size_t capacity = calculate_capacity(); size_t max_capacity = MetaspaceAux::reserved_in_bytes(); - size_t curr_capacity = calc_total_capacity(); size_t used = MetaspaceAux::allocated_used_bytes(); - initialize(min_capacity, max_capacity, curr_capacity, used); + _perf_counters = new MetaspacePerfCounters("metaspace", min_capacity, capacity, max_capacity, used); } } -static PerfVariable* create_ms_variable(const char *ns, - const char *name, - size_t value, - TRAPS) { - const char *path = PerfDataManager::counter_name(ns, name); - PerfVariable *result = - PerfDataManager::create_variable(SUN_GC, path, PerfData::U_Bytes, value, - CHECK_NULL); - return result; -} - -static void create_ms_constant(const char *ns, - const char *name, - size_t value, - TRAPS) { - const char *path = PerfDataManager::counter_name(ns, name); - PerfDataManager::create_constant(SUN_GC, path, PerfData::U_Bytes, value, CHECK); -} - -void MetaspaceCounters::initialize(size_t min_capacity, - size_t max_capacity, - size_t curr_capacity, - size_t used) { - +void MetaspaceCounters::update_performance_counters() { if (UsePerfData) { - EXCEPTION_MARK; - ResourceMark rm; + assert(_perf_counters != NULL, "Should be initialized"); - const char *ms = "metaspace"; + size_t capacity = calculate_capacity(); + size_t max_capacity = MetaspaceAux::reserved_in_bytes(); + size_t used = MetaspaceAux::allocated_used_bytes(); - create_ms_constant(ms, "minCapacity", min_capacity, CHECK); - _max_capacity = create_ms_variable(ms, "maxCapacity", max_capacity, CHECK); - _capacity = create_ms_variable(ms, "capacity", curr_capacity, CHECK); - _used = create_ms_variable(ms, "used", used, CHECK); + _perf_counters->update(capacity, max_capacity, used); } } -void MetaspaceCounters::update_capacity() { - assert(UsePerfData, "Should not be called unless being used"); - size_t total_capacity = calc_total_capacity(); - _capacity->set_value(total_capacity); -} +MetaspacePerfCounters* CompressedClassSpaceCounters::_perf_counters = NULL; -void MetaspaceCounters::update_used() { - assert(UsePerfData, "Should not be called unless being used"); - size_t used_in_bytes = MetaspaceAux::allocated_used_bytes(); - _used->set_value(used_in_bytes); +size_t CompressedClassSpaceCounters::calculate_capacity() { + return MetaspaceAux::allocated_capacity_bytes(_class_type) + + MetaspaceAux::free_bytes(_class_type) + + MetaspaceAux::free_chunks_total_in_bytes(_class_type); } -void MetaspaceCounters::update_max_capacity() { - assert(UsePerfData, "Should not be called unless being used"); - assert(_max_capacity != NULL, "Should be initialized"); - size_t reserved_in_bytes = MetaspaceAux::reserved_in_bytes(); - _max_capacity->set_value(reserved_in_bytes); -} +void CompressedClassSpaceCounters::update_performance_counters() { + if (UsePerfData && UseCompressedKlassPointers) { + assert(_perf_counters != NULL, "Should be initialized"); -void MetaspaceCounters::update_all() { - if (UsePerfData) { - update_used(); - update_capacity(); - update_max_capacity(); - } -} + size_t capacity = calculate_capacity(); + size_t max_capacity = MetaspaceAux::reserved_in_bytes(_class_type); + size_t used = MetaspaceAux::allocated_used_bytes(_class_type); -void MetaspaceCounters::initialize_performance_counters() { - if (UsePerfData) { - assert(_metaspace_counters == NULL, "Should only be initialized once"); - _metaspace_counters = new MetaspaceCounters(); + _perf_counters->update(capacity, max_capacity, used); } } -void MetaspaceCounters::update_performance_counters() { +void CompressedClassSpaceCounters::initialize_performance_counters() { if (UsePerfData) { - assert(_metaspace_counters != NULL, "Should be initialized"); - _metaspace_counters->update_all(); + assert(_perf_counters == NULL, "Should only be initialized once"); + const char* ns = "compressedclassspace"; + + if (UseCompressedKlassPointers) { + size_t min_capacity = MetaspaceAux::min_chunk_size(); + size_t capacity = calculate_capacity(); + size_t max_capacity = MetaspaceAux::reserved_in_bytes(_class_type); + size_t used = MetaspaceAux::allocated_used_bytes(_class_type); + + _perf_counters = new MetaspacePerfCounters(ns, min_capacity, capacity, max_capacity, used); + } else { + _perf_counters = new MetaspacePerfCounters(ns, 0, 0, 0, 0); + } } } - diff --git a/src/share/vm/memory/metaspaceCounters.hpp b/src/share/vm/memory/metaspaceCounters.hpp index 46a9308888ac9bd4dd709408d0f4bb9d8e5e2e7d..5b481d59b4df8cccc2c1ef0353f40aaec479fd11 100644 --- a/src/share/vm/memory/metaspaceCounters.hpp +++ b/src/share/vm/memory/metaspaceCounters.hpp @@ -25,31 +25,27 @@ #ifndef SHARE_VM_MEMORY_METASPACECOUNTERS_HPP #define SHARE_VM_MEMORY_METASPACECOUNTERS_HPP -#include "runtime/perfData.hpp" - -class MetaspaceCounters: public CHeapObj { - friend class VMStructs; - PerfVariable* _capacity; - PerfVariable* _used; - PerfVariable* _max_capacity; - static MetaspaceCounters* _metaspace_counters; - void initialize(size_t min_capacity, - size_t max_capacity, - size_t curr_capacity, - size_t used); - size_t calc_total_capacity(); - public: - MetaspaceCounters(); - ~MetaspaceCounters(); +#include "memory/metaspace.hpp" - void update_capacity(); - void update_used(); - void update_max_capacity(); +class MetaspacePerfCounters; - void update_all(); +class MetaspaceCounters: public AllStatic { + static MetaspacePerfCounters* _perf_counters; + static size_t calculate_capacity(); + public: static void initialize_performance_counters(); static void update_performance_counters(); +}; + +class CompressedClassSpaceCounters: public AllStatic { + static MetaspacePerfCounters* _perf_counters; + static size_t calculate_capacity(); + static const Metaspace::MetadataType _class_type = Metaspace::ClassType; + public: + static void initialize_performance_counters(); + static void update_performance_counters(); }; + #endif // SHARE_VM_MEMORY_METASPACECOUNTERS_HPP diff --git a/src/share/vm/memory/universe.cpp b/src/share/vm/memory/universe.cpp index 1e380ed39f81dd694d4b2f475b89364cb5d8d4af..d85d23e015be36b21817aa92a2c67193d6e84da4 100644 --- a/src/share/vm/memory/universe.cpp +++ b/src/share/vm/memory/universe.cpp @@ -1101,6 +1101,8 @@ bool universe_post_init() { // Initialize performance counters for metaspaces MetaspaceCounters::initialize_performance_counters(); + CompressedClassSpaceCounters::initialize_performance_counters(); + MemoryService::add_metaspace_memory_pools(); GC_locker::unlock(); // allow gc after bootstrapping diff --git a/test/gc/metaspace/TestMetaspacePerfCounters.java b/test/gc/metaspace/TestMetaspacePerfCounters.java new file mode 100644 index 0000000000000000000000000000000000000000..26934249a7c1b7db0b09c92cd10521e65f94e3d2 --- /dev/null +++ b/test/gc/metaspace/TestMetaspacePerfCounters.java @@ -0,0 +1,104 @@ +/* + * 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.util.ArrayList; + +import com.oracle.java.testlibrary.*; +import static com.oracle.java.testlibrary.Asserts.*; + +/* @test TestMetaspacePerfCounters + * @bug 8014659 + * @library /testlibrary + * @summary Tests that performance counters for metaspace and compressed class + * space exists and works. + * + * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:-UseCompressedOops -XX:-UseCompressedKlassPointers -XX:+UsePerfData -XX:+UseSerialGC TestMetaspacePerfCounters + * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:-UseCompressedOops -XX:-UseCompressedKlassPointers -XX:+UsePerfData -XX:+UseParallelGC -XX:+UseParallelOldGC TestMetaspacePerfCounters + * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:-UseCompressedOops -XX:-UseCompressedKlassPointers -XX:+UsePerfData -XX:+UseG1GC TestMetaspacePerfCounters + * + * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:+UseCompressedOops -XX:+UseCompressedKlassPointers -XX:+UsePerfData -XX:+UseSerialGC TestMetaspacePerfCounters + * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:+UseCompressedOops -XX:+UseCompressedKlassPointers -XX:+UsePerfData -XX:+UseParallelGC -XX:+UseParallelOldGC TestMetaspacePerfCounters + * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:+UseCompressedOops -XX:+UseCompressedKlassPointers -XX:+UsePerfData -XX:+UseG1GC TestMetaspacePerfCounters + */ +public class TestMetaspacePerfCounters { + public static Class fooClass = null; + private static final String[] counterNames = {"minCapacity", "maxCapacity", "capacity", "used"}; + + public static void main(String[] args) throws Exception { + String metaspace = "sun.gc.metaspace"; + String ccs = "sun.gc.compressedclassspace"; + + checkPerfCounters(metaspace); + + if (isUsingCompressedClassPointers()) { + checkPerfCounters(ccs); + checkUsedIncreasesWhenLoadingClass(ccs); + } else { + checkEmptyPerfCounters(ccs); + checkUsedIncreasesWhenLoadingClass(metaspace); + } + } + + 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); + } + } + + private static void checkEmptyPerfCounters(String ns) throws Exception { + for (PerfCounter counter : countersInNamespace(ns)) { + String msg = "Expected " + counter.getName() + " to equal 0"; + assertEQ(counter.longValue(), 0L, msg); + } + } + + private static void checkUsedIncreasesWhenLoadingClass(String ns) throws Exception { + PerfCounter used = PerfCounters.findByName(ns + ".used"); + + long before = used.longValue(); + fooClass = compileAndLoad("Foo", "public class Foo { }"); + System.gc(); + long after = used.longValue(); + + assertGT(after, before); + } + + private static List countersInNamespace(String ns) throws Exception { + List counters = new ArrayList<>(); + for (String name : counterNames) { + counters.add(PerfCounters.findByName(ns + "." + name)); + } + return counters; + } + + private static Class compileAndLoad(String name, String source) throws Exception { + byte[] byteCode = InMemoryJavaCompiler.compile(name, source); + return ByteCodeLoader.load(name, byteCode); + } + + private static boolean isUsingCompressedClassPointers() { + return Platform.is64bit() && InputArguments.contains("-XX:+UseCompressedKlassPointers"); + } +} diff --git a/test/testlibrary/AssertsTest.java b/test/testlibrary/AssertsTest.java new file mode 100644 index 0000000000000000000000000000000000000000..9ab62403cd22df8ab377578986dcba76d65fd297 --- /dev/null +++ b/test/testlibrary/AssertsTest.java @@ -0,0 +1,237 @@ +/* + * 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 static com.oracle.java.testlibrary.Asserts.*; + +/* @test + * @summary Tests the different assertions in the Assert class + * @library /testlibrary + */ +public class AssertsTest { + private static class Foo implements Comparable { + final int id; + public Foo(int id) { + this.id = id; + } + + public int compareTo(Foo f) { + return new Integer(id).compareTo(new Integer(f.id)); + } + } + + public static void main(String[] args) throws Exception { + testLessThan(); + testLessThanOrEqual(); + testEquals(); + testGreaterThanOrEqual(); + testGreaterThan(); + testNotEquals(); + testNull(); + testNotNull(); + testTrue(); + testFalse(); + } + + private static void testLessThan() throws Exception { + expectPass(Assertion.LT, 1, 2); + + expectFail(Assertion.LT, 2, 2); + expectFail(Assertion.LT, 2, 1); + expectFail(Assertion.LT, null, 2); + expectFail(Assertion.LT, 2, null); + } + + private static void testLessThanOrEqual() throws Exception { + expectPass(Assertion.LTE, 1, 2); + expectPass(Assertion.LTE, 2, 2); + + expectFail(Assertion.LTE, 3, 2); + expectFail(Assertion.LTE, null, 2); + expectFail(Assertion.LTE, 2, null); + } + + private static void testEquals() throws Exception { + expectPass(Assertion.EQ, 1, 1); + expectPass(Assertion.EQ, null, null); + + Foo f1 = new Foo(1); + expectPass(Assertion.EQ, f1, f1); + + Foo f2 = new Foo(1); + expectFail(Assertion.EQ, f1, f2); + expectFail(Assertion.LTE, null, 2); + expectFail(Assertion.LTE, 2, null); + } + + private static void testGreaterThanOrEqual() throws Exception { + expectPass(Assertion.GTE, 1, 1); + expectPass(Assertion.GTE, 2, 1); + + expectFail(Assertion.GTE, 1, 2); + expectFail(Assertion.GTE, null, 2); + expectFail(Assertion.GTE, 2, null); + } + + private static void testGreaterThan() throws Exception { + expectPass(Assertion.GT, 2, 1); + + expectFail(Assertion.GT, 1, 1); + expectFail(Assertion.GT, 1, 2); + expectFail(Assertion.GT, null, 2); + expectFail(Assertion.GT, 2, null); + } + + private static void testNotEquals() throws Exception { + expectPass(Assertion.NE, null, 1); + expectPass(Assertion.NE, 1, null); + + Foo f1 = new Foo(1); + Foo f2 = new Foo(1); + expectPass(Assertion.NE, f1, f2); + + expectFail(Assertion.NE, null, null); + expectFail(Assertion.NE, f1, f1); + expectFail(Assertion.NE, 1, 1); + } + + private static void testNull() throws Exception { + expectPass(Assertion.NULL, null); + + expectFail(Assertion.NULL, 1); + } + + private static void testNotNull() throws Exception { + expectPass(Assertion.NOTNULL, 1); + + expectFail(Assertion.NOTNULL, null); + } + + private static void testTrue() throws Exception { + expectPass(Assertion.TRUE, true); + + expectFail(Assertion.TRUE, false); + } + + private static void testFalse() throws Exception { + expectPass(Assertion.FALSE, false); + + expectFail(Assertion.FALSE, true); + } + + private static > void expectPass(Assertion assertion, T ... args) + throws Exception { + Assertion.run(assertion, args); + } + + private static > void expectFail(Assertion assertion, T ... args) + throws Exception { + try { + Assertion.run(assertion, args); + } catch (RuntimeException e) { + return; + } + throw new Exception("Expected " + Assertion.format(assertion, (Object[]) args) + + " to throw a RuntimeException"); + } + +} + +enum Assertion { + LT, LTE, EQ, GTE, GT, NE, NULL, NOTNULL, FALSE, TRUE; + + public static > void run(Assertion assertion, T ... args) { + String msg = "Expected " + format(assertion, args) + " to pass"; + switch (assertion) { + case LT: + assertLessThan(args[0], args[1], msg); + break; + case LTE: + assertLessThanOrEqual(args[0], args[1], msg); + break; + case EQ: + assertEquals(args[0], args[1], msg); + break; + case GTE: + assertGreaterThanOrEqual(args[0], args[1], msg); + break; + case GT: + assertGreaterThan(args[0], args[1], msg); + break; + case NE: + assertNotEquals(args[0], args[1], msg); + break; + case NULL: + assertNull(args == null ? args : args[0], msg); + break; + case NOTNULL: + assertNotNull(args == null ? args : args[0], msg); + break; + case FALSE: + assertFalse((Boolean) args[0], msg); + break; + case TRUE: + assertTrue((Boolean) args[0], msg); + break; + default: + // do nothing + } + } + + public static String format(Assertion assertion, Object ... args) { + switch (assertion) { + case LT: + return asString("assertLessThan", args); + case LTE: + return asString("assertLessThanOrEqual", args); + case EQ: + return asString("assertEquals", args); + case GTE: + return asString("assertGreaterThanOrEquals", args); + case GT: + return asString("assertGreaterThan", args); + case NE: + return asString("assertNotEquals", args); + case NULL: + return asString("assertNull", args); + case NOTNULL: + return asString("assertNotNull", args); + case FALSE: + return asString("assertFalse", args); + case TRUE: + return asString("assertTrue", args); + default: + return ""; + } + } + + private static String asString(String assertion, Object ... args) { + if (args == null) { + return String.format("%s(null)", assertion); + } + if (args.length == 1) { + return String.format("%s(%s)", assertion, args[0]); + } else { + return String.format("%s(%s, %s)", assertion, args[0], args[1]); + } + } +} diff --git a/test/testlibrary/com/oracle/java/testlibrary/Asserts.java b/test/testlibrary/com/oracle/java/testlibrary/Asserts.java new file mode 100644 index 0000000000000000000000000000000000000000..e92e26dd4b5159d4e3763e567d6e39ae54a733e6 --- /dev/null +++ b/test/testlibrary/com/oracle/java/testlibrary/Asserts.java @@ -0,0 +1,395 @@ +/* + * 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. + */ + +package com.oracle.java.testlibrary; + +/** + * Asserts that can be used for verifying assumptions in tests. + * + * An assertion will throw a {@link RuntimeException} if the assertion isn't + * valid. All the asserts can be imported into a test by using a static + * import: + * + *
+ * {@code
+ * import static com.oracle.java.testlibrary.Asserts.*;
+ * }
+ *
+ * Always provide a message describing the assumption if the line number of the
+ * failing assertion isn't enough to understand why the assumption failed. For
+ * example, if the assertion is in a loop or in a method that is called
+ * multiple times, then the line number won't provide enough context to
+ * understand the failure.
+ * 
+ */ +public class Asserts { + + /** + * Shorthand for {@link #assertLessThan(T, T)}. + * + * @see #assertLessThan(T, T) + */ + public static > void assertLT(T lhs, T rhs) { + assertLessThan(lhs, rhs); + } + + /** + * Shorthand for {@link #assertLessThan(T, T, String)}. + * + * @see #assertLessThan(T, T, String) + */ + public static > void assertLT(T lhs, T rhs, String msg) { + assertLessThan(lhs, rhs, msg); + } + + /** + * Calls {@link #assertLessThan(T, T, String)} with a default message. + * + * @see #assertLessThan(T, T, String) + */ + public static > void assertLessThan(T lhs, T rhs) { + String msg = "Expected that " + format(lhs) + " < " + format(rhs); + assertLessThan(lhs, rhs, msg); + } + + /** + * Asserts that {@code lhs} is less than {@code rhs}. + * + * @param lhs The left hand side of the comparison. + * @param rhs The right hand side of the comparison. + * @param msg A description of the assumption. + * @throws RuntimeException if the assertion isn't valid. + */ + public static >void assertLessThan(T lhs, T rhs, String msg) { + assertTrue(compare(lhs, rhs, msg) < 0, msg); + } + + /** + * Shorthand for {@link #assertLessThanOrEqual(T, T)}. + * + * @see #assertLessThanOrEqual(T, T) + */ + public static > void assertLTE(T lhs, T rhs) { + assertLessThanOrEqual(lhs, rhs); + } + + /** + * Shorthand for {@link #assertLessThanOrEqual(T, T, String)}. + * + * @see #assertLessThanOrEqual(T, T, String) + */ + public static > void assertLTE(T lhs, T rhs, String msg) { + assertLessThanOrEqual(lhs, rhs, msg); + } + + /** + * Calls {@link #assertLessThanOrEqual(T, T, String)} with a default message. + * + * @see #assertLessThanOrEqual(T, T, String) + */ + public static > void assertLessThanOrEqual(T lhs, T rhs) { + String msg = "Expected that " + format(lhs) + " <= " + format(rhs); + assertLessThanOrEqual(lhs, rhs, msg); + } + + /** + * Asserts that {@code lhs} is less than or equal to {@code rhs}. + * + * @param lhs The left hand side of the comparison. + * @param rhs The right hand side of the comparison. + * @param msg A description of the assumption. + * @throws RuntimeException if the assertion isn't valid. + */ + public static > void assertLessThanOrEqual(T lhs, T rhs, String msg) { + assertTrue(compare(lhs, rhs, msg) <= 0, msg); + } + + /** + * Shorthand for {@link #assertEquals(T, T)}. + * + * @see #assertEquals(T, T) + */ + public static void assertEQ(Object lhs, Object rhs) { + assertEquals(lhs, rhs); + } + + /** + * Shorthand for {@link #assertEquals(T, T, String)}. + * + * @see #assertEquals(T, T, String) + */ + public static void assertEQ(Object lhs, Object rhs, String msg) { + assertEquals(lhs, rhs, msg); + } + + /** + * Calls {@link #assertEquals(T, T, String)} with a default message. + * + * @see #assertEquals(T, T, String) + */ + public static void assertEquals(Object lhs, Object rhs) { + String msg = "Expected " + format(lhs) + " to equal " + format(rhs); + assertEquals(lhs, rhs, msg); + } + + /** + * Asserts that {@code lhs} is equal to {@code rhs}. + * + * @param lhs The left hand side of the comparison. + * @param rhs The right hand side of the comparison. + * @param msg A description of the assumption. + * @throws RuntimeException if the assertion isn't valid. + */ + public static void assertEquals(Object lhs, Object rhs, String msg) { + if (lhs == null) { + if (rhs != null) { + error(msg); + } + } else { + assertTrue(lhs.equals(rhs), msg); + } + } + + /** + * Shorthand for {@link #assertGreaterThanOrEqual(T, T)}. + * + * @see #assertGreaterThanOrEqual(T, T) + */ + public static > void assertGTE(T lhs, T rhs) { + assertGreaterThanOrEqual(lhs, rhs); + } + + /** + * Shorthand for {@link #assertGreaterThanOrEqual(T, T, String)}. + * + * @see #assertGreaterThanOrEqual(T, T, String) + */ + public static > void assertGTE(T lhs, T rhs, String msg) { + assertGreaterThanOrEqual(lhs, rhs, msg); + } + + /** + * Calls {@link #assertGreaterThanOrEqual(T, T, String)} with a default message. + * + * @see #assertGreaterThanOrEqual(T, T, String) + */ + public static > void assertGreaterThanOrEqual(T lhs, T rhs) { + String msg = "Expected that " + format(lhs) + " >= " + format(rhs); + assertGreaterThanOrEqual(lhs, rhs, msg); + } + + /** + * Asserts that {@code lhs} is greater than or equal to {@code rhs}. + * + * @param lhs The left hand side of the comparison. + * @param rhs The right hand side of the comparison. + * @param msg A description of the assumption. + * @throws RuntimeException if the assertion isn't valid. + */ + public static > void assertGreaterThanOrEqual(T lhs, T rhs, String msg) { + assertTrue(compare(lhs, rhs, msg) >= 0, msg); + } + + /** + * Shorthand for {@link #assertGreaterThan(T, T)}. + * + * @see #assertGreaterThan(T, T) + */ + public static > void assertGT(T lhs, T rhs) { + assertGreaterThan(lhs, rhs); + } + + /** + * Shorthand for {@link #assertGreaterThan(T, T, String)}. + * + * @see #assertGreaterThan(T, T, String) + */ + public static > void assertGT(T lhs, T rhs, String msg) { + assertGreaterThan(lhs, rhs, msg); + } + + /** + * Calls {@link #assertGreaterThan(T, T, String)} with a default message. + * + * @see #assertGreaterThan(T, T, String) + */ + public static > void assertGreaterThan(T lhs, T rhs) { + String msg = "Expected that " + format(lhs) + " > " + format(rhs); + assertGreaterThan(lhs, rhs, msg); + } + + /** + * Asserts that {@code lhs} is greater than {@code rhs}. + * + * @param lhs The left hand side of the comparison. + * @param rhs The right hand side of the comparison. + * @param msg A description of the assumption. + * @throws RuntimeException if the assertion isn't valid. + */ + public static > void assertGreaterThan(T lhs, T rhs, String msg) { + assertTrue(compare(lhs, rhs, msg) > 0, msg); + } + + /** + * Shorthand for {@link #assertNotEquals(T, T)}. + * + * @see #assertNotEquals(T, T) + */ + public static void assertNE(Object lhs, Object rhs) { + assertNotEquals(lhs, rhs); + } + + /** + * Shorthand for {@link #assertNotEquals(T, T, String)}. + * + * @see #assertNotEquals(T, T, String) + */ + public static void assertNE(Object lhs, Object rhs, String msg) { + assertNotEquals(lhs, rhs, msg); + } + + /** + * Calls {@link #assertNotEquals(T, T, String)} with a default message. + * + * @see #assertNotEquals(T, T, String) + */ + public static void assertNotEquals(Object lhs, Object rhs) { + String msg = "Expected " + format(lhs) + " to not equal " + format(rhs); + assertNotEquals(lhs, rhs, msg); + } + + /** + * Asserts that {@code lhs} is not equal to {@code rhs}. + * + * @param lhs The left hand side of the comparison. + * @param rhs The right hand side of the comparison. + * @param msg A description of the assumption. + * @throws RuntimeException if the assertion isn't valid. + */ + public static void assertNotEquals(Object lhs, Object rhs, String msg) { + if (lhs == null) { + if (rhs == null) { + error(msg); + } + } else { + assertFalse(lhs.equals(rhs), msg); + } + } + + /** + * Calls {@link #assertNull(Object, String)} with a default message. + * + * @see #assertNull(Object, String) + */ + public static void assertNull(Object o) { + assertNull(o, "Expected " + format(o) + " to be null"); + } + + /** + * Asserts that {@code o} is null. + * + * @param o The reference assumed to be null. + * @param msg A description of the assumption. + * @throws RuntimeException if the assertion isn't valid. + */ + public static void assertNull(Object o, String msg) { + assertEquals(o, null, msg); + } + + /** + * Calls {@link #assertNotNull(Object, String)} with a default message. + * + * @see #assertNotNull(Object, String) + */ + public static void assertNotNull(Object o) { + assertNotNull(o, "Expected non null reference"); + } + + /** + * Asserts that {@code o} is not null. + * + * @param o The reference assumed not to be null, + * @param msg A description of the assumption. + * @throws RuntimeException if the assertion isn't valid. + */ + public static void assertNotNull(Object o, String msg) { + assertNotEquals(o, null, msg); + } + + /** + * Calls {@link #assertFalse(boolean, String)} with a default message. + * + * @see #assertFalse(boolean, String) + */ + public static void assertFalse(boolean value) { + assertFalse(value, "Expected value to be false"); + } + + /** + * Asserts that {@code value} is {@code false}. + * + * @param value The value assumed to be false. + * @param msg A description of the assumption. + * @throws RuntimeException if the assertion isn't valid. + */ + public static void assertFalse(boolean value, String msg) { + assertTrue(!value, msg); + } + + /** + * Calls {@link #assertTrue(boolean, String)} with a default message. + * + * @see #assertTrue(boolean, String) + */ + public static void assertTrue(boolean value) { + assertTrue(value, "Expected value to be true"); + } + + /** + * Asserts that {@code value} is {@code true}. + * + * @param value The value assumed to be true. + * @param msg A description of the assumption. + * @throws RuntimeException if the assertion isn't valid. + */ + public static void assertTrue(boolean value, String msg) { + if (!value) { + error(msg); + } + } + + private static > int compare(T lhs, T rhs, String msg) { + assertNotNull(lhs, msg); + assertNotNull(rhs, msg); + return lhs.compareTo(rhs); + } + + private static String format(Object o) { + return o == null? "null" : o.toString(); + } + + private static void error(String msg) { + throw new RuntimeException(msg); + } + +} diff --git a/test/testlibrary/com/oracle/java/testlibrary/ByteCodeLoader.java b/test/testlibrary/com/oracle/java/testlibrary/ByteCodeLoader.java new file mode 100644 index 0000000000000000000000000000000000000000..46309eae0ca0f5b7f73dd8a102c1ea6eb8a50390 --- /dev/null +++ b/test/testlibrary/com/oracle/java/testlibrary/ByteCodeLoader.java @@ -0,0 +1,74 @@ +/* + * 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. + */ + +package com.oracle.java.testlibrary; + +import java.security.SecureClassLoader; + +/** + * {@code ByteCodeLoader} can be used for easy loading of byte code already + * present in memory. + * + * {@code InMemoryCompiler} can be used for compiling source code in a string + * into byte code, which then can be loaded with {@code ByteCodeLoader}. + * + * @see InMemoryCompiler + */ +public class ByteCodeLoader extends SecureClassLoader { + private final String className; + private final byte[] byteCode; + + /** + * Creates a new {@code ByteCodeLoader} ready to load a class with the + * given name and the given byte code. + * + * @param className The name of the class + * @param byteCode The byte code of the class + */ + public ByteCodeLoader(String className, byte[] byteCode) { + this.className = className; + this.byteCode = byteCode; + } + + @Override + protected Class findClass(String name) throws ClassNotFoundException { + if (!name.equals(className)) { + throw new ClassNotFoundException(name); + } + + return defineClass(name, byteCode, 0, byteCode.length); + } + + /** + * Utility method for creating a new {@code ByteCodeLoader} and then + * directly load the given byte code. + * + * @param className The name of the class + * @param byteCode The byte code for the class + * @throws ClassNotFoundException if the class can't be loaded + * @return A {@see Class} object representing the class + */ + public static Class load(String className, byte[] byteCode) throws ClassNotFoundException { + return new ByteCodeLoader(className, byteCode).loadClass(className); + } +} diff --git a/test/testlibrary/com/oracle/java/testlibrary/InMemoryJavaCompiler.java b/test/testlibrary/com/oracle/java/testlibrary/InMemoryJavaCompiler.java new file mode 100644 index 0000000000000000000000000000000000000000..9b075e19f3dcf65bb7aa7196385df96b109b3cf6 --- /dev/null +++ b/test/testlibrary/com/oracle/java/testlibrary/InMemoryJavaCompiler.java @@ -0,0 +1,154 @@ +/* + * 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. + */ + +package com.oracle.java.testlibrary; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.OutputStream; + +import java.net.URI; +import java.util.Arrays; + +import javax.tools.ForwardingJavaFileManager; +import javax.tools.ForwardingJavaFileManager; +import javax.tools.FileObject; +import javax.tools.JavaCompiler; +import javax.tools.JavaCompiler.CompilationTask; +import javax.tools.JavaFileManager; +import javax.tools.JavaFileObject; +import javax.tools.JavaFileObject.Kind; +import javax.tools.SimpleJavaFileObject; +import javax.tools.ToolProvider; + +/** + * {@code InMemoryJavaCompiler} can be used for compiling a {@link + * CharSequence} to a {@code byte[]}. + * + * The compiler will not use the file system at all, instead using a {@link + * ByteArrayOutputStream} for storing the byte code. For the source code, any + * kind of {@link CharSequence} can be used, e.g. {@link String}, {@link + * StringBuffer} or {@link StringBuilder}. + * + * The {@code InMemoryCompiler} can easily be used together with a {@code + * ByteClassLoader} to easily compile and load source code in a {@link String}: + * + *
+ * {@code
+ * import com.oracle.java.testlibrary.InMemoryJavaCompiler;
+ * import com.oracle.java.testlibrary.ByteClassLoader;
+ *
+ * class Example {
+ *     public static void main(String[] args) {
+ *         String className = "Foo";
+ *         String sourceCode = "public class " + className + " {" +
+ *                             "    public void bar() {" +
+ *                             "        System.out.println("Hello from bar!");" +
+ *                             "    }" +
+ *                             "}";
+ *         byte[] byteCode = InMemoryJavaCompiler.compile(className, sourceCode);
+ *         Class fooClass = ByteClassLoader.load(className, byteCode);
+ *     }
+ * }
+ * }
+ * 
+ */ +public class InMemoryJavaCompiler { + private static class MemoryJavaFileObject extends SimpleJavaFileObject { + private final String className; + private final CharSequence sourceCode; + private final ByteArrayOutputStream byteCode; + + public MemoryJavaFileObject(String className, CharSequence sourceCode) { + super(URI.create("string:///" + className.replace('.','/') + Kind.SOURCE.extension), Kind.SOURCE); + this.className = className; + this.sourceCode = sourceCode; + this.byteCode = new ByteArrayOutputStream(); + } + + @Override + public CharSequence getCharContent(boolean ignoreEncodingErrors) { + return sourceCode; + } + + @Override + public OutputStream openOutputStream() throws IOException { + return byteCode; + } + + public byte[] getByteCode() { + return byteCode.toByteArray(); + } + + public String getClassName() { + return className; + } + } + + private static class FileManagerWrapper extends ForwardingJavaFileManager { + private MemoryJavaFileObject file; + + public FileManagerWrapper(MemoryJavaFileObject file) { + super(getCompiler().getStandardFileManager(null, null, null)); + this.file = file; + } + + @Override + public JavaFileObject getJavaFileForOutput(Location location, String className, + Kind kind, FileObject sibling) + throws IOException { + if (!file.getClassName().equals(className)) { + throw new IOException("Expected class with name " + file.getClassName() + + ", but got " + className); + } + return file; + } + } + + /** + * Compiles the class with the given name and source code. + * + * @param className The name of the class + * @param sourceCode The source code for the class with name {@code className} + * @throws RuntimeException if the compilation did not succeed + * @return The resulting byte code from the compilation + */ + public static byte[] compile(String className, CharSequence sourceCode) { + MemoryJavaFileObject file = new MemoryJavaFileObject(className, sourceCode); + CompilationTask task = getCompilationTask(file); + + if(!task.call()) { + throw new RuntimeException("Could not compile " + className + " with source code " + sourceCode); + } + + return file.getByteCode(); + } + + private static JavaCompiler getCompiler() { + return ToolProvider.getSystemJavaCompiler(); + } + + private static CompilationTask getCompilationTask(MemoryJavaFileObject file) { + return getCompiler().getTask(null, new FileManagerWrapper(file), null, null, null, Arrays.asList(file)); + } +} diff --git a/test/testlibrary/com/oracle/java/testlibrary/InputArguments.java b/test/testlibrary/com/oracle/java/testlibrary/InputArguments.java new file mode 100644 index 0000000000000000000000000000000000000000..650d6c233902b7941707a8536e6f6705366beaac --- /dev/null +++ b/test/testlibrary/com/oracle/java/testlibrary/InputArguments.java @@ -0,0 +1,51 @@ +/* + * 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. + */ + +package com.oracle.java.testlibrary; + +import java.lang.management.RuntimeMXBean; +import java.lang.management.ManagementFactory; +import java.util.List; + +/** + * This class provides access to the input arguments to the VM. + */ +public class InputArguments { + private static final List args; + + static { + RuntimeMXBean runtimeMxBean = ManagementFactory.getRuntimeMXBean(); + args = runtimeMxBean.getInputArguments(); + } + + /** + * Returns true if {@code arg} is an input argument to the VM. + * + * @param arg The name of the argument. + * @return {@code true} if the given argument is an input argument, + * otherwise {@code false}. + */ + public static boolean contains(String arg) { + return args.contains(arg); + } +} diff --git a/test/testlibrary/com/oracle/java/testlibrary/PerfCounter.java b/test/testlibrary/com/oracle/java/testlibrary/PerfCounter.java new file mode 100644 index 0000000000000000000000000000000000000000..1a90f0f1bdfe36a5bc5d0a6a236a96436eacfc59 --- /dev/null +++ b/test/testlibrary/com/oracle/java/testlibrary/PerfCounter.java @@ -0,0 +1,70 @@ +/* + * 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. + */ + +package com.oracle.java.testlibrary; + +import sun.jvmstat.monitor.Monitor; + +/** + * Represents a performance counter in the JVM. + * + * See http://openjdk.java.net/groups/hotspot/docs/Serviceability.html#bjvmstat + * for more details about performance counters. + */ +public class PerfCounter { + private final Monitor monitor; + private final String name; + + PerfCounter(Monitor monitor, String name) { + this.monitor = monitor; + this.name = name; + } + + /** + * Returns the value of this performance counter as a long. + * + * @return The long value of this performance counter + * @throws RuntimeException If the value of the performance counter isn't a long + */ + public long longValue() { + Object value = monitor.getValue(); + if (value instanceof Long) { + return ((Long) value).longValue(); + } + throw new RuntimeException("Expected " + monitor.getName() + " to have a long value"); + } + + /** + * Returns the name of the performance counter. + * + * @return The name of the performance counter. + */ + public String getName() { + return name; + } + + @Override + public String toString() { + return name; + } +} diff --git a/test/testlibrary/com/oracle/java/testlibrary/PerfCounters.java b/test/testlibrary/com/oracle/java/testlibrary/PerfCounters.java new file mode 100644 index 0000000000000000000000000000000000000000..bfe3d78430aaeb2f269491213a3d9a85962e792b --- /dev/null +++ b/test/testlibrary/com/oracle/java/testlibrary/PerfCounters.java @@ -0,0 +1,69 @@ +/* + * 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. + */ + +package com.oracle.java.testlibrary; + +import sun.jvmstat.monitor.Monitor; +import sun.jvmstat.monitor.MonitorException; +import sun.jvmstat.monitor.MonitoredHost; +import sun.jvmstat.monitor.MonitoredVm; +import sun.jvmstat.monitor.VmIdentifier; + +/** + * PerfCounters can be used to get a performance counter from the currently + * executing VM. + * + * Throws a runtime exception if an error occurs while communicating with the + * currently executing VM. + */ +public class PerfCounters { + private final static MonitoredVm vm; + + static { + try { + String pid = Integer.toString(ProcessTools.getProcessId()); + VmIdentifier vmId = new VmIdentifier(pid); + MonitoredHost host = MonitoredHost.getMonitoredHost(vmId); + vm = host.getMonitoredVm(vmId); + } catch (Exception e) { + throw new RuntimeException("Could not connect to the VM"); + } + } + + /** + * Returns the performance counter with the given name. + * + * @param name The name of the performance counter. + * @throws IllegalArgumentException If no counter with the given name exists. + * @throws MonitorException If an error occurs while communicating with the VM. + * @return The performance counter with the given name. + */ + public static PerfCounter findByName(String name) + throws MonitorException, IllegalArgumentException { + Monitor m = vm.findByName(name); + if (m == null) { + throw new IllegalArgumentException("Did not find a performance counter with name " + name); + } + return new PerfCounter(m, name); + } +}