C内核按库功能拆解,编译结果缓存区构建,编译过程与已有缓存结果对照功能实现

This commit is contained in:
lujingze committed 2026-09-12 05:24:48 +00:00
1 parent aa4951b14e
commit 151e6e4b97
30 files changed
+4856 -604

No files matched your search

+37 -14
View File
@@ -24,7 +24,9 @@ from app.simulation.backends import simulation_config
from app.simulation.native_codegen import build as builder
from app.simulation.native_codegen.compiler import compile_native_program
from app.simulation.native_codegen.input import load_input
from tests.manual.benchmark_native_pipe_solver import build_snapshot, pipe_source_path, working_native_paths
SNAPSHOT_HELPER = ROOT / 'tests/manual/benchmark_native_pipe_solver.py'
VARIANTS = ('guarded-newton', 'previous-newton', 'fixed-point')
FIELDS = '''cache_requests cache_hits cache_misses flow_calls zero_pressure_calls
pnl00r_analytic_calls resistance_calls scalar_analytic_calls iterative_calls
@@ -214,7 +216,7 @@ def instrument(source: str, variant: str) -> str:
limit = '(kind==0?64:16)' if fixed else '80' if variant == 'previous-newton' else '128'
prefix = PROFILE_PREFIX.replace('@VARIANT@', variant).replace('@FIXED@', str(int(fixed)))
prefix = prefix.replace('@LIMIT@', limit).replace('@FIELDS@', ' '.join(f'X({name})' for name in FIELDS))
source = replace_once(source, '#include <stddef.h>', '#include <stddef.h>\n' + prefix)
source = replace_once(source, '#include <math.h>', '#include <math.h>\n' + prefix)
# Exhaustion is marked at the actual loop fall-through, not inferred from
# visiting the last allowed iteration (which can still converge).
start = source.index('double native_pipe_resistance(')
@@ -259,6 +261,19 @@ def instrument(source: str, variant: str) -> str:
return source
def instrument_common(source: str) -> str:
"""Count both ordinary and canonical Jacobian RHS evaluations exactly once."""
calls = [('model_eval', ' return model_eval(t,y,dy,w);')]
if 'int native_jacobian_rhs(' in source:
calls.append(('model_eval_jacobian', ' return model_eval_jacobian(t,y,dy,w);'))
for function, fragment in calls:
source = replace_once(source, fragment,
' extern void pipe_profile_rhs_enter(void),pipe_profile_rhs_leave(void);\n'
f' pipe_profile_rhs_enter();int ok={function}(t,y,dy,w);pipe_profile_rhs_leave();return ok;')
return source
def git(*arguments: str) -> str:
return subprocess.check_output(['git', *arguments], cwd=ROOT, text=True).strip()
@@ -268,11 +283,14 @@ def prepare(args, out: Path) -> dict:
metadata = json.loads((out / 'prepared.json').read_text())
if metadata['input_sha256'] != sha256(args.input.read_bytes()).hexdigest():
raise ValueError('Prepared model no longer matches the input file')
if metadata['script_sha256'] != sha256(Path(__file__).read_bytes()).hexdigest():
if (metadata['script_sha256'] != sha256(Path(__file__).read_bytes()).hexdigest()
or metadata.get('snapshot_helper_sha256') != sha256(SNAPSHOT_HELPER.read_bytes()).hexdigest()):
raise ValueError('Diagnostic helper changed; choose a fresh output directory')
return metadata
if any((out / variant).exists() for variant in VARIANTS):
raise ValueError('Partially prepared variant directories exist; choose a fresh output directory')
previous = git('rev-parse', args.previous_ref)
current = git('rev-parse', args.current_ref)
current = 'working-tree' if args.current_ref == 'working-tree' else git('rev-parse', args.current_ref)
xml, doc = load_input(args.input)
config = simulation_config(doc.simulation)
if config.rtol != 1e-8 or config.t_start != 0 or config.t_stop != 10:
@@ -281,37 +299,40 @@ def prepare(args, out: Path) -> dict:
out.mkdir(parents=True, exist_ok=True)
(out / 'input.xml').write_bytes(xml)
(out / 'input.json').write_bytes(args.input.read_bytes())
paths = git('ls-tree', '-r', '--name-only', current, 'native').splitlines()
metadata = dict(input=str(args.input.resolve()), input_sha256=sha256(args.input.read_bytes()).hexdigest(),
xml_sha256=sha256(xml).hexdigest(), script_sha256=sha256(Path(__file__).read_bytes()).hexdigest(),
snapshot_helper_sha256=sha256(SNAPSHOT_HELPER.read_bytes()).hexdigest(),
previous_revision=previous, current_revision=current, settings=vars(config),
sample_step=doc.simulation.sample_step, variants={},
measurement_note='Instrumented times are diagnostic overhead and MUST NOT be used as production benchmark results.',
counter_scope='rhs counts native_rhs/model_eval calls including rejected trials and Jacobian differences; non_rhs includes initialization/output/probe evaluations.',
counter_scope='rhs counts native_rhs/model_eval and, where present, native_jacobian_rhs/model_eval_jacobian calls including rejected trials and Jacobian differences; non_rhs includes initialization/output/probe evaluations.',
replay_scope='All guarded RHS resistance calls, including scalar analytic low-Re cases; no sampling or deduplication. Cache hits, zero pressure difference and direct PNL00R analytic calls are excluded and counted separately.',
capture_format='Native-endian IEEE-754 binary64 records: base, diameter, length, relative roughness, den=pi*d*mu, kind (six doubles, 48 bytes). Replay on the same host.',
residual_test='At actual returned q, independently factored long-double f(Re) evaluates abs(Re^2*f(Re)/K-1)<=1e-9. Separate from each algorithm stopping rule.')
original_native = builder.NATIVE
prepared_builds = [] # Pin earlier variants while later variants are built.
try:
for variant in VARIANTS:
directory = out / variant
revision = current if variant == 'guarded-newton' else previous
paths = (working_native_paths() if revision == 'working-tree'
else git('ls-tree', '-r', '--name-only', revision, 'native').splitlines())
for name in paths:
target = directory / name
target.parent.mkdir(parents=True, exist_ok=True)
target.write_bytes(subprocess.check_output(['git', 'show', f'{revision}:{name}'], cwd=ROOT))
kernel = directory / 'native/components/kernels.c'
data = ((ROOT / name).read_bytes() if revision == 'working-tree'
else subprocess.check_output(['git', 'show', f'{revision}:{name}'], cwd=ROOT))
target.write_bytes(data)
kernel = pipe_source_path(directory / 'native')
original_hash = sha256(kernel.read_bytes()).hexdigest()
kernel.write_text(instrument(kernel.read_text(), variant))
common = directory / 'native/runtime/common.c'
common.write_text(replace_once(common.read_text(), ' return model_eval(t,y,dy,w);',
''' extern void pipe_profile_rhs_enter(void),pipe_profile_rhs_leave(void);
pipe_profile_rhs_enter();int ok=model_eval(t,y,dy,w);pipe_profile_rhs_leave();return ok;'''))
common.write_text(instrument_common(common.read_text()))
main = directory / 'native/runtime/main.c'
main.write_text(replace_once(main.read_text(), 'int main(int argc, char **argv) {',
'int main(int argc, char **argv) {\n extern void pipe_profile_install(void);pipe_profile_install();'))
builder.NATIVE = directory / 'native'
build = builder.build_native(program, cache_dir=out / 'cache')
build = build_snapshot(program, directory / 'native', out / 'cache', required_sources=(common, main))
prepared_builds.append(build)
replay_source = directory / 'replay.c'
replay_source.write_text(REPLAY_MAIN)
replay = directory / ('replay.exe' if os.name == 'nt' else 'replay')
@@ -323,7 +344,8 @@ def prepare(args, out: Path) -> dict:
if compiled.returncode:
raise RuntimeError(f'Replay compilation failed: {compiled.stderr}')
metadata['variants'][variant] = dict(executable=str(build.executable), replay=str(replay),
build_key=build.manifest['buildKey'], original_kernel_sha256=original_hash,
build_key=build.manifest['buildKey'], pipe_source=str(kernel.relative_to(directory)),
compiled_source_hashes=build.manifest['sourceHashes'], original_kernel_sha256=original_hash,
instrumented_kernel_sha256=sha256(kernel.read_bytes()).hexdigest())
print(f'Prepared {variant}', flush=True)
finally:
@@ -423,7 +445,8 @@ def main():
parser.add_argument('--input', type=Path, default=ROOT / 'tests/data/test-mql-8-corrected.json')
parser.add_argument('--output-dir', type=Path, required=True)
parser.add_argument('--previous-ref', default='5d5a2e1')
parser.add_argument('--current-ref', default='808c484')
parser.add_argument('--current-ref', default='808c484',
help='Audited guarded-solver revision, or working-tree for the current modular sources')
parser.add_argument('--timeout', type=float, default=120)
parser.add_argument('--prepare-only', action='store_true')
args = parser.parse_args()