Skip to content

atelet: measure what a snapshot image costs, not how long it is - #931

Merged
Max Smythe (maxsmythe) merged 3 commits into
agent-substrate:mainfrom
chw120:atelet-snapshot-allocated-size
Oct 3, 2026
Merged

Max Smythe (maxsmythe) merged 3 commits into
agent-substrate:mainfrom
chw120:atelet-snapshot-allocated-size

Conversation

@chw120

@chw120 Chenyi Wang (chw120) commented Aug 13, 2026 •

Copy link
Copy Markdown
Collaborator

atelet.snapshot.size read info.Size() for every image it recorded. For the gVisor images that is right, but the micro-VM memory image is sparse: cloud-hypervisor creates memory-ranges at the guest's full RAM size and writes only the pages the guest ever touched. Its length is therefore a constant — the VM's configured memory — so the metric reported the same number for a guest that had just booted and one that had filled its RAM. On a live counter actor it read 2147483648 for a file that occupies 163577856 bytes: the configured 2048 MiB, every time, on every actor.

Record st_blocks*512 instead, which is what the filesystem actually gave the file (including delayed-allocation blocks before writeback on ext4/XFS/btrfs). Sparse or not, that is the answer to "what did this checkpoint cost", and it is the figure the snapshot's transfer time and storage bill follow.

The count rounds up to a block, so the small JSON images beside the memory one now over-report by under 4 KiB. That is noise on a histogram whose first bucket boundary is 1 MB, and the gVisor images are dense, so for them the two readings agree to within that rounding.

docs/observability.md and docs/metrics/registry/metrics.yaml described this metric as the uncompressed size of a gVisor image, which it was back when gVisor was the only sandbox. They now say what is recorded, and why the two sandboxes read differently.

It's a good idea to open an issue first for discussion.

  • Tests pass
  • [] Appropriate changes to documentation are included in the PR

@chw120

Copy link
Copy Markdown
Collaborator Author

The previous snapshot size metric did not consider the micro-VM case, so this update ensures both scenarios are supported. Please let me know if this approach is correct. Thanks.

cc: Benjamin Elder (@BenTheElder) Max Smythe (@maxsmythe) Haven Xia (@HavenXia)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Thanks, added a few comments, but looks good overall!

We should probably also wire atelet.snapshot.size to PlatformMetricPrefixes e2e tests, it can also be a follow-up, though.

Comment thread cmd/atelet/metrics_test.go
Comment thread cmd/atelet/main.go Outdated
@chw120
Chenyi Wang (chw120) force-pushed the atelet-snapshot-allocated-size branch from 9996410 to 1dc089d Compare August 24, 2026 22:23
@chw120

Copy link
Copy Markdown
Collaborator Author

Thanks, added a few comments, but looks good overall!

We should probably also wire atelet.snapshot.size to PlatformMetricPrefixes e2e tests, it can also be a follow-up, though.

Added "atelet_snapshot_size" into e2e PlatformMetricPrefixes.

@chw120

Copy link
Copy Markdown
Collaborator Author

Thanks Krisztian F (@krisztianfekete) for review. I have resolved comments. Please review again.

Comment thread cmd/atelet/main.go Outdated
Comment thread cmd/atelet/main.go Outdated

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

for upload we can just do the compressed size, for pause ... hmm, this is complicated. I don't think the current approach is quite correct either.

thanks for working on this

@bowei Bowei Du (bowei) added kind/bug Something isn't working / bugfixes area/observability area/node labels Sep 17, 2026
@Nishanth29

Copy link
Copy Markdown
Contributor

Still seeing this on a microVM metal run: every memory-ranges sample is 2147483648, while atelet's upload log shows populated_bytes ≈ 294 MiB for the same files. #1725 now collects memory-ranges in the benchmark telemetry, so this fix makes those sizes correct.

+1 to Ben's SEEK_DATA/SEEK_HOLE approach.

Micro-VM memory-ranges snapshot files are sparse files whose logical size equals
the guest's configured RAM, while ateom skips fsync before handing checkpoint
files to atelet so dirty pages remain under ext4 delayed allocation. Walk
SEEK_DATA/SEEK_HOLE extents to record uncompressed populated bytes, excluding
sparse holes while still counting unwritten delalloc extents in the page cache.
@chw120
Chenyi Wang (chw120) force-pushed the atelet-snapshot-allocated-size branch from 8653be5 to 21396b7 Compare October 1, 2026 00:21
Comment thread cmd/atelet/main.go Outdated
Comment thread cmd/atelet/main.go Outdated
Comment thread cmd/atelet/main.go Outdated
Comment thread cmd/atelet/metrics_test.go Outdated
Comment thread cmd/atelet/main.go Outdated
Record st_blocks*512 (allocatedBytes) in atelet.snapshot.size rather than
apparent file size (st_size) so sparse micro-VM memory-ranges images
report allocated bytes instead of the guest RAM ceiling. On Linux,
ext4/XFS/btrfs include delayed-allocation blocks in st_blocks before
writeback, so the existing Lstat/Stat FileInfo is sufficient without
extra syscalls.
@chw120

Copy link
Copy Markdown
Collaborator Author

Note: moved back to st_blocks*512 since ext4 (ext4_file_getattr), XFS, and btrfs already include delayed-allocation blocks in st_blocks before writeback, avoiding the extra open and per-extent SEEK_DATA/SEEK_HOLE syscalls on the checkpoint path.

@maxsmythe Max Smythe (maxsmythe) left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

LGTM

@maxsmythe
Max Smythe (maxsmythe) added this pull request to the merge queue Oct 3, 2026
Merged via the queue into agent-substrate:main with commit bec4681 Oct 3, 2026
10 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/node area/observability kind/bug Something isn't working / bugfixes

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants