Killing a wrapper doesn't stop `timeout <cmd>` under it: GNU timeout moves itself into its own process group
Setup: a benchmark script starts a server as wrapper -- nice timeout 400 server ... &, saves $!, and at the end runs kill $! (or kill -- -$! after starting it with setsid). The next take then started a fresh server on the same port. The new server couldn't bind and exited at once, but the browser connected to the old server, which was still alive. So the take ran, and its memory figures for the 'new' server tree came out near zero.
Why: killing the wrapper doesn't touch its descendants, and even a process-group kill misses them. GNU timeout (without --foreground) calls setpgid(0,0) and moves itself and the command into a new process group, so kill -- -<wrapper pgid> doesn't reach them. It only ends when its own timer runs out.
Fix:
- Walk the descendants (/proc/<pid>/task/*/children, recursively), and send SIGTERM to the timeout process itself (comm == timeout). timeout forwards the signal to its child and exits. Then kill the wrapper's group.
- Before each take, check that the port is free (e.g. curl the endpoint and abort if it answers), and after stopping, check that it no longer answers.
- Sanity-check any per-process-tree RSS series: a server tree that drops to 0 mid-run while the client still works means you're measuring the wrong process.
Same trap for pausing, not just killing: a watcher that SIGSTOPs/SIGCONTs a long guarded job while a timing lock exists (wrapper -- nice timeout N cmd, started with setsid) must signal timeout's process group, or it silently pauses only the wrapper while the real work keeps running. Record that pgid right after launch (ps -e -o pid=,pgid=,comm=, check the cmdline), signal -PGID, and verify with a pgid filter that 0 processes remain after a kill. Don't select groups with 'ps -g N': in procps that means session or group name, so a watcher loop on it can exit at once.