#!/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 } # 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() { if [[ "$1" =~ ^0[0-7]*$ ]] ; then return 8; elif [[ "$1" =~ ^0x[0-9a-fA-F]+$ ]] ; then return 16; elif [[ "$1" =~ ^[1-9][0-9]*$ ]] ; then return 10; else return 0; fi } # check value is a valid number error_if_not_number() { guess_number_base $2 if test "$?" -eq 0 ; then echo "Argument for $1, $2, is not a valid number." >&2 exit 1 fi } # 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; 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. --note-table-size kernel notes buffer size in notes units (2.4 kernel) --xen Xen image (for Xen only) --active-domains=<list> List of domains in profiling session (for Xen) (list contains domain ids separated by commas) 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 /etc/mtab >/dev/null if test "$?" -ne 0; then mount -t oprofilefs nodev /dev/oprofile >/dev/null fi KERNEL_SUPPORT=yes OPROFILE_AVAILABLE=yes } load_module_24() { grep oprof /proc/devices >/dev/null if test "$?" -ne 0; then modprobe oprofile if test "$?" != "0"; then # couldn't load a module return fi grep oprofile /proc/modules >/dev/null if test "$?" != "0"; then # didn't find module return fi fi KERNEL_SUPPORT=no OPROFILE_AVAILABLE=yes } load_module() { OPROFILE_AVAILABLE=no load_module_26 if test "$OPROFILE_AVAILABLE" != "yes"; then load_module_24 fi 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 OPROFILED="$OPDIR/oprofiled" # location for daemon setup information SETUP_DIR="/root/.oprofile" SETUP_FILE="$SETUP_DIR/daemonrc" # initialize daemon vars decide_oprofile_device_mount CPUTYPE=`cat $MOUNT/cpu_type` OP_COUNTERS=`ls $MOUNT/ | grep "^[0-9]\+\$" | tr "\n" " "` 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 ia64/*) IS_PERFMON=$KERNEL_SUPPORT ;; esac 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" 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 } # reload all the setup-related information do_load_setup() { if test -f "$SETUP_FILE"; then # load the actual information from file # FIXME this is insecure, arbitrary commands could be added to # $SETUP_FILE and be executed as root . $SETUP_FILE fi } 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}'` if test -z "$UNIT_MASK"; then TMPEVENT="$EVENT:$COUNT" UNIT_MASK=`$OPHELP --unit-mask $TMPEVENT` if test "$?" != 0; then exit 1 fi 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_empty $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_empty $arg $val 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_empty $arg $val 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_empty $arg $val error_if_not_number $arg $val CPU_BUF_SIZE=$val DO_SETUP=yes ;; -e|--event) error_if_empty $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) error_if_empty $arg $val 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_empty $arg $val VMLINUX=$val DO_SETUP=yes ;; --no-vmlinux) VMLINUX=none DO_SETUP=yes ;; --kernel-range) error_if_empty $arg $val KERNEL_RANGE=$val DO_SETUP=yes ;; --xen) error_if_empty $arg $val XENIMAGE=$val DO_SETUP=yes ;; --active-domains) error_if_empty $arg $val ACTIVE_DOMAINS=$val DO_SETUP=yes ;; --note-table-size) error_if_empty $arg $val if test "$KERNEL_SUPPORT" = "yes"; then echo "\"$arg\" meaningless on this kernel" >&2 exit 1 else NOTE_SIZE=$val fi DO_SETUP=yes ;; -i|--image) error_if_empty $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 VERBOSE=$val fi ;; -l|--list-events) EXCLUSIVE_ARGC=`expr $EXCLUSIVE_ARGC + 1` EXCLUSIVE_ARGV="$arg" exec $OPHELP ;; *) 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" } rm_devices_24() { rm_device "$DEVICE_FILE" rm_device "$NOTE_DEVICE_FILE" rm_device "$HASH_MAP_DEVICE_FILE" } create_devices_24() { MAJOR_NR=`grep oprof /proc/devices | awk '{print $1}'` create_device $DEVICE_FILE $MAJOR_NR 0 create_device $NOTE_DEVICE_FILE $MAJOR_NR 2 create_device $HASH_MAP_DEVICE_FILE $MAJOR_NR 1 } # create jitdump directory and remove any old files from # a previous run prep_jitdump() { local dumpdir=$SESSION_DIR/jitdump test -d $dumpdir || { mkdir -p $dumpdir; chmod 777 $dumpdir; return; } # 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" if test "$KERNEL_SUPPORT" != "yes"; then rm_devices_24 create_devices_24 fi 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 -e $MOUNT/$1; then echo $3 >$MOUNT/$1/$2 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/*) tmp="${1/cell/CELL}" if test "$1" = "$tmp"; then #No substituion occurred, so cputype is not cell return 1 else return 0 fi ;; *) return 0; ;; esac } # The check_event_mapping_data procedure gives the # opportunity to validate events and enforce any # arch-specific restritions, etc. check_event_mapping_data() { 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 len=`echo -n $event_num | wc -m` 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 # 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 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))}"` check_event_mapping_data 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 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 check_event_mapping_data. # 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() { 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 echo "Daemon running: pid $OPROFILED_PID" else echo "Daemon not running" fi 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 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 echo do_jitconv >> $SESSION_DIR/opd_pipe 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 /etc/mtab` 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_empty $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 /etc/mtab >/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