Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

handle spikes /tstop when running forever #1501

Open
wants to merge 8 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 21 additions & 12 deletions spynnaker/pyNN/utilities/neo_buffer_database.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@
import neo # type: ignore[import]

from spinn_utilities.log import FormatAdapter
from spinn_utilities.logger_utils import warn_once

from spinnman.messages.eieio.data_messages import EIEIODataHeader


Expand Down Expand Up @@ -170,19 +172,22 @@ def write_t_stop(self) -> None:
The database must be writable for this to work!
"""
t_stop = SpynnakerDataView.get_current_run_time_ms()
if t_stop == 0:
if SpynnakerDataView.get_current_run_timesteps() is None:
return
self.execute(
"""
UPDATE segment
SET t_stop = ?
""", (t_stop,))

def __get_segment_info(self) -> Tuple[int, datetime, float, float, str]:
def __get_segment_info(
self) -> Tuple[int, datetime, Optional[float], float, str]:
"""
Gets the metadata for the segment.

:return: segment number, record time, last run time recorded,
simulator timestep in ms, simulator name
:rtype: tuple(int, ~datetime.datetime, float, float, str)
:raises \
~spinn_front_end_common.utilities.exceptions.ConfigurationException:
If the recording metadata not setup correctly
Expand All @@ -195,14 +200,9 @@ def __get_segment_info(self) -> Tuple[int, datetime, float, float, str]:
"""):
t_str = self._string(row[self._REC_DATETIME])
time = datetime.strptime(t_str, "%Y-%m-%d %H:%M:%S.%f")
if row[self._T_STOP] is None:
t_stop = 0.0
logger.warning("Data from a virtual run will be empty")
else:
t_stop = row[self._T_STOP]
return (row[self._SEGMENT_NUMBER], time, t_stop, row[self._DT],
self._string(row[self._SIMULATOR]))
raise ConfigurationException(
return (row[self._SEGMENT_NUMBER], time, row[self._T_STOP],
row[self._DT], self._string(row[self._SIMULATOR]))
raise ConfigurationException(
"No recorded data. Did the simulation run?")

def __get_simulation_time_step_ms(self) -> float:
Expand Down Expand Up @@ -1152,13 +1152,22 @@ def __add_data(
rec_id, view_indexes, buffer_type,
n_colour_bits, variable)
sampling_rate = 1000 / sampling_interval_ms * quantities.Hz
if t_stop is None:
if len(spikes) == 0:
t_stop = 0
warn_once(logger, "No spike data. Setting end time to 0")
else:
t_stop = numpy.amax(spikes, 0)[1]
warn_once(logger, "Unknown how long the simulation ran. "
"So using max spike as stop time")
self._insert_spike_data(
view_indexes, segment, spikes, t_start, t_stop,
sampling_rate)

def __read_and_csv_data(
self, pop_label: str, variable: str, csv_writer: CSVWriter,
view_indexes: ViewIndices, t_stop: float, allow_missing: bool):
view_indexes: ViewIndices, t_stop: Optional[float],
allow_missing: bool):
"""
Reads the data for one variable and adds it to the CSV file.

