CARLsim  6.1.0
CARLsim: a GPU-accelerated SNN simulator
spike_buffer.cpp
Go to the documentation of this file.
1 /* * Copyright (c) 2016 Regents of the University of California. All rights reserved.
2 *
3 * Redistribution and use in source and binary forms, with or without
4 * modification, are permitted provided that the following conditions
5 * are met:
6 *
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 *
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * 3. The names of its contributors may not be used to endorse or promote
15 * products derived from this software without specific prior written
16 * permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
22 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
23 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
24 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
25 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
26 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
27 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
28 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 *
30 * *********************************************************************************************** *
31 * CARLsim
32 * created by: (MDR) Micah Richert, (JN) Jayram M. Nageswaran
33 * maintained by:
34 * (MA) Mike Avery <averym@uci.edu>
35 * (MB) Michael Beyeler <mbeyeler@uci.edu>,
36 * (KDC) Kristofor Carlson <kdcarlso@uci.edu>
37 * (TSC) Ting-Shuo Chou <tingshuc@uci.edu>
38 * (HK) Hirak J Kashyap <kashyaph@uci.edu>
39 *
40 * CARLsim v1.0: JM, MDR
41 * CARLsim v2.0/v2.1/v2.2: JM, MDR, MA, MB, KDC
42 * CARLsim3: MB, KDC, TSC
43 * CARLsim4: TSC, HK
44 * CARLsim5: HK, JX, KC
45 * CARLsim6: LN, JX, KC, KW
46 *
47 * CARLsim available from http://socsci.uci.edu/~jkrichma/CARLsim/
48 * Ver 12/31/2016
49 */
50 #include <spike_buffer.h>
51 
52 #include <vector>
53 
54 
55 // the size of an allocation chunk
56 #define MAX_CHUNK_SIZE 1024
57 
58 
60 public:
61  // +++++ PUBLIC METHODS: SETUP / TEAR-DOWN ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ //
62 
63  Impl(int minDelay, int maxDelay) : _currNodeId(0), _spikeBufFront(maxDelay+1),
64  _spikeBufBack(maxDelay+1), _chunkBuf(0), _currFreeChunkId(NULL), _nextFreeNodeId(0), _nextFreeChunkId(0),
65  _recycledNodes(NULL)
66  {
67  reset(minDelay, maxDelay);
68  }
69 
70  ~Impl() {
71  for (size_t i=0; i<_chunkBuf.size(); i++) {
72  delete[] _chunkBuf[i];
73  }
74  }
75 
76  void reset(int minDelay, int maxDelay) {
77  init(maxDelay + minDelay);
78 
79  for (size_t i=0; i<_spikeBufFront.size(); i++) {
80  _spikeBufFront[i] = NULL;
81  _spikeBufBack[i] = NULL;
82  }
83 
84  _currFreeChunkId = _chunkBuf[0];
85  _nextFreeChunkId = 1;
86 
87  _currNodeId = 0;
88  _nextFreeNodeId = 0;
89  _recycledNodes = NULL;
90  }
91 
92 
93 
94  // +++++ PUBLIC METHODS +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ //
95 
96  // points to front of buffer
97  SpikeIterator front(int stepOffset=0) {
98  return SpikeIterator(_spikeBufFront[(_currNodeId + stepOffset + length()) % length()]);
99  };
100 
101  // End iterator corresponding to beginSynapseGroups
103  return SpikeIterator(NULL);
104  };
105 
106  // retrieve actual length of buffer
107  size_t length() {
108  return _spikeBufFront.size();
109  }
110 
111  // schedule a spike at t + delay for neuron neurId
112  void schedule(int neurId, int grpId, unsigned short int delay) {
113  SpikeNode* n = getFreeNode();
114 
115  int writeIdx = (_currNodeId+delay) % _spikeBufFront.size();
116 
117  n->neurId = neurId;
118  n->grpId = grpId;
119  n->delay = delay;
120  n->next = NULL;
121  if (_spikeBufFront[writeIdx] == NULL) {
122  _spikeBufFront[writeIdx] = n;
123  _spikeBufBack[writeIdx] = n;
124  } else {
125  _spikeBufBack[writeIdx]->next = n;
126  _spikeBufBack[writeIdx] = n;
127  }
128  }
129 
130  void step() {
131  // move the solts of _currNodeId to recycled slots
132  if (_spikeBufFront[_currNodeId] != NULL) {
133  _spikeBufBack[_currNodeId]->next = _recycledNodes;
134  _recycledNodes = _spikeBufFront[_currNodeId];
135  }
136 
137  // mark current index as processed
138  _spikeBufFront[_currNodeId] = NULL;
139  _spikeBufBack[_currNodeId] = NULL;
140  _currNodeId = (_currNodeId + 1) % _spikeBufFront.size();
141  }
142 
143 
144 private:
146  void init(size_t maxDelaySteps) {
147  if (_spikeBufFront.size() != maxDelaySteps + 1) {
148  _spikeBufFront.resize(maxDelaySteps + 1);
149  _spikeBufBack.resize(maxDelaySteps + 1);
150  }
151  if (_chunkBuf.size() < 1) {
152  _chunkBuf.reserve(10);
153  _chunkBuf.resize(0);
154  _chunkBuf.push_back(new SpikeNode[MAX_CHUNK_SIZE]);
155  }
156  }
157 
159  SpikeNode* getFreeNode() {
160  SpikeNode* n;
161  if (_recycledNodes != NULL) {
162  // find a recycled node
163  n = _recycledNodes;
164  _recycledNodes = _recycledNodes->next;
165  } else if (_nextFreeNodeId < MAX_CHUNK_SIZE) {
166  // as long as there is pre-allocated memory left: get a new slot from the current chunk
167  n = &(_currFreeChunkId[_nextFreeNodeId++]);
168  } else if (_nextFreeChunkId < _chunkBuf.size()) {
169  // pre-allocated memory chunk is used up: go to next chunk
170  _currFreeChunkId = _chunkBuf[_nextFreeChunkId++];
171  n = &(_currFreeChunkId[0]);
172  _nextFreeNodeId = 1;
173  } else {
174  // all chunks used up: need to allocate new one
175  _currFreeChunkId = new SpikeNode[MAX_CHUNK_SIZE];
176  _chunkBuf.push_back(_currFreeChunkId);
177 
178  _nextFreeChunkId++;
179  _nextFreeNodeId = 1;
180  n = &(_currFreeChunkId[0]);
181  }
182  return n;
183  }
184 
186  int _currNodeId;
187 
189  std::vector<SpikeNode*> _spikeBufFront;
190 
192  std::vector<SpikeNode*> _spikeBufBack;
193 
195  std::vector<SpikeNode*> _chunkBuf;
196 
198  SpikeNode* _currFreeChunkId;
199 
201  int _nextFreeNodeId;
202 
204  size_t _nextFreeChunkId;
205 
207  SpikeNode* _recycledNodes;
208 };
209 
210 
211 // ****************************************************************************************************************** //
212 // SPIKEBUFFER API IMPLEMENTATION
213 // ****************************************************************************************************************** //
214 
215 // constructor / destructor
216 SpikeBuffer::SpikeBuffer(int minDelay, int maxDelay) :
217  _impl( new Impl(minDelay, maxDelay) ) {}
218 SpikeBuffer::~SpikeBuffer() { delete _impl; }
219 
220 // public methods
221 void SpikeBuffer::schedule(int neurId, int grpId, unsigned short int delay) { _impl->schedule(neurId, grpId, delay); }
222 void SpikeBuffer::step() { _impl->step(); }
223 void SpikeBuffer::reset(int minDelay, int maxDelay) { _impl->reset(minDelay, maxDelay); }
224 size_t SpikeBuffer::length() { return _impl->length(); }
225 SpikeBuffer::SpikeIterator SpikeBuffer::front(int stepOffset) { return _impl->front(stepOffset); }
int grpId
corresponding global group Id
Definition: spike_buffer.h:93
void schedule(int neurId, int grpId, unsigned short int delay)
Schedule a spike.
Iterator to loop over the scheduled spikes at a certain delay.
Definition: spike_buffer.h:99
Impl(int minDelay, int maxDelay)
size_t length()
retrieve actual length of the buffer
SpikeIterator back()
unsigned short int delay
scheduling delay (in number of time steps)
Definition: spike_buffer.h:94
#define MAX_CHUNK_SIZE
SpikeIterator back()
pointer to the back of the spike buffer
linked list to hold the corresponding neuron Id and delivery delay for each spike ...
Definition: spike_buffer.h:91
SpikeNode * next
pointer to the next element in the list
Definition: spike_buffer.h:95
void reset(int minDelay, int maxDelay)
Reset buffer data.
void schedule(int neurId, int grpId, unsigned short int delay)
int neurId
corresponding global neuron Id
Definition: spike_buffer.h:92
SpikeIterator front(int stepOffset=0)
SpikeBuffer(int minDelay, int maxDelay)
SpikeBuffer Constructor.
void step()
advance to next time step
~SpikeBuffer()
SpikeBuffer Destructor.
SpikeIterator front(int stepOffset=0)
pointer to the front of the spike buffer
void reset(int minDelay, int maxDelay)