From 9b3898790e83770dc712962b0b17e63bdedfad5d Mon Sep 17 00:00:00 2001 From: poonam Date: Tue, 16 Feb 2016 21:42:29 +0000 Subject: [PATCH] 8072725: Provide more granular levels for GC verification Summary: Add option VerifySubSet to selectively verify the memory sub-systems Reviewed-by: kevinw, jmasa --- src/share/vm/memory/universe.cpp | 117 +++++++++++++++++++++++++------ src/share/vm/memory/universe.hpp | 19 ++++- src/share/vm/runtime/globals.hpp | 8 +++ test/gc/TestVerifySubSet.java | 91 ++++++++++++++++++++++++ 4 files changed, 212 insertions(+), 23 deletions(-) create mode 100644 test/gc/TestVerifySubSet.java diff --git a/src/share/vm/memory/universe.cpp b/src/share/vm/memory/universe.cpp index a0febc5c0..2e1e90f97 100644 --- a/src/share/vm/memory/universe.cpp +++ b/src/share/vm/memory/universe.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2016, 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 @@ -124,6 +124,7 @@ oop Universe::_out_of_memory_error_realloc_objects = NULL; objArrayOop Universe::_preallocated_out_of_memory_error_array = NULL; volatile jint Universe::_preallocated_out_of_memory_error_avail_count = 0; bool Universe::_verify_in_progress = false; +long Universe::verify_flags = Universe::Verify_All; oop Universe::_null_ptr_exception_instance = NULL; oop Universe::_arithmetic_exception_instance = NULL; oop Universe::_virtual_machine_error_instance = NULL; @@ -683,6 +684,9 @@ jint universe_init() { MetaspaceShared::prepare_for_dumping(); } } + if (strlen(VerifySubSet) > 0) { + Universe::initialize_verify_flags(); + } return JNI_OK; } @@ -1361,6 +1365,53 @@ void Universe::print_heap_after_gc(outputStream* st, bool ignore_extended) { st->print_cr("}"); } +void Universe::initialize_verify_flags() { + verify_flags = 0; + const char delimiter[] = " ,"; + + size_t length = strlen(VerifySubSet); + char* subset_list = NEW_C_HEAP_ARRAY(char, length + 1, mtInternal); + strncpy(subset_list, VerifySubSet, length + 1); + + char* token = strtok(subset_list, delimiter); + while (token != NULL) { + if (strcmp(token, "threads") == 0) { + verify_flags |= Verify_Threads; + } else if (strcmp(token, "heap") == 0) { + verify_flags |= Verify_Heap; + } else if (strcmp(token, "symbol_table") == 0) { + verify_flags |= Verify_SymbolTable; + } else if (strcmp(token, "string_table") == 0) { + verify_flags |= Verify_StringTable; + } else if (strcmp(token, "codecache") == 0) { + verify_flags |= Verify_CodeCache; + } else if (strcmp(token, "dictionary") == 0) { + verify_flags |= Verify_SystemDictionary; + } else if (strcmp(token, "classloader_data_graph") == 0) { + verify_flags |= Verify_ClassLoaderDataGraph; + } else if (strcmp(token, "metaspace") == 0) { + verify_flags |= Verify_MetaspaceAux; + } else if (strcmp(token, "jni_handles") == 0) { + verify_flags |= Verify_JNIHandles; + } else if (strcmp(token, "c-heap") == 0) { + verify_flags |= Verify_CHeap; + } else if (strcmp(token, "codecache_oops") == 0) { + verify_flags |= Verify_CodeCacheOops; + } else { + vm_exit_during_initialization(err_msg("VerifySubSet: \'%s\' memory sub-system is unknown, please correct it", token)); + } + token = strtok(NULL, delimiter); + } + FREE_C_HEAP_ARRAY(char, subset_list, mtInternal); +} + +bool Universe::should_verify_subset(uint subset) { + if (verify_flags & subset) { + return true; + } + return false; +} + void Universe::verify(VerifyOption option, const char* prefix, bool silent) { // The use of _verify_in_progress is a temporary work around for // 6320749. Don't bother with a creating a class to set and clear @@ -1380,33 +1431,55 @@ void Universe::verify(VerifyOption option, const char* prefix, bool silent) { if (!silent) gclog_or_tty->print("%s", prefix); if (!silent) gclog_or_tty->print("[Verifying "); - if (!silent) gclog_or_tty->print("threads "); - Threads::verify(); - if (!silent) gclog_or_tty->print("heap "); - heap()->verify(silent, option); - if (!silent) gclog_or_tty->print("syms "); - SymbolTable::verify(); - if (!silent) gclog_or_tty->print("strs "); - StringTable::verify(); + if (should_verify_subset(Verify_Threads)) { + if (!silent) gclog_or_tty->print("Threads "); + Threads::verify(); + } + if (should_verify_subset(Verify_Heap)) { + if (!silent) gclog_or_tty->print("Heap "); + heap()->verify(silent, option); + } + if (should_verify_subset(Verify_SymbolTable)) { + if (!silent) gclog_or_tty->print("SymbolTable "); + SymbolTable::verify(); + } + if (should_verify_subset(Verify_StringTable)) { + if (!silent) gclog_or_tty->print("StringTable "); + StringTable::verify(); + } + if (should_verify_subset(Verify_CodeCache)) { { MutexLockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag); - if (!silent) gclog_or_tty->print("zone "); + if (!silent) gclog_or_tty->print("CodeCache "); CodeCache::verify(); } - if (!silent) gclog_or_tty->print("dict "); - SystemDictionary::verify(); + } + if (should_verify_subset(Verify_SystemDictionary)) { + if (!silent) gclog_or_tty->print("SystemDictionary "); + SystemDictionary::verify(); + } #ifndef PRODUCT - if (!silent) gclog_or_tty->print("cldg "); - ClassLoaderDataGraph::verify(); + if (should_verify_subset(Verify_ClassLoaderDataGraph)) { + if (!silent) gclog_or_tty->print("ClassLoaderDataGraph "); + ClassLoaderDataGraph::verify(); + } #endif - if (!silent) gclog_or_tty->print("metaspace chunks "); - MetaspaceAux::verify_free_chunks(); - if (!silent) gclog_or_tty->print("hand "); - JNIHandles::verify(); - if (!silent) gclog_or_tty->print("C-heap "); - os::check_heap(); - if (!silent) gclog_or_tty->print("code cache "); - CodeCache::verify_oops(); + if (should_verify_subset(Verify_MetaspaceAux)) { + if (!silent) gclog_or_tty->print("MetaspaceAux "); + MetaspaceAux::verify_free_chunks(); + } + if (should_verify_subset(Verify_JNIHandles)) { + if (!silent) gclog_or_tty->print("JNIHandles "); + JNIHandles::verify(); + } + if (should_verify_subset(Verify_CHeap)) { + if (!silent) gclog_or_tty->print("C-heap "); + os::check_heap(); + } + if (should_verify_subset(Verify_CodeCacheOops)) { + if (!silent) gclog_or_tty->print("CodeCache Oops "); + CodeCache::verify_oops(); + } if (!silent) gclog_or_tty->print_cr("]"); _verify_in_progress = false; diff --git a/src/share/vm/memory/universe.hpp b/src/share/vm/memory/universe.hpp index db806ef6d..3c6a89d2c 100644 --- a/src/share/vm/memory/universe.hpp +++ b/src/share/vm/memory/universe.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2016, 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 @@ -247,6 +247,7 @@ class Universe: AllStatic { static int _verify_count; // number of verifies done // True during call to verify(). Should only be set/cleared in verify(). static bool _verify_in_progress; + static long verify_flags; static void compute_verify_oop_data(); @@ -425,6 +426,22 @@ class Universe: AllStatic { static void init_self_patching_vtbl_list(void** list, int count); // Debugging + enum VERIFY_FLAGS { + Verify_Threads = 1, + Verify_Heap = 2, + Verify_SymbolTable = 4, + Verify_StringTable = 8, + Verify_CodeCache = 16, + Verify_SystemDictionary = 32, + Verify_ClassLoaderDataGraph = 64, + Verify_MetaspaceAux = 128, + Verify_JNIHandles = 256, + Verify_CHeap = 512, + Verify_CodeCacheOops = 1024, + Verify_All = -1 + }; + static void initialize_verify_flags(); + static bool should_verify_subset(uint subset); static bool verify_in_progress() { return _verify_in_progress; } static void verify(VerifyOption option, const char* prefix, bool silent = VerifySilently); static void verify(const char* prefix, bool silent = VerifySilently) { diff --git a/src/share/vm/runtime/globals.hpp b/src/share/vm/runtime/globals.hpp index 1e01b2e7a..c76ced47f 100644 --- a/src/share/vm/runtime/globals.hpp +++ b/src/share/vm/runtime/globals.hpp @@ -2259,6 +2259,14 @@ class CommandLineFlags { diagnostic(bool, VerifyDuringGC, false, \ "Verify memory system during GC (between phases)") \ \ + diagnostic(ccstrlist, VerifySubSet, "", \ + "Memory sub-systems to verify when Verify*GC flag(s) " \ + "are enabled. One or more sub-systems can be specified " \ + "in a comma separated string. Sub-systems are: " \ + "threads, heap, symbol_table, string_table, codecache, " \ + "dictionary, classloader_data_graph, metaspace, jni_handles, " \ + "c-heap, codecache_oops") \ + \ diagnostic(bool, GCParallelVerificationEnabled, true, \ "Enable parallel memory system verification") \ \ diff --git a/test/gc/TestVerifySubSet.java b/test/gc/TestVerifySubSet.java new file mode 100644 index 000000000..879798301 --- /dev/null +++ b/test/gc/TestVerifySubSet.java @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2016, 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 TestVerifySubSet.java + * @key gc + * @bug 8072725 + * @summary Test VerifySubSet option + * @library /testlibrary + */ + +import com.oracle.java.testlibrary.OutputAnalyzer; +import com.oracle.java.testlibrary.ProcessTools; +import java.util.ArrayList; +import java.util.Collections; + +class RunSystemGC { + public static void main(String args[]) throws Exception { + System.gc(); + } +} + +public class TestVerifySubSet { + private static String[] getTestJavaOpts() { + String testVmOptsStr = System.getProperty("test.java.opts"); + if (!testVmOptsStr.isEmpty()) { + return testVmOptsStr.split(" "); + } else { + return new String[] {}; + } + } + + private static OutputAnalyzer runTest(String subset) throws Exception { + ArrayList vmOpts = new ArrayList(); + + Collections.addAll(vmOpts, getTestJavaOpts()); + Collections.addAll(vmOpts, new String[] {"-XX:+UnlockDiagnosticVMOptions", + "-XX:+VerifyBeforeGC", + "-XX:+VerifyAfterGC", + "-XX:VerifySubSet="+subset, + RunSystemGC.class.getName()}); + ProcessBuilder pb = + ProcessTools.createJavaProcessBuilder(vmOpts.toArray(new String[vmOpts.size()])); + OutputAnalyzer output = new OutputAnalyzer(pb.start()); + + System.out.println("Output:\n" + output.getOutput()); + return output; + } + + public static void main(String args[]) throws Exception { + + OutputAnalyzer output; + + output = runTest("heap, threads, codecache, metaspace"); + output.shouldContain("Heap"); + output.shouldContain("Threads"); + output.shouldContain("CodeCache"); + output.shouldContain("MetaspaceAux"); + output.shouldNotContain("SymbolTable"); + output.shouldNotContain("StringTable"); + output.shouldNotContain("SystemDictionary"); + output.shouldNotContain("CodeCache Oops"); + output.shouldHaveExitValue(0); + + output = runTest("hello, threads, codecache, metaspace"); + output.shouldContain("memory sub-system is unknown, please correct it"); + output.shouldNotContain("Threads"); + output.shouldNotContain("CodeCache"); + output.shouldNotContain("MetaspaceAux"); + output.shouldHaveExitValue(1); + } +} -- GitLab