Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-11-09 09:32:56

0001 """CPU-only checks for the optical serial/MT timeline integration validator."""
0002 
0003 import csv
0004 import json
0005 from pathlib import Path
0006 import subprocess
0007 import sys
0008 from tempfile import TemporaryDirectory
0009 import unittest
0010 
0011 
0012 CHECKER = Path(__file__).with_name("check_simg4ox_timing.py")
0013 
0014 
0015 def event_row(event_id, start, submit, gpu_start, gpu_end, release, end, threads=2):
0016     row = {
0017         "event_id": event_id, "dispatch_mode": "synchronous" if threads > 1 else "blocking",
0018         "start_offset_s": start, "cpu_pre_start_time_offset_s": start,
0019         "cpu_pre_end_time_offset_s": submit, "gpu_submit_time_offset_s": submit,
0020         "gpu_wait_start_time_offset_s": submit, "gpu_start_time_offset_s": gpu_start,
0021         "gpu_end_time_offset_s": gpu_end, "gpu_wait_end_time_offset_s": gpu_end,
0022         "cpu_post_start_time_offset_s": gpu_end, "cpu_post_end_time_offset_s": end,
0023         "end_offset_s": end, "gpu_release_time_offset_s": release,
0024         "runtime_s": end - start, "cpu_pre_runtime_s": submit - start,
0025         "cpu_post_runtime_s": end - gpu_end,
0026         "cpu_runtime_s": submit - start + end - gpu_end,
0027         "gpu_queue_delay_s": gpu_start - submit, "gpu_runtime_s": gpu_end - gpu_start,
0028         "gpu_wait_runtime_s": gpu_end - submit, "process_cpu_s": 0.1, "thread_cpu_s": 0.1,
0029         "cpu_post_locked_runtime_s": release - gpu_end,
0030         "cpu_post_unlocked_runtime_s": end - release, "gpu_gate_runtime_s": release - gpu_start,
0031         "primary_particle": "opticalphoton", "num_photons": 100,
0032         "worker_id": event_id % threads if threads > 1 else -1, "num_threads": threads,
0033     }
0034     return row
0035 
0036 
0037 class TimingCheckTest(unittest.TestCase):
0038     def invoke(self, rows, *, threads=2, recorder_enabled=False):
0039         with TemporaryDirectory() as directory:
0040             path = Path(directory) / "events.csv"
0041             with path.open("w", newline="") as stream:
0042                 writer = csv.DictWriter(stream, fieldnames=list(rows[0]))
0043                 writer.writeheader()
0044                 writer.writerows(rows)
0045             manifest = {
0046                 "schema_version": 2, "dispatch_mode": "synchronous" if threads > 1 else "blocking",
0047                 "event_count": len(rows), "num_threads": threads,
0048                 "primary_particle": "opticalphoton", "primary_multiplicity": 100,
0049                 "cpu_recorder_enabled": recorder_enabled, "torch_seed": 0,
0050             }
0051             path.with_suffix(".manifest.json").write_text(json.dumps(manifest))
0052             return subprocess.run(
0053                 [sys.executable, str(CHECKER), str(path), "--events", str(len(rows)),
0054                  "--threads", str(threads), "--expected-photons", "100", "--expect-no-cpu-recorder"],
0055                 capture_output=True, text=True, check=False,
0056             )
0057 
0058     def test_overlapping_cpu_intervals_and_serialized_gpu_gates_are_valid(self):
0059         result = self.invoke([
0060             event_row(0, 0, 0.3, 0.4, 0.6, 0.7, 0.8),
0061             event_row(1, 0.1, 0.5, 0.8, 1.0, 1.1, 1.2),
0062         ])
0063         self.assertEqual(result.returncode, 0, result.stderr)
0064 
0065     def test_gate_overlap_is_rejected_even_when_gpu_service_does_not_overlap(self):
0066         result = self.invoke([
0067             event_row(0, 0, 0.3, 0.4, 0.6, 0.7, 0.8),
0068             event_row(1, 0.1, 0.5, 0.65, 1.0, 1.1, 1.2),
0069         ])
0070         self.assertNotEqual(result.returncode, 0)
0071         self.assertIn("GPU dispatch gate overlaps", result.stderr)
0072 
0073     def test_incorrect_primary_photon_count_is_rejected(self):
0074         row = event_row(0, 0, 0.3, 0.4, 0.6, 0.7, 0.8)
0075         row["num_photons"] = 0
0076         result = self.invoke([row])
0077         self.assertNotEqual(result.returncode, 0)
0078         self.assertIn("expected 100 photons", result.stderr)
0079 
0080     def test_matched_serial_control_accepts_the_worker_free_schema(self):
0081         result = self.invoke([event_row(0, 0, 0.3, 0.4, 0.6, 0.7, 0.8, threads=1)], threads=1)
0082         self.assertEqual(result.returncode, 0, result.stderr)
0083 
0084     def test_mt_requires_every_gpu_gate_measurement(self):
0085         for missing in ('gpu_release_time_offset_s', 'cpu_post_locked_runtime_s',
0086                         'cpu_post_unlocked_runtime_s', 'gpu_gate_runtime_s'):
0087             row = event_row(0, 0, 0.3, 0.4, 0.6, 0.7, 0.8)
0088             del row[missing]
0089             with self.subTest(missing=missing):
0090                 result = self.invoke([row])
0091                 self.assertNotEqual(result.returncode, 0)
0092                 self.assertIn('Missing MT gate measurements', result.stderr)
0093 
0094     def test_legacy_serial_schema_keeps_optional_gate_columns(self):
0095         row = event_row(0, 0, 0.3, 0.4, 0.6, 0.7, 0.8, threads=1)
0096         for name in ('gpu_release_time_offset_s', 'cpu_post_locked_runtime_s',
0097                      'cpu_post_unlocked_runtime_s', 'gpu_gate_runtime_s'):
0098             del row[name]
0099         result = self.invoke([row], threads=1)
0100         self.assertEqual(result.returncode, 0, result.stderr)
0101 
0102     def test_core_durations_must_match_their_recorded_boundaries(self):
0103         for column in ('runtime_s', 'cpu_pre_runtime_s', 'cpu_post_runtime_s',
0104                        'cpu_runtime_s', 'gpu_runtime_s', 'gpu_queue_delay_s'):
0105             row = event_row(0, 0, 0.3, 0.4, 0.6, 0.7, 0.8)
0106             row[column] = 1000.0
0107             with self.subTest(column=column):
0108                 self.assertNotEqual(self.invoke([row]).returncode, 0)
0109 
0110     def test_cpu_recorder_mismatch_is_rejected(self):
0111         result = self.invoke([event_row(0, 0, 0.3, 0.4, 0.6, 0.7, 0.8)], recorder_enabled=True)
0112         self.assertNotEqual(result.returncode, 0)
0113         self.assertIn("CPU recorder", result.stderr)
0114 
0115 
0116 if __name__ == "__main__":
0117     unittest.main()