Re: [PATCH] oprofile-tests Add test to exercise libjvmti_oprofile.so
William Cohen <[email protected]> Mon, 23 Sep 2019 16:33:19 -0400
| Newsgroups | gmane.linux.oprofile |
|---|---|
| Message-ID | <[email protected]> |
On 9/6/19 12:25 PM, will schmidt wrote:
> Hi,
>
> This is a testsuite follow-on to the fix for the oprofile JIT
> bad event spec error patch that was posted a month or so ago.
>
> Assorted changes to exercise the use of oprofiles JVMTI hook.
> (libjvmti_oprofile.so - Oprofile library interface into the
> Java Virtual Machine Tools Interface).
>
> This has been tested this on assorted ppc64* systems with a mixture
> of having the libjvmti_oprofile present and not.
Hi,
Sorry for the slow turn around on the patch. The checking for libjvmti.so in op_resolve_java_dependencies() doesn't correctly identify location of libjvmti.so. On machines with both 32-bit and 64-bit versions such as x86-64 the library could be in /usr/lib64 or /usr/lib. Also will need to be careful to use the appropriate libjvmti.so. One might find 32-bit libjvmti.so but have 64-bit java installed.
-Will Cohen
>
>
>
> testsuite/lib/op_util.exp:
> * Update compile_workload() procedure to allow building of .java files.
> * Add procedure op_resolve_java_dependencies() to ensure that dependencies
> for building and running the java test can be found. This includes java,
> javac, and libjvmti_oprofile.so. Since the libjvmti_oprofile.so object
> can't be readily found via 'which', logic is in place that assumes it can
> be found in a path relative to where the operf binary is found.
>
> testsuite/lib/op_workloads.exp:
> * Add an op_java_workload_table containing the new test.
>
> testsuite/lib/operf_util.exp:
> * Add procedure (check_java_samples_exist) to see that samples can be
> found that are associated with the generated .jo object.
> * Add procedure (check_java_object_file_exists) to ensure that at
> least one "*.jo" file was created during the run.
> * Add procedure (do_java_test) to do the actual test.
>
> testsuite/workloads/java/Fibonacci.java:
> * Add the java test itself.
>
>
> Thanks
> -Will (Schmidt)
>
>
>
> diff --git a/testsuite/lib/op_util.exp b/testsuite/lib/op_util.exp
> index 7f0473d..d29e6eb 100644
> --- a/testsuite/lib/op_util.exp
> +++ b/testsuite/lib/op_util.exp
> @@ -179,15 +179,15 @@ proc check_user {} {
> proc compile_workload {workload_src compile_options } {
>
> # Ideally the TCL command target_compile should be used. However,
> # target_compile is ignoring the compiler options argument.
>
> - set compiler "cc"
> set extension [lindex [split $workload_src "."] 1]
> - set workload_exc [ lindex [split $workload_src "."] 0]_bin
>
> if { [string compare $extension "c"] == 0 } {
> + set workload_exc [ lindex [split $workload_src "."] 0]_bin
> + set compiler "cc"
> # workload is a C program, see if it needs to be compiled.
> set test [local_exec "ls $workload_exc" "" "" 10]
>
> if { [lindex $test 0] == 1 } {
> # workload has not been compiled
> @@ -198,10 +198,28 @@ proc compile_workload {workload_src compile_options } {
> }
> }
> return [ lindex [split $workload_src "."] 0]_bin
> }
>
> + if { [string compare $extension "java"] == 0 } {
> + set compiler "javac"
> + set workload_exc [ lindex [split $workload_src "."] 0].class
> + # workload is a java program, see if it needs to be compiled.
> + set test [local_exec "ls $workload_exc" "" "" 10]
> + if { [lindex $test 0] == 1 } {
> + # workload has not been compiled
> + set result [local_exec "$compiler $workload_src $compile_options" "" "" 10 ]
> + if { [lindex $result 0] == 1 } {
> + print "\nERROR compiling workload: $workload_src"
> + print "Compiler error message: $result\n"
> + }
> + }
> + set path_and_basename [lindex [split $workload_src "."] 0]
> + set classonly [ lindex [ split $path_and_basename "/"] 2]
> + return $classonly
> + }
> +
> # Assume the workload is a script, set the executable
> # name to the same as the source name.
> return $workload_src
> }
>
> @@ -243,5 +261,57 @@ proc op_check_dependencies {} {
> set op_deps_ok 0
> } else {
> set op_deps_ok 1
> }
> }
> +
> +proc op_resolve_java_dependencies {} {
> + global java_deps_ok
> + global path_to_libjvmti
> + set libjvmti_oprofile_present 0
> + set java_present 0
> + set javac_present 0
> + set operf_present 0
> +
> + set path_to_operf [ local_exec "which operf" "" "" 100 ]
> + if {[regexp "operf" $path_to_operf operf_present] == 1} {
> + verbose "Found operf ($operf_present) at $path_to_operf ."
> + } else {
> + send "Didn't find operf.\n"
> + }
> +
> + set path_to_javac [ local_exec "which javac" "" "" 100 ]
> + if {[regexp "javac" $path_to_javac javac_present] == 1} {
> + verbose "Found javac ($javac_present) at $path_to_javac ."
> + } else {
> + send "javac is require to build the java testcase. I didn't find javac via 'which'.\n"
> + }
> +
> + set path_to_java [ local_exec "which java" "" "" 100 ]
> + if {[regexp "java" $path_to_java java_present] == 1} {
> + verbose "Found java ($java_present) at $path_to_java ."
> + } else {
> + send "java is require to run the java testcase. I didn't find java via 'which'.\n"
> + }
> +
> +# Finding libjvmti_oprofile.so may be more interesting.
> +# Lets assume the oprofile install has sibling /bin/ and /lib/ directories,
> +# so as long as we have found the operf binary, we should be able to infer
> +# the location of libjvmti_oprofile.so.
> + set path_to_libjvmti [string map {bin/operf lib/oprofile/libjvmti_oprofile.so} $path_to_operf ]
> + set path_to_libjvmti [string trimleft $path_to_libjvmti "0\ \{"]
> + set path_to_libjvmti [string trim $path_to_libjvmti "\ \n\r\}"]
> +
> + set libjvmti_oprofile_present [file exists $path_to_libjvmti ]
> + if {$libjvmti_oprofile_present == 1 } {
> + verbose "found libjvmti_oprofile ($libjvmti_oprofile_present) at $path_to_libjvmti. \n"
> + } else {
> + send "did not find libjvmti_oprofile (checked $path_to_libjvmti ) .\n"
> + }
> +
> + if {$operf_present == 0 || $java_present == 0 || $javac_present == 0 || $libjvmti_oprofile_present == 0} {
> + set java_deps_ok 0
> + } else {
> + set java_deps_ok 1
> + }
> +}
> +
> diff --git a/testsuite/lib/op_workloads.exp b/testsuite/lib/op_workloads.exp
> index 661e280..9e96b52 100644
> --- a/testsuite/lib/op_workloads.exp
> +++ b/testsuite/lib/op_workloads.exp
> @@ -2,10 +2,14 @@
>
> if {! [array exists op_workload_table]} {
> array set op_workload_table {}
> }
>
> +if {! [array exists op_java_workload_table]} {
> + array set op_java_workload_table {}
> +}
> +
> # Make sure the workload binary name is unique and not a substring of the
> # directory or the test to see if the symbol exists may find the symbol in
> # the directory name not the executable.
> #
> # The op_workload_table consists of three or more entries. The entries
> @@ -59,5 +63,15 @@ set op_workload_table(anon_remap) \
> {workloads/anon_remap_src/anon_remap.c} \
> {} \
> {} \
> { anon } \
> }
> +
> +# A new/different table for the java workload(s).
> +set op_java_workload_table(fibonacci) \
> + { \
> + {workloads/java/Fibonacci.java} \
> + {} \
> + {Fibonacci.main} \
> + {} \
> +}
> +
> diff --git a/testsuite/lib/operf_util.exp b/testsuite/lib/operf_util.exp
> index b34fd33..10ea9ac 100644
> --- a/testsuite/lib/operf_util.exp
> +++ b/testsuite/lib/operf_util.exp
> @@ -1,7 +1,7 @@
> -# op_util.exp
> -# Copyright (C) 2012 IBM
> +# operf_util.exp
> +# Copyright (C) 2012-2019 IBM
> #
> # This file is free software; you can redistribute it and/or modify
> # it under the terms of the GNU General Public License as published by
> # the Free Software Foundation; either version 2 of the License, or
> # (at your option) any later version.
> @@ -86,10 +86,41 @@ proc operf_check_samples_exist {ctrs} {
> pass "$test: {$event} created nonzero sample files"
> }
> }
> }
>
> +proc operf_check_java_samples_exist {ctrs} {
> + set test "checking for samples associated with *.jo"
> + verbose "checking for samples associated with *.jo"
> +
> + foreach ctr $ctrs {
> + set n [lindex $ctr 0]
> + set event [lindex $ctr 1]
> + # add "-t 3" as a percentage threshold to cull some noise.
> + # add "-n" to suppress the opreport header (easier for debug).
> + # add a regexp blurb to get just the .jo entries.
> + set result [ local_exec "opreport event:$event -t 3 -n " "" "" 100 ]
> + if { [regexp "\[0-9\].jo" "$result" ]} {
> + pass "$test: {$event} found samples associated with *.jo"
> + } else {
> + fail "$test: {$event} didn't find samples associated with *.jo"
> + }
> + }
> +}
> +
> +proc operf_check_java_object_file_exists {} {
> + set test "At least one java object (.jo) file exists."
> + verbose "At least one java object (.jo) file exists."
> +
> + set result [ local_exec "find . -name \"*.jo\" " "" "" 100 ]
> + if {[regexp ".jo" "$result"]} {
> + pass "$test: found at least one java object file."
> + } else {
> + fail "$test: Did not find a java object (*.jo) file."
> + }
> +}
> +
> proc operf_ocount_get_version {tool} {
> global operf_ocount_version
> global user_is_root
>
> if { [string compare $tool "operf"] == 0 } {
> @@ -159,10 +190,85 @@ proc operf_get_version {} {
> set test "OProfile operf version check"
> operf_ocount_get_version "operf"
> set operf_version $operf_ocount_version
> }
>
> +# run a java test.
> +proc do_java_test {ctrs output_check test_debug_option} {
> +
> + global op_java_workload_table
> + global op_workload_table
> + global path_to_libjvmti
> + set kernel 1
> + set user 1
> + set ctr_opts {}
> +
> + if { $output_check == 1 && $test_debug_option == 0 } {
> + validate_xml_help
> + }
> +
> + foreach ctr $ctrs {
> +# n - counter number, no longer used but didn't want to change
> +# specification format
> + set n [lindex $ctr 0]
> + set event [lindex $ctr 1]
> + set um [lindex $ctr 2]
> + if {$output_check == 3} {
> + # With callgraph profiling, we only use the cycles-based event for the
> + # architecture. Just set the count value high enough to make sure it's
> + # at least 15x the minimum; 1,500,000 should do it.
> + set count 1500000
> + } else {
> + set count [lindex $ctr 3]
> + }
> + append ctr_opts "${event}:${count}:${um}:${kernel}:${user},"
> + }
> +
> + foreach entry [array name op_java_workload_table] {
> + set workload_src [lindex $op_java_workload_table($entry) 0]
> + set compile_options [lindex $op_java_workload_table($entry) 1]
> + set workload_exc [compile_workload $workload_src $compile_options]
> + verbose "Workload: $workload_exc\n"
> + verbose "Counter options: $ctr_opts\n"
> + # Run the workload
> + set java_classpath "workloads/java/"
> + set cmd "operf java -agentpath:${path_to_libjvmti} -cp ${java_classpath} ${workload_exc}"
> + verbose "operf command is: $cmd \n"
> +
> + if {$test_debug_option == 1} {
> + set dbg_test " (--debug-info)"
> + } else {
> + set dbg_test ""
> + }
> + set test "operf test against java: $cmd"
> + verbose "\nTest: $test\n"
> + if {[lindex [local_exec $cmd "" "" 100] 0] == 0} {
> + pass $test
> + } else {
> + fail $test
> + }
> +
> + # - verify that the test ran.
> + operf_check_samples_exist $ctrs
> + # - verify that at least one .jo file exists.
> + operf_check_java_object_file_exists
> + # - verify that the .jo entry shows up in the output.
> + operf_check_java_samples_exist $ctrs
> +
> + # Verify the interesting symbols for this test are found in
> + # the output. Only checking the symbols for the first group of
> + # events.
> + if {$output_check == 1} {
> + local_exec "sleep 1" "" "" 10
> + verify_output $op_java_workload_table($entry) $workload_exc $ctr_opts $test_debug_option
> + }
> +
> + operf_delete_samples
> + }
> +}
> +
> +
> proc do_single_process_test {ctrs output_check test_debug_option} {
> # The tests are run in single process mode which does not require root
> #
> # output_check values:
> # 1 - check output for symbols from workload table
> diff --git a/testsuite/oprofile-java/oprofile-java.exp b/testsuite/oprofile-java/oprofile-java.exp
> new file mode 100644
> index 0000000..47fe175
> --- /dev/null
> +++ b/testsuite/oprofile-java/oprofile-java.exp
> @@ -0,0 +1,112 @@
> +# oprofile-java.exp
> +# Copyright (C) 2019 IBM Corporation
> +#
> +# This file is free software; you can redistribute it and/or modify
> +# it under the terms of the GNU General Public License as published by
> +# the Free Software Foundation; either version 2 of the License, or
> +# (at your option) any later version.
> +#
> +# This program 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 for more details.
> +#
> +# You should have received a copy of the GNU General Public License
> +# along with this program; if not, write to the Free Software
> +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
> +#
> +
> +global path_to_libjvmti
> +
> +check_user
> +load_lib "op_events.exp"
> +load_lib "op_util.exp"
> +load_lib "operf_util.exp"
> +load_lib "op_workloads.exp"
> +
> +# run operf against a java utility, verify that a .jo file is created,
> +# and that an oreport can run successfully against the run.
> +
> +proc oprofile_run_java_tests {} {
> + global op_event_table
> +
> + set cpu [operf_cpu_type]
> + if {$cpu == "bogus"} {
> + send "Error, not able to find a valid cpu type. Exiting.\n"
> + } else {
> + set output_check 2
> + set test_debug_option 0
> + # Test using the first event entry only.
> + set spec [lindex $op_event_table($cpu) 0]
> + do_java_test $spec $output_check $test_debug_option
> + }
> +}
> +
> +#main
> +
> +set operf_version 0
> +set op_version 0
> +
> +op_check_dependencies
> +if {$op_deps_ok == 0} {
> + return
> +}
> +
> +op_resolve_java_dependencies
> +if {$java_deps_ok == 0} {
> +#send "returning from java_deps_ok check"
> + send "Skipping the java test due to missing dependencies.\n"
> + send "Oprofile needs to be built --with-java=<path/to/jdk/>, such \n"
> + send "that the libjvmti_oprofile.so object is built and installed.\n"
> + send "java,javac,operf also need to be available and in the PATH. \n"
> + return
> +}
> +
> +# Check to see of opcontrol is installed. Need to do this first as
> +# to set opcontrol_installed. If opcontrol is not installed, then we do
> +# not make any opcontrol calls to do cleanup of existing opcontrol data samples
> +# or call --deinit when exiting.
> +
> +operf_get_version
> +op_get_version
> +
> +if {$op_version == 0} {
> + # could not find opcontrol
> + set opcontrol_installed 0
> +} else {
> + if {$op_version < $operf_version} {
> + # Don't run the opcontrol tests at all if the opcontrol binary appears to
> + # be from an earlier version of OProfile.
> + set opcontrol_installed 0
> + } else {
> + set opcontrol_installed 1
> + }
> +}
> +
> +if { $operf_version == 0 } {
> + send "Skipping the operf tests.\n"
> + send "Unable to find or verify the version of the OProfile operf utility.\n"
> +} else {
> + # Ensure that the oprofile kernel module is unloaded, since it can
> + # interfere with proper operf operation on some platforms.
> +# if {$opcontrol_installed == 1} {
> +# local_exec "opcontrol --deinit" "" "" 100
> +# # Make sure there are no samples from the opcontrol laying
> +# # around that opreport might inadvertently pick up.
> +# op_daemon_delete_any_samples
> +# }
> + # Make sure there are no samples from the operf laying
> + # around that opreport might inadvertently pick up.
> + operf_delete_samples
> +
> + case $operf_version {
> + { 0.* } {
> + # Just don't run this on old versions.
> + send "v==0, skipping. \n"
> + }
> + { * } {
> + send "Running operf against a java workload. \n"
> + oprofile_run_java_tests
> + }
> + }
> +}
> diff --git a/testsuite/workloads/java/Fibonacci.java b/testsuite/workloads/java/Fibonacci.java
> new file mode 100644
> index 0000000..8d92b6a
> --- /dev/null
> +++ b/testsuite/workloads/java/Fibonacci.java
> @@ -0,0 +1,25 @@
> +
> +/* A simple java test to generate some activity to verify operf is working
> + * properly. */
> +
> +public class Fibonacci {
> + public static void main(String[] args) {
> + long sum=0;
> + int i = 1;
> + /* The test harness does not easily handle passing arguments
> + * to the test, so hardcode a value here.
> + * This (sum) will overflow, but that is fine as we are only after
> + * activity, and are not concerned with the result. */
> + int n = 12345; /*Integer.parseInt(args[0]);*/
> + long f1 = 0;
> + long f2 = f1 + 1;
> + while (i <= n) {
> + sum = f1 + f2;
> + f1 = f2;
> + f2 = sum;
> + i++;
> + }
> + System.out.print(sum);
> + System.out.print("\n");
> + }
> +}
>