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