Files
SystemSimulationApp/tests/test_native_pipe_cache.py
T

89 lines
3.5 KiB
Python

"""Check exact-input reuse at the C kernel boundary, including invalidation."""
from pathlib import Path
import subprocess
import tempfile
import unittest
from app.simulation.native_codegen.build import toolchain
from tests.native_kernel_source import native_kernel_source
ROOT = Path(__file__).resolve().parents[1]
class NativePipeCacheTests(unittest.TestCase):
def test_reuse_preserves_results_and_invalidates_every_input(self):
try:
compiler = toolchain()[0]
except (OSError, RuntimeError, subprocess.SubprocessError) as exc:
self.skipTest(f"Native toolchain unavailable: {exc}")
source = native_kernel_source()
signature = "double d, double length, double rr, int kind) {"
self.assertEqual(source.count(signature), 1)
source = "static int pipe_calls;\n" + source.replace(
signature, signature + "\n++pipe_calls;", 1)
harness = r'''
#include <stdio.h>
#define CHECK(expr) do { if(!(expr)) { fprintf(stderr,"line %d\n",__LINE__); return 1; } } while(0)
static int exercise(NativePipeCache *cache, NativeMedium *m, double *x, int kind) {
double expected=native_pipe_flow(m,x[0],x[1],x[2],x[3],x[4],x[5],kind);
int before=pipe_calls;
double actual=native_pipe_flow_cached(cache,m,x[0],x[1],x[2],x[3],x[4],x[5],kind);
CHECK(actual==expected);
CHECK(pipe_calls==before+1);
actual=native_pipe_flow_cached(cache,m,x[0],x[1],x[2],x[3],x[4],x[5],kind);
CHECK(actual==expected);
CHECK(pipe_calls==before+1);
return 0;
}
int main(void) {
NativeMedium m={0,287,1005,300,0,1.8e-5,300,110.4};
NativePipeCache cache={0},other={0};
double x[]={2e5,1e5,300,.01,1,.0001};
CHECK(!exercise(&cache,&m,x,1));
for(int i=0;i<6;i++) {
x[i]=nextafter(x[i],INFINITY);
CHECK(!exercise(&cache,&m,x,1));
}
double swap=x[0]; x[0]=x[1]; x[1]=swap;
CHECK(!exercise(&cache,&m,x,1));
for(int kind=0;kind<=3;kind++) CHECK(!exercise(&cache,&m,x,kind));
CHECK(!exercise(&cache,&m,x,1));
double *fields[]={&m.R,&m.cp,&m.Tref,&m.slope,&m.mu,&m.muT,&m.S};
for(int i=0;i<7;i++) {
*fields[i]+=.001*fmax(fabs(*fields[i]),1e-5);
CHECK(!exercise(&cache,&m,x,1));
}
m.real_helium=1;
CHECK(!exercise(&cache,&m,x,1));
NativeMedium copy=m;
int before=pipe_calls;
CHECK(native_pipe_flow_cached(&cache,&copy,x[0],x[1],x[2],x[3],x[4],x[5],1)==cache.flow);
CHECK(pipe_calls==before);
CHECK(!exercise(&other,&m,x,1));
x[3]=NAN;
for(int i=0;i<2;i++) {
before=pipe_calls;
CHECK(isnan(native_pipe_flow_cached(&cache,&m,x[0],x[1],x[2],x[3],x[4],x[5],1)));
CHECK(pipe_calls==before+1 && !cache.valid);
}
return 0;
}
'''
with tempfile.TemporaryDirectory(prefix="native-pipe-cache-") as directory:
path = Path(directory)
c_file, exe = path / "cache.c", path / "cache.exe"
c_file.write_text(source + harness)
build = subprocess.run([
compiler, "-std=c11", "-O3", "-Wall", "-Wextra", "-Werror",
"-ffp-contract=off", "-fno-fast-math", "-static-libgcc",
"-I", str(ROOT / "native/include"), str(c_file), "-lm", "-o", str(exe),
], capture_output=True, text=True, timeout=60)
self.assertEqual(build.returncode, 0, build.stderr)
run = subprocess.run([str(exe)], capture_output=True, text=True, timeout=30)
self.assertEqual(run.returncode, 0, run.stderr)
if __name__ == "__main__":
unittest.main()