Jon Turney via Cygwin-apps wrote:
On 15/09/2024 16:11, Jon Turney via Cygwin-apps wrote:
On 13/09/2024 18:33, Christian Franke via Cygwin-apps wrote:
I would like to contribute stress-ng. Also present in Debian,
Fedora, FreeBSD, Ubuntu, ...
I was thinking about adding a step to our CI to run stress-ng, as it
seems quite good at finding some kinds of regressions.
I wonder if you could suggest a suitable set of options to invoke it
with?
Attached is an enhanced version of my local script used to test
stress-ng before packaging. I agree that it should provide some more
comments :-)
Try
./cygstress -n CI
to see a selection of tests for CI. Remove -n to run these (~ 5min). It
would also be possible to run the tests with a single stress-ng command.
The tests which detected Cygwin bugs that are already fixed are
included, see comments "fixed in Cygwin ...".
Use WORK (or FAIL) instead of CI to run all working (or failing) tests.
See comments "TODO Cygwin: ..." for brief info about the failures. See
three links for testcases posted to ML.
Tests are intentionally run separately because failing tests sometimes
hang and may even ignore SIGKILL. Therefore an external tool is used,
pskill from Sysinternals Suite is the default.
--
Regards,
Christian
#!/bin/bash
#
# Run stress-ng on Cygwin
#
# Copyright 2025 Christian Franke
#
# SPDX-License-Identifier: BSD-3-Clause
#
set -e -o pipefail
usage()
{
cat <<EOF
Usage: ${0##*/} [OPTION...] {CI|WORK|FAIL|test...}
-n print commands only (dry-run)
-f force execution of tests tagged 'heavy' or 'admin'
-c LIST set CPU affinity to LIST
-k PATH tool to stop hanging tests [default: pskill]
-s PATH stress-ng executable [default: stress-ng]
-t N run each test for at least N seconds [default: 5]
-w N start N workers for each test [default: 2]
CI run all tests tagged CI
WORK run all tests tagged WORKS
FAIL run all tests tagged FAILS
test... run invidual test(s) (may require '-f')
EOF
exit 1
}
# Tags:
# WORKS: works on Cygwin (3.7.0-0.43.g779e46b5b3ee)
# WORKS,CI: possibly suitable subset for Cygwin CI test.
# FAILS: fails on Cygwin, see "TODO Cygwin" for details.
# heavy: heavy resource usage, may work, hang, freeze desktop, require reset,
...
# admin: requires administrator, may work or not, may be 'heavy' or not.
# -----: unsupported due to missing API, library, declaration, ...
stress_tests='
# TEST [ARGS] # Tag # Comment
access # FAILS # TODO undecided: "access 004 on chmod mode 400
failed: 13 (Permission denied)"
acl # WORKS,CI # (fixed in stress-ng 0.18.12)
affinity # WORKS
af-alg # ----- # requires AF_ALG
aio # WORKS
aiol # ----- # requires io_setup(2), io_submit(2), ...
alarm # WORKS,CI
apparmor # -----
atomic # WORKS
bad-altstack # WORKS
bad-ioctl # -----
besselmath # WORKS
bigheap # heavy
binderfs # -----
bind-mount # -----
bitonicsort # WORKS
bitops # WORKS
branch # WORKS
brk # heavy # allocates memory until OOM
bsearch # WORKS
bubblesort # WORKS
cache # WORKS
cacheline # WORKS
cachehammer # WORKS
cap # -----
cgroup # -----
chattr # -----
chdir # WORKS,CI
chmod # WORKS,CI
chown # FAILS # TODO undecided: "fchown failed, errno=22 (Invalid
argument)"
chroot # admin
clock # WORKS,CI # (fixed in stress-ng 0.18.12: "timer_create failed
for timer ...
# ... ''CLOCK_THREAD_CPUTIME_ID'', errno=134")
clone # -----
close # FAILS # TODO Cygwin: close(2) is not thread-safe
context # WORKS,CI # (fixed in Cygwin 3.6.0: signals lost after
swapcontext)
copy-file # -----
cpu # WORKS
cpu-online # -----
cpu-sched # FAILS # TODO undecided: "child died: signal 9 ''SIGKILL''"
# (fixed in Cygwin 3.6.0: signals lost after
SIGSTOP)
crypt # WORKS # uses libcrypt
cyclic # admin
daemon # WORKS
dccp # -----
dekker # WORKS
dentry # WORKS
dev # FAILS # TODO Cygwin: "*** fatal error in forked process -
pthread_mutex::_fixup_after_fork () ...
# ... doesn''t understand PROCESS_SHARED mutex''s"
dev-shm # -----
dfp # WORKS
dir # WORKS
dirdeep # heavy # creates deep dir tree
dirmany # heavy # creates many dirs/files
dnotify # -----
dup # WORKS,CI
dynlib # -----
easy-opcode # WORKS
eigen # WORKS
efivar # -----
enosys # -----
env # heavy # creates very large environment until OOM
epoll # -----
eventfd # -----
exec # WORKS,CI
exit-group # -----
expmath # WORKS
factor # WORKS # uses libgmp
fallocate # WORKS,CI
fanotify # -----
far-branch # WORKS
fault # WORKS
fcntl # FAILS # TODO Cygwin: "ftruncate failed, errno=21 (Is a
directory)", please see:
#
https://sourceware.org/pipermail/cygwin/2025-April/257871.html
fd-fork # WORKS,CI
fd-race # ----- # TODO stress-ng: drop Linux restriction (but then
it FAILS)
fibsearch # WORKS
fiemap # -----
fifo # WORKS
file-ioctl # WORKS,CI
filename # FAILS # TODO Cygwin: creates files Cygwin cannot remove
later, please see:
#
https://sourceware.org/pipermail/cygwin/2024-September/256451.html
filename --filename-opts posix # WORKS,CI # restricts filenames to POSIX
charset
# filerace # WORKS # TODO this script: add in stress-ng >0.18.12
flipflop # WORKS
flock # WORKS,CI
flushcache # WORKS
fma # WORKS
fork # WORKS,CI
forkheavy # heavy # forks until process table is full
fp # WORKS,CI
fp-error # WORKS,CI
fpunch # FAILS # TODO this script: fixed in stress-ng >0.18.12
fractal # WORKS
fsize # heavy # creates large files until disk is full
fstat # WORKS,CI
full # ----- # requires pread/pwrite() working on /dev/full
funccall # WORKS
funcret # WORKS
futex # -----
get # WORKS
getdent # -----
getrandom # -----
goto # WORKS
gpu # -----
handle # ----- # requires name/open_by_handle_at(2)
hash # WORKS
hdd # WORKS
heapsort # WORKS # uses libbsd
hrtimers # WORKS,CI # (fixed in Cygwin 3.5.7: "timer_delete failed")
hsearch # WORKS
hyperbolic # WORKS
icache # WORKS
icmp-flood # ----- # requires "struct icmphdr", ... in <netinet/*.h>
idle-page # ----- # requires /sys/kernel/mm/page_idle/bitmap
inode-flags # -----
inotify # ----- # requires inotify_*(2)
insertionsort # WORKS
intmath # WORKS
io # WORKS
iomix # WORKS
ioport # -----
ioprio # -----
io-uring # -----
ipsec-mb # ----- # requires libipsec-mb
itimer # WORKS,CI
jpeg # WORKS # uses libjpeg
judy # ----- # requires libJudy (ORPHANED)
kcmp # -----
key # -----
kill # WORKS,CI
klog # -----
kvm # -----
l1cache # ----- # requires /sys/devices/system/cpu
l1cache --l1cache-line-size 32768 --l1cache-ways 8 --l1cache-sets 1 # WORKS
landlock # -----
lease # -----
led # -----
link # WORKS,CI
list # WORKS
llc-affinity # WORKS
loadavg # WORKS
locka # WORKS
lockbus # WORKS
lockf # WORKS,CI # (fixed in Cygwin 3.5.5: "NtCreateEvent(lock):
0xC000003" and ...
# "can''t handle more than 910 locks per file")
lockmix # WORKS
lockofd # -----
logmath # WORKS,CI # (fixed in Cygwin 3.5.5: signal handler destroys
long double values)
longjmp # WORKS,CI # (fixed in Cygwin 3.5.5: signals lost during
setjmp or longjmp)
loop # -----
lsearch # WORKS
lsm # -----
madvise # WORKS
malloc # WORKS,CI
matrix # WORKS
matrix-3d # WORKS
mcontend # WORKS
membarrier # -----
memcpy # WORKS,CI # (fixed in Cygwin >3.6.0: crash due to set DF in
signal handler)
memfd # -----
memhotplug # -----
memrate # WORKS
memthrash # WORKS
mergesort # WORKS # uses libbsd
metamix # FAILS # TODO Cygwin: "fdatasync on
./tmp-stress-ng-metamix-*/... failed, errno=13"
mincore # -----
min-nanosleep # WORKS
misaligned # WORKS
mknod # -----
mlock # WORKS
mlockmany # heavy # requires --pathological
mmap # WORKS,CI
mmapaddr # WORKS
mmapfork # WORKS
mmapfiles # WORKS
mmapfixed # WORKS
mmaphuge # -----
mmapmany # WORKS
mmaptorture # heavy
module # -----
monte-carlo # WORKS
mpfr # WORKS # uses libmpfr
mprotect # FAILS # TODO Cygwin: crashes or hangs
mq # FAILS # TODO Cygwin: "mq_receive failed, errno=1"
# (fixed in Cygwin 3.5.6: crash on invalid mq fd)
mremap # -----
mseal # -----
msg # WORKS
msync # WORKS
msyncmany # WORKS
mtx # WORKS
munmap # -----
mutex # WORKS
nanosleep # FAILS # TODO undecided: "detected 1 unexpected nanosleep
underruns"
netdev # -----
netlink-proc # -----
netlink-task # -----
nice # heavy # TODO Cygwin: may change nice value of other
processes
nop # WORKS
null # WORKS
numa # -----
oom-pipe # -----
opcode # -----
open # WORKS,CI
pagemove # -----
pageswap # -----
pci # -----
personality # -----
peterson # WORKS
physmmap # -----
physpage # -----
pidfd # -----
ping-sock # -----
pipe # WORKS,CI
pipeherd # heavy # many forks, may freeze desktop
pkey # -----
plugin # -----
poll # WORKS
powmath # WORKS
prctl # -----
prefetch # WORKS
prime # WORKS # uses libgmp
prio-inv # ----- # requires <pthread_nt.h>
priv-instr # FAILS # TODO Cygwin: crashes or hangs, please see:
#
https://sourceware.org/pipermail/cygwin/2025-March/257726.html
procfs # ----- # TODO stress-ng: support /proc subset of Cygwin
pseek # WORKS,CI # (fixed in Cygwin 3.5.5: "pread: Bad file
descriptor")
pthread # WORKS,CI
ptr-chase # WORKS
ptrace # -----
pty # FAILS # TODO stress-ng: do not require
tcdrain/tcflow/TIOCINQ for pty, or ...
# ... TODO Cygwin: implement tcdrain/tcflow/TIOCINQ
for pty :-)
# (fixed in Cygwin 3.7.0: "No pty allocated,
errno=0")
qsort # WORKS
quota # -----
race-sched # WORKS
radixsort # WORKS # uses libbsd
ramfs # -----
rawdev # -----
randlist # WORKS
rawsock # -----
rawpkt # ----- # requires <linux/if_packet.h>, ...
rawudp # -----
rdrand # WORKS
readahead # -----
reboot # -----
regex # WORKS
regs # WORKS
remap # -----
rename # WORKS,CI
resched # heavy
resources # heavy
revio # WORKS
ring-pipe # WORKS
rlimit # heavy
rmap # WORKS
rotate # WORKS
rseq # -----
rtc # ----- # requires /dev/rtc
schedmix # WORKS
schedpolicy # WORKS,CI
sctp # -----
seal # -----
seccomp # -----
secretmem # -----
seek # WORKS,CI
sem # FAILS # TODO Cygwin: "instance 0 corrupted bogo-ops
counter, 556328 vs 556327"
sem-sysv # FAILS # TODO Cygwin: "aborted early, out of system
resources"
sendfile # ----- # requires sendfile(2)
session # WORKS
set # FAILS # TODO stress-ng: "setrlimit failed, ..., expected
-EPERM, instead got errno=22 (Invalid argument)"
shellsort # WORKS
shm # WORKS,CI
shm-sysv # ----- # requires shmat(2), smdt(2)
sigabrt # WORKS,CI
sigbus # FAILS # TODO Cygwin: "ftruncate file to a single page
failed, errno=13 (Permission denied)"
sigchld # FAILS # TODO Cygwin: hangs
sigfd # ----- # TODO stress-ng: drop restriction to glibc (WORKS
then)
sigfpe # FAILS # TODO undecided: "got SIGFPE error 15
(FPE_INTDEV), expecting 20 (FPE_FLTRES)"
sighup # WORKS,CI
sigill # FAILS # TODO Cygwin: "terminated on signal: 11", possibly
similar to "priv-instr"
sigio # ----- # requires O_ASYNC
signal # WORKS,CI
signest # FAILS # TODO Cygwin: "terminated on signal: 11"
sigpending # WORKS,CI
sigpipe # WORKS,CI
sigq # WORKS,CI
sigrt # WORKS,CI
sigsegv # FAILS # TODO Cygwin: crashes or hangs, possibly similar
to "priv-instr"
sigsuspend # WORKS,CI
sigtrap # WORKS,CI
sigurg # WORKS,CI
sigvtalrm # WORKS,CI
sigxcpu # FAILS # TODO stress-ng: "setrlimit failed, errno=22
(Invalid argument)"
sigxfsz # FAILS # TODO stress-ng: "setrlimit failed, errno=22
(Invalid argument)"
skiplist # WORKS
sleep # WORKS,CI
smi # -----
sock # WORKS
sockabuse # WORKS
sockdiag # -----
sockfd # -----
sockmany # heavy
sockpair # WORKS
softlockup # admin
sparsematrix # WORKS
spawn # heavy # TODO Cygwin: "NNN spawns failed (100.00%)", may
crash other processes
spinmem # WORKS
splice # -----
stack # heavy
stackmmap # WORKS
statmount # -----
str # WORKS
stream # WORKS # TODO stress-ng: get --stream-l3-size for
/proc/cpuinfo
swap # -----
switch # WORKS
symlink # WORKS,CI
sync-file # -----
syncload # WORKS
sysbadaddr # heavy
syscall # FAILS # TODO Cygwin: "terminated on signal: 11"
sysinfo # WORKS
sysinval # -----
sysfs # -----
tee # ----- # requires tee(2)
timer # WORKS,CI
timerfd # heavy # TODO undecided: may freeze desktop
time-warp # WORKS
tlb-shootdown # heavy
tmpfs # ----- # requires tmpfs filesystem
touch # WORKS
tree # WORKS # (fixed in Cygwin >3.6.0: crash due to set DF in
signal handler, see also "memcpy")
trig # WORKS
tsc # WORKS
tsearch # WORKS
tun # -----
udp # WORKS
udp-flood # ----- # requires AF_PACKET
umask # WORKS
umount # -----
unlink # WORKS,CI
unshare # -----
uprobe # -----
urandom # WORKS
userfaultfd # -----
usersyscall # -----
utime # WORKS,CI
vdso # -----
veccmp # WORKS
vecfp # WORKS
vecmath # WORKS
vecshuf # WORKS
vecwide # WORKS
verity # -----
vfork # WORKS
vforkmany # heavy # forks until process table is full
vm # WORKS,CI
vm-addr # WORKS
vm-rw # -----
vm-segv # WORKS
vm-splice # -----
vma # WORKS
vnni # WORKS
wait # FAILS # TODO Cygwin: hangs in few cases
waitcpu # WORKS
watchdog # -----
wcs # WORKS
workload # WORKS,CI # (fixed in Cygwin 3.5.5: hang in mq_send/receive)
x86cpuid # WORKS
x86syscall # -----
xattr # FAILS # TODO Cygwin: "fsetxattr succeeded unexpectedly,
created ...
# "... attribute with size greater than permitted
size, errno=61"
yield # WORKS
zero # WORKS,CI
zlib # WORKS # uses libz
zombie # WORKS,CI
'
# SIGKILL may not work if stress-ng hangs.
# Use Sysinternals 'pskill' as no 'killall --force' is available,
killall_force="pskill"
stress_ng="stress-ng"
timeout=5; workers=2
dryrun=false; force=false
taskset=
while :; do case $1 in
-c) shift; taskset=$1 ;;
-f) force=true ;;
-k) shift; killall_force=$1 ;;
-n) dryrun=true ;;
-s) shift; stress_ng=$1 ;;
-t) shift; timeout=$1 ;;
-w) shift; workers=$1 ;;
-*) usage ;;
*) break ;;
esac; shift || usage; done
run_ci=false; run_work=false; run_fail=false
run_tests=
for t in "$@"; do case $t in
CI) run_ci=true ;; WORK) run_work=true ;; FAIL) run_fail=true ;;
[a-z]*[a-z]) run_tests+=" $t" ;;
*) usage ;;
esac; done
$run_ci || $run_work || $run_fail || [ ${run_tests:+t} ] || usage
command -V "$stress_ng" >/dev/null || exit 1
command -V "$killall_force" >/dev/null || exit 1
stress_ng_name=${stress_ng##*/}
tempdir=${TMP:-/tmp}
find_stress()
{
local p=$(procps -C "$stress_ng_name" -o pid,ppid,s,pri,ni,tt,start,time,args
--sort pid)
test "$(wc -l <<< "$p")" -gt 1 || return 1
echo "$p"
}
stop_stress()
{
echo '$' "$killall_force" "$stress_ng_name"
"$killall_force" "$stress_ng_name" ||:
}
total=0
fails=0
# stress TEST [OPTION...]
stress()
{
local name=$1
shift || return 1
local td="$tempdir/stress-ng.$$.$total.d"
local cmd=("$stress_ng" -v -M --oomable --timestamp --verify --temp-path
"$td" -t "$timeout")
test -z "$taskset" || cmd+=(--taskset "$taskset")
cmd+=(--"$name" "$workers" "$@")
echo '$' "${cmd[@]}"
! $dryrun || return 0
(
t=$(date +%s); : $((t += timeout + 30)); sleep 1
while [ "$(date +%s)" -lt "$t" ]; do sleep 1; done
stop_stress & # TODO: without '&', 'exit 0' below is not reached (Hmm...)
exit 0
) &
local watchdog=$!
trap "kill $watchdog 2>/dev/null ||:; exit 130" SIGINT SIGTERM
mkdir "$td"
local rc=0
"${cmd[@]}" || rc=$?
kill $watchdog 2>/dev/null ||:
trap - SIGINT SIGTERM
local ok=true
if wait $watchdog; then
echo ">>> FAILURE: $name" "$@" "(command hangs)"
sleep 2
ok=false
fi
local n=0 p
if p=$(find_stress); then
echo ">>> FAILURE: $name" "$@" "(processes left, exit status $rc):"
echo "$p"
stop_stress
sleep 2
ok=false
fi
if ! rmdir "$td" 2>/dev/null; then
echo ">>> FAILURE: $name" "$@" "(files left in '$td', exit status $rc)"
ok=false
fi
if ! $ok; then
echo
return 1
fi
if [ $rc != 0 ]; then
echo ">>> FAILURE: $name" "$@" "(exit status $rc)"; echo
return 1
fi
echo ">>> SUCCESS: $name" "$@" ""; echo
}
if p=$(find_stress); then
echo "*** Other $stress_ng_name processes are still running:"
echo "$p"
$dryrun || exit 1
fi
while read; do
args=${REPLY#*|}
name=${args%% *}
run_this=false
for t in $run_tests; do if [ "$t" = "$name" ]; then
run_this=true; break
fi; done
tag=${REPLY%%|*}
case $tag in
FAILS) $run_this || $run_fail || continue ;;
WORKS) $run_this || $run_work || continue ;;
WORKS,CI) $run_this || $run_work || $run_ci || continue ;;
-----) $run_this || continue ;;
admin|heavy)
$run_this || continue
if ! $force; then
echo ">>> SKIPPED $name (tagged '$tag', use '-f' to override)"; echo
continue
fi ;;
*) echo "*** syntax error: '$REPLY'"; exit 1 ;;
esac
: $((++total))
stress $args ||: $((++fails))
done <<<"$(
sed -E \
-e 's/^ *([-0-9a-z]+)( +-[^#]*[^ #])? +#
*(FAILS|WORKS(,CI)?|admin|heavy|-----) *(#.*)?$/\3|\1\2/' \
-e '/^ *(#.*)?$/d' \
<<<"$stress_tests"
)"
if [ $fails -ne 0 ]; then
echo ">>> FAILURE: $fails of $total stress test(s) failed"
exit 1
fi
echo ">>> SUCCESS: All $total stress test(s) succeeded"
exit 0