#!__DEVLIB_SHELL__

CMD=$1
shift

BUSYBOX=${BUSYBOX:-__DEVLIB_BUSYBOX__}
FIND=${FIND:-$BUSYBOX find}
GREP=${GREP:-$BUSYBOX grep}
SED=${SED:-$BUSYBOX sed}
CAT=${CAT:-$BUSYBOX cat}
AWK=${AWK:-$BUSYBOX awk}
PS=${PS:-$BUSYBOX ps}

################################################################################
# CPUFrequency Utility Functions
################################################################################

cpufreq_set_all_frequencies() {
	FREQ=$1
	for CPU in /sys/devices/system/cpu/cpu[0-9]*; do
		echo $FREQ > $CPU/cpufreq/scaling_cur_freq
	done
}

cpufreq_get_all_frequencies() {
	$GREP '' /sys/devices/system/cpu/cpu*/cpufreq/scaling_cur_freq | \
		$SED -e 's|/sys/devices/system/cpu/cpu||' -e 's|/cpufreq/scaling_cur_freq:| |'
}

cpufreq_set_all_governors() {
	GOV=$1
	for CPU in /sys/devices/system/cpu/cpu[0-9]*; do
		echo $GOV > $CPU/cpufreq/scaling_governor
	done
}

cpufreq_get_all_governors() {
	$GREP '' /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor | \
		$SED -e 's|/sys/devices/system/cpu/cpu||' -e 's|/cpufreq/scaling_governor:| |'
}

cpufreq_trace_all_frequencies() {
	FREQS=$($CAT /sys/devices/system/cpu/cpu*/cpufreq/scaling_cur_freq)
	CPU=0; for F in $FREQS; do
		echo "cpu_frequency_devlib:        state=$F cpu_id=$CPU" > /sys/kernel/debug/tracing/trace_marker
		CPU=$((CPU + 1))
	done
}

################################################################################
# CPUIdle Utility Functions
################################################################################

cpuidle_wake_all_cpus() {
	CPU_PATHS=/sys/devices/system/cpu/cpu[0-9]*
	MASK=0x1; for F in $CPU_PATHS; do
		$BUSYBOX taskset $MASK true &
		MASK=$($BUSYBOX printf '0x%x' $((MASK * 2)))
	done
}

################################################################################
# FTrace Utility Functions
################################################################################

ftrace_get_function_stats() {
    for CPU in $(ls /sys/kernel/debug/tracing/trace_stat | sed 's/function//'); do
        REPLACE_STRING="s/  Function/\n  Function (CPU$CPU)/"
        $CAT /sys/kernel/debug/tracing/trace_stat/function$CPU \
            | sed "$REPLACE_STRING"
    done
}


################################################################################
# CGroups Utility Functions
################################################################################

cgroups_get_attributes() {
	test $# -eq 2 || exit -1
	CGROUP="$1"
	CONTROLLER="$2"
	# Check if controller is mounted with "noprefix" option, which is quite
	# common on Android for backward compatibility
	ls $CGROUP/$CONTROLLER\.* 2>&1 >/dev/null
	if [ $? -eq 0 ]; then
		# no "noprefix" option, attributes format is:
		#   mnt_point/controller.attribute_name
		$GREP '' $CGROUP/* | \
			$GREP "$CONTROLLER\." | \
			$SED -e "s|$CONTROLLER\.||" -e "s|$CGROUP/||"
	else
		# "noprefix" option, attribute format is:
		#   mnt_point/attribute_name
		$GREP '' $(\
			$FIND $CGROUP -type f -maxdepth 1 |
			$GREP -v -e ".*tasks" -e ".*cgroup\..*") | \
		$SED "s|$CGROUP/||"
	fi
}

cgroups_run_into() {

	# Control groups mount point
	CGMOUNT=${CGMOUNT:-/sys/fs/cgroup}
	# The control group we want to run into
	CGP=${1}
	shift 1
	# The command to run
	CMD="${@}"

	# Execution under root CGgroup
	if [ "x/" == "x$CGP" ]; then

	  $FIND $CGMOUNT -type d -maxdepth 0 | \
	  while read CGPATH; do
		# Move this shell into that control group
		echo $$ > $CGPATH/cgroup.procs
		echo "Moving task into root CGroup ($CGPATH)"
	  done

	# Execution under specified CGroup
	else

	  # Check if the required CGroup exists
	  $FIND $CGMOUNT -type d -mindepth 1 | \
	  $GREP "$CGP" &>/dev/null
	  if [ $? -ne 0 ]; then
		echo "ERROR: could not find any $CGP cgroup under $CGMOUNT"
		exit 1
	  fi

	  $FIND $CGMOUNT -type d -mindepth 1 | \
	  $GREP "$CGP" | \
	  while read CGPATH; do
		  # Move this shell into that control group
		  echo $$ > $CGPATH/cgroup.procs
		  echo "Moving task into $CGPATH"
	  done

	fi

	# Execute the command
	exec $CMD

}

cgroups_tasks_move() {
	SRC_GRP=${1}
	DST_GRP=${2}
	shift 2
	FILTERS=$*

	$CAT $SRC_GRP/tasks | while read TID; do
	  echo $TID > $DST_GRP/cgroup.procs
	done

	[ "x$FILTERS" = "x" ] && exit 0

	PIDS=`$PS -o comm,pid | $GREP $FILTERS | $AWK '{print $2}'`
	PIDS=`echo $PIDS`
	echo "PIDs to save: [$PIDS]"
	for TID in $PIDS; do
	  COMM=`$CAT /proc/$TID/comm`
	  echo "$TID : $COMM"
	  echo $TID > $SRC_GRP/cgroup.procs || true
	done
}

cgroups_tasks_in() {
	GRP=${1}
	for TID in $($CAT $GRP/tasks); do
		COMM=`$CAT /proc/$TID/comm 2>/dev/null`
		[ "$COMM" != "" ] && CMDL=`$CAT /proc/$TID/cmdline 2>/dev/null`
		[ "$COMM" != "" ] && echo "$TID,$COMM,$CMDL"
	done
	exit 0
}


################################################################################
# Main Function Dispatcher
################################################################################

case $CMD in
cpufreq_set_all_frequencies)
    cpufreq_set_all_frequencies $*
    ;;
cpufreq_get_all_frequencies)
    cpufreq_get_all_frequencies
    ;;
cpufreq_set_all_governors)
    cpufreq_set_all_governors $*
    ;;
cpufreq_get_all_governors)
    cpufreq_get_all_governors
    ;;
cpufreq_trace_all_frequencies)
    cpufreq_trace_all_frequencies $*
    ;;
cpuidle_wake_all_cpus)
    cpuidle_wake_all_cpus $*
    ;;
cgroups_get_attributes)
	cgroups_get_attributes $*
	;;
cgroups_run_into)
    cgroups_run_into $*
    ;;
cgroups_tasks_move)
	cgroups_tasks_move $*
	;;
cgroups_tasks_in)
	cgroups_tasks_in $*
	;;
ftrace_get_function_stats)
    ftrace_get_function_stats
    ;;
*)
    echo "Command [$CMD] not supported"
    exit -1
esac

# vim: tabstop=4 shiftwidth=4
