8191821: Finer granularity for GC verification
Reviewed-by: tschatzl, poonam, sangheki
This commit is contained in:
parent
9a3de631aa
commit
ea04c5cfb3
src/hotspot/share
gc
g1
g1Arguments.cppg1Arguments.hppg1CollectedHeap.cppg1ConcurrentMark.cppg1FullCollector.cppg1HeapVerifier.cppg1HeapVerifier.hpp
shared
memory
runtime
test/hotspot
@ -26,6 +26,7 @@
|
||||
#include "gc/g1/g1Arguments.hpp"
|
||||
#include "gc/g1/g1CollectedHeap.inline.hpp"
|
||||
#include "gc/g1/g1CollectorPolicy.hpp"
|
||||
#include "gc/g1/g1HeapVerifier.hpp"
|
||||
#include "gc/g1/heapRegion.hpp"
|
||||
#include "gc/shared/gcArguments.inline.hpp"
|
||||
#include "runtime/globals.hpp"
|
||||
@ -104,6 +105,12 @@ void G1Arguments::initialize_flags() {
|
||||
#endif
|
||||
}
|
||||
|
||||
bool G1Arguments::parse_verification_type(const char* type) {
|
||||
G1CollectedHeap::heap()->verifier()->parse_verification_type(type);
|
||||
// Always return true because we want to parse all values.
|
||||
return true;
|
||||
}
|
||||
|
||||
CollectedHeap* G1Arguments::create_heap() {
|
||||
return create_heap_with_policy<G1CollectedHeap, G1CollectorPolicy>();
|
||||
}
|
||||
|
@ -32,6 +32,7 @@ class CollectedHeap;
|
||||
class G1Arguments : public GCArguments {
|
||||
public:
|
||||
virtual void initialize_flags();
|
||||
virtual bool parse_verification_type(const char* type);
|
||||
virtual size_t conservative_max_heap_alignment();
|
||||
virtual CollectedHeap* create_heap();
|
||||
};
|
||||
|
@ -1084,7 +1084,6 @@ void G1CollectedHeap::print_hrm_post_compaction() {
|
||||
PostCompactionPrinterClosure cl(hr_printer());
|
||||
heap_region_iterate(&cl);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void G1CollectedHeap::abort_concurrent_cycle() {
|
||||
@ -1133,7 +1132,7 @@ void G1CollectedHeap::verify_before_full_collection(bool explicit_gc) {
|
||||
assert(!GCCause::is_user_requested_gc(gc_cause()) || explicit_gc, "invariant");
|
||||
assert(used() == recalculate_used(), "Should be equal");
|
||||
_verifier->verify_region_sets_optional();
|
||||
_verifier->verify_before_gc();
|
||||
_verifier->verify_before_gc(G1HeapVerifier::G1VerifyFull);
|
||||
_verifier->check_bitmaps("Full GC Start");
|
||||
}
|
||||
|
||||
@ -1174,7 +1173,7 @@ void G1CollectedHeap::verify_after_full_collection() {
|
||||
check_gc_time_stamps();
|
||||
_hrm.verify_optional();
|
||||
_verifier->verify_region_sets_optional();
|
||||
_verifier->verify_after_gc();
|
||||
_verifier->verify_after_gc(G1HeapVerifier::G1VerifyFull);
|
||||
// Clear the previous marking bitmap, if needed for bitmap verification.
|
||||
// Note we cannot do this when we clear the next marking bitmap in
|
||||
// G1ConcurrentMark::abort() above since VerifyDuringGC verifies the
|
||||
@ -2958,13 +2957,17 @@ G1CollectedHeap::do_collection_pause_at_safepoint(double target_pause_time_ms) {
|
||||
|
||||
GCTraceCPUTime tcpu;
|
||||
|
||||
G1HeapVerifier::G1VerifyType verify_type;
|
||||
FormatBuffer<> gc_string("Pause ");
|
||||
if (collector_state()->during_initial_mark_pause()) {
|
||||
gc_string.append("Initial Mark");
|
||||
verify_type = G1HeapVerifier::G1VerifyInitialMark;
|
||||
} else if (collector_state()->gcs_are_young()) {
|
||||
gc_string.append("Young");
|
||||
verify_type = G1HeapVerifier::G1VerifyYoungOnly;
|
||||
} else {
|
||||
gc_string.append("Mixed");
|
||||
verify_type = G1HeapVerifier::G1VerifyMixed;
|
||||
}
|
||||
GCTraceTime(Info, gc) tm(gc_string, NULL, gc_cause(), true);
|
||||
|
||||
@ -3005,7 +3008,7 @@ G1CollectedHeap::do_collection_pause_at_safepoint(double target_pause_time_ms) {
|
||||
heap_region_iterate(&v_cl);
|
||||
}
|
||||
|
||||
_verifier->verify_before_gc();
|
||||
_verifier->verify_before_gc(verify_type);
|
||||
|
||||
_verifier->check_bitmaps("GC Start");
|
||||
|
||||
@ -3165,7 +3168,7 @@ G1CollectedHeap::do_collection_pause_at_safepoint(double target_pause_time_ms) {
|
||||
heap_region_iterate(&v_cl);
|
||||
}
|
||||
|
||||
_verifier->verify_after_gc();
|
||||
_verifier->verify_after_gc(verify_type);
|
||||
_verifier->check_bitmaps("GC End");
|
||||
|
||||
assert(!ref_processor_stw()->discovery_enabled(), "Postcondition");
|
||||
|
@ -1015,9 +1015,7 @@ void G1ConcurrentMark::checkpoint_roots_final(bool clear_all_soft_refs) {
|
||||
SvcGCMarker sgcm(SvcGCMarker::OTHER);
|
||||
|
||||
if (VerifyDuringGC) {
|
||||
HandleMark hm; // handle scope
|
||||
g1h->prepare_for_verify();
|
||||
Universe::verify(VerifyOption_G1UsePrevMarking, "During GC (before)");
|
||||
g1h->verifier()->verify(G1HeapVerifier::G1VerifyRemark, VerifyOption_G1UsePrevMarking, "During GC (before)");
|
||||
}
|
||||
g1h->verifier()->check_bitmaps("Remark Start");
|
||||
|
||||
@ -1038,9 +1036,7 @@ void G1ConcurrentMark::checkpoint_roots_final(bool clear_all_soft_refs) {
|
||||
|
||||
// Verify the heap w.r.t. the previous marking bitmap.
|
||||
if (VerifyDuringGC) {
|
||||
HandleMark hm; // handle scope
|
||||
g1h->prepare_for_verify();
|
||||
Universe::verify(VerifyOption_G1UsePrevMarking, "During GC (overflow)");
|
||||
g1h->verifier()->verify(G1HeapVerifier::G1VerifyRemark, VerifyOption_G1UsePrevMarking, "During GC (overflow)");
|
||||
}
|
||||
|
||||
// Clear the marking state because we will be restarting
|
||||
@ -1055,9 +1051,7 @@ void G1ConcurrentMark::checkpoint_roots_final(bool clear_all_soft_refs) {
|
||||
true /* expected_active */);
|
||||
|
||||
if (VerifyDuringGC) {
|
||||
HandleMark hm; // handle scope
|
||||
g1h->prepare_for_verify();
|
||||
Universe::verify(VerifyOption_G1UseNextMarking, "During GC (after)");
|
||||
g1h->verifier()->verify(G1HeapVerifier::G1VerifyRemark, VerifyOption_G1UseNextMarking, "During GC (after)");
|
||||
}
|
||||
g1h->verifier()->check_bitmaps("Remark End");
|
||||
assert(!restart_for_overflow(), "sanity");
|
||||
@ -1189,9 +1183,7 @@ void G1ConcurrentMark::cleanup() {
|
||||
g1h->verifier()->verify_region_sets_optional();
|
||||
|
||||
if (VerifyDuringGC) {
|
||||
HandleMark hm; // handle scope
|
||||
g1h->prepare_for_verify();
|
||||
Universe::verify(VerifyOption_G1UsePrevMarking, "During GC (before)");
|
||||
g1h->verifier()->verify(G1HeapVerifier::G1VerifyCleanup, VerifyOption_G1UsePrevMarking, "During GC (before)");
|
||||
}
|
||||
g1h->verifier()->check_bitmaps("Cleanup Start");
|
||||
|
||||
@ -1263,9 +1255,7 @@ void G1ConcurrentMark::cleanup() {
|
||||
Universe::update_heap_info_at_gc();
|
||||
|
||||
if (VerifyDuringGC) {
|
||||
HandleMark hm; // handle scope
|
||||
g1h->prepare_for_verify();
|
||||
Universe::verify(VerifyOption_G1UsePrevMarking, "During GC (after)");
|
||||
g1h->verifier()->verify(G1HeapVerifier::G1VerifyCleanup, VerifyOption_G1UsePrevMarking, "During GC (after)");
|
||||
}
|
||||
|
||||
g1h->verifier()->check_bitmaps("Cleanup End");
|
||||
|
@ -245,8 +245,8 @@ void G1FullCollector::run_task(AbstractGangTask* task) {
|
||||
}
|
||||
|
||||
void G1FullCollector::verify_after_marking() {
|
||||
if (!VerifyDuringGC) {
|
||||
//Only do verification if VerifyDuringGC is set.
|
||||
if (!VerifyDuringGC || !_heap->verifier()->should_verify(G1HeapVerifier::G1VerifyFull)) {
|
||||
// Only do verification if VerifyDuringGC and G1VerifyFull is set.
|
||||
return;
|
||||
}
|
||||
|
||||
@ -265,6 +265,6 @@ void G1FullCollector::verify_after_marking() {
|
||||
// fail. At the end of the GC, the original mark word values
|
||||
// (including hash values) are restored to the appropriate
|
||||
// objects.
|
||||
GCTraceTime(Info, gc, verify)("During GC (full)");
|
||||
GCTraceTime(Info, gc, verify)("Verifying During GC (full)");
|
||||
_heap->verify(VerifyOption_G1UseFullMarking);
|
||||
}
|
||||
|
@ -376,6 +376,37 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
void G1HeapVerifier::parse_verification_type(const char* type) {
|
||||
if (strcmp(type, "young-only") == 0) {
|
||||
enable_verification_type(G1VerifyYoungOnly);
|
||||
} else if (strcmp(type, "initial-mark") == 0) {
|
||||
enable_verification_type(G1VerifyInitialMark);
|
||||
} else if (strcmp(type, "mixed") == 0) {
|
||||
enable_verification_type(G1VerifyMixed);
|
||||
} else if (strcmp(type, "remark") == 0) {
|
||||
enable_verification_type(G1VerifyRemark);
|
||||
} else if (strcmp(type, "cleanup") == 0) {
|
||||
enable_verification_type(G1VerifyCleanup);
|
||||
} else if (strcmp(type, "full") == 0) {
|
||||
enable_verification_type(G1VerifyFull);
|
||||
} else {
|
||||
log_warning(gc, verify)("VerifyGCType: '%s' is unknown. Available types are: "
|
||||
"young-only, initial-mark, mixed, remark, cleanup and full", type);
|
||||
}
|
||||
}
|
||||
|
||||
void G1HeapVerifier::enable_verification_type(G1VerifyType type) {
|
||||
// First enable will clear _enabled_verification_types.
|
||||
if (_enabled_verification_types == G1VerifyAll) {
|
||||
_enabled_verification_types = type;
|
||||
} else {
|
||||
_enabled_verification_types |= type;
|
||||
}
|
||||
}
|
||||
|
||||
bool G1HeapVerifier::should_verify(G1VerifyType type) {
|
||||
return (_enabled_verification_types & type) == type;
|
||||
}
|
||||
|
||||
void G1HeapVerifier::verify(VerifyOption vo) {
|
||||
if (!SafepointSynchronize::is_at_safepoint()) {
|
||||
@ -541,28 +572,32 @@ void G1HeapVerifier::prepare_for_verify() {
|
||||
}
|
||||
}
|
||||
|
||||
double G1HeapVerifier::verify(bool guard, const char* msg) {
|
||||
double G1HeapVerifier::verify(G1VerifyType type, VerifyOption vo, const char* msg) {
|
||||
double verify_time_ms = 0.0;
|
||||
|
||||
if (guard && _g1h->total_collections() >= VerifyGCStartAt) {
|
||||
if (should_verify(type) && _g1h->total_collections() >= VerifyGCStartAt) {
|
||||
double verify_start = os::elapsedTime();
|
||||
HandleMark hm; // Discard invalid handles created during verification
|
||||
prepare_for_verify();
|
||||
Universe::verify(VerifyOption_G1UsePrevMarking, msg);
|
||||
Universe::verify(vo, msg);
|
||||
verify_time_ms = (os::elapsedTime() - verify_start) * 1000;
|
||||
}
|
||||
|
||||
return verify_time_ms;
|
||||
}
|
||||
|
||||
void G1HeapVerifier::verify_before_gc() {
|
||||
double verify_time_ms = verify(VerifyBeforeGC, "Before GC");
|
||||
_g1h->g1_policy()->phase_times()->record_verify_before_time_ms(verify_time_ms);
|
||||
void G1HeapVerifier::verify_before_gc(G1VerifyType type) {
|
||||
if (VerifyBeforeGC) {
|
||||
double verify_time_ms = verify(type, VerifyOption_G1UsePrevMarking, "Before GC");
|
||||
_g1h->g1_policy()->phase_times()->record_verify_before_time_ms(verify_time_ms);
|
||||
}
|
||||
}
|
||||
|
||||
void G1HeapVerifier::verify_after_gc() {
|
||||
double verify_time_ms = verify(VerifyAfterGC, "After GC");
|
||||
_g1h->g1_policy()->phase_times()->record_verify_after_time_ms(verify_time_ms);
|
||||
void G1HeapVerifier::verify_after_gc(G1VerifyType type) {
|
||||
if (VerifyAfterGC) {
|
||||
double verify_time_ms = verify(type, VerifyOption_G1UsePrevMarking, "After GC");
|
||||
_g1h->g1_policy()->phase_times()->record_verify_after_time_ms(verify_time_ms);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -34,6 +34,7 @@ class G1CollectedHeap;
|
||||
class G1HeapVerifier : public CHeapObj<mtGC> {
|
||||
private:
|
||||
G1CollectedHeap* _g1h;
|
||||
int _enabled_verification_types;
|
||||
|
||||
// verify_region_sets() performs verification over the region
|
||||
// lists. It will be compiled in the product code to be used when
|
||||
@ -41,8 +42,21 @@ private:
|
||||
void verify_region_sets();
|
||||
|
||||
public:
|
||||
enum G1VerifyType {
|
||||
G1VerifyYoungOnly = 1, // -XX:VerifyGCType=young-only
|
||||
G1VerifyInitialMark = 2, // -XX:VerifyGCType=initial-mark
|
||||
G1VerifyMixed = 4, // -XX:VerifyGCType=mixed
|
||||
G1VerifyRemark = 8, // -XX:VerifyGCType=remark
|
||||
G1VerifyCleanup = 16, // -XX:VerifyGCType=cleanup
|
||||
G1VerifyFull = 32, // -XX:VerifyGCType=full
|
||||
G1VerifyAll = -1
|
||||
};
|
||||
|
||||
G1HeapVerifier(G1CollectedHeap* heap) : _g1h(heap) { }
|
||||
G1HeapVerifier(G1CollectedHeap* heap) : _g1h(heap), _enabled_verification_types(G1VerifyAll) { }
|
||||
|
||||
void parse_verification_type(const char* type);
|
||||
void enable_verification_type(G1VerifyType type);
|
||||
bool should_verify(G1VerifyType type);
|
||||
|
||||
// Perform verification.
|
||||
|
||||
@ -73,9 +87,9 @@ public:
|
||||
#endif // HEAP_REGION_SET_FORCE_VERIFY
|
||||
|
||||
void prepare_for_verify();
|
||||
double verify(bool guard, const char* msg);
|
||||
void verify_before_gc();
|
||||
void verify_after_gc();
|
||||
double verify(G1VerifyType type, VerifyOption vo, const char* msg);
|
||||
void verify_before_gc(G1VerifyType type);
|
||||
void verify_after_gc(G1VerifyType type);
|
||||
|
||||
#ifndef PRODUCT
|
||||
// Make sure that the given bitmap has no marked objects in the
|
||||
|
@ -25,6 +25,7 @@
|
||||
#include "precompiled.hpp"
|
||||
#include "gc/shared/gcArguments.hpp"
|
||||
#include "gc/serial/serialArguments.hpp"
|
||||
#include "logging/log.hpp"
|
||||
#include "memory/allocation.inline.hpp"
|
||||
#include "runtime/arguments.hpp"
|
||||
#include "runtime/globals.hpp"
|
||||
@ -84,6 +85,12 @@ void GCArguments::select_gc_ergonomically() {
|
||||
#endif // INCLUDE_ALL_GCS
|
||||
}
|
||||
|
||||
bool GCArguments::parse_verification_type(const char* type) {
|
||||
log_warning(gc, verify)("VerifyGCType is not supported by this collector.");
|
||||
// Return false to avoid multiple warnings.
|
||||
return false;
|
||||
}
|
||||
|
||||
void GCArguments::initialize_flags() {
|
||||
#if INCLUDE_ALL_GCS
|
||||
if (MinHeapFreeRatio == 100) {
|
||||
@ -99,6 +106,24 @@ void GCArguments::initialize_flags() {
|
||||
#endif // INCLUDE_ALL_GCS
|
||||
}
|
||||
|
||||
void GCArguments::post_heap_initialize() {
|
||||
if (strlen(VerifyGCType) > 0) {
|
||||
const char delimiter[] = " ,\n";
|
||||
size_t length = strlen(VerifyGCType);
|
||||
char* type_list = NEW_C_HEAP_ARRAY(char, length + 1, mtInternal);
|
||||
strncpy(type_list, VerifyGCType, length + 1);
|
||||
char* token = strtok(type_list, delimiter);
|
||||
while (token != NULL) {
|
||||
bool success = parse_verification_type(token);
|
||||
if (!success) {
|
||||
break;
|
||||
}
|
||||
token = strtok(NULL, delimiter);
|
||||
}
|
||||
FREE_C_HEAP_ARRAY(char, type_list);
|
||||
}
|
||||
}
|
||||
|
||||
jint GCArguments::initialize() {
|
||||
assert(!is_initialized(), "GC arguments already initialized");
|
||||
|
||||
|
@ -46,8 +46,16 @@ public:
|
||||
static bool is_initialized();
|
||||
static GCArguments* arguments();
|
||||
|
||||
void post_heap_initialize();
|
||||
|
||||
virtual void initialize_flags();
|
||||
|
||||
// Collector specific function to allow finer grained verification
|
||||
// through VerifyGCType. If not overridden the default version will
|
||||
// warn that the flag is not supported for the given collector.
|
||||
// Returns true if parsing should continue, false otherwise.
|
||||
virtual bool parse_verification_type(const char* type);
|
||||
|
||||
virtual size_t conservative_max_heap_alignment() = 0;
|
||||
|
||||
virtual CollectedHeap* create_heap() = 0;
|
||||
|
@ -768,6 +768,7 @@ jint Universe::initialize_heap() {
|
||||
}
|
||||
log_info(gc)("Using %s", _collectedHeap->name());
|
||||
|
||||
GCArguments::arguments()->post_heap_initialize();
|
||||
ThreadLocalAllocBuffer::set_max_size(Universe::heap()->max_tlab_size());
|
||||
|
||||
#ifdef _LP64
|
||||
|
@ -2268,6 +2268,10 @@ public:
|
||||
diagnostic(bool, VerifyDuringGC, false, \
|
||||
"Verify memory system during GC (between phases)") \
|
||||
\
|
||||
diagnostic(ccstrlist, VerifyGCType, "", \
|
||||
"GC type(s) to verify when Verify*GC is enabled." \
|
||||
"Available types are collector specific.") \
|
||||
\
|
||||
diagnostic(ccstrlist, VerifySubSet, "", \
|
||||
"Memory sub-systems to verify when Verify*GC flag(s) " \
|
||||
"are enabled. One or more sub-systems can be specified " \
|
||||
|
77
test/hotspot/gtest/gc/g1/test_g1HeapVerifier.cpp
Normal file
77
test/hotspot/gtest/gc/g1/test_g1HeapVerifier.cpp
Normal file
@ -0,0 +1,77 @@
|
||||
/*
|
||||
* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "precompiled.hpp"
|
||||
#include "gc/g1/g1HeapVerifier.hpp"
|
||||
#include "logging/logConfiguration.hpp"
|
||||
#include "unittest.hpp"
|
||||
|
||||
TEST(G1HeapVerifier, parse) {
|
||||
G1HeapVerifier verifier(NULL);
|
||||
|
||||
LogConfiguration::configure_stdout(LogLevel::Off, true, LOG_TAGS(gc, verify));
|
||||
|
||||
// Default is to verify everything.
|
||||
ASSERT_TRUE(verifier.should_verify(G1HeapVerifier::G1VerifyAll));
|
||||
ASSERT_TRUE(verifier.should_verify(G1HeapVerifier::G1VerifyYoungOnly));
|
||||
ASSERT_TRUE(verifier.should_verify(G1HeapVerifier::G1VerifyInitialMark));
|
||||
ASSERT_TRUE(verifier.should_verify(G1HeapVerifier::G1VerifyMixed));
|
||||
ASSERT_TRUE(verifier.should_verify(G1HeapVerifier::G1VerifyRemark));
|
||||
ASSERT_TRUE(verifier.should_verify(G1HeapVerifier::G1VerifyCleanup));
|
||||
ASSERT_TRUE(verifier.should_verify(G1HeapVerifier::G1VerifyFull));
|
||||
|
||||
// Setting one will disable all other.
|
||||
verifier.parse_verification_type("full");
|
||||
ASSERT_FALSE(verifier.should_verify(G1HeapVerifier::G1VerifyAll));
|
||||
ASSERT_FALSE(verifier.should_verify(G1HeapVerifier::G1VerifyYoungOnly));
|
||||
ASSERT_FALSE(verifier.should_verify(G1HeapVerifier::G1VerifyInitialMark));
|
||||
ASSERT_FALSE(verifier.should_verify(G1HeapVerifier::G1VerifyMixed));
|
||||
ASSERT_FALSE(verifier.should_verify(G1HeapVerifier::G1VerifyRemark));
|
||||
ASSERT_FALSE(verifier.should_verify(G1HeapVerifier::G1VerifyCleanup));
|
||||
ASSERT_TRUE(verifier.should_verify(G1HeapVerifier::G1VerifyFull));
|
||||
|
||||
// Verify case sensitivity.
|
||||
verifier.parse_verification_type("YOUNG-ONLY");
|
||||
ASSERT_FALSE(verifier.should_verify(G1HeapVerifier::G1VerifyYoungOnly));
|
||||
verifier.parse_verification_type("young-only");
|
||||
ASSERT_TRUE(verifier.should_verify(G1HeapVerifier::G1VerifyYoungOnly));
|
||||
|
||||
// Verify perfect match
|
||||
verifier.parse_verification_type("mixedgc");
|
||||
ASSERT_FALSE(verifier.should_verify(G1HeapVerifier::G1VerifyMixed));
|
||||
verifier.parse_verification_type("mixe");
|
||||
ASSERT_FALSE(verifier.should_verify(G1HeapVerifier::G1VerifyMixed));
|
||||
verifier.parse_verification_type("mixed");
|
||||
ASSERT_TRUE(verifier.should_verify(G1HeapVerifier::G1VerifyMixed));
|
||||
|
||||
// Verify the last three
|
||||
verifier.parse_verification_type("initial-mark");
|
||||
verifier.parse_verification_type("remark");
|
||||
verifier.parse_verification_type("cleanup");
|
||||
ASSERT_TRUE(verifier.should_verify(G1HeapVerifier::G1VerifyRemark));
|
||||
ASSERT_TRUE(verifier.should_verify(G1HeapVerifier::G1VerifyCleanup));
|
||||
|
||||
// Enabling all is not the same as G1VerifyAll
|
||||
ASSERT_FALSE(verifier.should_verify(G1HeapVerifier::G1VerifyAll));
|
||||
}
|
256
test/hotspot/jtreg/gc/g1/TestVerifyGCType.java
Normal file
256
test/hotspot/jtreg/gc/g1/TestVerifyGCType.java
Normal file
@ -0,0 +1,256 @@
|
||||
/*
|
||||
* Copyright (c) 2017, 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test TestVerifyGCType
|
||||
* @summary Test the VerifyGCType flag to ensure basic functionality.
|
||||
* @key gc
|
||||
* @requires vm.gc.G1
|
||||
* @library /test/lib
|
||||
* @build sun.hotspot.WhiteBox
|
||||
* @run main ClassFileInstaller sun.hotspot.WhiteBox
|
||||
* @run driver TestVerifyGCType
|
||||
*/
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
|
||||
import jdk.test.lib.Asserts;
|
||||
import jdk.test.lib.Utils;
|
||||
import jdk.test.lib.process.OutputAnalyzer;
|
||||
import jdk.test.lib.process.ProcessTools;
|
||||
import sun.hotspot.WhiteBox;
|
||||
|
||||
public class TestVerifyGCType {
|
||||
public static final String VERIFY_TAG = "[gc,verify]";
|
||||
public static final String VERIFY_BEFORE = "Verifying Before GC";
|
||||
public static final String VERIFY_DURING = "Verifying During GC";
|
||||
public static final String VERIFY_AFTER = "Verifying After GC";
|
||||
|
||||
public static void main(String args[]) throws Exception {
|
||||
testAllVerificationEnabled();
|
||||
testAllExplicitlyEnabled();
|
||||
testFullAndRemark();
|
||||
testConcurrentMark();
|
||||
testBadVerificationType();
|
||||
testUnsupportedCollector();
|
||||
}
|
||||
|
||||
private static void testAllVerificationEnabled() throws Exception {
|
||||
// Test with all verification enabled
|
||||
OutputAnalyzer output = testWithVerificationType(new String[0]);
|
||||
output.shouldHaveExitValue(0);
|
||||
|
||||
verifyCollection("Pause Young", true, false, true, output.getStdout());
|
||||
verifyCollection("Pause Initial Mark", true, false, true, output.getStdout());
|
||||
verifyCollection("Pause Mixed", true, false, true, output.getStdout());
|
||||
verifyCollection("Pause Remark", false, true, false, output.getStdout());
|
||||
verifyCollection("Pause Cleanup", false, true, false, output.getStdout());
|
||||
verifyCollection("Pause Full", true, true, true, output.getStdout());
|
||||
}
|
||||
|
||||
private static void testAllExplicitlyEnabled() throws Exception {
|
||||
OutputAnalyzer output;
|
||||
// Test with all explicitly enabled
|
||||
output = testWithVerificationType(new String[] {
|
||||
"young-only", "initial-mark", "mixed", "remark", "cleanup", "full"});
|
||||
output.shouldHaveExitValue(0);
|
||||
|
||||
verifyCollection("Pause Young", true, false, true, output.getStdout());
|
||||
verifyCollection("Pause Initial Mark", true, false, true, output.getStdout());
|
||||
verifyCollection("Pause Mixed", true, false, true, output.getStdout());
|
||||
verifyCollection("Pause Remark", false, true, false, output.getStdout());
|
||||
verifyCollection("Pause Cleanup", false, true, false, output.getStdout());
|
||||
verifyCollection("Pause Full", true, true, true, output.getStdout());
|
||||
}
|
||||
|
||||
private static void testFullAndRemark() throws Exception {
|
||||
OutputAnalyzer output;
|
||||
// Test with full and remark
|
||||
output = testWithVerificationType(new String[] {"remark", "full"});
|
||||
output.shouldHaveExitValue(0);
|
||||
|
||||
verifyCollection("Pause Young", false, false, false, output.getStdout());
|
||||
verifyCollection("Pause Initial Mark", false, false, false, output.getStdout());
|
||||
verifyCollection("Pause Mixed", false, false, false, output.getStdout());
|
||||
verifyCollection("Pause Remark", false, true, false, output.getStdout());
|
||||
verifyCollection("Pause Cleanup", false, false, false, output.getStdout());
|
||||
verifyCollection("Pause Full", true, true, true, output.getStdout());
|
||||
}
|
||||
|
||||
private static void testConcurrentMark() throws Exception {
|
||||
OutputAnalyzer output;
|
||||
// Test with full and remark
|
||||
output = testWithVerificationType(new String[] {"initial-mark", "cleanup", "remark"});
|
||||
output.shouldHaveExitValue(0);
|
||||
|
||||
verifyCollection("Pause Young", false, false, false, output.getStdout());
|
||||
verifyCollection("Pause Initial Mark", true, false, true, output.getStdout());
|
||||
verifyCollection("Pause Mixed", false, false, false, output.getStdout());
|
||||
verifyCollection("Pause Remark", false, true, false, output.getStdout());
|
||||
verifyCollection("Pause Cleanup", false, true, false, output.getStdout());
|
||||
verifyCollection("Pause Full", false, false, false, output.getStdout());
|
||||
}
|
||||
|
||||
private static void testBadVerificationType() throws Exception {
|
||||
OutputAnalyzer output;
|
||||
// Test bad type
|
||||
output = testWithVerificationType(new String[] {"old"});
|
||||
output.shouldHaveExitValue(0);
|
||||
|
||||
output.shouldMatch("VerifyGCType: '.*' is unknown. Available types are: young-only, initial-mark, mixed, remark, cleanup and full");
|
||||
verifyCollection("Pause Young", true, false, true, output.getStdout());
|
||||
verifyCollection("Pause Initial Mark", true, false, true, output.getStdout());
|
||||
verifyCollection("Pause Mixed", true, false, true, output.getStdout());
|
||||
verifyCollection("Pause Remark", false, true, false, output.getStdout());
|
||||
verifyCollection("Pause Cleanup", false, true, false, output.getStdout());
|
||||
verifyCollection("Pause Full", true, true, true, output.getStdout());
|
||||
}
|
||||
|
||||
private static void testUnsupportedCollector() throws Exception {
|
||||
OutputAnalyzer output;
|
||||
// Test bad gc
|
||||
output = testWithBadGC();
|
||||
output.shouldHaveExitValue(0);
|
||||
output.shouldMatch("VerifyGCType is not supported by this collector.");
|
||||
}
|
||||
|
||||
private static OutputAnalyzer testWithVerificationType(String[] types) throws Exception {
|
||||
ArrayList<String> basicOpts = new ArrayList<>();
|
||||
Collections.addAll(basicOpts, new String[] {
|
||||
"-Xbootclasspath/a:.",
|
||||
"-XX:+UnlockDiagnosticVMOptions",
|
||||
"-XX:+UseG1GC",
|
||||
"-XX:+WhiteBoxAPI",
|
||||
"-XX:+ExplicitGCInvokesConcurrent",
|
||||
"-Xlog:gc,gc+start,gc+verify=info",
|
||||
"-XX:+VerifyBeforeGC",
|
||||
"-XX:+VerifyAfterGC",
|
||||
"-XX:+VerifyDuringGC"});
|
||||
|
||||
for(String verifyType : types) {
|
||||
basicOpts.add("-XX:VerifyGCType="+verifyType);
|
||||
}
|
||||
|
||||
basicOpts.add(TriggerGCs.class.getName());
|
||||
|
||||
ProcessBuilder procBuilder = ProcessTools.createJavaProcessBuilder(basicOpts.toArray(
|
||||
new String[basicOpts.size()]));
|
||||
OutputAnalyzer analyzer = new OutputAnalyzer(procBuilder.start());
|
||||
return analyzer;
|
||||
}
|
||||
|
||||
private static OutputAnalyzer testWithBadGC() throws Exception {
|
||||
ProcessBuilder procBuilder = ProcessTools.createJavaProcessBuilder(new String[] {
|
||||
"-XX:+UseParallelGC",
|
||||
"-XX:+UnlockDiagnosticVMOptions",
|
||||
"-XX:VerifyGCType=full",
|
||||
"-version"});
|
||||
|
||||
OutputAnalyzer analyzer = new OutputAnalyzer(procBuilder.start());
|
||||
return analyzer;
|
||||
}
|
||||
|
||||
private static void verifyCollection(String name, boolean expectBefore, boolean expectDuring, boolean expectAfter, String data) {
|
||||
CollectionInfo ci = CollectionInfo.parseFirst(name, data);
|
||||
Asserts.assertTrue(ci != null, "Expected GC not found: " + name);
|
||||
|
||||
// Verify Before
|
||||
verifyType(ci, expectBefore, VERIFY_BEFORE);
|
||||
// Verify During
|
||||
verifyType(ci, expectDuring, VERIFY_DURING);
|
||||
// Verify After
|
||||
verifyType(ci, expectAfter, VERIFY_AFTER);
|
||||
}
|
||||
|
||||
private static void verifyType(CollectionInfo ci, boolean shouldExist, String pattern) {
|
||||
if (shouldExist) {
|
||||
Asserts.assertTrue(ci.containsVerification(pattern), "Missing expected verification for: " + ci.getName());
|
||||
} else {
|
||||
Asserts.assertFalse(ci.containsVerification(pattern), "Found unexpected verification for: " + ci.getName());
|
||||
}
|
||||
}
|
||||
|
||||
public static class CollectionInfo {
|
||||
String name;
|
||||
ArrayList<String> verification;
|
||||
public CollectionInfo(String name) {
|
||||
this.name = name;
|
||||
this.verification = new ArrayList<>();
|
||||
System.out.println("Created CollectionInfo: " + name);
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void addVerification(String verify) {
|
||||
System.out.println("Adding: " + verify);
|
||||
verification.add(verify);
|
||||
}
|
||||
|
||||
public boolean containsVerification(String contains) {
|
||||
for (String entry : verification) {
|
||||
if (entry.contains(contains)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static CollectionInfo parseFirst(String name, String data) {
|
||||
CollectionInfo result = null;
|
||||
int firstIndex = data.indexOf(name);
|
||||
if (firstIndex == -1) {
|
||||
return result;
|
||||
}
|
||||
int nextIndex = data.indexOf(name, firstIndex + 1);
|
||||
if (nextIndex == -1) {
|
||||
return result;
|
||||
}
|
||||
// Found an entry for this name
|
||||
result = new CollectionInfo(name);
|
||||
String collectionData = data.substring(firstIndex, nextIndex + name.length());
|
||||
for (String line : collectionData.split(System.getProperty("line.separator"))) {
|
||||
if (line.contains(VERIFY_TAG)) {
|
||||
result.addVerification(line);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
public static class TriggerGCs {
|
||||
public static void main(String args[]) throws Exception {
|
||||
WhiteBox wb = WhiteBox.getWhiteBox();
|
||||
// Trigger the different GCs using the WhiteBox API and System.gc()
|
||||
// to start a concurrent cycle with -XX:+ExplicitGCInvokesConcurrent.
|
||||
wb.fullGC(); // full
|
||||
System.gc(); // initial-mark, remark and cleanup
|
||||
// Sleep to make sure concurrent cycle is done
|
||||
Thread.sleep(1000);
|
||||
wb.youngGC(); // young-only
|
||||
wb.youngGC(); // mixed
|
||||
}
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user