255 lines
		
	
	
		
			6.6 KiB
		
	
	
	
		
			Bash
		
	
	
	
	
	
			
		
		
	
	
			255 lines
		
	
	
		
			6.6 KiB
		
	
	
	
		
			Bash
		
	
	
	
	
	
| #!/bin/bash
 | |
| # perf-with-kcore: use perf with a copy of kcore
 | |
| # Copyright (c) 2014, Intel Corporation.
 | |
| #
 | |
| # This program is free software; you can redistribute it and/or modify it
 | |
| # under the terms and conditions of the GNU General Public License,
 | |
| # version 2, as published by the Free Software Foundation.
 | |
| #
 | |
| # This program is distributed in the hope it will be useful, but WITHOUT
 | |
| # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 | |
| # FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
 | |
| # more details.
 | |
| 
 | |
| set -e
 | |
| 
 | |
| usage()
 | |
| {
 | |
|         echo "Usage: perf-with-kcore <perf sub-command> <perf.data directory> [<sub-command options> [ -- <workload>]]" >&2
 | |
|         echo "       <perf sub-command> can be record, script, report or inject" >&2
 | |
|         echo "   or: perf-with-kcore fix_buildid_cache_permissions" >&2
 | |
|         exit 1
 | |
| }
 | |
| 
 | |
| find_perf()
 | |
| {
 | |
| 	if [ -n "$PERF" ] ; then
 | |
| 		return
 | |
| 	fi
 | |
| 	PERF=`which perf || true`
 | |
| 	if [ -z "$PERF" ] ; then
 | |
| 		echo "Failed to find perf" >&2
 | |
| 	        exit 1
 | |
| 	fi
 | |
| 	if [ ! -x "$PERF" ] ; then
 | |
| 		echo "Failed to find perf" >&2
 | |
| 	        exit 1
 | |
| 	fi
 | |
| 	echo "Using $PERF"
 | |
| 	"$PERF" version
 | |
| }
 | |
| 
 | |
| copy_kcore()
 | |
| {
 | |
| 	echo "Copying kcore"
 | |
| 
 | |
| 	if [ $EUID -eq 0 ] ; then
 | |
| 		SUDO=""
 | |
| 	else
 | |
| 		SUDO="sudo"
 | |
| 	fi
 | |
| 
 | |
| 	rm -f perf.data.junk
 | |
| 	("$PERF" record -o perf.data.junk "${PERF_OPTIONS[@]}" -- sleep 60) >/dev/null 2>/dev/null &
 | |
| 	PERF_PID=$!
 | |
| 
 | |
| 	# Need to make sure that perf has started
 | |
| 	sleep 1
 | |
| 
 | |
| 	KCORE=$(($SUDO "$PERF" buildid-cache -v -f -k /proc/kcore >/dev/null) 2>&1)
 | |
| 	case "$KCORE" in
 | |
| 	"kcore added to build-id cache directory "*)
 | |
| 		KCORE_DIR=${KCORE#"kcore added to build-id cache directory "}
 | |
| 	;;
 | |
| 	*)
 | |
| 		kill $PERF_PID
 | |
| 		wait >/dev/null 2>/dev/null || true
 | |
| 		rm perf.data.junk
 | |
| 		echo "$KCORE"
 | |
| 		echo "Failed to find kcore" >&2
 | |
| 		exit 1
 | |
| 	;;
 | |
| 	esac
 | |
| 
 | |
| 	kill $PERF_PID
 | |
| 	wait >/dev/null 2>/dev/null || true
 | |
| 	rm perf.data.junk
 | |
| 
 | |
| 	$SUDO cp -a "$KCORE_DIR" "$(pwd)/$PERF_DATA_DIR"
 | |
| 	$SUDO rm -f "$KCORE_DIR/kcore"
 | |
| 	$SUDO rm -f "$KCORE_DIR/kallsyms"
 | |
| 	$SUDO rm -f "$KCORE_DIR/modules"
 | |
| 	$SUDO rmdir "$KCORE_DIR"
 | |
| 
 | |
| 	KCORE_DIR_BASENAME=$(basename "$KCORE_DIR")
 | |
| 	KCORE_DIR="$(pwd)/$PERF_DATA_DIR/$KCORE_DIR_BASENAME"
 | |
| 
 | |
| 	$SUDO chown $UID "$KCORE_DIR"
 | |
| 	$SUDO chown $UID "$KCORE_DIR/kcore"
 | |
| 	$SUDO chown $UID "$KCORE_DIR/kallsyms"
 | |
| 	$SUDO chown $UID "$KCORE_DIR/modules"
 | |
