8000 bench: add foreign runtime coverage for #776 P16 by adityamukho · Pull Request #832 · project-minigraf/minigraf · GitHub
[go: up one dir, main page]

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
    48 changes: 48 additions & 0 deletions .github/bench/bindings-report.cjs
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,48 @@
    // Binding jobs use Bencher JSON (nanoseconds), with separate foreign testbeds.
    const fs = require('node:fs');
    const { audit } = require('./report.cjs');
    function expected(binding) {
    if (!['python', 'browser', 'node', 'c'].includes(binding)) throw new Error('unknown binding');
    const suffixes = ['prepared_execute/1k', 'cursor_batch_1/1k', 'cursor_batch_256/1k', 'set_roundtrip/2', 'predicate/1k', 'aggregate/1k'];
    if (binding === 'browser') suffixes.push('indexeddb_write/1k', 'indexeddb_reopen/1k');
    return suffixes.map(s => `binding/${binding}/${s}`);
    }
    function validate(binding, metrics) {
    const ids = expected(binding);
    if (JSON.stringify(Object.keys(metrics).sort()) !== JSON.stringify([...ids].sort())) throw new Error('binding IDs do not match shortlist');
    for (const id of ids) {
    const value = metrics[id]?.latency?.value;
    if (typeof value !== 'number' || !Number.isFinite(value) || value <= 0) throw new Error(`invalid latency: ${id}`);
    }
    return ids;
    }
    function main(command) {
    const read = p => fs.existsSync(p) ? fs.readFileSync(p, 'utf8') : '';
    const binding = process.env.BINDING;
    const ids = expected(binding);
    if (command === 'validate') {
    validate(binding, JSON.parse(read('binding/binding-results.json')));
    const executed = read('binding-execution.txt').split('\n').filter(s => s.startsWith('ok: ')).map(s => s.slice(4));
    if (executed.length !== ids.length || new Set(executed).size !== ids.length || executed.some(id => !ids.includes(id))) throw new Error('executed IDs do not match shortlist');
    return;
    }
    if (command !== 'finish') throw new Error('unknown command');
    // Reuse the tested upload/alert parser without representing these as native
    // Criterion measurements: only the list of executed IDs is adapted.
    const execution = read('binding-execution.txt').replace(/^ok: (.+)$/gm, 'Benchmarking $1: Analyzing');
    const result = audit(ids, execution, read('binding-bencher.txt'), process.env.BENCHER_OUTCOME);
    const report = {
    binding, coreSha: process.env.BENCH_SHA, bindingSha: read('binding-sha.txt').trim(),
    workflowSha: process.env.WORKFLOW_SHA, ref: process.env.BENCH_REF, historyBranch: process.env.BINDING_HISTORY,
    testbed: `binding-${binding}-ubuntu24-v1`, selected: ids, ...result,
    };
    fs.writeFileSync('binding-report.json', JSON.stringify(report, null, 2) + '\n');
    const summary = `### Binding benchmark: ${binding}\n\nCore: ${report.coreSha}; binding: ${report.bindingSha}; workflow: ${report.workflowSha}\n\nHistory branch: ${report.historyBranch}; testbed: ${report.testbed}; executed ${result.executed.length}/${ids.length}; uploaded ${result.uploaded.length}/${ids.length}; alerts ${result.alerts.length}; upload ${result.uploadStatus}\n\n${result.errors.join('\n')}\n`;
    console.log(summary);
    if (process.env.GITHUB_STEP_SUMMARY) fs.appendFileSync(process.env.GITHUB_STEP_SUMMARY, summary);
    if (result.errors.length) process.exitCode = 1;
    }
    module.exports = { expected, validate };
    if (require.main === module) {
    try { main(process.argv[2]); } catch (e) { console.error(e.message); process.exitCode = 1; }
    }
    46 changes: 46 additions & 0 deletions .github/bench/bindings-report.test.cjs
    < 8000 td id="diff-9270e96f5318c81206ab783b11d0c98de7779ec6989a3f28a2612884a4b67f55R10" data-line-number="10" class="blob-num blob-num-addition js-linkable-line-number js-blob-rnum">
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,46 @@
    const { test } = require('node:test');
    const assert = require('node:assert/strict');
    const { expected, validate } = require('./bindings-report.cjs');
    const data = binding => Object.fromEntries(expected(binding).map(id => [id, { latency: { value: 100 } }]));
    test('exact dedicated routes and finite positive latency only', () => {
    for (const binding of ['python', 'browser', 'node', 'c']) {
    assert.equal(validate(binding, data(binding)).length, binding === 'browser' ? 8 : 6);
    const missing = data(binding); delete missing[expected(binding)[0]];
    assert.throws(() => validate(binding, missing), /IDs/);
    const extra = data(binding); extra['native/query'] = { latency: { value: 1 } };
    assert.throws(() => validate(binding, extra), /IDs/);
    for (const value of [0, -1, null, Infinity, '12']) {
    const bad = data(binding); bad[expected(binding)[0]].latency.value = value;
    assert.throws(() => validate(binding, bad), /latency/);
    }
    }
    assert.throws(() => expected('unknown'), /binding/);
    });

    const fs = require('node:fs');
    const os = require('node:os');
    const path = require('node:path');
    const { spawnSync } = require('node:child_process');
    test('CLI verifies execution and records provenance even when upload is partial', () => {
    const dir = fs.mkdtempSync(path.join(os.tmpdir(), 'p16-report-'));
    try {
    fs.mkdirSync(path.join(dir, 'binding'));
    fs.writeFileSync(path.join(dir, 'binding/binding-results.json'), JSON.stringify(data('python')));
    fs.writeFileSync(path.join(dir, 'binding-execution.txt'), expected('python').map(id => `ok: ${id}`).join('\n'));
    fs.writeFileSync(path.join(dir, 'binding-sha.txt'), 'binding-commit\n');
    const env = { ...process.env, BINDING: 'python', BENCH_SHA: 'core-commit', WORKFLOW_SHA: 'workflow-commit', BENCH_REF: 'v3', BINDING_HISTORY: 'binding-experiment/v3/pr', BENCHER_OUTCOME: 'success' };
    const run = command => spawnSync(process.execPath, [path.join(__dirname, 'bindings-report.cjs'), command], { cwd: dir, env, encoding: 'utf8' });
    assert.equal(run('validate').status, 0);
    fs.appendFileSync(path.join(dir, 'binding-execution.txt'), '\nok: binding/python/aggregate/1k');
    assert.notEqual(run('validate').status, 0);
    assert.notEqual(run('finish').status, 0);
    const report = JSON.parse(fs.readFileSync(path.join(dir, 'binding-report.json')));
    assert.equal(report.coreSha, 'core-commit');
    assert.equal(report.bindingSha, 'binding-commit');
    assert.equal(report.workflowSha, 'workflow-commit');
    assert.equal(report.testbed, 'binding-python-ubuntu24-v1');
    assert.equal(report.historyBranch, 'binding-experiment/v3/pr');
    assert.equal(report.uploaded.length, 0);
    assert.ok(report.errors.length);
    } finally { fs.rmSync(dir, { recursive: true, force: true }); }
    });
    60 changes: 60 additions & 0 deletions .github/bench/bindings.sh
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,60 @@
    #!/usr/bin/env bash
    # Called from the core checkout. Never changes checked-in binding dependencies.
    set -euo pipefail
    mode=$1
    binding=$2
    core_dir=$PWD
    export CARGO_TARGET_DIR="$PWD/binding/target/p16"
    export CARGO_BUILD_JOBS=2
    cd binding
    if [[ "$mode" = build ]]; then
    mkdir -p .cargo
    # Benchmark the exact measured core checkout, not the binding's release pin.
    cat > .cargo/config.toml <<EOF
    [patch."https://github.com/project-minigraf/minigraf"]
    minigraf = { path = "$core_dir" }
    EOF
    cargo update -p minigraf
    cargo metadata --format-version 1 > target-metadata.json
    python3 - "$core_dir" <<'PY'
    import json, pathlib, sys
    packages = json.load(open('target-metadata.json'))['packages']
    core = [p for p in packages if p['name'] == 'minigraf']
    assert len(core) == 1 and core[0]['source'] is None
    assert pathlib.Path(core[0]['manifest_path']).parent == pathlib.Path(sys.argv[1])
    PY
    case "$binding" in
    python)
    python3 -m venv target/bench-venv
    source target/bench-venv/bin/activate
    pip install 'maturin>=1.5,<2'
    cargo build --release --bin uniffi-bindgen
    maturin develop --release
    ;;
    browser)
    cargo install wasm-pack --locked --version 0.13.1
    wasm-pack build --target web --out-dir pkg -- --features browser
    npm install --no-save --package-lock=false playwright@1.55.0
    npx playwright install --with-deps chromium
    ;;
    node)
    cargo build --release --lib
    cp "$CARGO_TARGET_DIR/release/libminigraf_node.so" minigraf.linux-x64-gnu.node
    ;;
    c)
    cargo build --release --lib
    cc -O2 -std=c11 -Wall -Wextra -Werror -Iinclude bench/nightly.c \
    "$CARGO_TARGET_DIR/release/libminigraf.a" -lpthread -ldl -lm -o "$CARGO_TARGET_DIR/nightly"
    ;;
    *) exit 1 ;;
    esac
    else
    # --test is forwarded verbatim and never writes timing data.
    shift 2
    case "$binding" in
    python) target/bench-venv/bin/python bench/nightly.py "$@" ;;
    browser|node) node bench/nightly.mjs "$@" ;;
    c) "$CARGO_TARGET_DIR/nightly" "$@" ;;
    *) exit 1 ;;
    esac
    fi
    2 changes: 1 addition & 1 deletion .github/workflows/bench-report.yml
    Original file line number Diff line number Diff line change
    Expand Up @@ -19,4 +19,4 @@ jobs:
    - uses: actions/setup-node@v6
    with:
    node-version: '24'
    - run: node --test .github/bench/report.test.cjs
    - run: node --test .github/bench/*.test.cjs
    Loading
    Loading
    0