fix(kuna): run the inventory with the configured decode lanes
REA_KUNA_JOBS reached only `decompile-project`, so the export's first step, the `kuna functions` inventory that every cold request waits for, always ran serially. Kuna's `functions --jobs N` returns the serial inventory byte for byte, so both inventory runs now pass the configured jobs. On a 254 MB Mach-O the inventory takes 23 s with 8 lanes instead of 66 s; the default of one job is unchanged. Refs #1957 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
f255899ee8
commit
225d664e49
6 files changed
+53
-11
No files matched your search
@@ -13,14 +13,14 @@ rea doctor --provider kuna
|
||||
|
||||
Select it explicitly with `--provider kuna`, MCP's `open_binary.provider_id: "kuna"`, or `REA_ANALYSIS_PROVIDER=kuna`. With Kuna and another provider configured for the same target, `auto` reports `ambiguous` instead of choosing one.
|
||||
|
||||
| Setting | Default | Meaning |
|
||||
| ----------------------------- | --------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `REA_KUNA_COMMAND` | none (required) | Absolute path of the `kuna` executable. |
|
||||
| `REA_KUNA_CACHE_DIR` | `~/Library/Caches/rea/kuna` (macOS), `$XDG_CACHE_HOME/rea/kuna` (Linux; `~/.cache/rea/kuna` when `XDG_CACHE_HOME` is unset or relative) | Absolute directory REA owns for project exports. Kuna's own spec cache also lives here, not in your Kuna cache. |
|
||||
| `REA_KUNA_CACHE_MAX_BYTES` | 4 GiB | Size cap; least recently used exports are evicted above it. |
|
||||
| `REA_KUNA_PROJECT_TIMEOUT_MS` | 30 minutes | Deadline for one project export. |
|
||||
| `REA_KUNA_TIMEOUT_MS` | 120 s | Deadline for one single-function decompile. |
|
||||
| `REA_KUNA_JOBS` | 1 | `decompile-project --jobs`. 1 is Kuna's reference answer; more jobs finish sooner but lose callee-first prototypes, and change about 40–60% of function bodies on the measured binaries. |
|
||||
| Setting | Default | Meaning |
|
||||
| ----------------------------- | --------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `REA_KUNA_COMMAND` | none (required) | Absolute path of the `kuna` executable. |
|
||||
| `REA_KUNA_CACHE_DIR` | `~/Library/Caches/rea/kuna` (macOS), `$XDG_CACHE_HOME/rea/kuna` (Linux; `~/.cache/rea/kuna` when `XDG_CACHE_HOME` is unset or relative) | Absolute directory REA owns for project exports. Kuna's own spec cache also lives here, not in your Kuna cache. |
|
||||
| `REA_KUNA_CACHE_MAX_BYTES` | 4 GiB | Size cap; least recently used exports are evicted above it. |
|
||||
| `REA_KUNA_PROJECT_TIMEOUT_MS` | 30 minutes | Deadline for one project export. |
|
||||
| `REA_KUNA_TIMEOUT_MS` | 120 s | Deadline for one single-function decompile. |
|
||||
| `REA_KUNA_JOBS` | 1 | `--jobs` for `kuna functions` and `decompile-project`. The inventory is identical for any value. For the export, 1 is Kuna's reference answer; more jobs finish sooner but lose callee-first prototypes, and change about 40–60% of function bodies on the measured binaries. |
|
||||
|
||||
Windows is not supported yet. Supported targets are ELF and thin Mach-O executables for x86-64, AArch64 and ARM; PE and universal Mach-O are rejected with a typed reason.
|
||||
|
||||
|
||||
@@ -35,6 +35,16 @@ import { KUNA_PROVIDER_ID } from "./KunaRelease.js";
|
||||
*/
|
||||
export const KUNA_INVENTORY_OUTPUT_BYTES = 128 * 1024 * 1024;
|
||||
|
||||
/**
|
||||
* The `kuna functions` inventory of one image. Its `--jobs` decode lanes
|
||||
* return the serial inventory byte for byte, so the configured jobs change only
|
||||
* how fast discovery runs (a 254 MB Mach-O: 66 s serially, 23 s with 8 lanes).
|
||||
*/
|
||||
export const kunaInventoryArguments = (
|
||||
input: string,
|
||||
jobs: number,
|
||||
): readonly string[] => ["functions", input, "--json", "--jobs", String(jobs)];
|
||||
|
||||
/** Test seam for the owned process launcher; production uses the default. */
|
||||
export type KunaProcessLauncher = (
|
||||
options: OwnedProviderProcessSpawnOptions,
|
||||
|
||||
@@ -16,6 +16,7 @@ import type { ProviderProcessSupervisor } from "../process/ProviderProcess.js";
|
||||
import {
|
||||
copyAndHash,
|
||||
KUNA_INVENTORY_OUTPUT_BYTES,
|
||||
kunaInventoryArguments,
|
||||
runKunaCommand,
|
||||
type KunaProcessLauncher,
|
||||
} from "./KunaCommand.js";
|
||||
@@ -209,7 +210,7 @@ export const exportKunaProject = async (
|
||||
|
||||
request.onStatus({ phase: "inventory", inventoryFunctions: null });
|
||||
const listed = await run(
|
||||
["functions", input, "--json"],
|
||||
kunaInventoryArguments(input, configuration.jobs),
|
||||
KUNA_INVENTORY_OUTPUT_BYTES,
|
||||
);
|
||||
if (!listed.ok) return listed.outcome;
|
||||
|
||||
@@ -35,6 +35,7 @@ import type { ProviderProcessSupervisor } from "../process/ProviderProcess.js";
|
||||
import {
|
||||
copyAndHash,
|
||||
KUNA_INVENTORY_OUTPUT_BYTES,
|
||||
kunaInventoryArguments,
|
||||
runKunaCommand,
|
||||
type KunaProcessLauncher,
|
||||
} from "./KunaCommand.js";
|
||||
@@ -1167,7 +1168,10 @@ export class KunaSessionClient implements AnalysisClient {
|
||||
if (!workspace.ok) return workspace;
|
||||
const run = await runKunaCommand({
|
||||
installation,
|
||||
arguments: ["functions", workspace.value.input, "--json"],
|
||||
arguments: kunaInventoryArguments(
|
||||
workspace.value.input,
|
||||
installation.configuration.jobs,
|
||||
),
|
||||
workspace: workspace.value.root.path,
|
||||
operation: "list_procedures",
|
||||
timeoutMs: installation.configuration.functionTimeoutMs,
|
||||
|
||||
@@ -168,7 +168,13 @@ it("publishes a verified export and serves later requests from the cache", async
|
||||
// Kuna listed and decompiled a staged copy from REA's own HOME, in reference mode.
|
||||
const [listing] = await callsOf(kuna, "functions");
|
||||
const [exported] = await callsOf(kuna, "decompile-project");
|
||||
expect(listing?.argv).toEqual(["functions", exported?.argv[1], "--json"]);
|
||||
expect(listing?.argv).toEqual([
|
||||
"functions",
|
||||
exported?.argv[1],
|
||||
"--json",
|
||||
"--jobs",
|
||||
"1",
|
||||
]);
|
||||
expect(exported?.argv.slice(2)).toEqual([
|
||||
"-o",
|
||||
expect.stringContaining(join("cache", "staging")),
|
||||
|
||||
@@ -223,6 +223,27 @@ it("verifies a warm export once for concurrent first requests on a fresh server"
|
||||
}
|
||||
});
|
||||
|
||||
it("runs every inventory with the configured decode lanes", async () => {
|
||||
const { kuna, open } = await session(
|
||||
"rea-kuna-inventory-jobs-",
|
||||
{ project: "hang" },
|
||||
{ REA_KUNA_JOBS: "4" },
|
||||
);
|
||||
const client = open();
|
||||
try {
|
||||
await run(client, "list_procedures");
|
||||
await expect.poll(() => exportsOf(kuna)).toHaveLength(1);
|
||||
const calls = await fakeKunaCalls(kuna);
|
||||
const inventories = calls.filter(({ argv }) => argv[0] === "functions");
|
||||
expect(inventories.length).toBeGreaterThan(0);
|
||||
for (const { argv } of inventories)
|
||||
expect(argv.slice(2)).toEqual(["--json", "--jobs", "4"]);
|
||||
expect((await exportsOf(kuna))[0]?.argv.slice(-2)).toEqual(["--jobs", "4"]);
|
||||
} finally {
|
||||
expect(await client.close()).toEqual({ ok: true, value: null });
|
||||
}
|
||||
});
|
||||
|
||||
it("lists, searches and resolves procedures from Kuna's inventory", async () => {
|
||||
const { open } = await session("rea-kuna-inventory-");
|
||||
const client = open();
|
||||
|
||||
Reference in new issue
Block a user