Skip to content

feat: switch to a per-device metrics model for vsock and rng devices - #5599

Open
aerosouund wants to merge 10 commits into
firecracker-microvm:mainfrom
aerosouund:vmm-parallel
Open

aerosouund wants to merge 10 commits into
firecracker-microvm:mainfrom
aerosouund:vmm-parallel

Conversation

@aerosouund

@aerosouund aerosouund commented Dec 29, 2025 •

Copy link
Copy Markdown
Contributor

Changes

Building on the original PR and addressing the reviewer comments.
With the following remarks:

  • Vsock device metrics are keyed in the btreemap by the guest CID which is hardcoded for test instance to be 52. if the desire is to run the tests in a given file, it may be needed to not hardcode it
  • Entropy device metrics use a random generated UUID as the key of the map, because entropy devices don't have a unique identifier in the system that distinguishes them from one another (if one exists, let me know about it)

Reason

Closes #4709

License Acceptance

By submitting this pull request, I confirm that my contribution is made under
the terms of the Apache 2.0 license. For more information on following Developer
Certificate of Origin and signing off your commits, please check
CONTRIBUTING.md.

PR Checklist

  • I have read and understand CONTRIBUTING.md.
  • I have run tools/devtool checkbuild --all to verify that the PR passes
    build checks on all supported architectures.
  • I have run tools/devtool checkstyle to verify that the PR passes the
    automated style checks.
  • I have described what is done in these changes, why they are needed, and
    how they are solving the problem in a clear and encompassing way.
  • I have updated any relevant documentation (both in code and in the docs)
    in the PR.
  • I have mentioned all user-facing changes in CHANGELOG.md.
  • If a specific issue led to this PR, this PR closes the issue.
  • When making API changes, I have followed the
    Runbook for Firecracker API changes.
  • I have tested all new and changed functionalities in unit tests and/or
    integration tests.
  • I have linked an issue to every new TODO.

  • This functionality cannot be added in rust-vmm.

@aerosouund
aerosouund force-pushed the vmm-parallel branch 5 times, most recently from ddcbe7a to 3c724e5 Compare December 29, 2025 20:26
@aerosouund
aerosouund marked this pull request as ready for review December 29, 2025 20:26

@Manciukic Manciukic left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Thanks for the contibution!

I only had a quick look, but I think we can simplify the logic for devices that only allow a single instance. Maybe a simple RwLock<Arc<Metrics>> would do the job.

Once we align on the solution for single-entity devices, we should also tackle all other devices using global metrics (like mem and pmem which we recently added), and simplify their unit tests as well.

Please keep different devices in different commits for clarity (and feel free to tackle one at a time if you prefer).

I'm also not a big fan of the current per-device metrics for net and block sharing the same metrics Arc if the ID happens to be the same, which defeats the purpose of not sharing metrics. As in real life we can't have devices with the same ID, I'd rather have the device create the object and replace whatever is in the hashmap rather than the other way around.

Comment thread src/vmm/src/devices/virtio/net/tap.rs Outdated
Comment thread src/vmm/src/devices/virtio/rng/metrics.rs Outdated
Comment thread src/vmm/src/devices/virtio/rng/device.rs Outdated
@aerosouund

Copy link
Copy Markdown
Contributor Author

@Manciukic

Interesting thoughts for sure.

I'm also not a big fan of the current per-device metrics for net and block sharing the same metrics Arc if the ID happens to be the same, which defeats the purpose of not sharing metrics. As in real life we can't have devices with the same ID, I'd rather have the device create the object and replace whatever is in the hashmap rather than the other way around.

How does this fit with your previous statement of storing a single Arc in the RwLock ? single instance devices create their arc during initialization and store it directly in the RwLock and multi instance devices also create their own metrics but store it in the hashmap themselves rather than call alloc to give them a metrics instance ?

I think it sounds like a good way forward. Let me know if i misunderstood or you have any other opinions

@Manciukic

Copy link
Copy Markdown
Contributor

single instance devices create their arc during initialization and store it directly in the RwLock and multi instance devices also create their own metrics but store it in the hashmap themselves rather than call alloc to give them a metrics instance ?

Yes, that's what I meant. It seems it would simplify your implementation for the rng device quite much

@aerosouund
aerosouund force-pushed the vmm-parallel branch 4 times, most recently from 3cd82a4 to 602c7a0 Compare January 16, 2026 14:03
@aerosouund

Copy link
Copy Markdown
Contributor Author

Hello @Manciukic

I have switched to single instance model in the rng device using a OnceLock and made the vsock device own the creation of its metrics instance. If the current pattern looks satisfactory, i can switch the net and block devices to follow the same pattern, and address the other comments on the PR. Let me know what you think

Comment thread src/vmm/src/devices/virtio/rng/device.rs Outdated
Comment thread src/vmm/src/devices/virtio/rng/metrics.rs Outdated
Comment thread src/vmm/src/devices/virtio/rng/device.rs Outdated
@aerosouund
aerosouund force-pushed the vmm-parallel branch 3 times, most recently from 50c057d to 9b6b94c Compare January 22, 2026 18:28
@aerosouund

Copy link
Copy Markdown
Contributor Author

@Manciukic
Reworked the net and block devices to own their metrics creation and left a question regarding the macro thing you mentioned. let me know what you think

@Manciukic Manciukic added the Status: WIP Indicates that an issue is currently being worked on or triaged label Jan 28, 2026
@Manciukic Manciukic self-assigned this Jan 28, 2026

@Manciukic Manciukic left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I only skimmed through it but I think the approach is the right one. A few things to iron out:

  • We can improve all those unit tests that are reading the old values, doing an operation, and reading the new value and comparing. This was needed because of the global metrics. They should all now become simple assertions on the value of the metric after the operation. We don't need that macro anymore as well
  • We should split changes to different devices in different commits to make it simpler to review. The same for unrelated changes and the improvement to tests
  • Please ensure the PR passes the formatter and buildchecks by running the devtool (I left instructions in one of the comments)
  • We should do the same for all other devices to enable testing in parallel. If you have the time that'd be highly appreciated!

Thanks again for the contribution and sorry for the late reply!

Comment thread src/vmm/src/devices/virtio/net/tap.rs Outdated
Comment thread src/vmm/src/devices/virtio/rng/device.rs Outdated
Comment thread src/vmm/src/devices/virtio/rng/device.rs Outdated
Comment thread src/vmm/src/devices/virtio/rng/device.rs Outdated
Comment thread src/vmm/src/devices/virtio/rng/device.rs Outdated
Comment thread src/vmm/src/devices/virtio/rng/metrics.rs
@codecov

codecov Bot commented Feb 3, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 82.58427% with 31 lines in your changes missing coverage. Please review.
✅ Project coverage is 83.19%. Comparing base (f23a213) to head (33f7f7a).

⚠️ Current head 33f7f7a differs from pull request most recent head fc7fe89

Please upload reports for the commit fc7fe89 to get more accurate results.

Files with missing lines Patch % Lines
src/vmm/src/devices/virtio/rng/device.rs 62.50% 6 Missing ⚠️
...rc/vmm/src/devices/virtio/balloon/event_handler.rs 16.66% 5 Missing ⚠️
src/vmm/src/devices/virtio/mem/device.rs 85.18% 4 Missing ⚠️
src/vmm/src/devices/virtio/vsock/unix/muxer.rs 69.23% 4 Missing ⚠️
src/vmm/src/devices/virtio/balloon/device.rs 82.35% 3 Missing ⚠️
src/vmm/src/devices/virtio/vsock/device.rs 80.00% 3 Missing ⚠️
src/vmm/src/devices/virtio/vsock/event_handler.rs 75.00% 2 Missing ⚠️
src/vmm/src/devices/virtio/balloon/metrics.rs 75.00% 1 Missing ⚠️
src/vmm/src/devices/virtio/mem/metrics.rs 75.00% 1 Missing ⚠️
src/vmm/src/devices/virtio/rng/metrics.rs 75.00% 1 Missing ⚠️
... and 1 more
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #5599      +/-   ##
==========================================
- Coverage   83.34%   83.19%   -0.16%     
==========================================
  Files         277      277              
  Lines       31679    31603      -76     
