NEURON
multicore.cpp
Go to the documentation of this file.
1 /*
2 # =============================================================================
3 # Copyright (c) 2016 - 2021 Blue Brain Project/EPFL
4 #
5 # See top-level LICENSE file for details.
6 # =============================================================================.
7 */
8 
9 #include <cstdlib>
10 #include <vector>
11 
12 #include "coreneuron/nrnconf.h"
17 
18 /*
19 Now that threads have taken over the actual_v, v_node, etc, it might
20 be a good time to regularize the method of freeing, allocating, and
21 updating those arrays. To recapitulate the history, Node used to
22 be the structure that held direct values for v, area, d, rhs, etc.
23 That continued to hold for the cray vectorization project which
24 introduced v_node, v_parent, memb_list. Cache efficiency introduced
25 actual_v, actual_area, actual_d, etc and the Node started pointing
26 into those arrays. Additional nodes after allocation required updating
27 pointers to v and area since those arrays were freed and reallocated.
28 Now, the threads hold all these arrays and we want to update them
29 properly under the circumstances of changing topology, changing
30 number of threads, and changing distribution of cells on threads.
31 Note there are no longer global versions of any of these arrays.
32 We do not want to update merely due to a change in area. Recently
33 we have dealt with diam, area, ri on a section basis. We generally
34 desire an update just before a simulation when the efficient
35 structures are necessary. This is reasonably well handled by the
36 v_structure_change flag which historically freed and reallocated
37 v_node and v_parent and, just before this comment,
38 ended up setting the NrnThread tml. This makes most of the old
39 memb_list vestigial and we now got rid of it except for
40 the artificial cells (and it is possibly not really necessary there).
41 Switching between sparse and tree matrix just cause freeing and
42 reallocation of actual_rhs.
43 
44 If we can get the freeing, reallocation, and pointer update correct
45 for _actual_v, I am guessing everything else can be dragged along with
46 it. We have two major cases, call to pc.nthread and change in
47 model structure. We want to use Node* as much as possible and defer
48 the handling of v_structure_change as long as possible.
49 */
50 
51 namespace coreneuron {
52 
54 
55 int nrn_nthread = 0;
58 
59 /// --> CoreNeuron class
60 static int table_check_cnt_;
62 
63 
65  int mech_id,
67  int& shadow_rhs_cnt,
68  const std::vector<int>& mech_types,
69  const std::vector<int>& nodecounts) {
70  auto tml = (NrnThreadMembList*) emalloc_align(sizeof(NrnThreadMembList), 0);
71  tml->next = nullptr;
72  tml->index = mech_types[mech_id];
73 
74  tml->ml = (Memb_list*) ecalloc_align(1, sizeof(Memb_list), 0);
75  tml->ml->_net_receive_buffer = nullptr;
76  tml->ml->_net_send_buffer = nullptr;
77  tml->ml->_permute = nullptr;
78  if (memb_func.alloc == nullptr) {
79  hoc_execerror(memb_func.sym, "mechanism does not exist");
80  }
81  tml->ml->nodecount = nodecounts[mech_id];
82  if (!memb_func.sym) {
83  printf("%s (type %d) is not available\n", nrn_get_mechname(tml->index), tml->index);
84  exit(1);
85  }
86  tml->ml->_nodecount_padded = nrn_soa_padded_size(tml->ml->nodecount,
87  corenrn.get_mech_data_layout()[tml->index]);
88  if (memb_func.is_point && corenrn.get_is_artificial()[tml->index] == 0) {
89  // Avoid race for multiple PointProcess instances in same compartment.
90  if (tml->ml->nodecount > shadow_rhs_cnt) {
91  shadow_rhs_cnt = tml->ml->nodecount;
92  }
93  }
94 
95  if (auto* const priv_ctor = corenrn.get_memb_func(tml->index).private_constructor) {
96  priv_ctor(&nt, tml->ml, tml->index);
97  }
98 
99  return tml;
100 }
101 
103  if (nrn_nthread != n) {
104  /*printf("sizeof(NrnThread)=%d sizeof(Memb_list)=%d\n", sizeof(NrnThread),
105  * sizeof(Memb_list));*/
106 
107  nrn_threads = nullptr;
108  nrn_nthread = n;
109  if (n > 0) {
110  nrn_threads = new NrnThread[n];
111  for (int i = 0; i < nrn_nthread; ++i) {
112  NrnThread& nt = nrn_threads[i];
113  nt.id = i;
114  for (int j = 0; j < BEFORE_AFTER_SIZE; ++j) {
115  nt.tbl[j] = nullptr;
116  }
117  }
118  }
119  v_structure_change = 1;
120  diam_changed = 1;
121  }
122  /*printf("nrn_threads_create %d %d\n", nrn_nthread, nrn_thread_parallel_);*/
123 }
124 
126  if (nrn_nthread) {
127  delete[] nrn_threads;
128  nrn_threads = nullptr;
129  nrn_nthread = 0;
130  }
131 }
132 
134  if (table_check_) {
135  free((void*) table_check_);
136  table_check_ = nullptr;
137  }
138  auto& memb_func = corenrn.get_memb_funcs();
139  // Allocate int array of size of mechanism types
140  std::vector<int> ix(memb_func.size(), -1);
141  table_check_cnt_ = 0;
142  for (int id = 0; id < nrn_nthread; ++id) {
143  auto& nt = nrn_threads[id];
144  for (auto tml = nt.tml; tml; tml = tml->next) {
145  int index = tml->index;
146  if (memb_func[index].thread_table_check_ && ix[index] == -1) {
147  ix[index] = id;
148  table_check_cnt_ += 2;
149  }
150  }
151  }
152  if (table_check_cnt_) {
154  }
155  int i = 0;
156  for (int id = 0; id < nrn_nthread; ++id) {
157  auto& nt = nrn_threads[id];
158  for (auto tml = nt.tml; tml; tml = tml->next) {
159  int index = tml->index;
160  if (memb_func[index].thread_table_check_ && ix[index] == id) {
161  table_check_[i++].i = id;
162  table_check_[i++]._pvoid = (void*) tml;
163  }
164  }
165  }
166 }
167 
169  for (int i = 0; i < table_check_cnt_; i += 2) {
170  auto& nt = nrn_threads[table_check_[i].i];
171  auto tml = static_cast<NrnThreadMembList*>(table_check_[i + 1]._pvoid);
172  Memb_list* ml = tml->ml;
173  (*corenrn.get_memb_func(tml->index).thread_table_check_)(
174  0, ml->_nodecount_padded, ml->data, ml->pdata, ml->_thread, &nt, ml, tml->index);
175  }
176 }
177 } // namespace coreneuron
A class representing the CoreNEURON state, holding pointers to the various data structures.
Definition: coreneuron.hpp:56
auto & get_memb_func(size_t idx)
Definition: coreneuron.hpp:135
#define id
Definition: md1redef.h:41
#define i
Definition: md1redef.h:19
#define BEFORE_AFTER_SIZE
Definition: membfunc.hpp:72
printf
Definition: extdef.h:5
THIS FILE IS AUTO GENERATED DONT MODIFY IT.
NrnThread * nrn_threads
Definition: multicore.cpp:56
void nrn_threads_create(int n)
Definition: multicore.cpp:102
void * emalloc_align(size_t size, size_t alignment)
void * ecalloc_align(size_t n, size_t size, size_t alignment)
int nrn_nthread
Definition: multicore.cpp:55
void nrn_mk_table_check()
Definition: multicore.cpp:133
void nrn_thread_table_check()
Definition: multicore.cpp:168
const char * nrn_get_mechname(int type)
Definition: mk_mech.cpp:152
static int table_check_cnt_
--> CoreNeuron class
Definition: multicore.cpp:60
int v_structure_change
Definition: nrnoc_aux.cpp:20
void hoc_execerror(const char *s1, const char *s2)
Definition: nrnoc_aux.cpp:39
CoreNeuron corenrn
Definition: multicore.cpp:53
static void * emalloc(size_t size)
Definition: mpispike.cpp:30
void(* nrn_mk_transfer_thread_data_)()
Definition: multicore.cpp:57
void nrn_threads_free()
Definition: multicore.cpp:125
static ThreadDatum * table_check_
Definition: multicore.cpp:61
int nrn_soa_padded_size(int cnt, int layout)
calculate size after padding for specific memory layout
int diam_changed
Definition: nrnoc_aux.cpp:21
NrnThreadMembList * create_tml(NrnThread &nt, int mech_id, Memb_func &memb_func, int &shadow_rhs_cnt, const std::vector< int > &mech_types, const std::vector< int > &nodecounts)
Definition: multicore.cpp:64
int const size_t const size_t n
Definition: nrngsl.h:10
size_t j
short index
Definition: cabvars.h:11
std::vector< Memb_func > memb_func
Definition: init.cpp:145
ThreadDatum * _thread
Definition: mechanism.hpp:141
NrnThreadBAList * tbl[BEFORE_AFTER_SIZE]
Definition: multicore.hpp:133