1 #include "utils/profile/profiler_interface.h"
2 #include <../../nrnconf.h>
12 #include <unordered_map>
16 #define MD 2147483648.
89 std::vector<int>& spikegidvec);
98 extern void nrnmpi_split_clear();
106 #include "../nrnmpi/mpispike.h"
108 void nrn_timeout(
int);
112 bool nrn_use_compress_;
113 #define use_compress_ nrn_use_compress_
116 extern int ncs_multisend_sending_info(
int**);
117 extern int ncs_multisend_target_hosts(
int,
int**);
118 extern int ncs_multisend_target_info(
int**);
119 extern int ncs_multisend_mindelays(
int**,
double**);
122 int ncs_netcon_mindelays(
int** hosts,
double** delays) {
123 return ncs_multisend_mindelays(hosts, delays);
126 double ncs_netcon_localmindelay(
int srcgid) {
132 int ncs_netcon_count(
int srcgid,
bool localNetCons) {
134 const auto& iter =
map.find(srcgid);
135 PreSyn* ps{iter !=
map.end() ? iter->second :
nullptr};
138 fprintf(stderr,
"should never happen!\n");
142 return ps->
dil_.count();
146 void ncs_netcon_inject(
int srcgid,
int netconIndex,
double spikeTime,
bool localNetCons) {
149 const auto& iter =
map.find(srcgid);
150 PreSyn* ps{iter !=
map.end() ? iter->second :
nullptr};
163 int ncs_gid_receiving_info(
int** presyngids) {
164 return ncs_multisend_target_info(presyngids);
168 int ncs_gid_sending_count(
int** sendlist2build) {
169 return ncs_multisend_sending_info(sendlist2build);
172 int ncs_target_hosts(
int gid,
int** targetnodes) {
173 return ncs_multisend_target_hosts(gid, targetnodes);
181 static std::vector<std::unique_ptr<Gid2PreSyn>> localmaps_;
183 static int nsend_, nsendmax_, nrecv_, nrecv_useful_;
186 static int ocapacity_;
190 static int spfixout_capacity_;
192 static void nrn_spike_exchange_compressed(
NrnThread*);
224 #if NRN_ENABLE_THREADS
227 static std::atomic<int> seqcnt_;
324 inline static void sppk(
unsigned char*
c,
int gid) {
330 inline static int spupk(
unsigned char*
c) {
347 if (idxout_ >= spfixout_capacity_) {
348 spfixout_capacity_ *= 2;
350 spfixout_capacity_ *
sizeof(
unsigned char));
370 if (idxout_ >= spfixout_capacity_) {
371 spfixout_capacity_ *= 2;
373 spfixout_capacity_ *
sizeof(
unsigned char));
384 #if nrn_spikebuf_size == 0
386 if (
i >= ocapacity_) {
398 if (
i >= ocapacity_) {
407 spbufout_->gid[
i] = gid;
408 spbufout_->spiketime[
i] = firetime;
457 #include "multisend.cpp"
485 hoc_execerror(
"usable mindelay is 0",
"(or less than dt for fixed step method)");
528 #if nrn_spikebuf_size > 0
530 spbufout_->nspike = 0;
535 nsend_ = nsendmax_ = nrecv_ = nrecv_useful_ = 0;
538 #if NRN_ENABLE_THREADS
566 nrn_spike_exchange_compressed(nt);
577 if (nsendmax_ <
nout_) {
580 #if nrn_spikebuf_size > 0
581 spbufout_->nspike =
nout_;
593 tbuf_[itbuf_++] = (
unsigned long)
nout_;
594 tbuf_[itbuf_++] = (
unsigned long)
n;
603 if (max_histogram_) {
610 if (max_histogram_) {
614 #if nrn_spikebuf_size == 0
619 if (mx < spbufin_[
i].nspike) {
620 mx = spbufin_[
i].nspike;
626 mx = (mx <
ms) ? mx :
ms;
629 #if nrn_spikebuf_size > 0
632 int nn = spbufin_[
i].nspike;
636 for (
j = 0;
j < nn; ++
j) {
637 auto iter =
gid2in_.find(spbufin_[
i].gid[
j]);
639 PreSyn* ps = iter->second;
647 for (
i = 0;
i <
n; ++
i) {
650 PreSyn* ps = iter->second;
659 void nrn_spike_exchange_compressed(
NrnThread* nt) {
672 if (nsendmax_ <
nout_) {
697 tbuf_[itbuf_++] = (
unsigned long)
nout_;
698 tbuf_[itbuf_++] = (
unsigned long)
n;
707 if (max_histogram_) {
715 if (max_histogram_) {
725 mx = (mx <
ms) ? mx :
ms;
747 for (
j = 0;
j < nnn; ++
j) {
752 auto iter = gps->find(lgid);
753 if (iter != gps->end()) {
754 PreSyn* ps = iter->second;
759 for (;
j < nn; ++
j) {
763 auto iter = gps->find(lgid);
764 if (iter != gps->end()) {
765 PreSyn* ps = iter->second;
780 for (
j = 0;
j < nn; ++
j) {
787 PreSyn* ps = iter->second;
795 for (
i = 0;
i <
n; ++
i) {
801 PreSyn* ps = iter->second;
812 static void mk_localgid_rep() {
832 int* sbuf =
new int[ngidmax + 1];
841 ps->localgid_ = (
unsigned char) ngid;
867 sbuf = rbuf +
i * (ngidmax + 1);
869 for (
int k = 0;
k < ngid; ++
k) {
870 auto iter =
gid2in_.find(
int(sbuf[
k]));
872 PreSyn* ps = iter->second;
873 (*localmaps_[
i])[
k] = ps;
912 }
else if (fake_out && !ps) {
937 #if nrn_spikebuf_size > 0
938 spbufout_ = (NRNMPI_Spikebuf*)
hoc_Emalloc(
sizeof(NRNMPI_Spikebuf));
957 "gid=%d already exists as an input port. Setup all the output ports on this "
958 "process before using them as input ports.",
962 hoc_execerr_ext(
"gid=%d already exists on this process as an output port", gid);
989 if (arg == 0 || arg == 3 || arg == 4) {
992 nrnmpi_split_clear();
995 if (arg == 0 || arg == 2 || arg == 4) {
998 if (arg == 2 || arg == 3) {
1003 PreSyn* ps = iter.second;
1013 if (ps->
dil_.empty()) {
1019 for (
const auto& iter:
gid2in_) {
1020 PreSyn* ps = iter.second;
1029 if (ps->
dil_.empty()) {
1043 PreSyn* ps = iter->second;
1061 hoc_execerror(
"gid not associated with spike generation location", 0);
1063 PreSyn* ps = iter->second;
1075 "gid=%d is in the input list. Must register with pc.set_gid2node prior to connecting",
1090 if (ps->
gid_ >= 0 && ps->
gid_ != gid) {
1091 hoc_execerr_ext(
"Can't associate gid %d. PreSyn already associated with gid %d.",
1107 PreSyn* ps = iter->second;
1119 PreSyn* ps = iter->second;
1121 ps->
record(spikevec, gidvec, gid);
1126 PreSyn* ps = iter.second;
1140 for (
int i = 0;
i < sz; ++
i) {
1141 int gid = int(pd[
i]);
1144 PreSyn* ps = iter->second;
1146 ps->
record(spikevec, gidvec, gid);
1155 PreSyn* ps = iter->second;
1172 PreSyn* ps = iter->second;
1200 auto iter_out =
gid2out_.find(gid);
1203 ps = iter_out->second;
1208 auto iter_in =
gid2in_.find(gid);
1209 if (iter_in !=
gid2in_.end()) {
1211 ps = iter_in->second;
1217 ps =
new PreSyn({},
nullptr,
nullptr);
1230 nc = (
NetCon*) ((*po)->u.this_pointer);
1232 hoc_execerror(
"target is different from 3rd arg NetCon target", 0);
1236 nc =
new NetCon(ps, target);
1276 hoc_execerror(
"mindelay is 0",
"(or less than dt for fixed step method)");
1321 std::vector<int>& spikegidvec) {
1322 assert(spiketvec.size() == spikegidvec.size());
1323 if (spiketvec.size()) {
1335 spikegidvec.begin(),
1339 for (
size_t i = 0;
i < spikegidvec.size(); ++
i) {
1340 auto iter =
gid2out_.find(spikegidvec[
i]);
1342 PreSyn* ps = iter->second;
1366 for (
const auto& iter:
gid2in_) {
1367 PreSyn* ps = iter.second;
1377 if (use_compress_) {
1395 "Notice: The global minimum NetCon delay is %g, so turned off the "
1396 "cvode.queue_mode\n",
1398 Printf(
" use_self_queue option. The interprocessor minimum NetCon delay is %g\n",
1422 *nsendmax = nsendmax_;
1424 *nrecv_useful = nrecv_useful_;
1432 if (max_histogram_) {
1433 max_histogram_ =
NULL;
1436 max_histogram_ = mh;
1514 use_compress_ =
false;
1516 }
else if (nspike > 0) {
1519 hoc_warning(
"ParallelContext.spike_compress cannot be used with cvode active", 0);
1521 use_compress_ =
false;
1525 use_compress_ =
true;
1533 "Notice: gid compression did not succeed. Probably more than 255 cells on one "
1559 return iter->second;
1571 return iter->second;
1576 PreSyn* ps = iter.second;
1580 (*callback)(gid,
c);
1594 size_t ntot, nin, nout, nnet, nweight;
1595 ntot = nin = nout = nnet = nweight = 0;
1598 printf(
"size Presyn=%ld NetCon=%ld Point_process=%ld Prop=%ld\n",
1605 PreSyn* ps = iter.second;
1608 int n = ps->
dil_.size();
1610 for (
auto nc: ps->
dil_) {
1619 for (
const auto& iter:
gid2in_) {
1620 PreSyn* ps = iter.second;
1623 int n = ps->
dil_.size();
1625 for (
auto nc: ps->
dil_) {
1634 ntot = (nin + nout) *
sizeof(
PreSyn) + nnet *
sizeof(
NetCon) + nweight *
sizeof(
double);
static void nrnmpi_int_allgather(int *s, int *r, int n)
static void nrnmpi_barrier()
static int nrnmpi_int_allmax(int x)
void setup_topology(void)
void spike_record(int, IvocVect *, IvocVect *)
Object ** gid_connect(int)
void set_gid2node(int, int)
void netpar_solve(double)
IvocVect * netpar_max_histogram(IvocVect *)
void netpar_spanning_statistics(int *, int *, int *, int *)
double netpar_mindelay(double maxdelay)
auto end() const -> std::vector< double >::const_iterator
std::vector< double > & vec()
void replace_src(PreSyn *)
std::vector< PreSyn * > * psl_
TQItem * bin_event(double tdeliver, DiscreteEvent *, NrnThread *)
void deliver_events(double til, NrnThread *)
void psl_append(PreSyn *)
TQItem * event(double tdeliver, DiscreteEvent *, NrnThread *)
virtual void savestate_write(FILE *)
virtual void pgvts_deliver(double t, NetCvode *)
virtual DiscreteEvent * savestate_save()
static DiscreteEvent * savestate_read(FILE *)
virtual void send(double, NetCvode *, NrnThread *)
virtual void savestate_restore(double deliverytime, NetCvode *)
virtual void deliver(double, NetCvode *, NrnThread *)
virtual void pr(const char *, double t, NetCvode *)
virtual void send(double sendtime, NetCvode *, NrnThread *)
PreSyn(neuron::container::data_handle< double > src, Object *osrc, Section *ssrc=nullptr)
void record(IvocVect *, IvocVect *idvec=nullptr, int rec_id=0)
#define nrn_spikebuf_size
double chkarg(int, double low, double high)
void hoc_execerr_ext(const char *fmt,...)
printf style specification of hoc_execerror message.
Object ** hoc_temp_objvar(Symbol *symtemp, void *v)
void check_obj_type(Object *obj, const char *type_name)
char * hoc_object_name(Object *ob)
Symbol * hoc_lookup(const char *)
Point_process * ob2pntproc(Object *ob)
Object ** hoc_objgetarg(int)
static double map(void *v)
static double nrnmpi_wtime()
phase
Reading phase number.
double * vector_vec(IvocVect *v)
void nrn2ncs_outputevent(int netcon_output_index, double firetime)
void hoc_execerror(const char *s1, const char *s2)
void nrn_outputevent(unsigned char, double)
void nrn_multisend_receive(NrnThread *)
int vector_capacity(IvocVect *v)
void hoc_warning(const char *s1, const char *s2)
void * hoc_Emalloc(size_t)
int is_point_process(Object *)
#define nrn_assert(x)
assert()-like macro, independent of NDEBUG status
int const size_t const size_t n
void nrn_multisend_setup()
TBUF void nrn_multisend_send(PreSyn *ps, double t)
void nrn_multisend_cleanup_presyn(PreSyn *ps)
static void nrn_multisend_init()
static void nrn_multisend_cleanup()
void nrn_partrans_clear()
static IvocVect * all_spikegidvec
Gid2PreSyn & nrn_gid2out()
short * nrn_is_artificial_
void nrn_gidout_iter(PFIO)
static double t_exchange_
static NRNMPI_Spike * spikein_
static Gid2PreSyn gid2out_
double nrn_multisend_receive_time(int)
static int localgid_size_
static Symbol * netcon_sym_
static int weightcnt(NetCon *nc)
static Object * gid2obj_(int gid)
int nrnthread_all_spike_vectors_return(std::vector< double > &spiketvec, std::vector< int > &spikegidvec)
NEURON callback used from CORENEURON to transfer all spike vectors after simulation.
void ncs2nrn_integrate(double tstop)
void nrn_cleanup_presyn(PreSyn *)
static Gid2PreSyn gid2in_
static int n_multisend_interval
static NRNMPI_Spike * spikeout_
static int ovfl_capacity_
void nrn_spike_exchange_init()
void nrn_spike_exchange(NrnThread *)
static double min_interprocessor_delay_
double nrn_usable_mindelay()
PreSyn * nrn_gid2outputpresyn(int gid)
static unsigned char * spfixout_
void nrn_fake_fire(int gid, double spiketime, int fake_out)
PreSyn * nrn_gid2presyn(int)
void nrnmpi_multisplit_clear()
std::unordered_map< int, PreSyn * > Gid2PreSyn
int * nrn_prop_param_size_
static int nrn_need_npe()
static double set_mindelay(double maxdelay)
static NetParEvent * npe_
static int gid_donot_remove
void(* PFIO)(int, Object *)
static unsigned char * spfixin_
static int ag_send_nspike_
static double last_maxstep_arg_
static double usable_mindelay_
void nrnmpi_gid_clear(int)
int nrnmpi_spike_compress(int nspike, bool gid_compress, int xchng_meth)
static void alloc_space()
Object * nrn_sec2cell(Section *)
Symbol * nrn_netcon_sym()
static unsigned char * spfixin_ovfl_
NetCvode * net_cvode_instance
static IvocVect * all_spiketvec
static void calc_actual_mindelay()
size_t nrncore_netpar_bytes()
Object * nrn_gid2obj(int)
void nrn_pending_selfqueue(double, NrnThread *)
void nrnmusic_runtime_phase()
#define MUTCONSTRUCT(mkmut)
void * hoc_Erealloc(void *ptr, std::size_t size)
Object ** hoc_temp_objptr(Object *)
Represent main neuron object computed by single thread.
A point process is computed just like regular mechanisms.
int Printf(const char *fmt, Args... args)