Skip to content

perf(fs): write a writeFiles batch in one sidecar request - #2105

Merged
eersnington merged 1 commit into
mainfrom
perf/write-files-batch
Nov 12, 2026
Merged

eersnington merged 1 commit into
mainfrom
perf/write-files-batch

Conversation

@eersnington

Copy link
Copy Markdown
Member
  • vm.filesystem.writeFiles() sends a batch to the sidecar as one GuestFilesystemWriteFilesRequest instead of two round trips (mkdir -p + write) per file. Per-entry results keep their input order, and a failed entry doesn't stop the rest. TS and Rust clients behave the same.
  • The sidecar advertises its per-request limits in AuthenticatedResponse (maxFrameBytes, new maxWriteFilesEntries = 16). Clients split larger batches by those values; no client copies a sidecar constant.
  • Generated BARE data fields now decode as one block copy (serde_bytes) instead of byte by byte. Wire bytes are unchanged. This speeds up every binary field in the protocol: one 2.3 MB file write went from 42 to 11 ms.
  • The sidecar skips repeated mkdir -p for parents it already created in the same batch.
45 files, 2.29 MB, release sidecar p50 p90
main (per-file requests) 112 ms 122 ms
this PR 71 ms 75 ms

A batch runs in one sidecar critical section, so the entry cap is kept small. Another VM on the same sidecar waits at most 17–51 ms while 1k–8k files are written (6 s with a 4,096 cap).

- Add GuestFilesystemWriteFilesRequest: the sidecar runs mkdir -p and the write for each entry and returns per-entry errors in input order
- Bound each request to 16 entries (typed ERR_AGENTOS_RESOURCE_LIMIT) and to the frame limit; the sidecar advertises both in AuthenticatedResponse and the TS and Rust clients split larger batches by those values. A batch runs in one critical section, so the small cap keeps other VMs on the sidecar responsive
- Encode generated BARE data fields with serde_bytes so file bytes are copied as one block, not one byte at a time
- Skip repeated mkdir -p for a parent already created earlier in the same batch
@eersnington
eersnington force-pushed the perf/write-files-batch branch from 0631c48 to b64c9ea Compare November 12, 2026 23:01
@eersnington
eersnington merged commit e57c6aa into main Nov 12, 2026
6 of 8 checks passed
@eersnington
eersnington deleted the perf/write-files-batch branch November 12, 2026 23:03
@github-actions

Copy link
Copy Markdown
Contributor

📟 Pip-Boy · b64c9ea

📦 Packages

❌ Not run: the changes job was cancelled. See the run.

🧹 Rust dependencies

❌ Not run: the changes job was cancelled. See the run.

🦀 Binaries

❌ Not run: the changes job was cancelled. See the run.

⏱ Timing

job wall time slowest step
zizmor 8s checkout · 2s
⊘ changes 5m01s checkout · 4m59s
report 14s Write the comment and run summary · 3s
⏭ footprint — skipped
⏭ native · ${{ matrix.platform }} — skipped
⏭ hygiene — skipped
⏭ self-test — skipped
🔭 Full CI trace for this commit

One OpenTelemetry trace of CI and Pip-Boy for b64c9ea: every job and step, with the sizes above attached. Run after CI finishes.

pnpm install --frozen-lockfile --filter 'pipboy...'
pnpm --filter pipboy pipboy trace --sha b64c9eab0f97c01b17ea3cd644556b75033830ce

Add --otlp <url> to send it to any OTLP/HTTP collector.

Agent instruction: From a rivet-dev/agentos checkout, run the commands above, then read the trace file the last command prints. List the slowest jobs and steps and explain where CI time went.

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