Local project checks and contribution templates: make check, dependency-free C/python tests, issue forms + blank issues, CONTRIBUTING (#20)

* Add lightweight project checks and templates

* Ignore generated test binaries

* Keep project checks local
This commit is contained in:
ZacharyZcR
2026-07-10 14:56:41 +08:00
committed by GitHub
parent 99111993a4
commit 8a2e4439ba
12 changed files with 276 additions and 6 deletions
+26 -1
View File
@@ -35,7 +35,9 @@ CUDA_HOME ?= /usr/local/cuda
NVCC ?= $(CUDA_HOME)/bin/nvcc
CUDA_ARCH ?= native
NVCCFLAGS ?= -O3 -std=c++17 -arch=$(CUDA_ARCH) -Xcompiler=-Wall,-Wextra
PYTHON ?= python3
CUDA_OBJ =
TEST_BINS = tests/test_json tests/test_st
ifeq ($(CUDA),1)
ifeq ($(UNAME_S),Darwin)
$(error CUDA=1 is supported only on Linux)
@@ -66,5 +68,28 @@ olmoe: olmoe.c st.h json.h
portable:
$(MAKE) glm ARCH=x86-64-v3
tests/test_json: tests/test_json.c json.h
$(CC) $(CFLAGS) $< -o $@ $(LDFLAGS)
tests/test_st: tests/test_st.c st.h json.h compat.h
$(CC) $(CFLAGS) $< -o $@ $(LDFLAGS)
test-c: $(TEST_BINS)
@for test in $(TEST_BINS); do ./$$test || exit 1; done
test-python:
$(PYTHON) -m unittest discover -s tests -p 'test_*.py'
test: test-c test-python
# CI-friendly validation: one portable CPU build and dependency-free tests.
check:
$(MAKE) clean
$(MAKE) portable
$(MAKE) test
clean:
rm -f olmoe glm backend_cuda.o backend_cuda_test
rm -f olmoe glm backend_cuda.o backend_cuda_test $(TEST_BINS)
rm -rf tests/__pycache__
.PHONY: all cuda-test portable test-c test-python test check clean
+10 -5
View File
@@ -17,15 +17,20 @@ PROFILE_RE = re.compile(
PROFILE_KEYS = ("disk", "expert_matmul", "attention", "lm_head", "other")
def parse_output(stdout: str, stderr: str = "") -> tuple[float, list[float]]:
"""Extract throughput and profile timings from one engine run."""
speed = SPEED_RE.search(stdout)
profile = PROFILE_RE.search(stdout)
if not speed or not profile:
raise RuntimeError(f"benchmark output missing\nstdout:\n{stdout}\nstderr:\n{stderr}")
return float(speed.group(1)), [float(value) for value in profile.groups()]
def execute(engine: str, env: dict[str, str]) -> tuple[float, list[float]]:
run = subprocess.run(
[engine, "4", "4", "4"], env=env, text=True, capture_output=True, check=True
)
speed = SPEED_RE.search(run.stdout)
profile = PROFILE_RE.search(run.stdout)
if not speed or not profile:
raise RuntimeError(f"benchmark output missing\nstdout:\n{run.stdout}\nstderr:\n{run.stderr}")
return float(speed.group(1)), [float(value) for value in profile.groups()]
return parse_output(run.stdout, run.stderr)
def main() -> None:
+24
View File
@@ -0,0 +1,24 @@
import unittest
from benchmark_cuda_fixture import parse_output
SAMPLE = """
REPLAY decode: 4 tokens | 12.34 tok/s
PROFILO: expert-disk 1.25s | expert-matmul 2.50s | attention 0.75s | lm_head 0.10s | altro -0.05s
"""
class ParseOutputTest(unittest.TestCase):
def test_extracts_speed_and_profile(self):
speed, profile = parse_output(SAMPLE)
self.assertEqual(speed, 12.34)
self.assertEqual(profile, [1.25, 2.5, 0.75, 0.1, -0.05])
def test_rejects_incomplete_output(self):
with self.assertRaisesRegex(RuntimeError, "benchmark output missing"):
parse_output("REPLAY decode: 4 tokens | 12.34 tok/s", "engine failed")
if __name__ == "__main__":
unittest.main()
+36
View File
@@ -0,0 +1,36 @@
#include <math.h>
#include <stdio.h>
#include <string.h>
#include "../json.h"
#define CHECK(condition) do { \
if (!(condition)) { \
fprintf(stderr, "%s:%d: check failed: %s\n", __FILE__, __LINE__, #condition); \
return 1; \
} \
} while (0)
int main(void) {
jval *root = json_parse(
"{\"name\":\"Colibri\\nCPU\",\"enabled\":true,\"empty\":null,"
"\"values\":[1,-2.5,3e2],\"unicode\":\"\\u03bb \\uD83D\\uDE80\"}",
NULL
);
CHECK(root && root->t == J_OBJ);
CHECK(strcmp(json_get(root, "name")->str, "Colibri\nCPU") == 0);
CHECK(json_get(root, "enabled")->boolean == 1);
CHECK(json_get(root, "empty")->t == J_NULL);
CHECK(json_get(root, "missing") == NULL);
jval *values = json_get(root, "values");
CHECK(values->t == J_ARR && values->len == 3);
CHECK(values->kids[0]->num == 1.0);
CHECK(values->kids[1]->num == -2.5);
CHECK(values->kids[2]->num == 300.0);
CHECK(strcmp(json_get(root, "unicode")->str, "λ 🚀") == 0);
puts("json tests: ok");
return 0;
}
+26
View File
@@ -0,0 +1,26 @@
#include <math.h>
#include <stdint.h>
#include <stdio.h>
#include "../st.h"
#define CHECK(condition) do { \
if (!(condition)) { \
fprintf(stderr, "%s:%d: check failed: %s\n", __FILE__, __LINE__, #condition); \
return 1; \
} \
} while (0)
int main(void) {
CHECK(bf16_to_f32(0x3f80) == 1.0f);
CHECK(bf16_to_f32(0xc020) == -2.5f);
CHECK(f16_to_f32(0x3c00) == 1.0f);
CHECK(f16_to_f32(0xc100) == -2.5f);
CHECK(f16_to_f32(0x0001) > 0.0f);
CHECK(isinf(f16_to_f32(0x7c00)));
CHECK(st_hash("tensor.weight") == st_hash("tensor.weight"));
CHECK(st_hash("tensor.weight") != st_hash("tensor.bias"));
puts("safetensors primitive tests: ok");
return 0;
}