nrngui initonerun.hoconerun(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.hocmpiexec -n N nrniv -mpi initbatpar.hocinitbatpar.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")
}