Skip to main content
On macOS, CodSpeed profiles a benchmark by injecting a small profiling library into each process of the benchmark’s process tree, using the DYLD_INSERT_LIBRARIES environment variable. System Integrity Protection (SIP) strips all DYLD_* environment variables whenever a protected Apple system binary is executed, e.g., /bin/sh, /usr/bin/env, the system /usr/bin/python3, or the built-in coreutils. Once such a binary is executed, the profiling library is removed from that process and every process it spawns. The entire subtree becomes invisible to the profiler.

What this looks like

In the following execution tree, πŸ” marks a profiled process and πŸ”’ marks a SIP-protected system binary. Processes without an icon are not profiled:
Execution tree
codspeed run
β”œβ”€ πŸ” /opt/homebrew/bin/python3 bench.py    profiled
└─ πŸ”’ /bin/bash -c "python3 bench.py"       SIP strips DYLD_*
   └─ python3 bench.py                      not profiled
JavaScript tooling is particularly affected: package manager and node_modules/.bin shims go through /usr/bin/env and /bin/sh, so the profiling variable is stripped several times along the chain:
Execution tree (pnpm run bench)
codspeed run
└─ πŸ”’ /usr/bin/env -> node
   └─ πŸ” node (pnpm CLI)
      └─ πŸ”’ /bin/sh -> /bin/bash
         └─ πŸ” node (vitest runner)
            └─ πŸ” node Γ— 5 workers
CodSpeed re-sets DYLD_INSERT_LIBRARIES when launching benchmark runtimes such as Node.js and Go, re-enabling profiling for the rest of the process tree. Only the SIP-protected system processes themselves are never profiled.

When to ignore the warning

Check which binaries the warning mentions:
  • If they are launchers like /bin/sh or /usr/bin/env and your flamegraph contains your benchmark code, ignore the warning. The launcher only accounts for a negligible amount of time.
  • If the work you want to profile happens inside a system binary itself, e.g., you benchmark the system /usr/bin/python3, use one of the workarounds below.

Workarounds

Use a non-system toolchain

The recommended fix is to make sure no SIP-protected binary appears in the benchmark’s process tree. This requires no system changes and is the only workaround that also applies in CI. SIP only protects the binaries that ship with macOS, under /usr/bin, /bin, /usr/sbin, and /sbin. Toolchains installed by a package manager, e.g., Homebrew, uv, pyenv, nvm, or rustup, live outside these paths and are profiled normally:
  1. Install the toolchain with a package manager instead of using the system one under /usr/bin.
  2. Invoke it directly, so the kernel never executes a protected binary, e.g., uv run python3 bench.py instead of python3 bench.py.

Disable SIP

For local profiling on a machine you control, you can disable the part of SIP that strips DYLD_* variables. With it disabled, system binaries are profiled like any other process. Follow Apple’s instructions for disabling System Integrity Protection: boot into Recovery Mode, run one of the following commands in the Terminal, and reboot:
csrutil enable --without debug   # disable only the debugging restrictions
csrutil disable                  # disable SIP entirely
Prefer the first command: the debugging restrictions are the part of SIP that strips DYLD_* variables, so disabling only them keeps the filesystem and kernel extension protections in place. To re-enable SIP when you are done, boot into Recovery Mode again and run:
csrutil enable
Verify the current status at any time with: csrutil status.

Profiling in CI

SIP cannot be disabled on CI-hosted macOS runners, e.g., GitHub-hosted macOS runners. The only available workaround is to use a non-system toolchain: point the benchmark command at the exact non-system toolchain binary and avoid env or shell shims where possible. System processes will not appear in CI profiles, and that is expected. It does not affect the correctness of the benchmark measurements for your own code.

Next Steps

Walltime Instrument

Learn how the walltime instrument measures real-world execution time

Profiling

Learn how to read flamegraphs and use profiling data to optimize your code