Re: [PATCH v2 2/2] selftest/cpuidle: Add support for cpuidle latency measurement

2020-07-21 Thread Pratik Sampat

Hi Gautham, Thanks for the review.


On 20/07/20 11:22 am, Gautham R Shenoy wrote:

Hi Pratik,


On Fri, Jul 17, 2020 at 02:48:01PM +0530, Pratik Rajesh Sampat wrote:

This patch adds support to trace IPI based and timer based wakeup
latency from idle states

Latches onto the test-cpuidle_latency kernel module using the debugfs
interface to send IPIs or schedule a timer based event, which in-turn
populates the debugfs with the latency measurements.

Currently for the IPI and timer tests; first disable all idle states
and then test for latency measurements incrementally enabling each state

Signed-off-by: Pratik Rajesh Sampat 

A few comments below.


---
  tools/testing/selftests/Makefile   |   1 +
  tools/testing/selftests/cpuidle/Makefile   |   6 +
  tools/testing/selftests/cpuidle/cpuidle.sh | 257 +
  tools/testing/selftests/cpuidle/settings   |   1 +
  4 files changed, 265 insertions(+)
  create mode 100644 tools/testing/selftests/cpuidle/Makefile
  create mode 100755 tools/testing/selftests/cpuidle/cpuidle.sh
  create mode 100644 tools/testing/selftests/cpuidle/settings


[..skip..]


