Skip to content

Conversation

mstimberg
Copy link
Member

This interrupts a "graceful stop" if you interrupt a simulation with Ctrl+C (or e.g. use the interrupt mechanism in a Jupyter notebook). During a simulation run, pressing Ctrl+C will not trigger the usual interrupt (or KeyboardInterrupt), but instead do the equivalent of a Network.stop(), i.e. finish the current time step and then stop the simulation. This means that in particular for scripts that the code after the simulation run will still be run and can analyse/save/plot results. This works for both runtime and C++ standalone simulations.

@thesamovar @bdevans could you please test this on Windows/macOS? I'd use an example that takes a while to run, e.g. COBAHH. After it shows "Starting simulation at t=0. s for a duration of 1. s", you can press Ctrl+C which should output a warning and gracefully shut down the simulation at a time < the requested runtime, e.g.:

Starting simulation at t=0. s for a duration of 1. s
WARNING    Simulation stop requested. Press Ctrl+C again to interrupt. [brian2]
0.5314 s (53%) simulated in 3s, estimated 3s remaining.

If you could test this both in the default runtime mode and with an added set_device('cpp_standalone'), this would be great. In particular for the C++ standalone mechanism, I am not 100% sure whether it works the same on all OSes.
Thanks!

Closes #952

@mstimberg
Copy link
Member Author

OK, I have to admit, I am curious about this new "Copilot review" feature – I will see what it has to say !

@mstimberg mstimberg requested a review from Copilot April 24, 2025 09:34
Copy link

@Copilot Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR implements a graceful stop mechanism that allows a running simulation to finish its current time step when interrupted with Ctrl+C instead of raising an immediate KeyboardInterrupt.

  • Introduces two global flags (_globally_running and _globally_stopped) in the C++ standalone backend to control simulation interruption.
  • Installs a custom signal handler in both C++ (main.cpp) and Python (init.py) to switch between graceful and immediate interruption modes based on the user’s preference.
  • Updates the reporting and preference system to support the new interruption behaviour.

Reviewed Changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
brian2/devices/cpp_standalone/templates/network.cpp Adds global flags and adjusts the simulation run loop to check for graceful stops.
brian2/devices/cpp_standalone/templates/main.cpp Introduces a new signal handler (_int_handler) to process Ctrl+C signals.
brian2/devices/cpp_standalone/device.py Updates the subprocess run calls to set/reset the interruption flags.
brian2/core/network.py Modifies the run method to incorporate the graceful stop mechanism.
brian2/core/core_preferences.py Adds a new preference (stop_on_keyboard_interrupt) to control this behavior.
brian2/init.py Implements a custom _InterruptHandler that translates SIGINT into a simulation stop.
Comments suppressed due to low confidence (1)

brian2/devices/cpp_standalone/templates/main.cpp:38

  • Verify that the signal handler correctly restores the default behavior and safely escalates to a full interrupt on a second Ctrl+C press, particularly in reentrant or multithreaded contexts.
