| #!/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. |
| --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" |
| 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" " "` |
| 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" |
| 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 |
| 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_NAMED="$UNIT_MASK" |
| UNIT_MASK=`$OPHELP --unit-mask $TMPEVENT` |
| 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 |
| ;; |
| --note-table-size) |
| if test "$KERNEL_SUPPORT" = "yes"; then |
| echo "\"$arg\" meaningless on this kernel" >&2 |
| exit 1 |
| else |
| error_if_not_number "$arg" "$val" |
| NOTE_SIZE=$val |
| fi |
| 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 |
| ;; |
| |
| *) |
| 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/*cell*) |
| return 0 |
| ;; |
| ppc64/*) |
| return 1 |
| ;; |
| *) |
| 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 -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 |
| |
| # 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))}"` |
| 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 |
| |
| EXTRA=`$OPHELP --extra-mask $EVENT:$COUNT:$UNIT_MASK_NAMED` |
| if test "$EXTRA" -ne 0 ; 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 |
| 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 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 |
| 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 |
| |
| 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 |
| 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 /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_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 /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 |