CARLsim  4.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 *
45 * CARLsim available from http://socsci.uci.edu/~jkrichma/CARLsim/
46 * Ver 12/31/2016
47 */
48 #include <spike_buffer.h>
49 
50 #include <vector>
51 
52 
53 // the size of an allocation chunk
54 #define MAX_CHUNK_SIZE 1024
55 
56 
58 public:
59  // +++++ PUBLIC METHODS: SETUP / TEAR-DOWN ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ //
60 
61  Impl(int minDelay, int maxDelay) : _currNodeId(0), _spikeBufFront(maxDelay+1),
62  _spikeBufBack(maxDelay+1), _chunkBuf(0), _currFreeChunkId(NULL), _nextFreeNodeId(0), _nextFreeChunkId(0),
63  _recycledNodes(NULL)
64  {
65  reset(minDelay, maxDelay);
66  }
67 
68  ~Impl() {
69  for (size_t i=0; i<_chunkBuf.size(); i++) {
70  delete[] _chunkBuf[i];
71  }
72  }
73 
74  void reset(int minDelay, int maxDelay) {
75  init(maxDelay + minDelay);
76 
77  for (size_t i=0; i<_spikeBufFront.size(); i++) {
78  _spikeBufFront[i] = NULL;
79  _spikeBufBack[i] = NULL;
80  }
81 
82  _currFreeChunkId = _chunkBuf[0];
83  _nextFreeChunkId = 1;
84 
85  _currNodeId = 0;
86  _nextFreeNodeId = 0;
87  _recycledNodes = NULL;
88  }
89 
90 
91 
92  // +++++ PUBLIC METHODS +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ //
93 
94  // points to front of buffer
95  SpikeIterator front(int stepOffset=0) {
96  return SpikeIterator(_spikeBufFront[(_currNodeId + stepOffset + length()) % length()]);
97  };
98 
99  // End iterator corresponding to beginSynapseGroups
101  return SpikeIterator(NULL);
102  };
103 
104  // retrieve actual length of buffer
105  size_t length() {
106  return _spikeBufFront.size();
107  }
108 
109  // schedule a spike at t + delay for neuron neurId
110  void schedule(int neurId, int grpId, unsigned short int delay) {
111  SpikeNode* n = getFreeNode();
112 
113  int writeIdx = (_currNodeId+delay) % _spikeBufFront.size();
114 
115  n->neurId = neurId;
116  n->grpId = grpId;
117  n->delay = delay;
118  n->next = NULL;
119  if (_spikeBufFront[writeIdx] == NULL) {
120  _spikeBufFront[writeIdx] = n;
121  _spikeBufBack[writeIdx] = n;
122  } else {
123  _spikeBufBack[writeIdx]->next = n;
124  _spikeBufBack[writeIdx] = n;
125  }
126  }
127 
128  void step() {
129  // move the solts of _currNodeId to recycled slots
130  if (_spikeBufFront[_currNodeId] != NULL) {
131  _spikeBufBack[_currNodeId]->next = _recycledNodes;
132  _recycledNodes = _spikeBufFront[_currNodeId];
133  }
134 
135  // mark current index as processed
136  _spikeBufFront[_currNodeId] = NULL;
137  _spikeBufBack[_currNodeId] = NULL;
138  _currNodeId = (_currNodeId + 1) % _spikeBufFront.size();
139  }
140 
141 
142 private:
144  void init(size_t maxDelaySteps) {
145  if (_spikeBufFront.size() != maxDelaySteps + 1) {
146  _spikeBufFront.resize(maxDelaySteps + 1);
147  _spikeBufBack.resize(maxDelaySteps + 1);
148  }
149  if (_chunkBuf.size() < 1) {
150  _chunkBuf.reserve(10);
151  _chunkBuf.resize(0);
152  _chunkBuf.push_back(new SpikeNode[MAX_CHUNK_SIZE]);
153  }
154  }
155 
157  SpikeNode* getFreeNode() {
158  SpikeNode* n;
159  if (_recycledNodes != NULL) {
160  // find a recycled node
161  n = _recycledNodes;
162  _recycledNodes = _recycledNodes->next;
163  } else if (_nextFreeNodeId < MAX_CHUNK_SIZE) {
164  // as long as there is pre-allocated memory left: get a new slot from the current chunk
165  n = &(_currFreeChunkId[_nextFreeNodeId++]);
166  } else if (_nextFreeChunkId < _chunkBuf.size()) {
167  // pre-allocated memory chunk is used up: go to next chunk
168  _currFreeChunkId = _chunkBuf[_nextFreeChunkId++];
169  n = &(_currFreeChunkId[0]);
170  _nextFreeNodeId = 1;
171  } else {
172  // all chunks used up: need to allocate new one
173  _currFreeChunkId = new SpikeNode[MAX_CHUNK_SIZE];
174  _chunkBuf.push_back(_currFreeChunkId);
175 
176  _nextFreeChunkId++;
177  _nextFreeNodeId = 1;
178  n = &(_currFreeChunkId[0]);
179  }
180  return n;
181  }
182 
184  int _currNodeId;
185 
187  std::vector<SpikeNode*> _spikeBufFront;
188 
190  std::vector<SpikeNode*> _spikeBufBack;
191 
193  std::vector<SpikeNode*> _chunkBuf;
194 
196  SpikeNode* _currFreeChunkId;
197 
199  int _nextFreeNodeId;
200 
202  size_t _nextFreeChunkId;
203 
205  SpikeNode* _recycledNodes;
206 };
207 
208 
209 // ****************************************************************************************************************** //
210 // SPIKEBUFFER API IMPLEMENTATION
211 // ****************************************************************************************************************** //
212 
213 // constructor / destructor
214 SpikeBuffer::SpikeBuffer(int minDelay, int maxDelay) :
215  _impl( new Impl(minDelay, maxDelay) ) {}
216 SpikeBuffer::~SpikeBuffer() { delete _impl; }
217 
218 // public methods
219 void SpikeBuffer::schedule(int neurId, int grpId, unsigned short int delay) { _impl->schedule(neurId, grpId, delay); }
220 void SpikeBuffer::step() { _impl->step(); }
221 void SpikeBuffer::reset(int minDelay, int maxDelay) { _impl->reset(minDelay, maxDelay); }
222 size_t SpikeBuffer::length() { return _impl->length(); }
223 SpikeBuffer::SpikeIterator SpikeBuffer::front(int stepOffset) { return _impl->front(stepOffset); }
SpikeBuffer::step
void step()
advance to next time step
Definition: spike_buffer.cpp:220
SpikeBuffer::SpikeNode::neurId
int neurId
corresponding global neuron Id
Definition: spike_buffer.h:90
SpikeBuffer::Impl::back
SpikeIterator back()
Definition: spike_buffer.cpp:100
SpikeBuffer::~SpikeBuffer
~SpikeBuffer()
SpikeBuffer Destructor.
Definition: spike_buffer.cpp:216
SpikeBuffer::schedule
void schedule(int neurId, int grpId, unsigned short int delay)
Schedule a spike.
Definition: spike_buffer.cpp:219
SpikeBuffer::Impl
Definition: spike_buffer.cpp:57
SpikeBuffer::Impl::~Impl
~Impl()
Definition: spike_buffer.cpp:68
SpikeBuffer::length
size_t length()
retrieve actual length of the buffer
Definition: spike_buffer.cpp:222
SpikeBuffer::Impl::Impl
Impl(int minDelay, int maxDelay)
Definition: spike_buffer.cpp:61
SpikeBuffer::SpikeNode::delay
unsigned short int delay
scheduling delay (in number of time steps)
Definition: spike_buffer.h:92
SpikeBuffer::SpikeNode::next
SpikeNode * next
pointer to the next element in the list
Definition: spike_buffer.h:93
SpikeBuffer::back
SpikeIterator back()
pointer to the back of the spike buffer
Definition: spike_buffer.cpp:224
spike_buffer.h
SpikeBuffer::SpikeNode
linked list to hold the corresponding neuron Id and delivery delay for each spike
Definition: spike_buffer.h:89
SpikeBuffer::Impl::front
SpikeIterator front(int stepOffset=0)
Definition: spike_buffer.cpp:95
SpikeBuffer::Impl::reset
void reset(int minDelay, int maxDelay)
Definition: spike_buffer.cpp:74
MAX_CHUNK_SIZE
#define MAX_CHUNK_SIZE
Definition: spike_buffer.cpp:54
SpikeBuffer::SpikeNode::grpId
int grpId
corresponding global group Id
Definition: spike_buffer.h:91
SpikeBuffer::front
SpikeIterator front(int stepOffset=0)
pointer to the front of the spike buffer
Definition: spike_buffer.cpp:223
SpikeBuffer::Impl::length
size_t length()
Definition: spike_buffer.cpp:105
SpikeBuffer::Impl::schedule
void schedule(int neurId, int grpId, unsigned short int delay)
Definition: spike_buffer.cpp:110
SpikeBuffer::SpikeBuffer
SpikeBuffer(int minDelay, int maxDelay)
SpikeBuffer Constructor.
Definition: spike_buffer.cpp:214
SpikeBuffer::Impl::step
void step()
Definition: spike_buffer.cpp:128
SpikeBuffer::reset
void reset(int minDelay, int maxDelay)
Reset buffer data.
Definition: spike_buffer.cpp:221
SpikeBuffer::SpikeIterator
Iterator to loop over the scheduled spikes at a certain delay.
Definition: spike_buffer.h:97