1*4882a593Smuzhiyun#!/bin/bash 2*4882a593Smuzhiyun# SPDX-License-Identifier: GPL-2.0-only 3*4882a593Smuzhiyun# perf-with-kcore: use perf with a copy of kcore 4*4882a593Smuzhiyun# Copyright (c) 2014, Intel Corporation. 5*4882a593Smuzhiyun# 6*4882a593Smuzhiyun 7*4882a593Smuzhiyunset -e 8*4882a593Smuzhiyun 9*4882a593Smuzhiyunusage() 10*4882a593Smuzhiyun{ 11*4882a593Smuzhiyun echo "Usage: perf-with-kcore <perf sub-command> <perf.data directory> [<sub-command options> [ -- <workload>]]" >&2 12*4882a593Smuzhiyun echo " <perf sub-command> can be record, script, report or inject" >&2 13*4882a593Smuzhiyun echo " or: perf-with-kcore fix_buildid_cache_permissions" >&2 14*4882a593Smuzhiyun exit 1 15*4882a593Smuzhiyun} 16*4882a593Smuzhiyun 17*4882a593Smuzhiyunfind_perf() 18*4882a593Smuzhiyun{ 19*4882a593Smuzhiyun if [ -n "$PERF" ] ; then 20*4882a593Smuzhiyun return 21*4882a593Smuzhiyun fi 22*4882a593Smuzhiyun PERF=`which perf || true` 23*4882a593Smuzhiyun if [ -z "$PERF" ] ; then 24*4882a593Smuzhiyun echo "Failed to find perf" >&2 25*4882a593Smuzhiyun exit 1 26*4882a593Smuzhiyun fi 27*4882a593Smuzhiyun if [ ! -x "$PERF" ] ; then 28*4882a593Smuzhiyun echo "Failed to find perf" >&2 29*4882a593Smuzhiyun exit 1 30*4882a593Smuzhiyun fi 31*4882a593Smuzhiyun echo "Using $PERF" 32*4882a593Smuzhiyun "$PERF" version 33*4882a593Smuzhiyun} 34*4882a593Smuzhiyun 35*4882a593Smuzhiyuncopy_kcore() 36*4882a593Smuzhiyun{ 37*4882a593Smuzhiyun echo "Copying kcore" 38*4882a593Smuzhiyun 39*4882a593Smuzhiyun if [ $EUID -eq 0 ] ; then 40*4882a593Smuzhiyun SUDO="" 41*4882a593Smuzhiyun else 42*4882a593Smuzhiyun SUDO="sudo" 43*4882a593Smuzhiyun fi 44*4882a593Smuzhiyun 45*4882a593Smuzhiyun rm -f perf.data.junk 46*4882a593Smuzhiyun ("$PERF" record -o perf.data.junk "${PERF_OPTIONS[@]}" -- sleep 60) >/dev/null 2>/dev/null & 47*4882a593Smuzhiyun PERF_PID=$! 48*4882a593Smuzhiyun 49*4882a593Smuzhiyun # Need to make sure that perf has started 50*4882a593Smuzhiyun sleep 1 51*4882a593Smuzhiyun 52*4882a593Smuzhiyun KCORE=$(($SUDO "$PERF" buildid-cache -v -f -k /proc/kcore >/dev/null) 2>&1) 53*4882a593Smuzhiyun case "$KCORE" in 54*4882a593Smuzhiyun "kcore added to build-id cache directory "*) 55*4882a593Smuzhiyun KCORE_DIR=${KCORE#"kcore added to build-id cache directory "} 56*4882a593Smuzhiyun ;; 57*4882a593Smuzhiyun *) 58*4882a593Smuzhiyun kill $PERF_PID 59*4882a593Smuzhiyun wait >/dev/null 2>/dev/null || true 60*4882a593Smuzhiyun rm perf.data.junk 61*4882a593Smuzhiyun echo "$KCORE" 62*4882a593Smuzhiyun echo "Failed to find kcore" >&2 63*4882a593Smuzhiyun exit 1 64*4882a593Smuzhiyun ;; 65*4882a593Smuzhiyun esac 66*4882a593Smuzhiyun 67*4882a593Smuzhiyun kill $PERF_PID 68*4882a593Smuzhiyun wait >/dev/null 2>/dev/null || true 69*4882a593Smuzhiyun rm perf.data.junk 70*4882a593Smuzhiyun 71*4882a593Smuzhiyun $SUDO cp -a "$KCORE_DIR" "$(pwd)/$PERF_DATA_DIR" 72*4882a593Smuzhiyun $SUDO rm -f "$KCORE_DIR/kcore" 73*4882a593Smuzhiyun $SUDO rm -f "$KCORE_DIR/kallsyms" 74*4882a593Smuzhiyun $SUDO rm -f "$KCORE_DIR/modules" 75*4882a593Smuzhiyun $SUDO rmdir "$KCORE_DIR" 76*4882a593Smuzhiyun 77*4882a593Smuzhiyun KCORE_DIR_BASENAME=$(basename "$KCORE_DIR") 78*4882a593Smuzhiyun KCORE_DIR="$(pwd)/$PERF_DATA_DIR/$KCORE_DIR_BASENAME" 79*4882a593Smuzhiyun 80*4882a593Smuzhiyun $SUDO chown $UID "$KCORE_DIR" 81*4882a593Smuzhiyun $SUDO chown $UID "$KCORE_DIR/kcore" 82*4882a593Smuzhiyun $SUDO chown $UID "$KCORE_DIR/kallsyms" 83*4882a593Smuzhiyun $SUDO chown $UID "$KCORE_DIR/modules" 84*4882a593Smuzhiyun 85*4882a593Smuzhiyun $SUDO chgrp $GROUPS "$KCORE_DIR" 86*4882a593Smuzhiyun $SUDO chgrp $GROUPS "$KCORE_DIR/kcore" 87*4882a593Smuzhiyun $SUDO chgrp $GROUPS "$KCORE_DIR/kallsyms" 88*4882a593Smuzhiyun $SUDO chgrp $GROUPS "$KCORE_DIR/modules" 89*4882a593Smuzhiyun 90*4882a593Smuzhiyun ln -s "$KCORE_DIR_BASENAME" "$PERF_DATA_DIR/kcore_dir" 91*4882a593Smuzhiyun} 92*4882a593Smuzhiyun 93*4882a593Smuzhiyunfix_buildid_cache_permissions() 94*4882a593Smuzhiyun{ 95*4882a593Smuzhiyun if [ $EUID -ne 0 ] ; then 96*4882a593Smuzhiyun echo "This script must be run as root via sudo " >&2 97*4882a593Smuzhiyun exit 1 98*4882a593Smuzhiyun fi 99*4882a593Smuzhiyun 100*4882a593Smuzhiyun if [ -z "$SUDO_USER" ] ; then 101*4882a593Smuzhiyun echo "This script must be run via sudo" >&2 102*4882a593Smuzhiyun exit 1 103*4882a593Smuzhiyun fi 104*4882a593Smuzhiyun 105*4882a593Smuzhiyun USER_HOME=$(bash <<< "echo ~$SUDO_USER") 106*4882a593Smuzhiyun 107*4882a593Smuzhiyun echo "Fixing buildid cache permissions" 108*4882a593Smuzhiyun 109*4882a593Smuzhiyun find "$USER_HOME/.debug" -xdev -type d ! -user "$SUDO_USER" -ls -exec chown "$SUDO_USER" \{\} \; 110*4882a593Smuzhiyun find "$USER_HOME/.debug" -xdev -type f -links 1 ! -user "$SUDO_USER" -ls -exec chown "$SUDO_USER" \{\} \; 111*4882a593Smuzhiyun find "$USER_HOME/.debug" -xdev -type l ! -user "$SUDO_USER" -ls -exec chown -h "$SUDO_USER" \{\} \; 112*4882a593Smuzhiyun 113*4882a593Smuzhiyun if [ -n "$SUDO_GID" ] ; then 114*4882a593Smuzhiyun find "$USER_HOME/.debug" -xdev -type d ! -group "$SUDO_GID" -ls -exec chgrp "$SUDO_GID" \{\} \; 115*4882a593Smuzhiyun find "$USER_HOME/.debug" -xdev -type f -links 1 ! -group "$SUDO_GID" -ls -exec chgrp "$SUDO_GID" \{\} \; 116*4882a593Smuzhiyun find "$USER_HOME/.debug" -xdev -type l ! -group "$SUDO_GID" -ls -exec chgrp -h "$SUDO_GID" \{\} \; 117*4882a593Smuzhiyun fi 118*4882a593Smuzhiyun 119*4882a593Smuzhiyun echo "Done" 120*4882a593Smuzhiyun} 121*4882a593Smuzhiyun 122*4882a593Smuzhiyuncheck_buildid_cache_permissions() 123*4882a593Smuzhiyun{ 124*4882a593Smuzhiyun if [ $EUID -eq 0 ] ; then 125*4882a593Smuzhiyun return 126*4882a593Smuzhiyun fi 127*4882a593Smuzhiyun 128*4882a593Smuzhiyun PERMISSIONS_OK+=$(find "$HOME/.debug" -xdev -type d ! -user "$USER" -print -quit) 129*4882a593Smuzhiyun PERMISSIONS_OK+=$(find "$HOME/.debug" -xdev -type f -links 1 ! -user "$USER" -print -quit) 130*4882a593Smuzhiyun PERMISSIONS_OK+=$(find "$HOME/.debug" -xdev -type l ! -user "$USER" -print -quit) 131*4882a593Smuzhiyun 132*4882a593Smuzhiyun PERMISSIONS_OK+=$(find "$HOME/.debug" -xdev -type d ! -group "$GROUPS" -print -quit) 133*4882a593Smuzhiyun PERMISSIONS_OK+=$(find "$HOME/.debug" -xdev -type f -links 1 ! -group "$GROUPS" -print -quit) 134*4882a593Smuzhiyun PERMISSIONS_OK+=$(find "$HOME/.debug" -xdev -type l ! -group "$GROUPS" -print -quit) 135*4882a593Smuzhiyun 136*4882a593Smuzhiyun if [ -n "$PERMISSIONS_OK" ] ; then 137*4882a593Smuzhiyun echo "*** WARNING *** buildid cache permissions may need fixing" >&2 138*4882a593Smuzhiyun fi 139*4882a593Smuzhiyun} 140*4882a593Smuzhiyun 141*4882a593Smuzhiyunrecord() 142*4882a593Smuzhiyun{ 143*4882a593Smuzhiyun echo "Recording" 144*4882a593Smuzhiyun 145*4882a593Smuzhiyun if [ $EUID -ne 0 ] ; then 146*4882a593Smuzhiyun 147*4882a593Smuzhiyun if [ "$(cat /proc/sys/kernel/kptr_restrict)" -ne 0 ] ; then 148*4882a593Smuzhiyun echo "*** WARNING *** /proc/sys/kernel/kptr_restrict prevents access to kernel addresses" >&2 149*4882a593Smuzhiyun fi 150*4882a593Smuzhiyun 151*4882a593Smuzhiyun if echo "${PERF_OPTIONS[@]}" | grep -q ' -a \|^-a \| -a$\|^-a$\| --all-cpus \|^--all-cpus \| --all-cpus$\|^--all-cpus$' ; then 152*4882a593Smuzhiyun echo "*** WARNING *** system-wide tracing without root access will not be able to read all necessary information from /proc" >&2 153*4882a593Smuzhiyun fi 154*4882a593Smuzhiyun 155*4882a593Smuzhiyun if echo "${PERF_OPTIONS[@]}" | grep -q 'intel_pt\|intel_bts\| -I\|^-I' ; then 156*4882a593Smuzhiyun if [ "$(cat /proc/sys/kernel/perf_event_paranoid)" -gt -1 ] ; then 157*4882a593Smuzhiyun echo "*** WARNING *** /proc/sys/kernel/perf_event_paranoid restricts buffer size and tracepoint (sched_switch) use" >&2 158*4882a593Smuzhiyun fi 159*4882a593Smuzhiyun 160*4882a593Smuzhiyun if echo "${PERF_OPTIONS[@]}" | grep -q ' --per-thread \|^--per-thread \| --per-thread$\|^--per-thread$' ; then 161*4882a593Smuzhiyun true 162*4882a593Smuzhiyun elif echo "${PERF_OPTIONS[@]}" | grep -q ' -t \|^-t \| -t$\|^-t$' ; then 163*4882a593Smuzhiyun true 164*4882a593Smuzhiyun elif [ ! -r /sys/kernel/debug -o ! -x /sys/kernel/debug ] ; then 165*4882a593Smuzhiyun echo "*** WARNING *** /sys/kernel/debug permissions prevent tracepoint (sched_switch) use" >&2 166*4882a593Smuzhiyun fi 167*4882a593Smuzhiyun fi 168*4882a593Smuzhiyun fi 169*4882a593Smuzhiyun 170*4882a593Smuzhiyun if [ -z "$1" ] ; then 171*4882a593Smuzhiyun echo "Workload is required for recording" >&2 172*4882a593Smuzhiyun usage 173*4882a593Smuzhiyun fi 174*4882a593Smuzhiyun 175*4882a593Smuzhiyun if [ -e "$PERF_DATA_DIR" ] ; then 176*4882a593Smuzhiyun echo "'$PERF_DATA_DIR' exists" >&2 177*4882a593Smuzhiyun exit 1 178*4882a593Smuzhiyun fi 179*4882a593Smuzhiyun 180*4882a593Smuzhiyun find_perf 181*4882a593Smuzhiyun 182*4882a593Smuzhiyun mkdir "$PERF_DATA_DIR" 183*4882a593Smuzhiyun 184*4882a593Smuzhiyun echo "$PERF record -o $PERF_DATA_DIR/perf.data ${PERF_OPTIONS[@]} -- $@" 185*4882a593Smuzhiyun "$PERF" record -o "$PERF_DATA_DIR/perf.data" "${PERF_OPTIONS[@]}" -- "$@" || true 186*4882a593Smuzhiyun 187*4882a593Smuzhiyun if rmdir "$PERF_DATA_DIR" > /dev/null 2>/dev/null ; then 188*4882a593Smuzhiyun exit 1 189*4882a593Smuzhiyun fi 190*4882a593Smuzhiyun 191*4882a593Smuzhiyun copy_kcore 192*4882a593Smuzhiyun 193*4882a593Smuzhiyun echo "Done" 194*4882a593Smuzhiyun} 195*4882a593Smuzhiyun 196*4882a593Smuzhiyunsubcommand() 197*4882a593Smuzhiyun{ 198*4882a593Smuzhiyun find_perf 199*4882a593Smuzhiyun check_buildid_cache_permissions 200*4882a593Smuzhiyun echo "$PERF $PERF_SUB_COMMAND -i $PERF_DATA_DIR/perf.data --kallsyms=$PERF_DATA_DIR/kcore_dir/kallsyms $@" 201*4882a593Smuzhiyun "$PERF" $PERF_SUB_COMMAND -i "$PERF_DATA_DIR/perf.data" "--kallsyms=$PERF_DATA_DIR/kcore_dir/kallsyms" "$@" 202*4882a593Smuzhiyun} 203*4882a593Smuzhiyun 204*4882a593Smuzhiyunif [ "$1" = "fix_buildid_cache_permissions" ] ; then 205*4882a593Smuzhiyun fix_buildid_cache_permissions 206*4882a593Smuzhiyun exit 0 207*4882a593Smuzhiyunfi 208*4882a593Smuzhiyun 209*4882a593SmuzhiyunPERF_SUB_COMMAND=$1 210*4882a593SmuzhiyunPERF_DATA_DIR=$2 211*4882a593Smuzhiyunshift || true 212*4882a593Smuzhiyunshift || true 213*4882a593Smuzhiyun 214*4882a593Smuzhiyunif [ -z "$PERF_SUB_COMMAND" ] ; then 215*4882a593Smuzhiyun usage 216*4882a593Smuzhiyunfi 217*4882a593Smuzhiyun 218*4882a593Smuzhiyunif [ -z "$PERF_DATA_DIR" ] ; then 219*4882a593Smuzhiyun usage 220*4882a593Smuzhiyunfi 221*4882a593Smuzhiyun 222*4882a593Smuzhiyuncase "$PERF_SUB_COMMAND" in 223*4882a593Smuzhiyun"record") 224*4882a593Smuzhiyun while [ "$1" != "--" ] ; do 225*4882a593Smuzhiyun PERF_OPTIONS+=("$1") 226*4882a593Smuzhiyun shift || break 227*4882a593Smuzhiyun done 228*4882a593Smuzhiyun if [ "$1" != "--" ] ; then 229*4882a593Smuzhiyun echo "Options and workload are required for recording" >&2 230*4882a593Smuzhiyun usage 231*4882a593Smuzhiyun fi 232*4882a593Smuzhiyun shift 233*4882a593Smuzhiyun record "$@" 234*4882a593Smuzhiyun;; 235*4882a593Smuzhiyun"script") 236*4882a593Smuzhiyun subcommand "$@" 237*4882a593Smuzhiyun;; 238*4882a593Smuzhiyun"report") 239*4882a593Smuzhiyun subcommand "$@" 240*4882a593Smuzhiyun;; 241*4882a593Smuzhiyun"inject") 242*4882a593Smuzhiyun subcommand "$@" 243*4882a593Smuzhiyun;; 244*4882a593Smuzhiyun*) 245*4882a593Smuzhiyun usage 246*4882a593Smuzhiyun;; 247*4882a593Smuzhiyunesac 248