104 lines
5.1 KiB
C
104 lines
5.1 KiB
C
/* SPDX-License-Identifier: AGPL-3.0-or-later */
|
|
/* Copyright (C) 2026 David (Corey) Herrera */
|
|
/**
|
|
* @file parity_accel_arm.h
|
|
* @brief Pick the accelerator arm a parity harness should score, and refuse the vacuous
|
|
* CPU-vs-CPU configuration — shared by every harness so the identity control means
|
|
* the same thing in all of them.
|
|
*
|
|
* @status Working
|
|
* @issues None
|
|
* @todo None
|
|
*/
|
|
#ifndef PN_TESTS_PARITY_ACCEL_ARM_H
|
|
#define PN_TESTS_PARITY_ACCEL_ARM_H
|
|
|
|
#include "../include/pantheon.h"
|
|
#include "../src/core/engine.h"
|
|
|
|
/**
|
|
* Return WHICHEVER forward the engine selected for `model`, not a hardcoded one.
|
|
*
|
|
* Hardcoding pn_llama_forward_cuda made a harness silently CPU-vs-CPU on any other card — a
|
|
* green run that proves nothing, which is the failure mode this project keeps paying for.
|
|
*
|
|
* PN_PARITY_IDENTITY=1 deliberately makes the arm the CPU oracle itself. That is the one
|
|
* legitimate CPU-vs-CPU configuration: every reported difference must come out exactly zero,
|
|
* and if it does not, no accelerator number from the harness can be believed. It says so on
|
|
* stderr so a stray environment variable can never be mistaken for a passing card run.
|
|
*
|
|
* The rule is an IDENTITY, not a table: the accelerator arm is `model->forward` whenever it
|
|
* differs from the architecture's own CPU forward. A table of known accelerator symbols has
|
|
* to be extended for every family, and the one that was here listed only the llama pair — so
|
|
* on a qwen35moe model (Ornith) it selected nothing and the caller refused, which is the same
|
|
* blindness in a politer form. The identity rule cannot go stale, and it is also the only
|
|
* rule that gets Bonsai right: that architecture's CPU forward is pn_bonsai_forward while its
|
|
* TT forward is pn_qwen35moe_forward_tt, a pair no per-family table would have written down.
|
|
*
|
|
* @param name_out set to a human name for the arm ("TT", "CUDA", "CPU-IDENTITY-CONTROL")
|
|
* @return the forward to score, or NULL when there is no accelerator and no
|
|
* identity control — in which case the caller must refuse to run
|
|
*
|
|
* Thread-safe: yes Reentrant: yes Signal-safe: no
|
|
*/
|
|
pn_forward_fn parity_select_accel_arm(pn_model *model, const char **name_out);
|
|
|
|
/**
|
|
* The CPU oracle every parity harness scores AGAINST, for `model`'s own architecture.
|
|
*
|
|
* It comes from `pn_get_forward_fn(model->config.arch)` — the engine's own architecture
|
|
* registry — rather than from a second copy of that mapping, so the oracle cannot drift from
|
|
* what the engine calls the CPU path. Harnesses used to hardcode `pn_llama_forward` here,
|
|
* which on a qwen35moe model would have scored a card against a DIFFERENT MODEL's forward
|
|
* reading a qwen35moe weight struct.
|
|
*
|
|
* @param name_out set to a human name for the oracle, e.g. "CPU/qwen35moe"
|
|
* @return the CPU forward, or NULL when the architecture has none
|
|
*
|
|
* Thread-safe: yes Reentrant: yes Signal-safe: no
|
|
*/
|
|
pn_forward_fn parity_select_cpu_oracle(pn_model *model, const char **name_out);
|
|
|
|
/**
|
|
* Refuse a model whose CPU oracle is not `expected`.
|
|
*
|
|
* The arm selection above is deliberately architecture-agnostic, but some harnesses' PROBES
|
|
* are not — a residual-divergence probe casts `model->weights` to `pn_llama_qweights *`, which
|
|
* on any other family is a wrong-struct read, and it used to be protected only by the arm
|
|
* table happening to list llama alone. Making selection general moved that guard out from
|
|
* under them, so it is stated here instead of being an accident of a table.
|
|
*
|
|
* @param tool the harness's name, for the refusal message
|
|
* @return 0 when the oracle matches, -1 when the caller must not run
|
|
*
|
|
* Thread-safe: yes Reentrant: yes Signal-safe: no
|
|
*/
|
|
int parity_require_cpu_oracle(pn_model *model, pn_forward_fn expected, const char *tool);
|
|
|
|
/**
|
|
* Detach or reattach whatever accelerator SEAM this model's family installs on shared state,
|
|
* so the CPU oracle is genuinely the CPU.
|
|
*
|
|
* **NOT EVERY ACCELERATOR IS A FORWARD.** The llama family's is: `pn_llama_forward_tt` is a
|
|
* different function and calling `pn_llama_forward` runs on the host. The qwen35/bonsai
|
|
* family's is a HOOK — `qwen35moe_mv()` consults `cfg->mv.fn` on every projection and the
|
|
* upload installs the card's there — so in a card-armed process the architecture's "CPU
|
|
* forward" still runs all 249 projections on the card. A harness that scored the two forwards
|
|
* against each other there would be comparing the card with the card, and against the
|
|
* RESIDENT-ACTIVATION arm it segfaults instead, which is how this was found.
|
|
*
|
|
* Families with no seam are a no-op, so a caller may bracket every oracle call with this
|
|
* unconditionally.
|
|
*
|
|
* @param enable 0 before running the CPU oracle, non-zero before running the accelerator
|
|
* @return 1 if a seam was attached before the call, 0 if not
|
|
*
|
|
* Thread-safe: no Reentrant: no Signal-safe: no
|
|
*/
|
|
int parity_accel_seam_enable(pn_model *model, int enable);
|
|
|
|
/** @return non-zero when PN_PARITY_IDENTITY selected the identity control. */
|
|
int parity_identity_control_active(void);
|
|
|
|
#endif /* PN_TESTS_PARITY_ACCEL_ARM_H */
|