perf-with-kcore.sh 6.7 KB

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