Skip to content
Merged
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
19 changes: 1 addition & 18 deletions spynnaker/pyNN/models/neuron/population_machine_vertex.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@
# limitations under the License.
import ctypes
from enum import IntEnum
import os
from typing import List, Optional, Sequence

from numpy import floating
Expand Down Expand Up @@ -198,7 +197,7 @@ def __init__(
self.COMMON_REGIONS,
NeuronProvenance.N_ITEMS + SynapseProvenance.N_ITEMS +
SpikeProcessingProvenance.N_ITEMS + MainProvenance.N_ITEMS,
self._PROFILE_TAG_LABELS, self.__get_binary_file_name(app_vertex))
self._PROFILE_TAG_LABELS, app_vertex.combined_binary_file_name)
self.__key: Optional[int] = None
self.__slice_index = slice_index
self.__ring_buffer_shifts = ring_buffer_shifts
Expand Down Expand Up @@ -259,22 +258,6 @@ def _synaptic_matrices(self) -> SynapticMatrices:
def _max_atoms_per_core(self) -> int:
return self.__max_atoms_per_core

@staticmethod
def __get_binary_file_name(app_vertex: PopulationVertex) -> str:
"""
Get the local binary filename for this vertex. Static because at
the time this is needed, the local `app_vertex` is not set.

:param PopulationVertex app_vertex:
The associated application vertex
:rtype: str
"""
# Split binary name into title and extension
name, ext = os.path.splitext(app_vertex.neuron_impl.binary_name)

# Reunite title and extension and return
return name + app_vertex.synapse_executable_suffix + ext

