Native GPU fixed-step path (Phase B): OpenACC integration without runtime CoreNEURON - #3801
Native GPU fixed-step path (Phase B): OpenACC integration without runtime CoreNEURON#3801nrnhines wants to merge 51 commits into
Conversation
- Support both 'main' and 'master' as base branch - Only pass existing files to the formatter - Eliminates noisy "ERROR: X jobs failed" when files were deleted
…ep 1) Introduce user-facing NEURON native GPU build options as scaffolding for the GPU adoption plan. During Phase A, NRN_ENABLE_GPU still requires CoreNEURON; CORENRN_ENABLE_GPU remains required for actual GPU execution. - Add NRN_ENABLE_GPU (OFF default) and NRN_GPU_BACKEND=OpenACC - Extend NeuronTestHelper REQUIRES gpu to accept NRN_ENABLE_GPU - Document options in cmake_doc/options.rst and dev/gpu-testing.rst Implemented by Grok (AI assistant).
Align the typical GPU development build example with gpu_workstation.md: add CMAKE_CUDA_COMPILER, install prefix, and CMAKE_CUDA_ARCHITECTURES. Clarify that the arch flag is optional (CoreNEURON defaults to 70;80) but recommended for single-GPU dev machines. Implemented by Grok (AI assistant).
external_ringtest::coreneuron_gpu_mpi failed on some NVHPC builds when NEURON special was launched with -coreneuron -gpu under MPI (pgcudafat*.o: cannot open shared object file). - Run GPU MPI ringtest via special-core (dump with special, simulate with special-core --gpu); copy out.dat to spk2.std for group comparison - Set per-test TMPDIR under the build tree for all REQUIRES gpu ctests - Apply -cuda/OpenACC link flags to NEURON libnrnmech/special in neuronMechMaker when CORENRN_ENABLE_GPU (mirror corenrnmech treatment) - Document the ringtest ctest behavior in docs/dev/gpu-testing.rst Implemented by Grok (AI assistant).
Apply NVHPC OpenACC compile flags to cellorder sources in libnrniv, link coreneuron-cuda for the interleaved-solve CUDA launcher, and add compile-only cellorder_openacc_smoke CI guard. Guard NEURON builds of cellorder.cpp so corenrn_param and NrnThread GPU fields remain PR 5/7 work. Extend neuronMechMaker and test LD_LIBRARY_PATH for NVHPC/CUDA dynamic loading after libnrniv gains OpenACC fat objects. Implemented by Grok (AI assistant).
Fork CoreNEURON offload helpers into src/neuron/gpu/offload.hpp with neuron::gpu::target_* APIs and nrn_target_* macros. Add offload.cpp (debug logging via NRN_GPU_DEBUG, NVHPC present-table workaround) as neuron_gpu static library linked into libnrniv. Add standalone testneuron_gpu_offload unit test for copyin/deviceptr/delete round trip. Implemented by Grok (AI assistant).
Add neuron::gpu::device_token with refcounted ModelDeviceState tied to model_sorted_token lifetime, ensure_on_device() upload stub, and invalidate_device_state() on layout invalidation. Extend NrnThread with compute_gpu and stream_id for upcoming OpenACC clauses (PR 7). Implemented by Grok (AI assistant).
Wire create_nrnmech and the nrnivmodl CMake wrapper to default NMODL NEURON codegen when NRN_ENABLE_GPU=ON, reject forced NOCMODL on GPU builds, and document NMODL-vs-NOCMODL feature gaps. Shell nrnivmodl keeps NOCMODL during Phase A so existing GPU ctests remain green. Implemented by Grok (AI assistant).
Add neuron::gpu::config (enabled/use_cuda_launcher stubs), refactor cellorder matrix access to host-resolved raw pointers for OpenACC device-link compatibility, and keep CoreNEURON OpenACC/CUDA launcher paths unchanged. NEURON native OpenACC offload on libnrniv is deferred to PR 9 (SOA upload) to avoid NVHPC pgcudafat loader regressions with special. Implemented by Grok (AI assistant).
Add CodegenNeuronAccVisitor for native GPU mechanism codegen: OpenACC parallel loops and present clauses on nrn_init/nrn_state/nrn_cur entrypoints, wired via `nmodl --neuron acc --oacc`. Default NMODL_NEURON_EXTRA_ARGS on GPU builds appends acc --oacc. Prototype gate: hh.mod unit test checks nrn_pragma_acc emission. Implemented by Grok (AI assistant).
New GPU adoption sources follow the no-header style used in src/neuron/gpu/; ensure trailing newlines on codegen_neuron_acc_visitor files. Implemented by Grok (AI assistant).
Replace device_token upload stubs with real OpenACC copyin for sorted node and mechanism SOA vectors, plus CoreNEURON-style struct-then-patch upload for InterleaveInfo permute types 1 and 2. Compile upload.cpp as a dedicated neuron_gpu_upload object library linked into libnrniv and GPU unit tests. Implemented by Grok (AI assistant).
Add gpu.enable/gpu.backend runtime config with hoc helpers and share/lib/python/neuron/gpu.py. Dispatch nrn_fixed_step_thread to neuron::gpu::fixed_step_thread when native backend is active; fused lastpart for the no-gap case mirrors CoreNEURON fadvance_core layout. Unit test gpu_fadvance covers config gate and dispatch counter. Implemented by Grok (AI assistant).
Add neuron::gpu net_events wrappers for deliver_net_events, nrn_deliver_events, and native-gated spike_exchange_after_group. Wire deliver_net_events_host into fixed_step_thread and call spike_exchange_after_group from nrn_fixed_step_group. Unit tests gpu_net_events and gpu_fadvance cover wrappers and dispatch. Implemented by Grok (AI assistant).
Route post-step delivery through deliver_post_step_events_host when native GPU is active. Add backend_helper and G4 native ctests (pointer, psolve, spikes, watchrange, nmodlrandom) launched via special with NRN_GPU_BACKEND_TEST=native. Extend NeuronTestHelper TMPDIR guard for NRN_ENABLE_GPU; install share/lib/python/neuron/gpu.py. Implemented by Grok (AI assistant).
Add -gpu-native flag (tracked patch for external/tests/ringtest clone), external_ringtest::neuron_gpu_native_mpi ctest with TMPDIR wrapper, and docs for runtime/spike reporting and sortspike workflow. Implemented by Grok (AI assistant).
Port CoreNEURON init_gpu() policy to neuron::gpu::assign_device() (local_rank % num_gpus_per_node) with gpu.device_count runtime config. Add OpenACC device helpers, ParallelContext gpu_assign_device/gpu_device_id, unit tests, and a 2-rank MPI smoke test. Implemented by Grok (AI assistant).
Move runtime GPU config to ParallelContext methods (gpu_enable, gpu_backend, gpu_device_count) and expand neuron.gpu with device_count, permute, and context manager. Add coreneuron deprecation shims, extend _check_for_intel_openmp() for NRN_ENABLE_GPU builds, and document the configuration truth table. Implemented by Grok (AI assistant).
…er copies) - Compare neuron_gpu_native_mpi against spk2.std (MPI ringtest output). - Copy backend_helper.py into coreneuron_modtests and standalone psolve trees. Implemented by Grok (AI assistant).
Port CoreNEURON-style OpenACC loops for SoA rhs/d zeroing and axial current assembly in nrn_rhs/nrn_lhs, gated on NrnThread::compute_gpu. Compile treeset.cpp with NVHPC OpenACC flags via libnrniv. Implemented by Grok (AI assistant).
PR 11b: NetSendBuffer_t on Memb_list, hoc_register_net_send_buffering, codegen_neuron_acc net_send_buffering/delivery, flush after setup_tree_matrix. PR 16: sync_before/after_vecplay and gap voltage host sync; native fadvance_gpu runs MPI gap transfer + lastpart when partrans is active. Implemented by Grok (AI assistant).
Upload per-thread _v_parent_index in upload_sorted_model so OpenACC present(parent_i) in treeset.cpp succeeds on device. Apply node-order permute immediately via verify_structure() when gpu.enable triggers optimize_node_order after finitialize, fixing testcorenrn_*::coreneuron_gpu_online model_ready() errors. Add host/device matrix sync for the hybrid native GPU path: mechanisms run on host while axial setup uses OpenACC. Zero rhs/d on host, push mechanism updates to device before axial loops, pull back before nonvint blocks and host solve, then push voltages after update. Skip test_watchrange2 under CORENRN_ENABLE_GPU (cvode threading vs in-process GPU permute). ctest -R gpu: 80/82 pass (was 67/82). Remaining: test_pointer_py_gpu and test_pointer_py_gpu_native (fast_imem vs axial.im under GPU).
The hybrid native GPU step was corrupting host matrix state after setup_tree_matrix: a redundant device→host pull ran after nonvint had already updated vec_rhs/vec_d on the host, so the Hines solve and nrn_calc_fast_imem saw stale RHS data (im != i_membrane_). Also fix voltage sync ordering: stop clobbering host voltages with a pre-vecplay device→host pull, and push host voltages to the device after lastpart so the next step starts from consistent state. Matrix assembly/solve/fast_imem remain on the host in this hybrid path; OpenACC axial can be re-enabled once its device mirrors are validated. ctest -R gpu: 82/82 pass (including test_pointer_py_gpu and _native).
…path Re-enable OpenACC axial loops in setup_tree_matrix and GPU Hines solve with minimal per-step host traffic: - Push post-nonvint vec_rhs/vec_d to device before solve; pull only vec_rhs back afterward for host voltage update and fast_imem. - Upload NrnThread shells (parent index pointer patched) so solve_interleaved present(nt) works under NRN_ENABLE_GPU without CORENRN_BUILD. - Enable OpenACC solve branches in cellorder.cpp for NEURON native builds. - Fix lhs device sync clobbering rhs axial results: use diagonal-only vec_d/sav_d sync in nrn_lhs; add OpenACC waits after async axial loops. - Sync voltages to device immediately before rhs axial. Per-step host work remains mechanisms, nonvint, second_order_cur, and nrn_update_voltage/fast_imem (CVode still deferred). ctest -R gpu: 82/82 pass.
Move second-order ion correction, voltage increment, capacitance current, and fast_imem off the per-step vec_rhs host pull. The native GPU step now keeps the Hines solution on device and syncs only node voltages and fast_imem sav_rhs for HOC/VecPlay reads. Upload mechanism nodeindices so OpenACC post-solve kernels can index into the sorted matrix. Host fallbacks remain for sparse13, extracellular, and LFP hooks. ctest -R gpu: 82/82 pass.
Mirror CoreNEURON-style mechanism device setup for NEURON native OpenACC: copy Memb_list shells, patch nodeindices/_thread/pdata/net_send_buffer pointers, upload SoA-padded pdata rows, and refresh per-thread _ml_list arrays on the device. Add _nodecount_padded on Memb_list for GPU kernels. Mechanism currents still run on the host in this step; the upload removes partial-present OpenACC hazards for NMODL GPU codegen and net_send buffers. ctest -R gpu: 82/82 pass.
Introduce download_flush_interval (default 1, 0 = psolve end only) to defer host pulls of voltages and fast_imem sav_rhs during native GPU psolve. device_token::update_host/update_device now perform selective batch download/upload; Graph.flush triggers download for live plots. Hook finalize_psolve_download at fixed-step and step-group completion so HOC reads after psolve stay correct when interval is 0. ctest -R gpu: 82/82 pass.
Add 14 native GPU modtests mirroring single-process CoreNEURON _py_gpu coverage: fornetcon, direct, spikes variants, fast_imem, datareturn, units, netmove, pointer, watchrange, psolve, ba, nmodlrandom, natrans, and array_variable_transfer run modes. Route modtests through backend_helper for both native and CoreNEURON paths, copy the helper into all affected CTest working directories, and fix native-only issues (sys.path, set_maxstep, single-thread datareturn). Serialize ensure_on_device upload under the device-state mutex to prevent concurrent UploadState corruption when multiple NEURON threads first enter the GPU path (fixes test_natrans double-free).
…rok/feature/neuron-core-gpu-adoption Want to pass ci formatting when this becomes a pull request.
treeset.cpp: include neuron/gpu/offload.hpp unconditionally so nrn_pragma_acc macros are no-op stubs without GPU/OpenACC. nrnivmodl.in: prefix every line of GPU-only nocmodl guards (not just the if). gpu.py: skip _sync_to_hoc when HOC gpu_* methods are absent (non-GPU builds). test_fast_imem.py: import backend_helper only when backend tests will run; ship backend_helper.py with basic_tests SCRIPT_PATTERNS.
Remove unused sync_voltage_and_rhs_to_device helper, mark solve_interleaved2_loop_body as routine gang so inner loop vector directives are valid under the outer gang parallel region, and use the nodiscard ensure_on_device return value in the device_state test.
|
✔️ 35f0822 -> Azure artifacts URL |
|
✔️ 35f0822 -> artifacts URL |
…egen NMODL NEURON C++ codegen registers net_send/net_event mechanisms via hoc_register_net_send_buffering, but the symbol lived only in the GPU object library. Provide a CPU no-op stub and expose the declaration in mech_api.h/nrniv_mf.h so nrnivmodl-generated mechanisms compile when NRN_ENABLE_GPU=OFF.
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## master #3801 +/- ##
==========================================
- Coverage 68.45% 68.33% -0.12%
==========================================
Files 688 690 +2
Lines 111300 111514 +214
==========================================
+ Hits 76187 76207 +20
- Misses 35113 35307 +194 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
|
✔️ a34dc84 -> artifacts URL |
|
✔️ a34dc84 -> Azure artifacts URL |
Turn on the Phase B native GPU CMake options (OpenACC, CUDA arch 75) on the self-hosted NVHPC runner and run the focused CTest subset from docs/dev/gpu-testing.rst instead of the full suite.
|
✔️ fc81dcb -> Azure artifacts URL |
|
✔️ fc81dcb -> artifacts URL |
|
✔️ fc81dcb -> Azure artifacts URL |
routine gang inside a parallel loop gang is NVC++-S-1045. Revert the 35f0822 gang annotation to seq so cellorder.cpp compiles on NVHPC 25.9; inner loop vector directives remain inside the seq routine.
|
✔️ 4053d97 -> Azure artifacts URL |
|
✔️ 4053d97 -> artifacts URL |
Native GPU fixed-step integration diverges with the default
interleave_permute_type=0 (non-interleaved nrn_solve on device). HOC callers
that set pc.gpu_enable(1) and pc.gpu_backend("native") without
pc.optimize_node_order(2) therefore produced wrong spike rasters on large
models such as Traub 82894.
Mirror the Python gpu.enable path (which already applies permute 2) and
CoreNEURON's GPU guard: when gpu.enable and gpu.backend="native" are both
active, call nrn_optimize_node_order(2) if permute is not already 2.
Trigger from set_enable(true) and set_backend() so ordering of the two HOC
calls does not matter.
Add unit test with a stub nrn_optimize_node_order verifying permute 0 and 1
are upgraded to 2.
Gap/partrans models register nrnthread_vi_compute_, forcing host post-solve. The hybrid GPU solve plus device→host sync_gap_after_voltage_update was pulling stale device voltages over the host nrn_update_voltage result (0 spikes on nrntraub with use_gap=1). Add sync_gap_after_host_voltage_update to push host voltages to device when post-solve ran on the host. Full hybrid stepping still diverged on Traub; until device gap gather/scatter is complete, dispatch the CPU fixed-step body when nrnthread_v_transfer_ is registered so native GPU enable_gpu models with gaps match CPU rasters. Add test/gjtests/test_par_gj_native_gpu.py comparing ggap voltages CPU vs native GPU.
Phase B docs previously described a hybrid GPU solve with host partrans gather/scatter. When nrnthread_v_transfer_ is registered, fadvance.cpp dispatches the full CPU fixed-step body instead of fadvance_gpu.cpp. Update the Sphinx scope contract, design journal, limitations, future work, test parity notes, and Phase B checklist to match.
|
|
✔️ 9874a5b -> artifacts URL |
|
✔️ 9874a5b -> Azure artifacts URL |



Summary
Introduces NEURON's native GPU backend (
gpu.backend="native") for fixed-steppc.psolve/h.fadvanceusing NVHPC + OpenACC. Models can run on the GPUwithout enabling CoreNEURON at runtime (
coreneuron.enable=False).Phase B delivers CoreNEURON-parity integration for single-process modtests while
keeping cross-rank spike scheduling on the CPU (same split CoreNEURON uses).