From 4617721c502b2ddaa4e324e86da4997edf738fa5 Mon Sep 17 00:00:00 2001 From: Steven Rostedt Date: Wed, 2 Sep 2026 09:55:01 -0400 Subject: ftrace: Synchronize the initialization of ftrace_ops There's some internal state that ftrace_ops needs to have set, but since it can be declared outside of the ftrace.c code, it calls ftrace_ops_init() on the ops in every global function. The issue is that if two tasks call it on the same ops at the same time it is possible to have the initialization of one corrupt the initialization of the other call. Create a ops_mutex to use to synchronize every initialization of the ftrace_ops. The mutex is taken within checking the ftrace_ops flag that states it was initializied but the flag is checked again after the mutex has been taken. Checking first outside the mutex allows it to shortcut having to take the mutex. But then the check needs to be done again after the mute is taken in case of races. Cc: stable@vger.kernel.org Link: https://patch.msgid.link/20260902095501.6b59af20@gandalf.local.home Fixes: f04f24fb7e48d ("ftrace, kprobes: Fix a deadlock on ftrace_regex_lock") Reported-by: sashiko-bot@kernel.org Close: https://lore.kernel.org/all/20260829025528.49A831F000E9@smtp.kernel.org/ Signed-off-by: Steven Rostedt --- tools/tracing/rtla/tests/bpf/bpf_action_map.c | 25 + tools/tracing/rtla/tests/engine.sh | 173 ++++ tools/tracing/rtla/tests/hwnoise.t | 25 + tools/tracing/rtla/tests/osnoise.t | 102 +++ .../rtla/tests/scripts/check-cgroup-match.sh | 17 + tools/tracing/rtla/tests/scripts/check-cpus.sh | 9 + .../rtla/tests/scripts/check-housekeeping-cpus.sh | 4 + .../rtla/tests/scripts/check-osnoise-option.sh | 16 + tools/tracing/rtla/tests/scripts/check-priority.sh | 8 + .../rtla/tests/scripts/check-tracefs-value.sh | 11 + .../tests/scripts/check-user-kernel-threads.sh | 16 + .../rtla/tests/scripts/lib/get_workload_pids.sh | 11 + tools/tracing/rtla/tests/timerlat.t | 156 ++++ tools/tracing/rtla/tests/unit/Build | 8 + tools/tracing/rtla/tests/unit/Makefile.unit | 17 + tools/tracing/rtla/tests/unit/actions.c | 393 +++++++++ tools/tracing/rtla/tests/unit/cli_opt_callback.c | 912 +++++++++++++++++++++ tools/tracing/rtla/tests/unit/cli_params_assert.h | 68 ++ tools/tracing/rtla/tests/unit/osnoise_hist_cli.c | 575 +++++++++++++ tools/tracing/rtla/tests/unit/osnoise_top_cli.c | 521 ++++++++++++ tools/tracing/rtla/tests/unit/timerlat_hist_cli.c | 740 +++++++++++++++++ tools/tracing/rtla/tests/unit/timerlat_top_cli.c | 672 +++++++++++++++ tools/tracing/rtla/tests/unit/unit_tests.c | 39 + tools/tracing/rtla/tests/unit/utils.c | 106 +++ 24 files changed, 4624 insertions(+) create mode 100644 tools/tracing/rtla/tests/bpf/bpf_action_map.c create mode 100644 tools/tracing/rtla/tests/engine.sh create mode 100644 tools/tracing/rtla/tests/hwnoise.t create mode 100644 tools/tracing/rtla/tests/osnoise.t create mode 100755 tools/tracing/rtla/tests/scripts/check-cgroup-match.sh create mode 100755 tools/tracing/rtla/tests/scripts/check-cpus.sh create mode 100755 tools/tracing/rtla/tests/scripts/check-housekeeping-cpus.sh create mode 100755 tools/tracing/rtla/tests/scripts/check-osnoise-option.sh create mode 100755 tools/tracing/rtla/tests/scripts/check-priority.sh create mode 100755 tools/tracing/rtla/tests/scripts/check-tracefs-value.sh create mode 100755 tools/tracing/rtla/tests/scripts/check-user-kernel-threads.sh create mode 100644 tools/tracing/rtla/tests/scripts/lib/get_workload_pids.sh create mode 100644 tools/tracing/rtla/tests/timerlat.t create mode 100644 tools/tracing/rtla/tests/unit/Build create mode 100644 tools/tracing/rtla/tests/unit/Makefile.unit create mode 100644 tools/tracing/rtla/tests/unit/actions.c create mode 100644 tools/tracing/rtla/tests/unit/cli_opt_callback.c create mode 100644 tools/tracing/rtla/tests/unit/cli_params_assert.h create mode 100644 tools/tracing/rtla/tests/unit/osnoise_hist_cli.c create mode 100644 tools/tracing/rtla/tests/unit/osnoise_top_cli.c create mode 100644 tools/tracing/rtla/tests/unit/timerlat_hist_cli.c create mode 100644 tools/tracing/rtla/tests/unit/timerlat_top_cli.c create mode 100644 tools/tracing/rtla/tests/unit/unit_tests.c create mode 100644 tools/tracing/rtla/tests/unit/utils.c (limited to 'tools/tracing/rtla/tests') diff --git a/tools/tracing/rtla/tests/bpf/bpf_action_map.c b/tools/tracing/rtla/tests/bpf/bpf_action_map.c new file mode 100644 index 000000000..1686e0b85 --- /dev/null +++ b/tools/tracing/rtla/tests/bpf/bpf_action_map.c @@ -0,0 +1,25 @@ +// SPDX-License-Identifier: GPL-2.0 +#include +#include + +char LICENSE[] SEC("license") = "GPL"; + +struct { + __uint(type, BPF_MAP_TYPE_ARRAY); + __uint(max_entries, 1); + __type(key, unsigned int); + __type(value, unsigned long long); +} rtla_test_map SEC(".maps"); + +struct trace_event_raw_timerlat_sample; + +SEC("tp/timerlat_action") +int action_handler(struct trace_event_raw_timerlat_sample *tp_args) +{ + unsigned int key = 0; + unsigned long long value = 42; + + bpf_map_update_elem(&rtla_test_map, &key, &value, BPF_ANY); + + return 0; +} diff --git a/tools/tracing/rtla/tests/engine.sh b/tools/tracing/rtla/tests/engine.sh new file mode 100644 index 000000000..4287cd64a --- /dev/null +++ b/tools/tracing/rtla/tests/engine.sh @@ -0,0 +1,173 @@ +#!/bin/bash +# SPDX-License-Identifier: GPL-2.0 +test_begin() { + # Count tests to allow the test harness to double-check if all were + # included correctly. + ctr=0 + # Set test directory to the directory of the script + scriptfile=$(realpath "$0") + testdir=$(dirname "$scriptfile") + [ -z "$RTLA" ] && RTLA="./rtla" + [ -n "$TEST_COUNT" ] && echo "1..$TEST_COUNT" +} + +reset_osnoise() { + # Reset osnoise options to default and remove any dangling instances created + # by improperly exited rtla runs. + pushd /sys/kernel/tracing >/dev/null || return 1 + + # Remove dangling instances created by previous rtla run + echo 0 > tracing_thresh + cd instances + for i in osnoise_top osnoise_hist timerlat_top timerlat_hist + do + [ ! -d "$i" ] && continue + rmdir "$i" + done + + # Reset options to default + # Note: those are copied from the default values of osnoise_data + # in kernel/trace/trace_osnoise.c + cd ../osnoise + echo all > cpus + echo DEFAULTS > options + echo 1000000 > period_us + echo 0 > print_stack + echo 1000000 > runtime_us + echo 0 > stop_tracing_total_us + echo 0 > stop_tracing_us + echo 1000 > timerlat_period_us + + popd >/dev/null +} + +check() { + test_name=$0 + tested_command=$1 + expected_exitcode=${3:-0} + expected_output=$4 + unexpected_output=$5 + # Simple check: run rtla with given arguments and test exit code. + # If TEST_COUNT is set, run the test. Otherwise, just count. + ctr=$(($ctr + 1)) + if [ -n "$TEST_COUNT" ] + then + # Reset osnoise options before running test. + [ "$NO_RESET_OSNOISE" == 1 ] || reset_osnoise + + # Create a temporary directory to contain rtla output + tmpdir=$(mktemp -d) + pushd $tmpdir >/dev/null + + # Run rtla; in case of failure, include its output as comment + # in the test results. + result=$(eval stdbuf -oL $TIMEOUT "$RTLA" $2 2>&1); exitcode=$? + failbuf='' + fail=0 + + # Test if the results matches if requested + if [ -n "$expected_output" ] && ! grep -qE "$expected_output" <<< "$result" + then + fail=1 + failbuf+=$(printf "# Output match failed: \"%s\"" "$expected_output") + failbuf+=$'\n' + fi + + if [ -n "$unexpected_output" ] && grep -qE "$unexpected_output" <<< "$result" + then + fail=1 + failbuf+=$(printf "# Output non-match failed: \"%s\"" "$unexpected_output") + failbuf+=$'\n' + fi + + if [ $exitcode -eq $expected_exitcode ] && [ $fail -eq 0 ] + then + echo "ok $ctr - $1" + else + # Add rtla output and exit code as comments in case of failure + echo "not ok $ctr - $1" + echo -n "$failbuf" + echo "$result" | col -b | while read line; do echo "# $line"; done + printf "#\n# exit code %s\n" $exitcode + fi + + # Remove temporary directory + popd >/dev/null + rm -r $tmpdir + fi +} + +check_with_osnoise_options() { + # Do the same as "check", but with pre-set tracefs options. + # Resets osnoise first, then writes the given tracefs option=value + # pairs before running the check with NO_RESET_OSNOISE=1. + # Arguments: test_name command exit_code expected_output [path=value ...] + # Each path is relative to /sys/kernel/tracing/ + local arg1=$1 + local arg2=$2 + local arg3=$3 + local arg4=$4 + local opt option value + + # Apply tracefs options (if not dry run) + if [ -n "$TEST_COUNT" ] + then + [ "$NO_RESET_OSNOISE" == 1 ] || reset_osnoise + shift 4 + for opt in "$@" + do + [ -z "$opt" ] && continue + option="${opt%%=*}" + value="${opt#*=}" + # Try to apply the option, ignore errors: when pre-setting fails + # (e.g. kernel does not know the option), the test itself will likely + # also fail. + # Throwing an error here would cause the test to be incorrectly + # skipped. + echo "$value" > "/sys/kernel/tracing/$option" + done + fi + + NO_RESET_OSNOISE=1 check "$arg1" "$arg2" "$arg3" "$arg4" +} + +check_top_hist() { + # Test one command with both "top" and "hist" tools, replacing "TOOL" in + # command with either "top" or "hist" respectively, and prefixing the test + # names with "top " and "hist ". + check "top $1" "$(echo "$2" | sed 's/TOOL/top/g')" "${@:3}" + check "hist $1" "$(echo "$2" | sed 's/TOOL/hist/g')" "${@:3}" +} + +check_top_q_hist() { + # Same as above, but pass "-q" to top so that strings printed in main + # loop are on their own line for top too, not only for hist. + check "top $1" "$(echo "$2" | sed 's/TOOL/top -q/g')" "${@:3}" + check "hist $1" "$(echo "$2" | sed 's/TOOL/hist/g')" "${@:3}" +} + +set_timeout() { + TIMEOUT="timeout -v -k 15s $1" +} + +unset_timeout() { + unset TIMEOUT +} + +set_no_reset_osnoise() { + NO_RESET_OSNOISE=1 +} + +unset_no_reset_osnoise() { + unset NO_RESET_OSNOISE +} + +test_end() { + # If running without TEST_COUNT, tests are not actually run, just + # counted. In that case, re-run the test with the correct count. + [ -z "$TEST_COUNT" ] && TEST_COUNT=$ctr exec bash $0 || true +} + +# Avoid any environmental discrepancies +export LC_ALL=C +unset_timeout diff --git a/tools/tracing/rtla/tests/hwnoise.t b/tools/tracing/rtla/tests/hwnoise.t new file mode 100644 index 000000000..b53d8d440 --- /dev/null +++ b/tools/tracing/rtla/tests/hwnoise.t @@ -0,0 +1,25 @@ +#!/bin/bash +# SPDX-License-Identifier: GPL-2.0 +source tests/engine.sh +test_begin + +set_timeout 2m + +check "verify help page" \ + "hwnoise --help" 129 "Usage: rtla hwnoise" +check "detect noise higher than one microsecond" \ + "hwnoise -c 0 -T 1 -d 5s -q" 0 +check "set the automatic trace mode" \ + "hwnoise -a 5 -d 10s" 2 "osnoise hit stop tracing" +check "set scheduling param to the osnoise tracer threads" \ + "hwnoise -P F:1 -c 0 -r 900000 -d 10s -q" +check "stop the trace if a single sample is higher than 1 us" \ + "hwnoise -s 1 -T 1 -t -d 10s" 2 "Saving trace to osnoise_trace.txt" +check "enable a trace event trigger" \ + "hwnoise -t -e osnoise:irq_noise --trigger=\"hist:key=desc,duration:sort=desc,duration:vals=hitcount\" -d 10s" \ + 0 "Saving event osnoise:irq_noise hist to osnoise_irq_noise_hist.txt" +check "verify OSNOISE_IRQ_DISABLE" \ + "hwnoise -S 1 --on-threshold shell,command=\"$testdir/scripts/check-osnoise-option.sh OSNOISE_IRQ_DISABLE\"" \ + 2 "^OSNOISE_IRQ_DISABLE=enabled$" + +test_end diff --git a/tools/tracing/rtla/tests/osnoise.t b/tools/tracing/rtla/tests/osnoise.t new file mode 100644 index 000000000..214fd40fc --- /dev/null +++ b/tools/tracing/rtla/tests/osnoise.t @@ -0,0 +1,102 @@ +#!/bin/bash +# SPDX-License-Identifier: GPL-2.0 +source tests/engine.sh +test_begin + +set_timeout 2m + +check "verify help page" \ + "osnoise --help" 129 "osnoise version" +check_top_hist "verify help page" \ + "osnoise TOOL --help" 129 "rtla osnoise" +check_top_q_hist "verify the --stop/-s param" \ + "osnoise TOOL -s 30 -T 1" 2 "osnoise hit stop tracing" +check_top_q_hist "verify the --trace param" \ + "osnoise TOOL -s 30 -T 1 -t" 2 "Saving trace to osnoise_trace.txt" + +# Thread tests +check_top_q_hist "verify the --priority/-P param" \ + "osnoise TOOL -P F:1 -c 0 -r 900000 -d 10s -S 1 --on-threshold shell,command=\"$testdir/scripts/check-priority.sh SCHED_FIFO 1\"" \ + 2 "Priorities are set correctly" +check_top_q_hist "verify the -C/--cgroup param" \ + "osnoise TOOL -C -c 0 -r 900000 -d 10s -S 1 --on-threshold shell,command=\"$testdir/scripts/check-cgroup-match.sh\"" \ + 2 "cgroup matches for all workload PIDs" +check_top_q_hist "verify the -c/--cpus param" \ + "osnoise TOOL -P F:1 -c 0 -r 900000 -d 10s -S 1 --on-threshold shell,command=$testdir/scripts/check-cpus.sh" 2 "^Affinity of threads: 0$" +check_top_q_hist "verify the -H/--house-keeping param" \ + "osnoise TOOL -P F:1 -H 0 -r 900000 -d 10s -S 1 --on-threshold shell,command=$testdir/scripts/check-housekeeping-cpus.sh" 2 "^Affinity of threads: 0$" + +# Histogram tests +check "hist with -b/--bucket-size" \ + "osnoise hist -b 1 -d 1s" +check "hist with -E/--entries" \ + "osnoise hist -E 10 -d 1s" +check "hist with -E/--entries out of range" \ + "osnoise hist -E 1 -d 1s" 129 "out of range \[10, 9999999\]" +check "hist with --no-header" \ + "osnoise hist --no-header -d 1s" 0 "" "RTLA osnoise histogram" +check "hist with --with-zeros" \ + "osnoise hist --with-zeros -b 100000 -E 21 -d 1s" 0 '^2000000\s+0\s+' +check "hist with --no-index" \ + "osnoise hist --no-index --with-zeros -d 1s" 0 "" "^count:" +check "hist with --no-summary" \ + "osnoise hist --no-summary -d 1s" 0 "" "^count:" + +# Tracer option tests - verify that rtla correctly sets tracefs options +# Default tests: poison tracefs with wrong values, verify rtla resets to defaults +check_with_osnoise_options "apply default period" \ + "osnoise top -q -S 1 --on-threshold shell,command=\"$testdir/scripts/check-tracefs-value.sh osnoise/period_us\"" \ + 2 "^osnoise/period_us=1000000$" osnoise/period_us=600000000 +check_with_osnoise_options "apply default runtime" \ + "osnoise top -q -S 1 --on-threshold shell,command=\"$testdir/scripts/check-tracefs-value.sh osnoise/runtime_us\"" \ + 2 "^osnoise/runtime_us=1000000$" osnoise/runtime_us=100 +check_with_osnoise_options "apply default tracing_thresh" \ + "osnoise top -q -S 1 --on-threshold shell,command=\"$testdir/scripts/check-tracefs-value.sh tracing_thresh\"" \ + 2 "^tracing_thresh=0$" tracing_thresh=999999 +check_with_osnoise_options "apply default stop_tracing_us" \ + "osnoise top -q -S 1 --on-threshold shell,command=\"$testdir/scripts/check-tracefs-value.sh osnoise/stop_tracing_us\"" \ + 2 "^osnoise/stop_tracing_us=0$" osnoise/stop_tracing_us=999999 +check_with_osnoise_options "apply default stop_tracing_total_us" \ + "osnoise top -q -s 1 --on-threshold shell,command=\"$testdir/scripts/check-tracefs-value.sh osnoise/stop_tracing_total_us\"" \ + 2 "^osnoise/stop_tracing_total_us=0$" osnoise/stop_tracing_total_us=999999 + +# Non-default tracer option tests: verify CLI options correctly set tracefs values +check_top_q_hist "verify -p sets period_us" \ + "osnoise TOOL -p 2000000 -S 1 --on-threshold shell,command=\"$testdir/scripts/check-tracefs-value.sh osnoise/period_us\"" \ + 2 "^osnoise/period_us=2000000$" +check_top_q_hist "verify -r sets runtime_us" \ + "osnoise TOOL -r 500000 -S 1 --on-threshold shell,command=\"$testdir/scripts/check-tracefs-value.sh osnoise/runtime_us\"" \ + 2 "^osnoise/runtime_us=500000$" +check_top_q_hist "verify -T sets tracing_thresh" \ + "osnoise TOOL -T 5 -S 1 --on-threshold shell,command=\"$testdir/scripts/check-tracefs-value.sh tracing_thresh\"" \ + 2 "^tracing_thresh=5$" +check_top_q_hist "verify -s sets stop_tracing_us" \ + "osnoise TOOL -s 30 -S 1 --on-threshold shell,command=\"$testdir/scripts/check-tracefs-value.sh osnoise/stop_tracing_us\"" \ + 2 "^osnoise/stop_tracing_us=30$" +check_top_q_hist "verify -S sets stop_tracing_total_us" \ + "osnoise TOOL -S 100 --on-threshold shell,command=\"$testdir/scripts/check-tracefs-value.sh osnoise/stop_tracing_total_us\"" \ + 2 "^osnoise/stop_tracing_total_us=100$" + +# Actions tests +check_top_q_hist "trace output through -t with custom filename" \ + "osnoise TOOL -S 2 -t custom_filename.txt" 2 "^ Saving trace to custom_filename.txt$" +check_top_q_hist "trace output through --on-threshold trace" \ + "osnoise TOOL -S 2 --on-threshold trace" 2 "^ Saving trace to osnoise_trace.txt$" +check_top_q_hist "trace output through --on-threshold trace with custom filename" \ + "osnoise TOOL -S 2 --on-threshold trace,file=custom_filename.txt" 2 "^ Saving trace to custom_filename.txt$" +check_top_q_hist "exec command" \ + "osnoise TOOL -S 2 --on-threshold shell,command='echo TestOutput'" 2 "^TestOutput$" +check_top_q_hist "multiple actions" \ + "osnoise TOOL -S 2 --on-threshold shell,command='echo -n 1' --on-threshold shell,command='echo 2'" 2 "^12$" +check "hist stop at failed action" \ + "osnoise hist -S 2 --on-threshold shell,command='echo -n 1; false' --on-threshold shell,command='echo -n 2'" 2 "^1# RTLA osnoise histogram$" +check "top stop at failed action" \ + "osnoise top -S 2 --on-threshold shell,command='echo -n abc; false' --on-threshold shell,command='echo -n defgh'" 2 "^abc" "defgh" +check_top_q_hist "with continue" \ + "osnoise TOOL -S 2 -d 5s --on-threshold shell,command='echo TestOutput' --on-threshold continue" 0 "^TestOutput$" +check_top_q_hist "with conditional continue" \ + "osnoise TOOL -S 2 --on-threshold shell,command='if [ -f a ]; then echo 2; exit 1; else echo -n 1; touch a; fi' --on-threshold continue" 2 "^12$" "^2$" +check_top_hist "with trace output at end" \ + "osnoise TOOL -d 1s --on-end trace" 0 "^ Saving trace to osnoise_trace.txt$" + +test_end diff --git a/tools/tracing/rtla/tests/scripts/check-cgroup-match.sh b/tools/tracing/rtla/tests/scripts/check-cgroup-match.sh new file mode 100755 index 000000000..fdc2c68c5 --- /dev/null +++ b/tools/tracing/rtla/tests/scripts/check-cgroup-match.sh @@ -0,0 +1,17 @@ +#!/bin/bash +# SPDX-License-Identifier: GPL-2.0 +. "$(dirname $0)/lib/get_workload_pids.sh" +rtla_pid=$(echo $(ps -o ppid= $$)) +rtla_cgroup=$( [ ...] +# Output: one line per option in the format "OPTION=enabled" or "OPTION=disabled" + +options=$(tr ' ' '\n' < /sys/kernel/tracing/osnoise/options) +for name in "$@"; do + if echo "$options" | grep -q "^NO_${name}$"; then + echo "$name=disabled" + elif echo "$options" | grep -q "^${name}$"; then + echo "$name=enabled" + else + echo "$name=unsupported" + fi +done diff --git a/tools/tracing/rtla/tests/scripts/check-priority.sh b/tools/tracing/rtla/tests/scripts/check-priority.sh new file mode 100755 index 000000000..b51d5232a --- /dev/null +++ b/tools/tracing/rtla/tests/scripts/check-priority.sh @@ -0,0 +1,8 @@ +#!/bin/bash +# SPDX-License-Identifier: GPL-2.0 +. "$(dirname $0)/lib/get_workload_pids.sh" +for pid in $(get_workload_pids) +do + chrt -p $pid | cut -d ':' -f 2 | head -n1 | grep "^ $1\$" >/dev/null + chrt -p $pid | cut -d ':' -f 2 | tail -n1 | grep "^ $2\$" >/dev/null +done && echo "Priorities are set correctly" diff --git a/tools/tracing/rtla/tests/scripts/check-tracefs-value.sh b/tools/tracing/rtla/tests/scripts/check-tracefs-value.sh new file mode 100755 index 000000000..12d0eacd6 --- /dev/null +++ b/tools/tracing/rtla/tests/scripts/check-tracefs-value.sh @@ -0,0 +1,11 @@ +#!/bin/bash +# SPDX-License-Identifier: GPL-2.0 +# Read tracefs values and print them. +# Usage: check-tracefs-value.sh [ ...] +# Each path is relative to /sys/kernel/tracing/ +# Output: one line per file in the format "path=value" + +for file in "$@"; do + read value < "/sys/kernel/tracing/$file" + echo "$file=$value" +done diff --git a/tools/tracing/rtla/tests/scripts/check-user-kernel-threads.sh b/tools/tracing/rtla/tests/scripts/check-user-kernel-threads.sh new file mode 100755 index 000000000..bb7ac510a --- /dev/null +++ b/tools/tracing/rtla/tests/scripts/check-user-kernel-threads.sh @@ -0,0 +1,16 @@ +#!/bin/bash +# SPDX-License-Identifier: GPL-2.0 +. "$(dirname $0)/lib/get_workload_pids.sh" +kthreadd_pid=$(pgrep ^kthreadd$) +cnt_kernel=0 +cnt_user=0 +for pid in $(get_workload_pids) +do + if [ "$(echo $(ps -o ppid= $pid))" = "$kthreadd_pid" ] + then + ((++cnt_kernel)) + else + ((++cnt_user)) + fi +done +echo "$cnt_kernel kernel threads, $cnt_user user threads" diff --git a/tools/tracing/rtla/tests/scripts/lib/get_workload_pids.sh b/tools/tracing/rtla/tests/scripts/lib/get_workload_pids.sh new file mode 100644 index 000000000..d10a4e3b3 --- /dev/null +++ b/tools/tracing/rtla/tests/scripts/lib/get_workload_pids.sh @@ -0,0 +1,11 @@ +#!/bin/bash +# SPDX-License-Identifier: GPL-2.0 +get_workload_pids() { + local shell_pid=$$ + local rtla_pid=$(ps -o ppid= $shell_pid) + + # kernel threads + pgrep -P $(pgrep ^kthreadd$) -f '^\[?(osnoise|timerlat)/[0-9]+\]?$' + # user threads + pgrep -P $rtla_pid | grep -v "^$shell_pid$" +} diff --git a/tools/tracing/rtla/tests/timerlat.t b/tools/tracing/rtla/tests/timerlat.t new file mode 100644 index 000000000..5116857d7 --- /dev/null +++ b/tools/tracing/rtla/tests/timerlat.t @@ -0,0 +1,156 @@ +#!/bin/bash +# SPDX-License-Identifier: GPL-2.0 +source tests/engine.sh +test_begin + +set_timeout 2m +timerlat_sample_event='/sys/kernel/tracing/events/osnoise/timerlat_sample' + +if ldd $RTLA | grep libbpf >/dev/null && [ -d "$timerlat_sample_event" ] +then + # rtla build with BPF and system supports BPF mode + no_bpf_options='0 1' +else + no_bpf_options='1' +fi + +# Do every test with and without BPF +for option in $no_bpf_options +do +export RTLA_NO_BPF=$option + +# Basic tests +check "verify help page" \ + "timerlat --help" 129 "timerlat version" +check_top_hist "verify help page" \ + "timerlat TOOL --help" 129 "rtla timerlat" +check_top_hist "verify -s/--stack" \ + "timerlat TOOL -s 3 -T 10 -t" 2 "Blocking thread stack trace" +check_top_hist "test in nanoseconds" \ + "timerlat TOOL -i 2 -c 0 -n -d 10s" 2 "ns" +check_top_hist "set the automatic trace mode" \ + "timerlat TOOL -a 5" 2 "analyzing it" +check_top_hist "dump tasks" \ + "timerlat TOOL -a 5 --dump-tasks" 2 "Printing CPU tasks" +check "verify --aa-only stop on threshold" \ + "timerlat top --aa-only 5" 2 "analyzing it" "Timer Latency" +check "verify --aa-only max latency" \ + "timerlat top --aa-only 2000000 -d 1s" 0 "^ Max latency was" "Timer Latency" +check_top_hist "disable auto-analysis" \ + "timerlat TOOL -s 3 -T 10 -t --no-aa" 2 "" "analyzing it" + +# Thread tests +check_top_hist "verify -P/--priority" \ + "timerlat TOOL -P F:1 -c 0 -d 10s -T 1 --on-threshold shell,command=\"$testdir/scripts/check-priority.sh SCHED_FIFO 1\"" \ + 2 "Priorities are set correctly" +check_top_hist "verify -C/--cgroup" \ + "timerlat TOOL -k -C -c 0 -d 10s -T 1 --on-threshold shell,command=\"$testdir/scripts/check-cgroup-match.sh\"" \ + 2 "cgroup matches for all workload PIDs" +check_top_q_hist "verify -c/--cpus" \ + "timerlat TOOL -c 0 -d 10s -T 1 --on-threshold shell,command=$testdir/scripts/check-cpus.sh" 2 "^Affinity of threads: 0$" +check_top_q_hist "verify -H/--house-keeping" \ + "timerlat TOOL -H 0 -d 10s -T 1 --on-threshold shell,command=$testdir/scripts/check-housekeeping-cpus.sh" 2 "^Affinity of threads: 0$" +check_top_q_hist "verify -k/--kernel-threads" \ + "timerlat TOOL -k -c 0 -d 10s -T 1 --on-threshold shell,command=$testdir/scripts/check-user-kernel-threads.sh" 2 "1 kernel threads, 0 user threads" +check_top_q_hist "verify -u/--user-threads" \ + "timerlat TOOL -u -c 0 -d 10s -T 1 --on-threshold shell,command=$testdir/scripts/check-user-kernel-threads.sh" 2 "0 kernel threads, 1 user threads" + +# Tracer option tests - verify that rtla correctly sets tracefs options +# Default tests: poison tracefs with wrong values, verify rtla resets to defaults +check_with_osnoise_options "apply default timerlat_period_us" \ + "timerlat top -q -T 1 --on-threshold shell,command=\"$testdir/scripts/check-tracefs-value.sh osnoise/timerlat_period_us\"" \ + 2 "^osnoise/timerlat_period_us=1000$" osnoise/timerlat_period_us=999999 +check_with_osnoise_options "apply default print_stack" \ + "timerlat top -q -T 1 --on-threshold shell,command=\"$testdir/scripts/check-tracefs-value.sh osnoise/print_stack\"" \ + 2 "^osnoise/print_stack=0$" osnoise/print_stack=999999 +check_with_osnoise_options "apply default stop_tracing_us" \ + "timerlat top -q -T 1 --on-threshold shell,command=\"$testdir/scripts/check-tracefs-value.sh osnoise/stop_tracing_us\"" \ + 2 "^osnoise/stop_tracing_us=0$" osnoise/stop_tracing_us=999999 +check_with_osnoise_options "apply default stop_tracing_total_us" \ + "timerlat top -q -i 1 --on-threshold shell,command=\"$testdir/scripts/check-tracefs-value.sh osnoise/stop_tracing_total_us\"" \ + 2 "^osnoise/stop_tracing_total_us=0$" osnoise/stop_tracing_total_us=999999 + +# Non-default tracer option tests: verify CLI options correctly set tracefs values +check_top_q_hist "verify -p sets timerlat_period_us" \ + "timerlat TOOL -p 2000 -T 1 --on-threshold shell,command=\"$testdir/scripts/check-tracefs-value.sh osnoise/timerlat_period_us\"" \ + 2 "^osnoise/timerlat_period_us=2000$" +check_top_q_hist "verify -s sets print_stack" \ + "timerlat TOOL -s 5 -T 1 --on-threshold shell,command=\"$testdir/scripts/check-tracefs-value.sh osnoise/print_stack\"" \ + 2 "^osnoise/print_stack=5$" +check_top_q_hist "verify -i sets stop_tracing_us" \ + "timerlat TOOL -i 2 --on-threshold shell,command=\"$testdir/scripts/check-tracefs-value.sh osnoise/stop_tracing_us\"" \ + 2 "^osnoise/stop_tracing_us=2$" +check_top_q_hist "verify -T sets stop_tracing_total_us" \ + "timerlat TOOL -T 2 --on-threshold shell,command=\"$testdir/scripts/check-tracefs-value.sh osnoise/stop_tracing_total_us\"" \ + 2 "^osnoise/stop_tracing_total_us=2$" +check_with_osnoise_options "apply default TIMERLAT_ALIGN" \ + "timerlat top -q -T 1 --on-threshold shell,command=\"$testdir/scripts/check-osnoise-option.sh TIMERLAT_ALIGN\"" \ + 2 "^TIMERLAT_ALIGN=disabled$" osnoise/options=TIMERLAT_ALIGN +check_top_q_hist "verify -A sets TIMERLAT_ALIGN" \ + "timerlat TOOL -A 100 -T 1 --on-threshold shell,command=\"$testdir/scripts/check-osnoise-option.sh TIMERLAT_ALIGN\"" \ + 2 "^TIMERLAT_ALIGN=enabled$" +check_top_q_hist "verify -A sets timerlat_align_us" \ + "timerlat TOOL -A 100 -T 1 --on-threshold shell,command=\"$testdir/scripts/check-tracefs-value.sh osnoise/timerlat_align_us\"" \ + 2 "^osnoise/timerlat_align_us=100$" + +# Histogram tests +check "hist with -b/--bucket-size" \ + "timerlat hist -b 1 -d 1s" +check "hist with -E/--entries" \ + "timerlat hist -E 10 -d 1s" +check "hist with -E/--entries out of range" \ + "timerlat hist -E 1 -d 1s" 129 "out of range \[10, 9999999\]" +check "hist with --no-header" \ + "timerlat hist --no-header -d 1s" 0 "" "RTLA timerlat histogram" +check "hist with --with-zeros" \ + "timerlat hist --with-zeros -b 100000 -E 21 -d 1s" 0 '^2000000\s+0\s+' +check "hist with --no-index" \ + "timerlat hist --no-index --with-zeros -d 1s" 0 "" "^count:" +check "hist with --no-summary" \ + "timerlat hist --no-summary -d 1s" 0 "" "^ALL:" +check "hist with --no-irq" \ + "timerlat hist --no-irq -d 1s" 0 "" "IRQ-" +check "hist with --no-thread" \ + "timerlat hist --no-thread -d 1s" 0 "" "Thr-" + +# Actions tests +check_top_q_hist "trace output through -t" \ + "timerlat TOOL -T 2 -t" 2 "^ Saving trace to timerlat_trace.txt$" +check_top_q_hist "trace output through -t with custom filename" \ + "timerlat TOOL -T 2 -t custom_filename.txt" 2 "^ Saving trace to custom_filename.txt$" +check_top_q_hist "trace output through --on-threshold trace" \ + "timerlat TOOL -T 2 --on-threshold trace" 2 "^ Saving trace to timerlat_trace.txt$" +check_top_q_hist "trace output through --on-threshold trace with custom filename" \ + "timerlat TOOL -T 2 --on-threshold trace,file=custom_filename.txt" 2 "^ Saving trace to custom_filename.txt$" +check_top_q_hist "exec command" \ + "timerlat TOOL -T 2 --on-threshold shell,command='echo TestOutput'" 2 "^TestOutput$" +check_top_q_hist "multiple actions" \ + "timerlat TOOL -T 2 --on-threshold shell,command='echo -n 1' --on-threshold shell,command='echo 2'" 2 "^12$" +check "hist stop at failed action" \ + "timerlat hist -T 2 --on-threshold shell,command='echo -n 1; false' --on-threshold shell,command='echo -n 2'" 2 "^1# RTLA timerlat histogram$" +check "top stop at failed action" \ + "timerlat top -T 2 --on-threshold shell,command='echo -n abc; false' --on-threshold shell,command='echo -n defgh'" 2 "^abc" "defgh" +check_top_q_hist "with continue" \ + "timerlat TOOL -T 2 -d 5s --on-threshold shell,command='echo TestOutput' --on-threshold continue" 0 "^TestOutput$" +check_top_q_hist "with conditional continue" \ + "timerlat TOOL -T 2 --on-threshold shell,command='if [ -f a ]; then echo 2; exit 1; else echo -n 1; touch a; fi' --on-threshold continue" 2 "^12$" "^2$" +check_top_hist "with trace output at end" \ + "timerlat TOOL -d 1s --on-end trace" 0 "^ Saving trace to timerlat_trace.txt$" + +# BPF action program tests +if [ "$option" -eq 0 ] +then + # Test BPF action program properly in BPF mode + [ -z "$BPFTOOL" ] && BPFTOOL=bpftool + check_top_q_hist "with BPF action program (BPF mode)" \ + "timerlat TOOL -T 2 --bpf-action $testdir/bpf/bpf_action_map.o --on-threshold shell,command='$BPFTOOL map dump name rtla_test_map'" \ + 2 '"value": 42' +else + # Test BPF action program failure in non-BPF mode + check_top_q_hist "with BPF action program (non-BPF mode)" \ + "timerlat TOOL -T 2 --bpf-action $testdir/bpf/bpf_action_map.o" \ + 1 "BPF actions are not supported in tracefs-only mode" +fi +done + +test_end diff --git a/tools/tracing/rtla/tests/unit/Build b/tools/tracing/rtla/tests/unit/Build new file mode 100644 index 000000000..d5a0f1392 --- /dev/null +++ b/tools/tracing/rtla/tests/unit/Build @@ -0,0 +1,8 @@ +unit_tests-y += utils.o +unit_tests-y += actions.o +unit_tests-y += unit_tests.o +unit_tests-y += osnoise_top_cli.o +unit_tests-y += osnoise_hist_cli.o +unit_tests-y += timerlat_top_cli.o +unit_tests-y += timerlat_hist_cli.o +unit_tests-y += cli_opt_callback.o diff --git a/tools/tracing/rtla/tests/unit/Makefile.unit b/tools/tracing/rtla/tests/unit/Makefile.unit new file mode 100644 index 000000000..839abda64 --- /dev/null +++ b/tools/tracing/rtla/tests/unit/Makefile.unit @@ -0,0 +1,17 @@ +# SPDX-License-Identifier: GPL-2.0-only + +UNIT_TESTS := $(OUTPUT)unit_tests +UNIT_TESTS_IN := $(UNIT_TESTS)-in.o + +$(UNIT_TESTS): $(UNIT_TESTS_IN) $(RTLA_IN) $(LIBSUBCMD) $(LIB_STRING) $(LIB_STR_ERROR_R) + $(QUIET_LINK)$(CC) $(LDFLAGS) -o $@ $^ $(EXTLIBS) -lcheck + +$(UNIT_TESTS_IN): fixdep $(LIBSUBCMD_INCLUDES) + make $(build)=unit_tests + +unit-tests: FORCE + $(Q)if [ "$(feature-libcheck)" = "1" ]; then \ + $(MAKE) $(UNIT_TESTS) && $(UNIT_TESTS); \ + else \ + echo "libcheck is missing, skipping unit tests. Please install check-devel/check"; \ + fi diff --git a/tools/tracing/rtla/tests/unit/actions.c b/tools/tracing/rtla/tests/unit/actions.c new file mode 100644 index 000000000..94ad5ad42 --- /dev/null +++ b/tools/tracing/rtla/tests/unit/actions.c @@ -0,0 +1,393 @@ +// SPDX-License-Identifier: GPL-2.0 + +#define _GNU_SOURCE +#include +#include + +#include "../../src/actions.h" + +static struct actions actions_fixture; + +static void actions_fixture_setup(void) +{ + actions_init(&actions_fixture); +} + +static void actions_fixture_teardown(void) +{ + actions_destroy(&actions_fixture); +} + +START_TEST(test_actions_init) +{ + struct actions actions; + + actions_init(&actions); + + ck_assert_int_eq(actions.len, 0); + ck_assert_int_eq(actions.size, action_default_size); + ck_assert(!actions.continue_flag); + ck_assert_ptr_eq(actions.trace_output_inst, NULL); +} +END_TEST + +START_TEST(test_actions_destroy) +{ + struct actions actions; + + actions_init(&actions); + actions_destroy(&actions); +} +END_TEST + +START_TEST(test_actions_reallocate) +{ + struct actions actions; + int i; + + actions_init(&actions); + + ck_assert_int_eq(actions.len, 0); + ck_assert_int_eq(actions.size, action_default_size); + + /* Fill size of actions array */ + for (i = 0; i < action_default_size; i++) + actions_add_continue(&actions); + + ck_assert_int_eq(actions.len, action_default_size); + ck_assert_int_eq(actions.size, action_default_size); + + /* Add one more action to trigger reallocation */ + actions_add_continue(&actions); + + ck_assert_int_eq(actions.len, action_default_size + 1); + ck_assert_int_eq(actions.size, action_default_size * 2); + + actions_destroy(&actions); +} +END_TEST + +START_TEST(test_actions_add_trace_output) +{ + actions_add_trace_output(&actions_fixture, "trace_output.txt"); + + ck_assert_int_eq(actions_fixture.len, 1); + ck_assert_int_eq(actions_fixture.list[0].type, ACTION_TRACE_OUTPUT); + ck_assert_str_eq(actions_fixture.list[0].trace_output, "trace_output.txt"); + ck_assert(actions_fixture.present[ACTION_TRACE_OUTPUT]); +} +END_TEST + +START_TEST(test_actions_add_signal) +{ + actions_add_signal(&actions_fixture, SIGINT, 1234); + + ck_assert_int_eq(actions_fixture.len, 1); + ck_assert_int_eq(actions_fixture.list[0].type, ACTION_SIGNAL); + ck_assert_int_eq(actions_fixture.list[0].signal, SIGINT); + ck_assert_int_eq(actions_fixture.list[0].pid, 1234); + ck_assert(actions_fixture.present[ACTION_SIGNAL]); +} +END_TEST + +START_TEST(test_actions_add_shell) +{ + actions_add_shell(&actions_fixture, "echo Hello"); + + ck_assert_int_eq(actions_fixture.len, 1); + ck_assert_int_eq(actions_fixture.list[0].type, ACTION_SHELL); + ck_assert_str_eq(actions_fixture.list[0].command, "echo Hello"); + ck_assert(actions_fixture.present[ACTION_SHELL]); +} +END_TEST + +START_TEST(test_actions_add_continue) +{ + actions_add_continue(&actions_fixture); + + ck_assert_int_eq(actions_fixture.len, 1); + ck_assert_int_eq(actions_fixture.list[0].type, ACTION_CONTINUE); + ck_assert(actions_fixture.present[ACTION_CONTINUE]); +} +END_TEST + +START_TEST(test_actions_add_multiple_same_action) +{ + actions_add_trace_output(&actions_fixture, "trace1.txt"); + actions_add_trace_output(&actions_fixture, "trace2.txt"); + + ck_assert_int_eq(actions_fixture.len, 2); + ck_assert_int_eq(actions_fixture.list[0].type, ACTION_TRACE_OUTPUT); + ck_assert_str_eq(actions_fixture.list[0].trace_output, "trace1.txt"); + ck_assert_int_eq(actions_fixture.list[1].type, ACTION_TRACE_OUTPUT); + ck_assert_str_eq(actions_fixture.list[1].trace_output, "trace2.txt"); + ck_assert(actions_fixture.present[ACTION_TRACE_OUTPUT]); +} +END_TEST + +START_TEST(test_actions_add_multiple_different_action) +{ + actions_add_trace_output(&actions_fixture, "trace_output.txt"); + actions_add_signal(&actions_fixture, SIGINT, 1234); + + ck_assert_int_eq(actions_fixture.len, 2); + ck_assert_int_eq(actions_fixture.list[0].type, ACTION_TRACE_OUTPUT); + ck_assert_str_eq(actions_fixture.list[0].trace_output, "trace_output.txt"); + ck_assert(actions_fixture.present[ACTION_TRACE_OUTPUT]); + ck_assert_int_eq(actions_fixture.list[1].type, ACTION_SIGNAL); + ck_assert_int_eq(actions_fixture.list[1].signal, SIGINT); + ck_assert_int_eq(actions_fixture.list[1].pid, 1234); + ck_assert(actions_fixture.present[ACTION_SIGNAL]); +} +END_TEST + +START_TEST(test_actions_parse_trace_output) +{ + ck_assert_int_eq(actions_parse(&actions_fixture, "trace", "trace.txt"), 0); + + ck_assert_int_eq(actions_fixture.len, 1); + ck_assert_int_eq(actions_fixture.list[0].type, ACTION_TRACE_OUTPUT); + ck_assert_str_eq(actions_fixture.list[0].trace_output, "trace.txt"); + ck_assert(actions_fixture.present[ACTION_TRACE_OUTPUT]); +} +END_TEST + +START_TEST(test_actions_parse_trace_output_arg) +{ + ck_assert_int_eq(actions_parse(&actions_fixture, "trace,file=trace2.txt", "trace1.txt"), 0); + + ck_assert_int_eq(actions_fixture.len, 1); + ck_assert_int_eq(actions_fixture.list[0].type, ACTION_TRACE_OUTPUT); + ck_assert_str_eq(actions_fixture.list[0].trace_output, "trace2.txt"); + ck_assert(actions_fixture.present[ACTION_TRACE_OUTPUT]); +} +END_TEST + +START_TEST(test_actions_parse_trace_output_arg_bad) +{ + ck_assert_int_eq(actions_parse(&actions_fixture, "trace,foo=bar", "trace_output.txt"), -1); + + ck_assert_int_eq(actions_fixture.len, 0); + ck_assert(!actions_fixture.present[ACTION_TRACE_OUTPUT]); +} +END_TEST + +START_TEST(test_actions_parse_signal) +{ + ck_assert_int_eq(actions_parse(&actions_fixture, "signal,num=1,pid=1234", NULL), 0); + + ck_assert_int_eq(actions_fixture.len, 1); + ck_assert_int_eq(actions_fixture.list[0].type, ACTION_SIGNAL); + ck_assert_int_eq(actions_fixture.list[0].signal, 1); + ck_assert_int_eq(actions_fixture.list[0].pid, 1234); + ck_assert(actions_fixture.present[ACTION_SIGNAL]); +} +END_TEST + +START_TEST(test_actions_parse_signal_swapped) +{ + ck_assert_int_eq(actions_parse(&actions_fixture, "signal,pid=1234,num=1", NULL), 0); + + ck_assert_int_eq(actions_fixture.len, 1); + ck_assert_int_eq(actions_fixture.list[0].type, ACTION_SIGNAL); + ck_assert_int_eq(actions_fixture.list[0].signal, 1); + ck_assert_int_eq(actions_fixture.list[0].pid, 1234); + ck_assert(actions_fixture.present[ACTION_SIGNAL]); +} +END_TEST + +START_TEST(test_actions_parse_signal_parent) +{ + ck_assert_int_eq(actions_parse(&actions_fixture, "signal,pid=parent,num=1", NULL), 0); + + ck_assert_int_eq(actions_fixture.len, 1); + ck_assert_int_eq(actions_fixture.list[0].type, ACTION_SIGNAL); + ck_assert_int_eq(actions_fixture.list[0].signal, 1); + ck_assert_int_eq(actions_fixture.list[0].pid, -1); + ck_assert(actions_fixture.present[ACTION_SIGNAL]); +} +END_TEST + +START_TEST(test_actions_parse_signal_no_arg) +{ + ck_assert_int_eq(actions_parse(&actions_fixture, "signal", NULL), -1); + + ck_assert_int_eq(actions_fixture.len, 0); + ck_assert(!actions_fixture.present[ACTION_SIGNAL]); +} +END_TEST + +START_TEST(test_actions_parse_signal_no_pid) +{ + ck_assert_int_eq(actions_parse(&actions_fixture, "signal,num=1", NULL), -1); + + ck_assert_int_eq(actions_fixture.len, 0); + ck_assert(!actions_fixture.present[ACTION_SIGNAL]); +} +END_TEST + +START_TEST(test_actions_parse_signal_no_num) +{ + ck_assert_int_eq(actions_parse(&actions_fixture, "signal,pid=1234", NULL), -1); + + ck_assert_int_eq(actions_fixture.len, 0); + ck_assert(!actions_fixture.present[ACTION_SIGNAL]); +} +END_TEST + +START_TEST(test_actions_parse_signal_arg_bad) +{ + ck_assert_int_eq(actions_parse(&actions_fixture, "signal,foo=bar", NULL), -1); + + ck_assert_int_eq(actions_fixture.len, 0); + ck_assert(!actions_fixture.present[ACTION_SIGNAL]); +} +END_TEST + +START_TEST(test_actions_parse_shell) +{ + ck_assert_int_eq(actions_parse(&actions_fixture, "shell,command=echo Hello", NULL), 0); + + ck_assert_int_eq(actions_fixture.len, 1); + ck_assert_int_eq(actions_fixture.list[0].type, ACTION_SHELL); + ck_assert_str_eq(actions_fixture.list[0].command, "echo Hello"); + ck_assert(actions_fixture.present[ACTION_SHELL]); +} +END_TEST + +START_TEST(test_actions_parse_shell_no_arg) +{ + ck_assert_int_eq(actions_parse(&actions_fixture, "shell", NULL), -1); + + ck_assert_int_eq(actions_fixture.len, 0); + ck_assert(!actions_fixture.present[ACTION_SHELL]); +} +END_TEST + +START_TEST(test_actions_parse_shell_arg_bad) +{ + ck_assert_int_eq(actions_parse(&actions_fixture, "shell,foo=bar", NULL), -1); + ck_assert_int_eq(actions_fixture.len, 0); + ck_assert(!actions_fixture.present[ACTION_SHELL]); +} +END_TEST + +START_TEST(test_actions_parse_continue) +{ + ck_assert_int_eq(actions_parse(&actions_fixture, "continue", NULL), 0); + + ck_assert_int_eq(actions_fixture.len, 1); + ck_assert_int_eq(actions_fixture.list[0].type, ACTION_CONTINUE); + ck_assert(actions_fixture.present[ACTION_CONTINUE]); +} +END_TEST + +START_TEST(test_actions_parse_continue_arg_bad) +{ + ck_assert_int_eq(actions_parse(&actions_fixture, "continue,foo=bar", NULL), -1); + + ck_assert_int_eq(actions_fixture.len, 0); + ck_assert(!actions_fixture.present[ACTION_CONTINUE]); +} +END_TEST + +START_TEST(test_actions_parse_invalid) +{ + ck_assert_int_eq(actions_parse(&actions_fixture, "foobar", NULL), -1); + + ck_assert_int_eq(actions_fixture.len, 0); +} +END_TEST + +START_TEST(test_actions_perform_continue) +{ + actions_add_continue(&actions_fixture); + ck_assert_int_eq(actions_perform(&actions_fixture), 0); + + ck_assert(actions_fixture.continue_flag); +} +END_TEST + +START_TEST(test_actions_perform_continue_after_successful_shell_command) +{ + actions_add_shell(&actions_fixture, "exit 0"); + actions_add_continue(&actions_fixture); + ck_assert_int_eq(actions_perform(&actions_fixture), 0 << 8); + + ck_assert(actions_fixture.continue_flag); +} +END_TEST + +START_TEST(test_actions_perform_continue_after_failed_shell_command) +{ + actions_add_shell(&actions_fixture, "exit 1"); + actions_add_continue(&actions_fixture); + ck_assert_int_eq(actions_perform(&actions_fixture), 1 << 8); + + ck_assert(!actions_fixture.continue_flag); +} +END_TEST + +START_TEST(test_actions_perform_continue_unset_flag) +{ + actions_fixture.continue_flag = true; + + actions_add_shell(&actions_fixture, "exit 1"); + actions_add_continue(&actions_fixture); + ck_assert_int_eq(actions_perform(&actions_fixture), 1 << 8); + + ck_assert(!actions_fixture.continue_flag); +} +END_TEST + +Suite *actions_suite(void) +{ + Suite *s = suite_create("actions"); + TCase *tc; + + tc = tcase_create("alloc"); + tcase_add_test(tc, test_actions_init); + tcase_add_test(tc, test_actions_destroy); + tcase_add_test(tc, test_actions_reallocate); + suite_add_tcase(s, tc); + + tc = tcase_create("add"); + tcase_add_checked_fixture(tc, actions_fixture_setup, actions_fixture_teardown); + tcase_add_test(tc, test_actions_add_trace_output); + tcase_add_test(tc, test_actions_add_signal); + tcase_add_test(tc, test_actions_add_shell); + tcase_add_test(tc, test_actions_add_continue); + tcase_add_test(tc, test_actions_add_multiple_same_action); + tcase_add_test(tc, test_actions_add_multiple_different_action); + suite_add_tcase(s, tc); + + tc = tcase_create("parse"); + tcase_add_checked_fixture(tc, actions_fixture_setup, actions_fixture_teardown); + tcase_add_test(tc, test_actions_parse_trace_output); + tcase_add_test(tc, test_actions_parse_trace_output_arg); + tcase_add_test(tc, test_actions_parse_trace_output_arg_bad); + tcase_add_test(tc, test_actions_parse_signal); + tcase_add_test(tc, test_actions_parse_signal_swapped); + tcase_add_test(tc, test_actions_parse_signal_parent); + tcase_add_test(tc, test_actions_parse_signal_no_arg); + tcase_add_test(tc, test_actions_parse_signal_no_pid); + tcase_add_test(tc, test_actions_parse_signal_no_num); + tcase_add_test(tc, test_actions_parse_signal_arg_bad); + tcase_add_test(tc, test_actions_parse_shell); + tcase_add_test(tc, test_actions_parse_shell_no_arg); + tcase_add_test(tc, test_actions_parse_shell_arg_bad); + tcase_add_test(tc, test_actions_parse_continue); + tcase_add_test(tc, test_actions_parse_continue_arg_bad); + tcase_add_test(tc, test_actions_parse_invalid); + suite_add_tcase(s, tc); + + tc = tcase_create("perform"); + tcase_add_checked_fixture(tc, actions_fixture_setup, actions_fixture_teardown); + tcase_add_test(tc, test_actions_perform_continue); + tcase_add_test(tc, test_actions_perform_continue_after_successful_shell_command); + tcase_add_test(tc, test_actions_perform_continue_after_failed_shell_command); + tcase_add_test(tc, test_actions_perform_continue_unset_flag); + suite_add_tcase(s, tc); + + return s; +} diff --git a/tools/tracing/rtla/tests/unit/cli_opt_callback.c b/tools/tracing/rtla/tests/unit/cli_opt_callback.c new file mode 100644 index 000000000..70e2576b1 --- /dev/null +++ b/tools/tracing/rtla/tests/unit/cli_opt_callback.c @@ -0,0 +1,912 @@ +// SPDX-License-Identifier: GPL-2.0 + +#define _GNU_SOURCE +#include +#include + +#define RTLA_ALLOW_CLI_P_H +#include "../../src/cli_p.h" +#include "cli_params_assert.h" + +#define TEST_CALLBACK(value, cb) OPT_CALLBACK('t', "test", value, "test value", "test help", cb) +#define TEST_LLONG_RANGE(value, lo, hi) \ + RTLA_OPT_CALLBACK_DATA('t', "test", value, "test value", "test help", \ + opt_llong_callback, LLONG_RANGE(lo, hi)) +#define TEST_INT_RANGE(value, lo, hi) \ + RTLA_OPT_CALLBACK_DATA('t', "test", value, "test value", "test help", \ + opt_int_callback, INT_RANGE(lo, hi)) + +START_TEST(test_opt_llong_callback_simple) +{ + long long test_value = 0; + const struct option opt = TEST_CALLBACK(&test_value, opt_llong_callback); + + ck_assert_int_eq(opt_llong_callback(&opt, "1234567890", 0), 0); + ck_assert_int_eq(test_value, 1234567890); +} +END_TEST + +START_TEST(test_opt_llong_callback_max) +{ + long long test_value = 0; + const struct option opt = TEST_CALLBACK(&test_value, opt_llong_callback); + + ck_assert_int_eq(opt_llong_callback(&opt, "9223372036854775807", 0), 0); + ck_assert_int_eq(test_value, 9223372036854775807LL); +} +END_TEST + +START_TEST(test_opt_llong_callback_min) +{ + long long test_value = 0; + const struct option opt = TEST_CALLBACK(&test_value, opt_llong_callback); + + ck_assert_int_eq(opt_llong_callback(&opt, "-9223372036854775808", 0), 0); + ck_assert_int_eq(test_value, ~9223372036854775807LL); +} +END_TEST + +START_TEST(test_opt_llong_callback_non_numeric) +{ + long long test_value = 0; + const struct option opt = TEST_CALLBACK(&test_value, opt_llong_callback); + + assert(freopen("/dev/null", "w", stderr)); + ck_assert_int_eq(opt_llong_callback(&opt, "abc", 0), -1); + ck_assert_int_eq(test_value, 0); +} +END_TEST + +START_TEST(test_opt_llong_callback_non_numeric_suffix) +{ + long long test_value = 0; + const struct option opt = TEST_CALLBACK(&test_value, opt_llong_callback); + + assert(freopen("/dev/null", "w", stderr)); + ck_assert_int_eq(opt_llong_callback(&opt, "1234567890abc", 0), -1); + ck_assert_int_eq(test_value, 0); +} +END_TEST + +START_TEST(test_opt_llong_callback_unset) +{ + long long test_value = 0; + const struct option opt = TEST_CALLBACK(&test_value, opt_llong_callback); + + ck_assert_int_eq(opt_llong_callback(&opt, "1234567890", 0), 0); + ck_assert_int_eq(opt_llong_callback(&opt, NULL, 1), 0); + ck_assert_int_eq(test_value, 0); +} +END_TEST + +START_TEST(test_opt_llong_callback_unset_defval) +{ + long long test_value = 0; + const long long default_value = 42; + const struct option opt = RTLA_OPT_LLONG_DEFVAL('t', "test", &test_value, "test value", + "test help", &default_value); + + ck_assert_int_eq(opt_llong_callback(&opt, "1234567890", 0), 0); + ck_assert_int_eq(opt_llong_callback(&opt, NULL, 1), 0); + ck_assert_int_eq(test_value, default_value); +} +END_TEST + +START_TEST(test_opt_int_callback_simple) +{ + int test_value = 0; + const struct option opt = TEST_CALLBACK(&test_value, opt_int_callback); + + ck_assert_int_eq(opt_int_callback(&opt, "1234567890", 0), 0); + ck_assert_int_eq(test_value, 1234567890); +} +END_TEST + +START_TEST(test_opt_int_callback_max) +{ + int test_value = 0; + const struct option opt = TEST_CALLBACK(&test_value, opt_int_callback); + + ck_assert_int_eq(opt_int_callback(&opt, "2147483647", 0), 0); + ck_assert_int_eq(test_value, 2147483647); +} +END_TEST + +START_TEST(test_opt_int_callback_min) +{ + int test_value = 0; + const struct option opt = TEST_CALLBACK(&test_value, opt_int_callback); + + ck_assert_int_eq(opt_int_callback(&opt, "-2147483648", 0), 0); + ck_assert_int_eq(test_value, -2147483648); +} +END_TEST + +START_TEST(test_opt_int_callback_non_numeric) +{ + int test_value = 0; + const struct option opt = TEST_CALLBACK(&test_value, opt_int_callback); + + assert(freopen("/dev/null", "w", stderr)); + ck_assert_int_eq(opt_int_callback(&opt, "abc", 0), -1); + ck_assert_int_eq(test_value, 0); +} +END_TEST + +START_TEST(test_opt_int_callback_non_numeric_suffix) +{ + int test_value = 0; + const struct option opt = TEST_CALLBACK(&test_value, opt_int_callback); + + assert(freopen("/dev/null", "w", stderr)); + ck_assert_int_eq(opt_int_callback(&opt, "1234567890abc", 0), -1); + ck_assert_int_eq(test_value, 0); +} +END_TEST + +START_TEST(test_opt_int_callback_unset) +{ + int test_value = 0; + const struct option opt = TEST_CALLBACK(&test_value, opt_int_callback); + + ck_assert_int_eq(opt_int_callback(&opt, "1234567890", 0), 0); + ck_assert_int_eq(opt_int_callback(&opt, NULL, 1), 0); + ck_assert_int_eq(test_value, 0); +} +END_TEST + +START_TEST(test_opt_int_callback_unset_defval) +{ + int test_value = 0; + const struct option opt = RTLA_OPT_INT_DEFVAL('t', "test", &test_value, "test value", + "test help", 42); + + ck_assert_int_eq(opt_int_callback(&opt, "1234567890", 0), 0); + ck_assert_int_eq(opt_int_callback(&opt, NULL, 1), 0); + ck_assert_int_eq(test_value, 42); +} +END_TEST + +START_TEST(test_opt_llong_callback_range_in) +{ + long long test_value = 0; + const struct option opt = TEST_LLONG_RANGE(&test_value, 10, 100); + + ck_assert_int_eq(opt_llong_callback(&opt, "50", 0), 0); + ck_assert_int_eq(test_value, 50); +} +END_TEST + +START_TEST(test_opt_llong_callback_range_below) +{ + long long test_value = 0; + const struct option opt = TEST_LLONG_RANGE(&test_value, 10, 100); + + assert(freopen("/dev/null", "w", stderr)); + ck_assert_int_eq(opt_llong_callback(&opt, "9", 0), -1); +} +END_TEST + +START_TEST(test_opt_llong_callback_range_above) +{ + long long test_value = 0; + const struct option opt = TEST_LLONG_RANGE(&test_value, 10, 100); + + assert(freopen("/dev/null", "w", stderr)); + ck_assert_int_eq(opt_llong_callback(&opt, "101", 0), -1); +} +END_TEST + +START_TEST(test_opt_llong_callback_range_boundary) +{ + long long test_value = 0; + const struct option opt = TEST_LLONG_RANGE(&test_value, 10, 100); + + ck_assert_int_eq(opt_llong_callback(&opt, "10", 0), 0); + ck_assert_int_eq(test_value, 10); + ck_assert_int_eq(opt_llong_callback(&opt, "100", 0), 0); + ck_assert_int_eq(test_value, 100); +} +END_TEST + +START_TEST(test_opt_int_callback_range_in) +{ + int test_value = 0; + const struct option opt = TEST_INT_RANGE(&test_value, 0, 10000); + + ck_assert_int_eq(opt_int_callback(&opt, "5000", 0), 0); + ck_assert_int_eq(test_value, 5000); +} +END_TEST + +START_TEST(test_opt_int_callback_range_below) +{ + int test_value = 0; + const struct option opt = TEST_INT_RANGE(&test_value, 0, 10000); + + assert(freopen("/dev/null", "w", stderr)); + ck_assert_int_eq(opt_int_callback(&opt, "-1", 0), -1); +} +END_TEST + +START_TEST(test_opt_int_callback_range_above) +{ + int test_value = 0; + const struct option opt = TEST_INT_RANGE(&test_value, 0, 10000); + + assert(freopen("/dev/null", "w", stderr)); + ck_assert_int_eq(opt_int_callback(&opt, "10001", 0), -1); +} +END_TEST + +START_TEST(test_opt_int_callback_range_boundary) +{ + int test_value = 0; + const struct option opt = TEST_INT_RANGE(&test_value, 0, 10000); + + ck_assert_int_eq(opt_int_callback(&opt, "0", 0), 0); + ck_assert_int_eq(test_value, 0); + ck_assert_int_eq(opt_int_callback(&opt, "10000", 0), 0); + ck_assert_int_eq(test_value, 10000); +} +END_TEST + +START_TEST(test_opt_cpus_cb) +{ + struct common_params params = {0}; + const struct option opt = TEST_CALLBACK(¶ms, opt_cpus_cb); + + nr_cpus = 4; + ck_assert_int_eq(opt_cpus_cb(&opt, "0-3", 0), 0); + ck_assert_str_eq(params.cpus, "0-3"); +} +END_TEST + +START_TEST(test_opt_cpus_cb_invalid) +{ + struct common_params params = {0}; + const struct option opt = TEST_CALLBACK(¶ms, opt_cpus_cb); + + nr_cpus = 4; + assert(freopen("/dev/null", "w", stderr)); + ck_assert_int_eq(opt_cpus_cb(&opt, "0-3,5", 0), -1); +} +END_TEST + +START_TEST(test_opt_cgroup_cb) +{ + struct common_params params = {0}; + const struct option opt = TEST_CALLBACK(¶ms, opt_cgroup_cb); + + ck_assert_int_eq(opt_cgroup_cb(&opt, "cgroup", 0), 0); + ck_assert_int_eq(params.cgroup, 1); + ck_assert_str_eq(params.cgroup_name, "cgroup"); +} +END_TEST + +START_TEST(test_opt_cgroup_cb_equals) +{ + struct common_params params = {0}; + const struct option opt = TEST_CALLBACK(¶ms, opt_cgroup_cb); + + ck_assert_int_eq(opt_cgroup_cb(&opt, "=cgroup", 0), 0); + ck_assert_int_eq(params.cgroup, 1); + ck_assert_str_eq(params.cgroup_name, "cgroup"); +} +END_TEST + +START_TEST(test_opt_cgroup_cb_unset) +{ + struct common_params params = {0}; + const struct option opt = TEST_CALLBACK(¶ms, opt_cgroup_cb); + + ck_assert_int_eq(opt_cgroup_cb(&opt, "cgroup", 0), 0); + ck_assert_int_eq(opt_cgroup_cb(&opt, NULL, 1), 0); + ck_assert_int_eq(params.cgroup, 0); + ck_assert_ptr_null(params.cgroup_name); +} +END_TEST + +START_TEST(test_opt_duration_cb) +{ + struct common_params params = {0}; + const struct option opt = TEST_CALLBACK(¶ms, opt_duration_cb); + + ck_assert_int_eq(opt_duration_cb(&opt, "1m", 0), 0); + ck_assert_int_eq(params.duration, 60); +} +END_TEST + +START_TEST(test_opt_duration_cb_invalid) +{ + struct common_params params = {0}; + const struct option opt = TEST_CALLBACK(¶ms, opt_duration_cb); + + assert(freopen("/dev/null", "w", stderr)); + ck_assert_int_eq(opt_duration_cb(&opt, "abc", 0), -1); +} +END_TEST + +START_TEST(test_opt_duration_cb_unset) +{ + struct common_params params = {0}; + const struct option opt = TEST_CALLBACK(¶ms, opt_duration_cb); + + ck_assert_int_eq(opt_duration_cb(&opt, "1m", 0), 0); + ck_assert_int_eq(opt_duration_cb(&opt, NULL, 1), 0); + ck_assert_int_eq(params.duration, 0); +} +END_TEST + +START_TEST(test_opt_event_cb) +{ + struct trace_events *events = NULL; + const struct option opt = TEST_CALLBACK(&events, opt_event_cb); + + ck_assert_int_eq(opt_event_cb(&opt, "sched:sched_switch", 0), 0); + ck_assert_str_eq(events->system, "sched"); + ck_assert_str_eq(events->event, "sched_switch"); + ck_assert_ptr_eq(events->next, NULL); +} +END_TEST + +START_TEST(test_opt_event_cb_multiple) +{ + struct trace_events *events = NULL; + const struct option opt = TEST_CALLBACK(&events, opt_event_cb); + + ck_assert_int_eq(opt_event_cb(&opt, "sched:sched_switch", 0), 0); + ck_assert_int_eq(opt_event_cb(&opt, "sched:sched_wakeup", 0), 0); + ck_assert_str_eq(events->system, "sched"); + ck_assert_str_eq(events->event, "sched_wakeup"); + ck_assert_str_eq(events->next->system, "sched"); + ck_assert_str_eq(events->next->event, "sched_switch"); + ck_assert_ptr_eq(events->next->next, NULL); +} +END_TEST + +START_TEST(test_opt_housekeeping_cb) +{ + struct common_params __params = {0}; + struct common_params *params = &__params; + const struct option opt = TEST_CALLBACK(params, opt_housekeeping_cb); + + nr_cpus = 4; + ck_assert_int_eq(opt_housekeeping_cb(&opt, "0-3", 0), 0); + ck_assert_int_eq(params->hk_cpus, 1); + CLI_ASSERT_CPUSET(hk_cpu_set, 0, 1, 2, 3); +} +END_TEST + +START_TEST(test_opt_housekeeping_cb_invalid) +{ + struct common_params params = {0}; + const struct option opt = TEST_CALLBACK(¶ms, opt_housekeeping_cb); + + nr_cpus = 4; + assert(freopen("/dev/null", "w", stderr)); + ck_assert_int_eq(opt_housekeeping_cb(&opt, "0-3,5", 0), -1); +} +END_TEST + +START_TEST(test_opt_housekeeping_cb_unset) +{ + struct common_params params = {0}; + const struct option opt = TEST_CALLBACK(¶ms, opt_housekeeping_cb); + + nr_cpus = 4; + ck_assert_int_eq(opt_housekeeping_cb(&opt, "0-3", 0), 0); + ck_assert_int_eq(opt_housekeeping_cb(&opt, NULL, 1), 0); + ck_assert_int_eq(params.hk_cpus, 0); + ck_assert_int_eq(CPU_COUNT(¶ms.hk_cpu_set), 0); +} +END_TEST + +START_TEST(test_opt_priority_cb) +{ + struct common_params params = {0}; + const struct option opt = TEST_CALLBACK(¶ms, opt_priority_cb); + + ck_assert_int_eq(opt_priority_cb(&opt, "f:95", 0), 0); + ck_assert_int_eq(params.sched_param.sched_policy, SCHED_FIFO); + ck_assert_int_eq(params.sched_param.sched_priority, 95); +} +END_TEST + +START_TEST(test_opt_priority_cb_invalid) +{ + struct common_params params = {0}; + const struct option opt = TEST_CALLBACK(¶ms, opt_priority_cb); + + assert(freopen("/dev/null", "w", stderr)); + ck_assert_int_eq(opt_priority_cb(&opt, "abc", 0), -1); +} +END_TEST + +START_TEST(test_opt_priority_cb_unset) +{ + struct common_params params = {0}; + const struct option opt = TEST_CALLBACK(¶ms, opt_priority_cb); + + ck_assert_int_eq(opt_priority_cb(&opt, "f:95", 0), 0); + ck_assert_int_eq(opt_priority_cb(&opt, NULL, 1), 0); + ck_assert_int_eq(params.sched_param.sched_policy, 0); + ck_assert_int_eq(params.sched_param.sched_priority, 0); +} +END_TEST + +START_TEST(test_opt_trigger_cb) +{ + struct trace_events *events = trace_event_alloc("sched:sched_switch"); + const struct option opt = TEST_CALLBACK(&events, opt_trigger_cb); + + ck_assert_int_eq(opt_trigger_cb(&opt, "stacktrace", 0), 0); + ck_assert_str_eq(events->trigger, "stacktrace"); +} +END_TEST + +START_TEST(test_opt_trigger_cb_no_event) +{ + struct trace_events *events = NULL; + const struct option opt = TEST_CALLBACK(&events, opt_trigger_cb); + + assert(freopen("/dev/null", "w", stderr)); + ck_assert_int_eq(opt_trigger_cb(&opt, "stacktrace", 0), -1); +} +END_TEST + +START_TEST(test_opt_filter_cb) +{ + struct trace_events *events = trace_event_alloc("sched:sched_switch"); + const struct option opt = TEST_CALLBACK(&events, opt_filter_cb); + + ck_assert_int_eq(opt_filter_cb(&opt, "comm ~ \"rtla\"", 0), 0); + ck_assert_str_eq(events->filter, "comm ~ \"rtla\""); +} +END_TEST + +START_TEST(test_opt_filter_cb_no_event) +{ + struct trace_events *events = NULL; + const struct option opt = TEST_CALLBACK(&events, opt_filter_cb); + + assert(freopen("/dev/null", "w", stderr)); + ck_assert_int_eq(opt_filter_cb(&opt, "comm ~ \"rtla\"", 0), -1); +} +END_TEST + +START_TEST(test_opt_osnoise_auto_cb) +{ + struct osnoise_params params = {0}; + struct osnoise_cb_data cb_data = {¶ms}; + const struct option opt = TEST_CALLBACK(&cb_data, opt_osnoise_auto_cb); + + ck_assert_int_eq(opt_osnoise_auto_cb(&opt, "10", 0), 0); + ck_assert_int_eq(params.common.stop_us, 10); + ck_assert_int_eq(params.threshold, 1); + ck_assert_str_eq(cb_data.trace_output, "osnoise_trace.txt"); +} +END_TEST + +START_TEST(test_opt_osnoise_auto_cb_unset) +{ + struct osnoise_params params = {0}; + struct osnoise_cb_data cb_data = {¶ms}; + const struct option opt = TEST_CALLBACK(&cb_data, opt_osnoise_auto_cb); + + ck_assert_int_eq(opt_osnoise_auto_cb(&opt, "10", 0), 0); + ck_assert_int_eq(opt_osnoise_auto_cb(&opt, NULL, 1), 0); + ck_assert_int_eq(params.common.stop_us, 0); + ck_assert_int_eq(params.threshold, 0); + ck_assert_ptr_null(cb_data.trace_output); +} +END_TEST + + +START_TEST(test_opt_osnoise_trace_output_cb) +{ + const char *trace_output = NULL; + const struct option opt = TEST_CALLBACK(&trace_output, opt_osnoise_trace_output_cb); + + ck_assert_int_eq(opt_osnoise_trace_output_cb(&opt, "trace.txt", 0), 0); + ck_assert_str_eq(trace_output, "trace.txt"); +} +END_TEST + +START_TEST(test_opt_osnoise_trace_output_cb_noarg) +{ + const char *trace_output = NULL; + const struct option opt = TEST_CALLBACK(&trace_output, opt_osnoise_trace_output_cb); + + ck_assert_int_eq(opt_osnoise_trace_output_cb(&opt, NULL, 0), 0); + ck_assert_str_eq(trace_output, "osnoise_trace.txt"); +} +END_TEST + +START_TEST(test_opt_osnoise_trace_output_cb_unset) +{ + const char *trace_output = NULL; + const struct option opt = TEST_CALLBACK(&trace_output, opt_osnoise_trace_output_cb); + + ck_assert_int_eq(opt_osnoise_trace_output_cb(&opt, "trace.txt", 0), 0); + ck_assert_int_eq(opt_osnoise_trace_output_cb(&opt, NULL, 1), 0); + ck_assert_ptr_null(trace_output); +} +END_TEST + +START_TEST(test_opt_osnoise_on_threshold_cb) +{ + struct actions actions = {0}; + const struct option opt = TEST_CALLBACK(&actions, opt_osnoise_on_threshold_cb); + + ck_assert_int_eq(opt_osnoise_on_threshold_cb(&opt, "trace", 0), 0); + ck_assert_int_eq(actions.len, 1); + ck_assert_int_eq(actions.list[0].type, ACTION_TRACE_OUTPUT); + ck_assert_str_eq(actions.list[0].trace_output, "osnoise_trace.txt"); +} +END_TEST + +START_TEST(test_opt_osnoise_on_threshold_cb_invalid) +{ + struct actions actions = {0}; + const struct option opt = TEST_CALLBACK(&actions, opt_osnoise_on_threshold_cb); + + assert(freopen("/dev/null", "w", stderr)); + ck_assert_int_eq(opt_osnoise_on_threshold_cb(&opt, "abc", 0), -1); +} +END_TEST + +START_TEST(test_opt_osnoise_on_end_cb) +{ + struct actions actions = {0}; + const struct option opt = TEST_CALLBACK(&actions, opt_osnoise_on_end_cb); + + ck_assert_int_eq(opt_osnoise_on_end_cb(&opt, "trace", 0), 0); + ck_assert_int_eq(actions.len, 1); + ck_assert_int_eq(actions.list[0].type, ACTION_TRACE_OUTPUT); + ck_assert_str_eq(actions.list[0].trace_output, "osnoise_trace.txt"); +} +END_TEST + +START_TEST(test_opt_osnoise_on_end_cb_invalid) +{ + struct actions actions = {0}; + const struct option opt = TEST_CALLBACK(&actions, opt_osnoise_on_end_cb); + + assert(freopen("/dev/null", "w", stderr)); + ck_assert_int_eq(opt_osnoise_on_end_cb(&opt, "abc", 0), -1); +} +END_TEST + +START_TEST(test_opt_timerlat_auto_cb) +{ + struct timerlat_params params = {0}; + struct timerlat_cb_data cb_data = {¶ms}; + const struct option opt = TEST_CALLBACK(&cb_data, opt_timerlat_auto_cb); + + ck_assert_int_eq(opt_timerlat_auto_cb(&opt, "10", 0), 0); + ck_assert_int_eq(params.common.stop_us, 10); + ck_assert_int_eq(params.common.stop_total_us, 10); + ck_assert_int_eq(params.print_stack, 10); + ck_assert_str_eq(cb_data.trace_output, "timerlat_trace.txt"); +} +END_TEST + +START_TEST(test_opt_timerlat_auto_cb_unset) +{ + struct timerlat_params params = {0}; + struct timerlat_cb_data cb_data = {¶ms}; + const struct option opt = TEST_CALLBACK(&cb_data, opt_timerlat_auto_cb); + + ck_assert_int_eq(opt_timerlat_auto_cb(&opt, "10", 0), 0); + ck_assert_int_eq(opt_timerlat_auto_cb(&opt, NULL, 1), 0); + ck_assert_int_eq(params.common.stop_us, 0); + ck_assert_int_eq(params.common.stop_total_us, 0); + ck_assert_int_eq(params.print_stack, 0); + ck_assert_ptr_null(cb_data.trace_output); +} +END_TEST + + +START_TEST(test_opt_aa_only_cb) +{ + struct timerlat_params params = {0}; + const struct option opt = TEST_CALLBACK(¶ms, opt_aa_only_cb); + + ck_assert_int_eq(opt_aa_only_cb(&opt, "10", 0), 0); + ck_assert_int_eq(params.common.stop_us, 10); + ck_assert_int_eq(params.common.stop_total_us, 10); + ck_assert_int_eq(params.print_stack, 10); + ck_assert_int_eq(params.common.aa_only, 1); +} +END_TEST + +START_TEST(test_opt_aa_only_cb_unset) +{ + struct timerlat_params params = {0}; + const struct option opt = TEST_CALLBACK(¶ms, opt_aa_only_cb); + + ck_assert_int_eq(opt_aa_only_cb(&opt, "10", 0), 0); + ck_assert_int_eq(opt_aa_only_cb(&opt, NULL, 1), 0); + ck_assert_int_eq(params.common.stop_us, 0); + ck_assert_int_eq(params.common.stop_total_us, 0); + ck_assert_int_eq(params.print_stack, 0); + ck_assert_int_eq(params.common.aa_only, 0); +} +END_TEST + +START_TEST(test_opt_timerlat_trace_output_cb) +{ + const char *trace_output = NULL; + const struct option opt = TEST_CALLBACK(&trace_output, opt_timerlat_trace_output_cb); + + ck_assert_int_eq(opt_timerlat_trace_output_cb(&opt, "trace.txt", 0), 0); + ck_assert_str_eq(trace_output, "trace.txt"); +} +END_TEST + +START_TEST(test_opt_timerlat_trace_output_cb_noarg) +{ + const char *trace_output = NULL; + const struct option opt = TEST_CALLBACK(&trace_output, opt_timerlat_trace_output_cb); + + ck_assert_int_eq(opt_timerlat_trace_output_cb(&opt, NULL, 0), 0); + ck_assert_str_eq(trace_output, "timerlat_trace.txt"); +} +END_TEST + +START_TEST(test_opt_timerlat_trace_output_cb_unset) +{ + const char *trace_output = NULL; + const struct option opt = TEST_CALLBACK(&trace_output, opt_timerlat_trace_output_cb); + + ck_assert_int_eq(opt_timerlat_trace_output_cb(&opt, "trace.txt", 0), 0); + ck_assert_int_eq(opt_timerlat_trace_output_cb(&opt, NULL, 1), 0); + ck_assert_ptr_null(trace_output); +} +END_TEST + +START_TEST(test_opt_timerlat_on_threshold_cb) +{ + struct actions actions = {0}; + const struct option opt = TEST_CALLBACK(&actions, opt_timerlat_on_threshold_cb); + + ck_assert_int_eq(opt_timerlat_on_threshold_cb(&opt, "trace", 0), 0); + ck_assert_int_eq(actions.len, 1); + ck_assert_int_eq(actions.list[0].type, ACTION_TRACE_OUTPUT); + ck_assert_str_eq(actions.list[0].trace_output, "timerlat_trace.txt"); +} +END_TEST + +START_TEST(test_opt_timerlat_on_threshold_cb_invalid) +{ + struct actions actions = {0}; + const struct option opt = TEST_CALLBACK(&actions, opt_timerlat_on_threshold_cb); + + assert(freopen("/dev/null", "w", stderr)); + ck_assert_int_eq(opt_timerlat_on_threshold_cb(&opt, "abc", 0), -1); +} +END_TEST + +START_TEST(test_opt_timerlat_on_end_cb) +{ + struct actions actions = {0}; + const struct option opt = TEST_CALLBACK(&actions, opt_timerlat_on_end_cb); + + ck_assert_int_eq(opt_timerlat_on_end_cb(&opt, "trace", 0), 0); + ck_assert_int_eq(actions.len, 1); + ck_assert_int_eq(actions.list[0].type, ACTION_TRACE_OUTPUT); + ck_assert_str_eq(actions.list[0].trace_output, "timerlat_trace.txt"); +} +END_TEST + +START_TEST(test_opt_timerlat_on_end_cb_invalid) +{ + struct actions actions = {0}; + const struct option opt = TEST_CALLBACK(&actions, opt_timerlat_on_end_cb); + + assert(freopen("/dev/null", "w", stderr)); + ck_assert_int_eq(opt_timerlat_on_end_cb(&opt, "abc", 0), -1); +} +END_TEST + +START_TEST(test_opt_user_threads_cb) +{ + struct timerlat_params params = {0}; + const struct option opt = TEST_CALLBACK(¶ms, opt_user_threads_cb); + + ck_assert_int_eq(opt_user_threads_cb(&opt, NULL, 0), 0); + ck_assert_int_eq(params.common.user_workload, 1); + ck_assert_int_eq(params.common.user_data, 1); +} +END_TEST + +START_TEST(test_opt_user_threads_cb_unset) +{ + struct timerlat_params params = {0}; + const struct option opt = TEST_CALLBACK(¶ms, opt_user_threads_cb); + + ck_assert_int_eq(opt_user_threads_cb(&opt, NULL, 0), 0); + ck_assert_int_eq(opt_user_threads_cb(&opt, NULL, 1), 0); + ck_assert_int_eq(params.common.user_workload, 0); + ck_assert_int_eq(params.common.user_data, 0); +} +END_TEST + +START_TEST(test_opt_nano_cb) +{ + struct timerlat_params params = {0}; + const struct option opt = TEST_CALLBACK(¶ms, opt_nano_cb); + + ck_assert_int_eq(opt_nano_cb(&opt, NULL, 0), 0); + ck_assert_int_eq(params.common.output_divisor, 1); +} +END_TEST + +START_TEST(test_opt_nano_cb_unset) +{ + struct timerlat_params params = {0}; + const struct option opt = TEST_CALLBACK(¶ms, opt_nano_cb); + + ck_assert_int_eq(opt_nano_cb(&opt, NULL, 0), 0); + ck_assert_int_eq(opt_nano_cb(&opt, NULL, 1), 0); + ck_assert_int_eq(params.common.output_divisor, default_output_divisor); +} +END_TEST + +START_TEST(test_opt_timerlat_align_cb) +{ + struct timerlat_params params = {0}; + const struct option opt = RTLA_OPT_CALLBACK_DATA('A', "aligned", ¶ms, "us", + "test", opt_timerlat_align_cb, LLONG_RANGE(0, LLONG_MAX)); + + ck_assert_int_eq(opt_timerlat_align_cb(&opt, "500", 0), 0); + ck_assert(params.timerlat_align); + ck_assert_int_eq(params.timerlat_align_us, 500); +} +END_TEST + +START_TEST(test_opt_timerlat_align_cb_invalid) +{ + struct timerlat_params params = {0}; + const struct option opt = RTLA_OPT_CALLBACK_DATA('A', "aligned", ¶ms, "us", + "test", opt_timerlat_align_cb, LLONG_RANGE(0, LLONG_MAX)); + + assert(freopen("/dev/null", "w", stderr)); + ck_assert_int_eq(opt_timerlat_align_cb(&opt, "-1", 0), -1); +} +END_TEST + +START_TEST(test_opt_timerlat_align_cb_unset) +{ + struct timerlat_params params = {0}; + const struct option opt = RTLA_OPT_CALLBACK_DATA('A', "aligned", ¶ms, "us", + "test", opt_timerlat_align_cb, LLONG_RANGE(0, LLONG_MAX)); + + ck_assert_int_eq(opt_timerlat_align_cb(&opt, "500", 0), 0); + ck_assert_int_eq(opt_timerlat_align_cb(&opt, NULL, 1), 0); + ck_assert_int_eq(params.timerlat_align, 0); + ck_assert_int_eq(params.timerlat_align_us, 0); +} +END_TEST + +START_TEST(test_opt_stack_format_cb) +{ + int stack_format = 0; + const struct option opt = TEST_CALLBACK(&stack_format, opt_stack_format_cb); + + ck_assert_int_eq(opt_stack_format_cb(&opt, "full", 0), 0); + ck_assert_int_eq(stack_format, STACK_FORMAT_FULL); +} +END_TEST + +START_TEST(test_opt_stack_format_cb_invalid) +{ + int stack_format = 0; + const struct option opt = TEST_CALLBACK(&stack_format, opt_stack_format_cb); + + assert(freopen("/dev/null", "w", stderr)); + ck_assert_int_eq(opt_stack_format_cb(&opt, "abc", 0), -1); +} +END_TEST + +START_TEST(test_opt_stack_format_cb_unset) +{ + int stack_format = 0; + const struct option opt = TEST_CALLBACK(&stack_format, opt_stack_format_cb); + + ck_assert_int_eq(opt_stack_format_cb(&opt, "full", 0), 0); + ck_assert_int_eq(opt_stack_format_cb(&opt, NULL, 1), 0); + ck_assert_int_eq(stack_format, default_stack_format); +} +END_TEST + + +Suite *cli_opt_callback_suite(void) +{ + Suite *s = suite_create("cli_opt_callback"); + TCase *tc; + + tc = tcase_create("common"); + tcase_add_test(tc, test_opt_llong_callback_simple); + tcase_add_test(tc, test_opt_llong_callback_max); + tcase_add_test(tc, test_opt_llong_callback_min); + tcase_add_test(tc, test_opt_llong_callback_non_numeric); + tcase_add_test(tc, test_opt_llong_callback_non_numeric_suffix); + tcase_add_test(tc, test_opt_llong_callback_unset); + tcase_add_test(tc, test_opt_llong_callback_unset_defval); + tcase_add_test(tc, test_opt_llong_callback_range_in); + tcase_add_test(tc, test_opt_llong_callback_range_below); + tcase_add_test(tc, test_opt_llong_callback_range_above); + tcase_add_test(tc, test_opt_llong_callback_range_boundary); + tcase_add_test(tc, test_opt_int_callback_simple); + tcase_add_test(tc, test_opt_int_callback_max); + tcase_add_test(tc, test_opt_int_callback_min); + tcase_add_test(tc, test_opt_int_callback_non_numeric); + tcase_add_test(tc, test_opt_int_callback_non_numeric_suffix); + tcase_add_test(tc, test_opt_int_callback_unset); + tcase_add_test(tc, test_opt_int_callback_unset_defval); + tcase_add_test(tc, test_opt_int_callback_range_in); + tcase_add_test(tc, test_opt_int_callback_range_below); + tcase_add_test(tc, test_opt_int_callback_range_above); + tcase_add_test(tc, test_opt_int_callback_range_boundary); + tcase_add_test(tc, test_opt_cpus_cb); + tcase_add_test(tc, test_opt_cpus_cb_invalid); + tcase_add_test(tc, test_opt_cgroup_cb); + tcase_add_test(tc, test_opt_cgroup_cb_equals); + tcase_add_test(tc, test_opt_cgroup_cb_unset); + tcase_add_test(tc, test_opt_duration_cb); + tcase_add_test(tc, test_opt_duration_cb_unset); + tcase_add_test(tc, test_opt_duration_cb_invalid); + tcase_add_test(tc, test_opt_event_cb); + tcase_add_test(tc, test_opt_event_cb_multiple); + tcase_add_test(tc, test_opt_housekeeping_cb); + tcase_add_test(tc, test_opt_housekeeping_cb_invalid); + tcase_add_test(tc, test_opt_housekeeping_cb_unset); + tcase_add_test(tc, test_opt_priority_cb); + tcase_add_test(tc, test_opt_priority_cb_invalid); + tcase_add_test(tc, test_opt_priority_cb_unset); + tcase_add_test(tc, test_opt_trigger_cb); + tcase_add_test(tc, test_opt_trigger_cb_no_event); + tcase_add_test(tc, test_opt_filter_cb); + tcase_add_test(tc, test_opt_filter_cb_no_event); + suite_add_tcase(s, tc); + + tc = tcase_create("osnoise"); + tcase_add_test(tc, test_opt_osnoise_auto_cb); + tcase_add_test(tc, test_opt_osnoise_auto_cb_unset); + tcase_add_test(tc, test_opt_osnoise_trace_output_cb); + tcase_add_test(tc, test_opt_osnoise_trace_output_cb_noarg); + tcase_add_test(tc, test_opt_osnoise_trace_output_cb_unset); + tcase_add_test(tc, test_opt_osnoise_on_threshold_cb); + tcase_add_test(tc, test_opt_osnoise_on_threshold_cb_invalid); + tcase_add_test(tc, test_opt_osnoise_on_end_cb); + tcase_add_test(tc, test_opt_osnoise_on_end_cb_invalid); + suite_add_tcase(s, tc); + + tc = tcase_create("timerlat"); + tcase_add_test(tc, test_opt_timerlat_auto_cb); + tcase_add_test(tc, test_opt_timerlat_auto_cb_unset); + tcase_add_test(tc, test_opt_aa_only_cb); + tcase_add_test(tc, test_opt_aa_only_cb_unset); + tcase_add_test(tc, test_opt_timerlat_trace_output_cb); + tcase_add_test(tc, test_opt_timerlat_trace_output_cb_noarg); + tcase_add_test(tc, test_opt_timerlat_trace_output_cb_unset); + tcase_add_test(tc, test_opt_timerlat_on_threshold_cb); + tcase_add_test(tc, test_opt_timerlat_on_threshold_cb_invalid); + tcase_add_test(tc, test_opt_timerlat_on_end_cb); + tcase_add_test(tc, test_opt_timerlat_on_end_cb_invalid); + tcase_add_test(tc, test_opt_user_threads_cb); + tcase_add_test(tc, test_opt_user_threads_cb_unset); + tcase_add_test(tc, test_opt_nano_cb); + tcase_add_test(tc, test_opt_nano_cb_unset); + tcase_add_test(tc, test_opt_stack_format_cb); + tcase_add_test(tc, test_opt_stack_format_cb_invalid); + tcase_add_test(tc, test_opt_stack_format_cb_unset); + tcase_add_test(tc, test_opt_timerlat_align_cb); + tcase_add_test(tc, test_opt_timerlat_align_cb_invalid); + tcase_add_test(tc, test_opt_timerlat_align_cb_unset); + suite_add_tcase(s, tc); + + return s; +} diff --git a/tools/tracing/rtla/tests/unit/cli_params_assert.h b/tools/tracing/rtla/tests/unit/cli_params_assert.h new file mode 100644 index 000000000..4bc7d582f --- /dev/null +++ b/tools/tracing/rtla/tests/unit/cli_params_assert.h @@ -0,0 +1,68 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#pragma once + +#include "../../src/timerlat.h" + +/* Tracing Options */ + +#define CLI_ASSERT_SINGLE_EVENT(_system, _event) do {\ + ck_assert_ptr_nonnull(params->events);\ + ck_assert_str_eq(params->events->system, _system);\ + ck_assert_str_eq(params->events->event, _event);\ + ck_assert_ptr_null(params->events->next);\ +} while (0) + +#define CLI_ASSERT_SINGLE_FILTER(_filter) do {\ + ck_assert_ptr_nonnull(params->events);\ + ck_assert_str_eq(params->events->filter, _filter);\ + ck_assert_ptr_null(params->events->next);\ +} while (0) + +#define CLI_ASSERT_SINGLE_TRIGGER(_trigger) do {\ + ck_assert_ptr_nonnull(params->events);\ + ck_assert_str_eq(params->events->trigger, _trigger);\ + ck_assert_ptr_null(params->events->next);\ +} while (0) + +/* CPU Configuration */ + +#define CLI_ASSERT_CPUSET(_field, ...) do {\ + int n;\ + int cpus[] = { __VA_ARGS__ };\ + for (n = 0; n < sizeof(cpus) / sizeof(int); n++)\ + ck_assert(CPU_ISSET(cpus[n], ¶ms->_field));\ + ck_assert_int_eq(CPU_COUNT(¶ms->_field), n);\ +} while (0) + +/* Auto Analysis and Actions */ + +#define CLI_OSNOISE_ASSERT_AUTO(_stop) do {\ + ck_assert_int_eq(params->stop_us, _stop);\ + ck_assert_int_eq(osn_params->threshold, 1);\ + ck_assert_int_eq(params->threshold_actions.len, 1);\ + ck_assert_int_eq(params->threshold_actions.list[0].type, ACTION_TRACE_OUTPUT);\ + ck_assert_str_eq(params->threshold_actions.list[0].trace_output, "osnoise_trace.txt");\ +} while (0) + +#define CLI_TIMERLAT_ASSERT_AUTO(_threshold) do {\ + ck_assert_int_eq(params->stop_us, _threshold);\ + ck_assert_int_eq(params->stop_total_us, _threshold);\ + ck_assert_int_eq(tlat_params->print_stack, _threshold);\ + ck_assert_int_eq(params->threshold_actions.len, 1);\ + ck_assert_int_eq(params->threshold_actions.list[0].type, ACTION_TRACE_OUTPUT);\ + ck_assert_str_eq(params->threshold_actions.list[0].trace_output, "timerlat_trace.txt");\ +} while (0) + +#define CLI_TIMERLAT_ASSERT_AA_ONLY(_threshold) do {\ + ck_assert_int_eq(params->stop_us, _threshold);\ + ck_assert_int_eq(params->stop_total_us, _threshold);\ + ck_assert_int_eq(tlat_params->print_stack, _threshold);\ + ck_assert_int_eq(params->threshold_actions.len, 0);\ + ck_assert(params->aa_only);\ +} while (0) + +#define CLI_ASSERT_SINGLE_ACTION(_actions, _type, _arg, _valtype, _value) do {\ + ck_assert_int_eq(params->_actions.len, 1);\ + ck_assert_int_eq(params->_actions.list[0].type, _type);\ + ck_assert_##_valtype##_eq(params->_actions.list[0]._arg, _value);\ +} while (0) diff --git a/tools/tracing/rtla/tests/unit/osnoise_hist_cli.c b/tools/tracing/rtla/tests/unit/osnoise_hist_cli.c new file mode 100644 index 000000000..221985e67 --- /dev/null +++ b/tools/tracing/rtla/tests/unit/osnoise_hist_cli.c @@ -0,0 +1,575 @@ +// SPDX-License-Identifier: GPL-2.0 + +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include + +#include "cli_params_assert.h" +#include "../../src/cli.h" + +#define PARSE_ARGS(...) char *argv[] = { __VA_ARGS__, NULL };\ + int argc = sizeof(argv) / sizeof(char *) - 1;\ + struct common_params *params =\ + osnoise_hist_parse_args(argc, argv);\ + struct osnoise_params *osn_params __maybe_unused =\ + to_osnoise_params(params) + +/* Tracing Options */ + +START_TEST(test_period_short) +{ + PARSE_ARGS("osnoise", "hist", "-p", "100000"); + + ck_assert_int_eq(osn_params->period, 100000); +} +END_TEST + +START_TEST(test_period_long) +{ + PARSE_ARGS("osnoise", "hist", "--period", "100000"); + + ck_assert_int_eq(osn_params->period, 100000); +} +END_TEST + +START_TEST(test_period_unset_short) +{ + PARSE_ARGS("osnoise", "hist", "-p", "100000", "--no-period"); + + ck_assert_int_eq(osn_params->period, 0); +} +END_TEST + +START_TEST(test_period_unset_long) +{ + PARSE_ARGS("osnoise", "hist", "--period", "100000", "--no-period"); + + ck_assert_int_eq(osn_params->period, 0); +} +END_TEST + +START_TEST(test_runtime_short) +{ + PARSE_ARGS("osnoise", "hist", "-r", "95000"); + + ck_assert_int_eq(osn_params->runtime, 95000); +} +END_TEST + +START_TEST(test_runtime_long) +{ + PARSE_ARGS("osnoise", "hist", "--runtime", "95000"); + + ck_assert_int_eq(osn_params->runtime, 95000); +} +END_TEST + +START_TEST(test_stop_short) +{ + PARSE_ARGS("osnoise", "hist", "-s", "20"); + + ck_assert_int_eq(params->stop_us, 20); +} +END_TEST + +START_TEST(test_stop_long) +{ + PARSE_ARGS("osnoise", "hist", "--stop", "20"); + + ck_assert_int_eq(params->stop_us, 20); +} +END_TEST + +START_TEST(test_stop_total_short) +{ + PARSE_ARGS("osnoise", "hist", "-S", "20"); + + ck_assert_int_eq(params->stop_total_us, 20); +} +END_TEST + +START_TEST(test_stop_total_long) +{ + PARSE_ARGS("osnoise", "hist", "--stop-total", "20"); + + ck_assert_int_eq(params->stop_total_us, 20); +} +END_TEST + +START_TEST(test_threshold_short) +{ + PARSE_ARGS("osnoise", "hist", "-T", "5"); + + ck_assert_int_eq(osn_params->threshold, 5); +} +END_TEST + +START_TEST(test_threshold_long) +{ + PARSE_ARGS("osnoise", "hist", "--threshold", "5"); + + ck_assert_int_eq(osn_params->threshold, 5); +} +END_TEST + +START_TEST(test_trace_short_noarg) +{ + PARSE_ARGS("osnoise", "hist", "-t"); + + CLI_ASSERT_SINGLE_ACTION(threshold_actions, ACTION_TRACE_OUTPUT, trace_output, str, + "osnoise_trace.txt"); +} +END_TEST + +START_TEST(test_trace_short_followarg) +{ + PARSE_ARGS("osnoise", "hist", "-t", "-d", "20"); + + CLI_ASSERT_SINGLE_ACTION(threshold_actions, ACTION_TRACE_OUTPUT, trace_output, str, + "osnoise_trace.txt"); + ck_assert_int_eq(params->duration, 20); /* check if next argument is read correctly */ +} +END_TEST + +START_TEST(test_trace_short_space) +{ + PARSE_ARGS("osnoise", "hist", "-t", "tracefile"); + + CLI_ASSERT_SINGLE_ACTION(threshold_actions, ACTION_TRACE_OUTPUT, trace_output, str, + "tracefile"); +} +END_TEST + +START_TEST(test_trace_short_equals) +{ + PARSE_ARGS("osnoise", "hist", "-t=tracefile"); + + CLI_ASSERT_SINGLE_ACTION(threshold_actions, ACTION_TRACE_OUTPUT, trace_output, str, + "tracefile"); +} +END_TEST + +START_TEST(test_trace_long_noarg) +{ + PARSE_ARGS("osnoise", "hist", "--trace"); + + CLI_ASSERT_SINGLE_ACTION(threshold_actions, ACTION_TRACE_OUTPUT, trace_output, str, + "osnoise_trace.txt"); +} +END_TEST + +START_TEST(test_trace_long_followarg) +{ + PARSE_ARGS("osnoise", "hist", "--trace", "-d", "20"); + + CLI_ASSERT_SINGLE_ACTION(threshold_actions, ACTION_TRACE_OUTPUT, trace_output, str, + "osnoise_trace.txt"); + ck_assert_int_eq(params->duration, 20); /* check if next argument is read correctly */ +} +END_TEST + +START_TEST(test_trace_long_space) +{ + PARSE_ARGS("osnoise", "hist", "--trace", "tracefile"); + + CLI_ASSERT_SINGLE_ACTION(threshold_actions, ACTION_TRACE_OUTPUT, trace_output, str, + "tracefile"); +} +END_TEST + +START_TEST(test_trace_long_equals) +{ + PARSE_ARGS("osnoise", "hist", "--trace=tracefile"); + + CLI_ASSERT_SINGLE_ACTION(threshold_actions, ACTION_TRACE_OUTPUT, trace_output, str, + "tracefile"); +} +END_TEST + +/* Event Configuration */ + +START_TEST(test_event_short) +{ + PARSE_ARGS("osnoise", "hist", "-e", "system:event"); + + CLI_ASSERT_SINGLE_EVENT("system", "event"); +} +END_TEST + +START_TEST(test_event_long) +{ + PARSE_ARGS("osnoise", "hist", "--event", "system:event"); + + CLI_ASSERT_SINGLE_EVENT("system", "event"); +} +END_TEST + +START_TEST(test_filter) +{ + PARSE_ARGS("osnoise", "hist", "-e", "system:event", "--filter", "filter"); + + CLI_ASSERT_SINGLE_FILTER("filter"); +} +END_TEST + +START_TEST(test_trigger) +{ + PARSE_ARGS("osnoise", "hist", "-e", "system:event", "--trigger", "trigger"); + + CLI_ASSERT_SINGLE_TRIGGER("trigger"); +} +END_TEST + +/* CPU Configuration */ + +START_TEST(test_cpus_short) +{ + nr_cpus = 4; + + PARSE_ARGS("osnoise", "hist", "-c", "0-1,3"); + + ck_assert_str_eq(params->cpus, "0-1,3"); + CLI_ASSERT_CPUSET(monitored_cpus, 0, 1, 3); +} +END_TEST + +START_TEST(test_cpus_long) +{ + nr_cpus = 4; + + PARSE_ARGS("osnoise", "hist", "--cpus", "0-1,3"); + + ck_assert_str_eq(params->cpus, "0-1,3"); + CLI_ASSERT_CPUSET(monitored_cpus, 0, 1, 3); +} +END_TEST + +START_TEST(test_housekeeping_short) +{ + nr_cpus = 4; + + PARSE_ARGS("osnoise", "hist", "-H", "0-1,3"); + + CLI_ASSERT_CPUSET(hk_cpu_set, 0, 1, 3); +} +END_TEST + +START_TEST(test_housekeeping_long) +{ + nr_cpus = 4; + + PARSE_ARGS("osnoise", "hist", "--house-keeping", "0-1,3"); + + CLI_ASSERT_CPUSET(hk_cpu_set, 0, 1, 3); +} +END_TEST + +/* Thread Configuration */ + +START_TEST(test_cgroup_short_noarg) +{ + PARSE_ARGS("osnoise", "hist", "-C"); + + ck_assert(params->cgroup); + ck_assert_ptr_null(params->cgroup_name); +} +END_TEST + +START_TEST(test_cgroup_short_space) +{ + PARSE_ARGS("osnoise", "hist", "-C", "cgroup"); + + ck_assert(params->cgroup); + ck_assert_str_eq(params->cgroup_name, "cgroup"); +} +END_TEST + +START_TEST(test_cgroup_short_equals) +{ + PARSE_ARGS("osnoise", "hist", "-C=cgroup"); + + ck_assert(params->cgroup); + ck_assert_str_eq(params->cgroup_name, "cgroup"); +} +END_TEST + +START_TEST(test_cgroup_long_noarg) +{ + PARSE_ARGS("osnoise", "hist", "--cgroup"); + + ck_assert(params->cgroup); + ck_assert_ptr_null(params->cgroup_name); +} +END_TEST + +START_TEST(test_cgroup_long_space) +{ + PARSE_ARGS("osnoise", "hist", "--cgroup", "cgroup"); + + ck_assert(params->cgroup); + ck_assert_str_eq(params->cgroup_name, "cgroup"); +} +END_TEST + +START_TEST(test_cgroup_long_equals) +{ + PARSE_ARGS("osnoise", "hist", "--cgroup=cgroup"); + + ck_assert(params->cgroup); + ck_assert_str_eq(params->cgroup_name, "cgroup"); +} +END_TEST + +START_TEST(test_priority_short) +{ + PARSE_ARGS("osnoise", "hist", "-P", "f:95"); + + ck_assert_int_eq(params->sched_param.sched_policy, SCHED_FIFO); + ck_assert_int_eq(params->sched_param.sched_priority, 95); +} +END_TEST + +START_TEST(test_priority_long) +{ + PARSE_ARGS("osnoise", "hist", "--priority", "f:95"); + + ck_assert_int_eq(params->sched_param.sched_policy, SCHED_FIFO); + ck_assert_int_eq(params->sched_param.sched_priority, 95); +} +END_TEST + +/* Histogram Options */ + +START_TEST(test_bucket_size_short) +{ + PARSE_ARGS("osnoise", "hist", "-b", "2"); + + ck_assert_int_eq(params->hist.bucket_size, 2); +} +END_TEST + +START_TEST(test_bucket_size_long) +{ + PARSE_ARGS("osnoise", "hist", "--bucket-size", "2"); + + ck_assert_int_eq(params->hist.bucket_size, 2); +} +END_TEST + +START_TEST(test_entries_short) +{ + PARSE_ARGS("osnoise", "hist", "-E", "512"); + + ck_assert_int_eq(params->hist.entries, 512); +} +END_TEST + +START_TEST(test_entries_long) +{ + PARSE_ARGS("osnoise", "hist", "--entries", "512"); + + ck_assert_int_eq(params->hist.entries, 512); +} +END_TEST + +START_TEST(test_no_header) +{ + PARSE_ARGS("osnoise", "hist", "--no-header"); + + ck_assert(params->hist.no_header); +} +END_TEST + +START_TEST(test_no_index) +{ + PARSE_ARGS("osnoise", "hist", "--with-zeros", "--no-index"); + + ck_assert(params->hist.no_index); +} +END_TEST + +START_TEST(test_no_summary) +{ + PARSE_ARGS("osnoise", "hist", "--no-summary"); + + ck_assert(params->hist.no_summary); +} +END_TEST + +START_TEST(test_with_zeros) +{ + PARSE_ARGS("osnoise", "hist", "--with-zeros"); + + ck_assert(params->hist.with_zeros); +} +END_TEST + +/* System Tuning */ + +START_TEST(test_trace_buffer_size) +{ + PARSE_ARGS("osnoise", "hist", "--trace-buffer-size", "200"); + + ck_assert_int_eq(params->buffer_size, 200); +} +END_TEST + +START_TEST(test_warm_up) +{ + PARSE_ARGS("osnoise", "hist", "--warm-up", "5"); + + ck_assert_int_eq(params->warmup, 5); +} +END_TEST + +/* Auto Analysis and Actions */ + +START_TEST(test_auto) +{ + PARSE_ARGS("osnoise", "hist", "-a", "20"); + + CLI_OSNOISE_ASSERT_AUTO(20); +} +END_TEST + +START_TEST(test_on_end) +{ + PARSE_ARGS("osnoise", "hist", "--on-end", "trace"); + + CLI_ASSERT_SINGLE_ACTION(end_actions, ACTION_TRACE_OUTPUT, trace_output, str, + "osnoise_trace.txt"); +} +END_TEST + +START_TEST(test_on_threshold) +{ + PARSE_ARGS("osnoise", "hist", "--on-threshold", "trace"); + + CLI_ASSERT_SINGLE_ACTION(threshold_actions, ACTION_TRACE_OUTPUT, trace_output, str, + "osnoise_trace.txt"); +} +END_TEST + +/* General */ + +START_TEST(test_debug_short) +{ + PARSE_ARGS("osnoise", "hist", "-D"); + + ck_assert(config_debug); +} +END_TEST + +START_TEST(test_debug_long) +{ + PARSE_ARGS("osnoise", "hist", "--debug"); + + ck_assert(config_debug); +} +END_TEST + +START_TEST(test_duration_short) +{ + PARSE_ARGS("osnoise", "hist", "-d", "1m"); + + ck_assert_int_eq(params->duration, 60); +} +END_TEST + +START_TEST(test_duration_long) +{ + PARSE_ARGS("osnoise", "hist", "--duration", "1m"); + + ck_assert_int_eq(params->duration, 60); +} +END_TEST + +Suite *osnoise_hist_cli_suite(void) +{ + Suite *s = suite_create("osnoise_hist_cli"); + TCase *tc; + + tc = tcase_create("tracing_options"); + tcase_add_test(tc, test_period_short); + tcase_add_test(tc, test_period_long); + tcase_add_test(tc, test_period_unset_short); + tcase_add_test(tc, test_period_unset_long); + tcase_add_test(tc, test_runtime_short); + tcase_add_test(tc, test_runtime_long); + tcase_add_test(tc, test_stop_short); + tcase_add_test(tc, test_stop_long); + tcase_add_test(tc, test_stop_total_short); + tcase_add_test(tc, test_stop_total_long); + tcase_add_test(tc, test_threshold_short); + tcase_add_test(tc, test_threshold_long); + tcase_add_test(tc, test_trace_short_noarg); + tcase_add_test(tc, test_trace_short_followarg); + tcase_add_test(tc, test_trace_short_space); + tcase_add_test(tc, test_trace_short_equals); + tcase_add_test(tc, test_trace_long_noarg); + tcase_add_test(tc, test_trace_long_followarg); + tcase_add_test(tc, test_trace_long_space); + tcase_add_test(tc, test_trace_long_equals); + suite_add_tcase(s, tc); + + tc = tcase_create("event_configuration"); + tcase_add_test(tc, test_event_short); + tcase_add_test(tc, test_event_long); + tcase_add_test(tc, test_filter); + tcase_add_test(tc, test_trigger); + suite_add_tcase(s, tc); + + tc = tcase_create("cpu_configuration"); + tcase_add_test(tc, test_cpus_short); + tcase_add_test(tc, test_cpus_long); + tcase_add_test(tc, test_housekeeping_short); + tcase_add_test(tc, test_housekeeping_long); + suite_add_tcase(s, tc); + + tc = tcase_create("thread_configuration"); + tcase_add_test(tc, test_cgroup_short_noarg); + tcase_add_test(tc, test_cgroup_short_space); + tcase_add_test(tc, test_cgroup_short_equals); + tcase_add_test(tc, test_cgroup_long_noarg); + tcase_add_test(tc, test_cgroup_long_space); + tcase_add_test(tc, test_cgroup_long_equals); + tcase_add_test(tc, test_priority_short); + tcase_add_test(tc, test_priority_long); + suite_add_tcase(s, tc); + + tc = tcase_create("histogram_options"); + tcase_add_test(tc, test_bucket_size_short); + tcase_add_test(tc, test_bucket_size_long); + tcase_add_test(tc, test_entries_short); + tcase_add_test(tc, test_entries_long); + tcase_add_test(tc, test_no_header); + tcase_add_test(tc, test_no_index); + tcase_add_test(tc, test_no_summary); + tcase_add_test(tc, test_with_zeros); + suite_add_tcase(s, tc); + + tc = tcase_create("system_tuning"); + tcase_add_test(tc, test_trace_buffer_size); + tcase_add_test(tc, test_warm_up); + suite_add_tcase(s, tc); + + tc = tcase_create("aa_actions"); + tcase_add_test(tc, test_auto); + tcase_add_test(tc, test_on_end); + tcase_add_test(tc, test_on_threshold); + suite_add_tcase(s, tc); + + tc = tcase_create("general"); + tcase_add_test(tc, test_debug_short); + tcase_add_test(tc, test_debug_long); + tcase_add_test(tc, test_duration_short); + tcase_add_test(tc, test_duration_long); + suite_add_tcase(s, tc); + + return s; +} diff --git a/tools/tracing/rtla/tests/unit/osnoise_top_cli.c b/tools/tracing/rtla/tests/unit/osnoise_top_cli.c new file mode 100644 index 000000000..057dbe574 --- /dev/null +++ b/tools/tracing/rtla/tests/unit/osnoise_top_cli.c @@ -0,0 +1,521 @@ +// SPDX-License-Identifier: GPL-2.0 + +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include + +#include "cli_params_assert.h" +#include "../../src/cli.h" + +#define PARSE_ARGS(...) char *argv[] = { __VA_ARGS__, NULL };\ + int argc = sizeof(argv) / sizeof(char *) - 1;\ + struct common_params *params =\ + osnoise_top_parse_args(argc, argv);\ + struct osnoise_params *osn_params __maybe_unused =\ + to_osnoise_params(params) + +/* Tracing Options */ + +START_TEST(test_period_short) +{ + PARSE_ARGS("osnoise", "top", "-p", "100000"); + + ck_assert_int_eq(osn_params->period, 100000); +} +END_TEST + +START_TEST(test_period_long) +{ + PARSE_ARGS("osnoise", "top", "--period", "100000"); + + ck_assert_int_eq(osn_params->period, 100000); +} +END_TEST + +START_TEST(test_period_unset_short) +{ + PARSE_ARGS("osnoise", "top", "-p", "100000", "--no-period"); + + ck_assert_int_eq(osn_params->period, 0); +} +END_TEST + +START_TEST(test_period_unset_long) +{ + PARSE_ARGS("osnoise", "top", "--period", "100000", "--no-period"); + + ck_assert_int_eq(osn_params->period, 0); +} +END_TEST + +START_TEST(test_runtime_short) +{ + PARSE_ARGS("osnoise", "top", "-r", "95000"); + + ck_assert_int_eq(osn_params->runtime, 95000); +} +END_TEST + +START_TEST(test_runtime_long) +{ + PARSE_ARGS("osnoise", "top", "--runtime", "95000"); + + ck_assert_int_eq(osn_params->runtime, 95000); +} +END_TEST + +START_TEST(test_stop_short) +{ + PARSE_ARGS("osnoise", "top", "-s", "20"); + + ck_assert_int_eq(params->stop_us, 20); +} +END_TEST + +START_TEST(test_stop_long) +{ + PARSE_ARGS("osnoise", "top", "--stop", "20"); + + ck_assert_int_eq(params->stop_us, 20); +} +END_TEST + +START_TEST(test_stop_total_short) +{ + PARSE_ARGS("osnoise", "top", "-S", "20"); + + ck_assert_int_eq(params->stop_total_us, 20); +} +END_TEST + +START_TEST(test_stop_total_long) +{ + PARSE_ARGS("osnoise", "top", "--stop-total", "20"); + + ck_assert_int_eq(params->stop_total_us, 20); +} +END_TEST + +START_TEST(test_threshold_short) +{ + PARSE_ARGS("osnoise", "top", "-T", "5"); + + ck_assert_int_eq(osn_params->threshold, 5); +} +END_TEST + +START_TEST(test_threshold_long) +{ + PARSE_ARGS("osnoise", "top", "--threshold", "5"); + + ck_assert_int_eq(osn_params->threshold, 5); +} +END_TEST + +START_TEST(test_trace_short_noarg) +{ + PARSE_ARGS("osnoise", "top", "-t"); + + CLI_ASSERT_SINGLE_ACTION(threshold_actions, ACTION_TRACE_OUTPUT, trace_output, str, + "osnoise_trace.txt"); +} +END_TEST + +START_TEST(test_trace_short_followarg) +{ + PARSE_ARGS("osnoise", "top", "-t", "-d", "20"); + + CLI_ASSERT_SINGLE_ACTION(threshold_actions, ACTION_TRACE_OUTPUT, trace_output, str, + "osnoise_trace.txt"); + ck_assert_int_eq(params->duration, 20); /* check if next argument is read correctly */ +} +END_TEST + +START_TEST(test_trace_short_space) +{ + PARSE_ARGS("osnoise", "top", "-t", "tracefile"); + + CLI_ASSERT_SINGLE_ACTION(threshold_actions, ACTION_TRACE_OUTPUT, trace_output, str, + "tracefile"); +} +END_TEST + +START_TEST(test_trace_short_equals) +{ + PARSE_ARGS("osnoise", "top", "-t=tracefile"); + + CLI_ASSERT_SINGLE_ACTION(threshold_actions, ACTION_TRACE_OUTPUT, trace_output, str, + "tracefile"); +} +END_TEST + +START_TEST(test_trace_long_noarg) +{ + PARSE_ARGS("osnoise", "top", "--trace"); + + CLI_ASSERT_SINGLE_ACTION(threshold_actions, ACTION_TRACE_OUTPUT, trace_output, str, + "osnoise_trace.txt"); +} +END_TEST + +START_TEST(test_trace_long_followarg) +{ + PARSE_ARGS("osnoise", "top", "--trace", "-d", "20"); + + CLI_ASSERT_SINGLE_ACTION(threshold_actions, ACTION_TRACE_OUTPUT, trace_output, str, + "osnoise_trace.txt"); + ck_assert_int_eq(params->duration, 20); /* check if next argument is read correctly */ +} +END_TEST + +START_TEST(test_trace_long_space) +{ + PARSE_ARGS("osnoise", "top", "--trace", "tracefile"); + + CLI_ASSERT_SINGLE_ACTION(threshold_actions, ACTION_TRACE_OUTPUT, trace_output, str, + "tracefile"); +} +END_TEST + +START_TEST(test_trace_long_equals) +{ + PARSE_ARGS("osnoise", "top", "--trace=tracefile"); + + CLI_ASSERT_SINGLE_ACTION(threshold_actions, ACTION_TRACE_OUTPUT, trace_output, str, + "tracefile"); +} +END_TEST + +/* Event Configuration */ + +START_TEST(test_event_short) +{ + PARSE_ARGS("osnoise", "top", "-e", "system:event"); + + CLI_ASSERT_SINGLE_EVENT("system", "event"); +} +END_TEST + +START_TEST(test_event_long) +{ + PARSE_ARGS("osnoise", "top", "--event", "system:event"); + + CLI_ASSERT_SINGLE_EVENT("system", "event"); +} +END_TEST + +START_TEST(test_filter) +{ + PARSE_ARGS("osnoise", "top", "-e", "system:event", "--filter", "filter"); + + CLI_ASSERT_SINGLE_FILTER("filter"); +} +END_TEST + +START_TEST(test_trigger) +{ + PARSE_ARGS("osnoise", "top", "-e", "system:event", "--trigger", "trigger"); + + CLI_ASSERT_SINGLE_TRIGGER("trigger"); +} +END_TEST + +/* CPU Configuration */ + +START_TEST(test_cpus_short) +{ + nr_cpus = 4; + + PARSE_ARGS("osnoise", "top", "-c", "0-1,3"); + + ck_assert_str_eq(params->cpus, "0-1,3"); + CLI_ASSERT_CPUSET(monitored_cpus, 0, 1, 3); +} +END_TEST + +START_TEST(test_cpus_long) +{ + nr_cpus = 4; + + PARSE_ARGS("osnoise", "top", "--cpus", "0-1,3"); + + ck_assert_str_eq(params->cpus, "0-1,3"); + CLI_ASSERT_CPUSET(monitored_cpus, 0, 1, 3); +} +END_TEST + +START_TEST(test_housekeeping_short) +{ + nr_cpus = 4; + + PARSE_ARGS("osnoise", "top", "-H", "0-1,3"); + + CLI_ASSERT_CPUSET(hk_cpu_set, 0, 1, 3); +} +END_TEST + +START_TEST(test_housekeeping_long) +{ + nr_cpus = 4; + + PARSE_ARGS("osnoise", "top", "--house-keeping", "0-1,3"); + + CLI_ASSERT_CPUSET(hk_cpu_set, 0, 1, 3); +} +END_TEST + +/* Thread Configuration */ + +START_TEST(test_cgroup_short_noarg) +{ + PARSE_ARGS("osnoise", "top", "-C"); + + ck_assert(params->cgroup); + ck_assert_ptr_null(params->cgroup_name); +} +END_TEST + +START_TEST(test_cgroup_short_space) +{ + PARSE_ARGS("osnoise", "top", "-C", "cgroup"); + + ck_assert(params->cgroup); + ck_assert_str_eq(params->cgroup_name, "cgroup"); +} +END_TEST + +START_TEST(test_cgroup_short_equals) +{ + PARSE_ARGS("osnoise", "top", "-C=cgroup"); + + ck_assert(params->cgroup); + ck_assert_str_eq(params->cgroup_name, "cgroup"); +} +END_TEST + +START_TEST(test_cgroup_long_noarg) +{ + PARSE_ARGS("osnoise", "top", "--cgroup"); + + ck_assert(params->cgroup); + ck_assert_ptr_null(params->cgroup_name); +} +END_TEST + +START_TEST(test_cgroup_long_space) +{ + PARSE_ARGS("osnoise", "top", "--cgroup", "cgroup"); + + ck_assert(params->cgroup); + ck_assert_str_eq(params->cgroup_name, "cgroup"); +} +END_TEST + +START_TEST(test_cgroup_long_equals) +{ + PARSE_ARGS("osnoise", "top", "--cgroup=cgroup"); + + ck_assert(params->cgroup); + ck_assert_str_eq(params->cgroup_name, "cgroup"); +} +END_TEST + +START_TEST(test_priority_short) +{ + PARSE_ARGS("osnoise", "top", "-P", "f:95"); + + ck_assert_int_eq(params->sched_param.sched_policy, SCHED_FIFO); + ck_assert_int_eq(params->sched_param.sched_priority, 95); +} +END_TEST + +START_TEST(test_priority_long) +{ + PARSE_ARGS("osnoise", "top", "--priority", "f:95"); + + ck_assert_int_eq(params->sched_param.sched_policy, SCHED_FIFO); + ck_assert_int_eq(params->sched_param.sched_priority, 95); +} +END_TEST + +/* Output */ + +START_TEST(test_quiet_short) +{ + PARSE_ARGS("osnoise", "top", "-q"); + + ck_assert(params->quiet); +} +END_TEST + +START_TEST(test_quiet_long) +{ + PARSE_ARGS("osnoise", "top", "--quiet"); + + ck_assert(params->quiet); +} +END_TEST + +/* Auto Analysis and Actions */ + +START_TEST(test_auto) +{ + PARSE_ARGS("osnoise", "top", "-a", "20"); + + CLI_OSNOISE_ASSERT_AUTO(20); +} +END_TEST + +START_TEST(test_on_end) +{ + PARSE_ARGS("osnoise", "top", "--on-end", "trace"); + + CLI_ASSERT_SINGLE_ACTION(end_actions, ACTION_TRACE_OUTPUT, trace_output, str, + "osnoise_trace.txt"); +} +END_TEST + +START_TEST(test_on_threshold) +{ + PARSE_ARGS("osnoise", "top", "--on-threshold", "trace"); + + CLI_ASSERT_SINGLE_ACTION(threshold_actions, ACTION_TRACE_OUTPUT, trace_output, str, + "osnoise_trace.txt"); +} +END_TEST + +/* System Tuning */ + +START_TEST(test_trace_buffer_size) +{ + PARSE_ARGS("osnoise", "top", "--trace-buffer-size", "200"); + + ck_assert_int_eq(params->buffer_size, 200); +} +END_TEST + +START_TEST(test_warm_up) +{ + PARSE_ARGS("osnoise", "top", "--warm-up", "5"); + + ck_assert_int_eq(params->warmup, 5); +} +END_TEST + +/* General */ + +START_TEST(test_debug_short) +{ + PARSE_ARGS("osnoise", "top", "-D"); + + ck_assert(config_debug); +} +END_TEST + +START_TEST(test_debug_long) +{ + PARSE_ARGS("osnoise", "top", "--debug"); + + ck_assert(config_debug); +} +END_TEST + +START_TEST(test_duration_short) +{ + PARSE_ARGS("osnoise", "top", "-d", "1m"); + + ck_assert_int_eq(params->duration, 60); +} +END_TEST + +START_TEST(test_duration_long) +{ + PARSE_ARGS("osnoise", "top", "--duration", "1m"); + + ck_assert_int_eq(params->duration, 60); +} +END_TEST + +Suite *osnoise_top_cli_suite(void) +{ + Suite *s = suite_create("osnoise_top_cli"); + TCase *tc; + + tc = tcase_create("tracing_options"); + tcase_add_test(tc, test_period_short); + tcase_add_test(tc, test_period_long); + tcase_add_test(tc, test_period_unset_short); + tcase_add_test(tc, test_period_unset_long); + tcase_add_test(tc, test_runtime_short); + tcase_add_test(tc, test_runtime_long); + tcase_add_test(tc, test_stop_short); + tcase_add_test(tc, test_stop_long); + tcase_add_test(tc, test_stop_total_short); + tcase_add_test(tc, test_stop_total_long); + tcase_add_test(tc, test_threshold_short); + tcase_add_test(tc, test_threshold_long); + tcase_add_test(tc, test_trace_short_noarg); + tcase_add_test(tc, test_trace_short_followarg); + tcase_add_test(tc, test_trace_short_space); + tcase_add_test(tc, test_trace_short_equals); + tcase_add_test(tc, test_trace_long_noarg); + tcase_add_test(tc, test_trace_long_followarg); + tcase_add_test(tc, test_trace_long_space); + tcase_add_test(tc, test_trace_long_equals); + suite_add_tcase(s, tc); + + tc = tcase_create("event_configuration"); + tcase_add_test(tc, test_event_short); + tcase_add_test(tc, test_event_long); + tcase_add_test(tc, test_filter); + tcase_add_test(tc, test_trigger); + suite_add_tcase(s, tc); + + tc = tcase_create("cpu_configuration"); + tcase_add_test(tc, test_cpus_short); + tcase_add_test(tc, test_cpus_long); + tcase_add_test(tc, test_housekeeping_short); + tcase_add_test(tc, test_housekeeping_long); + suite_add_tcase(s, tc); + + tc = tcase_create("thread_configuration"); + tcase_add_test(tc, test_cgroup_short_noarg); + tcase_add_test(tc, test_cgroup_short_space); + tcase_add_test(tc, test_cgroup_short_equals); + tcase_add_test(tc, test_cgroup_long_noarg); + tcase_add_test(tc, test_cgroup_long_space); + tcase_add_test(tc, test_cgroup_long_equals); + tcase_add_test(tc, test_priority_short); + tcase_add_test(tc, test_priority_long); + suite_add_tcase(s, tc); + + tc = tcase_create("output"); + tcase_add_test(tc, test_quiet_short); + tcase_add_test(tc, test_quiet_long); + suite_add_tcase(s, tc); + + tc = tcase_create("system_tuning"); + tcase_add_test(tc, test_trace_buffer_size); + tcase_add_test(tc, test_warm_up); + suite_add_tcase(s, tc); + + tc = tcase_create("aa_actions"); + tcase_add_test(tc, test_auto); + tcase_add_test(tc, test_on_end); + tcase_add_test(tc, test_on_threshold); + suite_add_tcase(s, tc); + + tc = tcase_create("general"); + tcase_add_test(tc, test_debug_short); + tcase_add_test(tc, test_debug_long); + tcase_add_test(tc, test_duration_short); + tcase_add_test(tc, test_duration_long); + suite_add_tcase(s, tc); + + return s; +} diff --git a/tools/tracing/rtla/tests/unit/timerlat_hist_cli.c b/tools/tracing/rtla/tests/unit/timerlat_hist_cli.c new file mode 100644 index 000000000..d8dd9d752 --- /dev/null +++ b/tools/tracing/rtla/tests/unit/timerlat_hist_cli.c @@ -0,0 +1,740 @@ +// SPDX-License-Identifier: GPL-2.0 + +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "cli_params_assert.h" +#include "../../src/cli.h" + +#define PARSE_ARGS(...) char *argv[] = { __VA_ARGS__, NULL };\ + int argc = sizeof(argv) / sizeof(char *) - 1;\ + struct common_params *params =\ + timerlat_hist_parse_args(argc, argv);\ + struct timerlat_params *tlat_params __maybe_unused =\ + to_timerlat_params(params) + +/* Tracing Options */ + +START_TEST(test_irq_short) +{ + PARSE_ARGS("timerlat", "hist", "-i", "20"); + + ck_assert_int_eq(params->stop_us, 20); +} +END_TEST + +START_TEST(test_irq_long) +{ + PARSE_ARGS("timerlat", "hist", "--irq", "20"); + + ck_assert_int_eq(params->stop_us, 20); +} +END_TEST + +START_TEST(test_period_short) +{ + PARSE_ARGS("timerlat", "hist", "-p", "200"); + + ck_assert_int_eq(tlat_params->timerlat_period_us, 200); +} +END_TEST + +START_TEST(test_period_long) +{ + PARSE_ARGS("timerlat", "hist", "--period", "200"); + + ck_assert_int_eq(tlat_params->timerlat_period_us, 200); +} +END_TEST + +START_TEST(test_period_unset_short) +{ + PARSE_ARGS("timerlat", "hist", "-p", "200", "--no-period"); + + ck_assert_int_eq(tlat_params->timerlat_period_us, 0); +} +END_TEST + +START_TEST(test_period_unset_long) +{ + PARSE_ARGS("timerlat", "hist", "--period", "200", "--no-period"); + + ck_assert_int_eq(tlat_params->timerlat_period_us, 0); +} +END_TEST + +START_TEST(test_stack_short) +{ + PARSE_ARGS("timerlat", "hist", "-s", "20"); + + ck_assert_int_eq(tlat_params->print_stack, 20); +} +END_TEST + +START_TEST(test_stack_long) +{ + PARSE_ARGS("timerlat", "hist", "--stack", "20"); + + ck_assert_int_eq(tlat_params->print_stack, 20); +} +END_TEST + +START_TEST(test_thread_short) +{ + PARSE_ARGS("timerlat", "hist", "-T", "20"); + + ck_assert_int_eq(params->stop_total_us, 20); +} +END_TEST + +START_TEST(test_thread_long) +{ + PARSE_ARGS("timerlat", "hist", "--thread", "20"); + + ck_assert_int_eq(params->stop_total_us, 20); +} +END_TEST + +START_TEST(test_trace_short_noarg) +{ + PARSE_ARGS("timerlat", "hist", "-t"); + + CLI_ASSERT_SINGLE_ACTION(threshold_actions, ACTION_TRACE_OUTPUT, trace_output, str, + "timerlat_trace.txt"); +} +END_TEST + +START_TEST(test_trace_short_followarg) +{ + PARSE_ARGS("timerlat", "hist", "-t", "-d", "20"); + + CLI_ASSERT_SINGLE_ACTION(threshold_actions, ACTION_TRACE_OUTPUT, trace_output, str, + "timerlat_trace.txt"); + ck_assert_int_eq(params->duration, 20); /* check if next argument is read correctly */ +} +END_TEST + +START_TEST(test_trace_short_space) +{ + PARSE_ARGS("timerlat", "hist", "-t", "tracefile"); + + CLI_ASSERT_SINGLE_ACTION(threshold_actions, ACTION_TRACE_OUTPUT, trace_output, str, + "tracefile"); +} +END_TEST + +START_TEST(test_trace_short_equals) +{ + PARSE_ARGS("timerlat", "hist", "-t=tracefile"); + + CLI_ASSERT_SINGLE_ACTION(threshold_actions, ACTION_TRACE_OUTPUT, trace_output, str, + "tracefile"); +} +END_TEST + +START_TEST(test_trace_long_noarg) +{ + PARSE_ARGS("timerlat", "hist", "--trace"); + + CLI_ASSERT_SINGLE_ACTION(threshold_actions, ACTION_TRACE_OUTPUT, trace_output, str, + "timerlat_trace.txt"); +} +END_TEST + +START_TEST(test_trace_long_followarg) +{ + PARSE_ARGS("timerlat", "hist", "--trace", "-d", "20"); + + CLI_ASSERT_SINGLE_ACTION(threshold_actions, ACTION_TRACE_OUTPUT, trace_output, str, + "timerlat_trace.txt"); + ck_assert_int_eq(params->duration, 20); /* check if next argument is read correctly */ +} +END_TEST + +START_TEST(test_trace_long_space) +{ + PARSE_ARGS("timerlat", "hist", "--trace", "tracefile"); + + CLI_ASSERT_SINGLE_ACTION(threshold_actions, ACTION_TRACE_OUTPUT, trace_output, str, + "tracefile"); +} +END_TEST + +START_TEST(test_trace_long_equals) +{ + PARSE_ARGS("timerlat", "hist", "--trace=tracefile"); + + CLI_ASSERT_SINGLE_ACTION(threshold_actions, ACTION_TRACE_OUTPUT, trace_output, str, + "tracefile"); +} +END_TEST + +/* Event Configuration */ + +START_TEST(test_event_short) +{ + PARSE_ARGS("timerlat", "hist", "-e", "system:event"); + + CLI_ASSERT_SINGLE_EVENT("system", "event"); +} +END_TEST + +START_TEST(test_event_long) +{ + PARSE_ARGS("timerlat", "hist", "--event", "system:event"); + + CLI_ASSERT_SINGLE_EVENT("system", "event"); +} +END_TEST + +START_TEST(test_filter) +{ + PARSE_ARGS("timerlat", "hist", "-e", "system:event", "--filter", "filter"); + + CLI_ASSERT_SINGLE_FILTER("filter"); +} +END_TEST + +START_TEST(test_trigger) +{ + PARSE_ARGS("timerlat", "hist", "-e", "system:event", "--trigger", "trigger"); + + CLI_ASSERT_SINGLE_TRIGGER("trigger"); +} +END_TEST + +/* CPU Configuration */ + +START_TEST(test_cpus_short) +{ + nr_cpus = 4; + + PARSE_ARGS("timerlat", "hist", "-c", "0-1,3"); + + ck_assert_str_eq(params->cpus, "0-1,3"); + CLI_ASSERT_CPUSET(monitored_cpus, 0, 1, 3); +} +END_TEST + +START_TEST(test_cpus_long) +{ + nr_cpus = 4; + + PARSE_ARGS("timerlat", "hist", "--cpus", "0-1,3"); + + ck_assert_str_eq(params->cpus, "0-1,3"); + CLI_ASSERT_CPUSET(monitored_cpus, 0, 1, 3); +} +END_TEST + +START_TEST(test_housekeeping_short) +{ + nr_cpus = 4; + + PARSE_ARGS("timerlat", "hist", "-H", "0-1,3"); + + CLI_ASSERT_CPUSET(hk_cpu_set, 0, 1, 3); +} +END_TEST + +START_TEST(test_housekeeping_long) +{ + nr_cpus = 4; + + PARSE_ARGS("timerlat", "hist", "--house-keeping", "0-1,3"); + + CLI_ASSERT_CPUSET(hk_cpu_set, 0, 1, 3); +} +END_TEST + +/* Thread Configuration */ + +START_TEST(test_cgroup_short_noarg) +{ + PARSE_ARGS("timerlat", "hist", "-C"); + + ck_assert(params->cgroup); + ck_assert_ptr_null(params->cgroup_name); +} +END_TEST + +START_TEST(test_cgroup_short_space) +{ + PARSE_ARGS("timerlat", "hist", "-C", "cgroup"); + + ck_assert(params->cgroup); + ck_assert_str_eq(params->cgroup_name, "cgroup"); +} +END_TEST + +START_TEST(test_cgroup_short_equals) +{ + PARSE_ARGS("timerlat", "hist", "-C=cgroup"); + + ck_assert(params->cgroup); + ck_assert_str_eq(params->cgroup_name, "cgroup"); +} +END_TEST + +START_TEST(test_cgroup_long_noarg) +{ + PARSE_ARGS("timerlat", "hist", "--cgroup"); + + ck_assert(params->cgroup); + ck_assert_ptr_null(params->cgroup_name); +} +END_TEST + +START_TEST(test_cgroup_long_space) +{ + PARSE_ARGS("timerlat", "hist", "--cgroup", "cgroup"); + + ck_assert(params->cgroup); + ck_assert_str_eq(params->cgroup_name, "cgroup"); +} +END_TEST + +START_TEST(test_cgroup_long_equals) +{ + PARSE_ARGS("timerlat", "hist", "--cgroup=cgroup"); + + ck_assert(params->cgroup); + ck_assert_str_eq(params->cgroup_name, "cgroup"); +} +END_TEST + +START_TEST(test_kernel_threads_short) +{ + PARSE_ARGS("timerlat", "hist", "-k"); + + ck_assert(params->kernel_workload); + ck_assert(!params->user_workload); + ck_assert(!params->user_data); +} +END_TEST + +START_TEST(test_kernel_threads_long) +{ + PARSE_ARGS("timerlat", "hist", "--kernel-threads"); + + ck_assert(params->kernel_workload); + ck_assert(!params->user_workload); + ck_assert(!params->user_data); +} +END_TEST + +START_TEST(test_priority_short) +{ + PARSE_ARGS("timerlat", "hist", "-P", "f:95"); + + ck_assert_int_eq(params->sched_param.sched_policy, SCHED_FIFO); + ck_assert_int_eq(params->sched_param.sched_priority, 95); +} +END_TEST + +START_TEST(test_priority_long) +{ + PARSE_ARGS("timerlat", "hist", "--priority", "f:95"); + + ck_assert_int_eq(params->sched_param.sched_policy, SCHED_FIFO); + ck_assert_int_eq(params->sched_param.sched_priority, 95); +} +END_TEST + +START_TEST(test_user_load_short) +{ + PARSE_ARGS("timerlat", "hist", "-U"); + + ck_assert(!params->kernel_workload); + ck_assert(!params->user_workload); + ck_assert(params->user_data); +} +END_TEST + +START_TEST(test_user_load_long) +{ + PARSE_ARGS("timerlat", "hist", "--user-load"); + + ck_assert(!params->kernel_workload); + ck_assert(!params->user_workload); + ck_assert(params->user_data); +} +END_TEST + +START_TEST(test_user_threads_short) +{ + PARSE_ARGS("timerlat", "hist", "-u"); + + ck_assert(!params->kernel_workload); + ck_assert(params->user_workload); + ck_assert(params->user_data); +} +END_TEST + +START_TEST(test_user_threads_long) +{ + PARSE_ARGS("timerlat", "hist", "--user-threads"); + + ck_assert(!params->kernel_workload); + ck_assert(params->user_workload); + ck_assert(params->user_data); +} +END_TEST + +START_TEST(test_aligned_short) +{ + PARSE_ARGS("timerlat", "hist", "-A", "500"); + + ck_assert(tlat_params->timerlat_align); + ck_assert_int_eq(tlat_params->timerlat_align_us, 500); +} +END_TEST + +START_TEST(test_aligned_long) +{ + PARSE_ARGS("timerlat", "hist", "--aligned", "500"); + + ck_assert(tlat_params->timerlat_align); + ck_assert_int_eq(tlat_params->timerlat_align_us, 500); +} +END_TEST + +/* Histogram Options */ + +START_TEST(test_bucket_size_short) +{ + PARSE_ARGS("timerlat", "hist", "-b", "2"); + + ck_assert_int_eq(params->hist.bucket_size, 2); +} +END_TEST + +START_TEST(test_bucket_size_long) +{ + PARSE_ARGS("timerlat", "hist", "--bucket-size", "2"); + + ck_assert_int_eq(params->hist.bucket_size, 2); +} +END_TEST + +START_TEST(test_entries_short) +{ + PARSE_ARGS("timerlat", "hist", "-E", "512"); + + ck_assert_int_eq(params->hist.entries, 512); +} +END_TEST + +START_TEST(test_entries_long) +{ + PARSE_ARGS("timerlat", "hist", "--entries", "512"); + + ck_assert_int_eq(params->hist.entries, 512); +} +END_TEST + +START_TEST(test_no_header) +{ + PARSE_ARGS("timerlat", "hist", "--no-header"); + + ck_assert(params->hist.no_header); +} +END_TEST + +START_TEST(test_no_index) +{ + PARSE_ARGS("timerlat", "hist", "--with-zeros", "--no-index"); + + ck_assert(params->hist.no_index); +} +END_TEST + +START_TEST(test_no_irq) +{ + PARSE_ARGS("timerlat", "hist", "--no-irq"); + + ck_assert(params->hist.no_irq); +} +END_TEST + +START_TEST(test_no_summary) +{ + PARSE_ARGS("timerlat", "hist", "--no-summary"); + + ck_assert(params->hist.no_summary); +} +END_TEST + +START_TEST(test_no_thread) +{ + PARSE_ARGS("timerlat", "hist", "--no-thread"); + + ck_assert(params->hist.no_thread); +} +END_TEST + +START_TEST(test_with_zeros) +{ + PARSE_ARGS("timerlat", "hist", "--with-zeros"); + + ck_assert(params->hist.with_zeros); +} +END_TEST + +/* Output */ + +START_TEST(test_nano_short) +{ + PARSE_ARGS("timerlat", "hist", "-n"); + + ck_assert_int_eq(params->output_divisor, 1); +} +END_TEST + +START_TEST(test_nano_long) +{ + PARSE_ARGS("timerlat", "hist", "--nano"); + + ck_assert_int_eq(params->output_divisor, 1); +} +END_TEST + +/* System Tuning */ + +START_TEST(test_deepest_idle_state) +{ + PARSE_ARGS("timerlat", "hist", "--deepest-idle-state", "1"); + + ck_assert_int_eq(tlat_params->deepest_idle_state, 1); +} +END_TEST + +START_TEST(test_dma_latency) +{ + PARSE_ARGS("timerlat", "hist", "--dma-latency", "10"); + + ck_assert_int_eq(tlat_params->dma_latency, 10); +} +END_TEST + +START_TEST(test_trace_buffer_size) +{ + PARSE_ARGS("timerlat", "hist", "--trace-buffer-size", "200"); + + ck_assert_int_eq(params->buffer_size, 200); +} +END_TEST + +START_TEST(test_warm_up) +{ + PARSE_ARGS("timerlat", "hist", "--warm-up", "5"); + + ck_assert_int_eq(params->warmup, 5); +} +END_TEST + +/* Auto Analysis and Actions */ + +START_TEST(test_auto) +{ + PARSE_ARGS("timerlat", "hist", "-a", "20"); + + CLI_TIMERLAT_ASSERT_AUTO(20); +} +END_TEST + +START_TEST(test_bpf_action) +{ + PARSE_ARGS("timerlat", "hist", "--bpf-action", "program"); + + ck_assert_str_eq(tlat_params->bpf_action_program, "program"); +} +END_TEST + +START_TEST(test_dump_tasks) +{ + PARSE_ARGS("timerlat", "hist", "--dump-tasks"); + + ck_assert(tlat_params->dump_tasks); +} +END_TEST + +START_TEST(test_no_aa) +{ + PARSE_ARGS("timerlat", "hist", "--no-aa"); + + ck_assert(tlat_params->no_aa); +} +END_TEST + +START_TEST(test_on_end) +{ + PARSE_ARGS("timerlat", "hist", "--on-end", "trace"); + + CLI_ASSERT_SINGLE_ACTION(end_actions, ACTION_TRACE_OUTPUT, trace_output, str, + "timerlat_trace.txt"); +} +END_TEST + +START_TEST(test_on_threshold) +{ + PARSE_ARGS("timerlat", "hist", "--on-threshold", "trace"); + + CLI_ASSERT_SINGLE_ACTION(threshold_actions, ACTION_TRACE_OUTPUT, trace_output, str, + "timerlat_trace.txt"); +} +END_TEST + +START_TEST(test_stack_format) +{ + PARSE_ARGS("timerlat", "hist", "--stack-format", "truncate"); + + ck_assert_int_eq(tlat_params->stack_format, STACK_FORMAT_TRUNCATE); +} +END_TEST + +/* General */ + +START_TEST(test_debug_short) +{ + PARSE_ARGS("timerlat", "hist", "-D"); + + ck_assert(config_debug); +} +END_TEST + +START_TEST(test_debug_long) +{ + PARSE_ARGS("timerlat", "hist", "--debug"); + + ck_assert(config_debug); +} +END_TEST + +START_TEST(test_duration_short) +{ + PARSE_ARGS("timerlat", "hist", "-d", "1m"); + + ck_assert_int_eq(params->duration, 60); +} +END_TEST + +START_TEST(test_duration_long) +{ + PARSE_ARGS("timerlat", "hist", "--duration", "1m"); + + ck_assert_int_eq(params->duration, 60); +} +END_TEST + +Suite *timerlat_hist_cli_suite(void) +{ + Suite *s = suite_create("timerlat_hist_cli"); + TCase *tc; + + tc = tcase_create("tracing_options"); + tcase_add_test(tc, test_irq_short); + tcase_add_test(tc, test_irq_long); + tcase_add_test(tc, test_period_short); + tcase_add_test(tc, test_period_long); + tcase_add_test(tc, test_period_unset_short); + tcase_add_test(tc, test_period_unset_long); + tcase_add_test(tc, test_stack_short); + tcase_add_test(tc, test_stack_long); + tcase_add_test(tc, test_thread_short); + tcase_add_test(tc, test_thread_long); + tcase_add_test(tc, test_trace_short_noarg); + tcase_add_test(tc, test_trace_short_followarg); + tcase_add_test(tc, test_trace_short_space); + tcase_add_test(tc, test_trace_short_equals); + tcase_add_test(tc, test_trace_long_noarg); + tcase_add_test(tc, test_trace_long_followarg); + tcase_add_test(tc, test_trace_long_space); + tcase_add_test(tc, test_trace_long_equals); + suite_add_tcase(s, tc); + + tc = tcase_create("event_configuration"); + tcase_add_test(tc, test_event_short); + tcase_add_test(tc, test_event_long); + tcase_add_test(tc, test_filter); + tcase_add_test(tc, test_trigger); + suite_add_tcase(s, tc); + + tc = tcase_create("cpu_configuration"); + tcase_add_test(tc, test_cpus_short); + tcase_add_test(tc, test_cpus_long); + tcase_add_test(tc, test_housekeeping_short); + tcase_add_test(tc, test_housekeeping_long); + suite_add_tcase(s, tc); + + tc = tcase_create("thread_configuration"); + tcase_add_test(tc, test_cgroup_short_noarg); + tcase_add_test(tc, test_cgroup_short_space); + tcase_add_test(tc, test_cgroup_short_equals); + tcase_add_test(tc, test_cgroup_long_noarg); + tcase_add_test(tc, test_cgroup_long_space); + tcase_add_test(tc, test_cgroup_long_equals); + tcase_add_test(tc, test_kernel_threads_short); + tcase_add_test(tc, test_kernel_threads_long); + tcase_add_test(tc, test_priority_short); + tcase_add_test(tc, test_priority_long); + tcase_add_test(tc, test_user_load_short); + tcase_add_test(tc, test_user_load_long); + tcase_add_test(tc, test_user_threads_short); + tcase_add_test(tc, test_user_threads_long); + tcase_add_test(tc, test_aligned_short); + tcase_add_test(tc, test_aligned_long); + suite_add_tcase(s, tc); + + tc = tcase_create("histogram_options"); + tcase_add_test(tc, test_bucket_size_short); + tcase_add_test(tc, test_bucket_size_long); + tcase_add_test(tc, test_entries_short); + tcase_add_test(tc, test_entries_long); + tcase_add_test(tc, test_no_header); + tcase_add_test(tc, test_no_index); + tcase_add_test(tc, test_no_irq); + tcase_add_test(tc, test_no_summary); + tcase_add_test(tc, test_no_thread); + tcase_add_test(tc, test_with_zeros); + suite_add_tcase(s, tc); + + tc = tcase_create("output"); + tcase_add_test(tc, test_nano_short); + tcase_add_test(tc, test_nano_long); + suite_add_tcase(s, tc); + + tc = tcase_create("system_tuning"); + tcase_add_test(tc, test_deepest_idle_state); + tcase_add_test(tc, test_dma_latency); + tcase_add_test(tc, test_trace_buffer_size); + tcase_add_test(tc, test_warm_up); + suite_add_tcase(s, tc); + + tc = tcase_create("aa_actions"); + tcase_add_test(tc, test_auto); + tcase_add_test(tc, test_bpf_action); + tcase_add_test(tc, test_dump_tasks); + tcase_add_test(tc, test_no_aa); + tcase_add_test(tc, test_on_end); + tcase_add_test(tc, test_on_threshold); + tcase_add_test(tc, test_stack_format); + suite_add_tcase(s, tc); + + tc = tcase_create("general"); + tcase_add_test(tc, test_debug_short); + tcase_add_test(tc, test_debug_long); + tcase_add_test(tc, test_duration_short); + tcase_add_test(tc, test_duration_long); + suite_add_tcase(s, tc); + + return s; +} diff --git a/tools/tracing/rtla/tests/unit/timerlat_top_cli.c b/tools/tracing/rtla/tests/unit/timerlat_top_cli.c new file mode 100644 index 000000000..e9fb1a86a --- /dev/null +++ b/tools/tracing/rtla/tests/unit/timerlat_top_cli.c @@ -0,0 +1,672 @@ +// SPDX-License-Identifier: GPL-2.0 + +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "cli_params_assert.h" +#include "../../src/cli.h" + +#define PARSE_ARGS(...) char *argv[] = { __VA_ARGS__, NULL };\ + int argc = sizeof(argv) / sizeof(char *) - 1;\ + struct common_params *params =\ + timerlat_top_parse_args(argc, argv);\ + struct timerlat_params *tlat_params __maybe_unused =\ + to_timerlat_params(params) + +/* Tracing Options */ + +START_TEST(test_irq_short) +{ + PARSE_ARGS("timerlat", "top", "-i", "20"); + + ck_assert_int_eq(params->stop_us, 20); +} +END_TEST + +START_TEST(test_irq_long) +{ + PARSE_ARGS("timerlat", "top", "--irq", "20"); + + ck_assert_int_eq(params->stop_us, 20); +} +END_TEST + +START_TEST(test_period_short) +{ + PARSE_ARGS("timerlat", "top", "-p", "200"); + + ck_assert_int_eq(tlat_params->timerlat_period_us, 200); +} +END_TEST + +START_TEST(test_period_long) +{ + PARSE_ARGS("timerlat", "top", "--period", "200"); + + ck_assert_int_eq(tlat_params->timerlat_period_us, 200); +} +END_TEST + +START_TEST(test_period_unset_short) +{ + PARSE_ARGS("timerlat", "top", "-p", "200", "--no-period"); + + ck_assert_int_eq(tlat_params->timerlat_period_us, 0); +} +END_TEST + +START_TEST(test_period_unset_long) +{ + PARSE_ARGS("timerlat", "top", "--period", "200", "--no-period"); + + ck_assert_int_eq(tlat_params->timerlat_period_us, 0); +} +END_TEST + +START_TEST(test_stack_short) +{ + PARSE_ARGS("timerlat", "top", "-s", "20"); + + ck_assert_int_eq(tlat_params->print_stack, 20); +} +END_TEST + +START_TEST(test_stack_long) +{ + PARSE_ARGS("timerlat", "top", "--stack", "20"); + + ck_assert_int_eq(tlat_params->print_stack, 20); +} +END_TEST + +START_TEST(test_thread_short) +{ + PARSE_ARGS("timerlat", "top", "-T", "20"); + + ck_assert_int_eq(params->stop_total_us, 20); +} +END_TEST + +START_TEST(test_thread_long) +{ + PARSE_ARGS("timerlat", "top", "--thread", "20"); + + ck_assert_int_eq(params->stop_total_us, 20); +} +END_TEST + +/* Event Configuration */ + +START_TEST(test_event_short) +{ + PARSE_ARGS("timerlat", "top", "-e", "system:event"); + + CLI_ASSERT_SINGLE_EVENT("system", "event"); +} +END_TEST + +START_TEST(test_event_long) +{ + PARSE_ARGS("timerlat", "top", "--event", "system:event"); + + CLI_ASSERT_SINGLE_EVENT("system", "event"); +} +END_TEST + +START_TEST(test_filter) +{ + PARSE_ARGS("timerlat", "top", "-e", "system:event", "--filter", "filter"); + + CLI_ASSERT_SINGLE_FILTER("filter"); +} +END_TEST + +START_TEST(test_trigger) +{ + PARSE_ARGS("timerlat", "top", "-e", "system:event", "--trigger", "trigger"); + + CLI_ASSERT_SINGLE_TRIGGER("trigger"); +} +END_TEST + +START_TEST(test_trace_short_noarg) +{ + PARSE_ARGS("timerlat", "top", "-t"); + + CLI_ASSERT_SINGLE_ACTION(threshold_actions, ACTION_TRACE_OUTPUT, trace_output, str, + "timerlat_trace.txt"); +} +END_TEST + +START_TEST(test_trace_short_followarg) +{ + PARSE_ARGS("timerlat", "top", "-t", "-d", "20"); + + CLI_ASSERT_SINGLE_ACTION(threshold_actions, ACTION_TRACE_OUTPUT, trace_output, str, + "timerlat_trace.txt"); + ck_assert_int_eq(params->duration, 20); /* check if next argument is read correctly */ +} +END_TEST + +START_TEST(test_trace_short_space) +{ + PARSE_ARGS("timerlat", "top", "-t", "tracefile"); + + CLI_ASSERT_SINGLE_ACTION(threshold_actions, ACTION_TRACE_OUTPUT, trace_output, str, + "tracefile"); +} +END_TEST + +START_TEST(test_trace_short_equals) +{ + PARSE_ARGS("timerlat", "top", "-t=tracefile"); + + CLI_ASSERT_SINGLE_ACTION(threshold_actions, ACTION_TRACE_OUTPUT, trace_output, str, + "tracefile"); +} +END_TEST + +START_TEST(test_trace_long_noarg) +{ + PARSE_ARGS("timerlat", "top", "--trace"); + + CLI_ASSERT_SINGLE_ACTION(threshold_actions, ACTION_TRACE_OUTPUT, trace_output, str, + "timerlat_trace.txt"); +} +END_TEST + +START_TEST(test_trace_long_followarg) +{ + PARSE_ARGS("timerlat", "top", "--trace", "-d", "20"); + + CLI_ASSERT_SINGLE_ACTION(threshold_actions, ACTION_TRACE_OUTPUT, trace_output, str, + "timerlat_trace.txt"); + ck_assert_int_eq(params->duration, 20); /* check if next argument is read correctly */ +} +END_TEST + +START_TEST(test_trace_long_space) +{ + PARSE_ARGS("timerlat", "top", "--trace", "tracefile"); + + CLI_ASSERT_SINGLE_ACTION(threshold_actions, ACTION_TRACE_OUTPUT, trace_output, str, + "tracefile"); +} +END_TEST + +START_TEST(test_trace_long_equals) +{ + PARSE_ARGS("timerlat", "top", "--trace=tracefile"); + + CLI_ASSERT_SINGLE_ACTION(threshold_actions, ACTION_TRACE_OUTPUT, trace_output, str, + "tracefile"); +} +END_TEST + +/* CPU Configuration */ + +START_TEST(test_cpus_short) +{ + nr_cpus = 4; + + PARSE_ARGS("timerlat", "top", "-c", "0-1,3"); + + ck_assert_str_eq(params->cpus, "0-1,3"); + CLI_ASSERT_CPUSET(monitored_cpus, 0, 1, 3); +} +END_TEST + +START_TEST(test_cpus_long) +{ + nr_cpus = 4; + + PARSE_ARGS("timerlat", "top", "--cpus", "0-1,3"); + + ck_assert_str_eq(params->cpus, "0-1,3"); + CLI_ASSERT_CPUSET(monitored_cpus, 0, 1, 3); +} +END_TEST + +START_TEST(test_housekeeping_short) +{ + nr_cpus = 4; + + PARSE_ARGS("timerlat", "top", "-H", "0-1,3"); + + CLI_ASSERT_CPUSET(hk_cpu_set, 0, 1, 3); +} +END_TEST + +START_TEST(test_housekeeping_long) +{ + nr_cpus = 4; + + PARSE_ARGS("timerlat", "top", "--house-keeping", "0-1,3"); + + CLI_ASSERT_CPUSET(hk_cpu_set, 0, 1, 3); +} +END_TEST + +/* Thread Configuration */ + +START_TEST(test_cgroup_short_noarg) +{ + PARSE_ARGS("timerlat", "top", "-C"); + + ck_assert(params->cgroup); + ck_assert_ptr_null(params->cgroup_name); +} +END_TEST + +START_TEST(test_cgroup_short_space) +{ + PARSE_ARGS("timerlat", "top", "-C", "cgroup"); + + ck_assert(params->cgroup); + ck_assert_str_eq(params->cgroup_name, "cgroup"); +} +END_TEST + +START_TEST(test_cgroup_short_equals) +{ + PARSE_ARGS("timerlat", "top", "-C=cgroup"); + + ck_assert(params->cgroup); + ck_assert_str_eq(params->cgroup_name, "cgroup"); +} +END_TEST + +START_TEST(test_cgroup_long_noarg) +{ + PARSE_ARGS("timerlat", "top", "--cgroup"); + + ck_assert(params->cgroup); + ck_assert_ptr_null(params->cgroup_name); +} +END_TEST + +START_TEST(test_cgroup_long_space) +{ + PARSE_ARGS("timerlat", "top", "--cgroup", "cgroup"); + + ck_assert(params->cgroup); + ck_assert_str_eq(params->cgroup_name, "cgroup"); +} +END_TEST + +START_TEST(test_cgroup_long_equals) +{ + PARSE_ARGS("timerlat", "top", "--cgroup=cgroup"); + + ck_assert(params->cgroup); + ck_assert_str_eq(params->cgroup_name, "cgroup"); +} +END_TEST + +START_TEST(test_kernel_threads_short) +{ + PARSE_ARGS("timerlat", "top", "-k"); + + ck_assert(params->kernel_workload); + ck_assert(!params->user_workload); + ck_assert(!params->user_data); +} +END_TEST + +START_TEST(test_kernel_threads_long) +{ + PARSE_ARGS("timerlat", "top", "--kernel-threads"); + + ck_assert(params->kernel_workload); + ck_assert(!params->user_workload); + ck_assert(!params->user_data); +} +END_TEST + +START_TEST(test_priority_short) +{ + PARSE_ARGS("timerlat", "top", "-P", "f:95"); + + ck_assert_int_eq(params->sched_param.sched_policy, SCHED_FIFO); + ck_assert_int_eq(params->sched_param.sched_priority, 95); +} +END_TEST + +START_TEST(test_priority_long) +{ + PARSE_ARGS("timerlat", "top", "--priority", "f:95"); + + ck_assert_int_eq(params->sched_param.sched_policy, SCHED_FIFO); + ck_assert_int_eq(params->sched_param.sched_priority, 95); +} +END_TEST + +START_TEST(test_user_load_short) +{ + PARSE_ARGS("timerlat", "top", "-U"); + + ck_assert(!params->kernel_workload); + ck_assert(!params->user_workload); + ck_assert(params->user_data); +} +END_TEST + +START_TEST(test_user_load_long) +{ + PARSE_ARGS("timerlat", "top", "--user-load"); + + ck_assert(!params->kernel_workload); + ck_assert(!params->user_workload); + ck_assert(params->user_data); +} +END_TEST + +START_TEST(test_user_threads_short) +{ + PARSE_ARGS("timerlat", "top", "-u"); + + ck_assert(!params->kernel_workload); + ck_assert(params->user_workload); + ck_assert(params->user_data); +} +END_TEST + +START_TEST(test_user_threads_long) +{ + PARSE_ARGS("timerlat", "top", "--user-threads"); + + ck_assert(!params->kernel_workload); + ck_assert(params->user_workload); + ck_assert(params->user_data); +} +END_TEST + +START_TEST(test_aligned_short) +{ + PARSE_ARGS("timerlat", "top", "-A", "500"); + + ck_assert(tlat_params->timerlat_align); + ck_assert_int_eq(tlat_params->timerlat_align_us, 500); +} +END_TEST + +START_TEST(test_aligned_long) +{ + PARSE_ARGS("timerlat", "top", "--aligned", "500"); + + ck_assert(tlat_params->timerlat_align); + ck_assert_int_eq(tlat_params->timerlat_align_us, 500); +} +END_TEST + +/* Output */ + +START_TEST(test_nano_short) +{ + PARSE_ARGS("timerlat", "top", "-n"); + + ck_assert_int_eq(params->output_divisor, 1); +} +END_TEST + +START_TEST(test_nano_long) +{ + PARSE_ARGS("timerlat", "top", "--nano"); + + ck_assert_int_eq(params->output_divisor, 1); +} +END_TEST + +START_TEST(test_quiet_short) +{ + PARSE_ARGS("timerlat", "top", "-q"); + + ck_assert(params->quiet); +} +END_TEST + +START_TEST(test_quiet_long) +{ + PARSE_ARGS("timerlat", "top", "--quiet"); + + ck_assert(params->quiet); +} +END_TEST + +/* System Tuning */ + +START_TEST(test_deepest_idle_state) +{ + PARSE_ARGS("timerlat", "top", "--deepest-idle-state", "1"); + + ck_assert_int_eq(tlat_params->deepest_idle_state, 1); +} +END_TEST + +START_TEST(test_dma_latency) +{ + PARSE_ARGS("timerlat", "top", "--dma-latency", "10"); + + ck_assert_int_eq(tlat_params->dma_latency, 10); +} +END_TEST + +START_TEST(test_trace_buffer_size) +{ + PARSE_ARGS("timerlat", "top", "--trace-buffer-size", "200"); + + ck_assert_int_eq(params->buffer_size, 200); +} +END_TEST + +START_TEST(test_warm_up) +{ + PARSE_ARGS("timerlat", "top", "--warm-up", "5"); + + ck_assert_int_eq(params->warmup, 5); +} +END_TEST + +/* Auto Analysis and Actions */ + +START_TEST(test_auto) +{ + PARSE_ARGS("timerlat", "top", "-a", "20"); + + CLI_TIMERLAT_ASSERT_AUTO(20); +} +END_TEST + +START_TEST(test_aa_only) +{ + PARSE_ARGS("timerlat", "top", "--aa-only", "20"); + + CLI_TIMERLAT_ASSERT_AA_ONLY(20); +} +END_TEST + +START_TEST(test_bpf_action) +{ + PARSE_ARGS("timerlat", "top", "--bpf-action", "program"); + + ck_assert_str_eq(tlat_params->bpf_action_program, "program"); +} +END_TEST + +START_TEST(test_dump_tasks) +{ + PARSE_ARGS("timerlat", "top", "--dump-tasks"); + + ck_assert(tlat_params->dump_tasks); +} +END_TEST + +START_TEST(test_no_aa) +{ + PARSE_ARGS("timerlat", "top", "--no-aa"); + + ck_assert(tlat_params->no_aa); +} +END_TEST + +START_TEST(test_on_end) +{ + PARSE_ARGS("timerlat", "top", "--on-end", "trace"); + + CLI_ASSERT_SINGLE_ACTION(end_actions, ACTION_TRACE_OUTPUT, trace_output, str, + "timerlat_trace.txt"); +} +END_TEST + +START_TEST(test_on_threshold) +{ + PARSE_ARGS("timerlat", "top", "--on-threshold", "trace"); + + CLI_ASSERT_SINGLE_ACTION(threshold_actions, ACTION_TRACE_OUTPUT, trace_output, str, + "timerlat_trace.txt"); +} +END_TEST + +START_TEST(test_stack_format) +{ + PARSE_ARGS("timerlat", "top", "--stack-format", "truncate"); + + ck_assert_int_eq(tlat_params->stack_format, STACK_FORMAT_TRUNCATE); +} +END_TEST + +/* General */ + +START_TEST(test_debug_short) +{ + PARSE_ARGS("timerlat", "top", "-D"); + + ck_assert(config_debug); +} +END_TEST + +START_TEST(test_debug_long) +{ + PARSE_ARGS("timerlat", "top", "--debug"); + + ck_assert(config_debug); +} +END_TEST + +START_TEST(test_duration_short) +{ + PARSE_ARGS("timerlat", "top", "-d", "1m"); + + ck_assert_int_eq(params->duration, 60); +} +END_TEST + +START_TEST(test_duration_long) +{ + PARSE_ARGS("timerlat", "top", "--duration", "1m"); + + ck_assert_int_eq(params->duration, 60); +} +END_TEST + +Suite *timerlat_top_cli_suite(void) +{ + Suite *s = suite_create("timerlat_top_cli"); + TCase *tc; + + tc = tcase_create("tracing_options"); + tcase_add_test(tc, test_irq_short); + tcase_add_test(tc, test_irq_long); + tcase_add_test(tc, test_period_short); + tcase_add_test(tc, test_period_long); + tcase_add_test(tc, test_period_unset_short); + tcase_add_test(tc, test_period_unset_long); + tcase_add_test(tc, test_stack_short); + tcase_add_test(tc, test_stack_long); + tcase_add_test(tc, test_thread_short); + tcase_add_test(tc, test_thread_long); + tcase_add_test(tc, test_trace_short_noarg); + tcase_add_test(tc, test_trace_short_followarg); + tcase_add_test(tc, test_trace_short_space); + tcase_add_test(tc, test_trace_short_equals); + tcase_add_test(tc, test_trace_long_noarg); + tcase_add_test(tc, test_trace_long_followarg); + tcase_add_test(tc, test_trace_long_space); + tcase_add_test(tc, test_trace_long_equals); + suite_add_tcase(s, tc); + + tc = tcase_create("event_configuration"); + tcase_add_test(tc, test_event_short); + tcase_add_test(tc, test_event_long); + tcase_add_test(tc, test_filter); + tcase_add_test(tc, test_trigger); + suite_add_tcase(s, tc); + + tc = tcase_create("cpu_configuration"); + tcase_add_test(tc, test_cpus_short); + tcase_add_test(tc, test_cpus_long); + tcase_add_test(tc, test_housekeeping_short); + tcase_add_test(tc, test_housekeeping_long); + suite_add_tcase(s, tc); + + tc = tcase_create("thread_configuration"); + tcase_add_test(tc, test_cgroup_short_noarg); + tcase_add_test(tc, test_cgroup_short_space); + tcase_add_test(tc, test_cgroup_short_equals); + tcase_add_test(tc, test_cgroup_long_noarg); + tcase_add_test(tc, test_cgroup_long_space); + tcase_add_test(tc, test_cgroup_long_equals); + tcase_add_test(tc, test_kernel_threads_short); + tcase_add_test(tc, test_kernel_threads_long); + tcase_add_test(tc, test_priority_short); + tcase_add_test(tc, test_priority_long); + tcase_add_test(tc, test_user_load_short); + tcase_add_test(tc, test_user_load_long); + tcase_add_test(tc, test_user_threads_short); + tcase_add_test(tc, test_user_threads_long); + tcase_add_test(tc, test_aligned_short); + tcase_add_test(tc, test_aligned_long); + suite_add_tcase(s, tc); + + tc = tcase_create("output"); + tcase_add_test(tc, test_nano_short); + tcase_add_test(tc, test_nano_long); + tcase_add_test(tc, test_quiet_short); + tcase_add_test(tc, test_quiet_long); + suite_add_tcase(s, tc); + + tc = tcase_create("system_tuning"); + tcase_add_test(tc, test_deepest_idle_state); + tcase_add_test(tc, test_dma_latency); + tcase_add_test(tc, test_trace_buffer_size); + tcase_add_test(tc, test_warm_up); + suite_add_tcase(s, tc); + + tc = tcase_create("aa_actions"); + tcase_add_test(tc, test_auto); + tcase_add_test(tc, test_aa_only); + tcase_add_test(tc, test_bpf_action); + tcase_add_test(tc, test_dump_tasks); + tcase_add_test(tc, test_no_aa); + tcase_add_test(tc, test_on_end); + tcase_add_test(tc, test_on_threshold); + tcase_add_test(tc, test_stack_format); + suite_add_tcase(s, tc); + + tc = tcase_create("general"); + tcase_add_test(tc, test_debug_short); + tcase_add_test(tc, test_debug_long); + tcase_add_test(tc, test_duration_short); + tcase_add_test(tc, test_duration_long); + suite_add_tcase(s, tc); + + return s; +} diff --git a/tools/tracing/rtla/tests/unit/unit_tests.c b/tools/tracing/rtla/tests/unit/unit_tests.c new file mode 100644 index 000000000..75ca813f8 --- /dev/null +++ b/tools/tracing/rtla/tests/unit/unit_tests.c @@ -0,0 +1,39 @@ +// SPDX-License-Identifier: GPL-2.0 + +#define _GNU_SOURCE +#include +#include + +#include "../../src/utils.h" +#include "../../src/cli.h" + +Suite *utils_suite(void); +Suite *actions_suite(void); +Suite *osnoise_top_cli_suite(void); +Suite *osnoise_hist_cli_suite(void); +Suite *timerlat_top_cli_suite(void); +Suite *timerlat_hist_cli_suite(void); +Suite *cli_opt_callback_suite(void); + +int main(int argc, char *argv[]) +{ + int num_failed; + SRunner *sr; + + in_unit_test = true; + + sr = srunner_create(utils_suite()); + srunner_add_suite(sr, cli_opt_callback_suite()); + srunner_add_suite(sr, actions_suite()); + srunner_add_suite(sr, osnoise_top_cli_suite()); + srunner_add_suite(sr, osnoise_hist_cli_suite()); + srunner_add_suite(sr, timerlat_top_cli_suite()); + srunner_add_suite(sr, timerlat_hist_cli_suite()); + + srunner_run_all(sr, CK_VERBOSE); + num_failed = srunner_ntests_failed(sr); + + srunner_free(sr); + + return (num_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE; +} diff --git a/tools/tracing/rtla/tests/unit/utils.c b/tools/tracing/rtla/tests/unit/utils.c new file mode 100644 index 000000000..ce53cab49 --- /dev/null +++ b/tools/tracing/rtla/tests/unit/utils.c @@ -0,0 +1,106 @@ +// SPDX-License-Identifier: GPL-2.0 + +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include + +#include "../../src/utils.h" + +extern int nr_cpus; + +START_TEST(test_strtoi) +{ + int result; + char buf[64]; + + ck_assert_int_eq(strtoi("123", &result), 0); + ck_assert_int_eq(result, 123); + ck_assert_int_eq(strtoi(" -456", &result), 0); + ck_assert_int_eq(result, -456); + + snprintf(buf, sizeof(buf), "%d", INT_MAX); + ck_assert_int_eq(strtoi(buf, &result), 0); + snprintf(buf, sizeof(buf), "%ld", (long)INT_MAX + 1); + ck_assert_int_eq(strtoi(buf, &result), -1); + + ck_assert_int_eq(strtoi("", &result), -1); + ck_assert_int_eq(strtoi("123abc", &result), -1); + ck_assert_int_eq(strtoi("123 ", &result), -1); +} +END_TEST + +START_TEST(test_parse_cpu_set) +{ + cpu_set_t set; + + nr_cpus = 8; + ck_assert_int_eq(parse_cpu_set("0", &set), 0); + ck_assert(CPU_ISSET(0, &set)); + ck_assert(!CPU_ISSET(1, &set)); + + ck_assert_int_eq(parse_cpu_set("0,2", &set), 0); + ck_assert(CPU_ISSET(0, &set)); + ck_assert(CPU_ISSET(2, &set)); + + ck_assert_int_eq(parse_cpu_set("0-3", &set), 0); + ck_assert(CPU_ISSET(0, &set)); + ck_assert(CPU_ISSET(1, &set)); + ck_assert(CPU_ISSET(2, &set)); + ck_assert(CPU_ISSET(3, &set)); + + ck_assert_int_eq(parse_cpu_set("1-3,5", &set), 0); + ck_assert(!CPU_ISSET(0, &set)); + ck_assert(CPU_ISSET(1, &set)); + ck_assert(CPU_ISSET(2, &set)); + ck_assert(CPU_ISSET(3, &set)); + ck_assert(!CPU_ISSET(4, &set)); + ck_assert(CPU_ISSET(5, &set)); + + ck_assert_int_eq(parse_cpu_set("-1", &set), 1); + ck_assert_int_eq(parse_cpu_set("abc", &set), 1); + ck_assert_int_eq(parse_cpu_set("9999", &set), 1); +} +END_TEST + +START_TEST(test_parse_prio) +{ + struct sched_attr attr; + + ck_assert_int_eq(parse_prio("f:50", &attr), 0); + ck_assert_uint_eq(attr.sched_policy, SCHED_FIFO); + ck_assert_uint_eq(attr.sched_priority, 50U); + + ck_assert_int_eq(parse_prio("r:30", &attr), 0); + ck_assert_uint_eq(attr.sched_policy, SCHED_RR); + + ck_assert_int_eq(parse_prio("o:0", &attr), 0); + ck_assert_uint_eq(attr.sched_policy, SCHED_OTHER); + ck_assert_int_eq(attr.sched_nice, 0); + + ck_assert_int_eq(parse_prio("d:10ms:100ms", &attr), 0); + ck_assert_uint_eq(attr.sched_policy, 6U); + + ck_assert_int_eq(parse_prio("f:999", &attr), -1); + ck_assert_int_eq(parse_prio("o:-20", &attr), -1); + ck_assert_int_eq(parse_prio("d:100ms:10ms", &attr), -1); + ck_assert_int_eq(parse_prio("x:50", &attr), -1); +} +END_TEST + +Suite *utils_suite(void) +{ + Suite *s = suite_create("utils"); + TCase *tc = tcase_create("core"); + + tcase_add_test(tc, test_strtoi); + tcase_add_test(tc, test_parse_cpu_set); + tcase_add_test(tc, test_parse_prio); + + suite_add_tcase(s, tc); + return s; +} -- cgit v1.3.1