@overrides(PopulationMachineCommon.parse_extra_provenance_items)
def parse_extra_provenance_items(
self, label: str, x: int, y: int, p: int,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@
# See the License for the specific language governing permissions and
# limitations under the License.
from enum import IntEnum
import os
import ctypes
from typing import List, Optional, Sequence

Expand Down Expand Up @@ -147,7 +146,7 @@ def __init__(
super().__init__(
label, app_vertex, vertex_slice, sdram, self.COMMON_REGIONS,
NeuronProvenance.N_ITEMS + NeuronMainProvenance.N_ITEMS,
self._PROFILE_TAG_LABELS, self.__get_binary_file_name(app_vertex))
self._PROFILE_TAG_LABELS, app_vertex.neuron_core_binary_file_name)
self.__key: Optional[int] = None
self.__sdram_partition: Optional[
SourceSegmentedSDRAMMachinePartition] = None
Expand Down Expand Up @@ -210,22 +209,6 @@ def set_sdram_partition(
"Trying to set SDRAM partition more than once")
self.__sdram_partition = sdram_partition

@staticmethod
def __get_binary_file_name(app_vertex: PopulationVertex) -> str:
"""
Get the local binary filename for this vertex. Static because at
the time this is needed, the local app_vertex is not set.

:param PopulationVertex app_vertex:
The associated application vertex
:rtype: str
"""
# Split binary name into title and extension
name, ext = os.path.splitext(app_vertex.neuron_impl.binary_name)

# Reunite title and extension and return
return name + "_neuron" + ext

@overrides(PopulationMachineCommon.parse_extra_provenance_items)
def parse_extra_provenance_items(
self, label: str, x: int, y: int, p: int,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,7 @@ def __init__(
super().__init__(
label, app_vertex, vertex_slice, sdram, self.COMMON_REGIONS,
SynapseProvenance.N_ITEMS + SpikeProcessingFastProvenance.N_ITEMS,
self._PROFILE_TAG_LABELS, self.__get_binary_file_name(app_vertex))
self._PROFILE_TAG_LABELS, app_vertex.synapse_core_binary_file_name)
self.__sdram_partition: Optional[
SourceSegmentedSDRAMMachinePartition] = None
self.__neuron_vertex: Optional[PopulationNeuronsMachineVertex] = None
Expand Down Expand Up @@ -199,19 +199,6 @@ def set_neuron_vertex_and_partition_id(
self.__neuron_vertex = neuron_vertex
self.__partition_id = partition_id

@staticmethod
def __get_binary_file_name(app_vertex: PopulationVertex) -> str:
"""
Get the local binary filename for this vertex. Static because at
the time this is needed, the local `app_vertex` is not set.

:param PopulationVertex app_vertex:
The associated application vertex
:rtype: str
"""
# Reunite title and extension and return
return "synapses" + app_vertex.synapse_executable_suffix + ".aplx"

@overrides(PopulationMachineCommon.get_recorded_region_ids)
def get_recorded_region_ids(self) -> Sequence[int]:
ids = self._pop_vertex.synapse_recorder.recorded_ids_by_slice(
Expand Down
145 changes: 142 additions & 3 deletions spynnaker/pyNN/models/neuron/population_vertex.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
from collections import defaultdict
import logging
import math
import os
from typing import (
Any, Collection, Dict, Iterable, List, Optional, Sequence, Tuple, Union,
cast, TYPE_CHECKING)
Expand Down Expand Up @@ -486,6 +487,73 @@ def set_max_atoms_per_dimension_per_core(
def set_structure(self, structure: BaseStructure) -> None:
self.__structure = structure

@property
def combined_binary_file_name(self) -> str:
"""
The name of the combined binary file for the vertex.
"""
# Split binary name into title and extension
name, ext = os.path.splitext(self.__neuron_impl.binary_name)

# Reunite title and extension and return
return name + self.synapse_executable_suffix + ext

@property
def neuron_core_binary_file_name(self) -> str:
"""
The name of the neuron core binary file for the vertex.
"""
# Split binary name into title and extension
name, ext = os.path.splitext(self.__neuron_impl.binary_name)

# Reunite title and extension and return
return name + "_neuron" + ext

@property
def synapse_core_binary_file_name(self) -> str:
"""
The name of the synapse core binary file for the vertex.
"""
return "synapses" + self.synapse_executable_suffix + ".aplx"

@property
def combined_binary_exists(self) -> bool:
"""
Whether the combined binary file exists.

:rtype: bool
"""
# If we are in virtual machine mode, we can work without binaries
# so easier to assume they exist
if get_config_bool("Machine", "virtual_board"):
return True
try:
SpynnakerDataView().get_executable_path(
self.combined_binary_file_name)
return True
except KeyError:
return False

@property
def split_binaries_exist(self) -> bool:
"""
Whether the split binary files exist.

:rtype: bool
"""
# If we are in virtual machine mode, we can work without binaries
# so easier to assume they exist
if get_config_bool("Machine", "virtual_board"):
return True
try:
SpynnakerDataView().get_executable_path(
self.neuron_core_binary_file_name)
SpynnakerDataView().get_executable_path(
self.synapse_core_binary_file_name)
return True
except KeyError:
return False

@property
def use_combined_core(self) -> bool:
"""
Expand All @@ -495,6 +563,15 @@ def use_combined_core(self) -> bool:

:rtype: bool
"""
# If there are no binaries at all, complain!
if not self.combined_binary_exists and not self.split_binaries_exist:
raise SynapticConfigurationException(
"This model has no binaries! Please compile the binaries"
f" {self.combined_binary_file_name} and/or"
f" ({self.synapse_core_binary_file_name} and"
f" {self.neuron_core_binary_file_name})"
" before running the simulation.")

# If we can't use a combined core, use a split core
if not self.__synapse_dynamics.is_combined_core_capable:
if not self.__synapse_dynamics.is_split_core_capable:
Expand All @@ -508,6 +585,13 @@ def use_combined_core(self) -> bool:
f"The synapse dynamics {self.__synapse_dynamics} must be"
" run using a synapse core separate from a neuron core."
" Please set the number of synapse cores to 1 or greater.")
if not self.split_binaries_exist:
raise SynapticConfigurationException(
"This model requires split binaries"
f" {self.neuron_core_binary_file_name} and"
f" {self.synapse_core_binary_file_name} but they do not "
"exist. Please compile the split binaries before "
"running the simulation.")
return False

# If we can't use a split core, use a combined core
Expand All @@ -518,21 +602,67 @@ def use_combined_core(self) -> bool:
f"The synapse dynamics {self.__synapse_dynamics} must be"
" run using a combined synapse-neuron core."
" Please set the number of synapse cores to 0.")
if not self.combined_binary_exists:
raise SynapticConfigurationException(
"This model requires a combined binary"
f" {self.combined_binary_file_name}, but it does not "
"exist. Please compile the combined binary before "
"running the simulation.")
return True

# If the user has chosen to have a synapse core, add one
if self.__n_synapse_cores is not None and self.__n_synapse_cores > 0:
if not self.split_binaries_exist:
raise SynapticConfigurationException(
"This model is configured to use split binaries"
f" {self.neuron_core_binary_file_name} and"
f" {self.synapse_core_binary_file_name} but they do not "
"exist. Please compile the split binaries before "
"running the simulation.")
return False

# If the user has chosen to have no synapse cores, use a combined core
if self.__n_synapse_cores is not None and self.__n_synapse_cores == 0:
if not self.combined_binary_exists:
raise SynapticConfigurationException(
"This model is configured to use a combined binary"
f" {self.combined_binary_file_name}, but it does not "
"exist. Please compile the combined binary before "
"running the simulation.")
return True

# If the time-step is less than 1, use combined core if no synapse
# cores are needed, otherwise use split core
# TODO: Look at if it is possible to include neurons in a combined
# core calculation and update to allow a choice of combined core if
# neurons and synapses fit on a single core
if SpynnakerDataView().get_simulation_time_step_ms() < 1.0:
return self.n_synapse_cores_required == 0
use_combined = (self.n_synapse_cores_required == 0)

# We want combined, but it doesn't exist, so use split
# (which is fine)
if use_combined and not self.combined_binary_exists:
return False

# If the timestep is 1 or greater, use a combined core generally
# We want split, but it doesn't exist, so use combined, which needs
# a warning as it might not work at this time-step!
if not use_combined and not self.split_binaries_exist:
logger.warning(
"The synapse dynamics are set to use a split core, but "
"the split binaries do not exist. Using the combined "
"core instead, but this may not work at this time-step. "
"To avoid this warning please build the split binaries "
f"{self.neuron_core_binary_file_name} and "
f"{self.synapse_core_binary_file_name}.")
return True

# Use the recommended mode
return use_combined

# If the timestep is 1 or greater, use a combined core generally,
# unless only a split core exists!
if not self.combined_binary_exists:
return False
return True

@property
Expand Down Expand Up @@ -616,7 +746,16 @@ def __update_n_synapse_cores(self) -> int:

# If the number of cores needed is more than the maximum, use the
# maximum
self.__n_synapse_cores = min(max_n_cores, n_synapse_cores)
if n_synapse_cores > max_n_cores:
logger.warning(
f"Ideally this execution would need {n_synapse_cores} synapse "
f"cores, but only {max_n_cores} cores are available. This may "
"mean that the simulation does not work correctly. Potential "
"solutions include increasing the time_scale_factor, or "
"reducing the number of synapses incoming into each "
"population")
n_synapse_cores = max_n_cores
self.__n_synapse_cores = n_synapse_cores
assert self.__n_synapse_cores is not None
return self.__n_synapse_cores

Expand Down
Loading