+
+ins_mod()
+{
+   if [ ! -f "$MODULE" ]; then
+   printf "$MODULE module does not exist. Exitting\n"

If the module has been compiled into the kernel (due to a
localyesconfig, for instance), then it is unlikely that we will find
it in /lib/modules. Perhaps you want to check if the debugfs
directories created by the module exist, and if so, print a message
saying that the modules is already loaded or some such?


That's a good idea. I can can grep for this module within /proc/modules
and not insert it, if it is already there


+   exit $ksft_skip
+   fi
+   printf "Inserting $MODULE module\n\n"
+   insmod $MODULE
+   if [ $? != 0 ]; then
+   printf "Insmod $MODULE failed\n"
+   exit $ksft_skip
+   fi
+}
+
+compute_average()
+{
+   arr=("$@")
+   sum=0
+   size=${#arr[@]}
+   for i in "${arr[@]}"
+   do
+   sum=$((sum + i))
+   done
+   avg=$((sum/size))

It would be good to assert that "size" isn't 0 here.


Sure


+}
+
+# Disable all stop states
+disable_idle()
+{
+   for ((cpu=0; cpu 
/sys/devices/system/cpu/cpu$cpu/cpuidle/state$state/disable

So, on offlined CPUs, we won't see
/sys/devices/system/cpu/cpu$cpu/cpuidle/state$state directory. You
should probably perform this operation only on online CPUs.


Right. I should make CPU operations only on online CPUs all over the script

[..snip..]

Thanks
Pratik



Re: [PATCH v2 2/2] selftest/cpuidle: Add support for cpuidle latency measurement

2020-07-19 Thread Gautham R Shenoy
Hi Pratik,


On Fri, Jul 17, 2020 at 02:48:01PM +0530, Pratik Rajesh Sampat wrote:
> This patch adds support to trace IPI based and timer based wakeup
> latency from idle states
> 
> Latches onto the test-cpuidle_latency kernel module using the debugfs
> interface to send IPIs or schedule a timer based event, which in-turn
> populates the debugfs with the latency measurements.
> 
> Currently for the IPI and timer tests; first disable all idle states
> and then test for latency measurements incrementally enabling each state
> 
> Signed-off-by: Pratik Rajesh Sampat 

A few comments below.

> ---
>  tools/testing/selftests/Makefile   |   1 +
>  tools/testing/selftests/cpuidle/Makefile   |   6 +
>  tools/testing/selftests/cpuidle/cpuidle.sh | 257 +
>  tools/testing/selftests/cpuidle/settings   |   1 +
>  4 files changed, 265 insertions(+)
>  create mode 100644 tools/testing/selftests/cpuidle/Makefile
>  create mode 100755 tools/testing/selftests/cpuidle/cpuidle.sh
>  create mode 100644 tools/testing/selftests/cpuidle/settings
> 

[..skip..]

> +
> +ins_mod()
> +{
> + if [ ! -f "$MODULE" ]; then
> + printf "$MODULE module does not exist. Exitting\n"

If the module has been compiled into the kernel (due to a
localyesconfig, for instance), then it is unlikely that we will find
it in /lib/modules. Perhaps you want to check if the debugfs
directories created by the module exist, and if so, print a message
saying that the modules is already loaded or some such?

> + exit $ksft_skip
> + fi
> + printf "Inserting $MODULE module\n\n"
> + insmod $MODULE
> + if [ $? != 0 ]; then
> + printf "Insmod $MODULE failed\n"
> + exit $ksft_skip
> + fi
> +}
> +
> +compute_average()
> +{
> + arr=("$@")
> + sum=0
> + size=${#arr[@]}
> + for i in "${arr[@]}"
> + do
> + sum=$((sum + i))
> + done
> + avg=$((sum/size))

It would be good to assert that "size" isn't 0 here.

> +}
> +
> +# Disable all stop states
> +disable_idle()
> +{
> + for ((cpu=0; cpu + do
> + for ((state=0; state + do
> + echo 1 > 
> /sys/devices/system/cpu/cpu$cpu/cpuidle/state$state/disable

So, on offlined CPUs, we won't see
/sys/devices/system/cpu/cpu$cpu/cpuidle/state$state directory. You
should probably perform this operation only on online CPUs.


> + done
> + done
> +}
> +
> +# Perform operation on each CPU for the given state
> +# $1 - Operation: enable (0) / disable (1)
> +# $2 - State to enable
> +op_state()
> +{
> + for ((cpu=0; cpu + do
> + echo $1 > 
> /sys/devices/system/cpu/cpu$cpu/cpuidle/state$2/disable


Ditto

> + done
> +}

This is a helper function. For better readability of the main code you
can define the following wrappers and use them.


cpuidle_enable_state()
{
state=$1
op_state 1 $state
}

cpuidle_disable_state()
{
state=$1
op_state 0 $state

}


> +

[..snip..]

> +run_ipi_tests()
> +{
> +extract_latency
> +disable_idle
> +declare -a avg_arr
> +echo -e "--IPI Latency Test---" >> $LOG
> +
> + echo -e "--Baseline IPI Latency measurement: CPU Busy--" >> $LOG
> + printf "%s %10s %12s\n" "SRC_CPU" "DEST_CPU" "IPI_Latency(ns)" 
> >> $LOG
> + for ((cpu=0; cpu + do
> + ipi_test_once "baseline" $cpu
> + printf "%-3s %10s %12s\n" $src_cpu $cpu $ipi_latency >> 
> $LOG
> + avg_arr+=($ipi_latency)
> + done
> + compute_average "${avg_arr[@]}"
> + echo -e "Baseline Average IPI latency(ns): $avg" >> $LOG
> +
> +for ((state=0; state +do
> + unset avg_arr
> + echo -e "---Enabling state: $state---" >> $LOG
> + op_state 0 $state
> + printf "%s %10s %12s\n" "SRC_CPU" "DEST_CPU" 
> "IPI_Latency(ns)" >> $LOG
> + for ((cpu=0; cpu + do

If a CPU is offline, then we should skip it here.

> + # Running IPI test and logging results
> + sleep 1
> + ipi_test_once "test" $cpu
> + printf "%-3s %10s %12s\n" $src_cpu $cpu 
> $ipi_latency >> $LOG
> + avg_arr+=($ipi_latency)
> + done
> + compute_average "${avg_arr[@]}"
> + echo -e "Expected IPI latency(ns): 
> ${latency_arr[$state]}" >> $LOG
> + echo -e "Observed Average IPI latency(ns): $avg" >> $LOG
> + op_state 1 $state
> +done
> +}
> +
> +# Extract the residency in microseconds and convert to nanoseconds.
> +# Add 100 ns so that the timer stays for a little longer than the residency
> +extract_residency()
> +{
> +

[PATCH v2 2/2] selftest/cpuidle: Add support for cpuidle latency measurement

2020-07-17 Thread Pratik Rajesh Sampat
This patch adds support to trace IPI based and timer based wakeup
latency from idle states

Latches onto the test-cpuidle_latency kernel module using the debugfs
interface to send IPIs or schedule a timer based event, which in-turn
populates the debugfs with the latency measurements.

Currently for the IPI and timer tests; first disable all idle states
and then test for latency measurements incrementally enabling each state

Signed-off-by: Pratik Rajesh Sampat 
---
 tools/testing/selftests/Makefile   |   1 +
 tools/testing/selftests/cpuidle/Makefile   |   6 +
 tools/testing/selftests/cpuidle/cpuidle.sh | 257 +
 tools/testing/selftests/cpuidle/settings   |   1 +
 4 files changed, 265 insertions(+)
 create mode 100644 tools/testing/selftests/cpuidle/Makefile
 create mode 100755 tools/testing/selftests/cpuidle/cpuidle.sh
 create mode 100644 tools/testing/selftests/cpuidle/settings

diff --git a/tools/testing/selftests/Makefile b/tools/testing/selftests/Makefile
index 1195bd85af38..ab6cf51f3518 100644
--- a/tools/testing/selftests/Makefile
+++ b/tools/testing/selftests/Makefile
@@ -7,6 +7,7 @@ TARGETS += capabilities
 TARGETS += cgroup
 TARGETS += clone3
 TARGETS += cpufreq
+TARGETS += cpuidle
 TARGETS += cpu-hotplug
 TARGETS += drivers/dma-buf
 TARGETS += efivarfs
diff --git a/tools/testing/selftests/cpuidle/Makefile 
b/tools/testing/selftests/cpuidle/Makefile
new file mode 100644
index ..72fd5d2e974d
--- /dev/null
+++ b/tools/testing/selftests/cpuidle/Makefile
@@ -0,0 +1,6 @@
+# SPDX-License-Identifier: GPL-2.0
+all:
+
+TEST_PROGS := cpuidle.sh
+
+include ../lib.mk
diff --git a/tools/testing/selftests/cpuidle/cpuidle.sh 
b/tools/testing/selftests/cpuidle/cpuidle.sh
new file mode 100755
index ..5c313a3abb0c
--- /dev/null
+++ b/tools/testing/selftests/cpuidle/cpuidle.sh
@@ -0,0 +1,257 @@
+#!/bin/bash
+# SPDX-License-Identifier: GPL-2.0
+
+LOG=cpuidle.log
+MODULE=/lib/modules/$(uname -r)/kernel/drivers/cpuidle/test-cpuidle_latency.ko
+
+# Kselftest framework requirement - SKIP code is 4.
+ksft_skip=4
+
+helpme()
+{
+   printf "Usage: $0 [-h] [-todg args]
+   [-h ]
+   [-m ]
+   [-o ]
+   \n"
+   exit 2
+}
+
+parse_arguments()
+{
+   while getopts ht:m:o: arg
+   do
+   case $arg in
+   h) # --help
+   helpme
+   ;;
+   m) # --mod-file
+   MODULE=$OPTARG
+   ;;
+   o) # output log files
+   LOG=$OPTARG
+   ;;
+   \?)
+   helpme
+   ;;
+   esac
+   done
+}
+
+ins_mod()
+{
+   if [ ! -f "$MODULE" ]; then
+   printf "$MODULE module does not exist. Exitting\n"
+   exit $ksft_skip
+   fi
+   printf "Inserting $MODULE module\n\n"
+   insmod $MODULE
+   if [ $? != 0 ]; then
+   printf "Insmod $MODULE failed\n"
+   exit $ksft_skip
+   fi
+}
+
+compute_average()
+{
+   arr=("$@")
+   sum=0
+   size=${#arr[@]}
+   for i in "${arr[@]}"
+   do
+   sum=$((sum + i))
+   done
+   avg=$((sum/size))
+}
+
+# Disable all stop states
+disable_idle()
+{
+   for ((cpu=0; cpu 
/sys/devices/system/cpu/cpu$cpu/cpuidle/state$state/disable
+   done
+   done
+}
+
+# Perform operation on each CPU for the given state
+# $1 - Operation: enable (0) / disable (1)
+# $2 - State to enable
+op_state()
+{
+   for ((cpu=0; cpu 
/sys/devices/system/cpu/cpu$cpu/cpuidle/state$2/disable
+   done
+}
+
+# Extract latency in microseconds and convert to nanoseconds
+extract_latency()
+{
+   for ((state=0; state /dev/null &
+   task_pid=$!
+   # Wait for the workload to achieve 100% CPU usage
+   sleep 1
+fi
+taskset 0x1 echo $dest_cpu > 
/sys/kernel/debug/latency_test/ipi_cpu_dest
+ipi_latency=$(cat /sys/kernel/debug/latency_test/ipi_latency_ns)
+src_cpu=$(cat /sys/kernel/debug/latency_test/ipi_cpu_src)
+if [ "$1" = "baseline" ]; then
+   kill $task_pid
+   wait $task_pid 2>/dev/null
+fi
+}
+
+# Incrementally Enable idle states one by one and compute the latency
+run_ipi_tests()
+{
+extract_latency
+disable_idle
+declare -a avg_arr
+echo -e "--IPI Latency Test---" >> $LOG
+
+   echo -e "--Baseline IPI Latency measurement: CPU Busy--" >> $LOG
+   printf "%s %10s %12s\n" "SRC_CPU" "DEST_CPU" "IPI_Latency(ns)" 
>> $LOG
+   for ((cpu=0; cpu> 
$LOG
+   avg_arr+=($ipi_latency)
+   done
+   compute_average "${avg_arr[@]}"
+   echo -e "Baseline Aver