[75ec9c]: testsuite / lib / operf_util.exp Maximize Restore History

Download this file

operf_util.exp    350 lines (298 with data), 11.5 kB

# op_util.exp
#   Copyright (C) 2012 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.
#
# 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.
#

# globals which might change, perhaps?
set op_proc_prefix "/dev/oprofile"
set op_var_prefix "/var/lib/oprofile"

proc operf_get_proc_name {string} {
    # ophelp returns the processor name as a series of space separated
    # names.  Read string and replace spaces with underscores to match
    # the format expected in the operf_cpu_type{} switch statement
    set res ""
    set len [llength $string]
    set i 0

    foreach field $string {
	set res $res$field
	incr i

	if {$i != $len} {
	    set res $res\_
	}
    }
    return $res
}

# detect CPU type
proc operf_cpu_type {} {
    global op_proc_prefix

    set ophelp_result [ local_exec "ophelp -r" "" "" 100 ]
    set cpu_name [operf_get_proc_name [ lindex $ophelp_result 1 ]]
    
    set cpu_events [select_cpu_events $cpu_name]

# Note, operf does not support the timer modes

    switch -exact "$cpu_name" {
	4 {set cpu_events bogus}
	timer {set cpu_events bogus}
	5 {set cpu_events bogus}
	rtc {set cpu_events bogus}
    }

    return $cpu_events
}

proc operf_delete_samples {} {
    set result [local_exec "rm -rf ./oprofile_data" "" "" 100 ]
    if { [lindex $result 0] == 0 } {
	verbose "Successfully deleted exiting data directory"
    } else {
	verbose "Failed to delete exiting data directory"
    }
}

proc operf_check_samples_exist {ctrs} {
    set test "nonzero-sized sample file creation"

    verbose "checking for nonzero sample files"

    foreach ctr $ctrs {
	set n [lindex $ctr 0]
	set event [lindex $ctr 1]

	verbose "running opreport --symbols --long-filenames event:$event"
	set result [ local_exec "opreport --symbols --long-filenames event:$event" "" "" 100 ]
	if { [regexp "error:" "$result" ]} {
	    fail "$test: {$event} created nonzero sample files"
	} else {
	    pass "$test: {$event} created nonzero sample files"
	}
    }
}

proc operf_ocount_get_version {tool} {
    global operf_ocount_version
    global user_is_root

    set test "OProfile operf/ocount version check"
    verbose $test
    set result [ local_exec "$tool -v" "" "" 100 ]

    if {[regexp "\[0-9\]+\(.\[0-9\]+\)+\[a-zA-Z_\]*" $result operf_ocount_version] == 1} {

#	Need to make sure the kernel has perf support as well
        if {[lindex [local_exec op-check-perfevents "" "" 100] 0] == 0} {
            pass $test
        } else {
            verbose "Kernel does not support operf\n"
            set operf_ocount_version 0
        }
    } else {
        verbose "unable to determine version"
        # A common cause for this is when cpu type "timer" is detected.
        # If running the full testsuite (i.e., 'runtest --tool=oprofile'), the
        # oprofile-opcontrol part will have run first.  However, the exit proc
        # does not run until we're completely finished, so opcontrol_exit will
        # not have been called to do the deinit.  Some newer processor models
        # are not supported by opcontrol except in timer mode, so running
        # opcontrol results in /dev/oprofile/cpu_type being set to 'timer' by
        # the oprofile kernel module.  If operf/ocount are run in such a situation,
        # they detect the "timer" mode and exit with a message telling the user
        # to run 'opcontrol --deinit'. If we are root user, we'll run the deinit
        # here; then we'll try again to get the version.  If we're not user, we'll
        # print a big message asking the user to do so.
        set operf_ocount_version 0
        check_user
        if {$user_is_root == 1} {
            if {[lindex [local_exec "opcontrol --deinit" "" "" 100] 0] == 0} {
                verbose "oprofile deinitialized ok"
                set result [ local_exec "$tool -v" "" "" 100 ]
                if {[regexp "\[0-9\]+\(.\[0-9\]+\)+\[a-zA-Z_\]*" $result operf_ocount_version] == 1} {
                    if {[lindex [local_exec op-check-perfevents "" "" 100] 0] == 0} {
                        pass $test
                        set operf_ocount_version 1
                    } else {
                        verbose "Kernel does not support operf/ocount\n"
                    }
                }
            }
        } else {
            send "Unable to get version from operf.  Try running 'opcontrol --deinit'.\n"
        }
    }
    if {$operf_ocount_version == 0} {
        warning $test
    }
}

