openclaw - 💡(How to fix) Fix Windows: lstat bottleneck causes 2-3x slower performance vs Mac (59% of CPU time) [2 pull requests]

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…

Root Cause

Three re-export modules (path-safety.ts, path-guards.ts, boundary-path.ts) forward safeRealpathSync and isPathInsideWithRealpath from @openclaw/fs-safe/path without any cross-call caching. Each invocation starts fresh, even for identical path prefixes that were just resolved moments ago.

Fix Action

Fixed

RAW_BUFFERClick to expand / collapse

Problem

OpenClaw on Windows is 2-3x slower than on Mac. CPU profiling (120s full flow) reveals lstat system calls as the dominant bottleneck:

  • 81s non-idle time, of which 47.8s (59%) is spent in lstat
  • safeRealpathSync / isPathInsideWithRealpath called ~48,000 times → ~976,000 lstat calls
  • Most callers do not pass a cache parameter, causing the same path prefixes to be repeatedly resolved with identical results
  • Windows single lstat: 49µs vs Mac 1.1µs (45x slower per call) — multiplied by ~1M calls = 47s

Root Cause

Three re-export modules (path-safety.ts, path-guards.ts, boundary-path.ts) forward safeRealpathSync and isPathInsideWithRealpath from @openclaw/fs-safe/path without any cross-call caching. Each invocation starts fresh, even for identical path prefixes that were just resolved moments ago.

Proposed Fix

Inject a global Map<string, string> cache at the re-export layer:

  1. path-safety.ts: Wrap safeRealpathSync with a dual-layer cache (global + caller-local)
  2. path-guards.ts: Import from path-safety.js (instead of directly from @openclaw/fs-safe/path) so all 25 importing files benefit from the global cache
  3. boundary-path.ts: Add input→output result cache for resolvePathViaExistingAncestorSync

Rewrite isPathInsideWithRealpath to call the cached safeRealpathSync from its own module.

Benchmark Results (120s CPU Profile, before → after)

MetricBeforeAfterImprovement
lstat total47,834ms8,135ms-83%
safeRealpathSync direct lstat~14,000ms743ms-95%
resolvePathViaExistingAncestorSync4,300ms61ms-99%
chat.send → lane enqueue17-20s5.4s-70%

Implementation

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING

openclaw - 💡(How to fix) Fix Windows: lstat bottleneck causes 2-3x slower performance vs Mac (59% of CPU time) [2 pull requests]