Skip to content

Commit 07fcb34

Browse files
committed
runtests_flaky: Add parallel execution script for runtests
This is useful to detect flaky tests or race conditions.
1 parent 3cc75a0 commit 07fcb34

1 file changed

Lines changed: 135 additions & 0 deletions

File tree

‎scripts/runtests_flaky‎

Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
#! /bin/bash
2+
3+
# Copyright 2026 Hannes Diethelm <hannes.diethelm@gmail.com>
4+
#
5+
# This program is free software; you can redistribute it and/or
6+
# modify it under the terms of version 2 of the GNU General
7+
# Public License as published by the Free Software Foundation.
8+
# This library is distributed in the hope that it will be useful,
9+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+
# GNU General Public License for more details.
12+
#
13+
# You should have received a copy of the GNU General Public
14+
# License along with this library; if not, write to the Free Software
15+
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
16+
17+
set -o pipefail
18+
19+
usage () {
20+
P=${0##*/}
21+
cat <<EOF
22+
$P: Run HAL test suite runs in parallel to detect flaky tests or race conditions
23+
24+
Notes:
25+
Start with a low number for -j and -p to not run out of memory or
26+
trigger timeouts in the tests due to heavy load.
27+
The defaults, which should run well on a quad core are:
28+
$P -r4 -j16 -p2 -c0 -s16 -otestout
29+
30+
Usage:
31+
$P -r runs
32+
Total runs of runtests
33+
34+
$P -j jobs
35+
Jobs of runtests
36+
37+
$P -p parallel_jobs
38+
Parallel runtests
39+
40+
$P -c cpus_per_job
41+
If this cpus_per_job > 0, each runtests run gets cpus_per_job assigned
42+
using taskset. cpus_per_job*parallel_jobs <= nproc
43+
44+
$P -s sleep_max
45+
Random sleep up to sleep_max before starting runtests
46+
47+
$P -o testout_dir
48+
Testresults will be stored in testout_dir/$JOB_ID
49+
50+
Examples:
51+
$P -r128 -j32 -p8 -c4 -s0 2>/dev/null
52+
Good for a 16 core CPU with hyper-threading
53+
128 testruns
54+
Running 8x parallel each using 32 parallel jobs
55+
Each 32x parallel runtests run has 4 CPU's assigned
56+
No sleep between start
57+
2>/dev/null: Run messages are not shown, only failures and summary
58+
$P -r128 -j32 -p8 -s15 2>/dev/null
59+
Good for a 16 core CPU with hyper-threading
60+
128 testruns
61+
Running 8x parallel each using 32 parallel jobs
62+
No cpu assignment
63+
0...15s random sleep to randomize spread the highest load part
64+
at startup
65+
2>/dev/null: Run messages are not shown, only failures and summary
66+
EOF
67+
}
68+
69+
#Default: Should run on a quad core
70+
RUNS=4
71+
RUNTEST_JOBS=16
72+
PARALLEL_JOBS=2
73+
CPUS_PER_JOB=0
74+
SLEEP_MAX=16
75+
TESTOUT_DIR=testout
76+
while getopts r:j:p:c:s:o:h opt; do
77+
case "$opt" in
78+
r) RUNS="$OPTARG" ;;
79+
j) RUNTEST_JOBS="$OPTARG" ;;
80+
p) PARALLEL_JOBS="$OPTARG" ;;
81+
c) CPUS_PER_JOB="$OPTARG" ;;
82+
s) SLEEP_MAX="$OPTARG" ;;
83+
o) TESTOUT_DIR="$OPTARG" ;;
84+
h|?) usage; exit 0 ;;
85+
*) usage; exit 1 ;;
86+
esac
87+
done
88+
shift $((OPTIND-1))
89+
90+
if [ $((CPUS_PER_JOB*PARALLEL_JOBS)) -gt "$(nproc --all)" ]; then
91+
echo "ERROR: cpus_per_job*parallel_jobs <= nproc but is $((CPUS_PER_JOB*PARALLEL_JOBS)) > $(nproc)"
92+
exit 1
93+
fi
94+
95+
#Convert to full path before changing directory
96+
TESTOUT_DIR=$(realpath -s "$TESTOUT_DIR")
97+
98+
run_job(){
99+
local JOB_ID=$1
100+
local JOB_SLOT=$2
101+
local RUNTEST_JOBS=$3
102+
local CPUS_PER_JOB=$4
103+
local SLEEP_MAX=$5
104+
local TESTOUT_DIR=$6
105+
106+
local SLEEP=0
107+
if [ "$SLEEP_MAX" -gt 0 ]; then
108+
SLEEP=$(shuf -i "0-$SLEEP_MAX" -n 1)
109+
fi
110+
111+
if [ "$CPUS_PER_JOB" -gt 0 ]; then
112+
RT_CPU_ID=$((CPUS_PER_JOB*(JOB_SLOT-1)))
113+
CPU_RANGE=$((CPUS_PER_JOB*(JOB_SLOT-1)))-$((CPUS_PER_JOB*JOB_SLOT-1))
114+
echo "Running $JOB_ID sleep $SLEEP RTAI_CPU_NUMBER $RT_CPU_ID taskset $CPU_RANGE"
115+
sleep "$SLEEP"
116+
export RTAPI_CPU_NUMBER=$RT_CPU_ID
117+
taskset -c $CPU_RANGE scripts/runtests -n -o "$TESTOUT_DIR/$JOB_ID" -p -j "$RUNTEST_JOBS"
118+
else
119+
echo "Running $JOB_ID sleep $SLEEP"
120+
sleep "$SLEEP"
121+
unset RTAPI_CPU_NUMBER
122+
scripts/runtests -n -o "$TESTOUT_DIR/$JOB_ID" -p -j "$RUNTEST_JOBS"
123+
fi
124+
}
125+
126+
export -f run_job
127+
128+
#Start from top directory
129+
cd "$(dirname "$0")/.." || { echo "Could not change directory to '$(dirname "$0")/..'"; exit 1; }
130+
seq "$RUNS" | parallel -j "$PARALLEL_JOBS" "run_job {} {%} $RUNTEST_JOBS $CPUS_PER_JOB $SLEEP_MAX $TESTOUT_DIR"
131+
exitcode=$?
132+
if [ "$exitcode" -ne 0 ]; then
133+
echo "Failed with $exitcode"
134+
exit "$exitcode"
135+
fi

0 commit comments

Comments
 (0)