mac sysadmin essentials: dtruss, sample, fs_usage, and the macOS equivalents of strace, ltrace, and iotop

You’ve spent a decade reaching for strace when a Linux process is misbehaving. You move to a Mac. You type strace. Nothing. man strace. Nothing. You google “strace mac” and get six different answers, half of them recommending you install something. Most of them don’t work on Apple Silicon, or only work after disabling System Integrity Protection, or only on the user’s processes (not system daemons), or only inside Docker.

The good news: macOS already has the equivalents built in, you don’t need to install anything, and they work on Apple Silicon out of the box. The bad news: their names are different, their flags are different, and they’re scattered across the toolchain instead of unified into a single famous command. Here’s a working translation table for the kinds of debugging you actually do.

strace → dtruss

dtruss is the macOS equivalent of strace. It’s a thin wrapper around DTrace that prints every syscall a process makes, with arguments and return values. It’s been part of macOS since Lion.

# Trace every syscall of a new command
sudo dtruss curl https://example.com 2>&1 | head -40

# Attach to a running process
sudo dtruss -p $(pgrep -n SomeApp)

# Filter to just one syscall (e.g. open)
sudo dtruss -t open_nocancel curl https://example.com 2>&1 | head

# With timestamps and elapsed time
sudo dtruss -d -e curl https://example.com 2>&1 | head

The catch: dtruss requires SIP to allow DTrace, which is the default on macOS Sonoma and later. If you’ve ever booted into Recovery and disabled SIP for some other tool, you may also need csrutil enable --without dtrace. On a stock machine, it just works.

ltrace (library calls) → no direct equivalent, use dtrace

macOS doesn’t ship an ltrace equivalent. The DTrace probe-set pid$target:libsystem_kernel: can intercept libc calls, but you write your own one-shot DTrace script:

# Trace every libc call made by a process
sudo dtrace -n 'pid$target:libsystem_c.dylib::entry { @[probefunc] = count(); }' \
  -p $(pgrep -n SomeApp)
# Press Ctrl+C — prints a histogram of which libc functions were called and how many times.

It’s clunkier than ltrace but more powerful. The DTrace one-liner pattern (pid$target:LIBNAME::entry { ... }) lets you instrument any library, not just libc.

iotop → fs_usage

For “what process is hammering the disk right now,” macOS has fs_usage:

# Live filesystem activity, all processes
sudo fs_usage -w -f filesys

# Just one process
sudo fs_usage -w -f filesys -p $(pgrep -n SomeApp)

# Just open() calls (great for "where's this app reading config from?")
sudo fs_usage -w -f filesys | grep -E '^[^ ]+ +open'

# Just network-syscall activity
sudo fs_usage -w -f network

-w is wider columns (full paths shown). -f filesys filters to the filesystem subsystem. The output is one line per syscall; expect to pipe to grep or awk to make it readable.

perf / pprof → sample, spindump

sample is the simplest CPU profiler — give it a PID and a duration, and it returns a stack-trace summary of where the process spent its CPU time:

# Profile a process for 10 seconds, print a tree of where CPU time went
sudo sample SomeApp 10
sudo sample 12345 10              # by PID

# Save the report to a file (for sharing with engineering)
sudo sample SomeApp 10 -file /tmp/sample.txt

spindump is the heavier-weight alternative — it samples the entire system (not just one process) and writes a textual stack-trace report covering everything that was running. Use it for “the whole machine is unresponsive” debugging where you don’t know which process is the culprit.

sudo spindump 5 10 -file /tmp/spindump.txt
# 5 = sample for 5 seconds, 10 = sample interval microseconds

tcpdump / ss → tcpdump (yes, same), nettop, lsof

Network-side tools that ARE the same name, just included by Apple:

# Capture packets — same as Linux
sudo tcpdump -i en0 -nn -X 'tcp port 80' | head

# Live "ss" / "netstat -tnp" equivalent — what processes are using which sockets, with traffic counts
sudo nettop -m tcp

# Open files / sockets for a process (same lsof you know from Linux)
lsof -p $(pgrep -n SomeApp) | head -20
lsof -i -P | grep LISTEN     # listening ports

htop / top → top (mostly), Activity Monitor for the GUI

Apple’s top has different default flags than Linux’s top — the most useful options:

# Sorted by CPU, refresh every 2 seconds, show "interesting" stats
top -o cpu -s 2 -stats pid,command,cpu,mem,th,state

# Sorted by memory
top -o mem

# Show open file count per process (useful for fd-leak debugging)
top -stats pid,command,fd,th,cpu

If you actually want htop, brew install htop works fine and the Linux behavior is identical. Some sysadmins prefer btop (also brew-installable), which has nicer defaults.

journalctl → log show / log stream

# Live tail of the unified system log (all subsystems)
log stream

# Just one subsystem
log stream --predicate 'subsystem == "com.apple.network"'

# Last 10 minutes, search-style
log show --last 10m --predicate 'eventMessage contains "denied"'

# Just errors and faults from the last hour
log show --last 1h --info | grep -iE 'error|fault'

The predicate syntax is NSPredicate, similar to a SQL WHERE clause but with macOS-specific keys. log help predicates documents what’s queryable.

Cheatsheet

  • stracesudo dtruss
  • ltrace → custom DTrace one-liner with pid$target:LIB::entry
  • iotop / per-process disk I/O → sudo fs_usage -w -f filesys
  • perf / sampling profiler → sudo sample <pid> <sec> or sudo spindump
  • tcpdumptcpdump (same)
  • ss / netstatsudo nettop -m tcp or lsof -i -P
  • htoptop -o cpu or brew install htop
  • journalctllog show / log stream

You won’t need to install much. The macOS tools are powerful, often more than their Linux counterparts — but you’ll spend a week learning DTrace’s syntax before you’re as fluent as you are with strace. The cheatsheet above is the 80% you’ll hit on day one.

Photo: System monitor display by Tima Miroshnichenko on Pexels.

Leave a Comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.