1287 lines
72 KiB
Makefile
1287 lines
72 KiB
Makefile
# SPDX-License-Identifier: AGPL-3.0-or-later
|
|
# Copyright (C) 2026 David (Corey) Herrera
|
|
# Pantheon Makefile
|
|
#
|
|
# Builds Pantheon sources + Foundry sources into a single binary.
|
|
#
|
|
# Foundry location, in precedence order:
|
|
# 1. FOUNDRY=/path/to/foundry explicit override
|
|
# 2. ./foundry the git submodule (git clone --recursive, or
|
|
# git submodule update --init), or a symlink
|
|
# 3. ../foundry sibling checkout
|
|
|
|
CC ?= clang
|
|
# CPU target. Default -march=native: fastest, but the binary only runs on a CPU
|
|
# with the build machine's instruction set, so build on the machine that runs it.
|
|
# PORTABLE=1 builds a binary you can copy between machines: -march=x86-64-v2 on
|
|
# x86-64 (SSE4.2, no AVX; runs on any x86-64 CPU since ~2009), the compiler's
|
|
# generic default elsewhere.
|
|
ifeq ($(PORTABLE),1)
|
|
ifneq ($(filter x86_64 amd64,$(shell uname -m)),)
|
|
ARCH_FLAGS = -march=x86-64-v2
|
|
else
|
|
ARCH_FLAGS =
|
|
endif
|
|
else
|
|
ARCH_FLAGS = -march=native
|
|
endif
|
|
CFLAGS = -Wall -Wextra -std=c11 -O3 $(ARCH_FLAGS) -ffast-math
|
|
CFLAGS += -I$(FOUNDRY) -I.
|
|
ifneq ($(shell uname -s),Darwin)
|
|
CFLAGS += -D_GNU_SOURCE
|
|
endif
|
|
|
|
# The serve layer (pantheon serve) is thread-per-connection, so pthreads are
|
|
# linked unconditionally. This is independent of the opt-in USE_THREADS compute
|
|
# thread pool below.
|
|
CFLAGS += -pthread
|
|
LDFLAGS += -pthread
|
|
|
|
FOUNDRY ?= $(if $(wildcard ./foundry/tensor/tensor.h),./foundry,../foundry)
|
|
|
|
ifeq ($(wildcard $(FOUNDRY)/tensor/tensor.h),)
|
|
$(error Foundry not found at '$(FOUNDRY)'. Run 'git submodule update --init', \
|
|
symlink a checkout to ./foundry, clone it as ../foundry, or pass FOUNDRY=/path/to/foundry)
|
|
endif
|
|
|
|
# Debug build
|
|
ifdef DEBUG
|
|
CFLAGS = -Wall -Wextra -std=c11 -O0 -g -DDEBUG
|
|
CFLAGS += -I$(FOUNDRY) -I.
|
|
endif
|
|
|
|
# ============================================================
|
|
# Build provenance: the commit this binary came from.
|
|
#
|
|
# Stamped into src/accel/backend_identity.c so the process can print it next to
|
|
# its backend at startup and through `pantheon --backend`. A tree with no git
|
|
# (a tarball, a copied checkout) reports "unknown" rather than failing the
|
|
# build — the point is that the binary never has to be reverse-engineered with
|
|
# `strings`, and "unknown" is itself an answer.
|
|
#
|
|
# Deliberately appended AFTER the DEBUG block, which REASSIGNS CFLAGS: put it
|
|
# above and a DEBUG=1 build silently loses the stamp.
|
|
# ============================================================
|
|
PN_BUILD_COMMIT := $(shell git rev-parse --short=12 HEAD 2>/dev/null || echo unknown)
|
|
PN_BUILD_DIRTY := $(shell git diff --quiet HEAD 2>/dev/null || echo -dirty)
|
|
CFLAGS += -DPN_BUILD_COMMIT='"$(PN_BUILD_COMMIT)$(PN_BUILD_DIRTY)"'
|
|
|
|
# pthread thread pool (opt-in: make USE_THREADS=1)
|
|
ifdef USE_THREADS
|
|
CFLAGS += -DUSE_THREADS -pthread
|
|
LDFLAGS += -pthread
|
|
THREADPOOL_SRC = $(FOUNDRY)/threadpool/threadpool.c
|
|
else
|
|
THREADPOOL_SRC =
|
|
endif
|
|
|
|
# BLAS acceleration (opt-in: make USE_BLAS=1)
|
|
ifdef USE_BLAS
|
|
CFLAGS += -DUSE_BLAS
|
|
ifeq ($(shell uname -s),Darwin)
|
|
CFLAGS += -DACCELERATE_NEW_LAPACK
|
|
LDFLAGS_BLAS = -framework Accelerate
|
|
else
|
|
CFLAGS += -DUSE_OPENBLAS
|
|
LDFLAGS_BLAS = -lopenblas
|
|
endif
|
|
else
|
|
LDFLAGS_BLAS =
|
|
endif
|
|
|
|
# Metal GPU backend (opt-in: make USE_METAL=1, macOS only)
|
|
ifdef USE_METAL
|
|
CFLAGS += -DUSE_METAL
|
|
LDFLAGS_METAL = -framework Metal -framework MetalPerformanceShaders -framework Foundation
|
|
# fm_metal is a device/queue/pipeline core plus one unit per kernel family
|
|
# (foundry P1.0, cfa6727). Globbed, never hand-listed: the family units are
|
|
# added one per kernel through Phase 1, and a hand-listed link line fails as
|
|
# an undefined symbol at the END of a 40-source compile.
|
|
METAL_SRC = $(FOUNDRY)/metal/fm_metal.m $(wildcard $(FOUNDRY)/metal/kernels/*.m)
|
|
OBJCFLAGS = -Wall -Wextra -O3 -ffast-math -fobjc-arc -DUSE_METAL -I$(FOUNDRY) -I.
|
|
ifdef DEBUG
|
|
OBJCFLAGS = -Wall -Wextra -O0 -g -DDEBUG -fobjc-arc -DUSE_METAL -I$(FOUNDRY) -I.
|
|
endif
|
|
else
|
|
LDFLAGS_METAL =
|
|
METAL_SRC =
|
|
endif
|
|
|
|
# CUDA GPU backend (opt-in: make USE_CUDA=1, Linux only)
|
|
ifdef USE_CUDA
|
|
CFLAGS += -DUSE_CUDA
|
|
LDFLAGS_CUDA = -ldl
|
|
# barswap.c is pulled in too: the 2-die layer-split forward in
|
|
# qwen35moe_forward_cuda.c time-multiplexes the K80 dies through the single
|
|
# MMIO slot via bs_acquire/bs_release. On a single-die host it is harmless
|
|
# (only the 2-die path calls it, gated by a configured split layer).
|
|
CUDA_SRC = $(FOUNDRY)/cuda/fc_cuda.c $(FOUNDRY)/barswap/barswap.c
|
|
else
|
|
LDFLAGS_CUDA =
|
|
CUDA_SRC =
|
|
endif
|
|
|
|
# Tenstorrent Blackhole backend (opt-in: make USE_TT=1, Linux only)
|
|
#
|
|
# FT_TT_PHASE1B_NOC_ENABLED comes with it and is deliberately not a second knob.
|
|
# The fence exists so a DEFAULT foundry build cannot issue a NoC transaction
|
|
# during bring-up; a Pantheon serve that opens the card is past that by
|
|
# definition, and without it ft_tt_mem_info() cannot read a bank count, so
|
|
# pn_dm_init_tt() refuses every device. Coupling the two is what stops a build
|
|
# that links the backend and then silently declines to see the card.
|
|
#
|
|
# Device kernels are NOT built here: SFPI is needed only to bake them, and the kernel ELFs
|
|
# are pre-baked into tt/ft_tt_kernels.h — the same trick cuda/ uses for PTX.
|
|
#
|
|
# ft_tt_program_blob.c + ft_tt_program_resolve.c are what make that true of whole
|
|
# PROGRAMS as well, and they are named here rather than dragged in by a foundry
|
|
# header on purpose: ft_tt_program_resolve.c is the only file that pulls the
|
|
# 2.8 MB tt/ft_tt_programs.h into a link, so a build that has not adopted
|
|
# name-based program resolution links exactly what it linked before. Pantheon
|
|
# HAS adopted it (pn_tt_device.c, pn_tt_oncard.c), which is why the binary now
|
|
# carries its own Tensix programs instead of reading them out of a home
|
|
# directory at start-up.
|
|
#
|
|
# The ft_tt_udrv_* files are foundry's OWN USERSPACE DRIVER, linked in so that
|
|
# FT_TT_DRIVER=udrv can reach the card on a machine with no vendor module.
|
|
# Linking them is not using them: the default transport is still tt-kmd and
|
|
# ft_tt_runtime_open() is the only thing that ever chooses. What linking buys is
|
|
# that ONE binary runs on a board with tt-kmd and on the board that will not
|
|
# have it, which is the whole point of Phase 12 — the alternative is a second
|
|
# build configuration nobody tests until the card has already moved.
|
|
ifdef USE_TT
|
|
# tt/convert/ sources include tt/ headers by bare name (ft_tt_op_l1_layout.h), which
|
|
# resolves in the convert tools' own build via -I../.. and resolves nowhere here.
|
|
CFLAGS += -DUSE_TT -DFT_TT_PHASE1B_NOC_ENABLED -I$(FOUNDRY)/tt
|
|
TT_SRC = $(FOUNDRY)/tt/ft_tt_kmd.c \
|
|
$(FOUNDRY)/tt/ft_tt_arch.c \
|
|
$(FOUNDRY)/tt/ft_tt_arch_blackhole.c \
|
|
$(FOUNDRY)/tt/ft_tt_device.c \
|
|
$(FOUNDRY)/tt/ft_tt_tlb.c \
|
|
$(FOUNDRY)/tt/ft_tt_arc_telemetry.c \
|
|
$(FOUNDRY)/tt/ft_tt_coord.c \
|
|
$(FOUNDRY)/tt/ft_tt_noc.c \
|
|
$(FOUNDRY)/tt/ft_tt_buffer.c \
|
|
$(FOUNDRY)/tt/ft_tt_elf.c \
|
|
$(FOUNDRY)/tt/ft_tt_kernel_blob.c \
|
|
$(FOUNDRY)/tt/ft_tt_program_blob.c \
|
|
$(FOUNDRY)/tt/ft_tt_program_resolve.c \
|
|
$(FOUNDRY)/tt/ft_tt_launch.c \
|
|
$(FOUNDRY)/tt/ft_tt_core_status.c \
|
|
$(FOUNDRY)/tt/ft_tt_core_readiness.c \
|
|
$(FOUNDRY)/tt/ft_tt_multicast.c \
|
|
$(FOUNDRY)/tt/ft_tt_group_shared_operand.c \
|
|
$(FOUNDRY)/tt/ft_tt_dram_stripe.c \
|
|
$(FOUNDRY)/tt/ft_tt_op_matmul_cooperative.c \
|
|
$(FOUNDRY)/tt/ft_tt_group_broadcast_partition.c \
|
|
$(FOUNDRY)/tt/ft_tt_op_matmul_resident_multicast.c \
|
|
$(FOUNDRY)/tt/ft_tt_tilize.c \
|
|
$(FOUNDRY)/tt/ft_tt_tile_row0.c \
|
|
$(FOUNDRY)/tt/ft_tt_watchdog.c \
|
|
$(FOUNDRY)/tt/ft_tt_queue.c \
|
|
$(FOUNDRY)/tt/ft_tt_group.c \
|
|
$(FOUNDRY)/tt/ft_tt_runtime.c \
|
|
$(FOUNDRY)/tt/ft_tt_runtime_udrv.c \
|
|
$(FOUNDRY)/tt/ft_tt_udrv_pci_sysfs.c \
|
|
$(FOUNDRY)/tt/ft_tt_udrv_tlb_encode.c \
|
|
$(FOUNDRY)/tt/ft_tt_udrv_claim.c \
|
|
$(FOUNDRY)/tt/ft_tt_udrv_noc.c \
|
|
$(FOUNDRY)/tt/ft_tt_udrv_noc_bank.c \
|
|
$(FOUNDRY)/tt/ft_tt_udrv_arc_msg.c \
|
|
$(FOUNDRY)/tt/ft_tt_udrv_arc_probe.c \
|
|
$(FOUNDRY)/tt/ft_tt_udrv_reset.c \
|
|
$(FOUNDRY)/tt/ft_tt_fttw.c \
|
|
$(FOUNDRY)/tt/ft_tt_op_dispatch.c \
|
|
$(FOUNDRY)/tt/ft_tt_op_matmul.c \
|
|
$(FOUNDRY)/tt/ft_tt_op_memory.c \
|
|
$(FOUNDRY)/tt/ft_tt_op_rms_norm.c \
|
|
$(FOUNDRY)/tt/ft_tt_op_rope.c \
|
|
$(FOUNDRY)/tt/ft_tt_op_sample.c \
|
|
$(FOUNDRY)/tt/ft_tt_op_vector.c \
|
|
$(FOUNDRY)/tt/ft_tt_op_attention.c \
|
|
$(FOUNDRY)/tt/ft_tt_op_gdn.c \
|
|
$(FOUNDRY)/tt/ft_tt_op_gdnc.c \
|
|
$(FOUNDRY)/tt/ft_tt_op_replicas.c \
|
|
$(FOUNDRY)/tt/convert/ft_bfp.c \
|
|
$(FOUNDRY)/tt/convert/ft_float_convert.c \
|
|
$(FOUNDRY)/tt/convert/ft_tt_precision_ledger.c \
|
|
$(FOUNDRY)/tt/convert/ft_gguf_map.c \
|
|
$(FOUNDRY)/tt/convert/ft_gguf_dequant.c \
|
|
$(FOUNDRY)/tt/convert/ft_tt_weight_convert.c \
|
|
$(FOUNDRY)/tt/convert/ft_tt_capacity_plan.c \
|
|
$(FOUNDRY)/tt/convert/ft_tt_artifact_provenance.c \
|
|
$(FOUNDRY)/tt/convert/ft_tt_artifact_cache.c
|
|
else
|
|
TT_SRC =
|
|
endif
|
|
|
|
# ============================================================
|
|
# Foundry sources we depend on
|
|
# ============================================================
|
|
|
|
FOUNDRY_SRC = \
|
|
$(FOUNDRY)/tensor/tensor.c \
|
|
$(FOUNDRY)/safetensors/safetensors.c \
|
|
$(FOUNDRY)/tokenizer/tokenizer.c \
|
|
$(FOUNDRY)/quantization/quantization.c \
|
|
$(FOUNDRY)/pth/pth.c \
|
|
$(THREADPOOL_SRC) \
|
|
$(METAL_SRC) \
|
|
$(CUDA_SRC) \
|
|
$(TT_SRC)
|
|
|
|
# ============================================================
|
|
# Pantheon sources
|
|
# ============================================================
|
|
|
|
PN_SRC = \
|
|
src/core/engine.c \
|
|
src/core/mem/pn_host_signals.c \
|
|
src/core/mem/pn_memwatch.c \
|
|
src/core/mem/pn_admission.c \
|
|
src/core/mem/pn_kv_geometry.c \
|
|
src/core/mem/pn_ladder.c \
|
|
src/core/mem/pn_lazy_zero.c \
|
|
src/core/bench.c \
|
|
src/core/sample_profiler.c \
|
|
src/core/qweight.c \
|
|
src/core/sampling_modifiers.c \
|
|
src/core/grammar_mask_shortlist.c \
|
|
src/core/chat.c \
|
|
src/core/bpe_pretokenize.c \
|
|
src/core/ngram_draft.c \
|
|
src/core/prefix_cache.c \
|
|
src/core/session_snapshot.c \
|
|
src/memory/arena.c \
|
|
src/accel/simd.c \
|
|
src/accel/die_manager.c \
|
|
src/accel/die_layer_split.c \
|
|
src/accel/backend_identity.c \
|
|
src/accel/tt/pn_tt_device.c \
|
|
src/accel/tt/pn_tt_matmul_group.c \
|
|
src/accel/tt/pn_tt_residency.c \
|
|
src/accel/tt/pn_tt_issue.c \
|
|
src/accel/tt/pn_tt_core_boot_guard.c \
|
|
src/accel/tt/pn_tt_oncard.c \
|
|
src/accel/tt/pn_tt_eltwise_group.c \
|
|
src/accel/tt/pn_tt_eltwise_split.c \
|
|
src/accel/tt/pn_tt_reader.c \
|
|
src/accel/tt/pn_tt_attention.c \
|
|
src/accel/tt/pn_tt_gdn.c \
|
|
src/accel/tt/pn_tt_gdn_checkpoint.c \
|
|
src/accel/tt/pn_tt_gdnc.c \
|
|
src/accel/tt/pn_tt_gdngate.c \
|
|
src/accel/tt/pn_tt_stage_pipeline.c \
|
|
src/accel/tt/pn_tt_head_norm.c \
|
|
src/accel/tt/pn_tt_render.c \
|
|
src/accel/tt/pn_tt_gate.c \
|
|
src/accel/tt/pn_tt_fp32_strip.c \
|
|
src/accel/tt/pn_tt_column_runs.c \
|
|
src/accel/tt/pn_tt_descriptor_census.c \
|
|
src/accel/tt/pn_tt_name_list.c \
|
|
src/accel/tt/pn_tt_gdn_layout.c \
|
|
src/accel/tt/pn_tt_gdn_core_scaling.c \
|
|
src/accel/tt/pn_tt_replica_map.c \
|
|
src/accel/tt/pn_tt_dispatch.c \
|
|
src/formats/gguf.c \
|
|
src/formats/gguf_dequant.c \
|
|
src/formats/gguf_layer_bytes.c \
|
|
src/models/llama.c \
|
|
src/models/llama_state_snapshot.c \
|
|
src/models/llama_attention_trace.c \
|
|
src/models/llama_residual_trace.c \
|
|
src/models/llama_forward_cuda.c \
|
|
src/models/llama_forward_tt.c \
|
|
src/models/pixtral_vision.c \
|
|
src/models/phi3.c \
|
|
src/models/rwkvx.c \
|
|
src/models/gpu_attn_path_tracker.c \
|
|
src/models/gpu_graph_capture_tracker.c \
|
|
src/models/qwen35moe.c \
|
|
src/models/qwen35moe_attn.c \
|
|
src/models/qwen35moe_ssm.c \
|
|
src/models/qwen35moe_moe.c \
|
|
src/models/qwen35moe_forward.c \
|
|
src/models/qwen35moe_forward_cuda.c \
|
|
src/models/qwen35moe_forward_tt.c \
|
|
src/models/qwen35moe_resident_tt.c \
|
|
src/models/qwen35moe_gdn_tt.c \
|
|
src/models/qwen35moe_gdn_strip_tt.c \
|
|
src/models/qwen35moe_attn_tt.c \
|
|
src/models/qwen35moe_prefill_tt.c \
|
|
src/models/qwen35moe_prefill_checkpoint_tt.c \
|
|
src/models/qwen35moe_checkpoint_band.c \
|
|
src/models/qwen35moe_prefill_prefetch_tt.c \
|
|
src/models/qwen35moe_prefill_overlap_tt.c \
|
|
src/models/qwen35moe_prefill_tt_wall.c \
|
|
src/models/qwen35moe_gdn_parity_tt.c \
|
|
src/models/qwen35moe_gdn_normcheck_tt.c \
|
|
src/models/qwen35moe_forward_metal.c \
|
|
src/models/qwen35moe_metal_kernel_registry.c \
|
|
src/models/qwen35moe_metal_coverage.c \
|
|
src/models/qwen35moe_state_snapshot.c \
|
|
src/models/bonsai_forward.c
|
|
|
|
# OpenAI-compatible HTTP serving layer (pantheon serve). Pure C + POSIX
|
|
# sockets; no extra link deps. Compiled into the CLI and the static library.
|
|
SERVE_SRC = \
|
|
src/serve/json_reader.c \
|
|
src/serve/json_writer.c \
|
|
src/serve/attn_residency_json.c \
|
|
src/serve/graph_residency_json.c \
|
|
src/serve/http_server.c \
|
|
src/serve/json_value_grammar.c \
|
|
src/serve/tool_calling.c \
|
|
src/serve/tool_grammar.c \
|
|
src/serve/tool_grammar_json.c \
|
|
src/serve/grammar_spec_chooser.c \
|
|
src/serve/tool_param_empty_value_rule.c \
|
|
src/serve/response_format_grammar.c \
|
|
src/serve/serve_emitter.c \
|
|
src/serve/json_canonical_stream.c \
|
|
src/serve/tool_call_stream.c \
|
|
src/serve/repetition_loop_detector.c \
|
|
src/serve/serve_prompt_tokens.c \
|
|
src/serve/serve_spec_lookup.c \
|
|
src/serve/serve_generation.c \
|
|
src/serve/model_registry.c \
|
|
src/serve/model_session.c \
|
|
src/serve/batch_sched.c \
|
|
src/serve/base64.c \
|
|
src/serve/model_admin.c \
|
|
src/serve/openai_chat.c \
|
|
src/serve/request_profile.c \
|
|
src/serve/signal_handlers.c \
|
|
src/serve/serve_shutdown.c \
|
|
src/serve/serve_backend_guard.c \
|
|
src/serve/serve_command.c \
|
|
src/serve/session_watch.c \
|
|
src/serve/serve_registry.c \
|
|
src/serve/registry.c \
|
|
src/serve/session_affinity.c \
|
|
src/serve/registry_client.c \
|
|
src/serve/http_client.c \
|
|
src/serve/router.c \
|
|
src/serve/router_command.c
|
|
|
|
# ============================================================
|
|
# Header dependencies — DISCOVERED, never hand-listed
|
|
#
|
|
# Every harness/test binary below is a one-shot whole-program compile whose
|
|
# prerequisites are .c files ONLY. A changed HEADER therefore left make saying
|
|
# "is up to date" and handing back the PREVIOUS binary.
|
|
#
|
|
# For $(FOUNDRY)/cuda/fc_cuda_ptx.h — the GENERATED header carrying the
|
|
# embedded PTX for every CUDA kernel (regenerated on a CUDA host by
|
|
# cuda_kernels/Makefile) — that fails in the worst possible direction: the A/B
|
|
# reads 1.000x and the bit-exactness gate passes vacuously. Both look like an
|
|
# honest "no change" rather than a broken build.
|
|
#
|
|
# The list is produced by find, NOT written by hand, so it cannot go stale the
|
|
# way this file's link lines already have once (Pantheon 8616f92, five targets
|
|
# with stale hand-maintained link lines). It is deliberately over-approximate:
|
|
# these targets recompile every .c on every build anyway, so per-target
|
|
# precision would buy nothing. The one place objects ARE compiled separately
|
|
# (libpantheon.a) uses real -MMD -MP depfiles instead.
|
|
#
|
|
# `pantheon` and `pantheon-convert` are .PHONY and so always rebuild — that is
|
|
# deliberate and is what keeps a flag change (USE_CUDA=1 etc., which make
|
|
# cannot see) from silently reusing a binary built with different flags.
|
|
# ============================================================
|
|
PN_HDR := $(shell find -L src include cli tests -name '*.h' 2>/dev/null)
|
|
FOUNDRY_HDR := $(shell find -L $(FOUNDRY) -name '.git' -prune -o -name '*.h' -print 2>/dev/null)
|
|
ALL_HDR := $(PN_HDR) $(FOUNDRY_HDR)
|
|
|
|
# ============================================================
|
|
# PER-BACKEND OUTPUT NAMES — the three builds are three programs
|
|
#
|
|
# `make`, `make USE_CUDA=1` and `make USE_TT=1` produce binaries that cannot run
|
|
# each other's work, and until this block they all wrote ONE file, `pantheon`.
|
|
# Last build won, silently. That is how a CPU-only binary came to sit at the
|
|
# path a deploy config named as its binary and serve a 35B
|
|
# MoE off a 2-core no-AVX Pentium with all 8 K80 dies idle at 0 MiB, for an
|
|
# unknown period, with measurements taken against it: a Tenstorrent session ran
|
|
# `rm -f pantheon && make USE_TT=1 pantheon` in that checkout, and a later bare
|
|
# `make` left a CPU build behind.
|
|
#
|
|
# So each backend gets its OWN name. A TT build is now physically incapable of
|
|
# overwriting the deployed CUDA binary — it writes a different file.
|
|
#
|
|
# `pantheon` survives as a SYMLINK to whichever backend was built last, because
|
|
# deploy scripts, tests/serve_*.sh and the docs all name it. The symlink keeps every
|
|
# existing invocation working AND fixes the damage case: a stray TT build now
|
|
# only re-points a link, so `ln -sfn pantheon-cuda pantheon` restores a CUDA
|
|
# deployment in one command instead of a ~10-minute CUDA rebuild. The link is not the
|
|
# safety net, though — `pantheon --backend` is (check it in a deploy preflight),
|
|
# and the serve refuses to start when --dies names dies it cannot use.
|
|
#
|
|
# Combination builds get a combination name so no two configurations can ever
|
|
# collide on one path.
|
|
# ============================================================
|
|
PN_BACKEND_SUFFIX :=
|
|
ifdef USE_CUDA
|
|
PN_BACKEND_SUFFIX := $(PN_BACKEND_SUFFIX)-cuda
|
|
endif
|
|
ifdef USE_TT
|
|
PN_BACKEND_SUFFIX := $(PN_BACKEND_SUFFIX)-tt
|
|
endif
|
|
ifdef USE_METAL
|
|
PN_BACKEND_SUFFIX := $(PN_BACKEND_SUFFIX)-metal
|
|
endif
|
|
ifeq ($(PN_BACKEND_SUFFIX),)
|
|
PN_BACKEND_SUFFIX := -cpu
|
|
endif
|
|
|
|
PN_BIN := pantheon$(PN_BACKEND_SUFFIX)
|
|
PN_COMPAT_BIN := pantheon
|
|
|
|
# Every per-backend name this build system can emit — `clean` has to remove all
|
|
# of them, not just the one the current flags select, or a stale binary from
|
|
# another configuration outlives the clean that was supposed to remove it.
|
|
PN_ALL_BINS := pantheon-cpu pantheon-cuda pantheon-tt pantheon-metal \
|
|
pantheon-cuda-tt pantheon-cuda-metal pantheon-tt-metal \
|
|
pantheon-cuda-tt-metal
|
|
|
|
# ============================================================
|
|
# Targets
|
|
# ============================================================
|
|
|
|
.PHONY: all clean test pantheon pantheon-convert $(PN_BIN)
|
|
|
|
all: pantheon
|
|
|
|
# CLI binary, named for its backend. PHONY (as `pantheon` always was): make
|
|
# cannot see a flag change, so a rebuild is the only thing that keeps
|
|
# USE_CUDA=1 from silently reusing a CPU object graph.
|
|
$(PN_BIN): cli/main.c $(PN_SRC) $(SERVE_SRC) $(FOUNDRY_SRC)
|
|
$(CC) $(CFLAGS) -o $@ cli/main.c $(PN_SRC) $(SERVE_SRC) $(FOUNDRY_SRC) \
|
|
-lm $(LDFLAGS) $(LDFLAGS_BLAS) $(LDFLAGS_METAL) $(LDFLAGS_CUDA)
|
|
@echo "built $@ (backend $(PN_BACKEND_SUFFIX:-%=%), commit $(PN_BUILD_COMMIT)$(PN_BUILD_DIRTY))"
|
|
|
|
# Back-compat: `make pantheon` still works and still leaves something runnable
|
|
# at ./pantheon — now a symlink, so the OTHER backends' binaries survive it.
|
|
# rm-then-ln rather than `ln -sfn`: the deployed ./pantheon is a regular FILE
|
|
# until the first build after this change, and rm-then-ln replaces both a file
|
|
# and a link identically on GNU and BSD.
|
|
pantheon: $(PN_BIN)
|
|
@rm -f $(PN_COMPAT_BIN)
|
|
@ln -s $(PN_BIN) $(PN_COMPAT_BIN)
|
|
@echo "./$(PN_COMPAT_BIN) -> $(PN_BIN) (verify with: ./$(PN_COMPAT_BIN) --backend)"
|
|
|
|
# `make pantheon-cuda` WITHOUT USE_CUDA=1 must not quietly produce a CPU binary
|
|
# wearing a CUDA name — that is precisely the confusion the rename exists to
|
|
# remove, and it would be worse than the original bug because the file name
|
|
# would now be an active lie. Every backend name that is not the one these flags
|
|
# select refuses and prints the flag it wanted.
|
|
PN_WRONG_FLAG_BINS := $(filter-out $(PN_BIN),$(PN_ALL_BINS))
|
|
.PHONY: $(PN_WRONG_FLAG_BINS)
|
|
$(PN_WRONG_FLAG_BINS):
|
|
@echo "make: '$@' needs its backend flag — these flags build $(PN_BIN)." >&2
|
|
@echo " cuda: make USE_CUDA=1 tt: make USE_TT=1" >&2
|
|
@echo " metal: make USE_METAL=1 cpu: make" >&2
|
|
@false
|
|
|
|
# ============================================================
|
|
# Static library for embedding in another program — same objects as the CLI
|
|
# minus cli/main.c. Build with the SAME flags you intend to link against, e.g.:
|
|
# make USE_BLAS=1 USE_THREADS=1 libpantheon.a
|
|
# then link: -lpantheon <Accelerate/Metal/openblas as used> -lm
|
|
# ============================================================
|
|
LIB_OBJDIR = build/lib
|
|
LIB_C_ONLY = $(filter %.c,$(PN_SRC) $(SERVE_SRC) $(FOUNDRY_SRC))
|
|
LIB_OBJS = $(patsubst %,$(LIB_OBJDIR)/%.o,$(LIB_C_ONLY))
|
|
ifdef USE_METAL
|
|
LIB_OBJS += $(patsubst %,$(LIB_OBJDIR)/%.o,$(METAL_SRC))
|
|
endif
|
|
LIB_DEPS = $(LIB_OBJS:.o=.d)
|
|
|
|
# Real depfiles: these are the only separately-compiled objects in the build,
|
|
# so the precise mechanism applies. -MMD writes
|
|
# build/lib/<path>.c.d beside the object; -MP adds phony targets so a DELETED
|
|
# header does not wedge the build.
|
|
$(LIB_OBJDIR)/%.c.o: %.c
|
|
@mkdir -p $(dir $@)
|
|
$(CC) $(CFLAGS) -MMD -MP -c $< -o $@
|
|
|
|
# Same mechanism for the Objective-C Metal units. A pattern rule, not one rule
|
|
# per file, so a new kernel family unit needs no Makefile edit.
|
|
$(LIB_OBJDIR)/%.m.o: %.m
|
|
@mkdir -p $(dir $@)
|
|
$(CC) $(OBJCFLAGS) -MMD -MP -c $< -o $@
|
|
|
|
-include $(LIB_DEPS)
|
|
|
|
libpantheon.a: $(LIB_OBJS)
|
|
ar rcs $@ $(LIB_OBJS)
|
|
@echo "built $@ (public header: include/pantheon.h)"
|
|
@echo "link with: -lpantheon $(LDFLAGS_BLAS) $(LDFLAGS_METAL) $(LDFLAGS_CUDA) -lm"
|
|
|
|
# Build + run tests
|
|
test: tests/test_backend_guard tests/test_build tests/test_gguf tests/test_gguf_layer_bytes tests/test_admission_reserve tests/test_die_scratch_ctx tests/test_die_layer_split tests/test_arena tests/test_qmv tests/test_simd tests/test_simd_props tests/test_chat tests/test_tool_calling tests/test_tool_call_defects tests/test_tool_call_truncation tests/test_empty_argument tests/test_frame_capture tests/test_json_value_grammar tests/test_tool_grammar tests/test_tool_grammar_json tests/test_grammar_spec_chooser tests/test_grammar_mask_shortlist tests/test_grammar_topn_sampler tests/test_response_format_grammar tests/test_sampling_modifiers tests/test_chat_request tests/test_serve_emitter tests/test_tool_call_stream tests/test_repetition_loop_detector tests/test_serve_spec_lookup tests/test_registry tests/test_base64 tests/test_prefix_cache_sys tests/test_llama_state_snapshot tests/test_prefix_projection tests/test_session_watch tests/test_session_affinity tests/test_bs_load tests/test_bpe_pretokenize tests/test_pretok_props tests/test_dequant_props tests/test_rwkvx tests/test_qwen35moe tests/test_qwen35_prefill_causality tests/test_qwen35moe_metal_coverage tests/test_qwen35moe_metal_coverage_fake tests/test_die_manager tests/test_model_registry tests/test_model_unload_reclaim tests/test_embed_row tests/test_tt_column_runs tests/test_qwen35_ckpt_band tests/test_tt_name_list tests/test_tt_eltwise_split tests/test_tt_descriptor_census tests/test_tt_stage_pipeline tests/test_graph_capture_retry tests/test_attn_ring_retry tests/test_serve_shutdown
|
|
./tests/test_backend_guard
|
|
./tests/test_build
|
|
./tests/test_gguf
|
|
./tests/test_gguf_layer_bytes
|
|
./tests/test_admission_reserve
|
|
./tests/test_die_scratch_ctx
|
|
./tests/test_die_layer_split
|
|
./tests/test_arena
|
|
./tests/test_qmv
|
|
./tests/test_simd
|
|
./tests/test_simd_props
|
|
./tests/test_chat
|
|
./tests/test_tool_calling
|
|
./tests/test_tool_call_defects
|
|
./tests/test_tool_call_truncation
|
|
./tests/test_empty_argument
|
|
./tests/test_frame_capture
|
|
./tests/test_json_value_grammar
|
|
./tests/test_tool_grammar
|
|
./tests/test_tool_grammar_json
|
|
./tests/test_grammar_spec_chooser
|
|
./tests/test_grammar_mask_shortlist
|
|
./tests/test_grammar_topn_sampler
|
|
./tests/test_grammar_topn_sampler --selftest
|
|
./tests/test_response_format_grammar
|
|
./tests/test_sampling_modifiers
|
|
./tests/test_chat_request
|
|
./tests/test_serve_emitter
|
|
./tests/test_tool_call_stream
|
|
./tests/test_repetition_loop_detector
|
|
./tests/test_registry
|
|
./tests/test_base64
|
|
./tests/test_prefix_cache_sys
|
|
./tests/test_llama_state_snapshot
|
|
./tests/test_prefix_projection
|
|
./tests/test_session_watch
|
|
./tests/test_session_affinity
|
|
./tests/test_bs_load
|
|
./tests/test_bpe_pretokenize
|
|
./tests/test_pretok_props
|
|
./tests/test_dequant_props
|
|
./tests/test_rwkvx
|
|
./tests/test_qwen35moe
|
|
./tests/test_qwen35_prefill_causality
|
|
./tests/test_qwen35moe_metal_coverage
|
|
./tests/test_qwen35moe_metal_coverage_fake
|
|
./tests/test_die_manager
|
|
./tests/test_model_registry
|
|
./tests/test_model_unload_reclaim
|
|
./tests/test_embed_row
|
|
./tests/test_tt_column_runs
|
|
./tests/test_qwen35_ckpt_band
|
|
./tests/test_tt_eltwise_split
|
|
./tests/test_tt_descriptor_census
|
|
./tests/test_graph_capture_retry
|
|
./tests/test_graph_capture_retry --latch
|
|
./tests/test_attn_ring_retry
|
|
./tests/test_attn_ring_retry --latch
|
|
./tests/test_serve_shutdown
|
|
|
|
tests/test_build: tests/test_build.c $(PN_SRC) $(FOUNDRY_SRC) $(ALL_HDR)
|
|
$(CC) $(CFLAGS) -o $@ tests/test_build.c $(PN_SRC) $(FOUNDRY_SRC) \
|
|
-lm $(LDFLAGS) $(LDFLAGS_BLAS) $(LDFLAGS_METAL) $(LDFLAGS_CUDA)
|
|
|
|
tests/test_gguf: tests/test_gguf.c $(PN_SRC) $(FOUNDRY_SRC) $(ALL_HDR)
|
|
$(CC) $(CFLAGS) -o $@ tests/test_gguf.c $(PN_SRC) $(FOUNDRY_SRC) \
|
|
-lm $(LDFLAGS) $(LDFLAGS_BLAS) $(LDFLAGS_METAL) $(LDFLAGS_CUDA)
|
|
|
|
tests/test_gguf_layer_bytes: tests/test_gguf_layer_bytes.c $(PN_SRC) $(FOUNDRY_SRC) $(ALL_HDR)
|
|
$(CC) $(CFLAGS) -o $@ tests/test_gguf_layer_bytes.c $(PN_SRC) $(FOUNDRY_SRC) \
|
|
-lm $(LDFLAGS) $(LDFLAGS_BLAS) $(LDFLAGS_METAL) $(LDFLAGS_CUDA)
|
|
|
|
tests/test_admission_reserve: tests/test_admission_reserve.c $(PN_SRC) $(FOUNDRY_SRC) $(ALL_HDR)
|
|
$(CC) $(CFLAGS) -o $@ tests/test_admission_reserve.c $(PN_SRC) $(FOUNDRY_SRC) \
|
|
-lm $(LDFLAGS) $(LDFLAGS_BLAS) $(LDFLAGS_METAL) $(LDFLAGS_CUDA)
|
|
|
|
tests/test_die_layer_split: tests/test_die_layer_split.c src/accel/die_layer_split.c src/accel/die_layer_split.h
|
|
$(CC) $(CFLAGS) -o $@ tests/test_die_layer_split.c src/accel/die_layer_split.c -lm
|
|
|
|
tests/test_die_scratch_ctx: tests/test_die_scratch_ctx.c $(PN_SRC) $(FOUNDRY_SRC) $(ALL_HDR)
|
|
$(CC) $(CFLAGS) -o $@ tests/test_die_scratch_ctx.c $(PN_SRC) $(FOUNDRY_SRC) \
|
|
-lm $(LDFLAGS) $(LDFLAGS_BLAS) $(LDFLAGS_METAL) $(LDFLAGS_CUDA)
|
|
|
|
tests/test_arena: tests/test_arena.c $(PN_SRC) $(FOUNDRY_SRC) $(ALL_HDR)
|
|
$(CC) $(CFLAGS) -o $@ tests/test_arena.c $(PN_SRC) $(FOUNDRY_SRC) \
|
|
-lm $(LDFLAGS) $(LDFLAGS_BLAS) $(LDFLAGS_METAL) $(LDFLAGS_CUDA)
|
|
|
|
tests/test_qmv: tests/test_qmv.c $(PN_SRC) $(FOUNDRY_SRC) $(ALL_HDR)
|
|
$(CC) $(CFLAGS) -o $@ tests/test_qmv.c $(PN_SRC) $(FOUNDRY_SRC) \
|
|
-lm $(LDFLAGS) $(LDFLAGS_BLAS) $(LDFLAGS_METAL) $(LDFLAGS_CUDA)
|
|
|
|
tests/test_simd: tests/test_simd.c $(PN_SRC) $(FOUNDRY_SRC) $(ALL_HDR)
|
|
$(CC) $(CFLAGS) -o $@ tests/test_simd.c $(PN_SRC) $(FOUNDRY_SRC) \
|
|
-lm $(LDFLAGS) $(LDFLAGS_BLAS) $(LDFLAGS_METAL) $(LDFLAGS_CUDA)
|
|
|
|
# Clean-room property tests for the CPU vector kernels (spec-derived, flag-independent).
|
|
tests/test_simd_props: tests/test_simd_props.c src/accel/simd.c src/accel/simd.h \
|
|
src/formats/gguf_dequant.c src/formats/gguf.c src/formats/gguf_dequant.h src/formats/gguf.h
|
|
$(CC) $(CFLAGS) -o $@ tests/test_simd_props.c src/accel/simd.c \
|
|
src/formats/gguf_dequant.c src/formats/gguf.c -lm
|
|
|
|
tests/test_chat: tests/test_chat.c $(PN_SRC) $(FOUNDRY_SRC) $(ALL_HDR)
|
|
$(CC) $(CFLAGS) -o $@ tests/test_chat.c $(PN_SRC) $(FOUNDRY_SRC) \
|
|
-lm $(LDFLAGS) $(LDFLAGS_BLAS) $(LDFLAGS_METAL) $(LDFLAGS_CUDA)
|
|
|
|
# FRAME CAPTURE: a forced-close turn whose compelled XML frame swallowed the
|
|
# call the model was still writing. Synthetic fixtures in the observed failure
|
|
# shapes (tests/frame_capture_fixtures.h). Same deps as the parser
|
|
# suite below — pure C, no engine/model/CUDA.
|
|
tests/test_frame_capture: tests/test_frame_capture.c tests/frame_capture_fixtures.h src/serve/tool_calling.c src/serve/json_value_grammar.c src/serve/json_reader.c src/serve/json_writer.c $(ALL_HDR)
|
|
$(CC) $(CFLAGS) -o $@ tests/test_frame_capture.c src/serve/tool_calling.c src/serve/json_value_grammar.c src/serve/json_reader.c src/serve/json_writer.c \
|
|
-lm $(LDFLAGS)
|
|
|
|
# tc_parse_tool_calls (+ render) is pure C string parsing over the JSON DOM;
|
|
# links only the three serve string modules, no engine/model/CUDA deps.
|
|
tests/test_tool_calling: tests/test_tool_calling.c tests/abandoned_call_fixture.h src/serve/tool_calling.c src/serve/json_value_grammar.c src/serve/json_reader.c src/serve/json_writer.c $(ALL_HDR)
|
|
$(CC) $(CFLAGS) -o $@ tests/test_tool_calling.c src/serve/tool_calling.c src/serve/json_value_grammar.c src/serve/json_reader.c src/serve/json_writer.c \
|
|
-lm $(LDFLAGS)
|
|
|
|
# Structurally-wrong tool-call shapes (leaked dialect tail / reasoning leak /
|
|
# missing + unknown name) and the truncated-JSON argument repair — the two
|
|
# serve-side items from the Qwen harness audit. Same deps as the parser suite
|
|
# above: pure C, no engine/model/CUDA.
|
|
tests/test_tool_call_defects: tests/test_tool_call_defects.c src/serve/tool_calling.c src/serve/json_value_grammar.c src/serve/json_reader.c src/serve/json_writer.c $(ALL_HDR)
|
|
$(CC) $(CFLAGS) -o $@ tests/test_tool_call_defects.c src/serve/tool_calling.c src/serve/json_value_grammar.c src/serve/json_reader.c src/serve/json_writer.c \
|
|
-lm $(LDFLAGS)
|
|
|
|
# Truncated tool calls: the grammar and the parser must agree about where a value
|
|
# ended, and a call the grammar never closed must not be handed back as a call.
|
|
# The only test that links BOTH halves — the defect lives in the gap between
|
|
# them. Still pure C: no engine/model/CUDA.
|
|
tests/test_tool_call_truncation: tests/test_tool_call_truncation.c src/serve/tool_calling.c src/serve/json_value_grammar.c src/serve/tool_grammar.c src/serve/tool_param_empty_value_rule.c src/serve/json_reader.c src/serve/json_writer.c $(ALL_HDR)
|
|
$(CC) $(CFLAGS) -o $@ tests/test_tool_call_truncation.c src/serve/tool_calling.c src/serve/json_value_grammar.c src/serve/tool_grammar.c src/serve/tool_param_empty_value_rule.c src/serve/json_reader.c src/serve/json_writer.c \
|
|
-lm $(LDFLAGS)
|
|
|
|
# EMPTY IS NOT ABSENT: a parameter the model CLOSED around an empty value is
|
|
# emitted as "" rather than dropped, so the client can tell "the model meant
|
|
# empty" (edit's new_string:"" is a deletion) from "the argument never arrived"
|
|
# (a truncated call, which the client charges against a task-ending budget).
|
|
# Pure C string parsing over the JSON DOM — no engine/model/CUDA.
|
|
tests/test_empty_argument: tests/test_empty_argument.c src/serve/tool_calling.c src/serve/json_value_grammar.c src/serve/json_reader.c src/serve/json_writer.c $(ALL_HDR)
|
|
$(CC) $(CFLAGS) -o $@ tests/test_empty_argument.c src/serve/tool_calling.c src/serve/json_value_grammar.c src/serve/json_reader.c src/serve/json_writer.c \
|
|
-lm $(LDFLAGS)
|
|
|
|
# Incremental JSON-value well-formedness walk — the shared core that makes a
|
|
# container-typed tool argument unfailable (grammar side) and its raw splice
|
|
# safe (parser side). Pure C, libc-only: no engine/model/CUDA, fully local.
|
|
tests/test_json_value_grammar: tests/test_json_value_grammar.c src/serve/json_value_grammar.c $(ALL_HDR)
|
|
$(CC) $(CFLAGS) -o $@ tests/test_json_value_grammar.c src/serve/json_value_grammar.c \
|
|
-lm $(LDFLAGS)
|
|
|
|
# Grammar-constrained tool decoding FSM (Phase 5). Pure C string/DOM parsing
|
|
# over the tools schema; links only the grammar module + the JSON reader — no
|
|
# engine/model/CUDA deps, fully local.
|
|
tests/test_tool_grammar: tests/test_tool_grammar.c src/serve/tool_grammar.c src/serve/tool_calling.c src/serve/json_value_grammar.c src/serve/tool_param_empty_value_rule.c src/serve/json_reader.c src/serve/json_writer.c $(ALL_HDR)
|
|
$(CC) $(CFLAGS) -o $@ tests/test_tool_grammar.c src/serve/tool_grammar.c src/serve/tool_calling.c src/serve/json_value_grammar.c src/serve/tool_param_empty_value_rule.c src/serve/json_reader.c src/serve/json_writer.c \
|
|
-lm $(LDFLAGS)
|
|
|
|
tests/test_tool_grammar_json: tests/test_tool_grammar_json.c src/serve/tool_grammar_json.c src/serve/tool_param_empty_value_rule.c src/serve/json_reader.c src/serve/json_writer.c $(ALL_HDR)
|
|
$(CC) $(CFLAGS) -o $@ tests/test_tool_grammar_json.c src/serve/tool_grammar_json.c src/serve/tool_param_empty_value_rule.c src/serve/json_reader.c src/serve/json_writer.c \
|
|
-lm $(LDFLAGS)
|
|
|
|
# Speculative decoding under the tool-call grammar: drafts verified through the
|
|
# grammar-aware chooser must reproduce plain constrained decoding token for
|
|
# token (self-falsifying simulation). Links the real JSON grammar and the
|
|
# parser; no engine/model/device.
|
|
tests/test_grammar_spec_chooser: tests/test_grammar_spec_chooser.c src/serve/grammar_spec_chooser.c src/core/grammar_mask_shortlist.c src/serve/tool_grammar_json.c src/serve/tool_calling.c src/serve/json_value_grammar.c src/serve/tool_param_empty_value_rule.c src/serve/json_reader.c src/serve/json_writer.c $(ALL_HDR)
|
|
$(CC) $(CFLAGS) -o $@ tests/test_grammar_spec_chooser.c src/serve/grammar_spec_chooser.c src/core/grammar_mask_shortlist.c src/serve/tool_grammar_json.c src/serve/tool_calling.c src/serve/json_value_grammar.c src/serve/tool_param_empty_value_rule.c src/serve/json_reader.c src/serve/json_writer.c \
|
|
-lm $(LDFLAGS)
|
|
|
|
# The grammar mask decided from a shortlist of the highest logits must leave the
|
|
# same greedy pick / top-K set as the full-vocabulary mask. libc-only.
|
|
tests/test_grammar_mask_shortlist: tests/test_grammar_mask_shortlist.c src/core/grammar_mask_shortlist.c src/core/sampling_modifiers.c $(ALL_HDR)
|
|
$(CC) $(CFLAGS) -o $@ tests/test_grammar_mask_shortlist.c src/core/grammar_mask_shortlist.c src/core/sampling_modifiers.c \
|
|
-lm $(LDFLAGS)
|
|
|
|
# Full-logits ARMING WINDOW (PN_GRAMMAR_ARM_WINDOW): is the row a masked step
|
|
# reads armed one token EARLY enough? Models the decode loop's ordering over
|
|
# the three real grammar walks; self-falsifying — exits 2 VACUOUS if the
|
|
# deliberately-stale policy fails to break. No engine/model/CUDA deps.
|
|
tests/test_grammar_arm_window: tests/test_grammar_arm_window.c src/serve/tool_grammar.c src/serve/json_value_grammar.c src/serve/tool_grammar_json.c src/serve/response_format_grammar.c src/serve/tool_param_empty_value_rule.c src/serve/json_reader.c src/serve/json_writer.c $(ALL_HDR)
|
|
$(CC) $(CFLAGS) -o $@ tests/test_grammar_arm_window.c src/serve/tool_grammar.c src/serve/json_value_grammar.c src/serve/tool_grammar_json.c src/serve/response_format_grammar.c src/serve/tool_param_empty_value_rule.c src/serve/json_reader.c src/serve/json_writer.c \
|
|
-lm $(LDFLAGS)
|
|
|
|
# response_format (json_object) constrained-decoding FSM. Pure C char walk with
|
|
# no schema/DOM input at all — links only the grammar module. No engine/model/
|
|
# CUDA deps, fully local.
|
|
tests/test_response_format_grammar: tests/test_response_format_grammar.c src/serve/response_format_grammar.c $(ALL_HDR)
|
|
$(CC) $(CFLAGS) -o $@ tests/test_response_format_grammar.c src/serve/response_format_grammar.c \
|
|
-lm $(LDFLAGS)
|
|
|
|
# OpenAI logits-row sampling controls (logit_bias / presence+frequency penalties /
|
|
# seeded RNG / logprobs). Pure float-array math — links only the modifier module.
|
|
tests/test_sampling_modifiers: tests/test_sampling_modifiers.c src/core/sampling_modifiers.c $(ALL_HDR)
|
|
$(CC) $(CFLAGS) -o $@ tests/test_sampling_modifiers.c src/core/sampling_modifiers.c \
|
|
-lm $(LDFLAGS)
|
|
|
|
# parse_chat_request tool_choice handling + forced_name lifetime (Phase 5 BUG 2).
|
|
# #includes openai_chat.c directly to reach its static parse fn; the request-parse
|
|
# path only touches the JSON reader + tool_calling renderer (linked), and tiny
|
|
# link stubs in the test satisfy the engine-side handlers it never calls. No
|
|
# engine/model/CUDA deps, fully local. serve_shutdown.c is linked because the
|
|
# parse's DEFAULT abort predicate is the shutdown check — every turn has to be
|
|
# stoppable by a SIGTERM — and that module is libc + pthread only.
|
|
# src/accel/backend_identity.c joins the link line because oai_handle_models now
|
|
# names the compiled backend on /v1/models. The module is a handful of string
|
|
# literals with no dependencies of its own, so it costs this harness nothing.
|
|
tests/test_chat_request: tests/test_chat_request.c src/serve/tool_calling.c src/serve/json_value_grammar.c src/serve/json_reader.c src/serve/json_writer.c src/serve/serve_shutdown.c src/serve/openai_chat.c src/serve/tool_call_stream.c src/serve/json_canonical_stream.c src/serve/serve_emitter.c src/accel/backend_identity.c $(ALL_HDR)
|
|
$(CC) $(CFLAGS) -o $@ tests/test_chat_request.c src/serve/tool_calling.c src/serve/json_value_grammar.c src/serve/json_reader.c src/serve/json_writer.c src/serve/request_profile.c src/serve/serve_shutdown.c src/serve/tool_call_stream.c src/serve/json_canonical_stream.c src/serve/serve_emitter.c src/accel/backend_identity.c \
|
|
-lm $(LDFLAGS)
|
|
|
|
# Stream tool-call detection (serve_generation.c emitter, Phase 2). The emitter
|
|
# lives in serve_emitter.c and depends only on libc, so this links just that one
|
|
# module — no engine/model/CUDA deps.
|
|
# Where the multi-turn prefill checkpoint sits (a band boundary, at or below the history the
|
|
# next turn resends). Pure arithmetic, host-only — no card.
|
|
tests/test_qwen35_ckpt_band: tests/test_qwen35_ckpt_band.c src/models/qwen35moe_checkpoint_band.c $(ALL_HDR)
|
|
$(CC) $(CFLAGS) -o $@ tests/test_qwen35_ckpt_band.c src/models/qwen35moe_checkpoint_band.c \
|
|
-lm $(LDFLAGS)
|
|
|
|
tests/test_serve_emitter: tests/test_serve_emitter.c src/serve/serve_emitter.c $(ALL_HDR)
|
|
$(CC) $(CFLAGS) -o $@ tests/test_serve_emitter.c src/serve/serve_emitter.c \
|
|
-lm $(LDFLAGS)
|
|
|
|
# Incremental tool-call streaming (tool_call_stream.c + json_canonical_stream.c):
|
|
# the streamed argument fragments must concatenate to exactly the arguments the
|
|
# end-of-turn parse returns. libc-only — the emitter, the streamer and the
|
|
# parser, no engine.
|
|
tests/test_tool_call_stream: tests/test_tool_call_stream.c src/serve/tool_call_stream.c src/serve/json_canonical_stream.c src/serve/serve_emitter.c src/serve/tool_calling.c src/serve/json_value_grammar.c src/serve/json_reader.c src/serve/json_writer.c $(ALL_HDR)
|
|
$(CC) $(CFLAGS) -o $@ tests/test_tool_call_stream.c src/serve/tool_call_stream.c src/serve/json_canonical_stream.c src/serve/serve_emitter.c src/serve/tool_calling.c src/serve/json_value_grammar.c src/serve/json_reader.c src/serve/json_writer.c \
|
|
-lm $(LDFLAGS)
|
|
|
|
# Decode-time repetition-cycle detector (the saber-orch Q3_K_M collapse: one
|
|
# paragraph re-emitted 31 times, reported as a normal finish). The detector
|
|
# depends only on libc, so this links just that one module — no engine/model/
|
|
# CUDA. The NEGATIVE tests (legitimate code, JSON, tables, log excerpts that
|
|
# must NOT trip it) are the ones that matter; run the red proof by relaxing
|
|
# RLD_DEFAULT_MIN_PERIOD to 1 and watching them go red.
|
|
tests/test_serve_spec_lookup: tests/test_serve_spec_lookup.c src/serve/serve_spec_lookup.c src/core/ngram_draft.c $(ALL_HDR)
|
|
$(CC) $(CFLAGS) -o $@ tests/test_serve_spec_lookup.c src/serve/serve_spec_lookup.c \
|
|
src/core/ngram_draft.c -lm $(LDFLAGS)
|
|
|
|
tests/test_repetition_loop_detector: tests/test_repetition_loop_detector.c src/serve/repetition_loop_detector.c $(ALL_HDR)
|
|
$(CC) $(CFLAGS) -o $@ tests/test_repetition_loop_detector.c \
|
|
src/serve/repetition_loop_detector.c -lm $(LDFLAGS)
|
|
|
|
# Dispatch-layer registry unit test (Phase G1). Links only the registry + the
|
|
# two JSON modules — no engine/model/CUDA. Host-side, deterministic (injected
|
|
# clock for the TTL test).
|
|
tests/test_registry: tests/test_registry.c src/serve/registry.c src/serve/json_reader.c src/serve/json_writer.c $(ALL_HDR)
|
|
$(CC) $(CFLAGS) -o $@ tests/test_registry.c src/serve/registry.c \
|
|
src/serve/json_reader.c src/serve/json_writer.c \
|
|
-lm $(LDFLAGS)
|
|
|
|
# System-prefix cache unit test (SYS1). Links the prefix cache + the state
|
|
# snapshot module only; the test stubs pn_state_new/reset/free over hand-built
|
|
# qwen35moe dual states — no engine/model/CUDA, builds and runs on the Mac.
|
|
tests/test_base64: tests/test_base64.c src/serve/base64.c $(ALL_HDR)
|
|
$(CC) $(CFLAGS) -o $@ tests/test_base64.c src/serve/base64.c \
|
|
-lm $(LDFLAGS)
|
|
|
|
# Retry policy + three-state residency gauge for the CUDA-graph capture tracker
|
|
# (tasks #41/#42). Pure host state machine, no GPU, runs anywhere. Run the red
|
|
# arm too — `tests/test_graph_capture_retry --latch` replays the OLD one-shot
|
|
# latch and must fail its expectations, which is what proves the gate is not
|
|
# vacuous.
|
|
tests/test_graph_capture_retry: tests/test_graph_capture_retry.c \
|
|
src/models/gpu_graph_capture_tracker.c $(ALL_HDR)
|
|
$(CC) $(CFLAGS) -o $@ tests/test_graph_capture_retry.c \
|
|
src/models/gpu_graph_capture_tracker.c -lm $(LDFLAGS)
|
|
|
|
# Deferred-shutdown mechanism for `pantheon serve` (SIGTERM/SIGINT retiring the
|
|
# card residencies). Links serve_shutdown.c alone — no engine, no serve, no
|
|
# card — and raises REAL signals through a real sigaction to prove the handler
|
|
# path. The retirement it gates is device-side and is proved on silicon.
|
|
tests/test_serve_shutdown: tests/test_serve_shutdown.c \
|
|
src/serve/serve_shutdown.c $(ALL_HDR)
|
|
$(CC) $(CFLAGS) -o $@ tests/test_serve_shutdown.c \
|
|
src/serve/serve_shutdown.c -lm $(LDFLAGS)
|
|
|
|
# Bounded retry after a failed per-slot KV-ring allocation + the ondie/host
|
|
# attention residency gauge. Pure host state machine, no GPU, runs anywhere.
|
|
# Run the red arm too — `tests/test_attn_ring_retry --latch` replays the OLD
|
|
# sticky latch (one attempt per geometry, then never again) and must fail its
|
|
# expectations, which is what proves the gate is not vacuous.
|
|
tests/test_attn_ring_retry: tests/test_attn_ring_retry.c \
|
|
src/models/gpu_attn_path_tracker.c $(ALL_HDR)
|
|
$(CC) $(CFLAGS) -o $@ tests/test_attn_ring_retry.c \
|
|
src/models/gpu_attn_path_tracker.c -lm $(LDFLAGS)
|
|
|
|
# Llama-family session snapshot (the primitive session export/restore rides on
|
|
# for every arch whose per-session state is a plain causal KV cache — the family
|
|
# the Tenstorrent backend serves). Pure host memory, no engine, no accelerator:
|
|
# the test hand-builds the tm_tensors so it links only the snapshot unit and the
|
|
# arch dispatcher. Byte comparison throughout; PCC would be blind to every
|
|
# failure this format can have.
|
|
tests/test_llama_state_snapshot: tests/test_llama_state_snapshot.c src/models/llama_state_snapshot.c src/models/qwen35moe_state_snapshot.c src/core/session_snapshot.c $(ALL_HDR)
|
|
$(CC) $(CFLAGS) -o $@ tests/test_llama_state_snapshot.c \
|
|
src/models/llama_state_snapshot.c src/models/qwen35moe_state_snapshot.c \
|
|
src/core/session_snapshot.c \
|
|
-lm $(LDFLAGS)
|
|
|
|
tests/test_prefix_cache_sys: tests/test_prefix_cache_sys.c tests/tt_prefix_cache_link_stubs.c src/core/prefix_cache.c src/core/session_snapshot.c src/models/qwen35moe_state_snapshot.c src/models/llama_state_snapshot.c src/serve/batch_sched.c src/serve/request_profile.c $(ALL_HDR)
|
|
$(CC) $(CFLAGS) -o $@ tests/test_prefix_cache_sys.c tests/tt_prefix_cache_link_stubs.c \
|
|
src/core/prefix_cache.c src/core/session_snapshot.c \
|
|
src/models/qwen35moe_state_snapshot.c src/models/llama_state_snapshot.c \
|
|
src/serve/batch_sched.c src/serve/request_profile.c \
|
|
-lm $(LDFLAGS)
|
|
|
|
# Liveness-based session release (§C.4). Links the watch manager + prefix cache
|
|
# + snapshot machinery + http_server (hs_client_alive); mr_acquire/mr_release +
|
|
# pn_state_* are test stubs. Host-side, deterministic (manual manager + sweep
|
|
# hooks), no engine/model/CUDA.
|
|
tests/test_session_watch: tests/test_session_watch.c tests/tt_prefix_cache_link_stubs.c src/serve/session_watch.c src/core/prefix_cache.c src/core/session_snapshot.c src/models/qwen35moe_state_snapshot.c src/models/llama_state_snapshot.c src/serve/http_server.c src/serve/model_session.c $(ALL_HDR)
|
|
$(CC) $(CFLAGS) -o $@ tests/test_session_watch.c tests/tt_prefix_cache_link_stubs.c \
|
|
src/serve/session_watch.c src/core/prefix_cache.c src/core/session_snapshot.c \
|
|
src/models/qwen35moe_state_snapshot.c src/models/llama_state_snapshot.c \
|
|
src/serve/http_server.c \
|
|
src/serve/model_session.c src/serve/batch_sched.c src/serve/request_profile.c \
|
|
-lm $(LDFLAGS)
|
|
|
|
# Session-affinity unit test (PC0.2). Links the affinity map + registry + the two
|
|
# JSON modules — no engine/model/CUDA. Host-side, deterministic.
|
|
tests/test_session_affinity: tests/test_session_affinity.c src/serve/session_affinity.c src/serve/registry.c src/serve/json_reader.c src/serve/json_writer.c $(ALL_HDR)
|
|
$(CC) $(CFLAGS) -o $@ tests/test_session_affinity.c \
|
|
src/serve/session_affinity.c src/serve/registry.c \
|
|
src/serve/json_reader.c src/serve/json_writer.c \
|
|
-lm $(LDFLAGS)
|
|
|
|
# Dispatch-layer end-to-end test (Phase G1+G2): boots the real `pantheon router`
|
|
# + Python stub upstreams and asserts dedup / least-busy / failover / SSE
|
|
# pass-through / TTL eviction. Mac-only (host networking; no GPU/CUDA).
|
|
# Requires the built `pantheon` binary + python3 + curl. Runs ~20s (TTL wait).
|
|
.PHONY: test-dispatch-e2e
|
|
test-dispatch-e2e: pantheon
|
|
bash tests/dispatch/e2e.sh
|
|
|
|
# Shared by every parity harness: the paired PPL/KL/gap scorer, the accelerator-arm
|
|
# selection that refuses a vacuous CPU-vs-CPU run, and the reproducible Gaussian
|
|
# perturbations. One copy so a gate and a debug sweep can never disagree about what a
|
|
# perplexity ratio means.
|
|
PARITY_LIB_SRC = tests/parity_score.c tests/parity_accel_arm.c tests/parity_noise.c \
|
|
tests/parity_gate_criteria.c tests/parity_logit_dump.c
|
|
PARITY_LIB_HDR = tests/parity_score.h tests/parity_accel_arm.h tests/parity_noise.h \
|
|
tests/parity_gate_criteria.h tests/parity_logit_dump.h
|
|
|
|
# The chat-templated, real-vocab, per-position accelerator parity GATE. Pass/fail on the
|
|
# perplexity a chat-framed prompt actually costs, not on one next-token argmax.
|
|
tests/test_chat_parity_gate: tests/test_chat_parity_gate.c tests/chat_corpus.c $(PARITY_LIB_SRC) $(PN_SRC) $(FOUNDRY_SRC) $(ALL_HDR) $(PARITY_LIB_HDR) tests/chat_corpus.h
|
|
$(CC) $(CFLAGS) -o $@ tests/test_chat_parity_gate.c tests/chat_corpus.c $(PARITY_LIB_SRC) $(PN_SRC) $(FOUNDRY_SRC) \
|
|
-lm $(LDFLAGS) $(LDFLAGS_BLAS) $(LDFLAGS_METAL) $(LDFLAGS_CUDA)
|
|
|
|
# THE SAME GATE AS TWO SEPARATE PASSES, paired offline. The interleaved gate above puts a
|
|
# ~26 s CPU-oracle forward between two consecutive card forwards, which retires the resident
|
|
# triads: 802 / 2406 / 442 descriptor refusals against 0 on single-arm runs. This one dumps
|
|
# each arm's per-position logit rows on its own and scores them afterwards, which also makes
|
|
# the oracle pass CACHEABLE across arms (~3 h once, not per arm). The pairing step loads no
|
|
# model and opens no card, so it builds and runs with no accelerator flag at all.
|
|
tests/test_two_pass_parity_gate: tests/test_two_pass_parity_gate.c tests/chat_corpus.c $(PARITY_LIB_SRC) $(PN_SRC) $(FOUNDRY_SRC) $(ALL_HDR) $(PARITY_LIB_HDR) tests/chat_corpus.h
|
|
$(CC) $(CFLAGS) -o $@ tests/test_two_pass_parity_gate.c tests/chat_corpus.c $(PARITY_LIB_SRC) $(PN_SRC) $(FOUNDRY_SRC) \
|
|
-lm $(LDFLAGS) $(LDFLAGS_BLAS) $(LDFLAGS_METAL) $(LDFLAGS_CUDA)
|
|
|
|
# L11b: the gdnc reader's on-card decay tile + gate runs vs the hardware multiply (FTZ+DAZ) and
|
|
# the host builders, bit for bit. Run it on an x86 host (where the builders run).
|
|
tests/test_gdnc_compact: tests/test_gdnc_compact.c $(FOUNDRY)/tt/kernels/ftgc_compact.h $(PN_SRC) $(FOUNDRY_SRC) $(ALL_HDR)
|
|
$(CC) $(CFLAGS) -o $@ tests/test_gdnc_compact.c $(PN_SRC) $(FOUNDRY_SRC) \
|
|
-lm $(LDFLAGS) $(LDFLAGS_BLAS) $(LDFLAGS_METAL) $(LDFLAGS_CUDA)
|
|
|
|
# PHASE B's CHEAP GATE: the prompt-lookup drafting ACCEPTANCE rate, two passes. --generate
|
|
# decodes a corpus greedily on the shipped arm and records the token ids (needs a card);
|
|
# --score replays those ids as speculative rounds (no model, no card, seconds); --selftest is
|
|
# a known-answer arm at both ends of the scale. Greedy verification accepts exactly the
|
|
# drafts that match the plain stream, so NO verify kernel is needed to measure this.
|
|
tests/bench_ngram_accept: tests/bench_ngram_accept.c tests/ngram_accept_stream.c tests/chat_corpus.c $(PARITY_LIB_SRC) $(PN_SRC) $(FOUNDRY_SRC) $(ALL_HDR) $(PARITY_LIB_HDR) tests/chat_corpus.h tests/ngram_accept_stream.h
|
|
$(CC) $(CFLAGS) -o $@ tests/bench_ngram_accept.c tests/ngram_accept_stream.c tests/chat_corpus.c $(PARITY_LIB_SRC) $(PN_SRC) $(FOUNDRY_SRC) \
|
|
-lm $(LDFLAGS) $(LDFLAGS_BLAS) $(LDFLAGS_METAL) $(LDFLAGS_CUDA)
|
|
|
|
# The GDN host STAGER's address arithmetic, against the layout accessors the two dataflow
|
|
# kernels compute their own offsets with. Needs USE_TT=1 for the foundry tile code, but NOT a
|
|
# card: it opens no device, so it runs on the Mac where the stager is written.
|
|
tests/test_gdn_layout: tests/test_gdn_layout.c $(PN_SRC) $(FOUNDRY_SRC) $(ALL_HDR)
|
|
$(CC) $(CFLAGS) -o $@ tests/test_gdn_layout.c $(PN_SRC) $(FOUNDRY_SRC) \
|
|
-lm $(LDFLAGS) $(LDFLAGS_BLAS) $(LDFLAGS_METAL) $(LDFLAGS_CUDA)
|
|
|
|
# BYTE-EXACTNESS of the batched TT prefill against the one-at-a-time path. Byte comparison
|
|
# and not PCC: what makes a 32-row pass safe is row INDEPENDENCE, and a correlation cannot
|
|
# see independence. Needs USE_TT=1 and a card; without one it refuses rather than passing.
|
|
# THE BOOT GUARD AGAINST A REAL LEFTOVER. Two invocations, one card, NO MODEL —
|
|
# --leak strands a spinning compute thread and exits without closing the device,
|
|
# --read reports what the card says about that core writing nothing, and --arm is
|
|
# the process that used to wedge it. Needs USE_TT=1 and a card. It is a CARD ARM
|
|
# and belongs behind the flock runner (tt/tests/run_gdn_writer_capacity_arms.sh's
|
|
# pattern), but it is not a model load and must never become one.
|
|
tests/test_tt_boot_guard_leftover: tests/test_tt_boot_guard_leftover.c $(PN_SRC) $(FOUNDRY_SRC) $(ALL_HDR)
|
|
$(CC) $(CFLAGS) -o $@ tests/test_tt_boot_guard_leftover.c $(PN_SRC) $(FOUNDRY_SRC) \
|
|
-lm $(LDFLAGS) $(LDFLAGS_BLAS) $(LDFLAGS_METAL) $(LDFLAGS_CUDA)
|
|
|
|
tests/test_tt_prefill_parity: tests/test_tt_prefill_parity.c $(PN_SRC) $(FOUNDRY_SRC) $(ALL_HDR)
|
|
$(CC) $(CFLAGS) -o $@ tests/test_tt_prefill_parity.c $(PN_SRC) $(FOUNDRY_SRC) \
|
|
-lm $(LDFLAGS) $(LDFLAGS_BLAS) $(LDFLAGS_METAL) $(LDFLAGS_CUDA)
|
|
|
|
# THE THREE MEASUREMENTS PHASE 4 IS GATED ON, on Ornith's own strips: what a whole-tile
|
|
# transfer costs against the row-0 one (there is no on-card row gather, so a batched pass
|
|
# reaches row r through the link or not at all), whether the 32-row tile quantum survives 32
|
|
# LIVE rows rather than 31 zeros, and what the two mixers cost alone — they are the terms a
|
|
# batched pass cannot batch. Needs USE_TT=1 and a card.
|
|
tests/bench_tt_prefill_quantum: tests/bench_tt_prefill_quantum.c $(PN_SRC) $(FOUNDRY_SRC) $(ALL_HDR)
|
|
$(CC) $(CFLAGS) -o $@ tests/bench_tt_prefill_quantum.c $(PN_SRC) $(FOUNDRY_SRC) \
|
|
-lm $(LDFLAGS) $(LDFLAGS_BLAS) $(LDFLAGS_METAL) $(LDFLAGS_CUDA)
|
|
|
|
# Speculative greedy decode gate + bench (n-gram drafts + batched verify):
|
|
# the speculative token stream must be identical to plain greedy. Build with
|
|
# USE_CUDA=1 on a CUDA host; run under QWEN35_FUSE=0x37 for the strict gate.
|
|
tests/test_spec_qwen35: tests/test_spec_qwen35.c $(PN_SRC) $(FOUNDRY_SRC) $(ALL_HDR)
|
|
$(CC) $(CFLAGS) -o $@ tests/test_spec_qwen35.c $(PN_SRC) $(FOUNDRY_SRC) \
|
|
-lm $(LDFLAGS) $(LDFLAGS_BLAS) $(LDFLAGS_METAL) $(LDFLAGS_CUDA)
|
|
|
|
# Multi-user decode gate + bench (pn_qwen35moe_decode_slots): K users, one
|
|
# token each per forward pass — each user's batched stream must be identical
|
|
# to that user decoding alone. Build with USE_CUDA=1 on a CUDA host; run under
|
|
# QWEN35_FUSE=0x37 for the strict gate.
|
|
tests/test_users_qwen35: tests/test_users_qwen35.c $(PN_SRC) $(FOUNDRY_SRC) $(ALL_HDR)
|
|
$(CC) $(CFLAGS) -o $@ tests/test_users_qwen35.c $(PN_SRC) $(FOUNDRY_SRC) \
|
|
-lm $(LDFLAGS) $(LDFLAGS_BLAS) $(LDFLAGS_METAL) $(LDFLAGS_CUDA)
|
|
|
|
# What temperature costs the HOST per token: times the real sampler
|
|
# (pn_sample_next_token) at temp 0 vs temp 0.7 over the sparse device-top-k
|
|
# logits buffer the serve actually hands it. The delta bounds every "move the
|
|
# sampling off the host" lever. CPU-only — no GPU, no model, runs anywhere.
|
|
tests/bench_sampler_temp_delta: tests/bench_sampler_temp_delta.c $(PN_SRC) $(FOUNDRY_SRC) $(ALL_HDR)
|
|
$(CC) $(CFLAGS) -o $@ tests/bench_sampler_temp_delta.c $(PN_SRC) $(FOUNDRY_SRC) \
|
|
-lm $(LDFLAGS) $(LDFLAGS_BLAS) $(LDFLAGS_METAL) $(LDFLAGS_CUDA)
|
|
|
|
# Ship gate for the sparse-survivor sampler: the fast path must return the
|
|
# SAME token as the full-vocab path for the same row, params and RNG state.
|
|
# `--selftest` proves the gate can go red (and that the fast path actually
|
|
# ran) — a green run from a gate that cannot fail means nothing.
|
|
tests/test_sparse_sampler_identity: tests/test_sparse_sampler_identity.c $(PN_SRC) $(FOUNDRY_SRC) $(ALL_HDR)
|
|
$(CC) $(CFLAGS) -o $@ tests/test_sparse_sampler_identity.c $(PN_SRC) $(FOUNDRY_SRC) \
|
|
-lm $(LDFLAGS) $(LDFLAGS_BLAS) $(LDFLAGS_METAL) $(LDFLAGS_CUDA)
|
|
|
|
# The grammar mask on a backend's top-N row (shortlist / dense chunks / whole-row
|
|
# refill) must draw the token the full mask draws on the dense row.
|
|
# `--selftest`: a subject that skips the mask must be caught.
|
|
tests/test_grammar_topn_sampler: tests/test_grammar_topn_sampler.c $(PN_SRC) $(FOUNDRY_SRC) $(ALL_HDR)
|
|
$(CC) $(CFLAGS) -o $@ tests/test_grammar_topn_sampler.c $(PN_SRC) $(FOUNDRY_SRC) \
|
|
-lm $(LDFLAGS) $(LDFLAGS_BLAS) $(LDFLAGS_METAL) $(LDFLAGS_CUDA)
|
|
|
|
# Gate for the top-N exactness check the sampler uses before sampling a top-N row
|
|
# (`--selftest`: a check blind to the penalties must be caught).
|
|
tests/test_topn_row_exact: tests/test_topn_row_exact.c $(PN_SRC) $(FOUNDRY_SRC) $(ALL_HDR)
|
|
$(CC) $(CFLAGS) -o $@ tests/test_topn_row_exact.c $(PN_SRC) $(FOUNDRY_SRC) \
|
|
-lm $(LDFLAGS) $(LDFLAGS_BLAS) $(LDFLAGS_METAL) $(LDFLAGS_CUDA)
|
|
|
|
# Context-DEPTH decode bench: per-user steady-state DECODE tok/s as the seeded
|
|
# context deepens (isolates the 10 O(context) attention layers). Cold-prefills a
|
|
# large seed per user (untimed), then times only the batched decode. Build with
|
|
# USE_CUDA=1 on a CUDA host; run under QWEN35_FUSE=0x37.
|
|
tests/bench_depth_qwen35: tests/bench_depth_qwen35.c $(PN_SRC) $(FOUNDRY_SRC) $(ALL_HDR)
|
|
$(CC) $(CFLAGS) -o $@ tests/bench_depth_qwen35.c $(PN_SRC) $(FOUNDRY_SRC) \
|
|
-lm $(LDFLAGS) $(LDFLAGS_BLAS) $(LDFLAGS_METAL) $(LDFLAGS_CUDA)
|
|
|
|
# Session-lifetime regression gate: bind a decode slot immediately after a
|
|
# session free. Asserts no decode slot still holds a back-pointer into the
|
|
# freed state (address compare only), then performs the real bind-after-free —
|
|
# the sequence the serve runs on every session release and idle reap. Build
|
|
# with DEBUG=1 USE_CUDA=1 on a CUDA host so the ASAN arm runs too.
|
|
tests/test_slot_free_bind_qwen35: tests/test_slot_free_bind_qwen35.c $(PN_SRC) $(FOUNDRY_SRC) $(ALL_HDR)
|
|
$(CC) $(CFLAGS) -o $@ tests/test_slot_free_bind_qwen35.c $(PN_SRC) $(FOUNDRY_SRC) \
|
|
-lm $(LDFLAGS) $(LDFLAGS_BLAS) $(LDFLAGS_METAL) $(LDFLAGS_CUDA)
|
|
|
|
# Phase 9.1 speculative-decoding GATE bench: cost of a D-row batched verify vs
|
|
# D sequential single-token forwards, plus the batched-slots row-cost curve.
|
|
# Pure measurement, changes no engine behaviour. Build with USE_CUDA=1 on a
|
|
# CUDA host; run under QWEN35_FUSE=0x37 to match the serve's kernel selection.
|
|
tests/bench_spec_verify_gate: tests/bench_spec_verify_gate.c $(PN_SRC) $(FOUNDRY_SRC) $(ALL_HDR)
|
|
$(CC) $(CFLAGS) -o $@ tests/bench_spec_verify_gate.c $(PN_SRC) $(FOUNDRY_SRC) \
|
|
-lm $(LDFLAGS) $(LDFLAGS_BLAS) $(LDFLAGS_METAL) $(LDFLAGS_CUDA)
|
|
|
|
# Phase 9.2 ACCEPTANCE bench: what fraction of prompt-lookup drafts the verify
|
|
# actually accepts, on real code-edit prompts, counted separately for the
|
|
# reasoning and answer segments — the measurement 9.1's break-even has to be
|
|
# tested against. Re-runs the exactness gate too (spec stream == plain greedy).
|
|
# Build with USE_CUDA=1 on a CUDA host; run under QWEN35_FUSE=0x37.
|
|
tests/bench_spec_accept: tests/bench_spec_accept.c $(PN_SRC) $(FOUNDRY_SRC) $(ALL_HDR)
|
|
$(CC) $(CFLAGS) -o $@ tests/bench_spec_accept.c $(PN_SRC) $(FOUNDRY_SRC) \
|
|
-lm $(LDFLAGS) $(LDFLAGS_BLAS) $(LDFLAGS_METAL) $(LDFLAGS_CUDA)
|
|
|
|
# Serve-scheduler gate (L1/L2/L3 — batched+chunked prefill, in-driver
|
|
# sampling): concurrent sg_run_completion_batched users vs the single-user
|
|
# reference (greedy text must be identical), join-during-decode, slow-client
|
|
# isolation. Build with USE_CUDA=1 on a CUDA host; run under QWEN35_FUSE=0x37.
|
|
tests/test_serve_sched_qwen35: tests/test_serve_sched_qwen35.c $(PN_SRC) $(SERVE_SRC) $(FOUNDRY_SRC) $(ALL_HDR)
|
|
$(CC) $(CFLAGS) -o $@ tests/test_serve_sched_qwen35.c $(PN_SRC) $(SERVE_SRC) $(FOUNDRY_SRC) \
|
|
-lm $(LDFLAGS) $(LDFLAGS_BLAS) $(LDFLAGS_METAL) $(LDFLAGS_CUDA)
|
|
|
|
# PC-batched gate: prefix caching wired into the MULTI-TENANT batched path.
|
|
# 4 concurrent users x 3 growing turns through the batch scheduler with
|
|
# session affinity + delta-prefill; every user's per-turn reply must be
|
|
# token-identical (argmax-exact) to a non-cached single-user reference. Build
|
|
# with USE_CUDA=1 on a CUDA host; run under QWEN35_BATCH_SLOTS=1 QWEN35_FUSE=0x37.
|
|
tests/test_serve_sched_prefix_cache: tests/test_serve_sched_prefix_cache.c $(PN_SRC) $(SERVE_SRC) $(FOUNDRY_SRC) $(ALL_HDR)
|
|
$(CC) $(CFLAGS) -o $@ tests/test_serve_sched_prefix_cache.c $(PN_SRC) $(SERVE_SRC) $(FOUNDRY_SRC) \
|
|
-lm $(LDFLAGS) $(LDFLAGS_BLAS) $(LDFLAGS_METAL) $(LDFLAGS_CUDA)
|
|
|
|
# True per-user capacity bench — realistic growing-context workload with prefix
|
|
# caching ON (steady-state delta-prefill), K concurrent users through the
|
|
# batched serve path. Reports per-user + aggregate tok/s + cost/1M. Build with
|
|
# USE_CUDA=1 on a CUDA host; run under QWEN35_BATCH_SLOTS=1 QWEN35_FUSE=0x37.
|
|
tests/bench_serve_prefix_cache: tests/bench_serve_prefix_cache.c $(PN_SRC) $(SERVE_SRC) $(FOUNDRY_SRC) $(ALL_HDR)
|
|
$(CC) $(CFLAGS) -o $@ tests/bench_serve_prefix_cache.c $(PN_SRC) $(SERVE_SRC) $(FOUNDRY_SRC) \
|
|
-lm $(LDFLAGS) $(LDFLAGS_BLAS) $(LDFLAGS_METAL) $(LDFLAGS_CUDA)
|
|
|
|
# Prefix-cache gate + latency bench (pn_prefix_cache): a multi-turn agentic
|
|
# scenario run with caching ON (delta-prefill only) vs OFF (re-prefill the
|
|
# whole context each turn) must produce token-identical replies (argmax-exact),
|
|
# and the cached per-turn prefill must be far cheaper. Build with USE_CUDA=1 on
|
|
# a CUDA host; run under QWEN35_FUSE=0x37 for the strict argmax gate.
|
|
tests/test_prefix_cache_qwen35: tests/test_prefix_cache_qwen35.c $(PN_SRC) $(FOUNDRY_SRC) $(ALL_HDR)
|
|
$(CC) $(CFLAGS) -o $@ tests/test_prefix_cache_qwen35.c $(PN_SRC) $(FOUNDRY_SRC) \
|
|
-lm $(LDFLAGS) $(LDFLAGS_BLAS) $(LDFLAGS_METAL) $(LDFLAGS_CUDA)
|
|
|
|
# Quality-eval driver (perplexity + greedy generation) for A/B-ing two engine
|
|
# builds whose logits are not bit-identical; driven by evals/eval_quality.sh.
|
|
# Build with USE_CUDA=1 on a CUDA host for the GPU path. Needs a model.
|
|
tests/eval_ppl: tests/eval_ppl.c $(PN_SRC) $(FOUNDRY_SRC) $(ALL_HDR)
|
|
$(CC) $(CFLAGS) -o $@ tests/eval_ppl.c $(PN_SRC) $(FOUNDRY_SRC) \
|
|
-lm $(LDFLAGS) $(LDFLAGS_BLAS) $(LDFLAGS_METAL) $(LDFLAGS_CUDA)
|
|
|
|
tests/test_prefix_projection: tests/test_prefix_projection.c $(PN_SRC) $(FOUNDRY_SRC) \
|
|
src/serve/serve_prompt_tokens.c src/serve/tool_calling.c \
|
|
src/serve/json_value_grammar.c \
|
|
src/serve/json_reader.c src/serve/json_writer.c $(ALL_HDR)
|
|
$(CC) $(CFLAGS) -o $@ tests/test_prefix_projection.c $(PN_SRC) $(FOUNDRY_SRC) \
|
|
src/serve/serve_prompt_tokens.c src/serve/tool_calling.c \
|
|
src/serve/json_value_grammar.c \
|
|
src/serve/json_reader.c src/serve/json_writer.c \
|
|
-lm $(LDFLAGS) $(LDFLAGS_BLAS) $(LDFLAGS_METAL) $(LDFLAGS_CUDA)
|
|
|
|
tests/test_bpe_pretokenize: tests/test_bpe_pretokenize.c $(PN_SRC) $(FOUNDRY_SRC) $(ALL_HDR)
|
|
$(CC) $(CFLAGS) -o $@ tests/test_bpe_pretokenize.c $(PN_SRC) $(FOUNDRY_SRC) \
|
|
-lm $(LDFLAGS) $(LDFLAGS_BLAS) $(LDFLAGS_METAL) $(LDFLAGS_CUDA)
|
|
|
|
# Clean-room property tests: pre-token split oracle over every code point, and
|
|
# bit-exact dequant/half-conversion checks against per-element references.
|
|
tests/test_pretok_props: tests/test_pretok_props.c $(PN_SRC) $(FOUNDRY_SRC) $(ALL_HDR)
|
|
$(CC) $(CFLAGS) -o $@ tests/test_pretok_props.c $(PN_SRC) $(FOUNDRY_SRC) \
|
|
-lm $(LDFLAGS) $(LDFLAGS_BLAS) $(LDFLAGS_METAL) $(LDFLAGS_CUDA)
|
|
|
|
tests/test_dequant_props: tests/test_dequant_props.c src/formats/gguf_dequant.c src/formats/gguf.c \
|
|
src/formats/gguf_dequant.h src/formats/gguf.h
|
|
$(CC) $(CFLAGS) -o $@ tests/test_dequant_props.c src/formats/gguf_dequant.c src/formats/gguf.c -lm
|
|
|
|
tests/test_rwkvx: tests/test_rwkvx.c $(PN_SRC) $(FOUNDRY_SRC) $(ALL_HDR)
|
|
$(CC) $(CFLAGS) -o $@ tests/test_rwkvx.c $(PN_SRC) $(FOUNDRY_SRC) \
|
|
-lm $(LDFLAGS) $(LDFLAGS_BLAS) $(LDFLAGS_METAL) $(LDFLAGS_CUDA)
|
|
|
|
tests/test_qwen35moe: tests/test_qwen35moe.c $(PN_SRC) $(FOUNDRY_SRC) $(ALL_HDR)
|
|
$(CC) $(CFLAGS) -o $@ tests/test_qwen35moe.c $(PN_SRC) $(FOUNDRY_SRC) \
|
|
-lm $(LDFLAGS) $(LDFLAGS_BLAS) $(LDFLAGS_METAL) $(LDFLAGS_CUDA)
|
|
|
|
# Batched-prefill causality (reference-free) on every qwen35 batched path the build has:
|
|
# CUDA forward_batch + 9b/9c, TT prefill. SKIPs without PN_QWEN35_MODEL or such a path.
|
|
# Red proof: tests/causality_red/run_red.sh.
|
|
tests/test_qwen35_prefill_causality: tests/test_qwen35_prefill_causality.c $(PN_SRC) $(FOUNDRY_SRC) $(ALL_HDR)
|
|
$(CC) $(CFLAGS) -o $@ tests/test_qwen35_prefill_causality.c $(PN_SRC) $(FOUNDRY_SRC) \
|
|
-lm $(LDFLAGS) $(LDFLAGS_BLAS) $(LDFLAGS_METAL) $(LDFLAGS_CUDA)
|
|
|
|
# Metal kernel-coverage gate: every weight the forward DISPATCHES must have a
|
|
# Metal matvec kernel registered for its quant type, or the stock mixed-quant
|
|
# GGUF turns into garbage logits at Phase-5 bring-up. Built TWICE from one
|
|
# source: the `_fake` binary links a stub fm_matvec_q5k, so Q5_K must flip to
|
|
# covered while the other missing types do not. A gate that printed a constant
|
|
# could not tell the two binaries apart — that difference IS the proof it
|
|
# measures registration. Both are model-gated on PN_QWEN35_MODEL.
|
|
tests/test_qwen35moe_metal_coverage: tests/test_qwen35moe_metal_coverage.c $(PN_SRC) $(FOUNDRY_SRC) $(ALL_HDR)
|
|
$(CC) $(CFLAGS) -o $@ tests/test_qwen35moe_metal_coverage.c $(PN_SRC) $(FOUNDRY_SRC) \
|
|
-lm $(LDFLAGS) $(LDFLAGS_BLAS) $(LDFLAGS_METAL) $(LDFLAGS_CUDA)
|
|
|
|
tests/test_qwen35moe_metal_coverage_fake: tests/test_qwen35moe_metal_coverage.c $(PN_SRC) $(FOUNDRY_SRC) $(ALL_HDR)
|
|
$(CC) $(CFLAGS) -DPN_COVERAGE_FAKE_KERNEL -o $@ \
|
|
tests/test_qwen35moe_metal_coverage.c $(PN_SRC) $(FOUNDRY_SRC) \
|
|
-lm $(LDFLAGS) $(LDFLAGS_BLAS) $(LDFLAGS_METAL) $(LDFLAGS_CUDA)
|
|
|
|
# Losslessness gate for greedy speculative decoding: proves the speculative
|
|
# stream is bit-identical to plain greedy decode for any draft. Needs a model.
|
|
tests/test_spec_decode: tests/test_spec_decode.c $(PN_SRC) $(FOUNDRY_SRC) $(ALL_HDR)
|
|
$(CC) $(CFLAGS) -o $@ tests/test_spec_decode.c $(PN_SRC) $(FOUNDRY_SRC) \
|
|
-lm $(LDFLAGS) $(LDFLAGS_BLAS) $(LDFLAGS_METAL) $(LDFLAGS_CUDA)
|
|
|
|
# End-to-end losslessness + realized-speedup measurement for the speculative
|
|
# generation loop (pn_spec_generate). Needs a model.
|
|
tests/test_spec_generate: tests/test_spec_generate.c $(PN_SRC) $(FOUNDRY_SRC) $(ALL_HDR)
|
|
$(CC) $(CFLAGS) -o $@ tests/test_spec_generate.c $(PN_SRC) $(FOUNDRY_SRC) \
|
|
-lm $(LDFLAGS) $(LDFLAGS_BLAS) $(LDFLAGS_METAL) $(LDFLAGS_CUDA)
|
|
|
|
# M1 bench: verify-pass cost vs number of rows M (picks the default draft width
|
|
# and confirms the batched-verify payoff). Needs a model.
|
|
tests/bench_verify_rows: tests/bench_verify_rows.c $(PN_SRC) $(FOUNDRY_SRC) $(ALL_HDR)
|
|
$(CC) $(CFLAGS) -o $@ tests/bench_verify_rows.c $(PN_SRC) $(FOUNDRY_SRC) \
|
|
-lm $(LDFLAGS) $(LDFLAGS_BLAS) $(LDFLAGS_METAL) $(LDFLAGS_CUDA)
|
|
|
|
# M2/M3 gate: pn_llama_verify_batch ragged multi-sequence verify is bit-identical
|
|
# (memcmp) to an independent per-slot forward_batch replay. Needs a model.
|
|
tests/test_verify_batch: tests/test_verify_batch.c $(PN_SRC) $(FOUNDRY_SRC) $(ALL_HDR)
|
|
$(CC) $(CFLAGS) -o $@ tests/test_verify_batch.c $(PN_SRC) $(FOUNDRY_SRC) \
|
|
-lm $(LDFLAGS) $(LDFLAGS_BLAS) $(LDFLAGS_METAL) $(LDFLAGS_CUDA)
|
|
|
|
# M4/M5 gate: batched speculative decode (pn_batch_decoder_step_spec) emits a
|
|
# token stream bit-identical to plain forward and plain batch decode for any
|
|
# draft, across batch sizes, K widths, mixed spec/plain slots, and EOS. Needs a model.
|
|
tests/test_spec_batch: tests/test_spec_batch.c $(PN_SRC) $(FOUNDRY_SRC) $(ALL_HDR)
|
|
$(CC) $(CFLAGS) -o $@ tests/test_spec_batch.c $(PN_SRC) $(FOUNDRY_SRC) \
|
|
-lm $(LDFLAGS) $(LDFLAGS_BLAS) $(LDFLAGS_METAL) $(LDFLAGS_CUDA)
|
|
|
|
# MemoryAware Phase 1 unit test (host signals + memwatch publish/read + level
|
|
# derivation + reserve policy). Self-contained: links only the mem module + the
|
|
# host-signal reader + libm, so it builds and runs on the Mac (no model/GPU).
|
|
MEM_SRC = src/core/mem/pn_host_signals.c src/core/mem/pn_memwatch.c \
|
|
src/core/mem/pn_admission.c src/core/mem/pn_ladder.c \
|
|
src/serve/signal_handlers.c
|
|
tests/test_memwatch: tests/test_memwatch.c $(MEM_SRC) $(ALL_HDR)
|
|
$(CC) $(CFLAGS) -o $@ tests/test_memwatch.c $(MEM_SRC) $(CUDA_SRC) -lm $(LDFLAGS) $(LDFLAGS_CUDA)
|
|
|
|
# Die-manager unit test (Phase 7 placement primitive). Self-contained: logical
|
|
# dies only — links just the die-manager module, no model/GPU, so it builds
|
|
# and runs on the Mac. The pn_dm_init_cuda probe is validated on the K80 test machine.
|
|
tests/test_die_manager: tests/test_die_manager.c $(PN_SRC) $(FOUNDRY_SRC) $(ALL_HDR)
|
|
$(CC) $(CFLAGS) -o $@ tests/test_die_manager.c $(PN_SRC) $(FOUNDRY_SRC) \
|
|
-lm $(LDFLAGS) $(LDFLAGS_BLAS) $(LDFLAGS_METAL) $(LDFLAGS_CUDA)
|
|
|
|
# Model-registry unit test (Phase 7 multi-model serving). Bookkeeping asserts
|
|
# run everywhere; the model-backed part (two names resident, generation,
|
|
# unload-drain) uses models/qwen3-0.6b-Q8_0.gguf and skips if it is absent
|
|
# (override with PN_TEST_MODEL).
|
|
tests/test_model_registry: tests/test_model_registry.c src/serve/model_registry.c src/serve/batch_sched.c src/serve/request_profile.c src/serve/serve_backend_guard.c $(PN_SRC) $(FOUNDRY_SRC) $(ALL_HDR)
|
|
$(CC) $(CFLAGS) -o $@ tests/test_model_registry.c src/serve/model_registry.c src/serve/batch_sched.c src/serve/request_profile.c src/serve/serve_backend_guard.c \
|
|
$(PN_SRC) $(FOUNDRY_SRC) \
|
|
-lm $(LDFLAGS) $(LDFLAGS_BLAS) $(LDFLAGS_METAL) $(LDFLAGS_CUDA)
|
|
|
|
# Unload-reclaim regression (the /admin/models/unload die leak). Proves the die
|
|
# budget comes BACK — a DIFFERENT model loads onto the SAME die in the SAME
|
|
# process, on a die sized to fit exactly one — and that an unload which cannot
|
|
# drain REFUSES instead of reporting success and stranding the dies. Same link
|
|
# set as test_model_registry; logical dies only, so it runs on the Mac.
|
|
tests/test_model_unload_reclaim: tests/test_model_unload_reclaim.c src/serve/model_registry.c src/serve/batch_sched.c src/serve/request_profile.c src/serve/serve_backend_guard.c $(PN_SRC) $(FOUNDRY_SRC) $(ALL_HDR)
|
|
$(CC) $(CFLAGS) -o $@ tests/test_model_unload_reclaim.c src/serve/model_registry.c src/serve/batch_sched.c src/serve/request_profile.c src/serve/serve_backend_guard.c \
|
|
$(PN_SRC) $(FOUNDRY_SRC) \
|
|
-lm $(LDFLAGS) $(LDFLAGS_BLAS) $(LDFLAGS_METAL) $(LDFLAGS_CUDA)
|
|
|
|
# The silent-deploy class: compiled-backend identity, the refuse-to-start guard
|
|
# for a `--dies` this binary cannot honour, and the SERVED-vs-configured
|
|
# concurrency the two JSON surfaces advertise. Links the whole serve + engine
|
|
# (like test_serve_sched_qwen35) so the JSON assertions run the REAL
|
|
# oai_handle_models / ma_handle_models over a socketpair rather than a
|
|
# reimplementation of them. No GPU, no model file, no network.
|
|
tests/test_backend_guard: tests/test_backend_guard.c $(PN_SRC) $(SERVE_SRC) $(FOUNDRY_SRC) $(ALL_HDR)
|
|
$(CC) $(CFLAGS) -o $@ tests/test_backend_guard.c $(PN_SRC) $(SERVE_SRC) $(FOUNDRY_SRC) \
|
|
-lm $(LDFLAGS) $(LDFLAGS_BLAS) $(LDFLAGS_METAL) $(LDFLAGS_CUDA)
|
|
|
|
# Dispatch-layer bs_get_load() accessor test (Phase G0). Exercises the pure
|
|
# slot/queue snapshot (sched==NULL single-user + hand-built cap=4 states);
|
|
# links batch_sched.c + the engine (batch_sched.c's other fns need it), no GPU.
|
|
tests/test_bs_load: tests/test_bs_load.c src/serve/batch_sched.c src/serve/request_profile.c $(PN_SRC) $(FOUNDRY_SRC) $(ALL_HDR)
|
|
$(CC) $(CFLAGS) -o $@ tests/test_bs_load.c src/serve/batch_sched.c src/serve/request_profile.c \
|
|
$(PN_SRC) $(FOUNDRY_SRC) \
|
|
-lm $(LDFLAGS) $(LDFLAGS_BLAS) $(LDFLAGS_METAL) $(LDFLAGS_CUDA)
|
|
|
|
# A4: unit tests for pn_gguf_dequantize_row (per-row byte-offset math +
|
|
# per-row == slice-of-full-tensor) and pn_qwen35moe_model_embed_row.
|
|
# Part A always runs (synthetic data); Part B needs PN_TEST_MODEL (a real GGUF).
|
|
tests/test_embed_row: tests/test_embed_row.c $(PN_SRC) $(FOUNDRY_SRC) $(ALL_HDR)
|
|
$(CC) $(CFLAGS) -o $@ tests/test_embed_row.c $(PN_SRC) $(FOUNDRY_SRC) \
|
|
-lm $(LDFLAGS) $(LDFLAGS_BLAS) $(LDFLAGS_METAL) $(LDFLAGS_CUDA)
|
|
|
|
# The column-tile permutation that de-interleaves a joint Q+gate projection. Links ONLY the
|
|
# module under test: it has no device, no artifact and no USE_TT, which is the point — the
|
|
# de-interleave is the one Phase 5 item with no proven shape to inherit, so its arithmetic
|
|
# is settled with no card and on any host.
|
|
tests/test_tt_column_runs: tests/test_tt_column_runs.c src/accel/tt/pn_tt_column_runs.c \
|
|
src/accel/tt/pn_tt_column_runs.h
|
|
$(CC) $(CFLAGS) -o $@ tests/test_tt_column_runs.c src/accel/tt/pn_tt_column_runs.c -lm
|
|
|
|
# The elementwise core split's tile arithmetic. Links ONLY the module under test — no device,
|
|
# no artifact, no USE_TT — because the one thing a split can get wrong that nothing reports is
|
|
# an ADDRESS, and that is settled here rather than on a card.
|
|
tests/test_tt_name_list: tests/test_tt_name_list.c \
|
|
src/accel/tt/pn_tt_name_list.c src/accel/tt/pn_tt_name_list.h
|
|
$(CC) $(CFLAGS) -o $@ tests/test_tt_name_list.c \
|
|
src/accel/tt/pn_tt_name_list.c -lm
|
|
|
|
# The staging pipeline's release contract, off hardware: a released item is always built.
|
|
# Build it with -DPN_TT_STAGE_PIPELINE_RED to see it fail.
|
|
tests/test_tt_stage_pipeline: tests/test_tt_stage_pipeline.c \
|
|
src/accel/tt/pn_tt_stage_pipeline.c src/accel/tt/pn_tt_stage_pipeline.h
|
|
$(CC) $(CFLAGS) -o $@ tests/test_tt_stage_pipeline.c src/accel/tt/pn_tt_stage_pipeline.c
|
|
|
|
tests/test_tt_eltwise_split: tests/test_tt_eltwise_split.c \
|
|
src/accel/tt/pn_tt_eltwise_split.c src/accel/tt/pn_tt_eltwise_split.h
|
|
$(CC) $(CFLAGS) -o $@ tests/test_tt_eltwise_split.c \
|
|
src/accel/tt/pn_tt_eltwise_split.c -lm
|
|
|
|
tests/test_tt_descriptor_census: tests/test_tt_descriptor_census.c \
|
|
src/accel/tt/pn_tt_descriptor_census.c src/accel/tt/pn_tt_descriptor_census.h \
|
|
src/accel/tt/pn_tt_name_list.c src/accel/tt/pn_tt_name_list.h
|
|
$(CC) $(CFLAGS) -o $@ tests/test_tt_descriptor_census.c \
|
|
src/accel/tt/pn_tt_descriptor_census.c src/accel/tt/pn_tt_name_list.c -lm
|
|
|
|
# Self-contained differential parity test for the optimized token sampler:
|
|
# diffs a verbatim copy of the original sampler against the optimized one over
|
|
# thousands of random cases. No model/engine deps, so it links only libm.
|
|
tests/test_sampler_parity: tests/test_sampler_parity.c $(ALL_HDR)
|
|
$(CC) $(CFLAGS) -o $@ tests/test_sampler_parity.c -lm
|
|
|
|
# GPU-vs-CPU parity harness for the qwen35moe CUDA kernels. Always links the
|
|
# Foundry CUDA backend (dlopen, -ldl) so it builds + runs everywhere: on a
|
|
# host with no CUDA driver it self-gates on fc_available() and prints
|
|
# [SKIP] no CUDA. The actual GPU diffs run on a K80 host. The backend is
|
|
# pulled in directly (not via USE_CUDA) so the harness is self-contained.
|
|
tests/test_kernel_parity: tests/test_kernel_parity.c $(FOUNDRY)/cuda/fc_cuda.c $(FOUNDRY)/barswap/barswap.c $(ALL_HDR)
|
|
$(CC) $(CFLAGS) -DUSE_CUDA -o $@ tests/test_kernel_parity.c \
|
|
$(FOUNDRY)/cuda/fc_cuda.c $(FOUNDRY)/barswap/barswap.c -lm -ldl $(LDFLAGS)
|
|
|
|
# GATING smoke test for the 2-die barswap context swap (Task 1). Proves two
|
|
# live CUDA contexts (one per K80 die, both ordinal 0) coexist and survive
|
|
# bs_acquire/release multiplexing through the single MMIO slot. Self-gates on
|
|
# fc_driver_load(): on a host with no CUDA driver it prints [SKIP] no CUDA.
|
|
# Linked like test_kernel_parity (fc_cuda.c + barswap.c, dlopen -ldl). The
|
|
# operator runs this FIRST — it gates the 2-die layer-split forward.
|
|
tests/test_2die_swap: tests/test_2die_swap.c $(FOUNDRY)/cuda/fc_cuda.c $(FOUNDRY)/barswap/barswap.c $(ALL_HDR)
|
|
$(CC) $(CFLAGS) -DUSE_CUDA -o $@ tests/test_2die_swap.c \
|
|
$(FOUNDRY)/cuda/fc_cuda.c $(FOUNDRY)/barswap/barswap.c -lm -ldl $(LDFLAGS)
|
|
|
|
# Regression guard for the GLOBAL stream-capture bug (task #28). Captures a
|
|
# graph on one die while a second thread allocates/syncs on another, and fails
|
|
# if either side is disturbed — which is what CU_STREAM_CAPTURE_MODE_GLOBAL did
|
|
# process-wide, showing up as unexplained 900/901 in the production log. Needs
|
|
# two visible devices; self-gates to [SKIP] otherwise. Run it on idle dies,
|
|
# e.g. CUDA_VISIBLE_DEVICES=2,3 tests/test_graph_capture_concurrency.
|
|
# Linked like test_kernel_parity (fc_cuda.c + barswap.c, dlopen -ldl).
|
|
tests/test_graph_capture_concurrency: tests/test_graph_capture_concurrency.c $(FOUNDRY)/cuda/fc_cuda.c $(FOUNDRY)/barswap/barswap.c $(ALL_HDR)
|
|
$(CC) $(CFLAGS) -DUSE_CUDA -o $@ tests/test_graph_capture_concurrency.c \
|
|
$(FOUNDRY)/cuda/fc_cuda.c $(FOUNDRY)/barswap/barswap.c -lm -ldl -lpthread $(LDFLAGS)
|
|
|
|
# CPU-reference golden-vector generator for the qwen35moe GPU kernels (no model).
|
|
# Builds the generator, then runs it to (re)produce tests/golden/*.bin.
|
|
tests/gen_golden_qwen35: tests/gen_golden_qwen35.c $(PN_SRC) $(FOUNDRY_SRC) $(ALL_HDR)
|
|
$(CC) $(CFLAGS) -o $@ tests/gen_golden_qwen35.c $(PN_SRC) $(FOUNDRY_SRC) \
|
|
-lm $(LDFLAGS) $(LDFLAGS_BLAS) $(LDFLAGS_METAL) $(LDFLAGS_CUDA)
|
|
|
|
.PHONY: golden
|
|
golden: tests/gen_golden_qwen35
|
|
./tests/gen_golden_qwen35
|
|
|
|
# Converter CLI
|
|
pantheon-convert: cli/convert.c $(FOUNDRY)/pth/pth.c $(FOUNDRY)/safetensors/safetensors.c
|
|
$(CC) $(CFLAGS) -o $@ cli/convert.c $(FOUNDRY)/pth/pth.c $(FOUNDRY)/safetensors/safetensors.c -lm
|
|
|
|
# Clean. Test/bench/debug binaries go by pattern (sources are .c/.h), the same rule as
|
|
# .gitignore, so a new test cannot be missed.
|
|
clean:
|
|
rm -f pantheon pantheon-convert libpantheon.a $(foreach b,cpu cuda tt metal cuda-tt cuda-metal tt-metal cuda-tt-metal,pantheon-$(b))
|
|
find tests -maxdepth 1 -type f \( -name 'test_*' -o -name 'bench_*' -o -name 'gen_golden_*' \) ! -name '*.c' ! -name '*.h' -delete
|
|
rm -rf *.dSYM tests/*.dSYM
|
|
rm -f *.o src/core/*.o src/formats/*.o src/models/*.o src/memory/*.o src/accel/*.o
|
|
rm -rf $(LIB_OBJDIR)
|