[{"data":1,"prerenderedAt":33},["ShallowReactive",2],{"note-one-worker-per-chain-or-one-process-per-plugin-en":3},{"slug":4,"order":5,"title":6,"summary":7,"measured":8,"topic":9,"toc":10,"html":32},"one-worker-per-chain-or-one-process-per-plugin",100,"\"One worker per chain or one process per plugin: the trade-offs\"","Grouping a chain into one worker saves most of the memory and much of the CPU that one process per plugin spends, and a crash still costs only the plugin that crashed; the price is that plugins sharing a process must be trusted, which is what qualification decides.","Raspberry Pi 5 with Zynthian, 48 kHz, 256 frames, October and November 2026; the versions are named with each figure.","zynthian",[11,14,17,20,23,26,29],{"id":12,"title":13},"what-grouping-buys","What grouping buys",{"id":15,"title":16},"what-it-costs","What it costs",{"id":18,"title":19},"clap-hosting","CLAP hosting",{"id":21,"title":22},"qualification-and-pins","Qualification and pins",{"id":24,"title":25},"mod-host-compatibility","mod-host compatibility",{"id":27,"title":28},"packaging","Packaging",{"id":30,"title":31},"what-is-not-done","What is not done","\u003Cp>plugin-hostd runs a chain in one worker process (grouped) or each plugin in a worker of its own. Zynthian's own hosts sit at\neither end: jalv runs one process per plugin, mod-host every plugin in one process. The figures are in\n\u003Ca href=\"\u002Fnotes\u002Fplugin-hostd-on-a-raspberry-pi-5\">plugin-hostd on a Raspberry Pi 5\u003C\u002Fa> and on the \u003Ca href=\"\u002Fbenchmarks\">benchmarks page\u003C\u002Fa>; they\nmeasure the daemon directly on a private JACK graph, not through Zynthian's engine.\u003C\u002Fp>\n\u003Ch2 id=\"what-grouping-buys\">What grouping buys\u003C\u002Fh2>\n\u003Cul>\n\u003Cli>\u003Cstrong>Memory.\u003C\u002Fstrong> 24 plugins in one chain take 64.1 MB of proportional memory, against 183.1 MB with one worker per plugin and\n109.4 MB under mod-host (plugin-hostd 0.15.9). Under jalv, 24 plugins took 993.6 MB (plugin-hostd 0.15.4). On a 4 GB Pi this is the difference that grows with the chain.\u003C\u002Fli>\n\u003Cli>\u003Cstrong>CPU.\u003C\u002Fstrong> The grouped chain has the lowest DSP load of the hosts measured: 12.51 % for the 24, against 17.76 % with one\nworker per plugin and 15.02 % under mod-host.\u003C\u002Fli>\n\u003Cli>\u003Cstrong>Fewer wake-ups.\u003C\u002Fstrong> One JACK client runs the whole chain. With 16 plugins, the grouped chain made 6023 context switches in\n20 s, against 84 099 with one worker per plugin and 72 292 under mod-host.\u003C\u002Fli>\n\u003Cli>\u003Cstrong>Crash containment.\u003C\u002Fstrong> A lost worker is restarted by the daemon with the links it made itself, in about 340 ms; jalv and\nmod-host lose the process and nothing brings the plugin back. Inside a chain, a member that aborts leaves the others\nplaying (see \u003Ca href=\"\u002Fnotes\u002Fchains-plugins-in-series-in-one-worker\">Chains\u003C\u002Fa>). Links made from outside, as Zynthian's routing is,\nare not restored by the daemon.\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Ch2 id=\"what-it-costs\">What it costs\u003C\u002Fh2>\n\u003Cul>\n\u003Cli>\u003Cstrong>A shared process must be trusted.\u003C\u002Fstrong> A plugin that corrupts memory instead of crashing cleanly can take the chain with it.\nQualification is the guard: a plugin that fails the real-time safety sweep is isolated (it runs in a worker of its own and\nis never grouped), and one that crashes, hangs or fails to load is not offered.\u003C\u002Fli>\n\u003Cli>\u003Cstrong>Isolation has its own cost.\u003C\u002Fstrong> Each isolated plugin is one more worker, one more process and one more JACK client: the\none-worker-per-plugin figures above. On the device, 306 of 1602 plugins qualify as isolated.\u003C\u002Fli>\n\u003Cli>\u003Cstrong>Adding to a chain.\u003C\u002Fstrong> Added into the chain's worker, 24 plugins take 549 ms cold against mod-host's 1459 ms, and from four\nplugins on a warm add is faster than mod-host's; mod-host adds two plugins to a running host faster (44.8 ms against\n55.9 ms).\u003C\u002Fli>\n\u003Cli>\u003Cstrong>Latency\u003C\u002Fstrong> is only the latency the clients declare (none for these plugins). A measured round trip per host needs a\nloopback through an audio interface, and has not been taken.\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Ch2 id=\"clap-hosting\">CLAP hosting\u003C\u002Fh2>\n\u003Cp>Zynthian has no CLAP host of its own: jalv and mod-host host LV2 only. plugin-hostd hosts CLAP in its worker,\nomx-clap-host, and LV2 through the same worker's LV2 adapter, so a chain can mix the two.\u003C\u002Fp>\n\u003Cul>\n\u003Cli>Every one of OpenMixer's own plugins sweeps clean in both formats.\u003C\u002Fli>\n\u003Cli>The CLAP and LV2 builds of one plugin are not interchangeable in cost: at 192 kHz and 512 frames, the LV2 build of one\nchorus costs 592.2 ns per sample at the median against 0.85 for its CLAP build. The reason is not established.\u003C\u002Fli>\n\u003Cli>CLAP behind MOD-UI does not carry over: MOD-UI reads LV2 descriptions, so CLAP ports, parameters, presets and MIDI maps\ndo not reach it. Zynthian's plugin-hostd engine does not go through MOD-UI.\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Ch2 id=\"qualification-and-pins\">Qualification and pins\u003C\u002Fh2>\n\u003Cp>Every plugin on the device is measured once, and plugin-hostd reads the result as a pin per binary: a plugin whose files\nchange is measured again.\u003C\u002Fp>\n\u003Cul>\n\u003Cli>Three classes: \u003Cstrong>suitable\u003C\u002Fstrong>; \u003Cstrong>isolated\u003C\u002Fstrong>, a plugin that fails the real-time safety sweep, run in a worker of its own and\nnever grouped; and \u003Cstrong>unsuitable\u003C\u002Fstrong>, a plugin that crashes, hangs, fails to load or breaks the host.\u003C\u002Fli>\n\u003Cli>LV2 suitability came out the same for jalv, mod-host and plugin-hostd's worker, so qualification does not shrink what\nZynthian offers for LV2: it isolates the plugins found allocating, locking or calling into the kernel on the audio thread,\nand leaves out the ones that crash or hang.\u003C\u002Fli>\n\u003Cli>A plugin plugin-hostd refuses stays on jalv, listed in its menu: nothing the user has disappears.\u003C\u002Fli>\n\u003Cli>Cost is not part of any verdict yet: the probe times 512-frame blocks only, so the menus' cost tags are not from Zynthian's\nown quantum.\u003C\u002Fli>\n\u003Cli>A full qualification of every plugin on a Pi 5 takes about six hours. It runs once per plugin set, not at boot, and a\npackage carries the records of a known set so a fresh device probes only what differs.\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Ch2 id=\"mod-host-compatibility\">mod-host compatibility\u003C\u002Fh2>\n\u003Cp>plugin-hostd speaks mod-host's protocol on its port, so MOD-UI and Zynthian code written for mod-host talk to it unchanged.\nIn a session driven through MOD-UI, 130 of 135 replies were identical. The five that differed: \u003Ccode>connect\u003C\u002Fcode> to the\n\u003Ccode>mod-monitor\u003C\u002Fcode> client (no worker owns it), \u003Ccode>feature_enable aggregated-midi\u003C\u002Fcode> (a worker started later never hears it), and\n\u003Ccode>preset_load\u003C\u002Fcode> of a user preset after a pedalboard reload. Feedback differs by worker: \u003Ccode>transport\u003C\u002Fcode> was reported six times\ninstead of once. The protocol and every verb are in the \u003Ca href=\"\u002Fprojects\u002Fplugin-hostd-protocol\u002Fprotocol\">plugin-hostd-protocol reference\u003C\u002Fa>.\u003C\u002Fp>\n\u003Ch2 id=\"packaging\">Packaging\u003C\u002Fh2>\n\u003Cp>The packages come from the OpenMixer apt repository for Debian 13 arm64: plugin-hostd, omx-clap-host, omx-plugins and\nomx-panel. ZynthianOS Vangelis ships Python 3.13, on which MOD-UI's install recipe did not build; the change that makes it\nbuild is offered to Zynthian. A second apt source is a cost for an image: a mirror, keys, and a release cadence that is not\nZynthian's.\u003C\u002Fp>\n\u003Ch2 id=\"what-is-not-done\">What is not done\u003C\u002Fh2>\n\u003Cul>\n\u003Cli>A listening test through an audio interface: the plugins are measured digitally at JACK ports on the Pi, and the\nsample-by-sample round trip of a chain ran in containers.\u003C\u002Fli>\n\u003Cli>The cost grid at the hosts' own quantums (128, 256 and 1024 frames).\u003C\u002Fli>\n\u003Cli>A cost estimate at Zynthian's quantum before an insert.\u003C\u002Fli>\n\u003Cli>The MOD-UI engine on plugin-hostd, measured on the device.\u003C\u002Fli>\n\u003C\u002Ful>\n",1793954995874]