I Fixed My Slow Mac and Found an Apple Bug

An afternoon with an LLM, one wrong theory, and a resource leak in an Apple daemon.

EssayJuly 20265 min read

The standard warning about LLMs is that they make things up, so the standard defence is to check the facts. I checked the facts. Every log line in the theory that cost me an hour was real, and I could open each one.

The theory was wrong anyway. It explained 45% CPU with an event that fired twice in 10 minutes, and neither of us compared those 2 numbers for about an hour. A plausible explanation assembled from true details is the failure that checking facts does not catch. What caught it was asking for a measurement instead of an explanation, and that turned up a resource leak in an Apple daemon.

My MacBook Pro had become slow. It was worst during a Teams screenshare, which is when other people can see it. I sent 3 Activity Monitor screenshots to an LLM and gave it access to my machine. This is what the afternoon looked like.

Activity Monitor CPU tab showing WindowServer at 158% CPU
WindowServer at 158% CPU
Activity Monitor memory tab showing ecosystemanalyticsd at 1.40 GB and 254,889 ports
ecosystemanalyticsd, 254,889 Mach ports

Display scaling

The first finding took under a minute.

My BenQ 4K monitor was set to “looks like 2560x1440”. At that setting macOS renders a 5120x2880 image and scales it down to the panel’s real 3840x2160. That is 77% more pixels than the screen has, on every frame.

WindowServer was using 124% CPU. I changed the setting to native. WindowServer dropped to 53%.

Granola was also running. It had 10 processes and held the microphone subsystem open for 18 hours. I quit it.

Rosetta translation

I asked the LLM to check what my shell actually ran.

2 Homebrew installations found, with git and node resolving to Intel binaries
Two Homebrew installs, one machine

My git was an Intel binary. My node was an Intel binary. Both ran under Rosetta translation on an Apple Silicon machine. I use oh-my-zsh, which runs git each time the prompt draws. I am a product designer and design engineer. Most of my day goes into iterating on UI and codebase in Claude Code, so node is running the whole time.

The cause was 2 Homebrew installations. The Intel one was at /usr/local and the Apple Silicon one was at /opt/homebrew. The Intel install had 110 packages and 1,365 symlinks. It was also broken. It could not parse the macOS version string and refused to run.

I had kept Intel and Rosetta installations off this machine on purpose. Then one project needed an x86 toolchain, so I made an exception for that work. The exception stayed after the project ended. It became the default, and nothing told me.

I had 9 Node versions in nvm. My default was an x86 build. An arm64 build of the same major version was already installed. My .zshrc had the old path written into it directly, so the nvm settings had no effect.

I switched both to native builds. This part alone was worth the afternoon. Every build I run is faster now.

Disk space

The disk was 92% full. macOS becomes slow above about 85%.

Caches held 24 GB. WhatsApp held 36 GB, and 33 GB of that was media from 4 group chats. I removed WhatsApp from the Mac. My phone still holds the messages.

The incorrect theory

2 system processes each used about 45% CPU. The logs showed failed Rosetta checks and failed code signature reads. The LLM built a theory around these log entries. I accepted it.

The LLM stating an incorrect conclusion about a tight retry loop
The first explanation

The theory was wrong.

I removed the Intel git. The Rosetta checks continued. There were only 2 of them in 10 minutes, which cannot account for 45% CPU. The log volume had always been too low to support the theory. Neither I nor the LLM checked this for about an hour.

I asked it to stop reading logs and measure the process directly.

The first 2 attempts to profile the process returned no output and no error message. The LLM read this as a permissions problem and went back to the logs.

The real reason was different. Homebrew had installed a Python package named sample at /opt/homebrew/bin/sample. This shadowed the macOS profiler at /usr/bin/sample. It ran and produced nothing. Once I used the full path, the profiler returned the data in 10 seconds.

The actual cause

Profiler output listing hundreds of dispatch queues named trust
551 live trust queues

ecosystemanalyticsd had 551 live dispatch queues named “trust”. It held 254,889 Mach ports and a 1.4 GB memory footprint after 30 hours of uptime.

The daemon creates one queue for each code signature check. It does not release them. The CPU cost grows with the size of the leak, not with the amount of work.

The kernel killing the process, and the clean replacement process
Kernel kill and clean respawn

The kernel terminated the process during the investigation. It restarted clean. It then ran for 55 minutes and used 0.06 seconds of CPU. The workload was the same. The cost was near zero.

This is an Apple defect. Nothing I installed caused it.

Results

What changedBeforeAfter
Load average (10-core machine)12.731.91
WindowServer CPU124%53%
ecosystemanalyticsd CPU45.8%0%
ecosystemanalyticsd memory1.4 GB7.7 MB
ecosystemd CPU50.6%0%
Free disk space36 GB (92% used)69 GB (85% used)
gitIntel 2.46.2 under RosettaUniversal 2.50.1 native
nodex86 v22.6.0 under Rosettaarm64 v22.22.3 native
Monitor render target5120x2880, scaled down3840x2160, native

I filed a report with Apple and attached the profiler output.

Apple Feedback Assistant confirming the report was sent
Filed with Apple

Notes on method

Give access in steps. Start with read-only commands. Approve deletions one at a time.

Ask for measurements, not explanations. The incorrect theory survived because it was plausible and because nobody compared it against the numbers.

When a tool returns no output, find out why before you move on. Here the profiler was being shadowed by another binary of the same name. Reading the silence as a permissions problem sent the investigation back to the logs it had just left.

Summary

  1. My MacBook Pro (M1 Max, 32 GB, macOS 26.5.1) became slow.
  2. My external 4K monitor was set to a scaled resolution. This made macOS render 77% more pixels than the screen has.
  3. My git and my node were Intel binaries. Both ran under Rosetta translation.
  4. The disk was 92% full. WhatsApp held 36 GB of it.
  5. 2 Apple system processes each used about 45% CPU. The first explanation for this was incorrect.
  6. The actual cause was a resource leak in an Apple daemon called ecosystemanalyticsd.
  1. I sent 3 Activity Monitor screenshots to an LLM.
  2. I gave it read-only access to my machine first. I approved each command.
  3. I approved changes one at a time. I approved deletions separately.
  4. I asked for measurements when an explanation did not match the numbers.
  5. I filed a bug report with Apple.
All notes