@openmixer/plugin-qualify 0.18.4 → 0.19.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +19 -730
- package/bin/plugin-qualify-sync.mjs +4 -2
- package/bin/plugin-qualify.mjs +7 -0
- package/dist/clap-qualify.d.ts +1 -1
- package/dist/compare.d.ts +311 -0
- package/dist/compare.js +502 -0
- package/dist/compare.js.map +1 -0
- package/dist/distributed-records.d.ts +0 -2
- package/dist/distributed-records.js +0 -2
- package/dist/distributed-records.js.map +1 -1
- package/dist/host-admission.d.ts +2 -2
- package/dist/host-admission.js +7 -0
- package/dist/host-admission.js.map +1 -1
- package/dist/hosting-codes.generated.d.ts +1 -0
- package/dist/hosting-codes.generated.js +1 -0
- package/dist/hosting-codes.generated.js.map +1 -1
- package/dist/hosting-suitability.d.ts +3 -1
- package/dist/hosting-suitability.js +9 -0
- package/dist/hosting-suitability.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/jack-registry.d.ts +6 -0
- package/dist/jack-registry.js +52 -0
- package/dist/jack-registry.js.map +1 -0
- package/dist/lv2-loader.js +6 -5
- package/dist/lv2-loader.js.map +1 -1
- package/dist/measurement/format.d.ts +15 -0
- package/dist/measurement/format.js +19 -0
- package/dist/measurement/format.js.map +1 -1
- package/dist/measurement/sweep-jsonl.js +5 -1
- package/dist/measurement/sweep-jsonl.js.map +1 -1
- package/dist/measurement-grid.js +1 -1
- package/dist/pins-file.d.ts +22 -2
- package/dist/pins-file.js +118 -17
- package/dist/pins-file.js.map +1 -1
- package/dist/probe-judge.d.ts +5 -0
- package/dist/probe-judge.js.map +1 -1
- package/dist/probe-runner.d.ts +8 -0
- package/dist/probe-runner.js +8 -4
- package/dist/probe-runner.js.map +1 -1
- package/dist/qualification-record.d.ts +45 -0
- package/dist/qualification-record.js +36 -0
- package/dist/qualification-record.js.map +1 -1
- package/dist/qualify-adapter-pass.js +20 -5
- package/dist/qualify-adapter-pass.js.map +1 -1
- package/dist/qualify-declarations.d.ts +6 -0
- package/dist/qualify-declarations.js +8 -0
- package/dist/qualify-declarations.js.map +1 -1
- package/dist/qualify-isolated.d.ts +16 -3
- package/dist/qualify-isolated.js +31 -3
- package/dist/qualify-isolated.js.map +1 -1
- package/dist/qualify-pool.d.ts +129 -0
- package/dist/qualify-pool.js +290 -0
- package/dist/qualify-pool.js.map +1 -0
- package/dist/qualify-rejudge.js +7 -0
- package/dist/qualify-rejudge.js.map +1 -1
- package/dist/qualify-sync.d.ts +46 -1
- package/dist/qualify-sync.js +184 -20
- package/dist/qualify-sync.js.map +1 -1
- package/dist/records-package.d.ts +5 -0
- package/dist/records-package.js +25 -8
- package/dist/records-package.js.map +1 -1
- package/fixtures/clap-scan/fake.json +8 -2
- package/fixtures/probe-output/success-msi.json +2 -2
- package/package.json +3 -3
- package/src/clap-qualify.ts +1 -1
- package/src/compare.ts +699 -0
- package/src/distributed-records.ts +0 -3
- package/src/host-admission.ts +9 -2
- package/src/hosting-codes.generated.ts +1 -0
- package/src/hosting-suitability.ts +14 -0
- package/src/index.ts +1 -0
- package/src/jack-registry.ts +49 -0
- package/src/lv2-loader.ts +5 -4
- package/src/measurement/format.ts +32 -0
- package/src/measurement/sweep-jsonl.ts +5 -1
- package/src/measurement-grid.ts +1 -1
- package/src/pins-file.ts +109 -16
- package/src/probe-judge.ts +2 -0
- package/src/probe-runner.ts +18 -4
- package/src/qualification-record.ts +69 -0
- package/src/qualify-adapter-pass.ts +18 -5
- package/src/qualify-declarations.ts +8 -0
- package/src/qualify-isolated.ts +31 -5
- package/src/qualify-pool.ts +318 -0
- package/src/qualify-rejudge.ts +8 -0
- package/src/qualify-sync.ts +187 -19
- package/src/records-package.ts +25 -8
- package/tools/benchmark.py +9 -3
- package/tools/compare-host.mjs +432 -0
- package/tools/compare-run.mjs +355 -0
- package/tools/descriptors.py +27 -0
- package/tools/isolated-step.mjs +3 -1
- package/tools/lilv_load.py +25 -0
- package/tools/lv2_resolve.py +3 -1
- package/tools/pool-step.mjs +186 -0
- package/tools/scan.py +16 -20
- package/tools/audit-overlap.sh +0 -250
- package/tools/commit-message-check.sh +0 -128
- package/tools/commit-message-patterns.json +0 -41
- package/tools/private-refs-check.sh +0 -90
package/src/qualify-sync.ts
CHANGED
|
@@ -24,21 +24,22 @@ import { homedir, tmpdir } from "node:os";
|
|
|
24
24
|
import { basename, dirname, join, resolve, sep } from "node:path";
|
|
25
25
|
|
|
26
26
|
import { clapQualifyTools } from "./clap-qualify.js";
|
|
27
|
-
import { DISTRIBUTED_DIR_SYSTEM, EMPTY_LAYER, applyDistributed, distributedUri, hostClassOfBoard, matchDistributed, readBoardModel, readDistributedLayer, type DistributedLayer } from "./distributed-records.js";
|
|
27
|
+
import { DISTRIBUTED_DIR_SYSTEM, EMPTY_LAYER, applyDistributed, distributedUri, hostClassOfBoard, outcomeOfVerdict, matchDistributed, readBoardModel, readDistributedLayer, type DistributedLayer } from "./distributed-records.js";
|
|
28
28
|
import { clapSearchPath, parseClapScan } from "./clap-loader.js";
|
|
29
29
|
import { HOSTING_CODE } from "./hosting-codes.js";
|
|
30
30
|
import { shippedHostProfile, type HostProfile } from "./host-profiles.js";
|
|
31
31
|
import { lv2BundlesOnPath, manifestPlugins } from "./lv2-loader.js";
|
|
32
|
-
import { judgmentPinEntries, pinsFile, type PinEntry } from "./pins-file.js";
|
|
32
|
+
import { judgmentPinEntries, pinClearLine, pinLineUri, pinsFile, type PinEntry } from "./pins-file.js";
|
|
33
|
+
import { POOL_RESULT, completePool, judgePoolRun, pinAfterPool, pinFromRecordWithPool, poolEnv, spawnedPoolRunner, type PoolRunner } from "./qualify-pool.js";
|
|
33
34
|
import { hostdPinFiles, type PinFilesRun } from "./hostd-pin-files.js";
|
|
34
35
|
import type { Judgment } from "./probe-judge.js";
|
|
35
36
|
import { qualifyTargets, type ProbeRun } from "./probe-runner.js";
|
|
36
37
|
import { GRID_FULL, parseGridSpec, type GridSpec } from "./measurement-grid.js";
|
|
37
38
|
import { adapterPass, type AdapterPassOptions, type AdapterPassResult } from "./qualify-adapter-pass.js";
|
|
38
39
|
import { ISOLATED_RESULT, baseSteps, completeIsolated, isolatedCell, missingSteps, judgeIsolatedRun, owesIsolated, pinAfterStep, spawnedIsolatedRunner, type IsolatedRunner } from "./qualify-isolated.js";
|
|
39
|
-
import { lv2World, rejudgeState, memoryPass, type MemoryPassResult, type RejudgeResult } from "./qualify-rejudge.js";
|
|
40
|
+
import { lv2World, rejudgeRecord, rejudgeState, rejudgeToolName, memoryPass, type MemoryPassResult, type RejudgeResult } from "./qualify-rejudge.js";
|
|
40
41
|
import { memoryBoundOf, parseMemoryLimit, type MemoryBound } from "./memory-bound.js";
|
|
41
|
-
import { rewriteRecord, writeQualification, type NotMeasured, type QualificationRecord } from "./qualification-record.js";
|
|
42
|
+
import { QUALIFICATION_RECORD_SCHEMA, latencyNeverTaken, rewriteRecord, writeQualification, type NotMeasured, type QualificationRecord } from "./qualification-record.js";
|
|
42
43
|
import { ADMIT_STEP_MS_ENV, DESCRIPTOR_DIR_STATE_SUBDIR, DESCRIPTOR_DIR_SYSTEM, MEMORY_PASS_PROBE_NOTES, QUALIFY_QUANTA, QUALIFY_RATES } from "./qualify-declarations.js";
|
|
43
44
|
import { toolsDir } from "./tool-paths.js";
|
|
44
45
|
import { writeFileWhole } from "./whole-file.js";
|
|
@@ -57,7 +58,7 @@ export const ZYNTHIAN_LV2_DIRS = ["/zynthian/zynthian-plugins/lv2", "/zynthian/z
|
|
|
57
58
|
export interface SyncSetting {
|
|
58
59
|
readonly key: string;
|
|
59
60
|
readonly meaning: string;
|
|
60
|
-
/** The default as `--help` and
|
|
61
|
+
/** The default as `--help` and docs/overview.md print it. */
|
|
61
62
|
readonly default: string;
|
|
62
63
|
}
|
|
63
64
|
|
|
@@ -142,6 +143,8 @@ export interface SyncArgs {
|
|
|
142
143
|
readonly adapterOnly: boolean;
|
|
143
144
|
/** `--isolated-only`: the missing isolated step of each record already judged, extending its run. */
|
|
144
145
|
readonly isolatedOnly: boolean;
|
|
146
|
+
/** `--pool-only`: the pool step of each CLAP record already judged that owes it, extending its run and giving its pin the word. */
|
|
147
|
+
readonly poolOnly: boolean;
|
|
145
148
|
readonly help: boolean;
|
|
146
149
|
/** The settings given as flags, by key. */
|
|
147
150
|
readonly values: ReadonlyMap<string, string>;
|
|
@@ -162,6 +165,7 @@ export function parseSyncArgs(argv: readonly string[]): { ok: true; args: SyncAr
|
|
|
162
165
|
let memoryOnly = false;
|
|
163
166
|
let adapterOnly = false;
|
|
164
167
|
let isolatedOnly = false;
|
|
168
|
+
let poolOnly = false;
|
|
165
169
|
let help = false;
|
|
166
170
|
for (let i = 0; i < argv.length; i++) {
|
|
167
171
|
const a = argv[i]!;
|
|
@@ -174,6 +178,7 @@ export function parseSyncArgs(argv: readonly string[]): { ok: true; args: SyncAr
|
|
|
174
178
|
else if (a === "--memory-only") memoryOnly = true;
|
|
175
179
|
else if (a === "--adapter-only") adapterOnly = true;
|
|
176
180
|
else if (a === "--isolated-only") isolatedOnly = true;
|
|
181
|
+
else if (a === "--pool-only") poolOnly = true;
|
|
177
182
|
else if (a === "--help") help = true;
|
|
178
183
|
else if (a === "--grid-hosts") values.set("grid", "hosts");
|
|
179
184
|
else if (a === "--config" || byFlag.has(a)) {
|
|
@@ -183,9 +188,9 @@ export function parseSyncArgs(argv: readonly string[]): { ok: true; args: SyncAr
|
|
|
183
188
|
else values.set(byFlag.get(a)!, v);
|
|
184
189
|
} else return { ok: false, error: `unknown argument ${a}` };
|
|
185
190
|
}
|
|
186
|
-
if (rejudge && (memoryOnly || adapterOnly || isolatedOnly || force || refreshPinsOnly)) return { ok: false, error: "--rejudge measures nothing: it goes with none of --memory-only, --adapter-only, --force and --refresh-pins" };
|
|
187
|
-
if ([memoryOnly, adapterOnly, isolatedOnly, refreshPinsOnly].filter(Boolean).length > 1) return { ok: false, error: "--memory-only, --adapter-only and --refresh-pins are different runs: one at a time" };
|
|
188
|
-
return { ok: true, args: { ...(config === undefined ? {} : { config }), system, force, noDistributed, noWait, refreshPins: refreshPinsOnly, rejudge, memoryOnly, adapterOnly, isolatedOnly, help, values } };
|
|
191
|
+
if (rejudge && (memoryOnly || adapterOnly || isolatedOnly || poolOnly || force || refreshPinsOnly)) return { ok: false, error: "--rejudge measures nothing: it goes with none of --memory-only, --adapter-only, --isolated-only, --pool-only, --force and --refresh-pins" };
|
|
192
|
+
if ([memoryOnly, adapterOnly, isolatedOnly, poolOnly, refreshPinsOnly].filter(Boolean).length > 1) return { ok: false, error: "--memory-only, --adapter-only, --isolated-only, --pool-only and --refresh-pins are different runs: one at a time" };
|
|
193
|
+
return { ok: true, args: { ...(config === undefined ? {} : { config }), system, force, noDistributed, noWait, refreshPins: refreshPinsOnly, rejudge, memoryOnly, adapterOnly, isolatedOnly, poolOnly, help, values } };
|
|
189
194
|
}
|
|
190
195
|
|
|
191
196
|
export function syncHelpText(): string {
|
|
@@ -202,6 +207,7 @@ export function syncHelpText(): string {
|
|
|
202
207
|
" --rejudge derive every record's verdicts, tiers and pin again from the figures it holds; measures nothing",
|
|
203
208
|
" --memory-only measure only the footprint of each recorded plugin at the Pi's cells and merge it; with --force, those already merged too",
|
|
204
209
|
" --isolated-only run only the isolated step each record still owes, adding it to the record's run",
|
|
210
|
+
" --pool-only run only the pool step each CLAP record still owes: a plugin that asks for the thread pool is run with it off and on, and its pin gets pool=cores or pool=off",
|
|
205
211
|
" --adapter-only run each LV2 plugin only under omx-clap-host's LV2 adapter at the Pi's cells, on private JACK servers, and merge it; with --force, those already done too",
|
|
206
212
|
" --grid-hosts the fast grid, the same as --grid hosts (7 cells with the shipped hosts)",
|
|
207
213
|
" --help this text",
|
|
@@ -522,6 +528,25 @@ export function machineReason(p: Pick<SyncPlugin, "outcome" | "code" | "detail">
|
|
|
522
528
|
return /wrote no document|cannot run the probe runner/.test(p.detail ?? "") ? "the measurement wrote no document" : undefined;
|
|
523
529
|
}
|
|
524
530
|
|
|
531
|
+
/**
|
|
532
|
+
* The figure the records of a recorded entry never took, or `undefined`: a record whose probe ran before that figure's
|
|
533
|
+
* pass ({@link latencyNeverTaken}) owes a measurement, and the sync measures the entry again although its bytes are the
|
|
534
|
+
* ones it recorded. A record that cannot be read owes nothing here: the sync's other checks deal with it.
|
|
535
|
+
*/
|
|
536
|
+
export function figureOwed(entry: Pick<SyncEntry, "plugins">): "latency" | undefined {
|
|
537
|
+
for (const p of entry.plugins) {
|
|
538
|
+
if (p.record === undefined) continue;
|
|
539
|
+
let r: QualificationRecord;
|
|
540
|
+
try {
|
|
541
|
+
r = JSON.parse(readFileSync(p.record, "utf8")) as QualificationRecord;
|
|
542
|
+
} catch {
|
|
543
|
+
continue;
|
|
544
|
+
}
|
|
545
|
+
if (r.schema === QUALIFICATION_RECORD_SCHEMA && latencyNeverTaken(r)) return "latency";
|
|
546
|
+
}
|
|
547
|
+
return undefined;
|
|
548
|
+
}
|
|
549
|
+
|
|
525
550
|
/** What the quick qualification never measures, stated in every record it writes. */
|
|
526
551
|
export const QUICK_NOT_MEASURED: readonly NotMeasured[] = [{ dimension: "stability", code: HOSTING_CODE.stabilityUnsoaked }];
|
|
527
552
|
|
|
@@ -621,6 +646,8 @@ export interface SyncContext {
|
|
|
621
646
|
readonly pinFilesRun?: PinFilesRun;
|
|
622
647
|
/** The isolated step, a stand-in in tests. */
|
|
623
648
|
readonly isolatedRunner?: IsolatedRunner;
|
|
649
|
+
/** The pool step, a stand-in in tests. */
|
|
650
|
+
readonly poolRunner?: PoolRunner;
|
|
624
651
|
}
|
|
625
652
|
|
|
626
653
|
/**
|
|
@@ -738,6 +765,13 @@ function judgedPlugins(ctx: SyncContext, runs: readonly { bytes: Buffer; judgmen
|
|
|
738
765
|
code = undefined;
|
|
739
766
|
}
|
|
740
767
|
}
|
|
768
|
+
// the pool is for a CLAP plugin that runs: the thread pool is granted by measuring it, here and nowhere else
|
|
769
|
+
if (judgment.output.plugin.format === "clap" && pin !== undefined && pin.verdict !== "refused" && outcome === "qualified") {
|
|
770
|
+
const runner = ctx.poolRunner ?? spawnedPoolRunner();
|
|
771
|
+
const step = judgePoolRun(runner(pin.uri, isolatedCell(record, host), poolEnv(ctx.env, ctx.settings.budgetS)));
|
|
772
|
+
steps.push(step);
|
|
773
|
+
pin = pinAfterPool(pin, step);
|
|
774
|
+
}
|
|
741
775
|
rewriteRecord(recordPath, { ...record, run: { id: judgment.output.run.id, steps } });
|
|
742
776
|
const plugin: SyncPlugin = { uri: pin?.uri ?? judgment.output.plugin.id, outcome, ...(code === undefined ? {} : { code }), ...(pin === undefined ? {} : { pin }), record: recordPath };
|
|
743
777
|
return { plugin, judgedHere: judgment.hosts.some((h) => h.verdict.host === host) };
|
|
@@ -866,8 +900,8 @@ export function qualifyItem(ctx: SyncContext, item: SyncItem, files: readonly Fi
|
|
|
866
900
|
* The isolated steps the records of a state still owe, each extending its record's run. A plugin's pin follows its step, and
|
|
867
901
|
* a step that could not run stays owed: the next pass tries it again.
|
|
868
902
|
*/
|
|
869
|
-
export function isolatedPass(ctx: SyncContext, state: SyncState): { readonly state: SyncState; readonly isolated: number; readonly refused: number; readonly notRun: number } {
|
|
870
|
-
const count = { isolated: 0, refused: 0, notRun: 0 };
|
|
903
|
+
export function isolatedPass(ctx: SyncContext, state: SyncState): { readonly state: SyncState; readonly isolated: number; readonly refused: number; readonly notRun: number; readonly repinned: number } {
|
|
904
|
+
const count = { isolated: 0, refused: 0, notRun: 0, repinned: 0 };
|
|
871
905
|
const runner = ctx.isolatedRunner ?? spawnedIsolatedRunner();
|
|
872
906
|
const host = ctx.settings.hostProfile.id;
|
|
873
907
|
const entries: Record<string, SyncEntry> = {};
|
|
@@ -885,7 +919,17 @@ export function isolatedPass(ctx: SyncContext, state: SyncState): { readonly sta
|
|
|
885
919
|
return p;
|
|
886
920
|
}
|
|
887
921
|
const done = completeIsolated(path, record, p.pin?.uri ?? record.plugin.id, isolatedCell(record, host), runner, isolatedEnv(ctx));
|
|
888
|
-
if (done === undefined)
|
|
922
|
+
if (done === undefined) {
|
|
923
|
+
// a plugin the isolated step already decided but the state holds no pin for: the record keeps the bytes and the
|
|
924
|
+
// step, and the pin follows them (hostd names the files, as at every other pin)
|
|
925
|
+
if (p.pin !== undefined) return p;
|
|
926
|
+
const rebuilt = withHostdFiles(ctx, pinFromRecordWithPool(record));
|
|
927
|
+
if (rebuilt === undefined) return p;
|
|
928
|
+
count.repinned++;
|
|
929
|
+
ctx.log(`${p.uri}: pinned again from its record (isolated step ${rebuilt.verdict ?? "undecided"})`);
|
|
930
|
+
const { code: _c, ...rest } = p;
|
|
931
|
+
return rest.outcome === "qualified" && rebuilt.verdict === "refused" ? { ...rest, outcome: "refused" as const, pin: rebuilt } : { ...rest, pin: rebuilt };
|
|
932
|
+
}
|
|
889
933
|
ctx.log(`${p.uri}: isolated step ${done.step.result}${done.step.code === undefined ? "" : ` (${done.step.code})`}`);
|
|
890
934
|
const pin = pinAfterStep(p.pin, done.step);
|
|
891
935
|
const { pin: _pin, code: _code, ...rest } = p;
|
|
@@ -899,7 +943,44 @@ export function isolatedPass(ctx: SyncContext, state: SyncState): { readonly sta
|
|
|
899
943
|
}),
|
|
900
944
|
};
|
|
901
945
|
}
|
|
902
|
-
return { ...count, state: count.isolated + count.refused + count.notRun === 0 ? state : { ...state, entries } };
|
|
946
|
+
return { ...count, state: count.isolated + count.refused + count.notRun + count.repinned === 0 ? state : { ...state, entries } };
|
|
947
|
+
}
|
|
948
|
+
|
|
949
|
+
/**
|
|
950
|
+
* The pool steps the CLAP records of a state still owe, each extending its record's run. A plugin's pin takes the pool word
|
|
951
|
+
* of its step (`cores`, or `off` for a plugin that was measured and gains nothing) and none for a plugin that does not ask
|
|
952
|
+
* for the pool. A step that could not run stays owed: the next pass tries it again.
|
|
953
|
+
*/
|
|
954
|
+
export function poolPass(ctx: SyncContext, state: SyncState): { readonly state: SyncState; readonly cores: number; readonly off: number; readonly notAsked: number; readonly notRun: number } {
|
|
955
|
+
const count = { cores: 0, off: 0, notAsked: 0, notRun: 0 };
|
|
956
|
+
const runner = ctx.poolRunner ?? spawnedPoolRunner();
|
|
957
|
+
const host = ctx.settings.hostProfile.id;
|
|
958
|
+
const entries: Record<string, SyncEntry> = {};
|
|
959
|
+
for (const [key, entry] of Object.entries(state.entries)) {
|
|
960
|
+
entries[key] = {
|
|
961
|
+
...entry,
|
|
962
|
+
plugins: entry.plugins.map((p) => {
|
|
963
|
+
if (p.record === undefined || !p.record.endsWith(".qualification.json") || p.pin === undefined || p.pin.verdict === "refused") return p;
|
|
964
|
+
const path = join(ctx.settings.qualificationDir, basename(p.record));
|
|
965
|
+
let record: QualificationRecord;
|
|
966
|
+
try {
|
|
967
|
+
record = JSON.parse(readFileSync(path, "utf8")) as QualificationRecord;
|
|
968
|
+
} catch {
|
|
969
|
+
ctx.log(`${p.uri}: its record does not read; no pool step`);
|
|
970
|
+
return p;
|
|
971
|
+
}
|
|
972
|
+
const done = completePool(path, record, p.pin.uri, isolatedCell(record, host), runner, poolEnv(ctx.env, ctx.settings.budgetS));
|
|
973
|
+
if (done === undefined) return p;
|
|
974
|
+
ctx.log(`${p.uri}: pool step ${done.step.result}${done.step.code === undefined ? "" : ` (${done.step.code})`}`);
|
|
975
|
+
if (done.step.result === POOL_RESULT.cores) count.cores++;
|
|
976
|
+
else if (done.step.result === POOL_RESULT.off) count.off++;
|
|
977
|
+
else if (done.step.result === POOL_RESULT.notAsked) count.notAsked++;
|
|
978
|
+
else count.notRun++;
|
|
979
|
+
return { ...p, pin: pinAfterPool(p.pin, done.step)! };
|
|
980
|
+
}),
|
|
981
|
+
};
|
|
982
|
+
}
|
|
983
|
+
return { ...count, state: count.cores + count.off + count.notAsked + count.notRun === 0 ? state : { ...state, entries } };
|
|
903
984
|
}
|
|
904
985
|
|
|
905
986
|
// --- the distributed records ----------------------------------------------------------------------------------------
|
|
@@ -938,10 +1019,35 @@ function takeDistributed(ctx: SyncContext, layer: DistributedLayer, item: SyncIt
|
|
|
938
1019
|
ctx.log(`distributed: ${distributedUri(item, r)}: its record lacks the step${missing.length === 1 ? "" : "s"} ${missing.join(", ")}; measured here`);
|
|
939
1020
|
return undefined;
|
|
940
1021
|
}
|
|
1022
|
+
if (latencyNeverTaken(r.record)) {
|
|
1023
|
+
ctx.log(`distributed: ${distributedUri(item, r)}: its record never took the latency figure (a probe from before that pass); measured here`);
|
|
1024
|
+
return undefined;
|
|
1025
|
+
}
|
|
1026
|
+
}
|
|
1027
|
+
// The set was judged by the plugin-qualify that measured it. Its figures are carried across and judged again under
|
|
1028
|
+
// today's rules, as an upgrade's are (`--rejudge`): a verdict of an older judge (RT-unsafe read as refused, before
|
|
1029
|
+
// #196) is never taken as it stands. A record today's judge cannot decide for this host is measured here.
|
|
1030
|
+
const by = rejudgeToolName();
|
|
1031
|
+
const at = new Date(started).toISOString();
|
|
1032
|
+
const records = [];
|
|
1033
|
+
for (const r of match.records) {
|
|
1034
|
+
let record: QualificationRecord;
|
|
1035
|
+
try {
|
|
1036
|
+
record = rejudgeRecord(r.record, readFileSync(join(r.path, "..", r.record.probe.file)), { host, by, at }).record;
|
|
1037
|
+
} catch (e) {
|
|
1038
|
+
ctx.log(`distributed: ${distributedUri(item, r)}: ${(e as Error).message}; measured here`);
|
|
1039
|
+
return undefined;
|
|
1040
|
+
}
|
|
1041
|
+
const v = record.verdicts.find((x) => x.host === host);
|
|
1042
|
+
if (v !== undefined && outcomeOfVerdict(v) === "unmeasured") {
|
|
1043
|
+
ctx.log(`distributed: ${distributedUri(item, r)}: judged again, ${v.deciding ?? "unknown"} for ${host}; measured here`);
|
|
1044
|
+
return undefined;
|
|
1045
|
+
}
|
|
1046
|
+
records.push({ ...r, record });
|
|
941
1047
|
}
|
|
942
1048
|
let plugins: SyncPlugin[];
|
|
943
1049
|
try {
|
|
944
|
-
plugins = applyDistributed(ctx.settings.qualificationDir, item, match, host);
|
|
1050
|
+
plugins = applyDistributed(ctx.settings.qualificationDir, item, { ...match, records }, host);
|
|
945
1051
|
} catch (e) {
|
|
946
1052
|
ctx.log(`distributed: ${distributedUri(item, match.records[0]!)}: ${(e as Error).message}; measured here`);
|
|
947
1053
|
return undefined;
|
|
@@ -980,7 +1086,7 @@ export function syncPinsText(state: SyncState): string {
|
|
|
980
1086
|
/** The pin lines, by uri. */
|
|
981
1087
|
function pinLinesOf(text: string): Map<string, string> {
|
|
982
1088
|
const out = new Map<string, string>();
|
|
983
|
-
for (const line of text.split("\n")) if (line !== "" && !line.startsWith("#")) out.set(line
|
|
1089
|
+
for (const line of text.split("\n")) if (line !== "" && !line.startsWith("#")) out.set(pinLineUri(line)!, line);
|
|
984
1090
|
return out;
|
|
985
1091
|
}
|
|
986
1092
|
|
|
@@ -1181,6 +1287,8 @@ export interface SyncSummary {
|
|
|
1181
1287
|
readonly machineFailure?: string;
|
|
1182
1288
|
/** `--isolated-only`: how the steps ended. */
|
|
1183
1289
|
readonly isolatedOnly?: { readonly isolated: number; readonly refused: number; readonly notRun: number };
|
|
1290
|
+
/** `--pool-only`: the plugins granted the thread pool, those measured and not granted it, those that do not ask for it, and those the step could not run for. */
|
|
1291
|
+
readonly poolOnly?: { readonly cores: number; readonly off: number; readonly notAsked: number; readonly notRun: number };
|
|
1184
1292
|
/** `--adapter-only`: the plugins run, those done already at these host versions, and those whose host could not be run. */
|
|
1185
1293
|
readonly adapterOnly?: { readonly measured: number; readonly already: number; readonly failed: number };
|
|
1186
1294
|
}
|
|
@@ -1218,8 +1326,55 @@ export function descriptorAccessProblems(dir: string): string[] {
|
|
|
1218
1326
|
return problems;
|
|
1219
1327
|
}
|
|
1220
1328
|
|
|
1329
|
+
/** What the records say per plugin, not per record: a CLAP plugin has a record per offer (.default, the console's
|
|
1330
|
+
* in-process tier, and .custom, omx-clap-host's isolated tier), and is offered when any of its records is. */
|
|
1331
|
+
export interface PluginCounts {
|
|
1332
|
+
readonly plugins: Readonly<Record<string, number>>;
|
|
1333
|
+
readonly offered: Readonly<Record<string, number>>;
|
|
1334
|
+
readonly notOffered: Readonly<Record<string, number>>;
|
|
1335
|
+
}
|
|
1336
|
+
|
|
1337
|
+
export function pluginCounts(qualificationDir: string): PluginCounts {
|
|
1338
|
+
const offeredBy = new Map<string, boolean>();
|
|
1339
|
+
let files: string[] = [];
|
|
1340
|
+
try {
|
|
1341
|
+
files = readdirSync(qualificationDir).filter((f) => f.endsWith(".qualification.json"));
|
|
1342
|
+
} catch {
|
|
1343
|
+
// no directory, no record
|
|
1344
|
+
}
|
|
1345
|
+
for (const f of files) {
|
|
1346
|
+
let r: { plugin?: { format?: string; id?: string }; tiers?: { offeredOn?: readonly string[] } };
|
|
1347
|
+
try {
|
|
1348
|
+
r = JSON.parse(readFileSync(join(qualificationDir, f), "utf8"));
|
|
1349
|
+
} catch {
|
|
1350
|
+
continue;
|
|
1351
|
+
}
|
|
1352
|
+
if (!r.plugin?.format || !r.plugin.id) continue;
|
|
1353
|
+
const key = `${r.plugin.format}\0${r.plugin.id}`;
|
|
1354
|
+
offeredBy.set(key, (offeredBy.get(key) ?? false) || (r.tiers?.offeredOn?.length ?? 0) > 0);
|
|
1355
|
+
}
|
|
1356
|
+
const plugins: Record<string, number> = {}, offered: Record<string, number> = {}, notOffered: Record<string, number> = {};
|
|
1357
|
+
for (const [key, isOffered] of offeredBy) {
|
|
1358
|
+
const format = key.split("\0")[0]!;
|
|
1359
|
+
plugins[format] = (plugins[format] ?? 0) + 1;
|
|
1360
|
+
const into = isOffered ? offered : notOffered;
|
|
1361
|
+
into[format] = (into[format] ?? 0) + 1;
|
|
1362
|
+
}
|
|
1363
|
+
return { plugins, offered, notOffered };
|
|
1364
|
+
}
|
|
1365
|
+
|
|
1366
|
+
/** The per-plugin counts as one line: `plugins 1577 (clap 248, lv2 1329), offered 1399 (...), not offered 178 (...)`. */
|
|
1367
|
+
export function pluginCountsLine(c: PluginCounts): string {
|
|
1368
|
+
const part = (m: Readonly<Record<string, number>>): string => {
|
|
1369
|
+
const keys = Object.keys(m).sort();
|
|
1370
|
+
const total = keys.reduce((n, k) => n + m[k]!, 0);
|
|
1371
|
+
return `${String(total)}${keys.length === 0 ? "" : ` (${keys.map((k) => `${k} ${String(m[k])}`).join(", ")})`}`;
|
|
1372
|
+
};
|
|
1373
|
+
return `plugins ${part(c.plugins)}, offered ${part(c.offered)}, not offered ${part(c.notOffered)}`;
|
|
1374
|
+
}
|
|
1375
|
+
|
|
1221
1376
|
export function summaryLine(s: SyncSummary): string {
|
|
1222
|
-
return `qualified ${String(s.qualified)}, skipped ${String(s.skipped)}, refused ${String(s.refused)}, crashed ${String(s.crashed)}, hung ${String(s.hung)}, unmeasured ${String(s.unmeasured)}, distributed ${String(s.distributed)}${s.refreshed ? `, pins refreshed ${String(s.refreshed)}` : ""}${s.rejudge === undefined ? "" : `, rejudged ${String(s.rejudge.changed)}, unchanged ${String(s.rejudge.unchanged)}, owing ${String(s.rejudge.owing)}`}${s.memoryOnly === undefined ? "" : `, memory measured ${String(s.memoryOnly.measured)}, already ${String(s.memoryOnly.already)}, failed ${String(s.memoryOnly.failed)}, leaks not measured`}${s.adapterOnly === undefined ? "" : `, adapter run ${String(s.adapterOnly.measured)}, already ${String(s.adapterOnly.already)}, failed ${String(s.adapterOnly.failed)}`}, ${s.seconds.toFixed(1)} s`;
|
|
1377
|
+
return `qualified ${String(s.qualified)}, skipped ${String(s.skipped)}, refused ${String(s.refused)}, crashed ${String(s.crashed)}, hung ${String(s.hung)}, unmeasured ${String(s.unmeasured)}, distributed ${String(s.distributed)}${s.refreshed ? `, pins refreshed ${String(s.refreshed)}` : ""}${s.rejudge === undefined ? "" : `, rejudged ${String(s.rejudge.changed)}, unchanged ${String(s.rejudge.unchanged)}, owing ${String(s.rejudge.owing)}`}${s.memoryOnly === undefined ? "" : `, memory measured ${String(s.memoryOnly.measured)}, already ${String(s.memoryOnly.already)}, failed ${String(s.memoryOnly.failed)}, leaks not measured`}${s.poolOnly === undefined ? "" : `, pool granted ${String(s.poolOnly.cores)}, off ${String(s.poolOnly.off)}, not asked ${String(s.poolOnly.notAsked)}, not run ${String(s.poolOnly.notRun)}`}${s.adapterOnly === undefined ? "" : `, adapter run ${String(s.adapterOnly.measured)}, already ${String(s.adapterOnly.already)}, failed ${String(s.adapterOnly.failed)}`}, ${s.seconds.toFixed(1)} s`;
|
|
1223
1378
|
}
|
|
1224
1379
|
|
|
1225
1380
|
/** The exit status `flock -n` returns when the lock is held (-E), told apart from a failure of flock itself. */
|
|
@@ -1273,6 +1428,10 @@ export interface SyncRunOptions {
|
|
|
1273
1428
|
readonly isolatedRunner?: IsolatedRunner;
|
|
1274
1429
|
/** `--isolated-only`: take only the isolated steps records still owe. */
|
|
1275
1430
|
readonly isolatedOnly?: boolean;
|
|
1431
|
+
/** The pool step, a stand-in in tests. */
|
|
1432
|
+
readonly poolRunner?: PoolRunner;
|
|
1433
|
+
/** `--pool-only`: take only the pool steps records still owe. */
|
|
1434
|
+
readonly poolOnly?: boolean;
|
|
1276
1435
|
/** `--adapter-only`: take only the adapter runs; `force` takes those already done again. */
|
|
1277
1436
|
readonly adapterOnly?: boolean;
|
|
1278
1437
|
/** Stand-ins for the pass's hosts, in tests. */
|
|
@@ -1341,6 +1500,7 @@ function addSummaries(a: SyncSummary, b: SyncSummary): SyncSummary {
|
|
|
1341
1500
|
...(b.rejudge === undefined ? (a.rejudge === undefined ? {} : { rejudge: a.rejudge }) : { rejudge: b.rejudge }),
|
|
1342
1501
|
...(b.memoryOnly === undefined ? (a.memoryOnly === undefined ? {} : { memoryOnly: a.memoryOnly }) : { memoryOnly: b.memoryOnly }),
|
|
1343
1502
|
...(b.isolatedOnly === undefined ? (a.isolatedOnly === undefined ? {} : { isolatedOnly: a.isolatedOnly }) : { isolatedOnly: b.isolatedOnly }),
|
|
1503
|
+
...(b.poolOnly === undefined ? (a.poolOnly === undefined ? {} : { poolOnly: a.poolOnly }) : { poolOnly: b.poolOnly }),
|
|
1344
1504
|
...(b.adapterOnly === undefined ? (a.adapterOnly === undefined ? {} : { adapterOnly: a.adapterOnly }) : { adapterOnly: b.adapterOnly }),
|
|
1345
1505
|
};
|
|
1346
1506
|
}
|
|
@@ -1366,7 +1526,7 @@ async function runLocked(settings: SyncSettings, options: SyncRunOptions): Promi
|
|
|
1366
1526
|
{
|
|
1367
1527
|
const started = Date.now();
|
|
1368
1528
|
const dirs = [...settings.clapDirs, ...settings.lv2Dirs];
|
|
1369
|
-
const ctx: SyncContext = { settings, env, log, ...(options.pinFilesRun === undefined ? {} : { pinFilesRun: options.pinFilesRun }), ...(options.isolatedRunner === undefined ? {} : { isolatedRunner: options.isolatedRunner }) };
|
|
1529
|
+
const ctx: SyncContext = { settings, env, log, ...(options.pinFilesRun === undefined ? {} : { pinFilesRun: options.pinFilesRun }), ...(options.isolatedRunner === undefined ? {} : { isolatedRunner: options.isolatedRunner }), ...(options.poolRunner === undefined ? {} : { poolRunner: options.poolRunner }) };
|
|
1370
1530
|
// the pins first, before the quiet wait and any measurement: an upgrade of plugin-hostd that collects more files
|
|
1371
1531
|
// than the pins on disk hold refuses those plugins until their pins name them (plugin-qualify#239)
|
|
1372
1532
|
const fresh = refreshPins(ctx, readSyncState(settings.stateFile, log));
|
|
@@ -1386,6 +1546,12 @@ async function runLocked(settings: SyncSettings, options: SyncRunOptions): Promi
|
|
|
1386
1546
|
const summary = await sendRefreshed(settings, r.state, fresh.refreshed.length, started, log);
|
|
1387
1547
|
return { ...summary, isolatedOnly: { isolated: r.isolated, refused: r.refused, notRun: r.notRun } };
|
|
1388
1548
|
}
|
|
1549
|
+
if (options.poolOnly === true) {
|
|
1550
|
+
const r = poolPass(ctx, fresh.state);
|
|
1551
|
+
if (r.state !== fresh.state) writeFileWhole(settings.stateFile, `${JSON.stringify(r.state, null, 1)}\n`);
|
|
1552
|
+
const summary = await sendRefreshed(settings, r.state, fresh.refreshed.length, started, log);
|
|
1553
|
+
return { ...summary, poolOnly: { cores: r.cores, off: r.off, notAsked: r.notAsked, notRun: r.notRun } };
|
|
1554
|
+
}
|
|
1389
1555
|
if (options.adapterOnly === true) {
|
|
1390
1556
|
const r: AdapterPassResult = adapterPass(ctx, fresh.state, { ...options.adapterPass, force: options.force === true });
|
|
1391
1557
|
log(`adapter runs under ${Object.entries(r.versions).map(([k, v]) => `${k} ${v}`).join(", ")}`);
|
|
@@ -1433,7 +1599,8 @@ async function runLocked(settings: SyncSettings, options: SyncRunOptions): Promi
|
|
|
1433
1599
|
for (const item of items) {
|
|
1434
1600
|
const recorded = recordedAsIs(item, entries[item.key]);
|
|
1435
1601
|
const retry = recorded.same ? entries[item.key]!.plugins.map(machineReason).find((r) => r !== undefined) : undefined;
|
|
1436
|
-
|
|
1602
|
+
const owed = recorded.same && options.force !== true && retry === undefined ? figureOwed(entries[item.key]!) : undefined;
|
|
1603
|
+
if (recorded.same && options.force !== true && retry === undefined && owed === undefined) {
|
|
1437
1604
|
if (pass === 0) count.skipped += entries[item.key]!.plugins.length;
|
|
1438
1605
|
continue;
|
|
1439
1606
|
}
|
|
@@ -1451,6 +1618,7 @@ async function runLocked(settings: SyncSettings, options: SyncRunOptions): Promi
|
|
|
1451
1618
|
continue;
|
|
1452
1619
|
}
|
|
1453
1620
|
if (recorded.same && retry !== undefined) log(`${item.key}: unmeasured last run by the machine (${retry}); measured again`);
|
|
1621
|
+
if (owed !== undefined) log(`${item.key}: its record never took the ${owed} figure (a probe from before that pass); measured again`);
|
|
1454
1622
|
const files = recorded.files ?? digestFiles(item.root, item.files);
|
|
1455
1623
|
if (files === undefined) {
|
|
1456
1624
|
log(`${item.key}: a file of it cannot be read; skipped this run`);
|
|
@@ -1497,7 +1665,7 @@ async function runLocked(settings: SyncSettings, options: SyncRunOptions): Promi
|
|
|
1497
1665
|
if (unreadable) log("a plugin directory could not be read; no record or descriptor is removed this run");
|
|
1498
1666
|
else for (const f of pruneStale(settings, stateBefore, state)) log(`${f}: removed, its plugin is gone or changed`);
|
|
1499
1667
|
// a plugin that was pinned and is not any more is also forgotten by a running daemon
|
|
1500
|
-
const changed = [...changedPinLines(before, after), ...removedPinUris(before, after).map(
|
|
1668
|
+
const changed = [...changedPinLines(before, after), ...removedPinUris(before, after).map(pinClearLine)];
|
|
1501
1669
|
const sent = await sendPins(settings.hostdPort, settings.hostdFeedbackPort, changed);
|
|
1502
1670
|
if ("unsent" in sent) {
|
|
1503
1671
|
const why = {
|
|
@@ -1508,7 +1676,7 @@ async function runLocked(settings: SyncSettings, options: SyncRunOptions): Promi
|
|
|
1508
1676
|
log(`${why}; the ${String(changed.length)} changed pins apply at its next start, from the pin file`);
|
|
1509
1677
|
}
|
|
1510
1678
|
const replies = "replies" in sent ? sent.replies : [];
|
|
1511
|
-
for (let i = 0; i < replies.length; i++) if (replies[i] !== "resp 0") log(`plugin-hostd answered ${replies[i]!} to ${changed[i]
|
|
1679
|
+
for (let i = 0; i < replies.length; i++) if (replies[i] !== "resp 0") log(`plugin-hostd answered ${replies[i]!} to ${pinLineUri(changed[i]!)!}`);
|
|
1512
1680
|
const taken = replies.filter((r) => r === "resp 0").length;
|
|
1513
1681
|
for (const [why, n] of byMachine) if (n > 1) log(`${String(n)} plugins unmeasured by the machine (${why}); the first is listed above`);
|
|
1514
1682
|
const [only] = byMachine.size === 1 ? [...byMachine] : [];
|
package/src/records-package.ts
CHANGED
|
@@ -4,7 +4,8 @@
|
|
|
4
4
|
* `plugin-qualify-records-package`: the Debian package of a device's qualification records, so other devices of the
|
|
5
5
|
* machine class install them as the distributed layer instead of measuring the same plugin set again.
|
|
6
6
|
*
|
|
7
|
-
* In: a qualification directory as plugin-qualify-sync leaves it. Out: `
|
|
7
|
+
* In: a qualification directory as plugin-qualify-sync leaves it. Out: `plugin-db-qualification-<class>-<set>_<version>_all.deb`,
|
|
8
|
+
* a package of plugin-db's qualification layer,
|
|
8
9
|
* installing every record and the probe output it judged under `/usr/share/omx/qualification/<class>/<set>/`, beside
|
|
9
10
|
* the set's `provenance.json`. A record goes in only with its probe output, byte for byte the copy the record names;
|
|
10
11
|
* an unmeasured record never applies and stays out. The archive is written here, `ar` and two `tar.xz` members, so a
|
|
@@ -16,7 +17,7 @@ import { closeSync, copyFileSync, mkdirSync, mkdtempSync, openSync, readFileSync
|
|
|
16
17
|
import { tmpdir } from "node:os";
|
|
17
18
|
import { join } from "node:path";
|
|
18
19
|
|
|
19
|
-
import { DISTRIBUTED_DIR_SYSTEM,
|
|
20
|
+
import { DISTRIBUTED_DIR_SYSTEM, DISTRIBUTED_PROVENANCE_FILE, DISTRIBUTED_PROVENANCE_SCHEMA, type DistributedProvenance } from "./distributed-records.js";
|
|
20
21
|
import { sha256Hex } from "./probe-output.js";
|
|
21
22
|
import { QUALIFICATION_RECORD_SCHEMA } from "./qualification-record.js";
|
|
22
23
|
|
|
@@ -53,7 +54,7 @@ export function recordsPackageHelp(): string {
|
|
|
53
54
|
" --maintainer <who> the package's Maintainer field",
|
|
54
55
|
" --help this text",
|
|
55
56
|
"",
|
|
56
|
-
`the package installs ${DISTRIBUTED_DIR_SYSTEM}/<class>/<set>/ and depends on plugin-qualify
|
|
57
|
+
`the package installs ${DISTRIBUTED_DIR_SYSTEM}/<class>/<set>/ and depends on this plugin-qualify's minor, up to the next one`,
|
|
57
58
|
"exit 0 the package was written, 2 it could not be",
|
|
58
59
|
"",
|
|
59
60
|
].join("\n");
|
|
@@ -97,7 +98,21 @@ export function parseRecordsPackageArgs(argv: readonly string[]): { ok: true; ar
|
|
|
97
98
|
}
|
|
98
99
|
|
|
99
100
|
/** The package of a class and a set. */
|
|
100
|
-
export const recordsPackageName = (hostClass: string, set: string): string => `
|
|
101
|
+
export const recordsPackageName = (hostClass: string, set: string): string => `plugin-db-qualification-${hostClass}-${set}`;
|
|
102
|
+
|
|
103
|
+
/** The plugin-qualify a package of records depends on: the minor that wrote them, up to the next minor. */
|
|
104
|
+
export function recordsDependsRange(version: string): { floor: string; ceiling: string } | undefined {
|
|
105
|
+
const m = /^(\d+)\.(\d+)\.\d+/.exec(version);
|
|
106
|
+
if (m === null) return undefined;
|
|
107
|
+
const major = Number(m[1]);
|
|
108
|
+
const minor = Number(m[2]);
|
|
109
|
+
return { floor: `${String(major)}.${String(minor)}.0`, ceiling: `${String(major)}.${String(minor + 1)}` };
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/** This plugin-qualify's own version, read where it is installed. */
|
|
113
|
+
function ownVersion(): string {
|
|
114
|
+
return (JSON.parse(readFileSync(new URL("../package.json", import.meta.url), "utf8")) as { version?: string }).version ?? "";
|
|
115
|
+
}
|
|
101
116
|
|
|
102
117
|
/** Today as a package version, `2026.10.29`, and as a date, `2026-10-29`, in local time. */
|
|
103
118
|
export function today(now = new Date()): { version: string; date: string } {
|
|
@@ -199,6 +214,8 @@ export interface BuiltRecordsPackage {
|
|
|
199
214
|
/** The package of `args`, written into `args.out`. Throws, naming why, when it cannot be built. */
|
|
200
215
|
export function buildRecordsPackage(args: RecordsPackageArgs, now = new Date()): BuiltRecordsPackage {
|
|
201
216
|
const name = recordsPackageName(args.hostClass, args.set);
|
|
217
|
+
const range = recordsDependsRange(ownVersion());
|
|
218
|
+
if (range === undefined) throw new Error("this plugin-qualify names no version, so the package cannot say which one reads it");
|
|
202
219
|
const day = today(now);
|
|
203
220
|
const version = args.version ?? day.version;
|
|
204
221
|
statSync(args.stateDir);
|
|
@@ -238,13 +255,13 @@ export function buildRecordsPackage(args: RecordsPackageArgs, now = new Date()):
|
|
|
238
255
|
"Architecture: all",
|
|
239
256
|
`Maintainer: ${args.maintainer}`,
|
|
240
257
|
`Installed-Size: ${String(kib)}`,
|
|
241
|
-
`Depends: plugin-qualify (>= ${
|
|
258
|
+
`Depends: plugin-qualify (>= ${range.floor}~), plugin-qualify (<< ${range.ceiling}~)`,
|
|
242
259
|
"Section: sound",
|
|
243
260
|
"Priority: optional",
|
|
244
261
|
"Multi-Arch: foreign",
|
|
245
|
-
`Description: qualification
|
|
246
|
-
` The
|
|
247
|
-
` ${args.hostClass} device. plugin-qualify-sync takes a plugin from them instead of`,
|
|
262
|
+
`Description: plugin-db qualification layer: ${args.set} set for ${args.hostClass}`,
|
|
263
|
+
` The qualification layer of the plugin database: the plugin-qualify records`,
|
|
264
|
+
` of the ${args.set} plugin set, measured on a ${args.hostClass} device. plugin-qualify-sync takes a plugin from them instead of`,
|
|
248
265
|
" measuring it, and only when every file of the installed plugin hashes as the",
|
|
249
266
|
" measured one did; any other plugin is measured on the device as before.",
|
|
250
267
|
"",
|
package/tools/benchmark.py
CHANGED
|
@@ -1201,7 +1201,9 @@ class _Host:
|
|
|
1201
1201
|
def __init__(self, rate, block):
|
|
1202
1202
|
import ctypes
|
|
1203
1203
|
|
|
1204
|
-
import
|
|
1204
|
+
from lilv_load import load_lilv
|
|
1205
|
+
|
|
1206
|
+
lilv = load_lilv()
|
|
1205
1207
|
|
|
1206
1208
|
self.urids = {}
|
|
1207
1209
|
|
|
@@ -1362,7 +1364,9 @@ def probe_one(host, uri, symbol, cycles=DEFAULT_RUN_CYCLES):
|
|
|
1362
1364
|
"""
|
|
1363
1365
|
import numpy as np
|
|
1364
1366
|
|
|
1365
|
-
import
|
|
1367
|
+
from lilv_load import load_lilv
|
|
1368
|
+
|
|
1369
|
+
lilv = load_lilv()
|
|
1366
1370
|
|
|
1367
1371
|
plugin = host.world.get_all_plugins().get_by_uri(host.world.new_uri(uri))
|
|
1368
1372
|
if plugin is None:
|
|
@@ -1453,7 +1457,9 @@ def instantiate_connected(host, plugin, overrides=None):
|
|
|
1453
1457
|
"""
|
|
1454
1458
|
import numpy as np
|
|
1455
1459
|
|
|
1456
|
-
import
|
|
1460
|
+
from lilv_load import load_lilv
|
|
1461
|
+
|
|
1462
|
+
lilv = load_lilv()
|
|
1457
1463
|
|
|
1458
1464
|
host.worker.reset()
|
|
1459
1465
|
instance = lilv.Instance(plugin, float(host.rate), host.features)
|