diff --git a/CHANGELOG.md b/CHANGELOG.md index 57efa08..2aa7b0a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,20 @@ All notable changes to `makewfs` are documented here. ## [Unreleased] +### Fixed + +- **Benchmark artifacts named the wrong GPU on multi-GPU hosts.** + `benchmarks/run.py` recorded the first line of `nvidia-smi`, which ignores + `CUDA_VISIBLE_DEVICES`. It now asks CuPy for the device the run used. On + Arm hosts, whose `/proc/cpuinfo` has no model name, it reads the CPU model + from `lscpu` (e.g. `Neoverse-N1`) instead of reporting `aarch64`. + +### Added + +- **Arm benchmark data point** (`benchmarks/device-results-neoverse-n1.*`): the + device table on an Ampere Neoverse-N1 host (16 pinned cores) with an RTX + 4060 and an RTX A400. + ## [2.0.0] - 2026-10-07 ### Breaking diff --git a/benchmarks/device-results-neoverse-n1-rtx4060.json b/benchmarks/device-results-neoverse-n1-rtx4060.json new file mode 100644 index 0000000..724322b --- /dev/null +++ b/benchmarks/device-results-neoverse-n1-rtx4060.json @@ -0,0 +1,357 @@ +{ + "schema_version": 2, + "generated_at_utc": "2026-10-07T07:11:47.632479+00:00", + "command": "/home/jtaylor/miniforge3/envs/aosim-bench/bin/python benchmarks/run.py --device both --frames 100 --config benchmarks/configs/pyramid_40_float32.toml --config benchmarks/configs/pyramid_60_mod8_float32.toml --config benchmarks/configs/pyramid_80_mod32_float64.toml --config benchmarks/configs/shack_hartmann_20x20_float32.toml --config benchmarks/configs/shack_hartmann_60x60_float64.toml --config benchmarks/configs/shack_hartmann_quadrature_9sample.toml --output /home/jtaylor/aosim-bench-logs/artifacts/makewfs-device-table-rtx4060.json", + "revision": "74b53697569dc8b2b5ce93f0b66e39a1de3b303d", + "source_dirty": true, + "python": "3.13.15 | packaged by conda-forge | (main, Sep 2 2026, 22:02:03) [GCC 15.3.0]", + "platform": "Linux-6.17.9-76061709-generic-aarch64-with-glibc2.39", + "processor": "aarch64", + "cpu": "Neoverse-N1", + "gpu": "NVIDIA GeForce RTX 4060", + "dependencies": { + "makewfs": "2.0.0", + "numpy": "2.5.3", + "scipy": "1.18.1", + "cupy": "14.2.0", + "getframes": "2.4.0", + "pyturb": "2.2.0" + }, + "methodology": { + "frames_per_cell": 100, + "persistent_sensor": true, + "warmup_frames": 1, + "device_resident_opd_rate_and_output": true, + "include_detector_truth": true, + "rng": "a distinct deterministic per-frame seed", + "cuda_synchronization": "before and after each timed region", + "construction_included_in_throughput": false, + "host_transfers_included": false + }, + "results": [ + { + "config": "benchmarks/configs/pyramid_40_float32.toml", + "sensor": "pyramid", + "device": "cpu", + "shape": [ + 54, + 54 + ], + "source_states": 1, + "wavelength_samples": 1, + "range_samples": 1, + "modulation_samples": 1, + "modulation_radius_lambda_over_d": 0.0, + "dtype": "float32", + "fft_workers": 1, + "frames": 100, + "construction_s": 0.7629785779863596, + "warm_optical_total_s": 0.06306239901459776, + "warm_optical_frame_s": 0.0006306239901459775, + "warm_detector_total_s": 0.10588375400402583, + "warm_detector_frame_s": 0.0010588375400402584, + "warm_optical_frames_per_s": 1585.7309833210102, + "warm_detector_frames_per_s": 944.4319474751327, + "warm_detector_only_frame_s": 0.00022277187992585822, + "warm_detector_only_frames_per_s": 4488.896894584786, + "python_peak_memory_mib": null + }, + { + "config": "benchmarks/configs/pyramid_40_float32.toml", + "sensor": "pyramid", + "device": "gpu", + "shape": [ + 54, + 54 + ], + "source_states": 1, + "wavelength_samples": 1, + "range_samples": 1, + "modulation_samples": 1, + "modulation_radius_lambda_over_d": 0.0, + "dtype": "float32", + "fft_workers": 1, + "frames": 100, + "construction_s": 0.2768877709750086, + "warm_optical_total_s": 0.13808018100098707, + "warm_optical_frame_s": 0.0013808018100098707, + "warm_detector_total_s": 0.24444962001871318, + "warm_detector_frame_s": 0.0024444962001871316, + "warm_optical_frames_per_s": 724.2168953941706, + "warm_detector_frames_per_s": 409.08224767273015, + "warm_detector_only_frame_s": 0.0006185778399230912, + "warm_detector_only_frames_per_s": 1616.6114197112713, + "python_peak_memory_mib": null + }, + { + "config": "benchmarks/configs/pyramid_60_mod8_float32.toml", + "sensor": "pyramid", + "device": "cpu", + "shape": [ + 80, + 80 + ], + "source_states": 1, + "wavelength_samples": 1, + "range_samples": 1, + "modulation_samples": 8, + "modulation_radius_lambda_over_d": 2.0, + "dtype": "float32", + "fft_workers": 1, + "frames": 100, + "construction_s": 0.07376596701215021, + "warm_optical_total_s": 0.5042883460118901, + "warm_optical_frame_s": 0.005042883460118901, + "warm_detector_total_s": 0.5606069839850534, + "warm_detector_frame_s": 0.005606069839850534, + "warm_optical_frames_per_s": 198.29924841777367, + "warm_detector_frames_per_s": 178.37808457032378, + "warm_detector_only_frame_s": 0.00035893032007152216, + "warm_detector_only_frames_per_s": 2786.056078518904, + "python_peak_memory_mib": null + }, + { + "config": "benchmarks/configs/pyramid_60_mod8_float32.toml", + "sensor": "pyramid", + "device": "gpu", + "shape": [ + 80, + 80 + ], + "source_states": 1, + "wavelength_samples": 1, + "range_samples": 1, + "modulation_samples": 8, + "modulation_radius_lambda_over_d": 2.0, + "dtype": "float32", + "fft_workers": 1, + "frames": 100, + "construction_s": 0.012662593013374135, + "warm_optical_total_s": 0.1342540149926208, + "warm_optical_frame_s": 0.0013425401499262079, + "warm_detector_total_s": 0.2391750770038925, + "warm_detector_frame_s": 0.002391750770038925, + "warm_optical_frames_per_s": 744.8566808634844, + "warm_detector_frames_per_s": 418.10376420772525, + "warm_detector_only_frame_s": 0.0006130585700157099, + "warm_detector_only_frames_per_s": 1631.1655181239448, + "python_peak_memory_mib": null + }, + { + "config": "benchmarks/configs/pyramid_80_mod32_float64.toml", + "sensor": "pyramid", + "device": "cpu", + "shape": [ + 108, + 108 + ], + "source_states": 1, + "wavelength_samples": 1, + "range_samples": 1, + "modulation_samples": 32, + "modulation_radius_lambda_over_d": 3.0, + "dtype": "float64", + "fft_workers": 1, + "frames": 100, + "construction_s": 0.08048216797760688, + "warm_optical_total_s": 8.533555491012521, + "warm_optical_frame_s": 0.0853355549101252, + "warm_detector_total_s": 8.6366516520211, + "warm_detector_frame_s": 0.086366516520211, + "warm_optical_frames_per_s": 11.718444920797582, + "warm_detector_frames_per_s": 11.578561232882254, + "warm_detector_only_frame_s": 0.0006370968700502999, + "warm_detector_only_frames_per_s": 1569.620017001572, + "python_peak_memory_mib": null + }, + { + "config": "benchmarks/configs/pyramid_80_mod32_float64.toml", + "sensor": "pyramid", + "device": "gpu", + "shape": [ + 108, + 108 + ], + "source_states": 1, + "wavelength_samples": 1, + "range_samples": 1, + "modulation_samples": 32, + "modulation_radius_lambda_over_d": 3.0, + "dtype": "float64", + "fft_workers": 1, + "frames": 100, + "construction_s": 0.025755188980838284, + "warm_optical_total_s": 0.4056679999921471, + "warm_optical_frame_s": 0.004056679999921471, + "warm_detector_total_s": 0.4848081910167821, + "warm_detector_frame_s": 0.004848081910167821, + "warm_optical_frames_per_s": 246.50699587331462, + "warm_detector_frames_per_s": 206.26714204285878, + "warm_detector_only_frame_s": 0.0005712536702048964, + "warm_detector_only_frames_per_s": 1750.5357989933289, + "python_peak_memory_mib": null + }, + { + "config": "benchmarks/configs/shack_hartmann_20x20_float32.toml", + "sensor": "shack_hartmann", + "device": "cpu", + "shape": [ + 160, + 160 + ], + "source_states": 1, + "wavelength_samples": 1, + "range_samples": 1, + "modulation_samples": 1, + "modulation_radius_lambda_over_d": 0.0, + "dtype": "float32", + "fft_workers": 1, + "frames": 100, + "construction_s": 0.08199134599999525, + "warm_optical_total_s": 2.28855264998856, + "warm_optical_frame_s": 0.0228855264998856, + "warm_detector_total_s": 2.4490860599908046, + "warm_detector_frame_s": 0.024490860599908047, + "warm_optical_frames_per_s": 43.695739313884644, + "warm_detector_frames_per_s": 40.831558201909594, + "warm_detector_only_frame_s": 0.0010764133499469608, + "warm_detector_only_frames_per_s": 929.0111461821558, + "python_peak_memory_mib": null + }, + { + "config": "benchmarks/configs/shack_hartmann_20x20_float32.toml", + "sensor": "shack_hartmann", + "device": "gpu", + "shape": [ + 160, + 160 + ], + "source_states": 1, + "wavelength_samples": 1, + "range_samples": 1, + "modulation_samples": 1, + "modulation_radius_lambda_over_d": 0.0, + "dtype": "float32", + "fft_workers": 1, + "frames": 100, + "construction_s": 0.01180534201557748, + "warm_optical_total_s": 0.08716972899856046, + "warm_optical_frame_s": 0.0008716972899856046, + "warm_detector_total_s": 0.19479694298934191, + "warm_detector_frame_s": 0.0019479694298934192, + "warm_optical_frames_per_s": 1147.187230576929, + "warm_detector_frames_per_s": 513.3550787060933, + "warm_detector_only_frame_s": 0.0006126053698244505, + "warm_detector_only_frames_per_s": 1632.372240365053, + "python_peak_memory_mib": null + }, + { + "config": "benchmarks/configs/shack_hartmann_60x60_float64.toml", + "sensor": "shack_hartmann", + "device": "cpu", + "shape": [ + 360, + 360 + ], + "source_states": 1, + "wavelength_samples": 1, + "range_samples": 1, + "modulation_samples": 1, + "modulation_radius_lambda_over_d": 0.0, + "dtype": "float64", + "fft_workers": 1, + "frames": 100, + "construction_s": 0.08440429499023594, + "warm_optical_total_s": 8.684691948990803, + "warm_optical_frame_s": 0.08684691948990803, + "warm_detector_total_s": 9.488772381999297, + "warm_detector_frame_s": 0.09488772381999297, + "warm_optical_frames_per_s": 11.514513190260066, + "warm_detector_frames_per_s": 10.538771083781636, + "warm_detector_only_frame_s": 0.005910381099965889, + "warm_detector_only_frames_per_s": 169.19382745146018, + "python_peak_memory_mib": null + }, + { + "config": "benchmarks/configs/shack_hartmann_60x60_float64.toml", + "sensor": "shack_hartmann", + "device": "gpu", + "shape": [ + 360, + 360 + ], + "source_states": 1, + "wavelength_samples": 1, + "range_samples": 1, + "modulation_samples": 1, + "modulation_radius_lambda_over_d": 0.0, + "dtype": "float64", + "fft_workers": 1, + "frames": 100, + "construction_s": 0.026143675000639632, + "warm_optical_total_s": 0.4227883660059888, + "warm_optical_frame_s": 0.004227883660059888, + "warm_detector_total_s": 0.4985939179896377, + "warm_detector_frame_s": 0.004985939179896377, + "warm_optical_frames_per_s": 236.52495678791573, + "warm_detector_frames_per_s": 200.5640189178527, + "warm_detector_only_frame_s": 0.0005747833198984153, + "warm_detector_only_frames_per_s": 1739.7860469867767, + "python_peak_memory_mib": null + }, + { + "config": "benchmarks/configs/shack_hartmann_quadrature_9sample.toml", + "sensor": "shack_hartmann", + "device": "cpu", + "shape": [ + 64, + 64 + ], + "source_states": 9, + "wavelength_samples": 3, + "range_samples": 3, + "modulation_samples": 1, + "modulation_radius_lambda_over_d": 0.0, + "dtype": "float32", + "fft_workers": 1, + "frames": 100, + "construction_s": 0.06993808099650778, + "warm_optical_total_s": 1.8203168570180424, + "warm_optical_frame_s": 0.018203168570180422, + "warm_detector_total_s": 1.8593171660031658, + "warm_detector_frame_s": 0.018593171660031656, + "warm_optical_frames_per_s": 54.93549082647914, + "warm_detector_frames_per_s": 53.78318547715153, + "warm_detector_only_frame_s": 0.00024450053984764964, + "warm_detector_only_frames_per_s": 4089.9705195870265, + "python_peak_memory_mib": null + }, + { + "config": "benchmarks/configs/shack_hartmann_quadrature_9sample.toml", + "sensor": "shack_hartmann", + "device": "gpu", + "shape": [ + 64, + 64 + ], + "source_states": 9, + "wavelength_samples": 3, + "range_samples": 3, + "modulation_samples": 1, + "modulation_radius_lambda_over_d": 0.0, + "dtype": "float32", + "fft_workers": 1, + "frames": 100, + "construction_s": 0.014552935026586056, + "warm_optical_total_s": 0.4028777669882402, + "warm_optical_frame_s": 0.004028777669882402, + "warm_detector_total_s": 0.5134580160083715, + "warm_detector_frame_s": 0.005134580160083715, + "warm_optical_frames_per_s": 248.2142431128967, + "warm_detector_frames_per_s": 194.75789038683465, + "warm_detector_only_frame_s": 0.0006140789898927323, + "warm_detector_only_frames_per_s": 1628.4549975804912, + "python_peak_memory_mib": null + } + ] +} diff --git a/benchmarks/device-results-neoverse-n1-rtxa400.json b/benchmarks/device-results-neoverse-n1-rtxa400.json new file mode 100644 index 0000000..5895f11 --- /dev/null +++ b/benchmarks/device-results-neoverse-n1-rtxa400.json @@ -0,0 +1,195 @@ +{ + "schema_version": 2, + "generated_at_utc": "2026-10-07T07:12:40.744797+00:00", + "command": "/home/jtaylor/miniforge3/envs/aosim-bench/bin/python benchmarks/run.py --device gpu --frames 100 --config benchmarks/configs/pyramid_40_float32.toml --config benchmarks/configs/pyramid_60_mod8_float32.toml --config benchmarks/configs/pyramid_80_mod32_float64.toml --config benchmarks/configs/shack_hartmann_20x20_float32.toml --config benchmarks/configs/shack_hartmann_60x60_float64.toml --config benchmarks/configs/shack_hartmann_quadrature_9sample.toml --output /home/jtaylor/aosim-bench-logs/artifacts/makewfs-device-table-rtxa400.json", + "revision": "74b53697569dc8b2b5ce93f0b66e39a1de3b303d", + "source_dirty": true, + "python": "3.13.15 | packaged by conda-forge | (main, Sep 2 2026, 22:02:03) [GCC 15.3.0]", + "platform": "Linux-6.17.9-76061709-generic-aarch64-with-glibc2.39", + "processor": "aarch64", + "cpu": "Neoverse-N1", + "gpu": "NVIDIA RTX A400", + "dependencies": { + "makewfs": "2.0.0", + "numpy": "2.5.3", + "scipy": "1.18.1", + "cupy": "14.2.0", + "getframes": "2.4.0", + "pyturb": "2.2.0" + }, + "methodology": { + "frames_per_cell": 100, + "persistent_sensor": true, + "warmup_frames": 1, + "device_resident_opd_rate_and_output": true, + "include_detector_truth": true, + "rng": "a distinct deterministic per-frame seed", + "cuda_synchronization": "before and after each timed region", + "construction_included_in_throughput": false, + "host_transfers_included": false + }, + "results": [ + { + "config": "benchmarks/configs/pyramid_40_float32.toml", + "sensor": "pyramid", + "device": "gpu", + "shape": [ + 54, + 54 + ], + "source_states": 1, + "wavelength_samples": 1, + "range_samples": 1, + "modulation_samples": 1, + "modulation_radius_lambda_over_d": 0.0, + "dtype": "float32", + "fft_workers": 1, + "frames": 100, + "construction_s": 0.9536263119953219, + "warm_optical_total_s": 0.14101205600309186, + "warm_optical_frame_s": 0.0014101205600309185, + "warm_detector_total_s": 0.27209407300688326, + "warm_detector_frame_s": 0.0027209407300688325, + "warm_optical_frames_per_s": 709.1592225122041, + "warm_detector_frames_per_s": 367.51994960753984, + "warm_detector_only_frame_s": 0.0008577363099902868, + "warm_detector_only_frames_per_s": 1165.8594702739401, + "python_peak_memory_mib": null + }, + { + "config": "benchmarks/configs/pyramid_60_mod8_float32.toml", + "sensor": "pyramid", + "device": "gpu", + "shape": [ + 80, + 80 + ], + "source_states": 1, + "wavelength_samples": 1, + "range_samples": 1, + "modulation_samples": 8, + "modulation_radius_lambda_over_d": 2.0, + "dtype": "float32", + "fft_workers": 1, + "frames": 100, + "construction_s": 0.01990843898965977, + "warm_optical_total_s": 0.13706612898386084, + "warm_optical_frame_s": 0.0013706612898386084, + "warm_detector_total_s": 0.26515891001326963, + "warm_detector_frame_s": 0.002651589100132696, + "warm_optical_frames_per_s": 729.5748463996873, + "warm_detector_frames_per_s": 377.13233922629865, + "warm_detector_only_frame_s": 0.0008346676401561126, + "warm_detector_only_frames_per_s": 1198.0816697445757, + "python_peak_memory_mib": null + }, + { + "config": "benchmarks/configs/pyramid_80_mod32_float64.toml", + "sensor": "pyramid", + "device": "gpu", + "shape": [ + 108, + 108 + ], + "source_states": 1, + "wavelength_samples": 1, + "range_samples": 1, + "modulation_samples": 32, + "modulation_radius_lambda_over_d": 3.0, + "dtype": "float64", + "fft_workers": 1, + "frames": 100, + "construction_s": 0.021844303002581, + "warm_optical_total_s": 1.8748067129927222, + "warm_optical_frame_s": 0.018748067129927222, + "warm_detector_total_s": 1.9770771820039954, + "warm_detector_frame_s": 0.019770771820039956, + "warm_optical_frames_per_s": 53.33883184169513, + "warm_detector_frames_per_s": 50.57971479830569, + "warm_detector_only_frame_s": 0.0007919555300031788, + "warm_detector_only_frames_per_s": 1262.6971617913773, + "python_peak_memory_mib": null + }, + { + "config": "benchmarks/configs/shack_hartmann_20x20_float32.toml", + "sensor": "shack_hartmann", + "device": "gpu", + "shape": [ + 160, + 160 + ], + "source_states": 1, + "wavelength_samples": 1, + "range_samples": 1, + "modulation_samples": 1, + "modulation_radius_lambda_over_d": 0.0, + "dtype": "float32", + "fft_workers": 1, + "frames": 100, + "construction_s": 0.018399502005195245, + "warm_optical_total_s": 0.2936565720010549, + "warm_optical_frame_s": 0.002936565720010549, + "warm_detector_total_s": 0.4119800759945065, + "warm_detector_frame_s": 0.004119800759945065, + "warm_optical_frames_per_s": 340.5338396432714, + "warm_detector_frames_per_s": 242.73018484838923, + "warm_detector_only_frame_s": 0.0008351940498687327, + "warm_detector_only_frames_per_s": 1197.3265376557338, + "python_peak_memory_mib": null + }, + { + "config": "benchmarks/configs/shack_hartmann_60x60_float64.toml", + "sensor": "shack_hartmann", + "device": "gpu", + "shape": [ + 360, + 360 + ], + "source_states": 1, + "wavelength_samples": 1, + "range_samples": 1, + "modulation_samples": 1, + "modulation_radius_lambda_over_d": 0.0, + "dtype": "float64", + "fft_workers": 1, + "frames": 100, + "construction_s": 0.017202607006765902, + "warm_optical_total_s": 1.8228039660025388, + "warm_optical_frame_s": 0.018228039660025386, + "warm_detector_total_s": 1.9881045959773473, + "warm_detector_frame_s": 0.019881045959773472, + "warm_optical_frames_per_s": 54.86053457481929, + "warm_detector_frames_per_s": 50.299164441516844, + "warm_detector_only_frame_s": 0.001127400370023679, + "warm_detector_only_frames_per_s": 886.9963382919564, + "python_peak_memory_mib": null + }, + { + "config": "benchmarks/configs/shack_hartmann_quadrature_9sample.toml", + "sensor": "shack_hartmann", + "device": "gpu", + "shape": [ + 64, + 64 + ], + "source_states": 9, + "wavelength_samples": 3, + "range_samples": 3, + "modulation_samples": 1, + "modulation_radius_lambda_over_d": 0.0, + "dtype": "float32", + "fft_workers": 1, + "frames": 100, + "construction_s": 0.02198778497404419, + "warm_optical_total_s": 0.41723625900340267, + "warm_optical_frame_s": 0.004172362590034027, + "warm_detector_total_s": 0.5441325049905572, + "warm_detector_frame_s": 0.005441325049905572, + "warm_optical_frames_per_s": 239.672362701307, + "warm_detector_frames_per_s": 183.77876543459828, + "warm_detector_only_frame_s": 0.0008288715701200999, + "warm_detector_only_frames_per_s": 1206.459524067286, + "python_peak_memory_mib": null + } + ] +} diff --git a/benchmarks/device-results-neoverse-n1.md b/benchmarks/device-results-neoverse-n1.md new file mode 100644 index 0000000..9b47e33 --- /dev/null +++ b/benchmarks/device-results-neoverse-n1.md @@ -0,0 +1,40 @@ +# CPU/GPU end-to-end WFS throughput on an Arm host + +Frames/s, higher is better (warm detector frames: optics plus detector). +These come from `benchmarks/device-results-neoverse-n1-rtx4060.json` and +`benchmarks/device-results-neoverse-n1-rtxa400.json`. They use the same +method and configurations as [device-results.md](device-results.md), whose +x86 + RTX 5090 numbers are repeated here for reference. + +- Host: cfl-test-bench, an 80-core Ampere Neoverse-N1 (aarch64), shared. + Every run was pinned to 16 cores (`taskset -c 16-31`) with 16 BLAS + threads, so CPU rows can vary with the frequency governor. +- GPUs: NVIDIA GeForce RTX 4060 (8 GB) and NVIDIA RTX A400 (4 GB), driver 580. +- Dependencies: makewfs 2.0.0, NumPy 2.5.3, SciPy 1.18.1, CuPy 14.2.0, + getframes 2.4.0, pyturb 2.2.0. +- Method: one persistent sensor, warm device-resident OPD and output, + detector truth enabled, a distinct seed per frame, construction and host + transfers excluded, CUDA synchronized. + +| Configuration | Output | Neoverse-N1 CPU (16 cores) | RTX A400 | RTX 4060 | Ryzen 9 9950X3D CPU | RTX 5090 | +| --- | ---: | ---: | ---: | ---: | ---: | ---: | +| pyramid_40_float32.toml | 54x54 | 944.4 | 367.5 | 409.1 | 3,526.4 | 1,604.7 | +| pyramid_60_mod8_float32.toml | 80x80 | 178.4 | 377.1 | 418.1 | 659.0 | 1,645.9 | +| pyramid_80_mod32_float64.toml | 108x108 | 11.6 | 50.6 | 206.3 | 24.3 | 923.6 | +| shack_hartmann_20x20_float32.toml | 160x160 | 40.8 | 242.7 | 513.4 | 126.5 | 2,041.8 | +| shack_hartmann_60x60_float64.toml | 360x360 | 10.5 | 50.3 | 200.6 | 17.9 | 899.3 | +| shack_hartmann_quadrature_9sample.toml | 64x64 | 53.8 | 183.8 | 194.8 | 186.0 | 780.4 | + +Reading this: + +- **The GPU pays off for every configuration except the smallest pyramid.** + `pyramid_40` runs about 2x faster on the CPU, because at that size each + frame is a few kernel launches. +- **The cards separate on the big, double-precision configurations.** On + `shack_hartmann_60x60_float64` and `pyramid_80_mod32_float64`, the RTX 4060 + runs about 4x the RTX A400. On the small ones they are within about 10%, + because both are launch-bound there. +- **16 Neoverse-N1 cores reach 0.27–0.59x a 16-core Ryzen 9 9950X3D** on + these sensors, typically about 0.3x. The gap is smallest on the large + double-precision configurations. The Ryzen numbers were measured with + makewfs 1.0. diff --git a/benchmarks/run.py b/benchmarks/run.py index c8d26dd..3c74451 100644 --- a/benchmarks/run.py +++ b/benchmarks/run.py @@ -135,17 +135,20 @@ def _git_state(root: Path) -> tuple[str | None, bool | None]: def _gpu_name() -> str | None: - """Return the first NVIDIA device name without requiring CUDA on CPU hosts.""" + """Return the name of the CUDA device the benchmark runs on. + + Asks CuPy for the current device, which honours ``CUDA_VISIBLE_DEVICES``. + ``nvidia-smi`` lists every card in its own order, so on a multi-GPU host + its first line can name a card the benchmark never used. + """ try: - output = subprocess.run( - ["nvidia-smi", "--query-gpu=name", "--format=csv,noheader"], - check=True, - capture_output=True, - text=True, - ).stdout - except (OSError, subprocess.CalledProcessError): + import cupy + + device = cupy.cuda.runtime.getDevice() + name = cupy.cuda.runtime.getDeviceProperties(device)["name"] + except Exception: return None - return output.splitlines()[0].strip() if output.splitlines() else None + return name.decode() if isinstance(name, bytes) else str(name) def _cpu_model() -> str: @@ -156,6 +159,15 @@ def _cpu_model() -> str: return line.split(":", 1)[1].strip() except OSError: pass + # Arm /proc/cpuinfo has no "model name"; lscpu decodes the part number + # (e.g. "Neoverse-N1"). + try: + output = subprocess.run(["lscpu"], check=True, capture_output=True, text=True).stdout + except (OSError, subprocess.CalledProcessError): + output = "" + for line in output.splitlines(): + if line.startswith("Model name:"): + return line.split(":", 1)[1].strip() return platform.processor() or "unknown CPU" diff --git a/docs/performance.md b/docs/performance.md index bef45b7..27bf56a 100644 --- a/docs/performance.md +++ b/docs/performance.md @@ -154,6 +154,12 @@ record exact configuration paths, command, revision, dirty-checkout flag, environment, timings, and detector-only rates. The checked-in snapshot records a specific local environment and is not a cross-hardware performance guarantee. +A second data point, on an Arm host (Ampere Neoverse-N1, 16 pinned cores) with +an RTX 4060 and an RTX A400, is in +[device-results-neoverse-n1.md](https://github.com/jacotay7/makewfs/blob/main/benchmarks/device-results-neoverse-n1.md). +On the large double-precision configurations the RTX 4060 runs about 4x the +RTX A400; on the small ones both cards are launch-bound and within about 10%. + The repository benchmark runner separates cold construction, warm optical frames, end-to-end frames, and detector-only frames: