Skip to content

Commit 8fe0e92

Browse files
Groknrnhines
authored andcommitted
Require cell permute type 2 when native GPU is enabled
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.
1 parent 4053d97 commit 8fe0e92

3 files changed

Lines changed: 69 additions & 0 deletions

File tree

src/neuron/gpu/config.cpp

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
#include "neuron/gpu/config.hpp"
22

3+
#include "node_order_optim/node_order_optim.h"
4+
35
#include <algorithm>
46
#include <cctype>
57
#include <cstdio>
@@ -59,9 +61,32 @@ Backend backend() noexcept {
5961
return config().backend;
6062
}
6163

64+
void ensure_native_gpu_cell_permute() noexcept {
65+
#if defined(NRN_ENABLE_GPU)
66+
if (!enabled() || !backend_native()) {
67+
return;
68+
}
69+
if (neuron::interleave_permute_type == 2) {
70+
return;
71+
}
72+
int const previous = neuron::interleave_permute_type;
73+
neuron::nrn_optimize_node_order(2);
74+
if (previous != 2) {
75+
fprintf(stderr,
76+
"neuron::gpu: native GPU requires cell permute type 2 "
77+
"(interleave_permute_type was %d); using permute 2\n",
78+
previous);
79+
}
80+
#else
81+
#endif
82+
}
83+
6284
void set_enable(bool value) noexcept {
6385
#if defined(NRN_ENABLE_GPU)
6486
config().enable = value;
87+
if (value) {
88+
ensure_native_gpu_cell_permute();
89+
}
6590
#else
6691
(void) value;
6792
#endif
@@ -70,6 +95,7 @@ void set_enable(bool value) noexcept {
7095
void set_backend(std::string_view name) {
7196
#if defined(NRN_ENABLE_GPU)
7297
config().backend = parse_backend(name);
98+
ensure_native_gpu_cell_permute();
7399
#else
74100
(void) name;
75101
#endif

src/neuron/gpu/config.hpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,13 @@ bool use_cuda_launcher() noexcept;
4545
/** One-time stderr notice when native GPU runs with pc.nthread() > 1. */
4646
void warn_native_gpu_multithread_policy() noexcept;
4747

48+
/**
49+
* Native GPU fixed-step requires interleaved Hines solve (permute type 2).
50+
* Called when gpu.enable and gpu.backend="native" are both active; sets
51+
* interleave_permute_type to 2 if it is not already.
52+
*/
53+
void ensure_native_gpu_cell_permute() noexcept;
54+
4855
namespace detail {
4956
void reset_config_for_testing();
5057
void set_enable_for_testing(bool value);

test/unit_tests/gpu/config.cpp

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,15 @@
22

33
#include "neuron/gpu/config.hpp"
44

5+
namespace neuron {
6+
int interleave_permute_type = 0;
7+
8+
int nrn_optimize_node_order(int type) {
9+
interleave_permute_type = type;
10+
return type;
11+
}
12+
} // namespace neuron
13+
514
TEST_CASE("gpu config defaults", "[gpu][config]") {
615
#if !defined(NRN_ENABLE_GPU)
716
SKIP("NRN_ENABLE_GPU required");
@@ -14,3 +23,30 @@ TEST_CASE("gpu config defaults", "[gpu][config]") {
1423
CHECK(neuron::gpu::device_count() == 0);
1524
#endif
1625
}
26+
27+
TEST_CASE("native GPU requires cell permute type 2", "[gpu][config]") {
28+
#if !defined(NRN_ENABLE_GPU)
29+
SKIP("NRN_ENABLE_GPU required");
30+
#else
31+
neuron::gpu::detail::reset_config_for_testing();
32+
neuron::interleave_permute_type = 0;
33+
34+
neuron::gpu::set_backend("native");
35+
CHECK(neuron::interleave_permute_type == 0);
36+
37+
neuron::gpu::set_enable(true);
38+
CHECK(neuron::interleave_permute_type == 2);
39+
40+
neuron::gpu::detail::reset_config_for_testing();
41+
neuron::interleave_permute_type = 1;
42+
neuron::gpu::set_enable(true);
43+
neuron::gpu::set_backend("native");
44+
CHECK(neuron::interleave_permute_type == 2);
45+
46+
neuron::gpu::detail::reset_config_for_testing();
47+
neuron::interleave_permute_type = 2;
48+
neuron::gpu::set_enable(true);
49+
neuron::gpu::set_backend("native");
50+
CHECK(neuron::interleave_permute_type == 2);
51+
#endif
52+
}

0 commit comments

Comments
 (0)