| 
 | |
| 	$SUDO chgrp $GROUPS "$KCORE_DIR"
 | |
| 	$SUDO chgrp $GROUPS "$KCORE_DIR/kcore"
 | |
| 	$SUDO chgrp $GROUPS "$KCORE_DIR/kallsyms"
 | |
| 	$SUDO chgrp $GROUPS "$KCORE_DIR/modules"
 | |
| 
 | |
| 	ln -s "$KCORE_DIR_BASENAME" "$PERF_DATA_DIR/kcore_dir"
 | |
| }
 | |
| 
 | |
| fix_buildid_cache_permissions()
 | |
| {
 | |
| 	if [ $EUID -ne 0 ] ; then
 | |
| 		echo "This script must be run as root via sudo " >&2
 | |
| 		exit 1
 | |
| 	fi
 | |
| 
 | |
| 	if [ -z "$SUDO_USER" ] ; then
 | |
| 		echo "This script must be run via sudo" >&2
 | |
| 		exit 1
 | |
| 	fi
 | |
| 
 | |
| 	USER_HOME=$(bash <<< "echo ~$SUDO_USER")
 | |
| 
 | |
| 	echo "Fixing buildid cache permissions"
 | |
| 
 | |
| 	find "$USER_HOME/.debug" -xdev -type d          ! -user "$SUDO_USER" -ls -exec chown    "$SUDO_USER" \{\} \;
 | |
| 	find "$USER_HOME/.debug" -xdev -type f -links 1 ! -user "$SUDO_USER" -ls -exec chown    "$SUDO_USER" \{\} \;
 | |
| 	find "$USER_HOME/.debug" -xdev -type l          ! -user "$SUDO_USER" -ls -exec chown -h "$SUDO_USER" \{\} \;
 | |
| 
 | |
| 	if [ -n "$SUDO_GID" ] ; then
 | |
| 		find "$USER_HOME/.debug" -xdev -type d          ! -group "$SUDO_GID" -ls -exec chgrp    "$SUDO_GID" \{\} \;
 | |
| 		find "$USER_HOME/.debug" -xdev -type f -links 1 ! -group "$SUDO_GID" -ls -exec chgrp    "$SUDO_GID" \{\} \;
 | |
| 		find "$USER_HOME/.debug" -xdev -type l          ! -group "$SUDO_GID" -ls -exec chgrp -h "$SUDO_GID" \{\} \;
 | |
| 	fi
 | |
| 
 | |
| 	echo "Done"
 | |
| }
 | |
| 
 | |
| check_buildid_cache_permissions()
 | |
| {
 | |
| 	if [ $EUID -eq 0 ] ; then
 | |
| 		return
 | |
| 	fi
 | |
| 
 | |
| 	PERMISSIONS_OK+=$(find "$HOME/.debug" -xdev -type d          ! -user "$USER" -print -quit)
 | |
| 	PERMISSIONS_OK+=$(find "$HOME/.debug" -xdev -type f -links 1 ! -user "$USER" -print -quit)
 | |
| 	PERMISSIONS_OK+=$(find "$HOME/.debug" -xdev -type l          ! -user "$USER" -print -quit)
 | |
| 
 | |
| 	PERMISSIONS_OK+=$(find "$HOME/.debug" -xdev -type d          ! -group "$GROUPS" -print -quit)
 | |
| 	PERMISSIONS_OK+=$(find "$HOME/.debug" -xdev -type f -links 1 ! -group "$GROUPS" -print -quit)
 | |
| 	PERMISSIONS_OK+=$(find "$HOME/.debug" -xdev -type l          ! -group "$GROUPS" -print -quit)
 | |
| 
 | |
| 	if [ -n "$PERMISSIONS_OK" ] ; then
 | |
| 		echo "*** WARNING *** buildid cache permissions may need fixing" >&2
 | |
| 	fi
 | |
| }
 | |
| 
 | |
| record()
 | |
