Profiles
A profile names what a VM boots — a kernel, an initramfs, a command line, a guest OS — in provium.toml. Tests pick a profile by name when they create a VM. This page covers the practical patterns.
The configuration field reference is on provium.toml. A profile can also build its own artifacts before booting rather than pointing at files already on disk — see Dynamic profiles.
When you need more than one profile #
For most projects, one profile is enough — peios, pointing at the latest build. You'd add more when:
- You're testing across kernel versions (
peios-stable,peios-mainline). - You want a debug build available for diagnosing failures (
peios-debug). - You're gating tests on a feature flag in the kernel (
peios-prefeatx,peios-postfeatx). - You're testing a port to a new architecture (
peios-arm64).
Declaring multiple profiles #
[]
= "/build/peios/bzImage"
= "/build/peios/initrd.cpio.gz"
= "console=ttyS0 quiet"
[]
= "/build/peios-debug/bzImage"
= "/build/peios-debug/initrd.cpio.gz"
= "console=ttyS0 debug loglevel=7 nokaslr"
[]
= "/build/peios-stable/bzImage"
= "/build/peios-stable/initrd.cpio.gz"
= "console=ttyS0 quiet"
Tests pick:
provium:
provium:
provium:
A test can mix profiles in the same file — useful for compatibility testing:
test
One directory per profile #
Profiles do not have to be written in provium.toml at all. [profiles] from_dir reads them from a directory, one subdirectory each:
[]
= ["tests"]
[]
= "profiles"
profiles/
kernel-only/
profile.provium.toml # the profile
peiso.toml # whatever else it needs, beside it
full-system/
profile.provium.toml
peiso.toml
Everything a discovered profile names is relative to its own directory, and its build runs there. So a profile directory is self-contained: it can be moved, copied or renamed without rewriting what is inside it, and adding one is mkdir rather than an edit to a central list.
Prefer this when profiles carry files of their own — an image spec, a package manifest, a vendored initrd — and especially when the repository's purpose is holding many of them. Prefer inline blocks when a profile is three lines pointing at paths that already exist.
Profile choice patterns #
Default vs debug #
The most common split: a fast peios build for the default loop, and a peios-debug build with loglevel=7, nokaslr, and (probably) KASAN/UBSAN enabled. Use the debug profile when reproducing a kernel bug:
test
Cross-version compatibility #
Two profiles, one per release line. Ship a small handful of cross-version tests:
test
test
Tag these cross-version and gate via --no-tag cross-version in the dev loop. CI runs them on a nightly cadence with --include-slow.
Booting only a kernel #
A profile that names no initrd boots the agent overlay alone: the agent is PID 1 and there is no userspace at all. Paired with a root composed to hold nothing but the kernel, that gives a VM in which the only thing a test can reach is the kernel — so a failure is attributable to it and not to something in userspace that happened to be installed.
# profiles/kernel-only/profile.provium.toml
= "./build.sh {out}"
= "{out}/root"
= "console=hvc0 quiet panic=1"
The build is a script beside the profile rather than a peiso root one-liner because Provium runs it on every invocation: --out must not already exist, Provium never wipes {out}, and composing unconditionally can cost far more than the tests do.
No kernel either: Provium finds it inside the composed root. Tests then drive the kernel directly, through the agent's syscall interface rather than through any command:
test
Feature-flag gating #
Two profiles built from the same source with one feature toggled:
[]
= "/build/peios-prefeatx/bzImage" # FEATX disabled
# …
[]
= "/build/peios-postfeatx/bzImage" # FEATX enabled
# …
Tests that exercise FEATX-specific behaviour pick peios-postfeatx; regression tests run against both.
test
Per-VM cmdline overrides #
The profile's cmdline is the default; kernel_cmdline in vm:boot(opts) overrides it for one VM:
local vm = provium:
vm:
This is useful for one-off testing of cmdline-sensitive features. For cmdline configurations you use repeatedly, declare a dedicated profile.
To add a parameter rather than restate the whole line, kernel_cmdline_append keeps the profile's tokens and puts yours after them:
vm:
Where an appended token repeats one the profile already sets, the kernel takes the last occurrence, so the appended value wins.
Default profile selection #
One subcommand takes an optional profile arg and falls back to "the first profile in provium.toml sorted by name" when you omit it:
| Subcommand | Behaviour |
|---|---|
provium repl --fixture <path> (no profile) | Boots the first profile by sorted name. |
That is a boot-time choice and nothing more. It does not narrow the fixture cache key: the test runner, provium fixture build, provium fixture rebuild, provium fixture stale and provium repl --fixture all fold every profile's kernel and initrd into the key, so they address the same cache entry however many profiles you have configured. Pre-warming in CI with provium fixture build warms the entry the runner then reads.
To make the REPL default predictable, name your most common profile so it sorts first alphabetically. aaa-default is ugly but it works; peios is fine when it's your only profile.
What happens to the cache when profiles change #
The fixture cache key folds in the kernel and initrd identifiers of every profile in provium.toml, sorted by name for determinism (the full key model is on fixtures and dependencies). Practical consequences for profile changes specifically:
| Action | Cache effect |
|---|---|
| Edit a kernel image (any profile) | Every fixture invalidates. |
| Edit an initrd image (any profile) | Every fixture invalidates. |
| Add a new profile | Every fixture invalidates (the new profile's kernel/initrd are folded in). |
| Remove a profile | Every fixture invalidates. |
| Rename a profile | Usually invalidates everything (the fold order follows profile names). |
Edit cmdline on a profile | Cache is unaffected (cmdline isn't in the key). |
Change cache_dir | Cache is unaffected — the new dir is just empty. |
This is deliberately conservative. A new profile means a new kernel could behave differently, so the existing fixtures might be subtly stale. Rather than guess, the harness rebuilds.
If you need to add a profile without invalidating the cache, you can't. Either accept the rebuild or use a sibling provium.toml with --config alt-config.toml.
Multi-arch profiles (preview) #
In v1, the QemuVmm backend invokes qemu-system-x86_64 exclusively — there's no per-profile arch field yet. To run on aarch64, you'd have to swap the binary at the harness level (not currently exposed).
When multi-arch lands, the profile is the natural place for an arch = "x86_64" / arch = "aarch64" field.
See also #
- provium.toml reference — every field.
- VMs and profiles —
provium:vm(name, profile, opts?). - Fixtures and dependencies — what triggers a fixture rebuild.