Back to home page

OSCL-LXR

 
 

    


0001 #!/bin/sh
0002 # Check branch stack sampling
0003 
0004 # SPDX-License-Identifier: GPL-2.0
0005 # German Gomez <german.gomez@arm.com>, 2022
0006 
0007 # we need a C compiler to build the test programs
0008 # so bail if none is found
0009 if ! [ -x "$(command -v cc)" ]; then
0010         echo "failed: no compiler, install gcc"
0011         exit 2
0012 fi
0013 
0014 # skip the test if the hardware doesn't support branch stack sampling
0015 # and if the architecture doesn't support filter types: any,save_type,u
0016 perf record -b -o- -B --branch-filter any,save_type,u true > /dev/null 2>&1 || exit 2
0017 
0018 TMPDIR=$(mktemp -d /tmp/__perf_test.program.XXXXX)
0019 
0020 cleanup() {
0021         rm -rf $TMPDIR
0022 }
0023 
0024 trap cleanup exit term int
0025 
0026 gen_test_program() {
0027         # generate test program
0028         cat << EOF > $1
0029 #define BENCH_RUNS 999999
0030 int cnt;
0031 void bar(void) {
0032 }                       /* return */
0033 void foo(void) {
0034         bar();          /* call */
0035 }                       /* return */
0036 void bench(void) {
0037   void (*foo_ind)(void) = foo;
0038   if ((cnt++) % 3)      /* branch (cond) */
0039     foo();              /* call */
0040   bar();                /* call */
0041   foo_ind();            /* call (ind) */
0042 }
0043 int main(void)
0044 {
0045   int cnt = 0;
0046   while (1) {
0047     if ((cnt++) > BENCH_RUNS)
0048       break;
0049     bench();            /* call */
0050   }                     /* branch (uncond) */
0051   return 0;
0052 }
0053 EOF
0054 }
0055 
0056 test_user_branches() {
0057         echo "Testing user branch stack sampling"
0058 
0059         gen_test_program "$TEMPDIR/program.c"
0060         cc -fno-inline -g "$TEMPDIR/program.c" -o $TMPDIR/a.out
0061 
0062         perf record -o $TMPDIR/perf.data --branch-filter any,save_type,u -- $TMPDIR/a.out > /dev/null 2>&1
0063         perf script -i $TMPDIR/perf.data --fields brstacksym | xargs -n1 > $TMPDIR/perf.script
0064 
0065         # example of branch entries:
0066         #       foo+0x14/bar+0x40/P/-/-/0/CALL
0067 
0068         set -x
0069         egrep -m1 "^bench\+[^ ]*/foo\+[^ ]*/IND_CALL$"  $TMPDIR/perf.script
0070         egrep -m1 "^foo\+[^ ]*/bar\+[^ ]*/CALL$"        $TMPDIR/perf.script
0071         egrep -m1 "^bench\+[^ ]*/foo\+[^ ]*/CALL$"      $TMPDIR/perf.script
0072         egrep -m1 "^bench\+[^ ]*/bar\+[^ ]*/CALL$"      $TMPDIR/perf.script
0073         egrep -m1 "^bar\+[^ ]*/foo\+[^ ]*/RET$"         $TMPDIR/perf.script
0074         egrep -m1 "^foo\+[^ ]*/bench\+[^ ]*/RET$"       $TMPDIR/perf.script
0075         egrep -m1 "^bench\+[^ ]*/bench\+[^ ]*/COND$"    $TMPDIR/perf.script
0076         egrep -m1 "^main\+[^ ]*/main\+[^ ]*/UNCOND$"    $TMPDIR/perf.script
0077         set +x
0078 
0079         # some branch types are still not being tested:
0080         # IND COND_CALL COND_RET SYSCALL SYSRET IRQ SERROR NO_TX
0081 }
0082 
0083 # first argument <arg0> is the argument passed to "--branch-stack <arg0>,save_type,u"
0084 # second argument are the expected branch types for the given filter
0085 test_filter() {
0086         local filter=$1
0087         local expect=$2
0088 
0089         echo "Testing branch stack filtering permutation ($filter,$expect)"
0090 
0091         gen_test_program "$TEMPDIR/program.c"
0092         cc -fno-inline -g "$TEMPDIR/program.c" -o $TMPDIR/a.out
0093 
0094         perf record -o $TMPDIR/perf.data --branch-filter $filter,save_type,u -- $TMPDIR/a.out > /dev/null 2>&1
0095         perf script -i $TMPDIR/perf.data --fields brstack | xargs -n1 > $TMPDIR/perf.script
0096 
0097         # fail if we find any branch type that doesn't match any of the expected ones
0098         # also consider UNKNOWN branch types (-)
0099         if egrep -vm1 "^[^ ]*/($expect|-|( *))$" $TMPDIR/perf.script; then
0100                 return 1
0101         fi
0102 }
0103 
0104 set -e
0105 
0106 test_user_branches
0107 
0108 test_filter "any_call"  "CALL|IND_CALL|COND_CALL|SYSCALL|IRQ"
0109 test_filter "call"      "CALL|SYSCALL"
0110 test_filter "cond"      "COND"
0111 test_filter "any_ret"   "RET|COND_RET|SYSRET|ERET"
0112 
0113 test_filter "call,cond"         "CALL|SYSCALL|COND"
0114 test_filter "any_call,cond"             "CALL|IND_CALL|COND_CALL|IRQ|SYSCALL|COND"
0115 test_filter "cond,any_call,any_ret"     "COND|CALL|IND_CALL|COND_CALL|SYSCALL|IRQ|RET|COND_RET|SYSRET|ERET"