proc operf_get_version {} {
    global operf_ocount_version
    global operf_version

    set test "OProfile operf version check"
    operf_ocount_get_version "operf"
    set operf_version $operf_ocount_version
}

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
#     2 - check if kallsyms should show up in the output and the symbol
#         no-vmlinux is not be found to verify kallsyms was readable
#     3 - test the callgraph ouput
#
#   test_debug_option values:
#     0 - do not test any additional options
#     1 - test --debug-info option

    global op_workload_table
    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_workload_table] {
	set workload_src [lindex $op_workload_table($entry) 0]
	set compile_options [lindex $op_workload_table($entry) 1]
	set workload_exc [compile_workload $workload_src  $compile_options]

	# Run the workload
	if {$output_check == 3} {
	    set cmd "operf --callgraph --lazy-conversion --events  ${ctr_opts} ${workload_exc}"
	} else {
	    set cmd "operf --events  ${ctr_opts} ${workload_exc}"
	}

	if {$test_debug_option == 1} {
	    set dbg_test " (--debug-info)"
	} else {
	    set dbg_test ""
	}
	switch -exact "$output_check" {
	    1 {set test "operf check for symbols$dbg_test: $cmd"}
	    2 {set test "operf check for kallsyms$dbg_test: $cmd"}
	    3 {set test "operf check for callgraph output$dbg_test: $cmd"}
	}

        if {[lindex [local_exec $cmd "" "" 100] 0] == 0} {
            pass $test
        } else {
            fail $test
	}

	operf_check_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_workload_table($entry) $workload_exc $ctr_opts $test_debug_option
	}

	if {$output_check == 2} {
	    local_exec "sleep 1" "" "" 10
	    verify_kallsyms_output
	}

	if {$output_check == 3} {
	    # check callgraph output
	    local_exec "sleep 1" "" "" 10
	    verify_callgraph_output $op_workload_table($entry) $workload_exc $ctr_opts
	}

	operf_delete_samples
    }
}

proc do_system-wide_test {ctrs symbol_check} {
#   The tests are run in system-wide mode which requires the user to be
#   root.  System-wide mode is being used to make the operf interface
#   testing as functionally equivalent to the opcontrol interface testing
#   as possible.
#
#   The operf --system-wide command is started in system-wide mode in the
#   background.  Operf in system-wide mode runs until it received a kill
#   command.  The test script captures the parent process id printed by
#   operf.  After the workload has run, a script is called to kill the
#   operf data collection processes.

    global op_workload_table
    set kernel 1
    set user 1
    set ctr_opts {}

    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]
	set count [lindex $ctr 3]
	append ctr_opts "${event}:${count}:${um}:${kernel}:${user},"
    }

    foreach entry [array name op_workload_table] {
	set workload_src [lindex $op_workload_table($entry) 0]
	set compile_options [lindex $op_workload_table($entry) 1]
	set workload_exc [compile_workload $workload_src  $compile_options]

	if {$symbol_check == 1} {
	    set test "operf systemwide check for symbols: $workload_exc"
	} else {
	    set test "operf systemwide: $workload_exc"
	}

	# create the script to run operf command
	set filename "/tmp/operf_run.zzzz"
	set fileId [open $filename "w"]
	puts $fileId "#!/bin/bash"
	puts -nonewline $fileId "operf --system-wide --events "
	puts -nonewline $fileId $ctr_opts
	puts -nonewline $fileId " 2>&1  | tee > /tmp/operf_out.zzzz"
	close $fileId

	local_exec "chmod 755 /tmp/operf_run.zzzz" "" "" 10

	#  Start operf data collection in the background
	exec /tmp/operf_run.zzzz &

	# Create the script to stop the operf data collection.  Note this
	# must be done after operf starts and writes the kill command out to
	# operf_out.zzzz.
	set filename "/tmp/operf_create_stop.zzzz"
	set fileId [open $filename "w"]
	puts $fileId "#!/bin/bash"
	puts $fileId "echo -n  \"kill -s INT  \" > /tmp/operf_stop.zzzz "

	# Get the process id to kill
	puts $fileId "cat /tmp/operf_out.zzzz | grep \"kill\" | cut -d\"\'\" -f2 | cut -d\" \" -f3 >> /tmp/operf_stop.zzzz "
	close $fileId

	# check that operf started correctly
	if {[lindex [local_exec "grep \"usage\" /tmp/operf_out.zzzz " "" "" 100] 0] == 1} {
	    pass $test
	} else {
	    fail $test
	}

	# Run the script to create the operf stop script based on the
	# output of the operf command.
	local_exec "sleep 2" "" "" 10
	local_exec "chmod 755 /tmp/operf_create_stop.zzzz" "" "" 10
	exec /tmp/operf_create_stop.zzzz

	# Run the workload
	set result [local_exec "$workload_exc" "" "" 60]

	local_exec "chmod 755 /tmp/operf_stop.zzzz" "" "" 10
	exec /tmp/operf_stop.zzzz

	operf_check_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 {$symbol_check == 1} {
	    local_exec "sleep 2" "" "" 10
	    set test_debug_option 0
	    verify_output $op_workload_table($entry) $workload_exc $ctr_opts $test_debug_option
	}

	# cleanup the files created
	local_exec "rm -f /tmp/operf_out.zzzz" "" "" 10
	local_exec "rm -f /tmp/operf_stop.zzzz" "" "" 10
	local_exec "rm -f /tmp/operf_run.zzzz" "" "" 10
	local_exec "rm -f /tmp/operf_create_stop.zzzz" "" "" 10
	operf_delete_samples
    }
}