NEURON
multicore.cpp
Go to the documentation of this file.
1 /* included by treeset.cpp */
2 /*#include <../../nrnconf.h>*/
3 /*#include <multicore.h>*/
4 #include <nrnpthread.h>
5 #include <nrnmpi.h>
6 
7 
8 /*
9 Now that threads have taken over the actual_v, v_node, etc, it might
10 be a good time to regularize the method of freeing, allocating, and
11 updating those arrays. To recapitulate the history, Node used to
12 be the structure that held direct values for v, area, d, rhs, etc.
13 That continued to hold for the cray vectorization project which
14 introduced v_node, v_parent, memb_list. Cache efficiency introduced
15 actual_v, actual_area, actual_d, etc and the Node started pointing
16 into those arrays. Additional nodes after allocation required updating
17 pointers to v and area since those arrays were freed and reallocated.
18 Now, the threads hold all these arrays and we want to update them
19 properly under the circumstances of changing topology, changing
20 number of threads, and changing distribution of cells on threads.
21 Note there are no longer global versions of any of these arrays.
22 We do not want to update merely due to a change in area. Recently
23 we have dealt with diam, area, ri on a section basis. We generally
24 desire an update just before a simulation when the efficient
25 structures are necessary. This is reasonably well handled by the
26 v_structure_change flag which historically freed and reallocated
27 v_node and v_parent and, just before this comment,
28 ended up setting the NrnThread tml. This makes most of the old
29 memb_list vestigial and we now got rid of it except for
30 the artificial cells (and it is possibly not really necessary there).
31 Switching between sparse and tree matrix just cause freeing and
32 reallocation of actual_rhs.
33 
34 If we can get the freeing, reallocation, and pointer update correct
35 for _actual_v, I am guessing everything else can be dragged along with
36 it. We have two major cases, call to pc.nthread and change in
37 model structure. We want to use Node* as much as possible and defer
38 the handling of v_structure_change as long as possible.
39 */
40 
41 #define CACHELINE_ALLOC(name,type,size) name = (type*)nrn_cacheline_alloc((void**)&name, size*sizeof(type))
42 #define CACHELINE_CALLOC(name,type,size) name = (type*)nrn_cacheline_calloc((void**)&name, size, sizeof(type))
43 
47 
48 static int busywait_;
49 static int busywait_main_;
50 extern void nrn_thread_error(const char*);
51 extern void nrn_threads_free();
52 extern void nrn_old_thread_save();
53 extern double nrn_timeus();
54 
56 void nrn_mk_table_check();
57 static int table_check_cnt_;
59 static int allow_busywait_;
60 
61 /* linux specfic for performance testing */
62 /* eventually will be removed */
63 #define BENCHMARKING 0
64 #if BENCHMARKING
65 /* for rdtscll() */
66 #include <asm/msr.h>
67 #define BENCHDECLARE unsigned long t1;
68 #define BENCHBEGIN(arg) if (t_[arg] < t1_[arg] + BSIZE) {rdtscl(t1); *(t_[arg]++) = t1;}
69 #define BENCHADD(arg) BENCHBEGIN(arg)
70 #define WAIT wait_for_workers_timeit
71 #define CPU_MHZ 3192
72 #define BSIZE 200000
73 #define BS 10
74 static unsigned long bcnt_, bcnt1_;
75 static unsigned long t1_[BS][BSIZE], *t_[BS];
76 #else
77 #define BENCHDECLARE /**/
78 #define BENCHBEGIN(arg) /**/
79 #define BENCHADD(arg) /**/
80 #define WAIT wait_for_workers
81 #define BS 0
82 #endif
83 
84 static void* nulljob(NrnThread* nt) {
85  return nullptr;
86 }
87 
89 #if USE_PTHREAD
90 
91 #include <pthread.h>
92 #include <sched.h> /* for sched_setaffinity */
93 
94 /* abort if using threads and a call to malloc is unprotected */
95 #define use_malloc_hook 0
96 #if use_malloc_hook
97 #include <malloc.h>
98 
99 static int nrn_malloc_protected_;
100 static void my_init_hook();
101 static void *(*old_malloc_hook) (size_t, const void*);
102 static void *(*old_memalign_hook) (size_t, size_t, const void*);
103 static void *(*old_realloc_hook) (void*, size_t, const void*);
104 static void (*old_free_hook) (void*, const void*);
105 static void *my_malloc_hook (size_t, const void*);
106 static void *my_memalign_hook (size_t, size_t, const void*);
107 static void *my_realloc_hook (void*, size_t, const void*);
108 static void my_free_hook (void*, const void*);
109 void (*__malloc_initialize_hook)(void) = my_init_hook;
110 
111 static void* my_malloc_hook(size_t size, const void* caller) {
112  void* result;
113  if (nrn_inthread_ && !nrn_malloc_protected_) {
114  abort();
115  }
116  __malloc_hook = old_malloc_hook;
117  __memalign_hook = old_memalign_hook;
118  __realloc_hook = old_realloc_hook;
119  __free_hook = old_free_hook;
120  result = malloc(size);
121  old_malloc_hook = __malloc_hook;
122  old_memalign_hook = __memalign_hook;
123  old_realloc_hook = __realloc_hook;
124  old_free_hook = __free_hook;
125  __malloc_hook = my_malloc_hook;
126  __memalign_hook = my_memalign_hook;
127  __realloc_hook = my_realloc_hook;
128  __free_hook = my_free_hook;
129  return result;
130 }
131 static void* my_memalign_hook(size_t alignment, size_t size, const void* caller) {
132  void* result;
133  if (nrn_inthread_ && !nrn_malloc_protected_) {
134  abort();
135  }
136  __malloc_hook = old_malloc_hook;
137  __memalign_hook = old_memalign_hook;
138  __realloc_hook = old_realloc_hook;
139  __free_hook = old_free_hook;
140  result = memalign(alignment, size);
141  old_malloc_hook = __malloc_hook;
142  old_memalign_hook = __memalign_hook;
143  old_realloc_hook = __realloc_hook;
144  old_free_hook = __free_hook;
145  __malloc_hook = my_malloc_hook;
146  __memalign_hook = my_memalign_hook;
147  __realloc_hook = my_realloc_hook;
148  __free_hook = my_free_hook;
149  return result;
150 }
151 static void* my_realloc_hook(void* ptr, size_t size, const void* caller) {
152  void* result;
153  if (nrn_inthread_ && !nrn_malloc_protected_) {
154  abort();
155  }
156  __malloc_hook = old_malloc_hook;
157  __memalign_hook = old_memalign_hook;
158  __realloc_hook = old_realloc_hook;
159  __free_hook = old_free_hook;
160  result = realloc(ptr, size);
161  old_malloc_hook = __malloc_hook;
162  old_memalign_hook = __memalign_hook;
163  old_realloc_hook = __realloc_hook;
164  old_free_hook = __free_hook;
165  __malloc_hook = my_malloc_hook;
166  __memalign_hook = my_memalign_hook;
167  __realloc_hook = my_realloc_hook;
168  __free_hook = my_free_hook;
169  return result;
170 }
171 static void my_free_hook(void* ptr, const void* caller) {
172  if (nrn_inthread_ && !nrn_malloc_protected_) {
173  abort();
174  }
175  __malloc_hook = old_malloc_hook;
176  __memalign_hook = old_memalign_hook;
177  __realloc_hook = old_realloc_hook;
178  __free_hook = old_free_hook;
179  free(ptr);
180  old_malloc_hook = __malloc_hook;
181  old_memalign_hook = __memalign_hook;
182  old_realloc_hook = __realloc_hook;
183  old_free_hook = __free_hook;
184  __malloc_hook = my_malloc_hook;
185  __memalign_hook = my_memalign_hook;
186  __realloc_hook = my_realloc_hook;
187  __free_hook = my_free_hook;
188 }
189 static void my_init_hook() {
190  static int installed = 0;
191  if (installed) { return; }
192  installed = 1;
193  old_malloc_hook = __malloc_hook;
194  __malloc_hook = my_malloc_hook;
195  old_memalign_hook = __memalign_hook;
196  __memalign_hook = my_memalign_hook;
197  old_realloc_hook = __realloc_hook;
198  __realloc_hook = my_realloc_hook;
199  old_free_hook = __free_hook;
200  __free_hook = my_free_hook;
201 }
202 #endif
203 
204 static int interpreter_locked;
205 static pthread_mutex_t interpreter_lock_;
206 static pthread_mutex_t* _interpreter_lock;
207 
208 static pthread_mutex_t nmodlmutex_;
209 pthread_mutex_t* _nmodlmutex;
210 
211 static pthread_mutex_t nrn_malloc_mutex_;
212 static pthread_mutex_t* _nrn_malloc_mutex;
213 
214 extern "C" void nrn_malloc_lock() {
215  if (_nrn_malloc_mutex) {
216  pthread_mutex_lock(_nrn_malloc_mutex);
217 #if use_malloc_hook
218  nrn_malloc_protected_ = 1;
219 #endif
220  }
221 }
222 
223 extern "C" void nrn_malloc_unlock() {
224  if (_nrn_malloc_mutex) {
225 #if use_malloc_hook
226  nrn_malloc_protected_ = 0;
227 #endif
228  pthread_mutex_unlock(_nrn_malloc_mutex);
229  }
230 }
231 
232 /* when PERMANENT is 0, we avoid false warnings with helgrind, but a bit slower */
233 /* when 0, create/join instead of wait on condition. */
234 #ifndef PERMANENT
235 #define PERMANENT 1
236 #endif
237 
238 typedef volatile struct {
239  int flag;
240  int thread_id;
241  /* for nrn_solve etc.*/
242  void* (*job)(NrnThread*);
243 } slave_conf_t;
244 
245 static pthread_cond_t* cond;
246 static pthread_mutex_t* mut;
247 static pthread_t* slave_threads;
248 static slave_conf_t* wc;
249 
250 static void wait_for_workers() {
251  int i;
252  for (i=1; i < nrn_nthread; ++i) {
253 #if PERMANENT
254  if (busywait_main_) {
255  while (wc[i].flag != 0){;}
256  }else{
257  pthread_mutex_lock(mut + i);
258  while (wc[i].flag != 0) {
259  pthread_cond_wait(cond + i, mut + i);
260  }
261  pthread_mutex_unlock(mut + i);
262  }
263 #else
264  pthread_join(slave_threads[i], nullptr);
265 #endif
266  }
267 }
268 
269 static void wait_for_workers_timeit() {
271  BENCHBEGIN(BS-2)
272  wait_for_workers();
273  BENCHADD(BS-1)
274 }
275 
276 static void send_job_to_slave(int i, void* (*job)(NrnThread*)) {
277 #if PERMANENT
278  pthread_mutex_lock(mut + i);
279  wc[i].job = job;
280  wc[i].flag = 1;
281  pthread_cond_signal(cond + i);
282  pthread_mutex_unlock(mut + i);
283 #else
284  pthread_create(slave_threads + i, nullptr, (void*(*)(void*))job, (void*)(nrn_threads + i));
285 #endif
286 }
287 
288 void setaffinity(int i) {
289  int mask;
290 return;
291 #if 0
292  cpu_set_t mask;
293  CPU_ZERO(&mask);
294  CPU_SET(i, &mask);
295  mask = (1 << i);
296  sched_setaffinity(0, 4, &mask);
297 #endif
298 }
299 
300 static void* slave_main(void* arg) {
301  slave_conf_t* my_wc = (slave_conf_t*)arg;
302  pthread_mutex_t *my_mut = mut + my_wc->thread_id;
303  pthread_cond_t *my_cond = cond + my_wc->thread_id;
305 #if BENCHMARKING
306  unsigned long* t_[BS];
307  int a1, a2;
308  a1 = my_wc->thread_id;
309  a2 = my_wc->thread_id + nrn_nthread;
310  t_[a1] = t1_[a1];
311  t_[a2] = t1_[a2];
312 #endif
313  setaffinity(my_wc->thread_id);
314 
315  for(;;) {
316  if (busywait_) {
317  while(my_wc->flag == 0) {;}
318  if (my_wc->flag == 1) {
319  BENCHBEGIN(a1)
320  (*my_wc->job)(nrn_threads + my_wc->thread_id);
321  BENCHADD(a2)
322  }else{
323  return nullptr;
324  }
325  my_wc->flag = 0;
326  pthread_cond_signal(my_cond);
327  }else{
328  pthread_mutex_lock(my_mut);
329  while (my_wc->flag == 0) {
330  pthread_cond_wait(my_cond, my_mut);
331  }
332  pthread_mutex_unlock(my_mut);
333  pthread_mutex_lock(my_mut);
334  if (my_wc->flag == 1) {
335  pthread_mutex_unlock(my_mut);
336  BENCHBEGIN(a1)
337  (*my_wc->job)(nrn_threads + my_wc->thread_id);
338  BENCHADD(a2)
339  }else{
340  pthread_mutex_unlock(my_mut);
341  return nullptr;
342  }
343  pthread_mutex_lock(my_mut);
344  my_wc->flag = 0;
345  pthread_cond_signal(my_cond);
346  pthread_mutex_unlock(my_mut);
347  }
348  }
349  return nullptr;
350 }
351 
352 static void threads_create_pthread(){
353 #if NRNMPI
354  if (nrn_nthread > 1 && nrnmpi_numprocs > 1 && nrn_cannot_use_threads_and_mpi == 1) {
355  if (nrnmpi_myid == 0) { printf("This MPI is not threadsafe so pthreads are disabled.\n"); }
357  return;
358  }
359 #endif
360  setaffinity(nrnmpi_myid);
361  if (nrn_nthread > 1) {
362  int i;
363 #if PERMANENT
364  CACHELINE_ALLOC(wc, slave_conf_t, nrn_nthread);
365  slave_threads = (pthread_t *)emalloc(sizeof(pthread_t)*nrn_nthread);
366  cond = (pthread_cond_t *)emalloc(sizeof(pthread_cond_t)*nrn_nthread);
367  mut = (pthread_mutex_t *)emalloc(sizeof(pthread_mutex_t)*nrn_nthread);
368  for (i=1; i < nrn_nthread; ++i) {
369  wc[i].flag = 0;
370  wc[i].thread_id = i;
371  pthread_cond_init(cond + i, nullptr);
372  pthread_mutex_init(mut + i, nullptr);
373  pthread_create(slave_threads + i, nullptr, slave_main, (void*)(wc+i));
374  }
375 #else
376  slave_threads = (pthread_t *)emalloc(sizeof(pthread_t)*nrn_nthread);
377 #endif /* PERMANENT */
378  if (!_interpreter_lock) {
379  interpreter_locked = 0;
380  _interpreter_lock = &interpreter_lock_;
381  pthread_mutex_init(_interpreter_lock, nullptr);
382  }
383  if (!_nmodlmutex) {
384  _nmodlmutex = &nmodlmutex_;
385  pthread_mutex_init(_nmodlmutex, nullptr);
386  }
387  if (!_nrn_malloc_mutex) {
388  _nrn_malloc_mutex = &nrn_malloc_mutex_;
389  pthread_mutex_init(_nrn_malloc_mutex, nullptr);
390  }
392  }else{
394  }
395 }
396 
397 static void threads_free_pthread(){
398  int i;
399  if (slave_threads) {
400 #if PERMANENT
401  wait_for_workers();
402  for (i=1; i < nrn_nthread; ++i) {
403  pthread_mutex_lock(mut + i);
404  wc[i].flag = -1;
405  pthread_cond_signal(cond + i);
406  pthread_mutex_unlock(mut + i);
407  pthread_join(slave_threads[i], nullptr);
408  pthread_cond_destroy(cond + i);
409  pthread_mutex_destroy(mut + i);
410  }
411  free((char*)slave_threads);
412  free((char*)cond);
413  free((char*)mut);
414  free((char*)wc);
415  slave_threads = (pthread_t*)0;
416  cond = (pthread_cond_t*)0;
417  mut = (pthread_mutex_t*)0;
418  wc = (slave_conf_t*)0;
419 #else
420  free((char*)slave_threads);
421  slave_threads = (pthread_t*)0;
422 #endif /*PERMANENT*/
423  }
424  if (_interpreter_lock) {
425  pthread_mutex_destroy(_interpreter_lock);
426  _interpreter_lock = (pthread_mutex_t*)0;
427  interpreter_locked = 0;
428  }
429  if (_nmodlmutex) {
430  pthread_mutex_destroy(_nmodlmutex);
431  _nmodlmutex = (pthread_mutex_t*)0;
432  }
433  if (_nrn_malloc_mutex) {
434  pthread_mutex_destroy(_nrn_malloc_mutex);
435  _nrn_malloc_mutex = (pthread_mutex_t*)0;
436  }
438 }
439 
440 #else /* USE_PTHREAD */
441 
442 extern "C" void nrn_malloc_lock() {}
443 extern "C" void nrn_malloc_unlock() {}
444 
447 }
448 static void threads_free_pthread(){
450 }
451 #endif /* !USE_PTHREAD */
452 
453 void nrn_thread_error(const char* s) {
454  if (nrn_nthread != 1) {
455  hoc_execerror(s, (char*)0);
456  }
457 }
458 
460 #if BENCHMARKING
461  FILE* f;
462  long i, j, n;
463  char buf[50];
464  sprintf(buf, "bench.%d.dat", nrnmpi_myid);
465  f = fopen(buf, "w");
466 #if 1
467  n = (t_[0] - t1_[0]);
468  for (i=1; i < nrn_nthread; ++i) {
469  t_[i] = t1_[i] + n;
470  t_[i+nrn_nthread] = t1_[i+nrn_nthread] + n;
471  }
472 #endif
473  n = 0;
474  for (i=0; i < BS; ++i) {
475  n += t_[i] - t1_[i];
476  }
477  fprintf(f, "%ld\n", n);
478  n = 0;
479  for (j=0; j < BS; ++j) {
480  n = t_[j] - t1_[j];
481  for (i=0; i < n; ++i) {
482  fprintf(f, "%ld %d\n", t1_[j][i], j*nrnmpi_numprocs + nrnmpi_myid);
483  }
484  }
485  fclose(f);
486 #endif /*BENCHMARKING*/
487 }
488 
489 
490 void nrn_threads_create(int n, int parallel) {
491  int i, j;
492  NrnThread *nt;
493  if (nrn_nthread != n) {
494 /*printf("sizeof(NrnThread)=%d sizeof(Memb_list)=%d\n", sizeof(NrnThread), sizeof(Memb_list));*/
497  for (i = 0; i < nrn_nthread; ++i) {
498  nt = nrn_threads + i;
499  if (nt->userpart) {
500  hoc_obj_unref(nt->userpart);
501  }
502  }
503  free((char *) nrn_threads);
504 #if BENCHMARKING
505 #endif
506  nrn_threads = (NrnThread *) 0;
507  nrn_nthread = n;
508  if (n > 0) {
509  CACHELINE_ALLOC(nrn_threads, NrnThread, n);
510 #if BENCHMARKING
511  for (i=0; i < BS; ++i) {
512  t_[i] = t1_[i];
513  }
514 #endif
515  for (i = 0; i < n; ++i) {
516  nt = nrn_threads + i;
517  nt->_t = 0.;
518  nt->_dt = -1e9;
519  nt->id = i;
520  nt->_stop_stepping = 0;
521  nt->tml = (NrnThreadMembList *) 0;
522  nt->_ml_list = NULL;
523  nt->roots = (hoc_List *) 0;
524  nt->userpart = 0;
525  nt->ncell = 0;
526  nt->end = 0;
527  for (j = 0; j < BEFORE_AFTER_SIZE; ++j) {
528  nt->tbl[j] = (NrnThreadBAList *) 0;
529  }
530  nt->_actual_rhs = 0;
531  nt->_actual_d = 0;
532  nt->_actual_a = 0;
533  nt->_actual_b = 0;
534  nt->_actual_v = 0;
535  nt->_actual_area = 0;
536  nt->_v_parent_index = 0;
537  nt->_v_node = 0;
538  nt->_v_parent = 0;
539  nt->_ecell_memb_list = 0;
540  nt->_ecell_child_cnt = 0;
541  nt->_ecell_children = NULL;
542  nt->_sp13mat = 0;
543  nt->_ctime = 0.0;
544  nt->_vcv = 0;
545  nt->_nrn_fast_imem = 0;
546  }
547  }
548  v_structure_change = 1;
549  diam_changed = 1;
550  }
551  if (nrn_thread_parallel_ != parallel) {
553  if (parallel) {
555  }
556  }
557  /*printf("nrn_threads_create %d %d\n", nrn_nthread, nrn_thread_parallel_);*/
558 }
559 
560 /*
561 Avoid invalidating pointers to i_membrane_ unless the number of compartments
562 in a thread has changed.
563 */
564 static int fast_imem_nthread_ = 0;
565 static int* fast_imem_size_ = NULL;
567 
568 static void fast_imem_free() {
569  int i;
570  for (i = 0; i < nrn_nthread; ++i) {
571  nrn_threads[i]._nrn_fast_imem = NULL;
572  }
573  for (i = 0; i < fast_imem_nthread_; ++i) {
574  if (fast_imem_size_[i] > 0) {
575  free(fast_imem_[i]._nrn_sav_rhs);
576  free(fast_imem_[i]._nrn_sav_d);
577  }
578  }
579  if (fast_imem_nthread_) {
580  free(fast_imem_size_);
581  free(fast_imem_);
582  fast_imem_nthread_ = 0;
583  fast_imem_size_ = NULL;
584  fast_imem_ = NULL;
585  }
586 }
587 
588 static void fast_imem_alloc() {
589  int i;
590  if (fast_imem_nthread_ != nrn_nthread) {
591  fast_imem_free();
592  fast_imem_nthread_ = nrn_nthread;
593  fast_imem_size_ = static_cast<int*>(ecalloc(nrn_nthread, sizeof(int)));
594  fast_imem_ = (_nrn_Fast_Imem*)ecalloc(nrn_nthread, sizeof(_nrn_Fast_Imem));
595  }
596  for (i=0; i < nrn_nthread; ++i) {
597  NrnThread* nt = nrn_threads + i;
598  int n = nt->end;
599  _nrn_Fast_Imem* fi = fast_imem_ + i;
600  if (n != fast_imem_size_[i]) {
601  if (fast_imem_size_[i] > 0) {
602  free(fi->_nrn_sav_rhs);
603  free(fi->_nrn_sav_d);
604  }
605  if (n > 0) {
606  CACHELINE_CALLOC(fi->_nrn_sav_rhs, double, n);
607  CACHELINE_CALLOC(fi->_nrn_sav_d, double, n);
608  }
609  fast_imem_size_[i] = n;
610  }
611  }
612 }
613 
615  if (nrn_use_fast_imem) {
616  int i;
617  fast_imem_alloc();
618  for (i=0; i < nrn_nthread; ++i) {
619  nrn_threads[i]._nrn_fast_imem = fast_imem_ + i;
620  }
621  }else{
622  fast_imem_free();
623  }
624 }
625 
627  int it, i;
628  for (it = 0; it < nrn_nthread; ++it) {
629  NrnThread* nt = nrn_threads + it;
630  NrnThreadMembList* tml, *tml2;
631  for (tml = nt->tml; tml; tml = tml2) {
632  Memb_list* ml = tml->ml;
633  tml2 = tml->next;
634  free((char*)ml->nodelist);
635  free((char*)ml->nodeindices);
636  if (memb_func[tml->index].hoc_mech) {
637  free((char*)ml->prop);
638  }else{
639  free((char*)ml->data);
640  free((char*)ml->pdata);
641  }
642  if (ml->_thread) {
643  if (memb_func[tml->index].thread_cleanup_) {
644  (*memb_func[tml->index].thread_cleanup_)(ml->_thread);
645  }
646  free((char*)ml->_thread);
647  }
648  free((char*)ml);
649  free((char*)tml);
650  }
651  if (nt->_ml_list) { free((char*)nt->_ml_list); nt->_ml_list = NULL; }
652  for (i=0; i < BEFORE_AFTER_SIZE; ++i) {
653  NrnThreadBAList* tbl, *tbl2;
654  for (tbl = nt->tbl[i]; tbl; tbl = tbl2) {
655  tbl2 = tbl->next;
656  free((char*)tbl);
657  }
658  nt->tbl[i] = (NrnThreadBAList*)0;
659  }
660  nt->tml = (NrnThreadMembList*)0;
661  if (nt->userpart == 0 && nt->roots) {
662  hoc_l_freelist(&nt->roots);
663  nt->ncell = 0;
664  }
665  if (nt->_actual_rhs) {free((char*)nt->_actual_rhs); nt->_actual_rhs = 0;}
666  if (nt->_actual_d) {free((char*)nt->_actual_d); nt->_actual_d = 0;}
667  if (nt->_actual_a) {free((char*)nt->_actual_a); nt->_actual_a = 0;}
668  if (nt->_actual_b) {free((char*)nt->_actual_b); nt->_actual_b = 0;}
669  if (nt->_v_parent_index) {free((char*)nt->_v_parent_index); nt->_v_parent_index = 0;}
670  if (nt->_v_node) {free((char*)nt->_v_node); nt->_v_node = 0;}
671  if (nt->_v_parent) {free((char*)nt->_v_parent); nt->_v_parent = 0;}
672  nt->_ecell_memb_list = 0;
673  if (nt->_ecell_children) {
674  nt->_ecell_child_cnt = 0;
675  free(nt->_ecell_children);
676  nt->_ecell_children = NULL;
677  }
678  if (nt->_sp13mat) {
679  spDestroy(nt->_sp13mat);
680  nt->_sp13mat = 0;
681  }
682  nt->_nrn_fast_imem = NULL;
683  /* following freed by nrn_recalc_node_ptrs */
685  nt->_actual_v = 0;
686  nt->_actual_area = 0;
687  nt->end = 0;
688  nt->ncell = 0;
689  nt->_vcv = 0;
690  }
691 }
692 
693 /* be careful to make the tml list in proper memb_order. This is important */
694 /* for correct finitialize where mechanisms that write concentrations must be */
695 /* after ions and before mechanisms that read concentrations. */
696 
697 static void thread_memblist_setup(NrnThread* _nt, int* mlcnt, void** vmap) {
698  int i, ii;
699  Node* nd;
700  Prop* p;
701  NrnThreadMembList* tml, **ptml;
702  Memb_list** mlmap = (Memb_list**)vmap;
703  BAMech** bamap = (BAMech**)vmap;
704 #if 0
705 printf("thread_memblist_setup %lx v_node_count=%d ncell=%d end=%d\n", (long)nth, v_node_count, nth->ncell, nth->end);
706 #endif
707  for (i=0; i < n_memb_func; ++i) {
708  mlcnt[i] = 0;
709  }
710 
711  /* count */
712  for (i = 0; i < _nt->end; ++i) {
713  nd = _nt->_v_node[i];
714  for (p = nd->prop; p; p = p->next) {
715  if (memb_func[p->type].current
716  || memb_func[p->type].state
717  || memb_func[p->type].initialize
718  ) {
719  ++mlcnt[p->type];
720  }
721  }
722  }
723  /* allocate */
724  ptml = &_nt->tml;
725  for (ii = 0; ii < n_memb_func; ++ii) {
726  i = memb_order_[ii];
727  if (mlcnt[i]) {
728  if (_nt->id > 0 && memb_func[i].vectorized == 0) {
729 hoc_execerror(memb_func[i].sym->name, "is not thread safe");
730  }
731 /*printf("thread_memblist_setup %lx type=%d cnt=%d\n", (long)nth, i, mlcnt[i]);*/
733  tml->index = i;
734  tml->next = (NrnThreadMembList*)0;
735  *ptml = tml;
736  ptml = &tml->next;
737  CACHELINE_ALLOC(tml->ml, Memb_list, 1);
738  if (i == EXTRACELL) { _nt->_ecell_memb_list = tml->ml; }
739  mlmap[i] = tml->ml;
740  CACHELINE_ALLOC(tml->ml->nodelist, Node*, mlcnt[i]);
741  CACHELINE_ALLOC(tml->ml->nodeindices, int, mlcnt[i]);
742  if (memb_func[i].hoc_mech) {
743  tml->ml->prop = (Prop**)emalloc(mlcnt[i]*sizeof(Prop*));
744  }else{
745  CACHELINE_ALLOC(tml->ml->data, double*, mlcnt[i]);
746  CACHELINE_ALLOC(tml->ml->pdata, Datum*, mlcnt[i]);
747  }
748  tml->ml->_thread = (Datum*)0;
749  if (memb_func[i].thread_size_) {
750  tml->ml->_thread = (Datum*)ecalloc(memb_func[i].thread_size_, sizeof(Datum));
751  if (memb_func[tml->index].thread_mem_init_) {
752  (*memb_func[tml->index].thread_mem_init_)(tml->ml->_thread);
753  }
754  }
755  tml->ml->nodecount = 0; /* counted again below */
756  }
757  }
758  CACHELINE_CALLOC(_nt->_ml_list, Memb_list*, n_memb_func);
759  for (tml = _nt->tml; tml; tml = tml->next) {
760  _nt->_ml_list[tml->index] = tml->ml;
761  }
762 
763  /* fill */
764  for (i = 0; i < _nt->end; ++i) {
765  nd = _nt->_v_node[i];
766  for (p = nd->prop; p; p = p->next) {
767  if (memb_func[p->type].current
768  || memb_func[p->type].state
769  || memb_func[p->type].initialize
770  ) {
771  Memb_list* ml = mlmap[p->type];
772  ml->nodelist[ml->nodecount] = nd;
773  ml->nodeindices[ml->nodecount] = nd->v_node_index;
774  if (memb_func[p->type].hoc_mech) {
775  ml->prop[ml->nodecount] = p;
776  }else{
777  ml->data[ml->nodecount] = p->param;
778  ml->pdata[ml->nodecount] = p->dparam;
779  }
780  ++ml->nodecount;
781  }
782  }
783  }
784  /* count and store any Node* with the property
785  nd->extnode == NULL && nd->pnd != NULL && nd->pnd->extcell != NULL
786  */
787  if (_nt->_ecell_memb_list) {
788  Node* pnd;
789  int cnt=0;
790  for (i = 0; i < _nt->end; ++i) {
791  nd = _nt->_v_node[i];
792  pnd = _nt->_v_parent[i];
793  if (nd->extnode == NULL && pnd && pnd->extnode) {
794  ++cnt;
795  }
796  }
797  if (cnt) {
798  Node** p;
799  CACHELINE_ALLOC(_nt->_ecell_children, Node*, cnt);
800  _nt->_ecell_child_cnt = cnt;
801  p = _nt->_ecell_children;
802  cnt = 0;
803  for (i = 0; i < _nt->end; ++i) {
804  nd = _nt->_v_node[i];
805  pnd = _nt->_v_parent[i];
806  if (nd->extnode == NULL && pnd && pnd->extnode) {
807  p[cnt++] = nd;
808  }
809  }
810  }
811  }
812 #if 0
813  for (i=0; i < n_memb_func; ++i) {
814  if (mlcnt[i]) {assert(mlcnt[i] = mlmap[i]->nodecount);}
815  }
816  for (tml = _nt->tml; tml; tml = tml->next) {
817  assert(mlcnt[tml->index] == tml->ml->nodecount);
818  }
819 #endif
820  /* fill the ba lists */
821  /* need map from ml type to BA type. Reuse vmap */
822  for (i=0; i < BEFORE_AFTER_SIZE; ++i) {
823  BAMech* bam;
824  NrnThreadBAList* tbl, **ptbl;
825  for (ii=0; ii < n_memb_func; ++ii) {
826  bamap[ii] = (BAMech*)0;
827  }
828  for (bam = bamech_[i]; bam; bam = bam->next) {
829  bamap[bam->type] = bam;
830  }
831  /* unnecessary but keep in order anyway */
832  ptbl = _nt->tbl + i;
833  for (tml = _nt->tml; tml; tml = tml->next) {
834  if (bamap[tml->index]) {
835  Memb_list* ml = tml->ml;
836  tbl = (NrnThreadBAList*)emalloc(sizeof(NrnThreadBAList));
837  tbl->next = (NrnThreadBAList*)0;
838  tbl->bam = bamap[tml->index];
839  tbl->ml = ml;
840  *ptbl = tbl;
841  ptbl = &(tbl->next);
842  }
843  }
844  }
845  /* fill in the Point_process._vnt value. */
846  /* artificial cells done in v_setup_vectors() */
847  for (tml = _nt->tml; tml; tml = tml->next) if (memb_func[tml->index].is_point) {
848  for (i=0; i < tml->ml->nodecount; ++i) {
849  Point_process* pnt = (Point_process*)tml->ml->pdata[i][1]._pvoid;
850  pnt->_vnt = (void*)_nt;
851  }
852  }
853 }
854 
856  int it, *mlcnt;
857  void** vmap;
858  mlcnt = (int*)emalloc(n_memb_func*sizeof(int));
859  vmap = (void**)emalloc(n_memb_func*sizeof(void*));
860  for (it=0; it < nrn_nthread; ++it) {
861  thread_memblist_setup(nrn_threads + it, mlcnt, vmap);
862  }
864  free((char*)vmap);
865  free((char*)mlcnt);
867  if (nrn_mk_transfer_thread_data_) { (*nrn_mk_transfer_thread_data_)(); }
868 }
869 
870 /* secorder needs to correspond to cells in NrnThread with roots */
871 /* at the beginning of each thread region */
872 /* this differs from original secorder where all roots are at the beginning */
873 /* in passing, also set start and end indices. */
874 
875 static void reorder_secorder() {
876  NrnThread* _nt;
877  Section* sec, *ch;
878  Node* nd;
879  hoc_Item* qsec;
880  hoc_List* sl;
881  int order, isec, i, j, inode;
882  /* count and allocate */
883  ForAllSections(sec)
884  sec->order = -1;
885  }
886  order = 0;
887  FOR_THREADS(_nt) {
888  /* roots of this thread */
889  sl = _nt->roots;
890  inode = 0;
891  ITERATE(qsec, sl) {
892  sec = hocSEC(qsec);
893  assert(sec->order == -1);
894  secorder[order] = sec;
895  sec->order = order;
896  ++order;
897  nd = sec->parentnode;
898  nd->_nt = _nt;
899  inode += 1;
900  }
901  /* all children of what is already in secorder */
902  for (isec = order - _nt->ncell; isec < order; ++isec) {
903  sec = secorder[isec];
904  /* to make it easy to fill in PreSyn.nt_*/
905  sec->prop->dparam[9]._pvoid = (void*)_nt;
906  for (j = 0; j < sec->nnode; ++j) {
907  nd = sec->pnode[j];
908  nd->_nt = _nt;
909  inode += 1;
910  }
911  for (ch = sec->child; ch; ch = ch->sibling) {
912  assert(ch->order == -1);
913  secorder[order] = ch;
914  ch->order = order;
915  ++order;
916  }
917  }
918  _nt->end = inode;
919  CACHELINE_CALLOC(_nt->_actual_rhs, double, inode);
920  CACHELINE_CALLOC(_nt->_actual_d, double, inode);
921  CACHELINE_CALLOC(_nt->_actual_a, double, inode);
922  CACHELINE_CALLOC(_nt->_actual_b, double, inode);
923  CACHELINE_CALLOC(_nt->_v_node, Node*, inode);
924  CACHELINE_CALLOC(_nt->_v_parent, Node*, inode);
925  CACHELINE_CALLOC(_nt->_v_parent_index, int, inode);
926  }
927  /* do it again and fill _v_node and _v_parent */
928  /* index each cell section in relative order. Do offset later */
930  sec->order = -1;
931  }
932  order = 0;
933  FOR_THREADS(_nt) {
934  /* roots of this thread */
935  sl = _nt->roots;
936  inode = 0;
937  ITERATE(qsec, sl) {
938  sec = hocSEC(qsec);
939  assert(sec->order == -1);
940  secorder[order] = sec;
941  sec->order = order;
942  ++order;
943  nd = sec->parentnode;
944  nd->_nt = _nt;
945  _nt->_v_node[inode] = nd;
946  _nt->_v_parent[inode] = (Node*)0;
947  _nt->_v_node[inode]->v_node_index = inode;
948  inode += 1;
949  }
950  /* all children of what is already in secorder */
951  for (isec = order - _nt->ncell; isec < order; ++isec) {
952  sec = secorder[isec];
953  /* to make it easy to fill in PreSyn.nt_*/
954  sec->prop->dparam[9]._pvoid = (void*)_nt;
955  for (j = 0; j < sec->nnode; ++j) {
956  nd = sec->pnode[j];
957  nd->_nt = _nt;
958  _nt->_v_node[inode] = nd;
959  if (j) {
960  _nt->_v_parent[inode] = sec->pnode[j - 1];
961  }else{
962  _nt->_v_parent[inode] = sec->parentnode;
963  }
964  _nt->_v_node[inode]->v_node_index = inode;
965  inode += 1;
966  }
967  for (ch = sec->child; ch; ch = ch->sibling) {
968  assert(ch->order == -1);
969  secorder[order] = ch;
970  ch->order = order;
971  ++order;
972  }
973  }
974  _nt->end = inode;
975  }
977  /*assert(inode == v_node_count);*/
978  /* not missing any */
979  ForAllSections(sec) assert(sec->order != -1); }
980 
981  /* here is where multisplit reorders the nodes. Afterwards
982  in either case, we can then point to v, d, rhs in proper
983  node order
984  */
985  FOR_THREADS(_nt) for (inode=0; inode < _nt->end; ++inode) {
986  _nt->_v_node[inode]->_classical_parent = _nt->_v_parent[inode];
987  }
989  /* classical order abandoned */
990  (*nrn_multisplit_setup_)();
991  }
992  /* make the Nodes point to the proper d, rhs */
993  FOR_THREADS(_nt) {
994  for (j = 0; j < _nt->end; ++j) {
995  Node* nd = _nt->_v_node[j];
996  nd->_d = _nt->_actual_d + j;
997  nd->_rhs = _nt->_actual_rhs + j;
998  }
999  }
1000  /* because the d,rhs changed, if multisplit is used we need to update
1001  the reduced tree gather/scatter pointers
1002  */
1003  if (nrn_multisplit_setup_) {
1005  }
1006 }
1007 
1008 
1010  int i, id, index;
1011  int* ix;
1012  if (table_check_) {
1013  free((void*)table_check_);
1014  table_check_ = (Datum*)0;
1015  }
1016  ix = (int*)emalloc(n_memb_func*sizeof(int));
1017  for (i=0; i < n_memb_func; ++i) {
1018  ix[i] = -1;
1019  }
1020  table_check_cnt_ = 0;
1021  for (id=0; id < nrn_nthread; ++id) {
1022  NrnThread* nt = nrn_threads + id;
1023  NrnThreadMembList* tml;
1024  for (tml = nt->tml; tml; tml = tml->next) {
1025  index = tml->index;
1026  if (memb_func[index].thread_table_check_ && ix[index] == -1) {
1027  ix[index] = id;
1028  table_check_cnt_ += 2;
1029  }
1030  }
1031  }
1032  if (table_check_cnt_) {
1033  table_check_ = (Datum*)emalloc(table_check_cnt_*sizeof(Datum));
1034  }
1035  i=0;
1036  for (id=0; id < nrn_nthread; ++id) {
1037  NrnThread* nt = nrn_threads + id;
1038  NrnThreadMembList* tml;
1039  for (tml = nt->tml; tml; tml = tml->next) {
1040  index = tml->index;
1041  if (memb_func[index].thread_table_check_ && ix[index] == id) {
1042  table_check_[i++].i = id;
1043  table_check_[i++]._pvoid = (void*)tml;
1044  }
1045  }
1046  }
1047  free((void*)ix);
1048 }
1049 
1051  int i;
1052  for (i=0; i < table_check_cnt_; i += 2) {
1053  NrnThread* nt = nrn_threads + table_check_[i].i;
1054  NrnThreadMembList* tml = (NrnThreadMembList*)table_check_[i+1]._pvoid;
1055  Memb_list* ml = tml->ml;
1057  ml->data[0], ml->pdata[0], ml->_thread, nt, tml->index
1058  );
1059  }
1060 }
1061 
1062 /* if it is possible for more than one thread to get into the
1063  interpreter, lock it. */
1065 #if USE_PTHREAD
1066  if (nrn_inthread_) {
1067  pthread_mutex_lock(_interpreter_lock);
1068  interpreter_locked = 1;
1069  }
1070 #endif
1071 }
1073 #if USE_PTHREAD
1074  if (interpreter_locked) {
1075  interpreter_locked = 0;
1076  pthread_mutex_unlock(_interpreter_lock);
1077  }
1078 #endif
1079 }
1080 
1081 void nrn_multithread_job(void*(*job)(NrnThread*)) {
1082  int i;
1083 #if USE_PTHREAD
1084  BENCHDECLARE
1085  if (nrn_thread_parallel_) {
1086  nrn_inthread_ = 1;
1087  for (i=1; i < nrn_nthread; ++i) {
1088  send_job_to_slave(i, job);
1089  }
1090  BENCHBEGIN(0)
1091  (*job)(nrn_threads);
1092  BENCHADD(nrn_nthread)
1093  WAIT();
1094  nrn_inthread_ = 0;
1095  }else{ /* sequential */
1096 #else
1097  {
1098 #endif
1099  for (i=1; i < nrn_nthread; ++i) {
1100  BENCHBEGIN(i)
1101  (*job)(nrn_threads + i);
1102  BENCHADD(i+nrn_nthread)
1103  }
1104  BENCHBEGIN(0)
1105  (*job)(nrn_threads);
1106  BENCHADD(nrn_nthread)
1107  }
1108 }
1109 
1110 
1111 void nrn_onethread_job(int i, void*(*job)(NrnThread*)) {
1112  BENCHDECLARE
1113  assert(i >= 0 && i < nrn_nthread);
1114 #if USE_PTHREAD
1115  if (nrn_thread_parallel_) {
1116  if (i > 0) {
1117  send_job_to_slave(i, job);
1118  WAIT();
1119  }else{
1120  BENCHBEGIN(0)
1121  (*job)(nrn_threads);
1122  BENCHADD(nrn_nthread)
1123  }
1124  }else{
1125 #else
1126  {
1127 #endif
1128  (*job)(nrn_threads + i);
1129  }
1130 }
1131 
1133 #if USE_PTHREAD
1134  if (nrn_thread_parallel_) {
1135  wait_for_workers();
1136  }
1137 #endif
1138 }
1139 
1141  NrnThread* nt;
1142  assert(it >= 0 && it < nrn_nthread);
1143  nt = nrn_threads + it;
1144  if (nt->userpart == nullptr && nt->roots) {
1145  hoc_l_freelist(&nt->roots);
1146  }
1147  if (sl) {
1148  hoc_obj_ref(sl);
1149  }
1150  if (nt->userpart) {
1151  hoc_obj_unref(nt->userpart);
1152  nt->userpart = nullptr;
1153  nt->roots = (hoc_List*)0;
1154  }
1155  if (sl) {
1156  nt->userpart = sl; /* already reffed above */
1157  nt->roots = (hoc_List*)sl->u.this_pointer;
1158  }
1159  v_structure_change = 1;
1160 }
1161 
1163  int i, it, b, n;
1164  hoc_Item* qsec;
1165  hoc_List* sl;
1166  char buf[256];
1167  Section* sec;
1168  NrnThread* nt;
1169  /* all one or all the other*/
1170  b = (nrn_threads[0].userpart != nullptr);
1171  for (it=1; it < nrn_nthread; ++it) {
1172  if ((nrn_threads[it].userpart != nullptr) != b) {
1173 hoc_execerror("some threads have a user defined partition", "and some do not");
1174  }
1175  }
1176  if (!b) { return 0; }
1177 
1178  /* discard partition if any section mentioned has been deleted. The
1179  model has changed */
1180  FOR_THREADS(nt) {
1181  sl = nt->roots;
1182  ITERATE(qsec, sl) {
1183  sec = hocSEC(qsec);
1184  if (!sec->prop) {
1185  for (i=0; i < nrn_nthread; ++i) {
1186  nrn_thread_partition(i, nullptr);
1187  }
1188  return 0;
1189  }
1190  }
1191  }
1192 
1193  ForAllSections(sec)
1194  sec->volatile_mark = 0;
1195  }
1196  /* fill in ncell and verify consistency */
1197  n = 0;
1198  for (it=0; it < nrn_nthread; ++it) {
1199  nt = nrn_threads + it;
1200  sl = nt->roots;
1201  nt->ncell = 0;
1202  ITERATE(qsec, sl) {
1203  sec = hocSEC(qsec);
1204  ++nt->ncell;
1205  ++n;
1206  if (sec->parentsec) {
1207 sprintf(buf, "in thread partition %d is not a root section", it);
1209  }
1210  if (sec->volatile_mark) {
1211 sprintf(buf, "appeared again in partition %d", it);
1213  }
1214  sec->volatile_mark = 1;
1215  }
1216  }
1218 sprintf(buf, "The total number of cells, %d, is different than the number of user partition cells, %d\n", nrn_global_ncell, n);
1219  hoc_execerror(buf, (char*)0);
1220  }
1221  return 1;
1222 }
1223 
1224 void nrn_use_busywait(int b) {
1225 #if USE_PTHREAD
1227  if (b == 0 && busywait_main_ == 1) {
1228  busywait_ = 0;
1230  busywait_main_ = 0;
1231  }else if (b == 1 && busywait_main_ == 0) {
1232  busywait_main_ = 1;
1233  wait_for_workers();
1234  busywait_ = 1;
1236  }
1237  }else{
1238  if (busywait_main_ == 1) {
1239  busywait_ = 0;
1241  busywait_main_ = 0;
1242  }
1243  }
1244 #endif
1245 }
1246 
1248  int old = allow_busywait_;
1249  allow_busywait_ = b;
1250  return old;
1251 }
1252 
1253 #if USE_PTHREAD
1254 static long waste_;
1255 static void* waste(void* v) {
1256  size_t i, j, n;
1257  n = (size_t)v;
1258  j = 0;
1259  for (i=0; i < n; ++i) {
1260  j += i;
1261  }
1262  /* hoping it is not optimized away */
1263  waste_ = j;
1264  return nullptr;
1265 }
1266 
1267 #define _nt_ 32
1268 static double trial(int ip) {
1269  int i;
1270  double t;
1271  pthread_t* th;
1272  th = (pthread_t*)ecalloc(ip, sizeof(pthread_t));
1273  t = nrn_timeus();
1274  for (i=0; i < ip; ++i) {
1275  pthread_create(th + i, nullptr, waste, (void*)100000000);
1276  }
1277  for (i=0; i < ip; ++i) {
1278  pthread_join(th[i], nullptr);
1279  }
1280  t = nrn_timeus() - t;
1281  free((char*)th);
1282  return t;
1283 }
1284 #endif
1285 
1287 #if USE_PTHREAD
1288  int i, ip;
1289  double t1, t2;
1290  printf("nthread walltime (count to 1e8 on each thread)\n");
1291  t1 = trial(1);
1292  printf("%4d\t %g\n", 1, t1);
1293  for (ip = 2; ip <= _nt_; ip *= 2) {
1294  t2 = trial(ip);
1295  printf("%4d\t %g\n", ip, t2);
1296  if (t2 > 1.3*t1) {
1297  return ip/2;
1298  }
1299  }
1300  return _nt_;
1301 #else
1302  return 1;
1303 #endif
1304 }
1305 
int nrn_use_fast_imem
Definition: fadvance.cpp:162
#define WAIT
Definition: multicore.cpp:80
Node ** _ecell_children
Definition: multicore.h:81
Memb_list ** _ml_list
Definition: multicore.h:63
FOR_THREADS(_nt)
Definition: multicore.cpp:887
double * _actual_d
Definition: multicore.h:71
void * ecalloc(size_t n, size_t size)
Definition: symbol.cpp:221
double * param
Definition: section.h:218
struct Prop * prop
Definition: section.h:62
int _stop_stepping
Definition: multicore.h:67
void * _vnt
Definition: section.h:269
void nrn_multithread_job(void *(*job)(NrnThread *))
Definition: multicore.cpp:1081
void * _pvoid
Definition: hocdec.h:186
#define hocSEC(q)
Definition: hoclist.h:66
Memb_list * ml
Definition: multicore.h:40
void(* nrn_multisplit_setup_)()
Definition: treeset.cpp:46
static int busywait_
Definition: multicore.cpp:48
order
Definition: multicore.cpp:886
struct NrnThreadMembList * next
Definition: multicore.h:34
void nrn_mk_table_check()
Definition: multicore.cpp:1009
#define BENCHBEGIN(arg)
Definition: multicore.cpp:78
int nrn_how_many_processors()
Definition: multicore.cpp:1286
double * _nrn_sav_d
Definition: multicore.h:47
void nrn_thread_table_check()
Definition: multicore.cpp:1050
#define ITERATE(itm, lst)
Definition: model.h:25
void nrn_thread_stat()
Definition: multicore.cpp:459
void
int _ecell_child_cnt
Definition: multicore.h:68
int * _v_parent_index
Definition: multicore.h:76
void * this_pointer
Definition: hocdec.h:231
Node ** _v_parent
Definition: multicore.h:78
Pvmi current
Definition: membfunc.h:33
size_t p
Represent main neuron object computed by single thread.
Definition: multicore.h:58
static double cond(void *v)
Definition: singlech.cpp:339
double * _actual_rhs
Definition: multicore.h:70
#define BS
Definition: multicore.cpp:81
static void * nulljob(NrnThread *nt)
Definition: multicore.cpp:84
void(* nrn_mk_transfer_thread_data_)()
Definition: multicore.cpp:46
NrnThreadBAList * tbl[BEFORE_AFTER_SIZE]
Definition: multicore.h:89
int diam_changed
Definition: cabcode.cpp:23
ForAllSections(sec) sec -> order=-1
Definition: extcelln.cpp:555
void nrn_thread_error(const char *)
Definition: multicore.cpp:453
Memb_func * memb_func
Definition: init.cpp:161
nd
Definition: treeset.cpp:893
void(* thread_cleanup_)(Datum *)
Definition: membfunc.h:50
void nrn_old_thread_save()
Definition: treeset.cpp:2140
#define v
Definition: md1redef.h:4
double ** data
Definition: nrnoc_ml.h:14
Object * userpart
Definition: multicore.h:91
static void nrn_thread_memblist_setup()
Definition: multicore.cpp:855
void hoc_l_freelist(hoc_List **)
int i
Definition: hocdec.h:179
void * hoc_mech
Definition: membfunc.h:54
sprintf(buf," if (secondorder) {\ " int _i;\" " for(_i=0;_i< %d;++_i) {\" " _p[_slist%d[_i]]+=dt *_p[_dlist%d[_i]];\" " }}\", numeqn, listnum, listnum)
Prop ** prop
Definition: nrnoc_ml.h:16
inode
Definition: multicore.cpp:985
int type
Definition: membfunc.h:81
static int * fast_imem_size_
Definition: multicore.cpp:565
void nrn_hoc_lock()
Definition: multicore.cpp:1064
#define BEFORE_AFTER_SIZE
Definition: membfunc.h:78
_nrn_Fast_Imem * _nrn_fast_imem
Definition: multicore.h:82
Datum * _thread
Definition: nrnoc_ml.h:17
int nrn_inthread_
Definition: multicore.cpp:88
short type
Definition: section.h:215
short volatile_mark
Definition: section.h:54
static int nrn_thread_parallel_
Definition: multicore.cpp:55
int id
Definition: multicore.h:66
double _dt
Definition: multicore.h:60
int ncell
Definition: multicore.h:64
void nrn_malloc_unlock()
Definition: multicore.cpp:443
sl
Definition: seclist.cpp:186
int nrn_nthread
Definition: multicore.cpp:44
Node ** _v_node
Definition: multicore.h:77
Memb_list * ml
Definition: multicore.h:35
Memb_list * _ecell_memb_list
Definition: multicore.h:80
#define BENCHADD(arg)
Definition: multicore.cpp:79
int nodecount
Definition: nrnoc_ml.h:18
int nrnmpi_numprocs
_CONST char * s
Definition: system.cpp:74
int nrn_user_partition()
Definition: multicore.cpp:1162
hoc_List * roots
Definition: multicore.h:90
NrnThread * nrn_threads
Definition: multicore.cpp:45
Pvmi state
Definition: membfunc.h:35
double * _nrn_sav_rhs
Definition: multicore.h:46
Section ** secorder
Definition: solve.cpp:77
void hoc_obj_unref(Object *obj)
Definition: hoc_oop.cpp:1998
static void threads_create_pthread()
Definition: multicore.cpp:445
#define printf
Definition: mwprefix.h:26
void(* thread_mem_init_)(Datum *)
Definition: membfunc.h:49
const char * secname(Section *sec)
Definition: cabcode.cpp:1787
#define BENCHDECLARE
Definition: multicore.cpp:77
short * memb_order_
Definition: init.cpp:163
static Node * pnd
Definition: clamp.cpp:33
static void threads_free_pthread()
Definition: multicore.cpp:448
int n_memb_func
Definition: init.cpp:471
void hoc_execerror(const char *, const char *)
Definition: hoc.cpp:741
nrn_bamech_t f
Definition: membfunc.h:80
#define cnt
Definition: spt2queue.cpp:19
void nrn_fast_imem_alloc()
Definition: multicore.cpp:614
char * _sp13mat
Definition: multicore.h:79
void nrn_threads_create(int n, int parallel)
Definition: multicore.cpp:490
size_t j
Datum ** pdata
Definition: nrnoc_ml.h:15
fprintf(stderr, "Don't know the location of params at %p\, pp)
Pvmi initialize
Definition: membfunc.h:36
int section_count
Definition: solve.cpp:76
BAMech ** bamech_
Definition: init.cpp:167
int v_structure_change
Definition: cvodestb.cpp:99
Definition: section.h:213
static void fast_imem_alloc()
Definition: multicore.cpp:588
char * emalloc(unsigned n)
Definition: list.cpp:189
static Datum * table_check_
Definition: multicore.cpp:58
void nrn_malloc_lock()
Definition: multicore.cpp:442
void hoc_obj_ref(Object *obj)
Definition: hoc_oop.cpp:1980
static int allow_busywait_
Definition: multicore.cpp:59
static void thread_memblist_setup(NrnThread *_nt, int *mlcnt, void **vmap)
Definition: multicore.cpp:697
double * _actual_a
Definition: multicore.h:72
int end
Definition: multicore.h:65
Datum * dparam
Definition: section.h:219
void nrn_onethread_job(int i, void *(*job)(NrnThread *))
Definition: multicore.cpp:1111
void nrn_hoc_unlock()
Definition: multicore.cpp:1072
Node ** nodelist
Definition: nrnoc_ml.h:5
static int fast_imem_nthread_
Definition: multicore.cpp:564
double _t
Definition: multicore.h:59
BAMech * bam
Definition: multicore.h:41
int v_node_index
Definition: section.h:174
int nrn_allow_busywait(int b)
Definition: multicore.cpp:1247
int nrnmpi_myid
assert(order==section_count)
Definition: hocdec.h:226
n
Definition: multicore.cpp:1197
int vectorized
Definition: membfunc.h:47
void * _vcv
Definition: multicore.h:83
double * _d
Definition: section.h:144
#define nodecount
Definition: md1redef.h:30
#define i
Definition: md1redef.h:12
int is_point
Definition: membfunc.h:53
#define id
Definition: md1redef.h:33
void(* thread_table_check_)(double *, Datum *, Datum *, NrnThread *, int)
Definition: membfunc.h:51
struct Prop * next
Definition: section.h:214
static int busywait_main_
Definition: multicore.cpp:49
sec
Definition: solve.cpp:885
#define arg
Definition: redef.h:28
void nrn_thread_partition(int it, Object *sl)
Definition: multicore.cpp:1140
static _nrn_Fast_Imem * fast_imem_
Definition: multicore.cpp:566
char buf[512]
Definition: init.cpp:13
double * _actual_area
Definition: multicore.h:75
#define CACHELINE_ALLOC(name, type, size)
Definition: multicore.cpp:41
double * _rhs
Definition: section.h:145
void nrn_use_busywait(int b)
Definition: multicore.cpp:1224
static int table_check_cnt_
Definition: multicore.cpp:57
double _ctime
Definition: multicore.h:86
NrnThreadMembList * tml
Definition: multicore.h:62
static void fast_imem_free()
Definition: multicore.cpp:568
#define spDestroy
Definition: cspredef.h:9
int order
Definition: section.h:52
union Object::@54 u
double t
Definition: init.cpp:123
Definition: section.h:132
struct BAMech * next
Definition: membfunc.h:82
Definition: hocdec.h:176
double nrn_timeus()
Definition: ftime.cpp:61
FILE * fopen()
double * _actual_b
Definition: multicore.h:73
void nrn_threads_free()
Definition: multicore.cpp:626
return NULL
Definition: cabcode.cpp:461
#define CACHELINE_CALLOC(name, type, size)
Definition: multicore.cpp:42
void nrn_wait_for_threads()
Definition: multicore.cpp:1132
double * _actual_v
Definition: multicore.h:74
short index
Definition: cabvars.h:11
struct Extnode * extnode
Definition: section.h:160
static void reorder_secorder()
Definition: multicore.cpp:875
void nrn_multisplit_ptr_update()
int nrn_global_ncell
Definition: init.cpp:127
struct Prop * prop
Definition: section.h:151
struct NrnThreadBAList * next
Definition: multicore.h:42