GeNN  4.9.0
GPU enhanced Neuronal Networks (GeNN)
single_threaded_cpu/backend.h
Go to the documentation of this file.
1 #pragma once
2 
3 // Standard C++ includes
4 #include <functional>
5 #include <map>
6 #include <string>
7 
8 // GeNN includes
9 #include "backendExport.h"
10 #include "varAccess.h"
11 
12 // GeNN code generator includes
14 
15 // Forward declarations
16 namespace filesystem
17 {
18  class path;
19 }
20 
21 //--------------------------------------------------------------------------
22 // CodeGenerator::SingleThreadedCPU::Preferences
23 //--------------------------------------------------------------------------
24 namespace CodeGenerator
25 {
26 namespace SingleThreadedCPU
27 {
29 {
30 };
31 
32 //--------------------------------------------------------------------------
33 // CodeGenerator::SingleThreadedCPU::Backend
34 //--------------------------------------------------------------------------
36 {
37 public:
38  Backend(const std::string &scalarType, const Preferences &preferences)
39  : BackendBase(scalarType, preferences)
40  {
41  }
42 
43  //--------------------------------------------------------------------------
44  // CodeGenerator::BackendBase virtuals
45  //--------------------------------------------------------------------------
46  virtual void genNeuronUpdate(CodeStream &os, const ModelSpecMerged &modelMerged,
47  HostHandler preambleHandler, HostHandler pushEGPHandler) const override;
48 
49  virtual void genSynapseUpdate(CodeStream &os, const ModelSpecMerged &modelMerged,
50  HostHandler preambleHandler, HostHandler pushEGPHandler) const override;
51 
52  virtual void genCustomUpdate(CodeStream &os, const ModelSpecMerged &modelMerged,
53  HostHandler preambleHandler, HostHandler pushEGPHandler) const override;
54 
55  virtual void genInit(CodeStream &os, const ModelSpecMerged &modelMerged,
56  HostHandler preambleHandler, HostHandler initPushEGPHandler, HostHandler initSparsePushEGPHandler) const override;
57 
58  virtual size_t getSynapticMatrixRowStride(const SynapseGroupInternal &sg) const override;
59 
60  virtual void genDefinitionsPreamble(CodeStream &os, const ModelSpecMerged &modelMerged) const override;
61  virtual void genDefinitionsInternalPreamble(CodeStream &os, const ModelSpecMerged &modelMerged) const override;
62  virtual void genRunnerPreamble(CodeStream &os, const ModelSpecMerged &modelMerged, const MemAlloc &memAlloc) const override;
63  virtual void genAllocateMemPreamble(CodeStream &os, const ModelSpecMerged &modelMerged, const MemAlloc &memAlloc) const override;
64  virtual void genFreeMemPreamble(CodeStream &os, const ModelSpecMerged &modelMerged) const override;
65  virtual void genStepTimeFinalisePreamble(CodeStream &os, const ModelSpecMerged &modelMerged) const override;
66 
67  virtual void genVariableDefinition(CodeStream &definitions, CodeStream &definitionsInternal, const std::string &type, const std::string &name, VarLocation loc) const override;
68  virtual void genVariableImplementation(CodeStream &os, const std::string &type, const std::string &name, VarLocation loc) const override;
69  virtual void genVariableAllocation(CodeStream &os, const std::string &type, const std::string &name, VarLocation loc, size_t count, MemAlloc &memAlloc) const override;
70  virtual void genVariableFree(CodeStream &os, const std::string &name, VarLocation loc) const override;
71 
72  virtual void genExtraGlobalParamDefinition(CodeStream &definitions, CodeStream &definitionsInternal, const std::string &type, const std::string &name, VarLocation loc) const override;
73  virtual void genExtraGlobalParamImplementation(CodeStream &os, const std::string &type, const std::string &name, VarLocation loc) const override;
74  virtual void genExtraGlobalParamAllocation(CodeStream &os, const std::string &type, const std::string &name,
75  VarLocation loc, const std::string &countVarName = "count", const std::string &prefix = "") const override;
76  virtual void genExtraGlobalParamPush(CodeStream &os, const std::string &type, const std::string &name,
77  VarLocation loc, const std::string &countVarName = "count", const std::string &prefix = "") const override;
78  virtual void genExtraGlobalParamPull(CodeStream &os, const std::string &type, const std::string &name,
79  VarLocation loc, const std::string &countVarName = "count", const std::string &prefix = "") const override;
80 
82  virtual void genMergedExtraGlobalParamPush(CodeStream &os, const std::string &suffix, size_t mergedGroupIdx,
83  const std::string &groupIdx, const std::string &fieldName,
84  const std::string &egpName) const override;
85 
87  virtual std::string getMergedGroupFieldHostType(const std::string &type) const override;
88 
90  virtual std::string getMergedGroupSimRNGType() const override;
91 
92  virtual void genPopVariableInit(CodeStream &os,const Substitutions &kernelSubs, Handler handler) const override;
93  virtual void genVariableInit(CodeStream &os, const std::string &count, const std::string &indexVarName,
94  const Substitutions &kernelSubs, Handler handler) const override;
95  virtual void genSparseSynapseVariableRowInit(CodeStream &os, const Substitutions &kernelSubs, Handler handler) const override;
96  virtual void genDenseSynapseVariableRowInit(CodeStream &os, const Substitutions &kernelSubs, Handler handler) const override;
97  virtual void genKernelSynapseVariableInit(CodeStream &os, const SynapseInitGroupMerged &sg, const Substitutions &kernelSubs, Handler handler) const final;
98  virtual void genKernelCustomUpdateVariableInit(CodeStream &os, const CustomWUUpdateInitGroupMerged &cu, const Substitutions &kernelSubs, Handler handler) const final;
99 
100  virtual void genVariablePush(CodeStream &os, const std::string &type, const std::string &name, VarLocation loc, bool autoInitialized, size_t count) const override;
101  virtual void genVariablePull(CodeStream &os, const std::string &type, const std::string &name, VarLocation loc, size_t count) const override;
102  virtual void genCurrentVariablePush(CodeStream &os, const NeuronGroupInternal &ng, const std::string &type,
103  const std::string &name, VarLocation loc, unsigned int batchSize) const override;
104  virtual void genCurrentVariablePull(CodeStream &os, const NeuronGroupInternal &ng, const std::string &type,
105  const std::string &name, VarLocation loc, unsigned int batchSize) const override;
106 
107  virtual void genCurrentTrueSpikePush(CodeStream &os, const NeuronGroupInternal &ng, unsigned int batchSize) const override;
108  virtual void genCurrentTrueSpikePull(CodeStream &os, const NeuronGroupInternal &ng, unsigned int batchSize) const override;
109  virtual void genCurrentSpikeLikeEventPush(CodeStream &os, const NeuronGroupInternal &ng, unsigned int batchSize) const override;
110  virtual void genCurrentSpikeLikeEventPull(CodeStream &os, const NeuronGroupInternal &ng, unsigned int batchSize) const override;
111 
112  virtual void genGlobalDeviceRNG(CodeStream &definitions, CodeStream &definitionsInternal, CodeStream &runner,
113  CodeStream &allocations, CodeStream &free, MemAlloc &memAlloc) const override;
114  virtual void genPopulationRNG(CodeStream &definitions, CodeStream &definitionsInternal, CodeStream &runner,
115  CodeStream &allocations, CodeStream &free,
116  const std::string &name, size_t count, MemAlloc &memAlloc) const override;
117  virtual void genTimer(CodeStream &definitions, CodeStream &definitionsInternal, CodeStream &runner, CodeStream &allocations, CodeStream &free,
118  CodeStream &stepTimeFinalise, const std::string &name, bool updateInStepTime) const override;
119 
121  virtual void genReturnFreeDeviceMemoryBytes(CodeStream &os) const override;
122 
123  virtual void genMakefilePreamble(std::ostream &os) const override;
124  virtual void genMakefileLinkRule(std::ostream &os) const override;
125  virtual void genMakefileCompileRule(std::ostream &os) const override;
126 
127  virtual void genMSBuildConfigProperties(std::ostream &os) const override;
128  virtual void genMSBuildImportProps(std::ostream &os) const override;
129  virtual void genMSBuildItemDefinitions(std::ostream &os) const override;
130  virtual void genMSBuildCompileModule(const std::string &moduleName, std::ostream &os) const override;
131  virtual void genMSBuildImportTarget(std::ostream &os) const override;
132 
133  virtual std::string getDeviceVarPrefix() const override{ return ""; }
134 
136  virtual bool isDeviceScalarRequired() const override { return false; }
137 
138  virtual bool isGlobalHostRNGRequired(const ModelSpecMerged &modelMerged) const override;
139  virtual bool isGlobalDeviceRNGRequired(const ModelSpecMerged &modelMerged) const override;
140  virtual bool isPopulationRNGRequired() const override { return false; }
141 
143  virtual bool isPopulationRNGInitialisedOnDevice() const override { return false; }
144 
145  virtual bool isPostsynapticRemapRequired() const override{ return true; }
146 
148  virtual bool isHostReductionRequired() const override { return false; }
149 
151  virtual size_t getDeviceMemoryBytes() const override{ return 0; }
152 
156  virtual MemorySpaces getMergedGroupMemorySpaces(const ModelSpecMerged &modelMerged) const override;
157 
158  virtual bool supportsNamespace() const override { return true; };
159 
161  virtual boost::uuids::detail::sha1::digest_type getHashDigest() const override;
162 
163 private:
164  //--------------------------------------------------------------------------
165  // Private methods
166  //--------------------------------------------------------------------------
167  void genPresynapticUpdate(CodeStream &os, const ModelSpecMerged &modelMerged, const PresynapticUpdateGroupMerged &sg, const Substitutions &popSubs, bool trueSpike) const;
168 
169  void genEmitSpike(CodeStream &os, const NeuronUpdateGroupMerged &ng, const Substitutions &subs, bool trueSpike, bool recordingEnabled) const;
170 
171  template<typename T>
172  void genMergedStructArrayPush(CodeStream &os, const std::vector<T> &groups) const
173  {
174  // Loop through groups
175  for(const auto &g : groups) {
176  // Check there's no memory space assigned as single-threaded CPU backend doesn't support them
177  assert(g.getMemorySpace().empty());
178 
179  // Implement merged group
180  os << "static Merged" << T::name << "Group" << g.getIndex() << " merged" << T::name << "Group" << g.getIndex() << "[" << g.getGroups().size() << "];" << std::endl;
181 
182  // Write function to update
183  os << "void pushMerged" << T::name << "Group" << g.getIndex() << "ToDevice(unsigned int idx, ";
184  g.generateStructFieldArgumentDefinitions(os, *this);
185  os << ")";
186  {
187  CodeStream::Scope b(os);
188 
189  // Loop through sorted fields and set array entry
190  const auto sortedFields = g.getSortedFields(*this);
191  for(const auto &f : sortedFields) {
192  os << "merged" << T::name << "Group" << g.getIndex() << "[idx]." << std::get<1>(f) << " = " << std::get<1>(f) << ";" << std::endl;
193  }
194  }
195  }
196  }
197 
199 
200  void genWriteBackReductions(CodeStream &os, const CustomUpdateGroupMerged &cg, const std::string &idx) const;
201 
203 
204  void genWriteBackReductions(CodeStream &os, const CustomUpdateWUGroupMerged &cg, const std::string &idx) const;
205 
206  template<typename G, typename R>
207  void genWriteBackReductions(CodeStream &os, const G &cg, const std::string &idx, R getVarRefIndexFn) const
208  {
209  const auto *cm = cg.getArchetype().getCustomUpdateModel();
210  for(const auto &v : cm->getVars()) {
211  // If variable is a reduction target, copy value from register straight back into global memory
212  if(v.access & VarAccessModeAttribute::REDUCE) {
213  os << "group->" << v.name << "[" << cg.getVarIndex(getVarAccessDuplication(v.access), idx) << "] = l" << v.name << ";" << std::endl;
214  }
215  }
216 
217  // Loop through variable references
218  const auto modelVarRefs = cm->getVarRefs();
219  const auto &varRefs = cg.getArchetype().getVarReferences();
220  for (size_t i = 0; i < varRefs.size(); i++) {
221  const auto varRef = varRefs.at(i);
222  const auto modelVarRef = modelVarRefs.at(i);
223 
224  // If variable reference is a reduction target, copy value from register straight back into global memory
225  if(modelVarRef.access & VarAccessModeAttribute::REDUCE) {
226  os << "group->" << modelVarRef.name << "[" << getVarRefIndexFn(varRef, idx) << "] = l" << modelVarRef.name << ";" << std::endl;
227  }
228  }
229  }
230 };
231 } // namespace SingleThreadedCPU
232 } // namespace CodeGenerator
Definition: neuronGroupInternal.h:9
VarLocation
< Flags defining which memory space variables should be allocated in
Definition: variableMode.h:10
Definition: customUpdateGroupMerged.h:12
Base class for backend preferences - can be accessed via a global in &#39;classic&#39; C++ code generator...
Definition: backendBase.h:58
virtual std::string getDeviceVarPrefix() const override
Definition: single_threaded_cpu/backend.h:133
virtual bool isDeviceScalarRequired() const override
Should &#39;scalar&#39; variables be implemented on device or can host variables be used directly?
Definition: single_threaded_cpu/backend.h:136
Definition: modelSpecMerged.h:31
Helper class for generating code - automatically inserts brackets, indents etc.
Definition: backendBase.h:30
std::vector< std::pair< std::string, size_t > > MemorySpaces
Vector of prefixes required to allocate in memory space and size of memory space. ...
Definition: backendBase.h:190
Definition: synapseGroupInternal.h:9
Definition: codeStream.h:21
#define BACKEND_EXPORT
Definition: backendExport.h:13
Definition: backendBase.h:107
Definition: substitutions.h:21
Definition: single_threaded_cpu/backend.h:28
virtual size_t getDeviceMemoryBytes() const override
How many bytes of memory does &#39;device&#39; have.
Definition: single_threaded_cpu/backend.h:151
Definition: backendBase.h:176
virtual bool isPopulationRNGRequired() const override
Different backends use different RNGs for different things. Does this one require population RNGs...
Definition: single_threaded_cpu/backend.h:140
virtual bool supportsNamespace() const override
Does this backend support namespaces i.e. can C++ implementation of support functions be used...
Definition: single_threaded_cpu/backend.h:158
std::function< void(CodeStream &)> HostHandler
Definition: backendBase.h:182
Definition: initGroupMerged.h:329
virtual bool isPostsynapticRemapRequired() const override
Different backends may implement synaptic plasticity differently. Does this one require a postsynapti...
Definition: single_threaded_cpu/backend.h:145
Definition: single_threaded_cpu/backend.h:35
Definition: neuronUpdateGroupMerged.h:11
Definition: initGroupMerged.h:100
virtual bool isHostReductionRequired() const override
Backends which support batch-parallelism might require an additional host reduction phase after reduc...
Definition: single_threaded_cpu/backend.h:148
Definition: generateModules.h:16
Backend(const std::string &scalarType, const Preferences &preferences)
Definition: single_threaded_cpu/backend.h:38
VarAccessDuplication getVarAccessDuplication(VarAccess type)
Definition: varAccess.h:79
This variable is read-write.
virtual bool isPopulationRNGInitialisedOnDevice() const override
Different backends seed RNGs in different ways. Does this one initialise population RNGS on device...
Definition: single_threaded_cpu/backend.h:143
Definition: synapseUpdateGroupMerged.h:15
Definition: customUpdateGroupMerged.h:94
std::function< void(CodeStream &, Substitutions &)> Handler
Definition: backendBase.h:184
Definition: codeStream.h:94