@@ -27,14 +27,17 @@ THE POSSIBILITY OF SUCH DAMAGE.
2727*/
2828
2929#include < iostream>
30+ #include < sstream>
31+ #include < string.h>
3032#include < stdexcept> // std::lenght_error
3133#include < vector>
3234#include " coreneuron/nrnconf.h"
3335#include " coreneuron/nrniv/nrniv_decl.h"
3436#include " coreneuron/nrniv/output_spikes.h"
3537#include " coreneuron/nrnmpi/nrnmpi.h"
3638#include " coreneuron/nrniv/nrnmutdec.h"
37- #include " coreneuron/utils/sdprintf.h"
39+ #include " coreneuron/nrnmpi/nrnmpi_impl.h"
40+ #include " coreneuron/nrnmpi/nrnmpidec.h"
3841
3942std::vector<double > spikevec_time;
4043std::vector<int > spikevec_gid;
@@ -55,28 +58,113 @@ static MUTDEC
5558void spikevec_lock () {
5659 MUTLOCK
5760}
61+
5862void spikevec_unlock () {
5963 MUTUNLOCK
6064}
6165
62- void output_spikes (const char * outpath) {
63- char fnamebuf[100 ];
64- sd_ptr fname = sdprintf (fnamebuf, sizeof (fnamebuf), " %s/out%d.dat" , outpath, nrnmpi_myid);
65- FILE* f = fopen (fname, " w" );
66+ #if NRNMPI
67+ /* * Write generated spikes to out.dat using mpi parallel i/o.
68+ * \todo : MPI related code should be factored into nrnmpi.c
69+ * Check spike record length which is set to 64 chars
70+ */
71+ void output_spikes_parallel (const char * outpath) {
72+ std::stringstream ss;
73+ ss << outpath << " /out.dat" ;
74+ std::string fname = ss.str ();
75+
76+ // remove if file already exist
77+ if (nrnmpi_myid == 0 ) {
78+ remove (fname.c_str ());
79+ }
80+ nrnmpi_barrier ();
81+
82+ // each spike record in the file is time + gid (64 chars sufficient)
83+ const int SPIKE_RECORD_LEN = 64 ;
84+ unsigned num_spikes = spikevec_gid.size ();
85+ unsigned num_bytes = (sizeof (char ) * num_spikes * SPIKE_RECORD_LEN);
86+ char *spike_data = (char *) malloc (num_bytes);
87+
88+ if (spike_data == NULL ) {
89+ printf (" Error while writing spikes due to memory allocation\n " );
90+ return ;
91+ }
92+
93+ // empty if no spikes
94+ strcpy (spike_data, " " );
95+
96+ // populate buffer with all spike entries
97+ char spike_entry[SPIKE_RECORD_LEN];
98+ for (unsigned i = 0 ; i < num_spikes; i++) {
99+ snprintf (spike_entry, 64 , " %.8g\t %d\n " , spikevec_time[i], spikevec_gid[i]);
100+ strcat (spike_data, spike_entry);
101+ }
102+
103+ // calculate offset into global file. note that we don't write
104+ // all num_bytes but only "populated" buffer
105+ unsigned long num_chars = strlen (spike_data);
106+ unsigned long offset = 0 ;
107+
108+ // global offset into file
109+ MPI_Exscan (&num_chars, &offset, 1 , MPI_UNSIGNED_LONG, MPI_SUM, MPI_COMM_WORLD);
110+
111+ // write to file using parallel mpi i/o
112+ MPI_File fh;
113+ MPI_Status status;
114+
115+ // ibm mpi (bg-q) expects char* instead of const char* (even though it's standard)
116+ int op_status = MPI_File_open (MPI_COMM_WORLD, (char *) fname.c_str (), MPI_MODE_CREATE | MPI_MODE_WRONLY, MPI_INFO_NULL, &fh);
117+ if (op_status != MPI_SUCCESS && nrnmpi_myid == 0 ) {
118+ std::cerr << " Error while opening spike output file " << fname << std::endl;
119+ abort ();
120+ }
121+
122+ op_status = MPI_File_write_at_all (fh, offset, spike_data, num_chars, MPI_BYTE, &status);
123+ if (op_status != MPI_SUCCESS && nrnmpi_myid == 0 ) {
124+ std::cerr << " Error while writing spike output " << std::endl;
125+ abort ();
126+ }
127+
128+ MPI_File_close (&fh);
129+ }
130+ #endif
131+
132+ void output_spikes_serial (const char * outpath) {
133+ std::stringstream ss;
134+ ss << outpath << " /out.dat" ;
135+ std::string fname = ss.str ();
136+
137+ // remove if file already exist
138+ remove (fname.c_str ());
139+
140+ FILE* f = fopen (fname.c_str (), " w" );
66141 if (!f && nrnmpi_myid == 0 ) {
67142 std::cout << " WARNING: Could not open file for writing spikes." << std::endl;
68143 return ;
69144 }
70145
71- for (int i = 0 ; i < spikevec_gid.size (); ++i)
146+ for (unsigned i = 0 ; i < spikevec_gid.size (); ++i)
72147 if (spikevec_gid[i] > -1 )
73148 fprintf (f, " %.8g\t %d\n " , spikevec_time[i], spikevec_gid[i]);
74149
75150 fclose (f);
76151}
77152
153+ void output_spikes (const char * outpath) {
154+ #if NRNMPI
155+ if (nrnmpi_initialized ()) {
156+ output_spikes_parallel (outpath);
157+ } else {
158+ output_spikes_serial (outpath);
159+ }
160+ #else
161+ output_spikes_serial (outpath);
162+ #endif
163+ }
164+
165+
78166void validation (std::vector<std::pair<double , int > >& res) {
79- for (int i = 0 ; i < spikevec_gid.size (); ++i)
167+ for (unsigned i = 0 ; i < spikevec_gid.size (); ++i)
80168 if (spikevec_gid[i] > -1 )
81169 res.push_back (std::make_pair (spikevec_time[i], spikevec_gid[i]));
82170}
0 commit comments