| {
 | |
| 	echo "Recording"
 | |
| 
 | |
| 	if [ $EUID -ne 0 ] ; then
 | |
| 
 | |
| 		if [ "$(cat /proc/sys/kernel/kptr_restrict)" -ne 0 ] ; then
 | |
| 			echo "*** WARNING *** /proc/sys/kernel/kptr_restrict prevents access to kernel addresses" >&2
 | |
| 		fi
 | |
| 
 | |
| 		if echo "${PERF_OPTIONS[@]}" | grep -q ' -a \|^-a \| -a$\|^-a$\| --all-cpus \|^--all-cpus \| --all-cpus$\|^--all-cpus$' ; then
 | |
| 			echo "*** WARNING *** system-wide tracing without root access will not be able to read all necessary information from /proc" >&2
 | |
| 		fi
 | |
| 
 | |
| 		if echo "${PERF_OPTIONS[@]}" | grep -q 'intel_pt\|intel_bts\| -I\|^-I' ; then
 | |
| 			if [ "$(cat /proc/sys/kernel/perf_event_paranoid)" -gt -1 ] ; then
 | |
| 				echo "*** WARNING *** /proc/sys/kernel/perf_event_paranoid restricts buffer size and tracepoint (sched_switch) use" >&2
 | |
| 			fi
 | |
| 
 | |
| 			if echo "${PERF_OPTIONS[@]}" | grep -q ' --per-thread \|^--per-thread \| --per-thread$\|^--per-thread$' ; then
 | |
| 				true
 | |
| 			elif echo "${PERF_OPTIONS[@]}" | grep -q ' -t \|^-t \| -t$\|^-t$' ; then
 | |
| 				true
 | |
| 			elif [ ! -r /sys/kernel/debug -o ! -x /sys/kernel/debug ] ; then
 | |
| 				echo "*** WARNING *** /sys/kernel/debug permissions prevent tracepoint (sched_switch) use" >&2
 | |
| 			fi
 | |
| 		fi
 | |
| 	fi
 | |
| 
 | |
| 	if [ -z "$1" ] ; then
 | |
| 		echo "Workload is required for recording" >&2
 | |
| 		usage
 | |
| 	fi
 | |
| 
 | |
| 	if [ -e "$PERF_DATA_DIR" ] ; then
 | |
| 		echo "'$PERF_DATA_DIR' exists" >&2
 | |
| 		exit 1
 | |
| 	fi
 | |
| 
 | |
| 	find_perf
 | |
| 
 | |
| 	mkdir "$PERF_DATA_DIR"
 | |
| 
 | |
| 	echo "$PERF record -o $PERF_DATA_DIR/perf.data ${PERF_OPTIONS[@]} -- $@"
 | |
| 	"$PERF" record -o "$PERF_DATA_DIR/perf.data" "${PERF_OPTIONS[@]}" -- "$@" || true
 | |
| 
 | |
| 	if rmdir "$PERF_DATA_DIR" > /dev/null 2>/dev/null ; then
 | |
| 		exit 1
 | |
| 	fi
 | |
| 
 | |
| 	copy_kcore
 | |
| 
 | |
| 	echo "Done"
 | |
| }
 | |
| 
 | |
| subcommand()
 | |
| {
 | |
| 	find_perf
 | |
| 	check_buildid_cache_permissions
 | |
| 	echo "$PERF $PERF_SUB_COMMAND -i $PERF_DATA_DIR/perf.data --kallsyms=$PERF_DATA_DIR/kcore_dir/kallsyms $@"
 | |
| 	"$PERF" $PERF_SUB_COMMAND -i "$PERF_DATA_DIR/perf.data" "--kallsyms=$PERF_DATA_DIR/kcore_dir/kallsyms" "$@"
 | |
| }
 | |
| 
 | |
| if [ "$1" = "fix_buildid_cache_permissions" ] ; then
 | |
| 	fix_buildid_cache_permissions
 | |
| 	exit 0
 | |
| fi
 | |
| 
 | |
| PERF_SUB_COMMAND=$1
 | |
| PERF_DATA_DIR=$2
 | |
| shift || true
 | |
| shift || true
 | |
| 
 | |
| if [ -z "$PERF_SUB_COMMAND" ] ; then
 | |
| 	usage
 | |
| fi
 | |
| 
 | |
| if [ -z "$PERF_DATA_DIR" ] ; then
 | |
| 	usage
 | |
| fi
 | |
| 
 | |
| case "$PERF_SUB_COMMAND" in
 | |
| "record")
 | |
| 	while [ "$1" != "--" ] ; do
 | |
| 		PERF_OPTIONS+=("$1")
 | |
| 		shift || break
 | |
| 	done
 | |
| 	if [ "$1" != "--" ] ; then
 | |
| 		echo "Options and workload are required for recording" >&2
 | |
| 		usage
 | |
| 	fi
 | |
| 	shift
 | |
| 	record "$@"
 | |
| ;;
 | |
| "script")
 | |
| 	subcommand "$@"
 | |
| ;;
 | |
| "report")
 | |
| 	subcommand "$@"
 | |
| ;;
 | |
| "inject")
 | |
| 	subcommand "$@"
 | |
| ;;
 | |
| *)
 | |
| 	usage
 | |
| ;;
 | |
| esac
 |