==========================================
- Hits        26404    26291     -113     
- Misses       5275     5312      +37     
Flag Coverage Δ
5.10-m5n.metal 83.32% <82.58%> (-0.17%) ⬇️
5.10-m6a.metal 82.69% <82.58%> (-0.18%) ⬇️
5.10-m6g.metal 80.27% <82.58%> (-0.18%) ⬇️
5.10-m6i.metal 83.32% <82.58%> (-0.16%) ⬇️
5.10-m7a.metal-48xl 82.68% <82.58%> (-0.17%) ⬇️
5.10-m7g.metal 80.28% <82.58%> (-0.18%) ⬇️
5.10-m7i.metal-24xl 83.29% <82.58%> (-0.16%) ⬇️
5.10-m7i.metal-48xl 83.29% <82.58%> (-0.17%) ⬇️
5.10-m8g.metal-24xl 80.28% <82.58%> (-0.18%) ⬇️
5.10-m8g.metal-48xl 80.28% <82.58%> (-0.18%) ⬇️
5.10-m8i.metal-48xl 83.29% <82.58%> (-0.16%) ⬇️
5.10-m8i.metal-96xl 83.29% <82.58%> (-0.16%) ⬇️
5.10-m9g.metal-48xl 80.28% <82.58%> (-0.18%) ⬇️
6.1-m5n.metal 83.45% <82.58%> (-0.17%) ⬇️
6.1-m6a.metal 82.84% <82.58%> (-0.17%) ⬇️
6.1-m6g.metal 80.27% <82.58%> (-0.18%) ⬇️
6.1-m6i.metal 83.45% <82.58%> (-0.16%) ⬇️
6.1-m7a.metal-48xl 82.83% <82.58%> (-0.17%) ⬇️
6.1-m7g.metal 80.27% <82.58%> (-0.18%) ⬇️
6.1-m7i.metal-24xl 83.46% <82.58%> (-0.17%) ⬇️
6.1-m7i.metal-48xl 83.47% <82.58%> (-0.16%) ⬇️
6.1-m8g.metal-24xl 80.27% <82.58%> (-0.18%) ⬇️
6.1-m8g.metal-48xl 80.28% <82.58%> (-0.18%) ⬇️
6.1-m8i.metal-48xl 83.47% <82.58%> (-0.16%) ⬇️
6.1-m8i.metal-96xl 83.47% <82.58%> (-0.16%) ⬇️
6.1-m9g.metal-48xl 80.28% <82.58%> (-0.18%) ⬇️
6.18-m5n.metal 83.45% <82.58%> (-0.16%) ⬇️
6.18-m6a.metal 82.84% <82.58%> (-0.17%) ⬇️
6.18-m6g.metal 80.37% <82.58%> (-0.18%) ⬇️
6.18-m6i.metal 83.45% <82.58%> (-0.16%) ⬇️
6.18-m7a.metal-48xl 82.83% <82.58%> (-0.17%) ⬇️
6.18-m7g.metal 80.38% <82.58%> (-0.18%) ⬇️
6.18-m7i.metal-24xl 83.47% <82.58%> (-0.16%) ⬇️
6.18-m7i.metal-48xl 83.46% <82.58%> (-0.16%) ⬇️
6.18-m8g.metal-24xl 80.38% <82.58%> (-0.18%) ⬇️
6.18-m8g.metal-48xl 80.38% <82.58%> (-0.18%) ⬇️
6.18-m8i.metal-48xl 83.47% <82.58%> (-0.16%) ⬇️
6.18-m8i.metal-96xl 83.47% <82.58%> (-0.16%) ⬇️
6.18-m9g.metal-48xl 80.38% <82.58%> (-0.18%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@Manciukic

Copy link
Copy Markdown
Contributor

FYI I've kicked off the CI build: https://buildkite.com/firecracker/firecracker-pr/builds/15702

@aerosouund

aerosouund commented Feb 5, 2026 •

Copy link
Copy Markdown
Contributor Author

@Manciukic
Thanks for taking the time to review it. Will address your comments along with the CI failures shortly

@aerosouund
aerosouund force-pushed the vmm-parallel branch 9 times, most recently from cbadb04 to 3914f89 Compare August 24, 2026 00:41
@aerosouund

aerosouund commented Aug 24, 2026 •

Copy link
Copy Markdown
Contributor Author

@Manciukic
Thank you for the thorough review.
I have addressed your comments, please check the individual responses on the threads you started and ping me if anything can still be made better.

Apart from the threads i have:

  • Applied the same pattern to the block vhost user device, had missed it originally
  • I have squashed all commits that contain test fixes into the original device commits
  • Used absolute value assertion and included that in the original device commits
  • Ensured checkbuild/checkstyle pass on the current state of the code after rebasing on main

Regarding msix/mmds logger globals, i haven't taken a look at them in the context of this PR. I can do that if you'd like, or in a follow up which would also include the change of RUST_TEST_THREADS to be more than one

@AdaAibaby

Copy link
Copy Markdown

Independently verified the current head (f01c9ba) on a clean checkout:

  • cargo clippy --all --all-targets -- -D warnings passes (exit 0) — the earlier concern about clippy being red doesn't reproduce on this head.
  • All 23 per-device metrics unit tests pass under RUST_TEST_THREADS=32 (balloon, block, mem, rng, net, pmem, vhost-user, vsock, serial — both the single-instance serialization tests and the multi-instance aggregation tests).
  • The broader devices::virtio parallel run shows some failures + an IO Safety violation abort, but I confirmed these reproduce identically on main (9cbb96f) and are caused by the test host lacking /dev/kvm, not by this PR.

So the metrics rework itself is parallel-clean and clippy-clean.

Comment thread src/vmm/src/pci/msix.rs Outdated
Comment thread src/vmm/src/devices/virtio/vsock/unix/muxer.rs Outdated
Comment thread src/vmm/src/devices/virtio/mem/device.rs Outdated
Comment thread src/vmm/src/devices/virtio/rng/metrics.rs Outdated
@aerosouund

Copy link
Copy Markdown
Contributor Author

@Manciukic
Thanks again for looking at it. Addressed the current set of comments. Let me know what can i help with next

Comment thread src/vmm/src/devices/virtio/balloon/mod.rs Outdated
- turn the METRICS static variable into an rwlock of an option of an arc
  of BalloonDeviceMetrics. There can only be one balloon device per
  guest. the device creates the arc during init and sets it as METRICS
- replace access to METRICS for incrementing with self.metrics
- serialize an empty BalloonDeviceMetrics instance when METRICS has not
  been set so the schema stays stable
- replace check_metric_after_block with traditional asserts
- make report_balloon_event_fail take an arc of BalloonDeviceMetrics
  as an argument to avoid having to reset the METRICS instance after
  every test. given that each device will instantiate the metrics
  instance during the start of every test
- remove the comparison of the empty local metrics instance with the
  flushed global instance in test_balloon_dev_metrics

Signed-off-by: aerosouund <aerosound161@gmail.com>
- delete the BlockMetricsPerDevice type and make METRICS an rwlock of a
  btreemap directly, keyed on the block device id
- make a device create its own arc of BlockDeviceMetrics during init
  then add it to the METRICS map
- replace access to METRICS for incrementing with self.metrics
- replace check_metric_after_block with traditional asserts
- change values in tests with asserts that check the total not the delta

Signed-off-by: aerosouund <aerosound161@gmail.com>
- delete the PmemMetricsPerDevice type
- turn METRICS into an rwlock of the metrics btreemap directly
- make a device create its own metrics instance then add it to
  the METRICS map which is keyed on the device ids
- delete test_max_pmem_dev_metrics test because if the we remove
  reliance on the METRICS instance, it just becomes a test that checks
  counters incremenet for a group of metrics instance in a vector.
  meaning that it adds nothing over test_single_pmem_dev_metrics
- replace test_single_pmem_dev_metrics with
  test_pmem_metrics_aggregation which exercises aggregate() and
  the serialized output on local instances instead of the global

Signed-off-by: aerosouund <aerosound161@gmail.com>
- turn the METRICS static variable into an rwlock of an option of an arc
  of EntropyDeviceMetrics. There can only be one rng device per guest.
  the device creates the arc during init and sets it as METRICS
- replace access to METRICS for incrementing with self.metrics
- serialize an empty EntropyDeviceMetrics instance when METRICS has not
  been set so the schema stays stable
- replace check_metric_after_block with traditional asserts
- change test values to assert the absolute value not the delta
- depend on a local instance in test_rng_dev_metrics

Signed-off-by: aerosouund <aerosound161@gmail.com>
- delete the VhostUserMetricsPerDevice type and make METRICS an rwlock
  of a btreemap directly, keyed on the vhost-user device id
- make a device create its own arc of VhostUserDeviceMetrics during init
  then add it to the METRICS map instead of going through alloc()
- drop the now unused per-device allocation helper and its tests

Signed-off-by: aerosouund <aerosound161@gmail.com>
- delete the NetMetricsPerDevice type and make METRICS
  an rwlock of a btreemap directly, keyed on the net device id field.
- during net device initialization push the an arc of device metrics to
  the metrics map.
- replace access to METRICS for incrementing with self.metrics
- replace check_metric_after_block with traditional asserts that check
  the absolute count not the delta
- remove reliance on the global metrics instance in
  test_max_net_dev_metrics and test_single_net_dev_metrics by running
  tests against local instances

Signed-off-by: aerosouund <aerosound161@gmail.com>
- turn the METRICS static variable into an rwlock of an option of an arc
  of VirtioMemDeviceMetrics. There can only be one mem device per guest.
  the device creates the arc during init and sets it as METRICS
- replace access to METRICS for incrementing with self.metrics
- add derive default to VirtioMemDeviceMetrics
- serialize an empty VirtioMemDeviceMetrics instance when METRICS has
  not been set so the schema stays stable
- make the device tests assert absolute metric counts instead of a
  captured baseline plus a delta

Signed-off-by: aerosouund <aerosound161@gmail.com>
- turn the METRICS static variable to an Rwlock of option of arc of
  VsockDeviceMetrics. There can only be one vsock device per guest.
- the vsock multiplexer is the central piece and the entity that gets
  created first among the different vsock structs. make it create an
  arc of VsockDeviceMetrics and set that as the METRICS variable.
- thread that arc through the vsock device, its connections and the
  persist paths instead of reaching for the global.
- remove check_metrics_after_block use and replace it with traditional
  asserts. update the assertion values in select tests to make it
  reflect the real value not the delta

Signed-off-by: aerosouund <aerosound161@gmail.com>
- it has been replaced by pure asserts

Signed-off-by: aerosouund <aerosound161@gmail.com>
- its not in use anywhere after the previous commits

Signed-off-by: aerosouund <aerosound161@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Status: WIP Indicates that an issue is currently being worked on or triaged

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Allow Running vmm Unittests in Parallel

3 participants