|  | #!/bin/sh | 
|  | # | 
|  | # opcontrol is a script to control OProfile | 
|  | # opcontrol --help and opcontrol --list-events have info | 
|  | # | 
|  | # Copyright 2002 | 
|  | # Read the file COPYING | 
|  | # | 
|  | # Authors: John Levon, Philippe Elie, Will Cohen, Jens Wilke, Daniel Hansel | 
|  | # | 
|  | # Copyright IBM Corporation 2007 | 
|  | # | 
|  | # NOTE: This script should be as shell independent as possible | 
|  |  | 
|  | SYSCTL=do_sysctl | 
|  |  | 
|  | # A replacement function for the sysctl (procps package) utility which is | 
|  | # missing on some distribution (e.g. slack 7.0). | 
|  | # Handles only the -w option of sysctl. | 
|  | do_sysctl() | 
|  | { | 
|  | if test "$1" != "-w"; then | 
|  | echo "$0 unknown sysctl option" >&2 | 
|  | exit 1 | 
|  | fi | 
|  |  | 
|  | shift | 
|  |  | 
|  | arg=`echo $1 | awk -F= '{print $1}'` | 
|  | val=`echo $1 | awk -F= '{print $2}'` | 
|  |  | 
|  | dev_name=`echo $arg | tr . /` | 
|  |  | 
|  | if test ! -f /proc/sys/$dev_name; then | 
|  | echo "/proc/sys/$dev_name does not exist or is not a regular file" >&2 | 
|  | exit 1 | 
|  | fi | 
|  | echo $val > /proc/sys/$dev_name | 
|  | } | 
|  |  | 
|  | # Helper function to check if oprofile daemon is active. | 
|  | # Takes one argument: the "lock file" for the oprofile daemon. | 
|  | # The lock file may exist even if the daemon was killed or died in | 
|  | # some way.  So we do a kill SIG_DFL to test whether the daemon is | 
|  | # truly alive. If the lock file is stale (daemon dead), the kill will | 
|  | # not return '0'. | 
|  | is_oprofiled_active() | 
|  | { | 
|  | [ -f "$1" ] && kill -0 `cat "$1"` 2>/dev/null | 
|  | } | 
|  |  | 
|  | # check value is set | 
|  | error_if_empty() | 
|  | { | 
|  | if test -z "$2"; then | 
|  | echo "No value given for option $1" >&2 | 
|  | do_help | 
|  | exit 1 | 
|  | fi | 
|  | } | 
|  |  | 
|  | # guess_number_base() checks if string is a valid octal(8), hexidecimal(16), | 
|  | # or decimal number(10). The value is returned in $?. Returns 0, if string | 
|  | # isn't a octal, hexidecimal, or decimal number. | 
|  | guess_number_base() | 
|  | { | 
|  | case "$1" in | 
|  | 0[Xx]*[!0-9a-fA-F]*)	return 0  ;; # Bad hex string | 
|  | 0[Xx][0-9a-fA-F]*)	return 16 ;; # Hex | 
|  | *[!0-9]*)		return 0  ;; # Some non-digit char | 
|  | [1-9]*)			return 10 ;; # Base 10 | 
|  | 0*[89]*)		return 0  ;; # Bad octal string | 
|  | 0*)			return 8  ;; # Octal | 
|  | esac | 
|  | return 0 | 
|  | } | 
|  |  | 
|  | # check value is a valid number | 
|  | error_if_not_number() | 
|  | { | 
|  | error_if_empty "$1" "$2" | 
|  | guess_number_base "$2" | 
|  | if test "$?" -eq 0 ; then | 
|  | echo "Argument for $1, $2, is not a valid number." >&2 | 
|  | exit 1 | 
|  | fi | 
|  | } | 
|  |  | 
|  | # check value is a base filename | 
|  | error_if_not_valid_savename() | 
|  | { | 
|  | error_if_empty "$1" "$2" | 
|  | bname=`basename "$2"` | 
|  | if test "$2" !=  "$bname"; then | 
|  | echo "Argument for $1, $2, cannot change directory." >&2 | 
|  | exit 1 | 
|  | fi | 
|  | case "$2" in | 
|  | # The following catches anything that is not | 
|  | # 0-9, a-z, A-Z, an '-', ':', ',', '.', or '/' | 
|  | *[!-[:alnum:]_:,./]*) | 
|  | echo "Argument for $1, $2, not allow to have special characters" >&2 | 
|  | exit 1;; | 
|  | esac | 
|  | } | 
|  |  | 
|  | error_if_invalid_arg() | 
|  | { | 
|  | error_if_empty "$1" "$2" | 
|  | case "$2" in | 
|  | # The following catches anything that is not | 
|  | # 0-9, a-z, A-Z, an '-', ':', ',', '.', or '/' | 
|  | *[!-[:alnum:]_:,./]*) | 
|  | echo "Argument for $1, $2, is not valid argument." >&2 | 
|  | exit 1;; | 
|  | esac | 
|  | } | 
|  |  | 
|  | # rm_device arguments $1=file_name | 
|  | rm_device() | 
|  | { | 
|  | if test -c "$1"; then | 
|  | vecho "Removing $1" | 
|  | rm "$1" | 
|  | fi | 
|  | } | 
|  |  | 
|  |  | 
|  | # create_device arguments $1=file_name $2=MAJOR_NR $3=MINOR_NR | 
|  | create_device() | 
|  | { | 
|  | vecho "Doing mknod $1" | 
|  | mknod "$1" c $2 $3 | 
|  | if test "$?" != "0"; then | 
|  | echo "Couldn't mknod $1" >&2 | 
|  | exit 1 | 
|  | fi | 
|  | chmod 700 "$1" | 
|  | } | 
|  |  | 
|  |  | 
|  | move_and_remove() | 
|  | { | 
|  | if test -e $1; then | 
|  | mv $1 $SAMPLES_DIR/.tmp_reset.$$ | 
|  | rm -rf $SAMPLES_DIR/.tmp_reset.$$ | 
|  | fi | 
|  | } | 
|  |  | 
|  |  | 
|  | # verbose echo | 
|  | vecho() | 
|  | { | 
|  | if test -n "$VERBOSE"; then | 
|  | echo $@ | 
|  | fi | 
|  | } | 
|  |  | 
|  |  | 
|  | is_tool_available() | 
|  | { | 
|  | if which $1 > /dev/null 2>&1; then | 
|  | if test -x `which $1`; then | 
|  | return 1 | 
|  | fi | 
|  | fi | 
|  |  | 
|  | return 0 | 
|  | } | 
|  |  | 
|  |  | 
|  | # print help message | 
|  | do_help() | 
|  | { | 
|  | cat >&2 <<EOF | 
|  | opcontrol: usage: | 
|  | -l/--list-events list event types and unit masks | 
|  | -?/--help        this message | 
|  | -v/--version     show version | 
|  | --init           loads the oprofile module and oprofilefs | 
|  | --setup          give setup arguments (may be omitted) | 
|  | --status         show configuration | 
|  | --start-daemon   start daemon without starting profiling | 
|  | -s/--start       start data collection | 
|  | -d/--dump        flush the collected profiling data | 
|  | -t/--stop        stop data collection | 
|  | -h/--shutdown    stop data collection and kill daemon | 
|  | -V/--verbose[=all,sfile,arcs,samples,module,misc,ext] | 
|  | be verbose in the daemon log | 
|  | --reset          clears out data from current session | 
|  | --save=name      save data from current session to session_name | 
|  | --deinit         unload the oprofile module and oprofilefs | 
|  |  | 
|  | -e/--event=eventspec | 
|  |  | 
|  | Choose an event. May be specified multiple times. Of the form | 
|  | "default" or "name:count:unitmask:kernel:user", where : | 
|  |  | 
|  | name:     event name, e.g. CPU_CLK_UNHALTED or RTC_INTERRUPTS | 
|  | count:    reset counter value e.g. 100000 | 
|  | unitmask: hardware unit mask e.g. 0x0f | 
|  | kernel:   whether to profile kernel: 0 or 1 | 
|  | user:     whether to profile userspace: 0 or 1 | 
|  |  | 
|  | -p/--separate=type,[types] | 
|  |  | 
|  | Separate profiles as follows : | 
|  |  | 
|  | none:     no profile separation | 
|  | library:  separate shared library profiles per-application | 
|  | kernel:   same as library, plus kernel profiles | 
|  | thread:   per-thread/process profiles | 
|  | cpu:      per CPU profiles | 
|  | all:      all of the above | 
|  |  | 
|  | -c/--callgraph=#depth         enable callgraph sample collection with a | 
|  | maximum depth. Use '0' to disable callgraph | 
|  | profiling. | 
|  | --session-dir=dir             place sample database in dir instead of | 
|  | default location (/var/lib/oprofile) | 
|  | -i/--image=name[,names]       list of binaries to profile (default is "all") | 
|  | --vmlinux=file                vmlinux kernel image | 
|  | --no-vmlinux                  no kernel image (vmlinux) available | 
|  | --kernel-range=start,end      kernel range vma address in hexadecimal | 
|  | --buffer-size=num             kernel buffer size in sample units. | 
|  | Rules: A non-zero value goes into effect after | 
|  | a '--shutdown/start' sequence.  A value of | 
|  | zero sets this parameter back to default value | 
|  | but does not go into effect until after a | 
|  | '--deinit/init' sequence. | 
|  | --buffer-watershed            kernel buffer watershed in sample units (2.6 | 
|  | kernel). Same rules as defined for | 
|  | buffer-size. | 
|  | --cpu-buffer-size=num         per-cpu buffer size in units (2.6 kernel) | 
|  | Same rules as defined for buffer-size. | 
|  | --xen                         Xen image (for Xen only) | 
|  | --active-domains=<list>       List of domains in profiling session (for Xen) | 
|  | (list contains domain ids separated by commas) | 
|  |  | 
|  | System z specific options | 
|  |  | 
|  | --s390hwsampbufsize=num        Number of 2MB areas used per CPU for storing sample data. | 
|  | EOF | 
|  | } | 
|  |  | 
|  |  | 
|  | # load the module and mount oprofilefs | 
|  | load_module_26() | 
|  | { | 
|  | grep oprofilefs /proc/filesystems >/dev/null | 
|  | if test "$?" -ne 0; then | 
|  | modprobe oprofile | 
|  | if test "$?" != "0"; then | 
|  | # couldn't load the module | 
|  | return | 
|  | fi | 
|  | grep oprofile /proc/modules >/dev/null | 
|  | if test "$?" != "0"; then | 
|  | # didn't find module | 
|  | return | 
|  | fi | 
|  | grep oprofilefs /proc/filesystems >/dev/null | 
|  | if test "$?" -ne 0; then | 
|  | # filesystem still not around | 
|  | return | 
|  | fi | 
|  | fi | 
|  | mkdir /dev/oprofile >/dev/null 2>&1 | 
|  | grep oprofilefs /proc/mounts >/dev/null | 
|  | if test "$?" -ne 0; then | 
|  | mount -t oprofilefs nodev /dev/oprofile >/dev/null | 
|  | fi | 
|  | KERNEL_SUPPORT=yes | 
|  | OPROFILE_AVAILABLE=yes | 
|  | } | 
|  |  | 
|  |  | 
|  |  | 
|  | load_module() | 
|  | { | 
|  | OPROFILE_AVAILABLE=no | 
|  | load_module_26 | 
|  | if test "$OPROFILE_AVAILABLE" != "yes"; then | 
|  | echo "Kernel doesn't support oprofile" >&2 | 
|  | exit 1 | 
|  | fi | 
|  | } | 
|  |  | 
|  | # setup variables related to path or daemon. Set vars according to following | 
|  | # relationship: command-line-option > config-file-settings > defaults. | 
|  | # Note that upon entry SESSION_DIR may be set by command-line option. | 
|  | do_init_daemon_vars() | 
|  | { | 
|  | # load settings from config file, keeping command-line value | 
|  | # of SESSION_DIR if necessary. | 
|  | if test -n "$SESSION_DIR"; then | 
|  | SAVED=$SESSION_DIR | 
|  | fi | 
|  | do_load_setup | 
|  | if test -n "$SAVED"; then | 
|  | SESSION_DIR=$SAVED | 
|  | fi | 
|  |  | 
|  | # daemon parameters (as in op_config.h).  Note that we preserve | 
|  | # any previous value of SESSION_DIR | 
|  | if test -z "$SESSION_DIR"; then | 
|  | SESSION_DIR="/var/lib/oprofile" | 
|  | fi | 
|  | LOCK_FILE="$SESSION_DIR/lock" | 
|  | SAMPLES_DIR="$SESSION_DIR/samples" | 
|  | LOG_FILE="$SAMPLES_DIR/oprofiled.log" | 
|  | CURRENT_SAMPLES_DIR="$SAMPLES_DIR/current" | 
|  | } | 
|  |  | 
|  |  | 
|  | # pick the appropriate device mount based on kernel | 
|  | decide_oprofile_device_mount() | 
|  | { | 
|  | if test "$KERNEL_SUPPORT" = "yes"; then | 
|  | MOUNT="/dev/oprofile" | 
|  | else | 
|  | MOUNT="/proc/sys/dev/oprofile" | 
|  | fi | 
|  | } | 
|  |  | 
|  |  | 
|  | # pick the appropriate locations device for oprofile based on kernel | 
|  | decide_oprofile_device() | 
|  | { | 
|  | if test "$KERNEL_SUPPORT" = "yes"; then | 
|  | DEVICE_FILE="$MOUNT/buffer" | 
|  | else | 
|  | DEVICE_FILE="$SESSION_DIR/opdev" | 
|  | NOTE_DEVICE_FILE="$SESSION_DIR/opnotedev" | 
|  | HASH_MAP_DEVICE_FILE="$SESSION_DIR/ophashmapdev" | 
|  | fi | 
|  | } | 
|  |  | 
|  | # initialise parameters | 
|  | do_init() | 
|  | { | 
|  | # for these three buffer size == 0 means use the default value | 
|  | # hard-coded in op_user.h | 
|  | BUF_SIZE=0 | 
|  | BUF_WATERSHED=0 | 
|  | CPU_BUF_SIZE=0 | 
|  | NOTE_SIZE=0 | 
|  | VMLINUX= | 
|  | XENIMAGE="none" | 
|  | VERBOSE="" | 
|  | SEPARATE_LIB=0 | 
|  | SEPARATE_KERNEL=0 | 
|  | SEPARATE_THREAD=0 | 
|  | SEPARATE_CPU=0 | 
|  | CALLGRAPH=0 | 
|  | IBS_FETCH_EVENTS="" | 
|  | IBS_FETCH_COUNT=0 | 
|  | IBS_FETCH_UNITMASK=0 | 
|  | IBS_OP_EVENTS="" | 
|  | IBS_OP_COUNT=0 | 
|  | IBS_OP_UNITMASK=0 | 
|  |  | 
|  | # System z specific values | 
|  | S390_HW_SAMPLER=0 | 
|  | S390_HW_SAMPLER_BUFSIZE=0 | 
|  |  | 
|  | OPROFILED="$OPDIR/oprofiled" | 
|  |  | 
|  | # location for daemon setup information | 
|  | SETUP_DIR="/root/.oprofile" | 
|  | SETUP_FILE="$SETUP_DIR/daemonrc" | 
|  | SEC_SETUP_FILE="$SETUP_DIR/daemonrc_new" | 
|  |  | 
|  | # initialize daemon vars | 
|  | decide_oprofile_device_mount | 
|  | CPUTYPE=`cat $MOUNT/cpu_type` | 
|  | OP_COUNTERS=`ls $MOUNT/ | grep "^[0-9]\+\$" | tr "\n" " "` | 
|  | OP_COUNTERS="$OP_COUNTERS `ls $MOUNT/ | grep "^timer\+\$"`" | 
|  | NR_CHOSEN=0 | 
|  |  | 
|  | do_init_daemon_vars | 
|  | decide_oprofile_device | 
|  |  | 
|  | DEFAULT_EVENT=`$OPHELP --get-default-event` | 
|  |  | 
|  | IS_TIMER=0 | 
|  | IS_PERFMON=0 | 
|  | if test "$CPUTYPE" = "timer"; then | 
|  | IS_TIMER=1 | 
|  | else | 
|  | case "$CPUTYPE" in | 
|  | s390/*) | 
|  | S390_HW_SAMPLER=1 | 
|  | ;; | 
|  | ia64/*) | 
|  | IS_PERFMON=$KERNEL_SUPPORT | 
|  | ;; | 
|  | ppc64/power8) | 
|  | echo "*** IBM POWER 8 processor is not supported with opcontrol.  Please use operf instead. ***" | 
|  | do_deinit | 
|  | exit 1 | 
|  | ;; | 
|  | esac | 
|  | fi | 
|  |  | 
|  | # Ignore configured events when running in timer mode. | 
|  | if test "$IS_TIMER" = 1; then | 
|  | NR_CHOSEN=0 | 
|  | fi | 
|  | } | 
|  |  | 
|  |  | 
|  | create_dir() | 
|  | { | 
|  | if test ! -d "$1"; then | 
|  | mkdir -p "$1" | 
|  | if test "$?" != "0"; then | 
|  | echo "Couldn't mkdir -p $1" >&2 | 
|  | exit 1 | 
|  | fi | 
|  | chmod 755 "$1" | 
|  | fi | 
|  | } | 
|  |  | 
|  | get_event() | 
|  | { | 
|  | GOTEVENT=`eval "echo \\$CHOSEN_EVENTS_$1"` | 
|  | } | 
|  |  | 
|  | set_event() | 
|  | { | 
|  | eval "CHOSEN_EVENTS_$1=$2" | 
|  | } | 
|  |  | 
|  |  | 
|  | # save all the setup related information | 
|  | do_save_setup() | 
|  | { | 
|  | create_dir "$SETUP_DIR" | 
|  | SAVE_SETUP_FILE="$SETUP_FILE" | 
|  |  | 
|  | # If the daemon is currently running, we want changes to the daemon config | 
|  | # stored in the secondary cache file so that 'opcontrol --status' will | 
|  | # show actual config data for the running daemon.  The next time the | 
|  | # daemon is restarted, we'll reload the config data from this secondary | 
|  | # cache file. | 
|  |  | 
|  | if is_oprofiled_active "$LOCK_FILE"; then | 
|  | SETUP_FILE="$SEC_SETUP_FILE" | 
|  | echo "The profiling daemon is currently active, so changes to the configuration" | 
|  | echo "will be used the next time you restart oprofile after a --shutdown or --deinit." | 
|  | fi | 
|  |  | 
|  | touch $SETUP_FILE | 
|  | chmod 644 $SETUP_FILE | 
|  | >$SETUP_FILE | 
|  |  | 
|  | echo "SESSION_DIR=$SESSION_DIR" >>$SETUP_FILE | 
|  |  | 
|  | if test "$NR_CHOSEN" != "0"; then | 
|  | for f in `seq 0 $((NR_CHOSEN - 1))`; do | 
|  | get_event $f | 
|  | echo "CHOSEN_EVENTS_${f}=$GOTEVENT" >>$SETUP_FILE | 
|  | done | 
|  | fi | 
|  |  | 
|  | echo "NR_CHOSEN=$NR_CHOSEN" >>$SETUP_FILE | 
|  |  | 
|  | echo "SEPARATE_LIB=$SEPARATE_LIB" >> $SETUP_FILE | 
|  | echo "SEPARATE_KERNEL=$SEPARATE_KERNEL" >> $SETUP_FILE | 
|  | echo "SEPARATE_THREAD=$SEPARATE_THREAD" >> $SETUP_FILE | 
|  | echo "SEPARATE_CPU=$SEPARATE_CPU" >> $SETUP_FILE | 
|  | echo "VMLINUX=$VMLINUX" >> $SETUP_FILE | 
|  | echo "IMAGE_FILTER=$IMAGE_FILTER" >> $SETUP_FILE | 
|  | # write the actual information to file | 
|  | if test "$BUF_SIZE" != "0"; then | 
|  | echo "BUF_SIZE=$BUF_SIZE" >> $SETUP_FILE | 
|  | fi | 
|  | if test "$BUF_WATERSHED" != "0"; then | 
|  | echo "BUF_WATERSHED=$BUF_WATERSHED" >> $SETUP_FILE | 
|  | fi | 
|  | if test "$KERNEL_SUPPORT" = "yes"; then | 
|  | echo "CPU_BUF_SIZE=$CPU_BUF_SIZE" >> $SETUP_FILE | 
|  | fi | 
|  | if test "$KERNEL_SUPPORT" != "yes"; then | 
|  | echo "NOTE_SIZE=$NOTE_SIZE" >> $SETUP_FILE | 
|  | fi | 
|  | echo "CALLGRAPH=$CALLGRAPH" >> $SETUP_FILE | 
|  | if test "$KERNEL_RANGE"; then | 
|  | echo "KERNEL_RANGE=$KERNEL_RANGE" >> $SETUP_FILE | 
|  | fi | 
|  | echo "XENIMAGE=$XENIMAGE" >> $SETUP_FILE | 
|  | if test "$XEN_RANGE"; then | 
|  | echo "XEN_RANGE=$XEN_RANGE" >> $SETUP_FILE | 
|  | fi | 
|  | if test "$S390_HW_SAMPLER" = "1" -a "$S390_HW_SAMPLER_BUFSIZE" != "0"; then | 
|  | echo "S390_HW_SAMPLER_BUFSIZE=$S390_HW_SAMPLER_BUFSIZE" >> $SETUP_FILE | 
|  | fi | 
|  | SETUP_FILE="$SAVE_SETUP_FILE" | 
|  | } | 
|  |  | 
|  |  | 
|  | # reload all the setup-related information | 
|  | do_load_setup() | 
|  | { | 
|  | # If a secondary setup file exists and the daemon is not running, | 
|  | # then we'll move the data from the secondary file to the actual | 
|  | # setup file to prepare for daemon startup. | 
|  | if test -z "$SESSION_DIR"; then | 
|  | __TMP_SESSION_DIR="/var/lib/oprofile" | 
|  | else | 
|  | __TMP_SESSION_DIR="$SESSION_DIR" | 
|  | fi | 
|  |  | 
|  | if test -f "$SEC_SETUP_FILE"; then | 
|  | is_oprofiled_active "$__TMP_SESSION_DIR/lock" \ | 
|  | || mv "$SEC_SETUP_FILE" "$SETUP_FILE" | 
|  | fi | 
|  |  | 
|  | if test ! -f "$SETUP_FILE"; then return; fi | 
|  |  | 
|  | while IFS== read -r arg val; do | 
|  | case "$arg" in | 
|  | # The following catches anything that is not | 
|  | # 0-9, a-z, A-Z, or an '_' | 
|  | *[![:alnum:]_]*) | 
|  | echo "Invalid variable \"$arg\" in $SETUP_FILE." | 
|  | exit 1;; | 
|  | esac | 
|  | case "$val" in | 
|  | # The following catches anything that is not | 
|  | # 0-9, a-z, A-Z, an '-', ':', ',', '.', or '/' | 
|  | *[!-[:alnum:]_:,./]*) | 
|  | echo "Invalid value \"$val\" for $arg in $SETUP_FILE." | 
|  | exit 1;; | 
|  | esac | 
|  | eval "${arg}=${val}" | 
|  | done < $SETUP_FILE | 
|  | } | 
|  |  | 
|  |  | 
|  | check_valid_args() | 
|  | { | 
|  | if test -z "$VMLINUX"; then | 
|  | echo "No vmlinux file specified. You must specify the correct vmlinux file, e.g." >&2 | 
|  | echo "opcontrol --vmlinux=/path/to/vmlinux" >&2 | 
|  | echo "If you do not have a vmlinux file, use " >&2 | 
|  | echo "opcontrol --no-vmlinux" >&2 | 
|  | echo "Enter opcontrol --help for full options" >&2 | 
|  | exit 1 | 
|  | fi | 
|  |  | 
|  | if test -f "$VMLINUX"; then | 
|  | return | 
|  | fi | 
|  |  | 
|  | if test "$VMLINUX" = "none"; then | 
|  | return | 
|  | fi | 
|  |  | 
|  | echo "The specified vmlinux file \"$VMLINUX\" doesn't exist." >&2 | 
|  | exit 1 | 
|  |  | 
|  | # similar check for Xen image | 
|  | if test -f "$XENIMAGE"; then | 
|  | return | 
|  | fi | 
|  |  | 
|  | if test "$XENIMAGE" = "none"; then | 
|  | return | 
|  | fi | 
|  |  | 
|  | echo "The specified XenImage file \"$XENIMAGE\" does not exist." >&2 | 
|  | exit 1 | 
|  | } | 
|  |  | 
|  |  | 
|  | # get start and end points of a file image (linux kernel or xen) | 
|  | # get_image_range parameter: $1=type_of_image (linux or xen) | 
|  | get_image_range() | 
|  | { | 
|  | if test "$1" = "xen"; then | 
|  | if test ! -z "$XEN_RANGE"; then | 
|  | return; | 
|  | fi | 
|  | FILE_IMAGE="$XENIMAGE" | 
|  | else | 
|  | if test ! -z "$KERNEL_RANGE"; then | 
|  | return; | 
|  | fi | 
|  | FILE_IMAGE="$VMLINUX" | 
|  | fi | 
|  |  | 
|  | if test "$FILE_IMAGE" = "none"; then | 
|  | return; | 
|  | fi | 
|  |  | 
|  | if is_tool_available objdump; then | 
|  | echo "objdump is not installed on this system, use opcontrol --kernel-range=start,end or opcontrol --xen-range= or install objdump" | 
|  | exit 1 | 
|  | fi | 
|  |  | 
|  | # start at the start of .text, and end at _etext | 
|  | range_info=`objdump -h $FILE_IMAGE 2>/dev/null | grep " .text "` | 
|  | tmp1=`echo $range_info | awk '{print $4}'` | 
|  | tmp2=`objdump -t $FILE_IMAGE 2>/dev/null | grep "_etext$" | awk '{ print $1 }'` | 
|  |  | 
|  | if test -z "$tmp1" -o -z "$tmp2"; then | 
|  | echo "The specified file $FILE_IMAGE does not seem to be valid" >&2 | 
|  | echo "Make sure you are using the non-compressed image file (e.g. vmlinux not vmlinuz)" >&2 | 
|  | vecho "found start as \"$tmp1\", end as \"$tmp2\"" >&2 | 
|  | exit 1 | 
|  | fi | 
|  |  | 
|  | if test "$1" = "xen"; then | 
|  | XEN_RANGE="`echo $tmp1`,`echo $tmp2`" | 
|  | vecho "XEN_RANGE $XEN_RANGE" | 
|  | else | 
|  | KERNEL_RANGE="`echo $tmp1`,`echo $tmp2`" | 
|  | vecho "KERNEL_RANGE $KERNEL_RANGE" | 
|  | fi | 
|  | } | 
|  |  | 
|  |  | 
|  | # validate --separate= parameters. This function is called with IFS=, | 
|  | # so on each argument is splitted | 
|  | validate_separate_args() | 
|  | { | 
|  | error_if_empty $1 $2	# we need at least one argument | 
|  | local i=1 | 
|  | SEPARATE_LIB=0 | 
|  | SEPARATE_KERNEL=0 | 
|  | SEPARATE_THREAD=0 | 
|  | SEPARATE_CPU=0 | 
|  | while [ "$i" -lt "$#" ]; do | 
|  | shift | 
|  | case "$1" in | 
|  | lib|library) | 
|  | SEPARATE_LIB=1 | 
|  | ;; | 
|  | kernel) | 
|  | # first implied by second | 
|  | SEPARATE_LIB=1 | 
|  | SEPARATE_KERNEL=1 | 
|  | ;; | 
|  | thread) | 
|  | SEPARATE_THREAD=1 | 
|  | ;; | 
|  | cpu) | 
|  | SEPARATE_CPU=1 | 
|  | ;; | 
|  | all) | 
|  | SEPARATE_LIB=1 | 
|  | SEPARATE_KERNEL=1 | 
|  | SEPARATE_THREAD=1 | 
|  | SEPARATE_CPU=1 | 
|  | ;; | 
|  | none) | 
|  | SEPARATE_LIB=0 | 
|  | SEPARATE_KERNEL=0 | 
|  | SEPARATE_THREAD=0 | 
|  | SEPARATE_CPU=0 | 
|  | ;; | 
|  | *) | 
|  | echo "invalid --separate= argument: $1" | 
|  | exit 1 | 
|  | esac | 
|  | done | 
|  | } | 
|  |  | 
|  |  | 
|  | # check the counters make sense, and resolve the hardware allocation | 
|  | verify_counters() | 
|  | { | 
|  | if test "$IS_TIMER" = 1; then | 
|  | if test "$NR_CHOSEN" != 0; then | 
|  | echo "You cannot specify any performance counter events" >&2 | 
|  | echo "because OProfile is in timer mode." >&2 | 
|  | exit 1 | 
|  | fi | 
|  | return | 
|  | fi | 
|  |  | 
|  | OPHELP_ARGS= | 
|  |  | 
|  | if test "$NR_CHOSEN" != 0; then | 
|  | for f in `seq 0 $((NR_CHOSEN - 1))`; do | 
|  | get_event $f | 
|  | if test "$GOTEVENT" != ""; then | 
|  | verify_ibs $GOTEVENT | 
|  | OPHELP_ARGS="$OPHELP_ARGS $GOTEVENT" | 
|  | fi | 
|  | done | 
|  |  | 
|  | if test ! -z "$OPHELP_ARGS" ; then | 
|  | HW_CTRS=`$OPHELP --check-events $OPHELP_ARGS --callgraph=$CALLGRAPH` | 
|  | if test "$?" != 0; then | 
|  | exit 1 | 
|  | fi | 
|  | fi | 
|  | fi | 
|  | } | 
|  |  | 
|  |  | 
|  | # setup any needed default value in chosen events | 
|  | normalise_events() | 
|  | { | 
|  | if test "$NR_CHOSEN" -le 0 || test "$IS_TIMER" = 1; then | 
|  | return | 
|  | fi | 
|  |  | 
|  | for f in `seq 0 $((NR_CHOSEN - 1))`; do | 
|  | get_event $f | 
|  | if test "$GOTEVENT" != ""; then | 
|  | EVENT=`echo $GOTEVENT | awk -F: '{print $1}'` | 
|  | EVENT_VAL=`$OPHELP $EVENT` | 
|  | if test "$?" != 0; then | 
|  | exit 1 | 
|  | fi | 
|  | COUNT=`echo $GOTEVENT | awk -F: '{print $2}'` | 
|  | UNIT_MASK=`echo $GOTEVENT | awk -F: '{print $3}'` | 
|  | KERNEL=`echo $GOTEVENT | awk -F: '{print $4}'` | 
|  | USER=`echo $GOTEVENT | awk -F: '{print $5}'` | 
|  | TMPEVENT="$EVENT:$COUNT:$UNIT_MASK" | 
|  | UNIT_MASK=`$OPHELP --unit-mask $TMPEVENT` | 
|  | UNIT_MASK_NAMED="$UNIT_MASK" | 
|  | if test "$?" != 0; then | 
|  | exit 1 | 
|  | fi | 
|  | if test -z "$KERNEL"; then | 
|  | KERNEL=1 | 
|  | fi | 
|  | if test -z "$USER"; then | 
|  | USER=1 | 
|  | fi | 
|  |  | 
|  | set_event $f "$EVENT:$COUNT:$UNIT_MASK:$KERNEL:$USER" | 
|  | fi | 
|  | done | 
|  | } | 
|  |  | 
|  |  | 
|  | # get and check specified options | 
|  | do_options() | 
|  | { | 
|  | EXCLUSIVE_ARGC=0 | 
|  | SETUP=no | 
|  | NEED_SETUP=no | 
|  | SEEN_EVENT=0 | 
|  |  | 
|  | # note: default settings have already been loaded | 
|  |  | 
|  | while [ "$#" -ne 0 ] | 
|  | do | 
|  | arg=`printf %s $1 | awk -F= '{print $1}'` | 
|  | val=`printf %s $1 | awk -F= '{print $2}'` | 
|  | shift | 
|  | if test -z "$val"; then | 
|  | local possibleval=$1 | 
|  | printf %s $1 "$possibleval" | grep ^- >/dev/null 2>&1 | 
|  | if test "$?" != "0"; then | 
|  | val=$possibleval | 
|  | if [ "$#" -ge 1 ]; then | 
|  | shift | 
|  | fi | 
|  | fi | 
|  | fi | 
|  |  | 
|  | case "$arg" in | 
|  |  | 
|  | --init) | 
|  | # this is already done in load_module | 
|  | # because need to know the processor type | 
|  | # and number of registers | 
|  | INIT=yes; | 
|  | EXCLUSIVE_ARGC=`expr $EXCLUSIVE_ARGC + 1` | 
|  | EXCLUSIVE_ARGV="$arg" | 
|  | ;; | 
|  |  | 
|  | --setup) | 
|  | SETUP=yes | 
|  | ;; | 
|  |  | 
|  | --start-daemon) | 
|  | if test "$KERNEL_SUPPORT" != "yes"; then | 
|  | echo "$arg unsupported. use \"--start\"" >&2 | 
|  | exit 1 | 
|  | fi | 
|  | START_DAEMON=yes | 
|  | EXCLUSIVE_ARGC=`expr $EXCLUSIVE_ARGC + 1` | 
|  | EXCLUSIVE_ARGV="$arg" | 
|  | ;; | 
|  |  | 
|  | -s|--start) | 
|  | START=yes | 
|  | EXCLUSIVE_ARGC=`expr $EXCLUSIVE_ARGC + 1` | 
|  | EXCLUSIVE_ARGV="$arg" | 
|  | ;; | 
|  |  | 
|  | -d|--dump) | 
|  | DUMP=yes | 
|  | ONLY_DUMP=yes | 
|  | EXCLUSIVE_ARGC=`expr $EXCLUSIVE_ARGC + 1` | 
|  | EXCLUSIVE_ARGV="$arg" | 
|  | ;; | 
|  |  | 
|  | -t|--stop) | 
|  | if test "$KERNEL_SUPPORT" != "yes"; then | 
|  | echo "$arg unsupported. use \"--shutdown\"" >&2 | 
|  | exit 1 | 
|  | fi | 
|  | DUMP=yes | 
|  | STOP=yes | 
|  | EXCLUSIVE_ARGC=`expr $EXCLUSIVE_ARGC + 1` | 
|  | EXCLUSIVE_ARGV="$arg" | 
|  | ;; | 
|  |  | 
|  | -h|--shutdown) | 
|  | DUMP=yes | 
|  | STOP=yes | 
|  | KILL_DAEMON=yes | 
|  | EXCLUSIVE_ARGC=`expr $EXCLUSIVE_ARGC + 1` | 
|  | EXCLUSIVE_ARGV="$arg" | 
|  | ;; | 
|  |  | 
|  | --status) | 
|  | STATUS=yes | 
|  | ;; | 
|  |  | 
|  | --reset) | 
|  | DUMP=yes | 
|  | RESET=yes | 
|  | EXCLUSIVE_ARGC=`expr $EXCLUSIVE_ARGC + 1` | 
|  | EXCLUSIVE_ARGV="$arg" | 
|  | ;; | 
|  |  | 
|  | --save) | 
|  | error_if_not_valid_savename "$arg" "$val" | 
|  | DUMP=yes | 
|  | SAVE_SESSION=yes | 
|  | SAVE_NAME=$val | 
|  | EXCLUSIVE_ARGC=`expr $EXCLUSIVE_ARGC + 1` | 
|  | EXCLUSIVE_ARGV="$arg" | 
|  | ;; | 
|  |  | 
|  | --deinit) | 
|  | DUMP=yes | 
|  | test ! -f "$LOCK_FILE" || { | 
|  | STOP=yes | 
|  | KILL_DAEMON=yes | 
|  | } | 
|  | DEINIT=yes | 
|  | EXCLUSIVE_ARGC=`expr $EXCLUSIVE_ARGC + 1` | 
|  | EXCLUSIVE_ARGV="$arg" | 
|  | ;; | 
|  |  | 
|  | # --setup options | 
|  |  | 
|  | --session-dir) | 
|  | # already processed | 
|  | ;; | 
|  | --buffer-size) | 
|  | error_if_not_number "$arg" "$val" | 
|  | BUF_SIZE=$val | 
|  | DO_SETUP=yes | 
|  | ;; | 
|  | --buffer-watershed) | 
|  | if test "$KERNEL_SUPPORT" != "yes"; then | 
|  | echo "$arg unsupported for this kernel version" | 
|  | exit 1 | 
|  | fi | 
|  | error_if_not_number "$arg" "$val" | 
|  | BUF_WATERSHED=$val | 
|  | DO_SETUP=yes | 
|  | ;; | 
|  | --cpu-buffer-size) | 
|  | if test "$KERNEL_SUPPORT" != "yes"; then | 
|  | echo "$arg unsupported for this kernel version" | 
|  | exit 1 | 
|  | fi | 
|  | error_if_not_number "$arg" "$val" | 
|  | CPU_BUF_SIZE=$val | 
|  | DO_SETUP=yes | 
|  | ;; | 
|  | -e|--event) | 
|  | error_if_invalid_arg "$arg" "$val" | 
|  | # reset any read-in defaults from daemonrc | 
|  | if test "$SEEN_EVENT" = "0"; then | 
|  | NR_CHOSEN=0 | 
|  | SEEN_EVENT=1 | 
|  | fi | 
|  | if test "$val" = "default"; then | 
|  | val=$DEFAULT_EVENT | 
|  | fi | 
|  | set_event $NR_CHOSEN "$val" | 
|  | NR_CHOSEN=`expr $NR_CHOSEN + 1` | 
|  | DO_SETUP=yes | 
|  | ;; | 
|  | -p|--separate) | 
|  | OLD_IFS=$IFS | 
|  | IFS=, | 
|  | validate_separate_args $arg $val | 
|  | IFS=$OLD_IFS | 
|  | DO_SETUP=yes | 
|  | ;; | 
|  | -c|--callgraph) | 
|  | if test ! -f $MOUNT/backtrace_depth; then | 
|  | echo "Call-graph profiling unsupported on this kernel/hardware" >&2 | 
|  | exit 1 | 
|  | fi | 
|  | error_if_not_number "$arg" "$val" | 
|  | CALLGRAPH=$val | 
|  | DO_SETUP=yes | 
|  | ;; | 
|  | --vmlinux) | 
|  | error_if_invalid_arg "$arg" "$val" | 
|  | VMLINUX=$val | 
|  | DO_SETUP=yes | 
|  | ;; | 
|  | --no-vmlinux) | 
|  | VMLINUX=none | 
|  | DO_SETUP=yes | 
|  | ;; | 
|  | --kernel-range) | 
|  | error_if_invalid_arg "$arg" "$val" | 
|  | KERNEL_RANGE=$val | 
|  | DO_SETUP=yes | 
|  | ;; | 
|  | --xen) | 
|  | error_if_invalid_arg "$arg" "$val" | 
|  | XENIMAGE=$val | 
|  | DO_SETUP=yes | 
|  | ;; | 
|  | --active-domains) | 
|  | error_if_invalid_arg $arg $val | 
|  | ACTIVE_DOMAINS=$val | 
|  | DO_SETUP=yes | 
|  | ;; | 
|  | -i|--image) | 
|  | error_if_invalid_arg "$arg" "$val" | 
|  | if test "$val" = "all"; then | 
|  | IMAGE_FILTER= | 
|  | else | 
|  | IMAGE_FILTER=$val | 
|  | fi | 
|  | DO_SETUP=yes | 
|  | ;; | 
|  |  | 
|  | -V|--verbose) | 
|  | if test -z "$val"; then | 
|  | VERBOSE="all" | 
|  | else | 
|  | error_if_invalid_arg "$arg" "$val" | 
|  | VERBOSE=$val | 
|  | fi | 
|  | ;; | 
|  |  | 
|  | -l|--list-events) | 
|  | EXCLUSIVE_ARGC=`expr $EXCLUSIVE_ARGC + 1` | 
|  | EXCLUSIVE_ARGV="$arg" | 
|  | exec $OPHELP | 
|  | ;; | 
|  |  | 
|  | --s390hwsampbufsize) | 
|  | error_if_not_number "$arg" "$val" | 
|  | S390_HW_SAMPLER_BUFSIZE=$val | 
|  | DO_SETUP=yes | 
|  | ;; | 
|  |  | 
|  |  | 
|  | *) | 
|  | echo "Unknown option \"$arg\". See opcontrol --help" >&2 | 
|  | exit 1 | 
|  | ;; | 
|  | esac | 
|  | done | 
|  |  | 
|  | normalise_events | 
|  | verify_counters | 
|  |  | 
|  | # error checking to make sure options make sense | 
|  | if test "$EXCLUSIVE_ARGC" -gt 1; then | 
|  | echo "Option \"$EXCLUSIVE_ARGV\" not valid with other options." >&2 | 
|  | exit 1 | 
|  | fi | 
|  |  | 
|  | if test "$SETUP" = "yes" -a "$DO_SETUP" != "yes"; then | 
|  | echo "No options specified for --setup." >&2 | 
|  | exit 1 | 
|  | fi | 
|  |  | 
|  | if test -n "$VERBOSE"; then | 
|  | if test "$START" != "yes" -a "$START_DAEMON" != "yes"; then | 
|  | echo "Option --verbose may only be used with --start or --start-daemon" >&2 | 
|  | exit 1 | 
|  | fi | 
|  | fi | 
|  |  | 
|  | if test "$DO_SETUP" = "yes"; then | 
|  | SETUP="$DO_SETUP" | 
|  | fi | 
|  |  | 
|  | if test "$EXCLUSIVE_ARGC" -eq 1 -a "$SETUP" = "yes"; then | 
|  | if test "$EXCLUSIVE_ARGV" != "--start-daemon" -a "$EXCLUSIVE_ARGV" != "--start"; then | 
|  | echo "Option \"--setup\" not valid with \"$EXCLUSIVE_ARGV\"." >&2 | 
|  | exit 1 | 
|  | fi | 
|  | fi | 
|  |  | 
|  | vecho "Parameters used:" | 
|  | vecho "SESSION_DIR $SESSION_DIR" | 
|  | vecho "LOCK_FILE   $LOCK_FILE" | 
|  | vecho "SAMPLES_DIR $SAMPLES_DIR" | 
|  | vecho "CURRENT_SAMPLES_DIR $CURRENT_SAMPLES_DIR" | 
|  | vecho "CPUTYPE $CPUTYPE" | 
|  | if test "$BUF_SIZE" != "0"; then | 
|  | vecho "BUF_SIZE $BUF_SIZE" | 
|  | else | 
|  | vecho "BUF_SIZE default value" | 
|  | fi | 
|  | if test "$BUF_WATERSHED" != "0"; then | 
|  | vecho "BUF_WATERSHED $BUF_WATERSHED" | 
|  | else | 
|  | vecho "BUF_WATERSHED default value" | 
|  | fi | 
|  | if test "$KERNEL_SUPPORT" = "yes"; then | 
|  | if test "$CPU_BUF_SIZE" != "0"; then | 
|  | vecho "CPU_BUF_SIZE $CPU_BUF_SIZE" | 
|  | else | 
|  | vecho "CPU_BUF_SIZE default value" | 
|  | fi | 
|  | fi | 
|  |  | 
|  | vecho "SEPARATE_LIB $SEPARATE_LIB" | 
|  | vecho "SEPARATE_KERNEL $SEPARATE_KERNEL" | 
|  | vecho "SEPARATE_THREAD $SEPARATE_THREAD" | 
|  | vecho "SEPARATE_CPU $SEPARATE_CPU" | 
|  | vecho "CALLGRAPH $CALLGRAPH" | 
|  | vecho "VMLINUX $VMLINUX" | 
|  | vecho "KERNEL_RANGE $KERNEL_RANGE" | 
|  | vecho "XENIMAGE $XENIMAGE" | 
|  | vecho "XEN_RANGE $XEN_RANGE" | 
|  | } | 
|  |  | 
|  |  | 
|  | # stop any existing daemon | 
|  | do_stop() | 
|  | { | 
|  | if test ! -f "$LOCK_FILE"; then | 
|  | echo "Daemon not running" >&2 | 
|  | return | 
|  | fi | 
|  |  | 
|  | kill -0 `cat $LOCK_FILE` 2>/dev/null | 
|  | if test "$?" -ne 0; then | 
|  | echo "Detected stale lock file. Removing." >&2 | 
|  | rm -f "$LOCK_FILE" | 
|  | return | 
|  | fi | 
|  |  | 
|  | if test $KERNEL_SUPPORT = "yes" \ | 
|  | && test 0 != $(cat /dev/oprofile/enable); then | 
|  | echo "Stopping profiling." | 
|  | echo 0 >/dev/oprofile/enable | 
|  | fi | 
|  | kill -USR2 `cat $LOCK_FILE` 2>/dev/null | 
|  | } | 
|  |  | 
|  |  | 
|  | # kill the daemon process(es) | 
|  | do_kill_daemon() | 
|  | { | 
|  | if test ! -f "$LOCK_FILE"; then | 
|  | # no error message, do_kill_daemon imply stop and stop already | 
|  | # output "Daemon not running" | 
|  | return | 
|  | fi | 
|  |  | 
|  | kill -0 `cat $LOCK_FILE` 2>/dev/null | 
|  | if test "$?" -ne 0; then | 
|  | echo "Detected stale lock file. Removing." >&2 | 
|  | rm -f "$LOCK_FILE" | 
|  | return | 
|  | fi | 
|  |  | 
|  | echo "Killing daemon." | 
|  |  | 
|  | if test $KERNEL_SUPPORT = "yes"; then | 
|  | kill -TERM `cat $LOCK_FILE` | 
|  | else | 
|  | echo 1 >/proc/sys/dev/oprofile/dump_stop | 
|  | fi | 
|  |  | 
|  | COUNT=0 | 
|  | while test -n "`pidof oprofiled`" | 
|  | do | 
|  | sleep 1 | 
|  |  | 
|  | # because oprofiled only sets a variable inside the | 
|  | # signal handler itself, it's possible to miss a | 
|  | # signal just before it goes to sleep waiting for | 
|  | # data from the kernel that never arrives. So we | 
|  | # remind it it needs to die - this works because | 
|  | # the signal will bring oprofiled out of the kernel | 
|  | # back into userspace | 
|  | if test $KERNEL_SUPPORT = "yes"; then | 
|  | pid=`cat $LOCK_FILE 2>/dev/null` | 
|  | kill -TERM "$pid" 2>/dev/null | 
|  | fi | 
|  |  | 
|  | COUNT=`expr $COUNT + 1` | 
|  |  | 
|  | # IBS can generate a large number of samples/events. | 
|  | # Therefore, extend the delay before killing | 
|  | if test "$IBS_FETCH_COUNT" != "0" \ | 
|  | -o "$IBS_OP_COUNT" != "0" ; then | 
|  | DELAY_KILL=60 | 
|  | else | 
|  | DELAY_KILL=15 | 
|  | fi | 
|  | if test "$COUNT" -eq "$DELAY_KILL"; then | 
|  | echo "Daemon stuck shutting down; killing !" | 
|  | kill -9 `cat $LOCK_FILE` | 
|  | fi | 
|  | done | 
|  | sleep 1 | 
|  | # already removed unless we forced the kill | 
|  | rm -f "$SESSION_DIR/lock" | 
|  | } | 
|  |  | 
|  |  | 
|  | # remove any old files from a previous run | 
|  | prep_jitdump() { | 
|  | local dumpdir=/tmp/.oprofile/jitdump | 
|  | # VMs may already be running when profiling is started, so | 
|  | # remove only dump files that are not in use | 
|  | for I in $dumpdir/*; do | 
|  | test -f $I || continue; | 
|  | local pid=`basename $I .dump`; | 
|  | if test -d /proc/$pid; then | 
|  | local files=`find /proc/$pid/fd -lname $I`; | 
|  | test -n "$files" && continue; | 
|  | fi | 
|  | rm -f $I; | 
|  | done | 
|  | } | 
|  |  | 
|  | # setup and start module | 
|  | do_setup() | 
|  | { | 
|  | create_dir "$SESSION_DIR" | 
|  |  | 
|  | create_dir "$CURRENT_SAMPLES_DIR" | 
|  |  | 
|  | prep_jitdump; | 
|  | } | 
|  |  | 
|  |  | 
|  | # set a sysctl/oprofilefs parameter | 
|  | set_param() | 
|  | { | 
|  | if test "$KERNEL_SUPPORT" = "yes"; then | 
|  | echo $2 >$MOUNT/$1 | 
|  | else | 
|  | $SYSCTL -w dev.oprofile.$1=$2 | 
|  | fi | 
|  | } | 
|  |  | 
|  |  | 
|  | # set a sysctl/oprofilefs counter parameter | 
|  | set_ctr_param() | 
|  | { | 
|  | # no such thing for perfmon | 
|  | if test "$IS_PERFMON" = "yes"; then | 
|  | return | 
|  | fi | 
|  |  | 
|  | if test "$KERNEL_SUPPORT" = "yes"; then | 
|  | if test "$1" = "timer" -a "$2" != "enabled"; then | 
|  | # For now everything other than 'enabled' is | 
|  | # unsupported for the `timer' counter. | 
|  | return | 
|  | fi | 
|  | if test -e $MOUNT/$1; then | 
|  | echo $3 >$MOUNT/$1/$2 2>/dev/null | 
|  | if test $? -ne 0; then | 
|  | echo "Value $3 is not accepted by $MOUNT/$1/$2" | 
|  | exit 1 | 
|  | fi | 
|  | else | 
|  | echo -n "Error: counter $1 not available" | 
|  | if test -e /proc/sys/kernel/nmi_watchdog; then | 
|  | echo " nmi_watchdog using this resource ? Try:" | 
|  | echo "opcontrol --deinit" | 
|  | echo "echo 0 > /proc/sys/kernel/nmi_watchdog" | 
|  | fi | 
|  | exit 1 | 
|  | fi | 
|  | else | 
|  | $SYSCTL -w dev.oprofile.$1.$2=$3 | 
|  | fi | 
|  | } | 
|  |  | 
|  |  | 
|  | # returns 1 if $CPUTYPE is a PPC64 variant | 
|  | is_non_cell_ppc64_variant() | 
|  | { | 
|  | case "$1" in | 
|  | ppc64/*cell*) | 
|  | return 0 | 
|  | ;; | 
|  | ppc64/*) | 
|  | return 1 | 
|  | ;; | 
|  | *) | 
|  | return 0 | 
|  | ;; | 
|  | esac | 
|  | } | 
|  |  | 
|  |  | 
|  | # The arch_event_validate procedure gives the | 
|  | # opportunity to validate events and enforce any | 
|  | # arch-specific restritions, etc. | 
|  | arch_event_validate() | 
|  | { | 
|  |  | 
|  | is_non_cell_ppc64_variant $CPUTYPE | 
|  | if test $? -ne 0 ; then | 
|  | # For PPC64 architectures, the values required to program | 
|  | # MMCRs for the given event are returned along with the event. | 
|  | # Here we use those values to ensure that all chosen events | 
|  | # are from the same group. | 
|  | MMCR0=`echo $EVENT_STR | awk '{print $2}'` | 
|  | MMCR1=`echo $EVENT_STR | awk '{print $3}'` | 
|  | MMCRA=`echo $EVENT_STR | awk '{print $4}'` | 
|  | MMCR0_VAL=`echo $MMCR0 | awk -F: '{print $2}'` | 
|  | MMCR1_VAL=`echo $MMCR1 | awk -F: '{print $2}'` | 
|  | MMCRA_VAL=`echo $MMCRA | awk -F: '{print $2}'` | 
|  |  | 
|  | ## mmcr0, mmcr1, mmcra are for all ppc64 counters | 
|  | # Save first event mmcr settings to compare with additional | 
|  | # events.  All events must have the same mmcrx values i.e. be in | 
|  | # the same group.  Only one event is assigned per counter, | 
|  | # hence there will not be a conflict on the counters | 
|  | if [ "$MMCR0_CK_VAL" = "" ] ; then | 
|  | MMCR0_CK_VAL=$MMCR0_VAL | 
|  | MMCR1_CK_VAL=$MMCR1_VAL | 
|  | MMCRA_CK_VAL=$MMCRA_VAL | 
|  | else | 
|  | # make sure all events are from the same group | 
|  | if test $MMCR0_CK_VAL != $MMCR0_VAL \ | 
|  | -o $MMCR1_CK_VAL != $MMCR1_VAL \ | 
|  | -o $MMCRA_CK_VAL != $MMCRA_VAL ; then | 
|  | echo "ERROR: The specified events are not from the same group." | 
|  | echo "       Use 'opcontrol --list-events' to see event groupings." | 
|  | exit 1 | 
|  | fi | 
|  | fi | 
|  |  | 
|  | # Check if all user/kernel flags per-counter are matching. | 
|  | if [ "$USER_CK" = "" ] ; then | 
|  | USER_CK=$USER | 
|  | KERNEL_CK=$KERNEL | 
|  | else | 
|  | if test $USER_CK != $USER \ | 
|  | -o $KERNEL_CK != $KERNEL ; then | 
|  | echo "ERROR: All kernel/user event flags must match." | 
|  | exit 1 | 
|  | fi | 
|  | fi | 
|  | fi | 
|  | if [ "$CPUTYPE" = "ppc64/cell-be" ]; then | 
|  | event_num=`echo $EVENT_STR | awk '{print $1}'` | 
|  | # PPU event and cycle events can be measured at | 
|  | # the same time.  SPU event can not be measured | 
|  | # at the same time as any other event.  Similarly for | 
|  | # SPU Cycles | 
|  |  | 
|  | # We use EVNT_MSK to track what events have already | 
|  | # been seen.  Valid values are: | 
|  | #    NULL string -  no events seen yet | 
|  | #    1 - PPU CYCLES or PPU Event seen | 
|  | #    2 - SPU CYCLES seen | 
|  | #    3 - SPU EVENT seen | 
|  |  | 
|  | # check if event is PPU_CYCLES | 
|  | if [ "$event_num" = "1" ]; then | 
|  | if [ "$EVNT_MSK" = "1" ] || [ "$EVNT_MSK" = "" ]; then | 
|  | EVNT_MSK=1 | 
|  | else | 
|  | echo "PPU CYCLES not compatible with previously specified event" | 
|  | exit 1 | 
|  | fi | 
|  |  | 
|  | # check if event is SPU_CYCLES | 
|  | elif [ "$event_num" = "2" ]; then | 
|  | if [ "$EVNT_MSK" = "" ]; then | 
|  | EVNT_MSK=2 | 
|  | else | 
|  | echo "SPU CYCLES not compatible with any other event" | 
|  | exit 1 | 
|  | fi | 
|  |  | 
|  | # check if event is SPU Event profiling | 
|  | elif [ "$event_num" -ge "4100" ] && [ "$event_num" -le "4163" ] ; then | 
|  | if [ "$EVNT_MSK" = "" ]; then | 
|  | EVNT_MSK=3 | 
|  | else | 
|  | echo "SPU event profiling not compatible with any other event" | 
|  | exit 1 | 
|  | fi | 
|  |  | 
|  | # Check to see that the kernel supports SPU event | 
|  | # profiling.  Note, if the file exits it should have | 
|  | # the LSB bit set to 1 indicating SPU event profiling | 
|  | # support. For now, it is sufficient to test that the | 
|  | # file exists. | 
|  | if test ! -f /dev/oprofile/cell_support; then | 
|  | echo "Kernel does not support SPU event profiling" | 
|  | exit 1 | 
|  | fi | 
|  |  | 
|  | # check if event is PPU Event profiling (all other | 
|  | # events are PPU events) | 
|  | else | 
|  | if [ "$EVNT_MSK" = "1" ] || [ "$EVNT_MSK" = "" ]; then | 
|  | EVNT_MSK=1 | 
|  | else | 
|  | echo "PPU profiling not compatible with previously specified event" | 
|  | exit 1 | 
|  | fi | 
|  | fi | 
|  | fi | 
|  | if test "$S390_HW_SAMPLER" = "1" -a "$EVENT" = "HWSAMPLING"; then | 
|  | if test "$CALLGRAPH" != "0"; then | 
|  | echo "Callgraph sample collection is not supported with " >&2 | 
|  | echo "System z hardware sampling.  Please use --callgraph=0 " >&2 | 
|  | echo "or enable timer based sampling." >&2 | 
|  | exit 1 | 
|  | fi | 
|  | echo "$COUNT" > $MOUNT/0/count | 
|  | NEW_COUNT=`cat $MOUNT/0/count` | 
|  | if test "$NEW_COUNT" -lt "$COUNT"; then | 
|  | echo "Warning: Hardware sampling intervals higher than $NEW_COUNT are not supported." >&2 | 
|  | echo "Value is set to $NEW_COUNT." >&2 | 
|  | COUNT=$NEW_COUNT | 
|  | fi | 
|  | if test "$NEW_COUNT" -gt "$COUNT"; then | 
|  | echo "Warning: Hardware sampling intervals lower than $NEW_COUNT are not supported." >&2 | 
|  | echo "Value is set to $NEW_COUNT." >&2 | 
|  | COUNT=$NEW_COUNT | 
|  | fi | 
|  | fi | 
|  |  | 
|  | len=`echo -n $event_num | wc -c` | 
|  | num_chars_in_grpid=`expr $len - 2` | 
|  | GRP_NUM_VAL=`echo | awk '{print substr("'"${event_num}"'",1,"'"${num_chars_in_grpid}"'")}'` | 
|  | if [ "$GRP_NUM_CK_VAL" = "" ] ; then | 
|  | GRP_NUM_CK_VAL=$GRP_NUM_VAL | 
|  | else | 
|  | if test $GRP_NUM_CK_VAL != $GRP_NUM_VAL ; then | 
|  | echo "ERROR: The specified events are not from the same group." >&2 | 
|  | echo "       Use 'opcontrol --list-events' to see event groupings." >&2 | 
|  | exit 1 | 
|  | fi | 
|  | fi | 
|  | } | 
|  |  | 
|  |  | 
|  | do_param_setup() | 
|  | { | 
|  | # different names | 
|  | if test $BUF_SIZE != 0; then | 
|  | if test "$KERNEL_SUPPORT" = "yes"; then | 
|  | echo $BUF_SIZE >$MOUNT/buffer_size | 
|  | else | 
|  | $SYSCTL -w dev.oprofile.bufsize=$BUF_SIZE | 
|  | fi | 
|  | fi | 
|  |  | 
|  | if test $BUF_WATERSHED != 0; then | 
|  | if test "$KERNEL_SUPPORT" = "yes"; then | 
|  | echo $BUF_WATERSHED >$MOUNT/buffer_watershed | 
|  | else | 
|  | echo "buffer-watershed not supported - ignored" >&2 | 
|  | fi | 
|  | fi | 
|  |  | 
|  | if test $CPU_BUF_SIZE != 0; then | 
|  | if test "$KERNEL_SUPPORT" = "yes"; then | 
|  | echo $CPU_BUF_SIZE >$MOUNT/cpu_buffer_size | 
|  | else | 
|  | echo "cpu-buffer-size not supported - ignored" >&2 | 
|  | fi | 
|  | fi | 
|  |  | 
|  | if test -n "$ACTIVE_DOMAINS"; then | 
|  | if test "$KERNEL_SUPPORT" = "yes"; then | 
|  | echo $ACTIVE_DOMAINS >$MOUNT/active_domains | 
|  | else | 
|  | echo "active-domains not supported - ignored" >&2 | 
|  | fi | 
|  | fi | 
|  |  | 
|  | if test $NOTE_SIZE != 0; then | 
|  | set_param notesize $NOTE_SIZE | 
|  | fi | 
|  |  | 
|  | if test "$KERNEL_SUPPORT" = "yes" -a -f $MOUNT/backtrace_depth; then | 
|  | set_param backtrace_depth $CALLGRAPH | 
|  | elif test "$CALLGRAPH" != "0"; then | 
|  | echo "Call-graph profiling not supported - ignored" >&2 | 
|  | fi | 
|  |  | 
|  | if test "$IS_TIMER" = 1; then | 
|  | return | 
|  | fi | 
|  |  | 
|  | if test "$S390_HW_SAMPLER" = "1" -a "$S390_HW_SAMPLER_BUFSIZE" != "0"; then | 
|  | echo $S390_HW_SAMPLER_BUFSIZE >$MOUNT/0/hw_sdbt_blocks | 
|  | fi | 
|  |  | 
|  | # use the default setup if none set | 
|  | if test "$NR_CHOSEN" = 0; then | 
|  | set_event 0 $DEFAULT_EVENT | 
|  | NR_CHOSEN=1 | 
|  | HW_CTRS=`$OPHELP --check-events $DEFAULT_EVENT --callgraph=$CALLGRAPH` | 
|  | echo "Using default event: $DEFAULT_EVENT" | 
|  | fi | 
|  |  | 
|  | # Necessary in this case : | 
|  | # opcontrol ctr0-on ctr1-on then opcontrol ctr0-on | 
|  | for f in $OP_COUNTERS ; do | 
|  | set_ctr_param $f enabled 0 | 
|  | set_ctr_param $f event 0 | 
|  | set_ctr_param $f count 0 | 
|  |  | 
|  | if test -f $MOUNT/$f/extra ; then | 
|  | set_ctr_param $f extra 0 | 
|  | fi | 
|  | done | 
|  |  | 
|  | # Check if driver has IBS support | 
|  | if test -d $MOUNT/ibs_fetch; then | 
|  | # Reset driver's IBS fetch setting | 
|  | set_param ibs_fetch/enable 0 | 
|  | fi | 
|  |  | 
|  | if test -d $MOUNT/ibs_op ; then | 
|  | # Reset driver's IBS op setting | 
|  | set_param ibs_op/enable 0 | 
|  | fi | 
|  |  | 
|  | verify_counters | 
|  |  | 
|  | OPROFILED_EVENTS= | 
|  | for f in `seq 0 $((NR_CHOSEN - 1))`; do | 
|  | get_event $f | 
|  | if test "$GOTEVENT" != ""; then | 
|  | EVENT=`echo $GOTEVENT | awk -F: '{print $1}'` | 
|  | EVENT_STR=`$OPHELP $EVENT` | 
|  | EVENT_VAL=`echo $EVENT_STR | awk '{print $1}'` | 
|  | COUNT=`echo $GOTEVENT | awk -F: '{print $2}'` | 
|  | UNIT_MASK=`echo $GOTEVENT | awk -F: '{print $3}'` | 
|  | KERNEL=`echo $GOTEVENT | awk -F: '{print $4}'` | 
|  | USER=`echo $GOTEVENT | awk -F: '{print $5}'` | 
|  | CTR=`echo $HW_CTRS | awk "{print \\$$((f + 1))}"` | 
|  | arch_event_validate | 
|  |  | 
|  | if test "$EVENT" = "SPU_CYCLES"; then | 
|  | if test "$SEPARATE_KERNEL" = "1"; then | 
|  | SEPARATE_KERNEL=0 | 
|  | echo "Ignoring --separate=kernel option with SPU_CYCLES" | 
|  | fi | 
|  | if test "$SEPARATE_LIB" = "0"; then | 
|  | SEPARATE_LIB=1 | 
|  | echo "Forcing required option --separate=lib with SPU_CYCLES" | 
|  | fi | 
|  |  | 
|  | # It is possible for a single application to be | 
|  | # running on all SPUs simultaneously.  Without | 
|  | # SEPARATE_CPU, the resulting sample data would | 
|  | # consist of a single sample file.  If all SPUs | 
|  | # were truly running the same code, the merging | 
|  | # of sample data would be fine.  However, an | 
|  | # application file may have multiple SPU images | 
|  | # embedded within it, resulting in different | 
|  | # code running on different SPUs.  Therefore, | 
|  | # we force SEPARATE_CPU in order to properly | 
|  | # handle this case. | 
|  | if test "$SEPARATE_CPU" = "0"; then | 
|  | SEPARATE_CPU=1 | 
|  | echo "Forcing required option --separate=cpu with SPU_CYCLES" | 
|  |  | 
|  | fi | 
|  | fi | 
|  |  | 
|  | if [ "$CTR" = "ibs_fetch" -o "$CTR" = "ibs_op" ] ; then | 
|  | # Handle IBS events setup | 
|  | do_param_setup_ibs | 
|  | continue | 
|  | fi | 
|  |  | 
|  | if test "$EVENT" = "RTC_INTERRUPTS"; then | 
|  | set_param rtc_value $COUNT | 
|  | $SYSCTL -w dev.oprofile.rtc_value=$COUNT | 
|  | else | 
|  | set_ctr_param $CTR enabled 1 | 
|  | set_ctr_param $CTR event $EVENT_VAL | 
|  | loop_count=1 | 
|  | for i in ${EVENT_STR}; do | 
|  | #Skip first argument of EVENT_STR (event val) since we've already | 
|  | #processed that value. | 
|  | if test "$loop_count" -gt 1; then | 
|  | KEY=`echo $i | awk -F: '{print $1}'` | 
|  | VAL=`echo $i | awk -F: '{print $2}'` | 
|  | set_ctr_param "" $KEY $VAL | 
|  | fi | 
|  | loop_count=$((loop_count+1)) | 
|  | done | 
|  | set_ctr_param $CTR count $COUNT | 
|  | set_ctr_param $CTR kernel $KERNEL | 
|  | set_ctr_param $CTR user $USER | 
|  | set_ctr_param $CTR unit_mask $UNIT_MASK | 
|  |  | 
|  | EXTRA=`$OPHELP --extra-mask $EVENT:$COUNT:$UNIT_MASK_NAMED` | 
|  | if test "$EXTRA" -ne 0 ; then | 
|  | # A value >= 0x40000 returned by 'ophelp --extra-mask' (EXTRA_MIN_VAL) is interpreted | 
|  | # as a valid extra value; otherwise we interpret as a simple unit mask value | 
|  | # for a named unit mask with EXTRA_NONE. | 
|  | EXTRA_MIN_VAL=262144 | 
|  | if test "$EXTRA" -ge $EXTRA_MIN_VAL ; then | 
|  | if ! test -f $MOUNT/$CTR/extra ; then | 
|  | echo >&2 "Warning: $GOTEVENT has extra mask, but kernel does not support extra field" | 
|  | echo >&2 "Please update your kernel or use a different event. Will miscount." | 
|  | else | 
|  | set_ctr_param $CTR extra $EXTRA | 
|  | fi | 
|  | else | 
|  | UNIT_MASK=$EXTRA | 
|  | set_ctr_param $CTR unit_mask $UNIT_MASK | 
|  | fi | 
|  | fi | 
|  | fi | 
|  | OPROFILED_EVENTS=${OPROFILED_EVENTS}$EVENT:$EVENT_VAL: | 
|  | OPROFILED_EVENTS=${OPROFILED_EVENTS}$CTR:$COUNT:$UNIT_MASK: | 
|  | OPROFILED_EVENTS=${OPROFILED_EVENTS}$KERNEL:$USER, | 
|  | fi | 
|  | done | 
|  |  | 
|  | # For PPC64 architectures we need to set the enable_kernel and | 
|  | # enable_user flags for enabling/disabling user/kernel domain | 
|  | # profiling. All per-counter user/kernel flags must match. | 
|  | # This condition is checked previously by arch_event_validate. | 
|  | # This statement uses the last event's user/kernel flags to set | 
|  | # /dev/oprofile/enable_kernel and /dev/oprofile/enable_user. | 
|  | is_non_cell_ppc64_variant $CPUTYPE | 
|  | if test $? -ne 0 ; then | 
|  | set_param "enable_kernel" $KERNEL | 
|  | set_param "enable_user" $USER | 
|  | fi | 
|  |  | 
|  | } | 
|  |  | 
|  |  | 
|  | do_start_daemon() | 
|  | { | 
|  |  | 
|  | $OPDIR/op-check-perfevents | 
|  | if [ "$?" = "0" ]; then | 
|  | echo "ATTENTION: Use of opcontrol is discouraged.  Please see the man page for operf." | 
|  | fi | 
|  |  | 
|  | if test -f "$LOCK_FILE"; then | 
|  | kill -0 `cat $LOCK_FILE` 2>/dev/null | 
|  | if test "$?" -eq 0; then | 
|  | return; | 
|  | else | 
|  | echo "Detected stale lock file. Removing." >&2 | 
|  | rm -f "$LOCK_FILE" | 
|  | fi | 
|  | fi | 
|  |  | 
|  | do_setup | 
|  | check_valid_args | 
|  | get_image_range "linux" | 
|  | get_image_range "xen" | 
|  | do_param_setup | 
|  |  | 
|  | OPD_ARGS=" \ | 
|  | --session-dir=$SESSION_DIR \ | 
|  | --separate-lib=$SEPARATE_LIB \ | 
|  | --separate-kernel=$SEPARATE_KERNEL \ | 
|  | --separate-thread=$SEPARATE_THREAD \ | 
|  | --separate-cpu=$SEPARATE_CPU" | 
|  |  | 
|  | if test "$IS_TIMER" = 1; then | 
|  | OPD_ARGS="$OPD_ARGS --events=" | 
|  | else | 
|  | if ! test -z "$OPROFILED_EVENTS"; then | 
|  | OPD_ARGS="$OPD_ARGS --events=$OPROFILED_EVENTS" | 
|  | fi | 
|  | fi | 
|  |  | 
|  | if test "$VMLINUX" = "none"; then | 
|  | OPD_ARGS="$OPD_ARGS --no-vmlinux" | 
|  | else | 
|  | OPD_ARGS="$OPD_ARGS --vmlinux=$VMLINUX --kernel-range=$KERNEL_RANGE" | 
|  | fi | 
|  |  | 
|  | if ! test "$XENIMAGE" = "none"; then | 
|  | OPD_ARGS="$OPD_ARGS --xen-image=$XENIMAGE --xen-range=$XEN_RANGE" | 
|  | fi | 
|  |  | 
|  | if ! test -z "$IMAGE_FILTER"; then | 
|  | OPD_ARGS="$OPD_ARGS --image=$IMAGE_FILTER" | 
|  | fi | 
|  |  | 
|  | if test -n "$VERBOSE"; then | 
|  | OPD_ARGS="$OPD_ARGS --verbose=$VERBOSE" | 
|  | fi | 
|  |  | 
|  | help_start_daemon_with_ibs | 
|  |  | 
|  | vecho "executing oprofiled $OPD_ARGS" | 
|  |  | 
|  | $OPROFILED $OPD_ARGS | 
|  |  | 
|  | COUNT=0 | 
|  | while ! test -f "$SESSION_DIR/lock" | 
|  | do | 
|  | sleep 1 | 
|  | COUNT=`expr $COUNT + 1` | 
|  | if test "$COUNT" -eq 10; then | 
|  | echo "Couldn't start oprofiled." >&2 | 
|  | echo "Check the log file \"$LOG_FILE\" and kernel syslog" >&2 | 
|  | exit 1 | 
|  | fi | 
|  | done | 
|  |  | 
|  | echo "Daemon started." | 
|  | } | 
|  |  | 
|  | do_start() | 
|  | { | 
|  | prep_jitdump; | 
|  | if test "$KERNEL_SUPPORT" = "yes"; then | 
|  | echo 1 >$MOUNT/enable | 
|  | fi | 
|  | kill -USR1 `cat $LOCK_FILE` 2>/dev/null | 
|  | echo "Profiler running." | 
|  | } | 
|  |  | 
|  |  | 
|  | # print status | 
|  | do_status() | 
|  | { | 
|  | OPROFILED_PID=`cat $SESSION_DIR/lock 2>/dev/null` | 
|  | if test -n "$OPROFILED_PID" -a -d "/proc/$OPROFILED_PID"; then | 
|  | if test "$KERNEL_SUPPORT" = yes \ | 
|  | && test 0 != $(cat /dev/oprofile/enable); then | 
|  | echo "Daemon running: pid $OPROFILED_PID" | 
|  | else | 
|  | echo "Daemon paused: pid $OPROFILED_PID" | 
|  | fi | 
|  | else | 
|  | echo "Daemon not running" | 
|  | fi | 
|  | echo "Session-dir: $SESSION_DIR" | 
|  |  | 
|  | if test "$NR_CHOSEN" != "0"; then | 
|  | for f in `seq 0 $((NR_CHOSEN - 1))`; do | 
|  | get_event $f | 
|  | echo "Event $f: $GOTEVENT" | 
|  | done | 
|  | fi | 
|  |  | 
|  | SEPARATE="" | 
|  | if test "$SEPARATE_LIB" = "1"; then | 
|  | SEPARATE="library"; | 
|  | fi | 
|  | if test "$SEPARATE_KERNEL" = "1"; then | 
|  | SEPARATE="$SEPARATE kernel"; | 
|  | fi | 
|  | if test "$SEPARATE_THREAD" = "1"; then | 
|  | SEPARATE="$SEPARATE thread"; | 
|  | fi | 
|  | if test "$SEPARATE_CPU" = "1"; then | 
|  | SEPARATE="$SEPARATE cpu"; | 
|  | fi | 
|  |  | 
|  | if test -z "$SEPARATE"; then | 
|  | SEPARATE=none | 
|  | fi | 
|  |  | 
|  | echo "Separate options: $SEPARATE" | 
|  | echo "vmlinux file: $VMLINUX" | 
|  |  | 
|  | if test -z "$IMAGE_FILTER"; then | 
|  | echo "Image filter: none" | 
|  | else | 
|  | echo "Image filter: $IMAGE_FILTER" | 
|  | fi | 
|  |  | 
|  | echo "Call-graph depth: $CALLGRAPH" | 
|  | if test "$BUF_SIZE" != "0"; then | 
|  | echo "Buffer size: $BUF_SIZE" | 
|  | fi | 
|  | if test "$KERNEL_SUPPORT" != "yes"; then | 
|  | if test "$NOTE_SIZE" != "0"; then | 
|  | echo "Note buffer size: $NOTE_SIZE" | 
|  | fi | 
|  | else | 
|  | if test "$BUF_WATERSHED" != "0"; then | 
|  | echo "CPU buffer watershed: $BUF_WATERSHED" | 
|  | fi | 
|  | if test "$CPU_BUF_SIZE" != "0"; then | 
|  | echo "CPU buffer size: $CPU_BUF_SIZE" | 
|  | fi | 
|  | fi | 
|  | if test "$S390_HW_SAMPLER" = "1"; then | 
|  | echo -n "System z hardware sampling buffer size (in 2MB areas): " | 
|  | if test "$S390_HW_SAMPLER_BUFSIZE" = "0"; then | 
|  | cat $MOUNT/0/hw_sdbt_blocks | 
|  | else | 
|  | echo "$S390_HW_SAMPLER_BUFSIZE" | 
|  | fi | 
|  | fi | 
|  |  | 
|  | exit 0 | 
|  | } | 
|  |  | 
|  |  | 
|  | # do_dump_data | 
|  | # returns 0 if successful | 
|  | # returns 1 if the daemon is unable to dump data | 
|  | # exit 1 if we need to be root to dump | 
|  | do_dump_data() | 
|  | { | 
|  | # make sure that the daemon is not dead and gone | 
|  | if test -e "$SESSION_DIR/lock"; then | 
|  | OPROFILED_PID=`cat $SESSION_DIR/lock` | 
|  | if test ! -d "/proc/$OPROFILED_PID"; then | 
|  | echo "dump fail: daemon died during last run ?" >&2 | 
|  | return 1; | 
|  | fi | 
|  | else | 
|  | return 1; | 
|  | fi | 
|  |  | 
|  | if test "$KERNEL_SUPPORT" = "yes"; then | 
|  | if ! test -w $MOUNT/dump; then | 
|  | if test `id -u` != "0"; then | 
|  | echo "You must be root to dump with this kernel version" | 
|  | exit 1 | 
|  | fi | 
|  | fi | 
|  | # trigger oprofiled to execute opjitconv | 
|  | if test -p "$SESSION_DIR/opd_pipe"; then | 
|  | echo do_jitconv >> $SESSION_DIR/opd_pipe | 
|  | fi | 
|  | rm -f "$SESSION_DIR/complete_dump" | 
|  | echo 1 > $MOUNT/dump | 
|  | # loop until the complete_dump file is created to | 
|  | # signal that the dump has been completed | 
|  | while [ \( ! -e "$SESSION_DIR/complete_dump" \) ] | 
|  | do | 
|  | if test ! -d "/proc/$OPROFILED_PID"; then | 
|  | echo "dump fail: either daemon died during last run or dies during dump" >&2 | 
|  | return 1 | 
|  | fi | 
|  | sleep 1; | 
|  | done | 
|  | else | 
|  | echo 1 > $MOUNT/dump | 
|  | # HACK ! | 
|  | sleep 2 | 
|  | fi | 
|  | cp -r /dev/oprofile/stats "$SAMPLES_DIR/current" | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  |  | 
|  | # do_dump | 
|  | # returns 0 if successful | 
|  | # exits if unsuccessful | 
|  | do_dump() | 
|  | { | 
|  | do_dump_data | 
|  | if test $? -ne 0 -a "$ONLY_DUMP" = "yes"; then | 
|  | echo "Unable to complete dump of oprofile data: is the oprofile daemon running?" >& 2 | 
|  | exit 1; | 
|  | fi | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | # tell daemon to re-open the sample files | 
|  | hup_daemon() | 
|  | { | 
|  | if test -f "$LOCK_FILE"; then | 
|  | echo -n "Signalling daemon... " | 
|  | kill -HUP `cat $LOCK_FILE` | 
|  | echo "done" | 
|  | fi | 
|  | } | 
|  |  | 
|  |  | 
|  | # move all the sample files to a sample directory | 
|  | do_save_session() | 
|  | { | 
|  | SAVE_DIR="${SAMPLES_DIR}/${SAVE_NAME}" | 
|  |  | 
|  | if test -e "$SAVE_DIR"; then | 
|  | echo "session $SAVE_DIR already exists" >&2 | 
|  | exit 1 | 
|  | fi | 
|  |  | 
|  | if ! test -e $CURRENT_SAMPLES_DIR; then | 
|  | echo "$CURRENT_SAMPLES_DIR doesn't exist: nothing to save" >&2 | 
|  | exit 0 | 
|  | fi | 
|  |  | 
|  | # FIXME: I don't think it's worth checking for empty current directory | 
|  |  | 
|  | mv $CURRENT_SAMPLES_DIR $SAVE_DIR | 
|  | if test "$?" != "0"; then | 
|  | echo "Couldn't move $CURRENT_SAMPLES_DIR to $SAVE_DIR" >&2 | 
|  | exit 1 | 
|  | fi | 
|  |  | 
|  | hup_daemon | 
|  | } | 
|  |  | 
|  |  | 
|  | # remove all the sample files | 
|  | do_reset() | 
|  | { | 
|  | if test -z "$SAMPLES_DIR"; then | 
|  | echo "opcontrol:do_reset() SAMPLES_DIR is empty!" | 
|  | exit 1; | 
|  | fi | 
|  |  | 
|  | # daemon use {kern} and {root} subdir, it's not a typo to not use ${} | 
|  | move_and_remove $SAMPLES_DIR/current/{kern} | 
|  | move_and_remove $SAMPLES_DIR/current/{root} | 
|  | move_and_remove $SAMPLES_DIR/current/stats | 
|  |  | 
|  | # clear temp directory for jitted code | 
|  | prep_jitdump; | 
|  |  | 
|  | hup_daemon | 
|  | } | 
|  |  | 
|  |  | 
|  | do_deinit() | 
|  | { | 
|  | # unmount /dev/oprofile if it is mounted | 
|  | OPROF_FS=`grep /dev/oprofile /proc/mounts` | 
|  | if test -n "$OPROF_FS"; then | 
|  | umount /dev/oprofile | 
|  | fi | 
|  | # unload the oprofile module if it is around | 
|  | OPROF_MOD=`lsmod | grep oprofile` | 
|  | if test -n "$OPROF_MOD"; then | 
|  | echo "Unloading oprofile module" >& 2 | 
|  | rmmod oprofile | 
|  | fi | 
|  | } | 
|  |  | 
|  |  | 
|  | # The function that calls the appropriate operations | 
|  | do_operations() | 
|  | { | 
|  | # INIT always done by load_module to get access to cputype | 
|  | # thus INIT is a noop | 
|  |  | 
|  | if test "$STATUS" = "yes"; then | 
|  | do_status | 
|  | fi | 
|  |  | 
|  | if test "$SETUP" = "yes"; then | 
|  | check_valid_args | 
|  | do_save_setup | 
|  | fi | 
|  |  | 
|  | if test "$START_DAEMON" = "yes"; then | 
|  | do_start_daemon | 
|  | fi | 
|  |  | 
|  | if test "$START" = "yes"; then | 
|  | do_start_daemon | 
|  | do_start | 
|  | fi | 
|  |  | 
|  | if test "$DUMP" = "yes"; then | 
|  | do_dump | 
|  | fi | 
|  |  | 
|  | if test "$SAVE_SESSION" = "yes"; then | 
|  | do_save_session | 
|  | fi | 
|  |  | 
|  | if test "$STOP" = "yes"; then | 
|  | do_stop | 
|  | fi | 
|  |  | 
|  | if test "$KILL_DAEMON" = "yes"; then | 
|  | do_kill_daemon | 
|  | fi | 
|  |  | 
|  | if test "$RESET" = "yes"; then | 
|  | do_reset | 
|  | fi | 
|  |  | 
|  | if test "$DEINIT" = "yes"; then | 
|  | do_deinit | 
|  | fi | 
|  | } | 
|  |  | 
|  | # early check for --version, --help and --session-dir | 
|  | check_options_early() | 
|  | { | 
|  |  | 
|  | OPHELP="$OPDIR/ophelp" | 
|  |  | 
|  | for i in $@; do | 
|  | # added to handle arg=val parameters | 
|  | arg=`printf %s $i | awk -F= '{print $1}'` | 
|  | val=`printf %s $i | awk -F= '{print $2}'` | 
|  | case "$arg" in | 
|  | -\?|--help) | 
|  | do_help | 
|  | exit 0 | 
|  | ;; | 
|  |  | 
|  | -v|--version) | 
|  | echo -n "`basename $0`: " | 
|  | $OPHELP --version | cut -d' ' -f2- | 
|  | exit 0 | 
|  | ;; | 
|  | --session-dir) | 
|  | error_if_invalid_arg "$arg" "$val" | 
|  | SESSION_DIR="$val" | 
|  | DO_SETUP=yes | 
|  | # do not exit early | 
|  | ;; | 
|  |  | 
|  | esac | 
|  | done | 
|  | } | 
|  |  | 
|  |  | 
|  | # determine which module is loaded | 
|  | check_version() | 
|  | { | 
|  | OPROFILE_AVAILABLE=no | 
|  | grep oprofilefs /proc/mounts >/dev/null | 
|  | if test "$?" -eq 0; then | 
|  | # need to have oprofilefs mounted for this to work on 2.6 | 
|  | KERNEL_SUPPORT=yes | 
|  | OPROFILE_AVAILABLE=yes | 
|  | return | 
|  | fi | 
|  | # need to have /proc/oprof available for this to work on 2.4 | 
|  | grep oprof /proc/devices >/dev/null | 
|  | if test "$?" -eq 0; then | 
|  | KERNEL_SUPPORT=no | 
|  | OPROFILE_AVAILABLE=yes | 
|  | return | 
|  | fi | 
|  | } | 
|  |  | 
|  | # error out if the module is not loaded | 
|  | check_oprofile_available() | 
|  | { | 
|  | if test "$OPROFILE_AVAILABLE" != "yes"; then | 
|  | echo "Kernel support not available, missing opcontrol --init as root ?" | 
|  | exit 1 | 
|  | fi | 
|  | } | 
|  |  | 
|  |  | 
|  | try_reset_sample_file() | 
|  | { | 
|  | # special case to avoid loading the module, it works only if the | 
|  | # daemon is not running because --reset imply --dump. Rather to check | 
|  | # if the daemon is running we check if the module is loaded because | 
|  | # we are only trying to avoid its load, if the check fails we fallback | 
|  | # to the normal dump / reset sequence. | 
|  | if test -z "$2" -a "$1" = "--reset"; then | 
|  | check_version | 
|  | if test "$OPROFILE_AVAILABLE" != "yes"; then | 
|  | do_init_daemon_vars | 
|  | do_reset | 
|  | exit 0 | 
|  | fi | 
|  | fi | 
|  | } | 
|  |  | 
|  | # | 
|  | # Begin IBS Specific Functions | 
|  | # | 
|  | verify_ibs() | 
|  | { | 
|  | IBS_EVENT=`echo $1| awk -F: '{print $1}'` | 
|  | IBS_COUNT=`echo $1 | awk -F: '{print $2}'` | 
|  | IBS_MASK=`echo $1 | awk -F: '{print $3}'` | 
|  |  | 
|  | IBS_TYPE=`$OPHELP --check-events $1` | 
|  | if test "$?" != "0" ; then | 
|  | exit 1 | 
|  | fi | 
|  |  | 
|  | if [ "$IBS_TYPE" = "ibs_fetch " ] ; then | 
|  | # Check IBS_COUNT consistency | 
|  | if test "$IBS_FETCH_COUNT" = "0" ; then | 
|  | IBS_FETCH_COUNT=$IBS_COUNT | 
|  | IBS_FETCH_MASK=$IBS_MASK | 
|  | elif test "$IBS_FETCH_COUNT" != "$IBS_COUNT" ; then | 
|  | echo "ERROR: All IBS Fetch must have the same count." | 
|  | exit 1 | 
|  | fi | 
|  |  | 
|  | # Check IBS_MASK consistency | 
|  | if test "$IBS_FETCH_MASK" != "$IBS_MASK" ; then | 
|  | echo "ERROR: All IBS Fetch must have the same unitmask." | 
|  | exit 1 | 
|  | fi | 
|  |  | 
|  | # Check IBS_FETCH_COUNT within range | 
|  | if test "$IBS_FETCH_COUNT" -gt 1048575 ; then | 
|  | echo "ERROR: IBS Fetch count is too large." | 
|  | echo "       The maximum IBS-fetch count is 1048575." | 
|  | exit 1 | 
|  | fi | 
|  |  | 
|  | elif [ "$IBS_TYPE" = "ibs_op " ] ; then | 
|  | # Check IBS_COUNT consistency | 
|  | if test "$IBS_OP_COUNT" = "0" ; then | 
|  | IBS_OP_COUNT=$IBS_COUNT | 
|  | IBS_OP_MASK=$IBS_MASK | 
|  | elif test "$IBS_OP_COUNT" != "$IBS_COUNT" ; then | 
|  | echo "All IBS Op must have the same count." | 
|  | exit 1 | 
|  | fi | 
|  |  | 
|  | # Check IBS_MASK consistency | 
|  | if test "$IBS_OP_MASK" != "$IBS_MASK" ; then | 
|  | echo "All IBS Op must have the same unitmask." | 
|  | exit 1 | 
|  | fi | 
|  |  | 
|  | # Check IBS_OP_COUNT within range | 
|  | case "$CPUTYPE" in | 
|  | x86-64/family10) | 
|  | if test "$IBS_OP_COUNT" -gt 1048575 ; then | 
|  | echo "ERROR: IBS Op count is too large." | 
|  | echo "       The maximum IBS-fetch count is 1048575." | 
|  | exit 1 | 
|  | fi | 
|  | ;; | 
|  |  | 
|  | x86-64/family12h|\ | 
|  | x86-64/family14h|\ | 
|  | x86-64/family15h) | 
|  | if test "$IBS_OP_COUNT" -gt 134217727 ; then | 
|  | echo "ERROR: IBS Op count is too large." | 
|  | echo "       The maximum IBS-Op count is 134217727." | 
|  | exit 1 | 
|  | fi | 
|  | ;; | 
|  | *) | 
|  | esac | 
|  | fi | 
|  |  | 
|  | return | 
|  | } | 
|  |  | 
|  |  | 
|  | do_param_setup_ibs() | 
|  | { | 
|  | if test "$KERNEL_SUPPORT" != "yes" ; then | 
|  | echo "ERROR: No kernel support for IBS profiling." | 
|  | exit 1 | 
|  | fi | 
|  |  | 
|  | # Check if driver has IBS support | 
|  | if test ! -d $MOUNT/ibs_fetch -o ! -d $MOUNT/ibs_op ; then | 
|  | echo "ERROR: No kernel support for IBS profiling." | 
|  | exit 1 | 
|  | fi | 
|  |  | 
|  | if test `echo $EVENT |  \ | 
|  | awk '{ print substr($0, 1, 10)}'` = "IBS_FETCH_" ; then | 
|  | if test "$COUNT" != "0"; then | 
|  | if [ "$IBS_FETCH_EVENTS" = "" ] ; then | 
|  | IBS_FETCH_EVENTS="$EVENT" | 
|  | else | 
|  | IBS_FETCH_EVENTS="$IBS_FETCH_EVENTS,$EVENT" | 
|  | fi | 
|  | IBS_FETCH_COUNT=$COUNT | 
|  | set_param ibs_fetch/max_count $COUNT | 
|  | set_param ibs_fetch/rand_enable 1 | 
|  | set_param ibs_fetch/enable 1 | 
|  | else | 
|  | set_param ibs_fetch/enable 0 | 
|  | fi | 
|  |  | 
|  | elif test `echo $EVENT |  \ | 
|  | awk '{ print substr($0, 1, 7)}'` = "IBS_OP_" ; then | 
|  | if test "$COUNT" != "0"; then | 
|  | if [ "$IBS_OP_EVENTS" = "" ] ; then | 
|  | IBS_OP_EVENTS="$EVENT" | 
|  | else | 
|  | IBS_OP_EVENTS="$IBS_OP_EVENTS,$EVENT" | 
|  | fi | 
|  | IBS_OP_COUNT=$COUNT | 
|  | IBS_OP_UNITMASK=$UNIT_MASK | 
|  |  | 
|  | set_param ibs_op/max_count $COUNT | 
|  | set_param ibs_op/enable 1 | 
|  |  | 
|  | # NOTE: We default to use dispatched_op if available. | 
|  | #       Some of the older family10 system does not have | 
|  | #       dispatched_ops feature. | 
|  | #       Dispatched op is enabled by bit 0 of the unitmask | 
|  | IBS_OP_DISPATCHED_OP=$(( IBS_OP_UNITMASK & 0x1 )) | 
|  | if test -f $MOUNT/ibs_op/dispatched_ops ; then | 
|  | set_param ibs_op/dispatched_ops $IBS_OP_DISPATCHED_OP | 
|  | else | 
|  | if test $IBS_OP_DISPATCHED_OP -eq 1 ; then | 
|  | echo "ERROR: IBS Op dispatched ops is not supported." | 
|  | exit 1 | 
|  | fi | 
|  | fi | 
|  |  | 
|  | # NOTE: BTA is enabled by bit 2 of the unitmask | 
|  | IBS_OP_BTA=$(( IBS_OP_UNITMASK & 0x4 )) | 
|  | if test -f $MOUNT/ibs_op/branch_target; then | 
|  | if [ "$IBS_OP_BTA" = "4" ] ; then | 
|  | set_param ibs_op/branch_target 1 | 
|  | else | 
|  | set_param ibs_op/branch_target 0 | 
|  | fi | 
|  |  | 
|  | # TODO: Check if write successful | 
|  | else | 
|  | if test $IBS_OP_BTA -eq 1 ; then | 
|  | echo "ERROR: IBS Op Branch Target Address is not supported." | 
|  | exit 1 | 
|  | fi | 
|  | fi | 
|  | else | 
|  | set_param ibs_op/enable 0 | 
|  | fi | 
|  | fi | 
|  | } | 
|  |  | 
|  |  | 
|  | help_start_daemon_with_ibs() | 
|  | { | 
|  | if test "$IBS_FETCH_COUNT" != "0" -o "$IBS_OP_COUNT" != "0" ; then | 
|  | OPD_ARGS="${OPD_ARGS} --ext-feature=ibs:" | 
|  | if test "$IBS_FETCH_COUNT" != "0"; then | 
|  | OPD_ARGS="${OPD_ARGS}fetch:$IBS_FETCH_EVENTS:$IBS_FETCH_COUNT:$IBS_FETCH_UNITMASK|" | 
|  | fi | 
|  |  | 
|  | if test "$IBS_OP_COUNT" != "0"; then | 
|  | OPD_ARGS="${OPD_ARGS}op:$IBS_OP_EVENTS:$IBS_OP_COUNT:$IBS_OP_UNITMASK" | 
|  | fi | 
|  | fi | 
|  | } | 
|  |  | 
|  | # | 
|  | # End IBS Specific Functions | 
|  | # | 
|  |  | 
|  | # main | 
|  |  | 
|  | # determine the location of opcontrol and related programs | 
|  | if test -z "$OPDIR"; then | 
|  | BINDIR="/usr/bin" | 
|  | OPCONTROL=`$BINDIR/which $0` | 
|  | OPDIR=`$BINDIR/dirname $OPCONTROL` | 
|  | fi | 
|  |  | 
|  | PATH=$OPDIR:/usr/local/bin:/usr/local/sbin:/bin:/sbin:/usr/bin:/usr/sbin | 
|  |  | 
|  | check_options_early $@ | 
|  |  | 
|  | if test -z "$1"; then | 
|  | do_help | 
|  | exit 0 | 
|  | fi | 
|  |  | 
|  | if test `id -u` = "0"; then | 
|  | try_reset_sample_file $@ | 
|  |  | 
|  | load_module | 
|  | fi | 
|  | check_version | 
|  |  | 
|  | # Except --reset, even the few operations allowed as non root needs the | 
|  | # kernel support, if we don't error out now the error message will be obscure | 
|  | check_oprofile_available | 
|  |  | 
|  | do_init | 
|  | if test `id -u` != "0"; then | 
|  | if test -z "$2"; then | 
|  | case "$1" in | 
|  | --dump|-d) | 
|  | ONLY_DUMP=yes | 
|  | do_dump | 
|  | exit 0; | 
|  | ;; | 
|  | --list-events|-l) | 
|  | exec $OPHELP | 
|  | exit 0; | 
|  | ;; | 
|  | *) | 
|  | echo "Normal users are limited to either '--dump' or '--list-events'." >&2 | 
|  | exit 1 | 
|  | ;; | 
|  | esac | 
|  | else | 
|  | echo "Normal users are limited to either '--dump' or '--list-events'." >&2 | 
|  | exit 1 | 
|  | fi | 
|  | fi | 
|  |  | 
|  | do_options $@ | 
|  | do_operations |