Filed as FB24344519. Posting here too because the scope is wider than any single app, and other developers may be getting "your app uses too much CPU" reports that are not actually their bug.
Environment: macOS 27.0 (26A5406e), Apple Silicon (M5 Max).
SUMMARY
When a custom pointer color is set, every -[NSCursor set] call re-renders the pointer artwork from a PDF, with no caching. Any app whose UI frequently invalidates AppKit tracking areas then burns most of a CPU core continuously, with the mouse completely stationary.
Trigger:
defaults read com.apple.universalaccess cursorIsCustomized 1
That is System Settings > Accessibility > Display > Pointer, with a custom fill and outline color set. With default pointer colors, -[NSCursor set] is nearly free.
CALL PATH (sampled with the mouse untouched)
CFRUNLOOP_IS_CALLING_OUT_TO_A_BLOCK -[_NSTrackingAreaAKManager _activeTrackingAreasNeedUpdate]_block_invoke -[_NSTrackingAreaAKManager _updateActiveTrackingAreasForWindowLocation:modifierFlags:] -[NSCursor set] -[NSCursor _reallySet] _AXFCursorSetAndReturnSeed (AccessibilityFoundation) -[_AXFMouseCursorGenerator createImageForScale:] -[_AXFMouseCursorGeneratorLayer _createImageForScale:color:] -[_AXFMouseCursorGeneratorLayer _pdfPage] / _pdf CGPDFScannerScan -> CGPDFDrawingContextDrawPath createImageWithSizeRenderInstructions __createImageWithMaskedColor_block_invoke CGContextClipToMask -> CGContextDrawImage -> A8_image_mark_rgb32
The pointer artwork is re-parsed from PDF and re-composited on every tracking-area update.
SCOPE
Main-thread samples in that path, mouse stationary:
com.apple.weather.menu (Catalyst/UIKit): 1170 / 1327 = 88% Cloudflare WARP (Flutter): 1095 / 1154 = 95% Dayflow (SwiftUI/AppKit): 273 / 431 = 63% (bursts)
Three unrelated UI toolkits, identical stack, including one of Apple's own menu bar apps. Apps with a mostly static UI are unaffected on the same machine with the same setting enabled, so the amplifier appears to be tracking-area invalidation frequency rather than the toolkit.
Direct measurement of WeatherMenu with the trackpad untouched: 21.8 seconds of CPU in a 30 second window (73% of one core), sustained indefinitely, and 491 minutes of CPU time over 3 days of uptime.
STEPS TO REPRODUCE
- System Settings > Accessibility > Display > Pointer. Set a custom pointer fill and outline color.
- Enable the Weather menu bar item (Control Center > Weather).
- Leave the machine idle. Do not touch the trackpad or mouse.
- Watch com.apple.weather.menu in Activity Monitor.
Expected: near 0% CPU while idle. -[NSCursor set] with an unchanged cursor should be a cheap no-op.
Actual: 65-75% of a core held indefinitely with no user input.
CAVEAT
I have not toggled cursorIsCustomized back off to confirm the CPU drops, so the dependency is inferred from the stack reaching the custom-color renderer (_createImageForScale:color:, createImageWithMaskedColor), which is only used when a custom pointer color is set. About a minute for anyone to verify.
NOTES FOR OTHER DEVELOPERS
Two things that cost me time:
ps %CPU on macOS is a short decaying average, not steady state. It made an app look like it sat at 80% when its actual idle draw was under 4%. Compare cumulative CPU time deltas instead.
sample counts blocked threads too, so "N% of main-thread samples" is not the same as N% CPU. Check whether the leaf frames are actually running code first.
If your users report high CPU you cannot reproduce, it may be worth asking whether they have a custom pointer color set.
SUGGESTED FIX
Cache the generated cursor image in _AXFMouseCursorGenerator, and make -[NSCursor set] a no-op when the cursor and scale are unchanged, rather than re-parsing and re-rendering the PDF on every call.
Happy to provide full samples or a sysdiagnose.