Skip to content

Commit 3f3b297

Browse files
authored
Merge pull request #1390 from denisalevi/add-code-slots-around-run
Add `before_network_run` & `after_network_run` code slots for `insert_code` mechanism
2 parents ff3267e + d5cdbd2 commit 3f3b297

File tree

2 files changed

+56
-6
lines changed

2 files changed

+56
-6
lines changed

brian2/devices/cpp_standalone/device.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,8 @@ def __init__(self):
196196
#: Note that the main slot is handled separately as part of `main_queue`
197197
self.code_lines = {'before_start': [],
198198
'after_start': [],
199+
'before_network_run': [],
200+
'after_network_run': [],
199201
'before_end': [],
200202
'after_end': []}
201203

@@ -1479,7 +1481,9 @@ def network_run(self, net, duration, report=None, report_period=10*second,
14791481
if clock not in all_clocks:
14801482
run_lines.append(f'{net.name}.add(&{clock.name}, NULL);')
14811483

1484+
run_lines.extend(self.code_lines['before_network_run'])
14821485
run_lines.append(f'{net.name}.run({float(duration)!r}, {report_call}, {float(report_period)!r});')
1486+
run_lines.extend(self.code_lines['after_network_run'])
14831487
self.main_queue.append(('run_network', (net, run_lines)))
14841488

14851489
net.after_run()

docs_sphinx/user/computation.rst

Lines changed: 52 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -143,12 +143,7 @@ something like this may not behave as you would like::
143143

144144
The current C++ standalone code generation only works for a fixed number of `~Network.run` statements, not with loops.
145145
If you need to do loops or other features not supported automatically, you can do so by inspecting the generated
146-
C++ source code and modifying it, or by inserting code directly into the main loop as follows::
147-
148-
device.insert_code('main', '''
149-
cout << "Testing direct insertion of code." << endl;
150-
''')
151-
146+
C++ source code and modifying it, or by inserting code directly into the main loop as described below.
152147

153148
Variables
154149
~~~~~~~~~
@@ -177,6 +172,57 @@ of the number of threads. However, this is working fine for networks with not
177172
too small timestep (dt > 0.1ms), and results do not depend on the number of
178173
threads used in the simulation.
179174

175+
Custom code injection
176+
~~~~~~~~~~~~~~~~~~~~~
177+
It is possible to insert custom code directly into the generated code of a
178+
standalone simulation using a Device's `~.Device.insert_code` method::
179+
180+
device.insert_code(slot, code)
181+
182+
``slot`` can be one of ``main``, ``before_start``, ``after_start``,
183+
``before_network_run``, ``after_network_run``, ``before_end`` and ``after_end``,
184+
which determines where the code is inserted. ``code`` is the code in the
185+
Device's language. Here is an example for the C++ Standalone Device::
186+
187+
device.insert_code('main', '''
188+
cout << "Testing direct insertion of code." << endl;
189+
''')
190+
191+
For the C++ Standalone Device, all code is inserted into the ``main.cpp`` file,
192+
here into the ``main`` slot, referring to the main simulation function.
193+
This is a simplified version of this function in ``main.cpp``::
194+
195+
int main(int argc, char **argv)
196+
{
197+
// before_start
198+
brian_start();
199+
// after_start
200+
201+
{{main_lines}}
202+
203+
// before_end
204+
brian_end();
205+
// after_end
206+
207+
return 0;
208+
}
209+
210+
``{{main_lines}}`` is replaced in the generated code with the actual simulation.
211+
Code inserted into the ``main`` slot will be placed within the
212+
``{{main_lines}}``. ``brian_start`` allocates and initializes all arrays needed
213+
during the simulation and ``brian_end`` writes the results to disc and
214+
deallocates memory. Within the ``{{main_lines}}``, all ``Network`` objects
215+
defined in Python are created and run. Code inserted in the
216+
``before/after_network_run`` slot will be inserted around the ``Network.run``
217+
call, which starts the time loop. Note that if your Python script has multiple
218+
``Network`` objects or multiple ``run`` calls, code in the
219+
``before/after_network_run`` slot will be inserted around each ``Network.run``
220+
call in the generated code.
221+
222+
The code injection mechanism has been used for benchmarking experiments, see
223+
e.g. `here for Brian2CUDA benchmarks <https://github.com/brian-team/brian2cuda/blob/835c978ad758bc0621e34344c1fb7b811ef8a118/brian2cuda/tests/features/cuda_configuration.py#L148-L156>`_ or `here for Brian2GeNN benchmarks <https://github.com/brian-team/brian2genn_benchmarks/blob/6d1a6d9d97c05653cec2e413c9fd312cfe13e15c/benchmark_utils.py#L78-L136>`_.
224+
225+
180226
.. _standalone_custom_build:
181227

182228
Customizing the build process

0 commit comments

Comments
 (0)