nrngui initonerun.hoc
onerun(x)
onerun(0.3)
initonerun.hoc is organized in a modular fashion. Only highlights are mentioned.
nrngui initbatser.hoc
initbatser.hoc is based on initonerun.hoc. Only significant differences are mentioned.
trun = startsw()
records system time at the beginning of the code
whose run time will be evaluated.for
loop that iterates the run counter ii
from 0 to NRUNS-1. Each pass through this loop results in a new simulation with a
new stimulus amplitude, finds the spike frequency, and saves the stimulus amplitude
and frequency to a pair of vectors. It also prints a "." to the terminal to indicate
progress.
nrngui initbatpar.hoc
mpiexec -n N nrniv -mpi initbatpar.hoc
initbatpar.hoc is based on initbatser.hoc. Only key differences are mentioned below. Note that many statements have been wrapped in paried curly brackets { } to suppress printing of undesired return values (0s, 1s, etc.).
The serial program initbatser.hoc has a proc batchrun() that uses
this for
loop
to execute a series of simulations, one at a time, on a single processor:
for ii=0,$1-1 { setparams(ii) // set parameters for this run run() postproc() // analyze the data svec.append(stim.amp) fvec.append(freq) printf(".") // indicate progress }In initbatpar.hoc, everything that can be offloaded to the workers has been taken out of batchrun() and inserted into a new
func fi()
that is defined prior to batchrun().
func fi() { // set params, execute a simulation, analyze and return results setparams($1) // set parameters for this run run() postproc() // analyze the data return freq }Notice that
fi()
contains the procedures that involve the most computational
overhead. Also notice that fi()
expects a single numerical argument,
and returns a single numerical result.
This is how the implementation of fi()
tries to satisfy
the aim of keeping the workers busy,
while minimizing communication overhead.
Here is the heart of initbatpar.hoc's batchrun() procedure:
for ii = 0, $1-1 pc.submit("fi", ii) // post all jobs to bulletin board // retrieve results from bulletin board while (pc.working) { // is a result ready? fvec.append(pc.retval()) // get frequency pc.unpack(&tmp) // get job number svec.append(tmp) printf(".") // indicate progress }There still is a
for
loop,
but it uses pc.submit() to post jobs to the bulletin board.
Communication is minimized by passing only the name of a function ("fi" of course)
and the simulation index ii for each run that is to be carried out.
Next comes a while
loop
in which the master checks the bulletin board
for returned results.
If nothing is found, the master picks a task from the bulletin board
and executes it.
If a result is present, the master retrieves it from the bulletin board:
pc.retval() gets the value returned by fi()
,
and pc.unpack(&tmp) gets the job number into tmp.
The job number starts at 0 and increments by 1 each time
another job is posted,
so it is identical to the simulation index.
After the last job has been completed,
the master exits the while
loop,
and batchrun() is finished.
Then pc.done() releases the workers.
But the master still has some work to do.
fvec = fvec.index(svec.sortindex()) // rearrange fvec according to svec sortindex { svec.sort() // but svec contains job numbers, not actual stimulus currents svec.apply("fstimamp") }