Projects
Mega:23.09
openjdk-1.8.0
_service:tar_scm:0047-8025692-Log-what-methods-...
Sign Up
Log In
Username
Password
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File _service:tar_scm:0047-8025692-Log-what-methods-are-touched-at-run-time.patch of Package openjdk-1.8.0
Date: Fri, 9 Jun 2023 12:13:26 +0800 Subject: [PATCH 47/59] 8025692: Log what methods are touched at run-time Bug url: https://bugs.openjdk.org/browse/JDK-8025692 --- .../vm/templateInterpreter_aarch64.cpp | 4 +- hotspot/src/cpu/ppc/vm/interp_masm_ppc_64.cpp | 2 +- .../cpu/ppc/vm/templateInterpreter_ppc.cpp | 4 +- .../src/cpu/sparc/vm/interp_masm_sparc.cpp | 2 +- .../sparc/vm/templateInterpreter_sparc.cpp | 4 +- .../cpu/x86/vm/templateInterpreter_x86_32.cpp | 4 +- .../cpu/x86/vm/templateInterpreter_x86_64.cpp | 4 +- hotspot/src/share/vm/ci/ciMethod.cpp | 3 + hotspot/src/share/vm/oops/method.cpp | 84 +++++++++++ hotspot/src/share/vm/oops/method.hpp | 2 + hotspot/src/share/vm/runtime/globals.hpp | 6 + hotspot/src/share/vm/runtime/java.cpp | 8 ++ hotspot/src/share/vm/runtime/mutexLocker.cpp | 2 + hotspot/src/share/vm/runtime/mutexLocker.hpp | 1 + .../src/share/vm/runtime/vm_operations.hpp | 1 + .../share/vm/services/diagnosticCommand.cpp | 33 +++++ .../share/vm/services/diagnosticCommand.hpp | 17 +++ .../CommandLine/PrintTouchedMethods.java | 134 ++++++++++++++++++ .../CommandLine/TestLogTouchedMethods.java | 35 +++++ 19 files changed, 338 insertions(+), 12 deletions(-) create mode 100644 hotspot/test/runtime/CommandLine/PrintTouchedMethods.java create mode 100644 hotspot/test/runtime/CommandLine/TestLogTouchedMethods.java diff --git a/hotspot/src/cpu/aarch64/vm/templateInterpreter_aarch64.cpp b/hotspot/src/cpu/aarch64/vm/templateInterpreter_aarch64.cpp index a5a91e5f3..28b84cb51 100644 --- a/hotspot/src/cpu/aarch64/vm/templateInterpreter_aarch64.cpp +++ b/hotspot/src/cpu/aarch64/vm/templateInterpreter_aarch64.cpp @@ -1135,7 +1135,7 @@ void InterpreterGenerator::bang_stack_shadow_pages(bool native_call) { // native method than the typical interpreter frame setup. address InterpreterGenerator::generate_native_entry(bool synchronized) { // determine code generation flags - bool inc_counter = UseCompiler || CountCompiledCalls; + bool inc_counter = UseCompiler || CountCompiledCalls || LogTouchedMethods; // r1: Method* // rscratch1: sender sp @@ -1591,7 +1591,7 @@ address InterpreterGenerator::generate_native_entry(bool synchronized) { // address InterpreterGenerator::generate_normal_entry(bool synchronized) { // determine code generation flags - bool inc_counter = UseCompiler || CountCompiledCalls; + bool inc_counter = UseCompiler || CountCompiledCalls || LogTouchedMethods; // rscratch1: sender sp address entry_point = __ pc(); diff --git a/hotspot/src/cpu/ppc/vm/interp_masm_ppc_64.cpp b/hotspot/src/cpu/ppc/vm/interp_masm_ppc_64.cpp index 463f9da92..594905ef7 100644 --- a/hotspot/src/cpu/ppc/vm/interp_masm_ppc_64.cpp +++ b/hotspot/src/cpu/ppc/vm/interp_masm_ppc_64.cpp @@ -2226,7 +2226,7 @@ void InterpreterMacroAssembler::get_method_counters(Register method, } void InterpreterMacroAssembler::increment_invocation_counter(Register Rcounters, Register iv_be_count, Register Rtmp_r0) { - assert(UseCompiler, "incrementing must be useful"); + assert(UseCompiler || LogTouchedMethods, "incrementing must be useful"); Register invocation_count = iv_be_count; Register backedge_count = Rtmp_r0; int delta = InvocationCounter::count_increment; diff --git a/hotspot/src/cpu/ppc/vm/templateInterpreter_ppc.cpp b/hotspot/src/cpu/ppc/vm/templateInterpreter_ppc.cpp index 0fb934166..4e2cec39b 100644 --- a/hotspot/src/cpu/ppc/vm/templateInterpreter_ppc.cpp +++ b/hotspot/src/cpu/ppc/vm/templateInterpreter_ppc.cpp @@ -726,7 +726,7 @@ address TemplateInterpreterGenerator::generate_native_entry(bool synchronized) { address entry = __ pc(); - const bool inc_counter = UseCompiler || CountCompiledCalls; + const bool inc_counter = UseCompiler || CountCompiledCalls || LogTouchedMethods; // ----------------------------------------------------------------------------- // Allocate a new frame that represents the native callee (i2n frame). @@ -1176,7 +1176,7 @@ address TemplateInterpreterGenerator::generate_native_entry(bool synchronized) { // Generic interpreted method entry to (asm) interpreter. // address TemplateInterpreterGenerator::generate_normal_entry(bool synchronized) { - bool inc_counter = UseCompiler || CountCompiledCalls; + bool inc_counter = UseCompiler || CountCompiledCalls || LogTouchedMethods; address entry = __ pc(); // Generate the code to allocate the interpreter stack frame. Register Rsize_of_parameters = R4_ARG2, // Written by generate_fixed_frame. diff --git a/hotspot/src/cpu/sparc/vm/interp_masm_sparc.cpp b/hotspot/src/cpu/sparc/vm/interp_masm_sparc.cpp index 66bcfcaf1..83d54d731 100644 --- a/hotspot/src/cpu/sparc/vm/interp_masm_sparc.cpp +++ b/hotspot/src/cpu/sparc/vm/interp_masm_sparc.cpp @@ -2362,7 +2362,7 @@ void InterpreterMacroAssembler::get_method_counters(Register method, } void InterpreterMacroAssembler::increment_invocation_counter( Register Rcounters, Register Rtmp, Register Rtmp2 ) { - assert(UseCompiler, "incrementing must be useful"); + assert(UseCompiler || LogTouchedMethods, "incrementing must be useful"); assert_different_registers(Rcounters, Rtmp, Rtmp2); Address inv_counter(Rcounters, MethodCounters::invocation_counter_offset() + diff --git a/hotspot/src/cpu/sparc/vm/templateInterpreter_sparc.cpp b/hotspot/src/cpu/sparc/vm/templateInterpreter_sparc.cpp index 540f9b287..9526866bd 100644 --- a/hotspot/src/cpu/sparc/vm/templateInterpreter_sparc.cpp +++ b/hotspot/src/cpu/sparc/vm/templateInterpreter_sparc.cpp @@ -823,7 +823,7 @@ address InterpreterGenerator::generate_native_entry(bool synchronized) { // the following temporary registers are used during frame creation const Register Gtmp1 = G3_scratch ; const Register Gtmp2 = G1_scratch; - bool inc_counter = UseCompiler || CountCompiledCalls; + bool inc_counter = UseCompiler || CountCompiledCalls || LogTouchedMethods; // make sure registers are different! assert_different_registers(G2_thread, G5_method, Gargs, Gtmp1, Gtmp2); @@ -1261,7 +1261,7 @@ address InterpreterGenerator::generate_native_entry(bool synchronized) { address InterpreterGenerator::generate_normal_entry(bool synchronized) { address entry = __ pc(); - bool inc_counter = UseCompiler || CountCompiledCalls; + bool inc_counter = UseCompiler || CountCompiledCalls || LogTouchedMethods; // the following temporary registers are used during frame creation const Register Gtmp1 = G3_scratch ; diff --git a/hotspot/src/cpu/x86/vm/templateInterpreter_x86_32.cpp b/hotspot/src/cpu/x86/vm/templateInterpreter_x86_32.cpp index b7c515031..662d82222 100644 --- a/hotspot/src/cpu/x86/vm/templateInterpreter_x86_32.cpp +++ b/hotspot/src/cpu/x86/vm/templateInterpreter_x86_32.cpp @@ -990,7 +990,7 @@ address InterpreterGenerator::generate_CRC32_updateBytes_entry(AbstractInterpret address InterpreterGenerator::generate_native_entry(bool synchronized) { // determine code generation flags - bool inc_counter = UseCompiler || CountCompiledCalls; + bool inc_counter = UseCompiler || CountCompiledCalls || LogTouchedMethods; // rbx,: Method* // rsi: sender sp @@ -1405,7 +1405,7 @@ address InterpreterGenerator::generate_native_entry(bool synchronized) { // address InterpreterGenerator::generate_normal_entry(bool synchronized) { // determine code generation flags - bool inc_counter = UseCompiler || CountCompiledCalls; + bool inc_counter = UseCompiler || CountCompiledCalls || LogTouchedMethods; // rbx,: Method* // rsi: sender sp diff --git a/hotspot/src/cpu/x86/vm/templateInterpreter_x86_64.cpp b/hotspot/src/cpu/x86/vm/templateInterpreter_x86_64.cpp index 209a3f676..0f3bfc979 100644 --- a/hotspot/src/cpu/x86/vm/templateInterpreter_x86_64.cpp +++ b/hotspot/src/cpu/x86/vm/templateInterpreter_x86_64.cpp @@ -962,7 +962,7 @@ address InterpreterGenerator::generate_CRC32_updateBytes_entry(AbstractInterpret // native method than the typical interpreter frame setup. address InterpreterGenerator::generate_native_entry(bool synchronized) { // determine code generation flags - bool inc_counter = UseCompiler || CountCompiledCalls; + bool inc_counter = UseCompiler || CountCompiledCalls || LogTouchedMethods; // rbx: Method* // r13: sender sp @@ -1409,7 +1409,7 @@ address InterpreterGenerator::generate_native_entry(bool synchronized) { // address InterpreterGenerator::generate_normal_entry(bool synchronized) { // determine code generation flags - bool inc_counter = UseCompiler || CountCompiledCalls; + bool inc_counter = UseCompiler || CountCompiledCalls || LogTouchedMethods; // ebx: Method* // r13: sender sp diff --git a/hotspot/src/share/vm/ci/ciMethod.cpp b/hotspot/src/share/vm/ci/ciMethod.cpp index 22fe6c8f1..50fafc4f8 100644 --- a/hotspot/src/share/vm/ci/ciMethod.cpp +++ b/hotspot/src/share/vm/ci/ciMethod.cpp @@ -74,6 +74,9 @@ ciMethod::ciMethod(methodHandle h_m, ciInstanceKlass* holder) : { assert(h_m() != NULL, "no null method"); + if (LogTouchedMethods) { + h_m()->log_touched(Thread::current()); + } // These fields are always filled in in loaded methods. _flags = ciFlags(h_m()->access_flags()); diff --git a/hotspot/src/share/vm/oops/method.cpp b/hotspot/src/share/vm/oops/method.cpp index 305348bd0..406cd485e 100644 --- a/hotspot/src/share/vm/oops/method.cpp +++ b/hotspot/src/share/vm/oops/method.cpp @@ -408,6 +408,11 @@ MethodCounters* Method::build_method_counters(Method* m, TRAPS) { if (!mh->init_method_counters(counters)) { MetadataFactory::free_metadata(loader_data, counters); } + + if (LogTouchedMethods) { + mh->log_touched(CHECK_NULL); + } + return mh->method_counters(); } @@ -2088,6 +2093,85 @@ void Method::collect_statistics(KlassSizeStats *sz) const { } #endif // INCLUDE_SERVICES +// LogTouchedMethods and PrintTouchedMethods + +// TouchedMethodRecord -- we can't use a HashtableEntry<Method*> because +// the Method may be garbage collected. Let's roll our own hash table. +class TouchedMethodRecord : CHeapObj<mtTracing> { +public: + // It's OK to store Symbols here because they will NOT be GC'ed if + // LogTouchedMethods is enabled. + TouchedMethodRecord* _next; + Symbol* _class_name; + Symbol* _method_name; + Symbol* _method_signature; +}; + +static const int TOUCHED_METHOD_TABLE_SIZE = 20011; +static TouchedMethodRecord** _touched_method_table = NULL; + +void Method::log_touched(TRAPS) { + + const int table_size = TOUCHED_METHOD_TABLE_SIZE; + Symbol* my_class = klass_name(); + Symbol* my_name = name(); + Symbol* my_sig = signature(); + + unsigned int hash = my_class->identity_hash() + + my_name->identity_hash() + + my_sig->identity_hash(); + juint index = juint(hash) % table_size; + + MutexLocker ml(TouchedMethodLog_lock, THREAD); + if (_touched_method_table == NULL) { + _touched_method_table = NEW_C_HEAP_ARRAY2(TouchedMethodRecord*, table_size, + mtTracing, CURRENT_PC); + memset(_touched_method_table, 0, sizeof(TouchedMethodRecord*) * table_size); + } + + TouchedMethodRecord* ptr = _touched_method_table[index]; + while (ptr) { + if (ptr->_class_name == my_class && + ptr->_method_name == my_name && + ptr->_method_signature == my_sig) { + return; + } + if (ptr->_next == NULL) break; + ptr = ptr->_next; + } + TouchedMethodRecord* nptr = NEW_C_HEAP_OBJ(TouchedMethodRecord, mtTracing); + my_class->increment_refcount(); + my_name->increment_refcount(); + my_sig->increment_refcount(); + nptr->_class_name = my_class; + nptr->_method_name = my_name; + nptr->_method_signature = my_sig; + nptr->_next = NULL; + + if (ptr == NULL) { + // first + _touched_method_table[index] = nptr; + } else { + ptr->_next = nptr; + } +} + +void Method::print_touched_methods(outputStream* out) { + MutexLockerEx ml(Thread::current()->is_VM_thread() ? NULL : TouchedMethodLog_lock); + out->print_cr("# Method::print_touched_methods version 1"); + if (_touched_method_table) { + for (int i = 0; i < TOUCHED_METHOD_TABLE_SIZE; i++) { + TouchedMethodRecord* ptr = _touched_method_table[i]; + while(ptr) { + ptr->_class_name->print_symbol_on(out); out->print("."); + ptr->_method_name->print_symbol_on(out); out->print(":"); + ptr->_method_signature->print_symbol_on(out); out->cr(); + ptr = ptr->_next; + } + } + } +} + // Verification void Method::verify_on(outputStream* st) { diff --git a/hotspot/src/share/vm/oops/method.hpp b/hotspot/src/share/vm/oops/method.hpp index ec93f2fb4..ee74d959d 100644 --- a/hotspot/src/share/vm/oops/method.hpp +++ b/hotspot/src/share/vm/oops/method.hpp @@ -650,6 +650,8 @@ class Method : public Metadata { #if INCLUDE_SERVICES void collect_statistics(KlassSizeStats *sz) const; #endif + void log_touched(TRAPS); + static void print_touched_methods(outputStream* out); // interpreter support static ByteSize const_offset() { return byte_offset_of(Method, _constMethod ); } diff --git a/hotspot/src/share/vm/runtime/globals.hpp b/hotspot/src/share/vm/runtime/globals.hpp index 210e6bd67..11f713013 100644 --- a/hotspot/src/share/vm/runtime/globals.hpp +++ b/hotspot/src/share/vm/runtime/globals.hpp @@ -2694,6 +2694,12 @@ class CommandLineFlags { develop(bool, EagerInitialization, false, \ "Eagerly initialize classes if possible") \ \ + diagnostic(bool, LogTouchedMethods, false, \ + "Log methods which have been ever touched in runtime") \ + \ + diagnostic(bool, PrintTouchedMethodsAtExit, false, \ + "Print all methods that have been ever touched in runtime") \ + \ develop(bool, TraceMethodReplacement, false, \ "Print when methods are replaced do to recompilation") \ \ diff --git a/hotspot/src/share/vm/runtime/java.cpp b/hotspot/src/share/vm/runtime/java.cpp index c72a5a766..5a628b73e 100644 --- a/hotspot/src/share/vm/runtime/java.cpp +++ b/hotspot/src/share/vm/runtime/java.cpp @@ -360,6 +360,10 @@ void print_statistics() { SystemDictionary::print(); } + if (LogTouchedMethods && PrintTouchedMethodsAtExit) { + Method::print_touched_methods(tty); + } + if (PrintBiasedLockingStatistics) { BiasedLocking::print_counters(); } @@ -408,6 +412,10 @@ void print_statistics() { if (PrintNMTStatistics) { MemTracker::final_report(tty); } + + if (LogTouchedMethods && PrintTouchedMethodsAtExit) { + Method::print_touched_methods(tty); + } } #endif diff --git a/hotspot/src/share/vm/runtime/mutexLocker.cpp b/hotspot/src/share/vm/runtime/mutexLocker.cpp index a1c61f864..0b4a98cb7 100644 --- a/hotspot/src/share/vm/runtime/mutexLocker.cpp +++ b/hotspot/src/share/vm/runtime/mutexLocker.cpp @@ -63,6 +63,7 @@ Monitor* StringDedupQueue_lock = NULL; Mutex* StringDedupTable_lock = NULL; Mutex* CodeCache_lock = NULL; Mutex* MethodData_lock = NULL; +Mutex* TouchedMethodLog_lock = NULL; Mutex* RetData_lock = NULL; Monitor* VMOperationQueue_lock = NULL; Monitor* VMOperationRequest_lock = NULL; @@ -282,6 +283,7 @@ void mutex_init() { def(Compile_lock , Mutex , nonleaf+3, true ); def(MethodData_lock , Mutex , nonleaf+3, false); + def(TouchedMethodLog_lock , Mutex , nonleaf+3, false); def(MethodCompileQueue_lock , Monitor, nonleaf+4, true ); def(Debug2_lock , Mutex , nonleaf+4, true ); diff --git a/hotspot/src/share/vm/runtime/mutexLocker.hpp b/hotspot/src/share/vm/runtime/mutexLocker.hpp index f28058b0e..0d6de9ea0 100644 --- a/hotspot/src/share/vm/runtime/mutexLocker.hpp +++ b/hotspot/src/share/vm/runtime/mutexLocker.hpp @@ -71,6 +71,7 @@ extern Monitor* StringDedupQueue_lock; // a lock on the string dedupli extern Mutex* StringDedupTable_lock; // a lock on the string deduplication table extern Mutex* CodeCache_lock; // a lock on the CodeCache, rank is special, use MutexLockerEx extern Mutex* MethodData_lock; // a lock on installation of method data +extern Mutex* TouchedMethodLog_lock; // a lock on allocation of LogExecutedMethods info extern Mutex* RetData_lock; // a lock on installation of RetData inside method data extern Mutex* DerivedPointerTableGC_lock; // a lock to protect the derived pointer table extern Monitor* VMOperationQueue_lock; // a lock on queue of vm_operations waiting to execute diff --git a/hotspot/src/share/vm/runtime/vm_operations.hpp b/hotspot/src/share/vm/runtime/vm_operations.hpp index 19463b137..f2071a9d6 100644 --- a/hotspot/src/share/vm/runtime/vm_operations.hpp +++ b/hotspot/src/share/vm/runtime/vm_operations.hpp @@ -99,6 +99,7 @@ template(WhiteBoxOperation) \ template(ClassLoaderStatsOperation) \ template(ClassLoaderHierarchyOperation) \ + template(DumpTouchedMethods) \ template(JFROldObject) \ template(PrintClasses) \ template(PrintMetadata) \ diff --git a/hotspot/src/share/vm/services/diagnosticCommand.cpp b/hotspot/src/share/vm/services/diagnosticCommand.cpp index e37ba3cc8..50050a169 100644 --- a/hotspot/src/share/vm/services/diagnosticCommand.cpp +++ b/hotspot/src/share/vm/services/diagnosticCommand.cpp @@ -76,6 +76,7 @@ void DCmdRegistrant::register_dcmds(){ DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<CompileQueueDCmd>(full_export, true, false)); DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<CodeListDCmd>(full_export, true, false)); DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<CodeCacheDCmd>(full_export, true, false)); + DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<TouchedMethodsDCmd>(full_export, true, false)); #ifdef LINUX DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<TrimCLibcHeapDCmd>(full_export, true, false)); #endif // LINUX @@ -569,6 +570,38 @@ int ThreadDumpDCmd::num_arguments() { } } +class VM_DumpTouchedMethods : public VM_Operation { +private: + outputStream* _out; +public: + VM_DumpTouchedMethods(outputStream* out) { + _out = out; + } + + virtual VMOp_Type type() const { return VMOp_DumpTouchedMethods; } + + virtual void doit() { + Method::print_touched_methods(_out); + } +}; + +TouchedMethodsDCmd::TouchedMethodsDCmd(outputStream* output, bool heap) : + DCmdWithParser(output, heap) +{} + +void TouchedMethodsDCmd::execute(DCmdSource source, TRAPS) { + if (!UnlockDiagnosticVMOptions) { + output()->print_cr("VM.touched_methods command requires -XX:+UnlockDiagnosticVMOptions"); + return; + } + VM_DumpTouchedMethods dumper(output()); + VMThread::execute(&dumper); +} + +int TouchedMethodsDCmd::num_arguments() { + return 0; +} + // Enhanced JMX Agent support JMXStartRemoteDCmd::JMXStartRemoteDCmd(outputStream *output, bool heap_allocated) : diff --git a/hotspot/src/share/vm/services/diagnosticCommand.hpp b/hotspot/src/share/vm/services/diagnosticCommand.hpp index 65c04571b..3733fa7f7 100644 --- a/hotspot/src/share/vm/services/diagnosticCommand.hpp +++ b/hotspot/src/share/vm/services/diagnosticCommand.hpp @@ -36,6 +36,7 @@ #include "services/diagnosticFramework.hpp" #include "services/diagnosticCommand_ext.hpp" #include "utilities/macros.hpp" +#include "oops/method.hpp" class HelpDCmd : public DCmdWithParser { protected: @@ -358,6 +359,22 @@ public: virtual void execute(DCmdSource source, TRAPS); }; +class TouchedMethodsDCmd : public DCmdWithParser { +public: + TouchedMethodsDCmd(outputStream* output, bool heap); + static const char* name() { + return "VM.print_touched_methods"; + } + static const char* description() { + return "Print all methods that have ever been touched during the lifetime of this JVM."; + } + static const char* impact() { + return "Medium: Depends on Java content."; + } + static int num_arguments(); + virtual void execute(DCmdSource source, TRAPS); +}; + // See also: thread_dump in attachListener.cpp class ThreadDumpDCmd : public DCmdWithParser { protected: diff --git a/hotspot/test/runtime/CommandLine/PrintTouchedMethods.java b/hotspot/test/runtime/CommandLine/PrintTouchedMethods.java new file mode 100644 index 000000000..c85b2a5d8 --- /dev/null +++ b/hotspot/test/runtime/CommandLine/PrintTouchedMethods.java @@ -0,0 +1,134 @@ +/* + * Copyright (c) 2023, 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 + * @bug 8025692 + * @modules java.base/jdk.internal.misc + * java.management + * @library /testlibrary + * @compile TestLogTouchedMethods.java PrintTouchedMethods.java + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+LogTouchedMethods PrintTouchedMethods + */ + +import java.io.File; +import java.util.List; +import com.oracle.java.testlibrary.*; + +public class PrintTouchedMethods { + + public static void main(String args[]) throws Exception { + ProcessBuilder pb = ProcessTools.createJavaProcessBuilder( + "-XX:-UnlockDiagnosticVMOptions", + "-XX:+LogTouchedMethods", + "-XX:+PrintTouchedMethodsAtExit", + "TestLogTouchedMethods"); + + // UnlockDiagnostic turned off, should fail + OutputAnalyzer output = new OutputAnalyzer(pb.start()); + output.shouldContain("Error: VM option 'LogTouchedMethods' is diagnostic and must be enabled via -XX:+UnlockDiagnosticVMOptions."); + output.shouldContain("Error: Could not create the Java Virtual Machine."); + + pb = ProcessTools.createJavaProcessBuilder( + "-XX:+UnlockDiagnosticVMOptions", + "-XX:+LogTouchedMethods", + "-XX:+PrintTouchedMethodsAtExit", + "TestLogTouchedMethods"); + output = new OutputAnalyzer(pb.start()); + // check order: + // 1 "# Method::print_touched_methods version 1" is the first in first line + // 2 should contain TestLogMethods.methodA:()V + // 3 should not contain TestLogMethods.methodB:()V + // Repeat above for another run with -Xint + List<String> lines = output.asLines(); + + if (lines.size() < 1) { + throw new Exception("Empty output"); + } + + String first = lines.get(0); + if (!first.equals("# Method::print_touched_methods version 1")) { + throw new Exception("First line mismatch"); + } + + output.shouldContain("TestLogTouchedMethods.methodA:()V"); + output.shouldNotContain("TestLogTouchedMethods.methodB:()V"); + output.shouldHaveExitValue(0); + + pb = ProcessTools.createJavaProcessBuilder( + "-XX:+UnlockDiagnosticVMOptions", + "-Xint", + "-XX:+LogTouchedMethods", + "-XX:+PrintTouchedMethodsAtExit", + "TestLogTouchedMethods"); + output = new OutputAnalyzer(pb.start()); + lines = output.asLines(); + + if (lines.size() < 1) { + throw new Exception("Empty output"); + } + + first = lines.get(0); + if (!first.equals("# Method::print_touched_methods version 1")) { + throw new Exception("First line mismatch"); + } + + output.shouldContain("TestLogTouchedMethods.methodA:()V"); + output.shouldNotContain("TestLogTouchedMethods.methodB:()V"); + output.shouldHaveExitValue(0); + + pb = ProcessTools.createJavaProcessBuilder( + "-XX:+UnlockDiagnosticVMOptions", + "-Xint", + "-XX:+LogTouchedMethods", + "-XX:+PrintTouchedMethodsAtExit", + "-XX:-TieredCompilation", + "TestLogTouchedMethods"); + output = new OutputAnalyzer(pb.start()); + lines = output.asLines(); + + if (lines.size() < 1) { + throw new Exception("Empty output"); + } + + first = lines.get(0); + if (!first.equals("# Method::print_touched_methods version 1")) { + throw new Exception("First line mismatch"); + } + + output.shouldContain("TestLogTouchedMethods.methodA:()V"); + output.shouldNotContain("TestLogTouchedMethods.methodB:()V"); + output.shouldHaveExitValue(0); + + // Test jcmd PrintTouchedMethods VM.print_touched_methods + String pid = Long.toString(ProcessTools.getProcessId()); + pb = new ProcessBuilder(); + pb.command(new String[] {JDKToolFinder.getJDKTool("jcmd"), pid, "VM.print_touched_methods"}); + output = new OutputAnalyzer(pb.start()); + try { + output.shouldContain("PrintTouchedMethods.main:([Ljava/lang/String;)V"); + } catch (RuntimeException e) { + output.shouldContain("Unknown diagnostic command"); + } + } +} \ No newline at end of file diff --git a/hotspot/test/runtime/CommandLine/TestLogTouchedMethods.java b/hotspot/test/runtime/CommandLine/TestLogTouchedMethods.java new file mode 100644 index 000000000..655d4a916 --- /dev/null +++ b/hotspot/test/runtime/CommandLine/TestLogTouchedMethods.java @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2023, 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. + */ + +/* used by PrintTouchedMethods.java */ +public class TestLogTouchedMethods { + public static void main(String[] args) { + new TestLogTouchedMethods().methodA(); + } + + // methods without return values and local variables are optimized in interpreter mode + // it can not be recorded + // leave at least one local variable + public void methodA() { int a = 0; } // called + public void methodB() { int b = 0; } // this should not be called +} -- 2.22.0
Locations
Projects
Search
Status Monitor
Help
Open Build Service
OBS Manuals
API Documentation
OBS Portal
Reporting a Bug
Contact
Mailing List
Forums
Chat (IRC)
Twitter
Open Build Service (OBS)
is an
openSUSE project
.
浙ICP备2022010568号-2