Expand All @@ -1173,7 +1182,7 @@ def __read_and_csv_data(
:param ~csv.writer csv_writer: Open CSV writer to write to
:param view_indexes:
:type view_indexes: None, ~numpy.array or list(int)
:param float t_stop:
:param t_stop:
:param allow_missing: Flag to say if data for missing variable
should raise an exception
"""
Expand Down
14 changes: 9 additions & 5 deletions spynnaker/pyNN/utilities/neo_csv.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,22 +71,26 @@ class NeoCsv(object):

def _csv_variable_metdata(
self, csv_writer: CSVWriter, variable_type: str, variable: str,
t_start: float, t_stop: float, sampling_interval_ms: float,
units: Optional[str]):
t_start: float, t_stop: Optional[float],
sampling_interval_ms: float, units: Optional[str]) -> None:
"""
Writes the metadata for a variable to CSV

:param ~csv.writer csv_writer: Open CSV writer to write to
:param str variable_type:
:param str variable:
:param float t_start:
:param float t_stop:
:param t_stop:
:param float sampling_interval_ms:
:param str units:
"""
csv_writer.writerow([variable_type, variable])
csv_writer.writerow([self._T_START, t_start * ms])
csv_writer.writerow([self._T_STOP, t_stop * ms])
if t_stop is None:
csv_writer.writerow([self._T_START, "Unknown"])
csv_writer.writerow([self._T_STOP, "Unknown"])
else:
csv_writer.writerow([self._T_START, t_start * ms])
csv_writer.writerow([self._T_STOP, t_stop * ms])
sampling_period = sampling_interval_ms * ms
csv_writer.writerow([self._SAMPLING_PERIOD, sampling_period])
if units is None:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
from time import sleep
import pyNN.spiNNaker as sim
from spinnaker_testbase import BaseTestCase

from spynnaker.pyNN.utilities.neo_convertor import count_spikes

spike_receive_count = 0
spike_send_count = 0
Expand All @@ -33,41 +33,57 @@ def sim_control(label, sender):
def receive_spikes(label, time, neuron_ids):
global spike_receive_count
spike_receive_count += len(neuron_ids)
for neuron_id in neuron_ids:
print("Received spike at time", time, "from", label, "-", neuron_id)


def do_run():
# for neuron_id in neuron_ids:
# print("Received spike at time", time, "from", label, "-", neuron_id)

conn = sim.external_devices.SpynnakerLiveSpikesConnection(
receive_labels=["pop_1"], send_labels=["sender"], local_port=None)
conn.add_receive_callback("pop_1", receive_spikes)
conn.add_start_resume_callback("sender", sim_control)

# initial call to set up the front end (pynn requirement)
sim.setup(timestep=1.0, min_delay=1.0)
ssa = sim.Population(
1, sim.external_devices.SpikeInjector(
database_notify_port_num=conn.local_port),
label="sender")
pop = sim.Population(
1, sim.IF_curr_exp(), label="pop_1")
sim.Projection(ssa, pop, sim.OneToOneConnector(),
sim.StaticSynapse(weight=5, delay=1))
sim.external_devices.activate_live_output_for(
pop, database_notify_port_num=conn.local_port)

for _ in range(5):
sim.external_devices.run_forever()
sim.end()
print(spike_send_count, spike_receive_count)


class TestSpikeRunForeverAgain(BaseTestCase):

def do_run(self):
conn = sim.external_devices.SpynnakerLiveSpikesConnection(
receive_labels=["pop_1"], send_labels=["sender"], local_port=None)
conn.add_receive_callback("pop_1", receive_spikes)
conn.add_start_resume_callback("sender", sim_control)

# initial call to set up the front end (pynn requirement)
sim.setup(timestep=1.0, min_delay=1.0)
ssa = sim.Population(
1, sim.external_devices.SpikeInjector(
database_notify_port_num=conn.local_port),
label="sender")
pop = sim.Population(
1, sim.IF_curr_exp(), label="pop_1")
pop.record("spikes")
spike_times = [0, 2, 4, 8, 16, 32, 64, 128, 256]
input_pop = sim.Population(
1, sim.SpikeSourceArray(
spike_times=spike_times),
label="input")
input_pop.record("spikes")
sim.Projection(ssa, pop, sim.OneToOneConnector(),
sim.StaticSynapse(weight=5, delay=1))
sim.external_devices.activate_live_output_for(
pop, database_notify_port_num=conn.local_port)

n_loops = 5
for _ in range(n_loops):
sim.external_devices.run_forever()

neo = pop.get_data("spikes")
pop_spikes = count_spikes(neo)

neo = input_pop.get_data("spikes")
input_spikes = count_spikes(neo)

sim.end()
self.assertEqual(spike_send_count, spike_receive_count)
self.assertEqual(spike_send_count, pop_spikes)
print(input_spikes, len(spike_times) * n_loops)

def test_run(self):
self.runsafe(do_run)
self.runsafe(self.do_run)


if __name__ == "__main__":
do_run()
if __name__ == '__main__':
TestSpikeRunForeverAgain().do_run()
Loading