Skip to content

Load qubes-hcl-report asynchronously and cache it per boot - #332

Open
andreasglashauser wants to merge 1 commit into
QubesOS:mainfrom
andreasglashauser:hcl-report-cache
Open

andreasglashauser wants to merge 1 commit into
QubesOS:mainfrom
andreasglashauser:hcl-report-cache

Conversation

@andreasglashauser

Copy link
Copy Markdown

For: QubesOS/qubes-issues#11081

Constructing the This Device page ran qubes-hcl-report -y synchronously on the main thread. That script shells out to sudo lspci -nnvk, sudo dmidecode, xl info and xl dmesg, so the UI was blocked for its duration on every visit to the page.

The report now runs in a background thread, showing placeholder text while it loads, and its output is cached.

The cache is keyed on /proc/sys/kernel/random/boot_id, so it is discarded after a reboot and reused within one. Every field the report contains is fixed for the lifetime of a boot: hardware identity from dmidecode and lspci, the BIOS version, since a firmware flash takes effect only after a reboot, the virtualization fields parsed out of the xl dmesg boot log, since changing VT-d in firmware likewise needs a reboot, and the running kernel and Xen versions. A time-based expiry would re-run the probe when nothing can have changed, and could still miss a change after a reboot inside the window.

Two cases are deliberately not cached: a failed run, and a report degraded by an incomplete xl dmesg ring buffer, which empties slat and the other virtualization fields. Caching either would make it stick for the rest of the boot. A Refresh button re-runs the report and bypasses the cache, which also covers the one field that can change within a boot, the release string in
/etc/qubes-release.

New tests in qubes_config/tests/test_thisdevice.py cover loading, a cache hit, invalidation on a changed boot id, both non-caching cases, and refresh. Since those tests stub out the worker thread and GLib.idle_add, I also
exercised the real threaded path by running the GUI against qubesadmin.tests.mock_app and confirming it wrote the cache.

Lazy page construction, the other half of #11081, is a separate PR against this repo. The two touch disjoint files and can be merged in either order.

AI disclosure: I did write every code on my own, but I used LLMs for getting reviews & feedback, as well as generating this ticket description from the diff via my own tool running local models.

@marmarek

Copy link
Copy Markdown
Member

What do you think about doing the caching in the qubes-hcl-report script itself (at least if the yaml-only output is selected)?

@andreasglashauser

Copy link
Copy Markdown
Author

What do you think about doing the caching in the qubes-hcl-report script itself (at least if the yaml-only output is selected)?

Yeah thats definitely the better way to fix this. I was already working on the Qubes Global Config for another PR and searched for ways to make it more efficient, which is why I implemented this way.
I will update this PR and open up a new one for doing the caching in qubes-hcl-report itself probably tomorrow.

@andreasglashauser

Copy link
Copy Markdown
Author

Updated this PR: the caching is gone, so all it does now is move the report collection off the main thread and show placeholder text while it runs.

I also dropped the Refresh button that was in the earlier version, it only existed to bypass the cache that used to be here.

Caching in the script: QubesOS/qubes-core-admin#877

@marmarta

Copy link
Copy Markdown
Member

some formatting complaints from linters, but otherwise this looks good to me. Good idea, btw.

@marmarta

Copy link
Copy Markdown
Member

I tested this version and it works perfectly. Could you squash the linter commit into the main commit?

Constructing the This Device page ran qubes-hcl-report synchronously on
the main thread. The report shells out to sudo lspci -nnvk, sudo
dmidecode, xl info and xl dmesg, so the page froze for its duration on
every visit.

The report now runs in a background thread, with placeholder text shown
while it loads.

Caching its output is done in qubes-hcl-report itself, so that every
caller benefits and the script can decide on the basis of data the tool
does not have, such as whether the "xl dmesg" ring buffer was complete.

QubesOS/qubes-issues#11081
@andreasglashauser

Copy link
Copy Markdown
Author

I tested this version and it works perfectly. Could you squash the linter commit into the main commit?

Done.

@marmarek

Copy link
Copy Markdown
Member

PipelineRetry

@codecov

codecov Bot commented Aug 30, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 92.88%. Comparing base (d0e7102) to head (7477b70).
⚠️ Report is 1 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main     #332      +/-   ##
==========================================
+ Coverage   92.79%   92.88%   +0.08%     
==========================================
  Files          66       67       +1     
  Lines       13844    13910      +66     
==========================================
+ Hits        12847    12920      +73     
+ Misses        997      990       -7     

☔ 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.

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.

3 participants