Skip to content

perf(fuse): bounded spin-wait for metadata request completion (CORE-48) - #17

Merged
AprilNEA merged 2 commits into
masterfrom
perf/fuse-spin-wait
Jul 31, 2026
Merged

perf(fuse): bounded spin-wait for metadata request completion (CORE-48)#17
AprilNEA merged 2 commits into
masterfrom
perf/fuse-spin-wait

Conversation

@AprilNEA

Copy link
Copy Markdown
Member

Problem

On virtualized ARM64, every synchronous FUSE operation pays a cross-vCPU round trip: device-IRQ trap → reschedule-IPI trap → two context switches. Two architectural facts make this unavoidable by scheduling alone (all A/B'd in Linear CORE-48):

  • ARM64 has no TIF_POLLING_NRFLAG, so try_to_wake_up always sends a physical IPI — idle=poll and __wake_up_sync measurably change nothing.
  • All vCPUs share one LLC domain, so wake_affine never migrates the waiter onto the IRQ CPU — the best sched-feature toggle recovered +12% vs the +82% of hard pinning.

Measured 1:1 correspondence between virtio-fs request IRQs and reschedule IPIs during a stat loop.

Fix

request_wait_answer polls FR_FINISHED for ≤40µs before sleeping (KVM halt-polling applied at the FUSE wait point), gated to non-READ/WRITE opcodes. The waiter observes fast completions while still runnable: no wakeup IPI, no context switches. need_resched() breaks the spin the moment the CPU has real work.

The gate is load-bearing: ungated, bulk READ replies outlive the budget and the burnt CPU cost −54% sequential read; gated, sequential read is unchanged (−3.5%, run noise).

Numbers (Apple VZ guest, 18 vCPU, same-VM A/B, ArcBox bench trio)

bench stock 6.18.38 patched Δ
metadata_stat 31.8k ops/s 50.3k +58% (97% of the taskset+IRQ-pin ceiling)
negative_lookup 23.6k 33.0k +40%
create_delete 4.6k 5.9k +28%
sequential_read 3771 MB/s 3637 MB/s −3.5% (noise)

Also beats Colima's same-context numbers (51.7k / 30.2k / 6.7k) on the identical Apple virtiofs device.

Notes

  • The patch is generic fs/fuse code and applies to both arch builds; the win is ARM64-virt-specific, and on x86 the polling flag already avoids most wake IPIs — the gate + need_resched() bound the cost there to the spin budget on slow metadata ops.
  • Fixed 40µs budget keeps the patch minimal; a KVM-style adaptive grow/shrink budget is the natural upstream refinement (tracked in CORE-48).
  • Acceptance before release: bench_virtiofs e2e trio + sequential (done, table above), docker-build A/B on the ArcBox side (running, will attach), multi-flow iperf sanity.

Refs Linear CORE-48.

On virtualized ARM64 every reschedule IPI is a trap (no
TIF_POLLING_NRFLAG, single LLC domain keeps wake_affine from migrating
the waiter onto the IRQ CPU), so a synchronous FUSE workload pays
device-IRQ trap + IPI trap + two context switches per operation — the
reschedule-IPI count matches the virtio-fs request IRQ count 1:1.

Poll FR_FINISHED for up to 40us before sleeping (KVM halt polling at
the FUSE wait point), gated to non-READ/WRITE opcodes: bulk replies
outlive the budget and an ungated spin cost -54% sequential-read
throughput. A/B on the ArcBox bench trio (Apple VZ guest, 18 vCPU):
metadata_stat 31.8k -> 50.3k ops/s (+58%, 97% of the hard-pinned
ceiling), negative_lookup +40%, create_delete +28%, sequential read
-3.5% (noise). Beats Colima's same-context numbers.

Full investigation record: Linear CORE-48.
@linear-code

linear-code Bot commented Jul 31, 2026

Copy link
Copy Markdown

CORE-48

@greptile-apps

greptile-apps Bot commented Jul 31, 2026

Copy link
Copy Markdown

Greptile Summary

This PR adds bounded polling before FUSE request waits.

  • Polls kernel-mediated transport requests for up to 40µs.
  • Stops polling when completion is observed or rescheduling is needed.
  • Excludes several bulk-I/O, synchronization, copy, and locking opcodes.

Confidence Score: 4/5

The PR is not yet safe to merge because directory-read requests still enter the polling path despite the attempted non-metadata exclusion.

The revised switch handles several operations named in the earlier review, but directory reads remain admitted through the default branch and can still incur the full spin budget on every request.

Files Needing Attention: patches/fuse-spin-wait.patch

Important Files Changed

Filename Overview
patches/fuse-spin-wait.patch Adds the bounded FUSE completion spin and expands the opcode exclusion gate.

Reviews (2): Last reviewed commit: "perf(fuse): gate the spin to virtio-clas..." | Re-trigger Greptile

Comment thread patches/fuse-spin-wait.patch Outdated

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 1096af1277

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread patches/fuse-spin-wait.patch Outdated
@AprilNEA

Copy link
Copy Markdown
Member Author

Acceptance A/B complete (2026-07-31, back-to-back isolated-VM boots, identical bundle except the kernel)

bench stock 6.18.38 patched Δ
metadata_stat 32.1k ops/s 52.8k +64%
negative_lookup 23.9k 34.3k +44%
create_delete 4.9k 6.0k +22%
find_recursive 18.3k 21.6k +18%
rm_rf 2505 ms 2380 ms −5% (faster)
sequential_read 3708 MB/s 3720 MB/s ±0

Every row improves or holds; the v1 ungated −54% sequential regression is fully absent with the opcode gate. Boot/lifecycle sanity: 5 green boots of the patched kernel across the lab rounds, docker pull/run normal in each.

Real-world surface this accelerates: bind-mounted host volumes (docker run -v) — stat/lookup storms on source trees and node_modules — plus everything else on the VirtioFS share. docker build itself is btrfs/overlay-side and unaffected by design.

Remaining before release train (assets.lock bump side): multi-flow iperf sanity ride-along, and the boot-assets bundle rebuild picks the patch up automatically via patches/*.patch.

… opcodes

Review round: the single READ/WRITE exclusion left slow non-metadata
requests (flush/fsync, copy_file_range, blocking locks) burning the
budget, and classic /dev/fuse daemons with arbitrary completion latency
took the spin path on every build. The spin now requires a
kernel-mediated transport (fc->iq.ops != fuse_dev_fiq_ops, i.e.
virtio-fs) and skips every legitimately-blocking opcode.

Revalidated on hardware: metadata_stat 50.6k (+57% vs stock),
negative_lookup 37.6k (+57%), create_delete +17%, find_recursive +11%,
rm_rf 14% faster, sequential read -3% (noise).
@AprilNEA
AprilNEA merged commit 544b7e1 into master Jul 31, 2026
7 checks passed
@AprilNEA
AprilNEA deleted the perf/fuse-spin-wait branch July 31, 2026 12:25
AprilNEA added a commit to arcboxlabs/arcbox that referenced this pull request Jul 31, 2026
…513)

Bundle v0.6.13 ships kernel v0.0.22 with the opcode- and
transport-gated FUSE spin-wait (arcboxlabs/kernel#17): host-volume
metadata ops +44..64% (metadata_stat 32.1k -> 52.8k ops/s), bulk I/O
unchanged. Full A/B record in Linear CORE-48.

Validated: boot_assets e2e green on the new bundle (full Docker
lifecycle, 116s).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant