Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ jobs:
steps:
- name: Install the build tools
run: |
dnf install -y --setopt=install_weak_deps=False git dnf5-plugins gcc make python3 pkgconf-pkg-config clap-devel \
dnf install -y --setopt=install_weak_deps=False git dnf5-plugins gcc make python3 pkgconf-pkg-config clap-devel lv2-devel \
pipewire-jack-audio-connection-kit-devel pipewire pipewire-utils iproute util-linux procps-ng diffutils python3-jsonschema

- uses: actions/checkout@v4
Expand Down
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,5 @@ tests/format-test
tests/plugin-hostd-fixture.lv2/*.so
/plugin-hostd-probe
tests/probe-child
tests/lv2-probe-child
tests/rt_interpose.so
13 changes: 10 additions & 3 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ private-refs:

# clean rule
clean:
@rm -f src/*.o $(PROG) $(PROBE) tests/probe-child $(FAKE) $(PIN_TEST) $(FORMAT_TEST) $(GEN) tests/stress.clap tests/jack_levels tests/host_scenarios $(LV2_FIXTURE)
@rm -f src/*.o $(PROG) $(PROBE) tests/probe-child tests/lv2-probe-child tests/rt_interpose.so $(FAKE) $(PIN_TEST) $(FORMAT_TEST) $(GEN) tests/stress.clap tests/jack_levels tests/host_scenarios $(LV2_FIXTURE)

# the daemon against workers that are not plugin hosts at all (tests/fake-host speaks the same protocol and can be
# made to die on cue): placement, forwarding, ledger, replay, attribution, the storm bound; no jack, no plugin
Expand Down Expand Up @@ -164,7 +164,7 @@ tests/stress.clap: tests/stress_plugin.c
$(CC) $(CLAP_CFLAGS) $(CFLAGS) -Werror -shared -o $@ $<

# every guard broken on purpose, one at a time: its test must go red
sabotage: $(PROG) $(FAKE)
sabotage: $(PROG) $(FAKE) tests/lv2-probe-child tests/rt_interpose.so $(LV2_FIXTURE)
MOD_HOST_DIR=$(MOD_HOST_DIR) FAKE_HOST=./$(FAKE) python3 tests/sabotage.py

# the jack server the real-worker tests run over: pipewire's own jack implementation (default) or JACK2's jackd
Expand Down Expand Up @@ -261,9 +261,16 @@ check-schema:

# the probe runner over the stress plugin: crash, hang and a process left behind each give the named outcome in a document
# that validates
test-probe: $(PROBE) tests/probe-child tests/stress.clap
test-probe: $(PROBE) tests/probe-child tests/stress.clap tests/lv2-probe-child tests/rt_interpose.so $(LV2_FIXTURE)
python3 tests/probe_test.py

# lv2_measure's arguments and lines, with no lilv and no interposer: the LV2 tests of the runner load the fixture with it
tests/lv2-probe-child: tests/lv2_probe_child.c include/plugin-hostd/pin.h
$(CC) -Iinclude $(shell $(PKG_CONFIG) --cflags lv2) $(CFLAGS) -Wall -Wextra -Werror -o $@ $< -ldl

tests/rt_interpose.so: tests/rt_interpose_stub.c
$(CC) $(CFLAGS) -Werror -shared -o $@ $<

tests/probe-child: tests/probe_child.c
$(CC) $(CLAP_CFLAGS) $(CFLAGS) -Wall -Wextra -Werror -o $@ $< -ldl

Expand Down
16 changes: 15 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -303,9 +303,23 @@ Probing a plugin
----------------

`plugin-hostd-probe run` loads a plugin in a child process under limits and writes down what happened, as facts only: no
verdict. The child is clap-qualify today; the runner never loads plugin code itself.
verdict. The child is clap-qualify for a CLAP plugin. For an LV2 plugin, named `lv2:<uri>`, the child is plugin-qualify's
`lv2_measure`, found at run time in `/usr/libexec/plugin-qualify` (plugin-qualify is not a dependency of this package).
The runner never loads plugin code itself.

plugin-hostd-probe run --out probe.json --log probe.stderr.log /usr/lib64/clap/plate.clap org.example.plate
plugin-hostd-probe run --out probe.json lv2:http://example.org/plate

An LV2 plugin is measured the way plugin-qualify's LV2 hosting pass measures it today, in two children under the same
limits and the same wall clock. The first child (`lv2_measure --pin`) pins the bundle's files without instantiating the
plugin. The second measures at the highest of `--rates`, in blocks of `--quantum`, with 30 instantiate and destroy cycles
and 3 swept rt-safety runs. It runs under plugin-qualify's interposer (`rt_interpose.so` beside the child) and the noise
stimulus. The document's binary is the plugin's library, with every pinned file of the bundle listed. The rate's grid
point carries what run() did under the interposer, and `behaviour` carries the lifecycles, the threads and the features
the plugin requires. A plugin no bundle holds exits 3 with no document. A plugin of which nothing could be pinned exits 2
with no document, because the document has no binary to name. Its refusal is a code on stderr: `<plugin>: <code>: <why>`,
`probe.unpinnable` for a bundle the pin cannot cover. Version 1 runs the quick measurement only: the deep lifecycle pass
and the soak stay plugin-qualify's until the probe protocol says which plugins get them and for how long.

The runner kills the whole process tree of the child at its wall clock, and again when the child is done, so a process a
plugin started in a session of its own does not outlive the run. It applies these limits on every Linux: the wall clock,
Expand Down
10 changes: 8 additions & 2 deletions doc/plugin-hostd-probe.1
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,15 @@ plugin\-hostd\-probe \- run a plugin prober under limits and write what happened
.RI [ options ]
.I plugin.clap
.RI [ "clap id" ]
.br
.B plugin\-hostd\-probe run
.RI [ options ]
.BI lv2: uri
.SH DESCRIPTION
.B plugin\-hostd\-probe
starts a program that loads a plugin (clap\-qualify by default) in its own process group, with the portable
starts a program that loads a plugin (clap\-qualify for a CLAP, plugin\-qualify's lv2_measure for an LV2 named
.BI lv2: uri ,
the pin pass and then the measurement at the highest rate, under its interposer) in its own process group, with the portable
limits applied before the exec, and writes the facts of the run as a JSON document: the steps the child reached, how
each ended and the limits that were applied. It gives no verdict. The runner never loads plugin code itself. On the
deadline, on a cancel or when the child is done it kills the whole process tree, including a process the plugin
Expand All @@ -20,7 +26,7 @@ Nothing a plugin prints can enter it.
.SH OPTIONS
.TP
.BI \-\-child " program"
The program that loads the plugin. Default clap\-qualify.
The program that loads the plugin. Default clap\-qualify, and /usr/libexec/plugin\-qualify/lv2_measure for an LV2.
.TP
.BI \-\-rates " R,R,..."
Sample rates to run at. Default 44100,48000,96000,192000.
Expand Down
5 changes: 5 additions & 0 deletions include/plugin-hostd/protocol.h
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,11 @@
#define PHD_PROBE_FORMAT_MINOR 0
#define PHD_PROBE_PROTOCOL_NAME "plugin-hostd.probe-protocol"
#define PHD_PROBE_PROTOCOL_VERSION 1
/* version 1 of the probe protocol runs an LV2 plugin as plugin-qualify's LV2 hosting pass does today
* (LV2_HOSTING_LIFECYCLES, LV2_HOSTING_REPEATS), so the verdicts from its documents equal today's: this many
* instantiate/destroy cycles and swept rt-safety runs, at the highest rate asked for */
#define PHD_PROBE_LV2_LIFECYCLES 30
#define PHD_PROBE_LV2_REPEATS 3

/* how a step, a grid point or the whole run ended: X(id, code, meaning) */
#define PHD_PROBE_OUTCOMES(X) \
Expand Down
Loading
Loading