100% CPU usage while idle awaiting user input
Description
Claude CLI consumes 100%+ CPU while idle waiting for user input at the prompt. The process should be sleeping/blocked on stdin read, but instead is actively running.
System Information
- Platform: Raspberry Pi 5 (ARM64)
- OS: Linux (Debian-based)
- Claude CLI Version: Latest from npm
Diagnostic Output
top output
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
8175 jferraro 20 0 71.6g 959712 52480 R 114.0 5.9 22:28 claude
Note: Process is in R (running) state, not S (sleeping).
strace analysis
Running strace -p <pid> -f reveals three issues:
Issue 1: Busy-polling /proc stats
[pid 8175] pread64(10, "18762362 239712 13120 13620 0 16"..., 256, 0) = 41
[pid 8175] pread64(10, "18762362 239712 13120 13620 0 16"..., 256, 0) = 41
[pid 8175] pread64(10, "18762362 239712 13120 13620 0 16"..., 256, 0) = 41
The main thread is reading /proc/self/stat (process statistics) in a tight loop with no sleep between reads. This appears to be resource monitoring code (likely for status bar memory display) without any rate limiting.
Issue 2: Spinlock contention
[pid 8550] sched_yield()
[pid 8551] sched_yield()
[pid 8552] sched_yield()
Three worker threads are in tight sched_yield() loops - classic spinlock starvation pattern. They yield CPU but immediately retry, burning cycles.
Issue 3: 16ms timer (60 Hz)
timerfd_settime(7, ..., {it_value={tv_sec=0, tv_nsec=16000000}}, ...)
A 60Hz timer is running (reasonable for UI), but combined with busy polling creates excessive load.
Expected Behavior
When idle at the input prompt, the process should:
- Block on stdin read (sleeping state)
- Poll resource stats at most once per second, not continuously
- Worker threads should be sleeping on condition variables, not spinning
Impact
- Drains battery on laptops
- Causes thermal throttling on low-power devices (Pi)
- Wastes significant CPU resources
- Makes the system less responsive for other tasks
Suggested Fix
Replace the busy-poll resource monitoring with a timer-based approach (e.g., poll /proc/self/stat once per second). Review worker thread synchronization to use proper blocking primitives instead of spinlocks.
This issue has 12 comments on GitHub. Read the full discussion on GitHub ↗