void _int_handler(int signal_num) {

@bdevans
Copy link
Contributor

bdevans commented Apr 24, 2025

Hi @mstimberg,
I cloned the repo and checked out this PR then copied the code from the example into a script and ran that in the root of the cloned repo, which gave the following for the default runtime mode on macOS:

~ % python COBAHH.py
Cannot determine Brian version, running from source and setuptools_scm is not installed.
/opt/anaconda3/lib/python3.12/site-packages/setuptools/_distutils/_msvccompiler.py:12: UserWarning: _get_vc_env is private; find an alternative (pypa/distutils#340)
  warnings.warn(
WARNING    Cannot use Cython, a test compilation failed: Cython is not available (ImportError)
Certain compiler configurations (e.g. clang in a conda environment on OS X) are known to be problematic. Note that you can switch the compiler by setting the 'CC' and 'CXX' environment variables. For example, you may want to try 'CC=gcc' and 'CXX=g++'. [brian2.codegen.runtime.cython_rt.cython_rt.failed_compile_test]
INFO       Cannot use compiled code, falling back to the numpy code generation target. Note that this will likely be slower than using compiled code. Set the code generation to numpy manually to avoid this message:
prefs.codegen.target = "numpy" [brian2.devices.device.codegen_fallback]
Starting simulation at t=0. s for a duration of 1. s
0.6556 s (65%) simulated in 10s, estimated 5s remaining.
^CWARNING    Simulation stop requested. Press Ctrl+C again to interrupt. [brian2]
0.9643 s (96%) simulated in 14s, estimated 1s remaining.
2025-04-24 12:01:31.850 python[35498:168529363] +[IMKClient subclass]: chose IMKClient_Modern
2025-04-24 12:01:31.850 python[35498:168529363] +[IMKInputSession subclass]: chose IMKInputSession_Modern

When I hit Ctrl+C, the expected message was produced but the simulation stopped immediately and produced a figure.

After adding the standalone target to the script, I reran it and got the same behaviour as for the runtime mode, with the simulation stopping immediately:

~ % python COBAHH.py
Cannot determine Brian version, running from source and setuptools_scm is not installed.
/opt/anaconda3/lib/python3.12/site-packages/setuptools/_distutils/_msvccompiler.py:12: UserWarning: _get_vc_env is private; find an alternative (pypa/distutils#340)
  warnings.warn(
Starting simulation at t=0 s for duration 1 s
^C0.1888 s (18%) simulated in < 1s, estimated 3s remaining.
WARNING    Simulation stop requested. Press Ctrl+C again to interrupt. [brian2]
2025-04-24 12:06:33.208 python[40124:168544172] +[IMKClient subclass]: chose IMKClient_Modern
2025-04-24 12:06:33.208 python[40124:168544172] +[IMKInputSession subclass]: chose IMKInputSession_Modern

These were run on a Macbook Pro M1 Max and I believe the standalone target was compiled with clang.

@mstimberg
Copy link
Member Author

Thanks @bdevans, so this looks good for macOS, then. I assume you get the weird IMK... output also when you run anything else that opens a window with matplotlib, i.e. this is not specific to Brian?

@bdevans
Copy link
Contributor

bdevans commented Apr 24, 2025

I assume you get the weird IMK... output also when you run anything else that opens a window with matplotlib, i.e. this is not specific to Brian?

I just tested it at the terminal by launching python and creating a blank figure - the same messages then appeared when I clicked on the figure window.

@thesamovar
Copy link
Member

Works on Windows on my machine. Although it made me realise I don't know how to properly install the dev version of Brian any more! Do I really need to install MSVC build tools still? I thought Conda had solved that? I know that you don't have to when installing it via conda.

@mstimberg
Copy link
Member Author

Works on Windows on my machine.

Great, thanks!

Although it made me realise I don't know how to properly install the dev version of Brian any more! Do I really need to install MSVC build tools still? I thought Conda had solved that? I know that you don't have to when installing it via conda.

I don't actually know to be honest… According to the meta.yaml file of our conda package, we are only installing a compiler on UNIX systems, but the basic packaging test that runs for every conda package build runs a simulation with Cython, so it certainly has access to msvc on Windows. But it might also simply be because it runs on GitHub, and GitHub has Visual Studio pre-installed on the Windows runners.

@mstimberg mstimberg merged commit de316f0 into master Apr 30, 2025
64 checks passed
@mstimberg mstimberg deleted the interrupt_hook branch April 30, 2025 08:53
@thesamovar
Copy link
Member

I know that I can run compiled Brian scripts in my environment where I just conda install Brian, but can't do a pip install -e . in a fresh environment.

@thesamovar
Copy link
Member

I'll look into it! Maybe we can update the docs a bit if I get to the bottom of it.

@mstimberg
Copy link
Member Author

That would be great, thanks.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Create a mechanism to interrupt a simulation
3 participants