510 lines · 14.0 KB · Shell
RawDownload
#!/bin/bash# SPDX-License-Identifier: GPL-2.0# perf record tests set -e shelldir=$(dirname "$0"). "${shelldir}"/lib/perf_record.sh  # shellcheck source=lib/waiting.sh. "${shelldir}"/lib/waiting.sh # shellcheck source=lib/perf_has_symbol.sh. "${shelldir}"/lib/perf_has_symbol.sh testsym="test_loop"testsym2="brstack" skip_test_missing_symbol ${testsym}skip_test_missing_symbol ${testsym2} err=0perfdata=$(mktemp /tmp/__perf_test.perf.data.XXXXX)script_output=$(mktemp /tmp/__perf_test.perf.data.XXXXX.script)testprog="perf test -w thloop"cpu_pmu_dir="/sys/bus/event_source/devices/cpu*"br_cntr_file="/caps/branch_counter_nr"br_cntr_output="branch stack counters"br_cntr_script_output="br_cntr: A" default_fd_limit=$(ulimit -Sn)# With option --threads=cpu the number of open file descriptors should be# equal to sum of:    nmb_cpus * nmb_events (2+dummy),#                     nmb_threads for perf.data.n (equal to nmb_cpus) and#                     2*nmb_cpus of pipes = 4*nmb_cpus (each pipe has 2 ends)# All together it needs 8*nmb_cpus file descriptors plus some are also used# outside of testing, thus raising the limit to 16*nmb_cpusmin_fd_limit=$(($(getconf _NPROCESSORS_ONLN) * 16)) cleanup() {  rm -f "${perfdata}"  rm -f "${perfdata}".old  rm -f "${script_output}"  perf_record_cleanup   trap - EXIT TERM INT} trap_cleanup() {  echo "Unexpected signal in ${FUNCNAME[1]}"  cleanup  exit 1}trap trap_cleanup EXIT TERM INT check_per_thread() {  perf report -i "${perfdata}" -q | grep -q "${testsym}"} test_per_thread() {  echo "Basic --per-thread mode test"  local ret=0  perf_record_with_retry "${perfdata}" "check_per_thread" "perf test -w thloop" \    --per-thread || ret=$?  if [ $ret -eq 2 ]; then    echo "Per-thread record [Skipped event not supported]"    return  elif [ $ret -eq 1 ]; then    echo "Per-thread record [Failed record or missing output]"    err=1    return  fi   # run the test program in background (for 30 seconds)  ${testprog} 30 &  TESTPID=$!   rm -f "${perfdata}"   wait_for_threads ${TESTPID} 2  perf record -p "${TESTPID}" --per-thread -o "${perfdata}" sleep 1 2> /dev/null  kill ${TESTPID}   if [ ! -e "${perfdata}" ]  then    echo "Per-thread record [Failed record -p]"    err=1    return  fi  if ! perf report -i "${perfdata}" -q | grep -q "${testsym}"  then    echo "Per-thread record [Failed -p missing output]"    err=1    return  fi   echo "Basic --per-thread mode test [Success]"} check_register_capture() {  perf script -F ip,sym,iregs -i "${perfdata}" 2>/dev/null | grep -q "DI:"} test_register_capture() {  echo "Register capture test"  if ! perf list pmu | grep -q 'br_inst_retired.near_call'  then    echo "Register capture test [Skipped missing event]"    return  fi  if ! perf record --intr-regs=\? 2>&1 | grep -q 'available registers: AX BX CX DX SI DI BP SP IP FLAGS CS SS R8 R9 R10 R11 R12 R13 R14 R15'  then    echo "Register capture test [Skipped missing registers]"    return  fi   local ret=0  perf_record_with_retry "${perfdata}" "check_register_capture" "perf test -w thloop" \    --intr-regs=di,r8,dx,cx -e br_inst_retired.near_call -c 1000 --per-thread || ret=$?   if [ $ret -ne 0 ]; then    echo "Register capture test [Failed missing output]"    err=1    return  fi  echo "Register capture test [Success]"} check_system_wide() {  perf report -i "${perfdata}" -q | grep -q "${testsym}"} test_system_wide() {  echo "Basic --system-wide mode test"  local ret=0  perf_record_with_retry "${perfdata}" "check_system_wide" "perf test -w thloop" \    -aB --synth=no || ret=$?  if [ $ret -eq 2 ]; then    echo "System-wide record [Skipped not supported]"    return  elif [ $ret -eq 1 ]; then    echo "System-wide record [Failed missing output]"    err=1    return  fi   ret=0  perf_record_with_retry "${perfdata}" "check_system_wide" "perf test -w thloop" \    -aB --synth=no -e cpu-clock,cs --threads=cpu || ret=$?  if [ $ret -ne 0 ]; then    echo "System-wide record [Failed record --threads option or missing output]"    err=1    return  fi  echo "Basic --system-wide mode test [Success]"} check_workload() {  perf report -i "${perfdata}" -q | grep -q "${testsym}"} test_workload() {  echo "Basic target workload test"  local ret=0  perf_record_with_retry "${perfdata}" "check_workload" "perf test -w thloop" || ret=$?  if [ $ret -ne 0 ]; then    echo "Workload record [Failed record or missing output]"    err=1    return  fi   ret=0  perf_record_with_retry "${perfdata}" "check_workload" "perf test -w thloop" \    -e cpu-clock,cs --threads=package || ret=$?  if [ $ret -ne 0 ]; then    echo "Workload record [Failed record --threads option or missing output]"    err=1    return  fi  echo "Basic target workload test [Success]"} check_branch_counter() {  perf report -i "${perfdata}" -D -q 2>/dev/null | grep -q "$br_cntr_output" && \  perf script -i "${perfdata}" -F +brstackinsn,+brcntr 2>/dev/null | \    grep -q "$br_cntr_script_output"} test_branch_counter() {  echo "Branch counter test"  # Check if the branch counter feature is supported  for dir in $cpu_pmu_dir  do    if [ ! -e "$dir$br_cntr_file" ]    then      echo "branch counter feature not supported on all core PMUs ($dir) [Skipped]"      return    fi  done  local ret=0  perf_record_with_retry "${perfdata}" "check_branch_counter" "perf test -w thloop" \    -e "{branches:p,instructions}" -j any,counter || ret=$?  if [ $ret -ne 0 ]; then    echo "Branch counter test [Failed record or missing output]"    err=1    return  fi  echo "Branch counter test [Success]"} check_cgroup() {  perf report -i "${perfdata}" -D 2>/dev/null | grep -q "CGROUP" && \  perf script -i "${perfdata}" -F cgroup 2>/dev/null | grep -q -v "unknown"} test_cgroup() {  echo "Cgroup sampling test"  local ret=0  perf_record_with_retry "${perfdata}" "check_cgroup" "perf test -w thloop" \    -aB --synth=cgroup --all-cgroups || ret=$?  if [ $ret -eq 2 ]; then    echo "Cgroup sampling [Skipped not supported]"    return  elif [ $ret -eq 1 ]; then    echo "Cgroup sampling [Failed missing output]"    err=1    return  fi  echo "Cgroup sampling test [Success]"} check_uid() {  perf report -i "${perfdata}" -q | grep -q "${testsym}"} test_uid() {  echo "Uid sampling test"  local ret=0  perf_record_with_retry "${perfdata}" "check_uid" "perf test -w thloop" \    -aB --synth=no --uid "$(id -u)" || ret=$?  if [ $ret -eq 2 ]; then    local logfile="${PERF_RECORD_LOGS[${#PERF_RECORD_LOGS[@]}-1]}"    if grep -q -E "libbpf.*EPERM|Access to performance monitoring" "$logfile" || \       grep -q -E "Permission denied|Failure to open any events" "$logfile"    then      echo "Uid sampling [Skipped permissions]"      return    else      echo "Uid sampling [Failed to record]"      err=1      return    fi  elif [ $ret -eq 1 ]; then    echo "Uid sampling [Failed missing output]"    err=1    return  fi  echo "Uid sampling test [Success]"} test_leader_sampling() {  echo "Basic leader sampling test"  events="{cycles,cycles}:Su"  [ "$(uname -m)" = "s390x" ] && {    [ ! -d /sys/devices/cpum_sf ] && {      echo "No CPUMF [Skipped record]"      return    }    events="{cpum_sf/SF_CYCLES_BASIC/,cycles}:Su"    perf record -o "${perfdata}" -e "$events" -- perf test -w brstack 2> /dev/null    # Perf grouping might be unsupported, depends on version.    [ "$?" -ne 0 ] && {      echo "Grouping not support [Skipped record]"      return    }  }  if ! perf record -o "${perfdata}" -e "$events" -- \    perf test -w brstack 2> /dev/null  then    echo "Leader sampling [Failed record]"    err=1    return  fi  perf script -i "${perfdata}" | grep brstack > $script_output  # Check if the two instruction counts are equal in each record.  # However, the throttling code doesn't consider event grouping. During throttling, only the  # leader is stopped, causing the slave's counts significantly higher. To temporarily solve this,  # let's set the tolerance rate to 80%.  # TODO: Revert the code for tolerance once the throttling mechanism is fixed.  index=0  valid_counts=0  invalid_counts=0  tolerance_rate=0.8  while IFS= read -r line  do    cycles=$(echo $line | awk '{for(i=1;i<=NF;i++) if($i=="cycles:") print $(i-1)}')    if [ $(($index%2)) -ne 0 ] && [ ${cycles}x != ${prev_cycles}x ]    then      invalid_counts=$(($invalid_counts+1))    else      valid_counts=$(($valid_counts+1))    fi    index=$(($index+1))    prev_cycles=$cycles  done < "${script_output}"  total_counts=$(bc <<< "$invalid_counts+$valid_counts")  if (( $(bc <<< "$total_counts <= 0") ))  then    echo "Leader sampling [No sample generated]"    err=1    return  fi  isok=$(bc <<< "scale=2; if (($invalid_counts/$total_counts) < (1-$tolerance_rate)) { 0 } else { 1 };")  if [ $isok -eq 1 ]  then     echo "Leader sampling [Failed inconsistent cycles count]"     err=1  else    echo "Basic leader sampling test [Success]"  fi} test_topdown_leader_sampling() {  echo "Topdown leader sampling test"  if ! perf stat -e "{slots,topdown-retiring}" true 2> /dev/null  then    echo "Topdown leader sampling [Skipped event parsing failed]"    return  fi  if ! perf record -o "${perfdata}" -e "{instructions,slots,topdown-retiring}:S" true 2> /dev/null  then    echo "Topdown leader sampling [Failed topdown events not reordered correctly]"    err=1    return  fi  echo "Topdown leader sampling test [Success]"} test_precise_max() {  local -i skipped=0   echo "precise_max attribute test"  # Just to make sure event cycles is supported for sampling  if perf record -o "${perfdata}" -e "cycles" true 2> /dev/null  then    if ! perf record -o "${perfdata}" -e "cycles:P" true 2> /dev/null    then      echo "precise_max attribute [Failed cycles:P event]"      err=1      return    fi  else    echo "precise_max attribute [Skipped no cycles:P event]"    ((skipped+=1))  fi  # On s390 event instructions is not supported for perf record  if perf record -o "${perfdata}" -e "instructions" true 2> /dev/null  then    # On AMD, cycles and instructions events are treated differently    if ! perf record -o "${perfdata}" -e "instructions:P" true 2> /dev/null    then      echo "precise_max attribute [Failed instructions:P event]"      err=1      return    fi  else    echo "precise_max attribute [Skipped no instructions:P event]"    ((skipped+=1))  fi  if [ $skipped -eq 2 ]  then    echo "precise_max attribute [Skipped no hardware events]"  else    echo "precise_max attribute test [Success]"  fi} test_callgraph() {  echo "Callgraph test"   case $(uname -m)  in s390x)       cmd_flags="--call-graph dwarf -e cpu-clock";;     *)       cmd_flags="-g";;  esac   if ! perf record -o "${perfdata}" $cmd_flags perf test -w brstack  then    echo "Callgraph test [Failed missing output]"    err=1    return  fi   if ! perf report -i "${perfdata}" 2>&1 | grep "${testsym2}"  then    echo "Callgraph test [Failed missing symbol]"    err=1    return  fi   echo "Callgraph test [Success]"} test_acr_sampling() {  events="{instructions/period=40000,acr_mask=0x2/u,cycles/period=20000,acr_mask=0x3/u}"  pebs_events="{instructions/period=40000,acr_mask=0x2/pu,cycles/period=20000,acr_mask=0x3/u}"  echo "Auto counter reload (ACR) sampling test"  if ! perf record -o "${perfdata}" -e "${events}" ${testprog} 2> /dev/null  then    echo "Auto counter reload sampling [Skipped not supported]"    return  fi  if ! perf script -i "${perfdata}" -F event | grep -q "instructions"  then    echo "Auto counter reload sampling [Failed missing instructions event]"    err=1    return  fi  if perf script -i "${perfdata}" -F event | grep -q "cycles"  then    echo "Auto counter reload sampling [Failed cycles event shouldn't be sampled]"    err=1    return  fi  if ! perf record -o "${perfdata}" -e "${pebs_events}" ${testprog} 2> /dev/null  then    echo "Auto counter reload PEBS sampling [Skipped not supported]"    echo "Auto counter reload sampling [Success]"    return  fi  if ! perf script -i "${perfdata}" -F event | grep -q "instructions"  then    echo "Auto counter reload PEBS sampling [Failed missing instructions event]"    err=1    return  fi  if perf script -i "${perfdata}" -F event | grep -q "cycles"  then    echo "Auto counter reload PEBS sampling [Failed cycles event shouldn't be sampled]"    err=1    return  fi  echo "Auto counter reload sampling [Success]"} test_ratio_to_prev() {  echo "ratio-to-prev test"  if ! perf record -o /dev/null -e "{instructions, cycles/period=100000,ratio-to-prev=0.5/}" \     true 2> /dev/null  then    echo "ratio-to-prev [Skipped not supported]"    return  fi  if ! perf record -o /dev/null -e "instructions, cycles/period=100000,ratio-to-prev=0.5/" \     true |& grep -q 'Invalid use of ratio-to-prev term without preceding element in group'  then    echo "ratio-to-prev test [Failed elements must be in same group]"    err=1    return  fi  if ! perf record -o /dev/null -e "{instructions,dummy,cycles/period=100000,ratio-to-prev=0.5/}" \     true |& grep -q 'must have same PMU'  then    echo "ratio-to-prev test [Failed elements must have same PMU]"    err=1    return  fi  if ! perf record -o /dev/null -e "{instructions,cycles/ratio-to-prev=0.5/}" \     true |& grep -q 'Event period term or count (-c) must be set when using ratio-to-prev term.'  then    echo "ratio-to-prev test [Failed period must be set]"    err=1    return  fi  if ! perf record -o /dev/null -e "{cycles/ratio-to-prev=0.5/}" \     true |& grep -q 'Invalid use of ratio-to-prev term without preceding element in group'  then    echo "ratio-to-prev test [Failed need 2+ events]"    err=1    return  fi  echo "Basic ratio-to-prev record test [Success]"} # raise the limit of file descriptors to minimumif [[ $default_fd_limit -lt $min_fd_limit ]]; then       ulimit -Sn $min_fd_limitfi test_per_threadtest_register_capturetest_system_widetest_workloadtest_branch_countertest_cgrouptest_uidtest_leader_samplingtest_topdown_leader_sampling

Lines 1–500 of 510.