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