Your SSH-Launched Benchmark Is Running at nice 5

2026-09-02Hardware Notes

On macOS, backgrounding a process from a non-interactive SSH shell silently deprioritizes it. Every number you compare against a system daemon is invalid.

Summary

Any process backgrounded with nohup โ€ฆ & from a non-interactive SSH shell on macOS inherits Darwin background quality-of-service and runs at nice 5. A launchd daemon runs at nice 0. So a server you start over SSH to benchmark is deprioritized against the exact production daemon you're comparing it to, silently, and every number is invalid. The fix is one word: screen.

The measurement

Verified side by side on the same machine:

launch method ps -Ao pid,pri,ni
nohup sh -c "sleep 40" & over SSH pri 31, ni 5
screen -dmS t sh -c "sleep 40" over SSH pri 31, ni 0
launchd system daemon pri 4, ni 0

This is macOS-specific. Linux hosts don't do it โ€” our GPU servers are unaffected. It applies to every Mac you drive over SSH, which for us is all of them.

What it cost us

A hand-launched inference server produced 28.5 tok/s prefill on a 2,560-token prompt โ€” 89.8 seconds โ€” and a 25k-token prompt that hadn't finished after ten minutes. On a completely idle machine. Against a production median of about 320 tok/s.

The model was fine. The checkpoint was fine. The prompt was fine. The server was at nice 5.

We spent the session looking for a software regression that didn't exist. It's a particularly nasty failure because everything about the setup looks careful: idle box, controlled prompt, same binary, same flags. The one uncontrolled variable is invisible unless you go looking for it, and nothing in the output hints at it.

It's also a failure that biases in a consistent direction. Your hand-launched candidate always loses to the incumbent daemon. If you're evaluating a replacement for a production service โ€” which is exactly when you'd be hand-launching something โ€” the bias points at "keep what we have."

The fix

screen is preinstalled at /usr/bin/screen on macOS. tmux generally isn't.

screen -wipe >/dev/null 2>&1
screen -dmS <name> sh -c "ENV=x /path/to/server --flags > /tmp/out.log 2>&1"

# verify BEFORE trusting any number:
ps -Ao pid,pri,ni,command | grep "[m]yserver"     # want ni=0

The verification line is the important part. Add it to the harness, not to your memory.

Things that don't work

We tried these before landing on screen:

Since you can't fix it retroactively, the check has to happen before the run, not after you notice a weird number.

The general rule

Before benchmarking any hand-started service on a Mac, print ps -o pri,ni for it and confirm ni=0. If it says 5, the run is garbage.

The broader version: when you compare a hand-launched process against a system-managed one, you are comparing two different execution environments, not two different programs. Priority is the one that bit us. Environment variables, working directory, open file limits, and the sandbox profile are all in the same category โ€” the service manager sets them and your shell doesn't.

Key takeaways

  1. nohup โ€ฆ & over non-interactive SSH on macOS yields nice 5. A launchd daemon is nice 0. Your benchmark is throttled against its own comparison.
  2. Use screen -dmS โ€” preinstalled on macOS, and it produces nice 0.
  3. Verify with ps -o pri,ni before trusting a number, because you can't repair the priority afterward without root.
  4. The bias has a direction. Hand-launched candidates always lose to installed daemons, which is the opposite of what you want when evaluating a replacement.
  5. A hand-started service differs from a managed one in more than priority. Priority is just the one that's invisible.

Everything in these notes I also do for hire: local AI set up on hardware you own, configured on-site, then handed over with enough documentation that you do not need me afterward. If that sounds more useful than another weekend of reading forum threads, the details are at /hire. No obligation from an email, and the posts stay free either way.

See pricing and book a free audit โ†’