blob: cbb4226c186eda961bb3029bf02fba6bca7c52dc [file] [log] [blame]
Upstreamcc2ee171970-01-12 13:46:40 +00001#!/bin/bash
2#
3# opcontrol is a script to control OProfile
4# opcontrol --help and opcontrol --list-events have info
5#
6# Copyright 2002
7# Read the file COPYING
8#
9# Authors: John Levon, Philippe Elie, Will Cohen
10
11# ensure bash2
12if test "`echo $BASH_VERSION | cut -b1`" -lt 2; then
13 exec /bin/bash2 $0 $@
14fi
15
16
17SYSCTL=do_sysctl
18
19# A replacement function for the sysctl (procps package) utility which is
20# missing on some distribution (e.g. slack 7.0).
21# Handles only the -w option of sysctl.
22do_sysctl()
23{
24 if test "$1" != "-w"; then
25 echo "$0 unknown sysctl option" >&2
26 exit 1
27 fi
28
29 shift
30
31 arg=`echo $1 | awk -F= '{print $1}'`
32 val=`echo $1 | awk -F= '{print $2}'`
33
34 dev_name=`echo $arg | tr . /`
35
36 if test ! -f /proc/sys/$dev_name; then
37 echo "/proc/sys/$dev_name does not exist or is not a regular file" >&2
38 exit 1
39 fi
40 echo $val > /proc/sys/$dev_name
41}
42
43
44# check value is set
45error_if_empty()
46{
47 if test -z "$2"; then
48 echo "No value given for option $1" >&2
49 do_help
50 exit 1
51 fi
52}
53
54
55# rm_device arguments $1=file_name
56function rm_device
57{
58 if test -c "$1"; then
59 vecho "Removing $1"
60 rm "$1"
61 fi
62}
63
64
65# create_device arguments $1=file_name $2=MAJOR_NR $3=MINOR_NR
66function create_device {
67 vecho "Doing mknod $1"
68 mknod "$1" c $2 $3
69 if test "$?" != "0"; then
70 echo "Couldn't mknod $1" >&2
71 exit 1
72 fi
73 chmod 700 "$1"
74}
75
76
77move_and_remove()
78{
79 if test -e $1; then
80 mv $1 $SAMPLES_DIR/.tmp_reset.$$
81 rm -rf $SAMPLES_DIR/.tmp_reset.$$
82 fi
83}
84
85
86# verbose echo
87vecho()
88{
89 if test -n "$VERBOSE"; then
90 echo $@
91 fi
92}
93
94
95# print help message
96do_help()
97{
98 echo "opcontrol: usage:
99 -l/--list-events list event types and unit masks
100 -?/--help this message
101 -v/--version show version
102 --init loads the oprofile module and oprofilefs
103 --setup give setup arguments (may be omitted)
104 --status show configuration
105 --start-daemon start daemon without starting profiling
106 -s/--start start data collection
107 -d/--dump flush the collected profiling data
108 -t/--stop stop data collection
109 -h/--shutdown stop data collection and kill daemon
110 -V/--verbose[=all,sfile,arcs,samples,module,misc] be verbose in the daemon log
111 --reset clears out data from current session
112 --save=name save data from current session to session_name
113 --deinit unload the oprofile module and oprofilefs
114
115 -e/--event=eventspec
116
117 Choose an event. May be specified multiple times. Of the form
118 "default" or "name:count:unitmask:kernel:user", where :
119
120 name: event name, e.g. CPU_CLK_UNHALTED or RTC_INTERRUPTS
121 count: reset counter value e.g. 100000
122 unitmask: hardware unit mask e.g. 0x0f
123 kernel: whether to profile kernel: 0 or 1
124 user: whether to profile userspace: 0 or 1
125
126 -p/--separate=type,[types]
127
128 Separate profiles as follows :
129
130 none: no profile separation
131 library: separate shared library profiles per-application
132 kernel: same as library, plus kernel profiles
133 thread: per-thread/process profiles
134 cpu: per CPU profiles
135 all: all of the above
136
137 -c/--callgraph=#depth enable callgraph sample collection with a maximum depth.
138 Use 0 to disable callgraph profiling.
139
140 -i/--image=name[,names] list of binaries to profile (default is "all")
141 --vmlinux=file vmlinux kernel image
142 --no-vmlinux no kernel image (vmlinux) available
143 --kernel-range=start,end kernel range vma address in hexadecimal
144 --buffer-size=num kernel buffer size in sample units
145 --cpu-buffer-size=num per-cpu buffer size in units (2.6 only)
146 --note-table-size kernel notes buffer size in notes units (2.4 only)
147" >&2
148}
149
150
151# load the module and mount oprofilefs
152load_module_26()
153{
154 grep oprofilefs /proc/filesystems >/dev/null
155 if test "$?" -ne 0; then
156 modprobe oprofile
157 if test "$?" != "0"; then
158 # couldn't load a module
159 return
160 fi
161 grep oprofile /proc/modules >/dev/null
162 if test "$?" != "0"; then
163 # didn't find module
164 return
165 fi
166 fi
167 grep oprofilefs /proc/filesystems >/dev/null
168 if test "$?" -ne 0; then
169 # filesystem still not around
170 return
171 fi
172 mkdir /dev/oprofile >/dev/null 2>&1
173 grep oprofilefs /etc/mtab >/dev/null
174 if test "$?" -ne 0; then
175 mount -t oprofilefs nodev /dev/oprofile >/dev/null
176 fi
177 KERNEL_SUPPORT=yes
178 OPROFILE_AVAILABLE=yes
179}
180
181
182load_module_24()
183{
184 grep oprof /proc/devices >/dev/null
185 if test "$?" -ne 0; then
186 modprobe oprofile
187 if test "$?" != "0"; then
188 # couldn't load a module
189 return
190 fi
191 grep oprofile /proc/modules >/dev/null
192 if test "$?" != "0"; then
193 # didn't find module
194 return
195 fi
196 fi
197 KERNEL_SUPPORT=no
198 OPROFILE_AVAILABLE=yes
199}
200
201
202load_module()
203{
204 OPROFILE_AVAILABLE=no
205 load_module_26
206 if test "$OPROFILE_AVAILABLE" != "yes"; then
207 load_module_24
208 fi
209 if test "$OPROFILE_AVAILABLE" != "yes"; then
210 echo "Kernel doesn't support oprofile" >&2
211 exit 1
212 fi
213}
214
215# setup variables related to daemon
216do_init_daemon_vars()
217{
218 # as in op_user.h
219 DIR="/var/lib/oprofile"
220 LOCK_FILE="/var/lib/oprofile/lock"
221 LOG_FILE="$DIR/oprofiled.log"
222 SAMPLES_DIR="$DIR/samples"
223 CURRENT_SAMPLES_DIR=${SAMPLES_DIR}/current
224}
225
226# pick the appropriate locations device for oprofile based on kernel
227decide_oprofile_device()
228{
229 if test "$KERNEL_SUPPORT" = "yes"; then
230 MOUNT="/dev/oprofile"
231 DEVICE_FILE="$MOUNT/buffer"
232 else
233 MOUNT="/proc/sys/dev/oprofile"
234 DEVICE_FILE="$DIR/opdev"
235 NOTE_DEVICE_FILE="$DIR/opnotedev"
236 HASH_MAP_DEVICE_FILE="$DIR/ophashmapdev"
237 fi
238}
239
240# initialise parameters
241do_init()
242{
243 # for these three buffer size == 0 means use the default value
244 # hard-coded in op_user.h
245 BUF_SIZE=0
246 CPU_BUF_SIZE=0
247 NOTE_SIZE=0
248 VMLINUX=
249 VERBOSE=""
250 SEPARATE_LIB=0
251 SEPARATE_KERNEL=0
252 SEPARATE_THREAD=0
253 SEPARATE_CPU=0
254 CALLGRAPH=0
255
256 OPROFILED="$OPDIR/oprofiled"
257
258 # location for daemon setup information
259 SETUP_DIR="/root/.oprofile"
260 SETUP_FILE="$SETUP_DIR/daemonrc"
261
262 CPUTYPE=`cat $MOUNT/cpu_type`
263 OP_COUNTERS=`ls $MOUNT/ | grep "^[0-9]\+\$" | tr "\n" " "`
264 NR_CHOSEN=0
265
266 DEFAULT_EVENT=`$OPHELP --get-default-event`
267
268 IS_TIMER=0
269 IS_PERFMON=0
270 if test "$CPUTYPE" = "timer"; then
271 IS_TIMER=1
272 else
273 case "$CPUTYPE" in
274 ia64/*)
275 IS_PERFMON=$KERNEL_SUPPORT
276 ;;
277 esac
278 fi
279}
280
281
282create_dir()
283{
284 if test ! -d "$1"; then
285 mkdir -p "$1"
286 if test "$?" != "0"; then
287 echo "Couldn't mkdir -p $1" >&2
288 exit 1
289 fi
290 chmod 755 "$1"
291 fi
292}
293
294
295# save all the setup related information
296do_save_setup()
297{
298 create_dir "$SETUP_DIR"
299
300 touch $SETUP_FILE
301 chmod 644 $SETUP_FILE
302 >$SETUP_FILE
303
304 if test "$NR_CHOSEN" != "0"; then
305 for f in `seq 0 $((NR_CHOSEN - 1))`; do
306 echo "CHOSEN_EVENTS[${f}]=${CHOSEN_EVENTS[$f]}" >>$SETUP_FILE
307 done
308 fi
309
310 echo "NR_CHOSEN=$NR_CHOSEN" >>$SETUP_FILE
311
312 echo "SEPARATE_LIB=$SEPARATE_LIB" >> $SETUP_FILE
313 echo "SEPARATE_KERNEL=$SEPARATE_KERNEL" >> $SETUP_FILE
314 echo "SEPARATE_THREAD=$SEPARATE_THREAD" >> $SETUP_FILE
315 echo "SEPARATE_CPU=$SEPARATE_CPU" >> $SETUP_FILE
316 echo "VMLINUX=$VMLINUX" >> $SETUP_FILE
317 echo "IMAGE_FILTER=$IMAGE_FILTER" >> $SETUP_FILE
318 # write the actual information to file
319 if test "$BUF_SIZE" != "0"; then
320 echo "BUF_SIZE=$BUF_SIZE" >> $SETUP_FILE
321 fi;
322 if test "$KERNEL_SUPPORT" = "yes"; then
323 echo "CPU_BUF_SIZE=$CPU_BUF_SIZE" >> $SETUP_FILE
324 fi
325 if test "$KERNEL_SUPPORT" != "yes"; then
326 echo "NOTE_SIZE=$NOTE_SIZE" >> $SETUP_FILE
327 fi
328 echo "CALLGRAPH=$CALLGRAPH" >> $SETUP_FILE
329}
330
331
332# reload all the setup-related information
333do_load_setup()
334{
335 if test -f "$SETUP_FILE"; then
336 # load the actual information from file
337 # FIXME this is insecure, arbitrary commands could be added to
338 # $SETUP_FILE and be executed as root
339 source $SETUP_FILE
340 fi
341
342 vecho "Parameters used:"
343 vecho "CPUTYPE $CPUTYPE"
344 if test "$BUF_SIZE" != "0"; then
345 vecho "BUF_SIZE $BUF_SIZE"
346 else
347 vecho "BUF_SIZE default value"
348 fi;
349 if test "$KERNEL_SUPPORT" = "yes"; then
350 if test "$CPU_BUF_SIZE" != "0"; then
351 vecho "CPU_BUF_SIZE $CPU_BUF_SIZE"
352 else
353 vecho "CPU_BUF_SIZE default value"
354 fi;
355 fi
356
357 vecho "SEPARATE_LIB $SEPARATE_LIB"
358 vecho "SEPARATE_KERNEL $SEPARATE_KERNEL"
359 vecho "SEPARATE_THREAD $SEPARATE_THREAD"
360 vecho "SEPARATE_CPU $SEPARATE_CPU"
361 vecho "CALLGRAPH $CALLGRAPH"
362 vecho "VMLINUX $VMLINUX"
363}
364
365
366check_valid_args()
367{
368 if test -z "$VMLINUX"; then
369 echo "No vmlinux file specified. You must specify the correct vmlinux file, e.g." >&2
370 echo "opcontrol --vmlinux=/path/to/vmlinux" >&2
371 echo "If you do not have a vmlinux file, use " >&2
372 echo "opcontrol --no-vmlinux" >&2
373 echo "Enter opcontrol --help for full options" >&2
374 exit 1
375 fi
376
377 if test -f "$VMLINUX"; then
378 return
379 fi
380
381 if test "$VMLINUX" = "none"; then
382 return
383 fi
384
385 echo "The specified vmlinux file \"$VMLINUX\" doesn't exist." >&2
386 exit 1
387}
388
389
390# get start and end points of the kernel
391get_kernel_range()
392{
393 if test ! -z "$KERNEL_RANGE"; then
394 return;
395 fi
396
397 if test "$VMLINUX" = "none"; then
398 return;
399 fi
400
401 # start at the start of .text and then continue to the end
402 range_info=`objdump -h $VMLINUX 2>/dev/null | grep " .text "`
403 tmp1=`echo $range_info | awk '{print $4}'`
404 tmp_length=`echo $range_info | awk '{print $3}'`
405 tmp2=`objdump -h $VMLINUX --adjust-vma=0x$tmp_length 2>/dev/null | grep " .text " | awk '{print $4}'`
406
407 if test -z "$tmp1" -o -z "$tmp2"; then
408 echo "The specified file $VMLINUX does not seem to be valid" >&2
409 echo "Make sure you are using vmlinux not vmlinuz" >&2
410 vecho "found start as \"$tmp1\", end as \"$tmp2\"" >&2
411 exit 1
412 fi
413
414 KERNEL_RANGE="`echo $tmp1`,`echo $tmp2`"
415 vecho "KERNEL_RANGE $KERNEL_RANGE"
416}
417
418
419# validate --separate= parameters. This function is called with IFS=,
420# so on each argument is splitted
421validate_separate_args()
422{
423 error_if_empty $1 $2 # we need at least one argument
424 local i=1
425 SEPARATE_LIB=0
426 SEPARATE_KERNEL=0
427 SEPARATE_THREAD=0
428 SEPARATE_CPU=0
429 while (($i < $#)); do
430 shift
431 case "$1" in
432 lib|library)
433 SEPARATE_LIB=1
434 ;;
435 kernel)
436 # first implied by second
437 SEPARATE_LIB=1
438 SEPARATE_KERNEL=1
439 ;;
440 thread)
441 SEPARATE_THREAD=1
442 ;;
443 cpu)
444 SEPARATE_CPU=1
445 ;;
446 all)
447 SEPARATE_LIB=1
448 SEPARATE_KERNEL=1
449 SEPARATE_THREAD=1
450 SEPARATE_CPU=1
451 ;;
452 none)
453 SEPARATE_LIB=0
454 SEPARATE_KERNEL=0
455 SEPARATE_THREAD=0
456 SEPARATE_CPU=0
457 ;;
458 *)
459 echo "invalid --separate= argument: $1"
460 exit 1
461 esac
462 done
463}
464
465
466# check the counters make sense, and resolve the hardware allocation
467verify_counters()
468{
469 if test "$IS_TIMER" = 1; then
470 if test "$NR_CHOSEN" != 0; then
471 echo "You cannot specify any performance counter events" >&2
472 echo "because OProfile is in timer mode." >&2
473 exit 1
474 fi
475 return
476 fi
477
478 OPHELP_ARGS=
479
480 if test "$NR_CHOSEN" != 0; then
481 for f in `seq 0 $((NR_CHOSEN - 1))`; do
482 if test "${CHOSEN_EVENTS[$f]}" != ""; then
483 OPHELP_ARGS="$OPHELP_ARGS ${CHOSEN_EVENTS[$f]}"
484 fi
485 done
486
487 HW_CTRS=`$OPHELP --check-events $OPHELP_ARGS --callgraph=$CALLGRAPH`
488 if test "$?" != 0; then
489 exit 1
490 fi
491 fi
492}
493
494
495# setup any needed default value in chosen events
496normalise_events()
497{
498 if test "$NR_CHOSEN" -le 0; then
499 return
500 fi
501
502 for f in `seq 0 $((NR_CHOSEN - 1))`; do
503 if test "${CHOSEN_EVENTS[$f]}" != ""; then
504 EVENT=`echo ${CHOSEN_EVENTS[$f]} | awk -F: '{print $1}'`
505 EVENT_VAL=`$OPHELP $EVENT`
506 if test "$?" != 0; then
507 exit 1
508 fi
509 COUNT=`echo ${CHOSEN_EVENTS[$f]} | awk -F: '{print $2}'`
510 UNIT_MASK=`echo ${CHOSEN_EVENTS[$f]} | awk -F: '{print $3}'`
511 KERNEL=`echo ${CHOSEN_EVENTS[$f]} | awk -F: '{print $4}'`
512 USER=`echo ${CHOSEN_EVENTS[$f]} | awk -F: '{print $5}'`
513 if test -z "$UNIT_MASK"; then
514 TMPEVENT="$EVENT:$COUNT"
515 UNIT_MASK=`$OPHELP --unit-mask $TMPEVENT`
516 if test "$?" != 0; then
517 exit 1
518 fi
519 fi
520 if test -z "$KERNEL"; then
521 KERNEL=1
522 fi
523 if test -z "$USER"; then
524 USER=1
525 fi
526
527 CHOSEN_EVENTS[$f]=$EVENT:$COUNT:$UNIT_MASK:$KERNEL:$USER
528 fi
529 done
530}
531
532
533# get and check specified options
534do_options()
535{
536 EXCLUSIVE_ARGC=0
537 SETUP=no
538 NEED_SETUP=no
539 SEEN_EVENT=0
540
541 # load any default settings
542 do_load_setup
543
544 while [ "$#" -ne 0 ]
545 do
546 arg=`printf %s $1 | awk -F= '{print $1}'`
547 val=`printf %s $1 | awk -F= '{print $2}'`
548 shift
549 if test -z "$val"; then
550 local possibleval=$1
551 printf %s $1 "$possibleval" | grep ^- >/dev/null 2>&1
552 if test "$?" != "0"; then
553 val=$possibleval
554 shift
555 fi
556 fi
557
558 case "$arg" in
559
560 --init)
561 # this is already done in load_module
562 # because need to know the processor type
563 # and number of registers
564 INIT=yes;
565 EXCLUSIVE_ARGC=`expr $EXCLUSIVE_ARGC + 1`
566 EXCLUSIVE_ARGV="$arg"
567 ;;
568
569 --setup)
570 SETUP=yes
571 ;;
572
573 --start-daemon)
574 if test "$KERNEL_SUPPORT" != "yes"; then
575 echo "$arg unsupported. use \"--start\"" >&2
576 exit 1
577 fi
578 START_DAEMON=yes
579 EXCLUSIVE_ARGC=`expr $EXCLUSIVE_ARGC + 1`
580 EXCLUSIVE_ARGV="$arg"
581 ;;
582
583 -s|--start)
584 START=yes
585 EXCLUSIVE_ARGC=`expr $EXCLUSIVE_ARGC + 1`
586 EXCLUSIVE_ARGV="$arg"
587 ;;
588
589 -d|--dump)
590 DUMP=yes
591 ONLY_DUMP=yes
592 EXCLUSIVE_ARGC=`expr $EXCLUSIVE_ARGC + 1`
593 EXCLUSIVE_ARGV="$arg"
594 ;;
595
596 -t|--stop)
597 if test "$KERNEL_SUPPORT" != "yes"; then
598 echo "$arg unsupported. use \"--shutdown\"" >&2
599 exit 1
600 fi
601 DUMP=yes
602 STOP=yes
603 EXCLUSIVE_ARGC=`expr $EXCLUSIVE_ARGC + 1`
604 EXCLUSIVE_ARGV="$arg"
605 ;;
606
607 -h|--shutdown)
608 DUMP=yes
609 STOP=yes
610 KILL_DAEMON=yes
611 EXCLUSIVE_ARGC=`expr $EXCLUSIVE_ARGC + 1`
612 EXCLUSIVE_ARGV="$arg"
613 ;;
614
615 --status)
616 STATUS=yes
617 ;;
618
619 --reset)
620 DUMP=yes
621 RESET=yes
622 EXCLUSIVE_ARGC=`expr $EXCLUSIVE_ARGC + 1`
623 EXCLUSIVE_ARGV="$arg"
624 ;;
625
626 --save)
627 error_if_empty $arg $val
628 DUMP=yes
629 SAVE_SESSION=yes
630 SAVE_NAME=$val
631 EXCLUSIVE_ARGC=`expr $EXCLUSIVE_ARGC + 1`
632 EXCLUSIVE_ARGV="$arg"
633 ;;
634
635 --deinit)
636 DUMP=yes
637 STOP=yes
638 KILL_DAEMON=yes
639 DEINIT=yes
640 EXCLUSIVE_ARGC=`expr $EXCLUSIVE_ARGC + 1`
641 EXCLUSIVE_ARGV="$arg"
642 ;;
643
644 # --setup options
645
646 --buffer-size)
647 error_if_empty $arg $val
648 BUF_SIZE=$val
649 DO_SETUP=yes
650 ;;
651 --cpu-buffer-size)
652 if test "$KERNEL_SUPPORT" != "yes"; then
653 echo "$arg unsupported for this kernel version"
654 exit 1
655 fi
656 error_if_empty $arg $val
657 CPU_BUF_SIZE=$val
658 DO_SETUP=yes
659 ;;
660 -e|--event)
661 error_if_empty $arg $val
662 # reset any read-in defaults from daemonrc
663 if test "$SEEN_EVENT" = "0"; then
664 NR_CHOSEN=0
665 SEEN_EVENT=1
666 fi
667 if test "$val" = "default"; then
668 val=$DEFAULT_EVENT
669 fi
670 CHOSEN_EVENTS[$NR_CHOSEN]=$val
671 NR_CHOSEN=`expr $NR_CHOSEN + 1`
672 DO_SETUP=yes
673 ;;
674 -p|--separate)
675 OLD_IFS=$IFS
676 IFS=,
677 validate_separate_args $arg $val
678 IFS=$OLD_IFS
679 DO_SETUP=yes
680 ;;
681 -c|--callgraph)
682 error_if_empty $arg $val
683 if test ! -f $MOUNT/backtrace_depth; then
684 echo "Call-graph profiling unsupported on this kernel/hardware" >&2
685 exit 1
686 fi
687 CALLGRAPH=$val
688 DO_SETUP=yes
689 ;;
690 --vmlinux)
691 error_if_empty $arg $val
692 VMLINUX=$val
693 DO_SETUP=yes
694 # check validity
695 get_kernel_range
696 ;;
697 --no-vmlinux)
698 VMLINUX=none
699 DO_SETUP=yes
700 ;;
701 --kernel-range)
702 error_if_empty $arg $val
703 KERNEL_RANGE=$val
704 DO_SETUP=yes
705 ;;
706 --note-table-size)
707 error_if_empty $arg $val
708 if test $"KERNEL_SUPPORT" = "yes"; then
709 echo "\"$arg\" meaningless on this kernel" >&2
710 exit 1
711 else
712 NOTE_SIZE=$val
713 fi
714 DO_SETUP=yes
715 ;;
716 -i|--image)
717 error_if_empty $arg $val
718 if test "$val" = "all"; then
719 IMAGE_FILTER=
720 else
721 IMAGE_FILTER=$val
722 fi
723 DO_SETUP=yes
724 ;;
725
726 -V|--verbose)
727 if test -z "$val"; then
728 VERBOSE="all"
729 else
730 VERBOSE=$val
731 fi
732 ;;
733
734 -l|--list-events)
735 EXCLUSIVE_ARGC=`expr $EXCLUSIVE_ARGC + 1`
736 EXCLUSIVE_ARGV="$arg"
737 exec $OPHELP
738 ;;
739
740 *)
741 echo "Unknown option \"$arg\". See opcontrol --help" >&2
742 exit 1
743 ;;
744 esac
745 done
746
747 normalise_events
748 verify_counters
749
750 # error checking to make sure options make sense
751 if test "$EXCLUSIVE_ARGC" -gt 1; then
752 echo "Option \"$EXCLUSIVE_ARGV\" not valid with other options." >&2
753 exit 1
754 fi
755
756 if test "$SETUP" = "yes" -a "$DO_SETUP" != "yes"; then
757 echo "No options specified for --setup." >&2
758 exit 1
759 fi
760
761 if test -n "$VERBOSE"; then
762 if test "$START" != "yes" -a "$START_DAEMON" != "yes"; then
763 echo "Option --verbose may only be used with --start or --start-daemon" >&2
764 exit 1
765 fi
766 fi
767
768 if test "$DO_SETUP" = "yes"; then
769 SETUP="$DO_SETUP"
770 fi
771
772 if test "$EXCLUSIVE_ARGC" -eq 1 -a "$SETUP" = "yes"; then
773 if test "$EXCLUSIVE_ARGV" != "--start-daemon" -a "$EXCLUSIVE_ARGV" != "--start"; then
774 echo "Option \"--setup\" not valid with \"$EXCLUSIVE_ARGV\"." >&2
775 exit 1
776 fi
777 fi
778}
779
780
781# stop any existing daemon
782do_stop()
783{
784 if test ! -f "$LOCK_FILE"; then
785 echo "Daemon not running" >&2
786 return
787 fi
788
789 kill -s 0 `cat $LOCK_FILE` 2>/dev/null
790 if test "$?" -ne 0; then
791 echo "Detected stale lock file. Removing." >&2
792 rm -f "$LOCK_FILE"
793 return
794 fi
795
796 if test $KERNEL_SUPPORT = "yes"; then
797 echo "Stopping profiling."
798 echo 0 >/dev/oprofile/enable
799 fi
800 kill -s USR2 `cat $LOCK_FILE` 2>/dev/null
801}
802
803
804# kill the daemon process(es)
805do_kill_daemon()
806{
807 if test ! -f "$LOCK_FILE"; then
808 # no error message, do_kill_deamon imply stop and stop already
809 # output "Daemon not running"
810 return
811 fi
812
813 kill -s 0 `cat $LOCK_FILE` 2>/dev/null
814 if test "$?" -ne 0; then
815 echo "Detected stale lock file. Removing." >&2
816 rm -f "$LOCK_FILE"
817 return
818 fi
819
820 echo "Killing daemon."
821
822 if test $KERNEL_SUPPORT = "yes"; then
823 kill -TERM `cat $LOCK_FILE`
824 else
825 echo 1 >/proc/sys/dev/oprofile/dump_stop
826 fi
827
828 COUNT=0
829 while test -n "`pidof oprofiled`"
830 do
831 sleep 1
832
833 # because oprofiled only sets a variable inside the
834 # signal handler itself, it's possible to miss a
835 # signal just before it goes to sleep waiting for
836 # data from the kernel that never arrives. So we
837 # remind it it needs to die - this works because
838 # the signal will bring oprofiled out of the kernel
839 # back into userspace
840 if test $KERNEL_SUPPORT = "yes"; then
841 pid=`cat $LOCK_FILE 2>/dev/null`
842 kill -TERM "$pid" 2>/dev/null
843 fi
844
845 COUNT=`expr $COUNT + 1`
846 if test "$COUNT" -eq 15; then
847 echo "Daemon stuck shutting down; killing !"
848 kill -9 `cat $LOCK_FILE`
849 fi
850 done
851
852 # already removed unless we forced the kill
853 rm -f /var/lib/oprofile/lock
854}
855
856
857rm_devices_24()
858{
859 rm_device "$DEVICE_FILE"
860 rm_device "$NOTE_DEVICE_FILE"
861 rm_device "$HASH_MAP_DEVICE_FILE"
862}
863
864
865create_devices_24()
866{
867 MAJOR_NR=`grep oprof /proc/devices | awk '{print $1}'`
868
869 create_device $DEVICE_FILE $MAJOR_NR 0
870 create_device $NOTE_DEVICE_FILE $MAJOR_NR 2
871 create_device $HASH_MAP_DEVICE_FILE $MAJOR_NR 1
872}
873
874
875# setup and start module
876do_setup()
877{
878 create_dir "$DIR"
879
880 >$LOG_FILE
881
882 if test "$KERNEL_SUPPORT" != "yes"; then
883 rm_devices_24
884 create_devices_24
885 fi
886
887 create_dir "$CURRENT_SAMPLES_DIR"
888}
889
890
891# set a sysctl/oprofilefs parameter
892set_param()
893{
894 if test "$KERNEL_SUPPORT" = "yes"; then
895 echo $2 >$MOUNT/$1
896 else
897 $SYSCTL -w dev.oprofile.$1=$2
898 fi
899}
900
901
902# set a sysctl/oprofilefs counter parameter
903set_ctr_param()
904{
905 # no such thing for perfmon
906 if test "$IS_PERFMON" = "yes"; then
907 return
908 fi
909
910 if test "$KERNEL_SUPPORT" = "yes"; then
911 echo $3 >$MOUNT/$1/$2
912 else
913 $SYSCTL -w dev.oprofile.$1.$2=$3
914 fi
915}
916
917
918# If EVENT_STR has more than one token in it (i.e., the event ID),
919# this implies some additional information is present that is associated
920# with the event. For example, for PPC64 architectures, the values
921# required to program the MMCRs for the given event are returned along
922# with the event. This function will perform any needed validation
923# of such event mapping data.
924check_event_mapping_data()
925{
926
927 if [ "$CPUTYPE" = "ppc64/power4" -o "$CPUTYPE" = "ppc64/power5" -o "$CPUTYPE" = "ppc64/970" ]; then
928 MMCR0=`echo $EVENT_STR | awk '{print $2}'`
929 MMCR1=`echo $EVENT_STR | awk '{print $3}'`
930 MMCRA=`echo $EVENT_STR | awk '{print $4}'`
931 MMCR0_VAL=`echo $MMCR0 | awk -F: '{print $2}'`
932 MMCR1_VAL=`echo $MMCR1 | awk -F: '{print $2}'`
933 MMCRA_VAL=`echo $MMCRA | awk -F: '{print $2}'`
934
935 ## mmcr0, mmcr1, mmcra are for all ppc64 counters
936 # Save first event mmcr settings to compare with additional
937 # events. All events must have the same mmcrx values i.e. be in
938 # the same group. Only one event is assigned per counter,
939 # hence there will not be a conflict on the counters
940 if [ "$MMCR0_CK_VAL" = "" ] ; then
941 MMCR0_CK_VAL=$MMCR0_VAL
942 MMCR1_CK_VAL=$MMCR1_VAL
943 MMCRA_CK_VAL=$MMCRA_VAL
944 else
945 # make sure all events are from the same group
946 if test $MMCR0_CK_VAL != $MMCR0_VAL \
947 -o $MMCR1_CK_VAL != $MMCR1_VAL \
948 -o $MMCRA_CK_VAL != $MMCRA_VAL ; then
949 echo "ERROR: The specified events are not from the same group."
950 echo " Use 'opcontrol --list-events' to see event groupings."
951 exit 1
952 fi
953 fi
954 fi
955}
956
957
958do_param_setup()
959{
960 # different names
961 if test $BUF_SIZE != 0; then
962 if test "$KERNEL_SUPPORT" = "yes"; then
963 echo $BUF_SIZE >$MOUNT/buffer_size
964 else
965 $SYSCTL -w dev.oprofile.bufsize=$BUF_SIZE
966 fi
967 fi
968
969 if test $CPU_BUF_SIZE != 0; then
970 if test "$KERNEL_SUPPORT" = "yes"; then
971 echo $CPU_BUF_SIZE >$MOUNT/cpu_buffer_size
972 else
973 echo "cpu-buffer-size not supported - ignored" >&2
974 fi
975 fi
976
977 if test $NOTE_SIZE != 0; then
978 set_param notesize $NOTE_SIZE
979 fi
980
981 if test "$KERNEL_SUPPORT" = "yes" -a -f $MOUNT/backtrace_depth; then
982 set_param backtrace_depth $CALLGRAPH
983 elif test "$CALLGRAPH" != "0"; then
984 echo "Call-graph profiling not supported - ignored" >&2
985 fi
986
987 if test "$IS_TIMER" = 1; then
988 return
989 fi
990
991 # use the default setup if none set
992 if test "$NR_CHOSEN" = 0; then
993 CHOSEN_EVENTS[0]=$DEFAULT_EVENT
994 NR_CHOSEN=1
995 HW_CTRS=`$OPHELP --check-events $DEFAULT_EVENT --callgraph=$CALLGRAPH`
996 echo "Using default event: ${CHOSEN_EVENTS[0]}"
997 fi
998
999 # Necessary in this case :
1000 # opcontrol ctr0-on ctr1-on then opcontrol ctr0-on
1001 for f in $OP_COUNTERS ; do
1002 set_ctr_param $f enabled 0
1003 set_ctr_param $f event 0
1004 set_ctr_param $f count 0
1005 done
1006
1007 verify_counters
1008
1009 OPROFILED_EVENTS=
1010 for f in `seq 0 $((NR_CHOSEN - 1))`; do
1011 if test "${CHOSEN_EVENTS[$f]}" != ""; then
1012 EVENT=`echo ${CHOSEN_EVENTS[$f]} | awk -F: '{print $1}'`
1013 EVENT_STR=`$OPHELP $EVENT`
1014 # For some architectures, additional information associated with given
1015 # event is returned in EVENT_STR, so we validate this information if necessary
1016 check_event_mapping_data
1017 EVENT_VAL=`echo $EVENT_STR | awk '{print $1}'`
1018 COUNT=`echo ${CHOSEN_EVENTS[$f]} | awk -F: '{print $2}'`
1019 UNIT_MASK=`echo ${CHOSEN_EVENTS[$f]} | awk -F: '{print $3}'`
1020 KERNEL=`echo ${CHOSEN_EVENTS[$f]} | awk -F: '{print $4}'`
1021 USER=`echo ${CHOSEN_EVENTS[$f]} | awk -F: '{print $5}'`
1022 CTR=`echo $HW_CTRS | awk "{print \\$$((f + 1))}"`
1023
1024 if test "$EVENT" = "RTC_INTERRUPTS"; then
1025 set_param rtc_value $COUNT
1026 $SYSCTL -w dev.oprofile.rtc_value=$COUNT
1027 else
1028 set_ctr_param $CTR enabled 1
1029 set_ctr_param $CTR event $EVENT_VAL
1030 let loop_count=1
1031 for i in ${EVENT_STR}; do
1032 #Skip first argument of EVENT_STR (event val) since we've already
1033 #processed that value.
1034 if test "$loop_count" -gt 1; then
1035 KEY=`echo $i | awk -F: '{print $1}'`
1036 VAL=`echo $i | awk -F: '{print $2}'`
1037 set_ctr_param "" $KEY $VAL
1038 fi
1039 let loop_count="$loop_count"+1
1040 done
1041 set_ctr_param $CTR count $COUNT
1042 set_ctr_param $CTR kernel $KERNEL
1043 set_ctr_param $CTR user $USER
1044 set_ctr_param $CTR unit_mask $UNIT_MASK
1045 fi
1046 OPROFILED_EVENTS=${OPROFILED_EVENTS}$EVENT:$EVENT_VAL:
1047 OPROFILED_EVENTS=${OPROFILED_EVENTS}$CTR:$COUNT:$UNIT_MASK:
1048 OPROFILED_EVENTS=${OPROFILED_EVENTS}$KERNEL:$USER,
1049 fi
1050 done
1051}
1052
1053
1054do_start_daemon()
1055{
1056
1057 if test -f "$LOCK_FILE"; then
1058 kill -s 0 `cat $LOCK_FILE` 2>/dev/null
1059 if test "$?" -eq 0; then
1060 return;
1061 else
1062 echo "Detected stale lock file. Removing." >&2
1063 rm -f "$LOCK_FILE"
1064 fi
1065 fi
1066
1067 do_setup
1068 do_load_setup
1069 check_valid_args
1070 get_kernel_range
1071 do_param_setup
1072
1073 OPD_ARGS=" \
1074 --separate-lib=$SEPARATE_LIB \
1075 --separate-kernel=$SEPARATE_KERNEL \
1076 --separate-thread=$SEPARATE_THREAD \
1077 --separate-cpu=$SEPARATE_CPU"
1078
1079 OPD_ARGS="$OPD_ARGS --events=$OPROFILED_EVENTS"
1080
1081 if test "$VMLINUX" = "none"; then
1082 OPD_ARGS="$OPD_ARGS --no-vmlinux"
1083 else
1084 OPD_ARGS="$OPD_ARGS --vmlinux=$VMLINUX --kernel-range=$KERNEL_RANGE"
1085 fi
1086
1087 if ! test -z "$IMAGE_FILTER"; then
1088 OPD_ARGS="$OPD_ARGS --image=$IMAGE_FILTER"
1089 fi
1090
1091 if test -n "$VERBOSE"; then
1092 OPD_ARGS="$OPD_ARGS --verbose=$VERBOSE"
1093 fi
1094
1095 vecho "executing oprofiled $OPD_ARGS"
1096
1097 $OPROFILED $OPD_ARGS
1098
1099 COUNT=0
1100 while ! test -f "$DIR/lock"
1101 do
1102 sleep 1
1103 COUNT=`expr $COUNT + 1`
1104 if test "$COUNT" -eq 10; then
1105 echo "Couldn't start oprofiled." >&2
1106 echo "Check the log file \"$LOG_FILE\" and kernel syslog" >&2
1107 exit 1
1108 fi
1109 done
1110
1111 echo "Daemon started."
1112}
1113
1114
1115do_start()
1116{
1117 if test "$KERNEL_SUPPORT" = "yes"; then
1118 echo 1 >$MOUNT/enable
1119 fi
1120 kill -s USR1 `cat $LOCK_FILE` 2>/dev/null
1121 echo "Profiler running."
1122}
1123
1124
1125# print status
1126do_status()
1127{
1128 OPROFILED_PID=`cat $DIR/lock 2>/dev/null`
1129 if test -n "$OPROFILED_PID" -a -d "/proc/$OPROFILED_PID"; then
1130 echo "Daemon running: pid $OPROFILED_PID"
1131 else
1132 echo "Daemon not running"
1133 fi
1134
1135 if test "$NR_CHOSEN" != "0"; then
1136 for f in `seq 0 $((NR_CHOSEN - 1))`; do
1137 echo "Event 0: ${CHOSEN_EVENTS[$f]}"
1138 done
1139 fi
1140
1141 SEPARATE=""
1142 if test "$SEPARATE_LIB" = "1"; then
1143 SEPARATE="library";
1144 fi
1145 if test "$SEPARATE_KERNEL" = "1"; then
1146 SEPARATE="$SEPARATE kernel";
1147 fi
1148 if test "$SEPARATE_THREAD" = "1"; then
1149 SEPARATE="$SEPARATE thread";
1150 fi
1151 if test "$SEPARATE_CPU" = "1"; then
1152 SEPARATE="$SEPARATE cpu";
1153 fi
1154
1155 if test -z "$SEPARATE"; then
1156 SEPARATE=none
1157 fi
1158
1159 echo "Separate options: $SEPARATE"
1160 echo "vmlinux file: $VMLINUX"
1161
1162 if test -z "$IMAGE_FILTER"; then
1163 echo "Image filter: none"
1164 else
1165 echo "Image filter: $IMAGE_FILTER"
1166 fi
1167
1168 echo "Call-graph depth: $CALLGRAPH"
1169 if test "$BUF_SIZE" != "0"; then
1170 echo "Buffer size: $BUF_SIZE"
1171 fi;
1172 if test "$KERNEL_SUPPORT" != "yes"; then
1173 if test "$NOTE_SIZE" != "0"; then
1174 echo "Note buffer size: $NOTE_SIZE"
1175 fi
1176 else
1177 if test "$CPU_BUF_SIZE" != "0"; then
1178 echo "CPU buffer size: $CPU_BUF_SIZE"
1179 fi
1180 fi
1181
1182 exit 0
1183}
1184
1185
1186# do_dump_data
1187# returns 0 if successful
1188# returns 1 if the daemon is unable to dump data
1189# exit 1 if we need to be root to dump
1190do_dump_data()
1191{
1192 # make sure that the daemon is not dead and gone
1193 if test -e "$DIR/lock"; then
1194 OPROFILED_PID=`cat $DIR/lock`
1195 if test ! -d "/proc/$OPROFILED_PID"; then
1196 echo "dump fail: daemon died during last run ?" >&2
1197 return 1;
1198 fi
1199 else
1200 return 1;
1201 fi
1202
1203 if test "$KERNEL_SUPPORT" = "yes"; then
1204 # find current time
1205 TMPFILE=`mktemp /tmp/oprofile.XXXXXX` || exit 1
1206 if ! test -w $MOUNT/dump; then
1207 if test "$UID" != "0"; then
1208 echo "You must be root to dump with this kernel version"
1209 exit 1
1210 fi
1211 fi
1212 echo 1 > $MOUNT/dump
1213 # loop until there is a file to check and
1214 # the modification data of $MOUNT/dump after TMPFILE
1215 while [ \( ! -e "$DIR/complete_dump" \) -o \( "$TMPFILE" -nt "$DIR/complete_dump" \) ]
1216 do
1217 if test ! -d "/proc/$OPROFILED_PID"; then
1218 rm $TMPFILE
1219 echo "dump fail: either daemon died during last run or dies during dump" >&2
1220 return 1
1221 fi
1222 sleep 1;
1223 done
1224 rm $TMPFILE
1225 else
1226 echo 1 > $MOUNT/dump
1227 # HACK !
1228 sleep 2
1229 fi
1230 return 0;
1231}
1232
1233# do_dump
1234# returns 0 if successful
1235# exits if unsuccessful
1236do_dump()
1237{
1238 do_dump_data
1239 if test $? -ne 0 -a "$ONLY_DUMP" = "yes"; then
1240 echo "Unable to complete dump of oprofile data: is the oprofile daemon running?" >& 2
1241 exit 1;
1242 fi
1243 return 0;
1244}
1245
1246# tell daemon to re-open the sample files
1247hup_daemon()
1248{
1249 if test -f "$LOCK_FILE"; then
1250 echo -n "Signalling daemon... "
1251 kill -HUP `cat $LOCK_FILE`
1252 echo "done"
1253 fi
1254}
1255
1256
1257# move all the sample files to a sample directory
1258do_save_session()
1259{
1260 SAVE_DIR="${SAMPLES_DIR}/${SAVE_NAME}"
1261
1262 if test -e "$SAVE_DIR"; then
1263 echo "session $SAVE_DIR already exists" >&2
1264 exit 1
1265 fi
1266
1267 if ! test -e $CURRENT_SAMPLES_DIR; then
1268 echo "$CURRENT_SAMPLES_DIR doesn't exist: nothing to save" >&2
1269 exit 0
1270 fi
1271
1272 # FIXME: I don't think it's worth checking for empty current directory
1273
1274 mv $CURRENT_SAMPLES_DIR $SAVE_DIR
1275 if test "$?" != "0"; then
1276 echo "Couldn't move $CURRENT_SAMPLES_DIR to $SAVE_DIR" >&2
1277 exit 1
1278 fi
1279
1280 hup_daemon
1281}
1282
1283
1284# remove all the sample files
1285do_reset()
1286{
1287 if test -z "$SAMPLES_DIR"; then
1288 echo "opcontrol:do_reset() SAMPLES_DIR is empty!"
1289 exit 1;
1290 fi
1291
1292 # daemon use {kern} and {root} subdir, it's not a typo to not use ${}
1293 move_and_remove $SAMPLES_DIR/current/{kern}
1294 move_and_remove $SAMPLES_DIR/current/{root}
1295
1296 hup_daemon
1297}
1298
1299
1300do_deinit()
1301{
1302 # unmount /dev/oprofile if it is mounted
1303 OPROF_FS=`grep /dev/oprofile /etc/mtab`
1304 if test -n "$OPROF_FS"; then
1305 umount /dev/oprofile
1306 fi
1307 # unload the oprofile module if it is around
1308 OPROF_MOD=`lsmod | grep oprofile`
1309 if test -n "$OPROF_MOD"; then
1310 echo "Unloading oprofile module" >& 2
1311 rmmod oprofile
1312 fi
1313}
1314
1315
1316# The function that calls the appropriate operations
1317do_operations()
1318{
1319 # INIT always done by load_module to get access to cputype
1320 # thus INIT is a noop
1321
1322 if test "$STATUS" = "yes"; then
1323 do_status
1324 fi
1325
1326 if test "$SETUP" = "yes"; then
1327 check_valid_args
1328 do_save_setup
1329 fi
1330
1331 if test "$START_DAEMON" = "yes"; then
1332 do_start_daemon
1333 fi
1334
1335 if test "$START" = "yes"; then
1336 do_start_daemon
1337 do_start
1338 fi
1339
1340 if test "$DUMP" = "yes"; then
1341 do_dump
1342 fi
1343
1344 if test "$SAVE_SESSION" = "yes"; then
1345 do_save_session
1346 fi
1347
1348 if test "$STOP" = "yes"; then
1349 do_stop
1350 fi
1351
1352 if test "$KILL_DAEMON" = "yes"; then
1353 do_kill_daemon
1354 fi
1355
1356 if test "$RESET" = "yes"; then
1357 do_reset
1358 fi
1359
1360 if test "$DEINIT" = "yes"; then
1361 do_deinit
1362 fi
1363}
1364
1365# early check for --version, --help
1366check_version_help()
1367{
1368
1369 OPHELP="$OPDIR/ophelp"
1370
1371 for i in $@; do
1372 case "$i" in
1373 -\?|--help)
1374 do_help
1375 exit 0
1376 ;;
1377
1378 -v|--version)
1379 echo -n "`basename $0`: "
1380 $OPHELP --version | cut -d' ' -f2-
1381 exit 0
1382 ;;
1383
1384 esac
1385 done
1386}
1387
1388
1389#determine which module is loaded
1390check_version()
1391{
1392 OPROFILE_AVAILABLE=no
1393 grep oprofilefs /etc/mtab >/dev/null
1394 if test "$?" -eq 0; then
1395 # need to have oprofilefs mounted for this to work on 2.6
1396 KERNEL_SUPPORT=yes
1397 OPROFILE_AVAILABLE=yes
1398 return
1399 fi
1400 # need to have /proc/oprof available for this to work on 2.4
1401 grep oprof /proc/devices >/dev/null
1402 if test "$?" -eq 0; then
1403 KERNEL_SUPPORT=no
1404 OPROFILE_AVAILABLE=yes
1405 return
1406 fi
1407}
1408
1409
1410# main
1411
1412# determine the location of opcontrol and related programs
1413OPCONTROL=`which $0`
1414OPDIR=`dirname $OPCONTROL`
1415
1416PATH=/usr/local/bin:/usr/local/sbin:/bin:/sbin:/usr/bin:/usr/sbin
1417
1418check_version_help $@
1419
1420if test -z "$1"; then
1421 do_help
1422 exit 0
1423fi
1424
1425if test "$UID" = "0"; then
1426 load_module
1427fi
1428check_version
1429do_init_daemon_vars
1430decide_oprofile_device
1431if test "$UID" != "0"; then
1432 if test "$1" = "--dump" -a -z "$2"; then
1433 ONLY_DUMP=yes
1434 do_dump
1435 exit 0;
1436 elif test "$1" = "--list-events" -a -z "$2"; then
1437 exec $OPHELP
1438 else
1439 echo "Normal users are limited to either '--dump' or '--list-events'." >&2
1440 exit 1
1441 fi
1442fi
1443
1444do_init
1445do_options $@
1446do_operations