Skip to content

perf: write state directly to avoid temporary allocations - #21

Merged
MeteorsLiu merged 2 commits into
xgo-dev:mainfrom
MeteorsLiu:codex/memfd-output
Sep 20, 2026
Merged

MeteorsLiu merged 2 commits into
xgo-dev:mainfrom
MeteorsLiu:codex/memfd-output

Conversation

@MeteorsLiu

Copy link
Copy Markdown
Collaborator

No description provided.

@codecov

codecov Bot commented Sep 20, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 41.79104% with 39 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
image_linux.go 44.73% 11 Missing and 10 partials ⚠️
internal/state/memory.go 50.00% 4 Missing and 4 partials ⚠️
host_linux.go 0.00% 6 Missing ⚠️
guest_linux.go 0.00% 2 Missing ⚠️
internal/state/roundtrip.go 60.00% 2 Missing ⚠️

📢 Thoughts on this report? Let us know!

@MeteorsLiu MeteorsLiu changed the title perf: write state image to shared memory directly to avoid temporary allocations perf: write state image directly to avoid temporary allocations Sep 20, 2026
@MeteorsLiu MeteorsLiu changed the title perf: write state image directly to avoid temporary allocations perf: write state directly to avoid temporary allocations Sep 20, 2026

@fennoai fennoai 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.

Review: streaming memfd output

This is a clean, well-reasoned refactor. It replaces the mmap grow-and-retry buffer with a streaming bufio.Writer over a pwrite-backed imageWriter, and adds a shared save(mem, out, root) path so Save/SaveTo stay DRY.

Verified correct:

  • Header/size accounting in writeStateImage is consistent (reserve zero header at offset, write payload of n, zero the following header, then publish size = n + 8 last). Matches readStateImage and the tests.
  • The io.Writer short-write contract in writer.writeBytes/writeString is honored (panic on io.ErrShortWrite, converted to error via safely).
  • Security: no findings. Offset/size overflow guards hold, the host still reads its result from the host-retained offset (not the guest-writable input header), the unpublished-header invariant survives the new layout, and a failed guest write leaves a zero header that readStateImage rejects.

Inline comments below are minor/tuning suggestions, none blocking.

Also minor (not inlined): writeStateImage and imageWriter.Write emit the same "sandbox image size overflow" message from two sites, making a failure ambiguous — consider differentiating the two messages.

Comment thread image_linux.go
if err := unix.Ftruncate(fd, end); err != nil {
return 0, err
}
buffer := bufio.NewWriter(&output)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

bufio.NewWriter uses the default 4 KB buffer, so the payload flushes to pwrite every 4 KB. Since the encoder emits many tiny writes (per-object tag + varints), buffering is load-bearing here — but for large state images a bigger buffer (e.g. bufio.NewWriterSize(&output, 64<<10)) would materially cut the number of pwrite syscalls at negligible memory cost. Tuning only, not a correctness issue.

Comment thread image_linux.go
}
mem, err := unix.Mmap(fd, mapOffset, delta+n+16, unix.PROT_READ|unix.PROT_WRITE, unix.MAP_SHARED)
if err != nil {
// An unwritten result must keep its following header unpublished.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

This comment reads as a prohibition ("must keep ... unpublished"), but the next line actively writes an all-zero header at the following image's offset. The mechanism is proactive zeroing so a reader walking to the next offset sees a zero-length (rejected) image. Consider rewording to describe the action, e.g. "Zero the following image's header so the next result reads as unpublished until it is written."

Comment thread image_linux.go
n = max(n, 0)
w.offset += int64(n)
if err == nil && n != len(p) {
err = io.ErrShortWrite

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

A short Pwrite (err == nil && n != len(p)) is turned into io.ErrShortWrite and returned immediately, after advancing w.offset by the partial n. For a memfd on tmpfs this effectively never happens, so it's safe in practice — but since imageWriter is a general io.Writer fed through bufio, the more robust choice is to loop on the remainder (p = p[n:]) and only give up when Pwrite returns n == 0, nil. As-is, the partial-write branch is essentially unreachable/untested and would advance the offset past what was persisted. A one-line comment noting the reliance on tmpfs semantics would help if you keep it.

@MeteorsLiu
MeteorsLiu merged commit 534b9d1 into xgo-dev:main Sep 20, 2026
6 of 7 checks passed
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