From 4fae6c009c8bd97dbf07db0f46f4b1909b829b03 Mon Sep 17 00:00:00 2001 From: NicolasJPosey Date: Sat, 9 Aug 2025 21:56:10 -0700 Subject: [PATCH 1/5] Upgrade EventBuffer to be a templated class This involved moving the EventBuffer.cpp information into the header file and updating previous usages to use uint64_t type which was the old default. Also cleaned up redudent overrides and added getters and setters to the EventBuffer so that it's friendship with neuro classes could be removed. --- Simulator/Recorders/RecordableVector.h | 8 + Simulator/Vertices/EventBuffer.cpp | 120 ------------ Simulator/Vertices/EventBuffer.h | 178 ++++++++++++++---- Simulator/Vertices/Neuro/AllSpikingNeurons.h | 2 +- .../Vertices/Neuro/AllSpikingNeurons_d.cpp | 24 +-- Testing/UnitTesting/EventBufferTests.cpp | 55 +++++- Testing/UnitTesting/Hdf5RecorderTests.cpp | 12 +- Testing/UnitTesting/XmlRecorderTests.cpp | 10 +- 8 files changed, 227 insertions(+), 182 deletions(-) delete mode 100644 Simulator/Vertices/EventBuffer.cpp diff --git a/Simulator/Recorders/RecordableVector.h b/Simulator/Recorders/RecordableVector.h index 5f5cf1e4f..c60fb9360 100644 --- a/Simulator/Recorders/RecordableVector.h +++ b/Simulator/Recorders/RecordableVector.h @@ -93,6 +93,14 @@ template class RecordableVector : public RecordableBase { return dataSeries_; } + /// @brief Gets pointer to contiguous host memory array + /// @return Pointer to the first element in host memory + /// @note Returns nullptr if vector is empty + T *data() + { + return dataSeries_.data(); + } + /// Cereal serialization method template void serialize(Archive &archive) { diff --git a/Simulator/Vertices/EventBuffer.cpp b/Simulator/Vertices/EventBuffer.cpp deleted file mode 100644 index 05fa01805..000000000 --- a/Simulator/Vertices/EventBuffer.cpp +++ /dev/null @@ -1,120 +0,0 @@ -/** -* @file EventBuffer.cpp -* -* @ingroup Simulator/Vertices - * - * @brief Encapsulation of vertex event buffering -* -* @author Created by Prof. Michael Stiber on 11/23/21. -*/ - -#include "EventBuffer.h" -#include "Global.h" -#include -#include - -EventBuffer::EventBuffer(int maxEvents) -{ - dataSeries_.assign(maxEvents, numeric_limits::max()); - clear(); - setDataType(); // set up data type for recording purpose -} - - -// set up a string representing the basic data type -void EventBuffer::setDataType() -{ - basicDataType_ = typeid(uint64_t).name(); -} - -/// @brief Get the value of the recordable variable at the specified index. -/// @param index The index of the recorded value to retrieve. -/// @return A variant representing the recorded value (uint64_t, double, or string). -variantTypes EventBuffer::getElement(int index) const -{ - return dataSeries_[(epochStart_ + index) % dataSeries_.size()]; -} - - -const string &EventBuffer::getDataType() const -{ - return basicDataType_; -} - -int EventBuffer::getNumElementsInEpoch() const -{ - return numElementsInEpoch_; -} - -int EventBuffer::getNumElements() const -{ - return numElementsInEpoch_; -} - -void EventBuffer::resize(int maxEvents) -{ - // Only an empty buffer can be resized - assert(dataSeries_.empty()); - dataSeries_.resize(maxEvents, 0); - // If we resized, we should clear everything - clear(); -} - -void EventBuffer::clear() -{ - bufferFront_ = 0; - bufferEnd_ = 0; - epochStart_ = 0; - numElementsInEpoch_ = 0; -} - -uint64_t EventBuffer::operator[](int i) const -{ - return dataSeries_[(epochStart_ + i) % dataSeries_.size()]; -} - -void EventBuffer::startNewEpoch() -{ - epochStart_ = bufferEnd_; - bufferFront_ = bufferEnd_; - numElementsInEpoch_ = 0; -} - -void EventBuffer::insertEvent(uint64_t timeStep) -{ - // If the buffer is full, then this is an error condition - assert((numElementsInEpoch_ < dataSeries_.size())); - - // Insert time step and increment the queue end index, mod the buffer size - dataSeries_[bufferEnd_] = timeStep; - bufferEnd_ = (bufferEnd_ + 1) % dataSeries_.size(); - numElementsInEpoch_ += 1; -} - -uint64_t EventBuffer::getPastEvent(int offset) const -{ - // Quick checks: offset must be in past, and not larger than the buffer size - assert(((offset < 0)) && (offset > -(dataSeries_.size() - 1))); - - // The event is at bufferEnd_ + offset (taking into account the - // buffer size, and the fact that offset is negative). - int index = bufferEnd_ + offset; - if (index < 0) - index += dataSeries_.size(); - - // Need to check that we're not asking for an item so long ago that it is - // not in the buffer. Note that there are three possibilities: - // 1. if bufferEnd_ > bufferFront_, then valid entries are within the range - // [bufferFront_, bufferEnd_) - // 2. if bufferEnd_ < bufferFront_, then the buffer wraps around the end of - // vector and valid entries are within the range [0, bufferEnd_) or the - // range [bufferFront_, size()). - // 3. if buffer is empty (bufferFront_ == bufferEnd_), then there are no events - // - // Note that this means that index at this point must always be less than - // bufferEnd_ AND >= queueFront. - if ((index < bufferEnd_) && (index >= bufferFront_)) - return dataSeries_[index]; - else - return numeric_limits::max(); -} diff --git a/Simulator/Vertices/EventBuffer.h b/Simulator/Vertices/EventBuffer.h index 987dfabfb..1133d8ed0 100644 --- a/Simulator/Vertices/EventBuffer.h +++ b/Simulator/Vertices/EventBuffer.h @@ -26,11 +26,7 @@ // cereal #include -class AllSpikingNeurons; -class AllIFNeurons; -class EventBuffer : public RecordableVector { - friend class AllIFNeurons; - friend class AllSpikingNeurons; +template class EventBuffer : public RecordableVector { public: /// Create EventBuffer that is sized appropriately @@ -41,7 +37,13 @@ class EventBuffer : public RecordableVector { /// an empty and a full buffer. /// /// @param maxEvents Defaults to zero; otherwise, buffer size is set - EventBuffer(int maxEvents = 0); + EventBuffer(int maxEvents = 0) + { + //RecordableVector(); + this->dataSeries_.assign(maxEvents, numeric_limits::max()); + clear(); + this->setDataType(); // set up data type for recording purpose + } /** @name Recorder Interface * virtual methods in RecordableBase for use by Recorder classes @@ -52,31 +54,88 @@ class EventBuffer : public RecordableVector { /// Get the value of the recordable variable at the specified index. /// @param index The index of the recorded value to retrieve. /// @return A variant representing the recorded value (uint64_t, double, or string). - virtual variantTypes getElement(int index) const override; + variantTypes getElement(int index) const + { + return this->dataSeries_[(epochStart_ + index) % this->dataSeries_.size()]; + } /// Get the number of elements that needs to be recorded - virtual int getNumElements() const override; - - /// Return the runtime data type info of unit64_t - virtual void setDataType() override; - - /// Get the basic data type of the recordable variable - virtual const string &getDataType() const override; + int getNumElements() const + { + return numElementsInEpoch_; + } /// Start a new epoch /// /// Resets the internal variables associated with tracking the events in a epoch. Note that this doesn't /// affect the contents of the buffer; it just resets things so that the epoch start is the index of the next /// event to be enqueued and that the number of events in the epoch is 0. - virtual void startNewEpoch() override; + void startNewEpoch() + { + epochStart_ = bufferEnd_; + bufferFront_ = bufferEnd_; + numElementsInEpoch_ = 0; + } ///@} + + /// @brief Accessor for the buffer front value. + /// @return Returns index of the first event in the queue. + int getBufferFront() const + { + return bufferFront_; + } + + /// @brief Accessor for the buffer end value. + /// @return Returns index of the last event in the queue. + int getBufferEnd() const + { + return bufferEnd_; + } + + /// @brief Accessor for the epoch start value. + /// @return Returns index of the start of the events in the current epoch. + int getEpochStart() const + { + return epochStart_; + } + /// Get number of events in the current/preceding epoch /// /// Getting the number of events in the current epoch (or, in between epochs, the number of events /// in the preceding epoch) is not the same as the number of events in the buffer, because the buffer /// retains events from the previous epoch, too. - int getNumElementsInEpoch() const; + int getNumElementsInEpoch() const + { + return numElementsInEpoch_; + } + + /// Getters are needed for copying from the GPU. Allows us to remove the friend keyword requirement. + /// { + /// @brief Mutator for the buffer front value. + void setBufferFront(int bufferFront) + { + bufferFront_ = bufferFront; + } + + /// @brief Mutator for the buffer end value. + void setBufferEnd(int bufferEnd) + { + bufferEnd_ = bufferEnd; + } + + /// @brief Mutator for the epoch start value. + void setEpochStart(int epochStart) + { + epochStart_ = epochStart; + } + + /// Sets number of events in the current/preceding epoch + void setNumElementsInEpoch(int numElementsInEpoch) + { + numElementsInEpoch_ = numElementsInEpoch; + } + /// } /// Resize event buffer /// @@ -85,7 +144,14 @@ class EventBuffer : public RecordableVector { /// /// @pre current buffer must be empty /// @param maxEvents Buffer size - virtual void resize(int maxEvents) override; + void resize(int maxEvents) + { + // Only an empty buffer can be resized + assert(this->dataSeries_.empty()); + this->dataSeries_.resize(maxEvents, 0); + // If we resized, we should clear everything + clear(); + } /// Access event from current epoch /// @@ -93,14 +159,30 @@ class EventBuffer : public RecordableVector { /// event in the epoch (element numElementsInEpoch_ - 1 would be the last element in the epoch). /// /// @param i element number - uint64_t operator[](int i) const; + T operator[](int i) const + { + return this->dataSeries_[(epochStart_ + i) % this->dataSeries_.size()]; + } /** @name Vertex and Edge Interface * EventBuffer interface for use by the Vertex and Edge classes */ ///@{ /// Reset member variables consistent with an empty buffer - void clear(); + void clear() + { + bufferFront_ = 0; + bufferEnd_ = 0; + epochStart_ = 0; + numElementsInEpoch_ = 0; + } + + /// @brief + /// @return Returns the size of the buffer. + int size() + { + return this->dataSeries_.size(); + } /// Insert an event time step /// @@ -109,7 +191,16 @@ class EventBuffer : public RecordableVector { /// /// @pre The buffer is not full /// @param timeStep Value to store in buffer - void insertEvent(uint64_t timeStep); + void insertEvent(T timeStep) + { + // If the buffer is full, then this is an error condition + assert((numElementsInEpoch_ < this->dataSeries_.size())); + + // Insert time step and increment the queue end index, mod the buffer size + this->dataSeries_[bufferEnd_] = timeStep; + bufferEnd_ = (bufferEnd_ + 1) % this->dataSeries_.size(); + numElementsInEpoch_ += 1; + } /// Get an event from a time in the past /// @@ -118,11 +209,43 @@ class EventBuffer : public RecordableVector { /// /// @param offset How many events ago. Must be negative. If that event isn't in the buffer, /// or if the buffer is empty, returns ULONG_MAX. - uint64_t getPastEvent(int offset) const; + T getPastEvent(int offset) const + { + // Quick checks: offset must be in past, and not larger than the buffer size + assert(((offset < 0)) && (offset > -(this->dataSeries_.size() - 1))); + + // The event is at bufferEnd_ + offset (taking into account the + // buffer size, and the fact that offset is negative). + int index = bufferEnd_ + offset; + if (index < 0) + index += this->dataSeries_.size(); + + // Need to check that we're not asking for an item so long ago that it is + // not in the buffer. Note that there are three possibilities: + // 1. if bufferEnd_ > bufferFront_, then valid entries are within the range + // [bufferFront_, bufferEnd_) + // 2. if bufferEnd_ < bufferFront_, then the buffer wraps around the end of + // vector and valid entries are within the range [0, bufferEnd_) or the + // range [bufferFront_, size()). + // 3. if buffer is empty (bufferFront_ == bufferEnd_), then there are no events + // + // Note that this means that index at this point must always be less than + // bufferEnd_ AND >= queueFront. + if ((index < bufferEnd_) && (index >= bufferFront_)) + return this->dataSeries_[index]; + else + return numeric_limits::max(); + } ///@} /// Cereal serialization method - template void serialize(Archive &archive); + template void serialize(Archive &archive) + { + archive(cereal::base_class>(this), + cereal::make_nvp("bufferFront", bufferFront_), cereal::make_nvp("bufferEnd", bufferEnd_), + cereal::make_nvp("epochStart", epochStart_), + cereal::make_nvp("numElementsInEpoch", numElementsInEpoch_)); + } private: /// Holds the event time steps @@ -151,13 +274,4 @@ class EventBuffer : public RecordableVector { }; -CEREAL_REGISTER_TYPE(EventBuffer); - -/// Cereal serialization method -template void EventBuffer::serialize(Archive &archive) -{ - archive(cereal::base_class>(this), - cereal::make_nvp("bufferFront", bufferFront_), cereal::make_nvp("bufferEnd", bufferEnd_), - cereal::make_nvp("epochStart", epochStart_), - cereal::make_nvp("numElementsInEpoch", numElementsInEpoch_)); -} +// CEREAL_REGISTER_TYPE(EventBuffer); diff --git a/Simulator/Vertices/Neuro/AllSpikingNeurons.h b/Simulator/Vertices/Neuro/AllSpikingNeurons.h index 394f7091d..6e79cd3e7 100644 --- a/Simulator/Vertices/Neuro/AllSpikingNeurons.h +++ b/Simulator/Vertices/Neuro/AllSpikingNeurons.h @@ -121,7 +121,7 @@ class AllSpikingNeurons : public AllVertices { DeviceVector hasFired_; /// Holds at least one epoch's worth of event times for every vertex - vector vertexEvents_; + vector> vertexEvents_; /// The summation point for each vertex. /// Summation points are places where the synapses connected to the vertex diff --git a/Simulator/Vertices/Neuro/AllSpikingNeurons_d.cpp b/Simulator/Vertices/Neuro/AllSpikingNeurons_d.cpp index 91edc75f1..9a3602ec6 100644 --- a/Simulator/Vertices/Neuro/AllSpikingNeurons_d.cpp +++ b/Simulator/Vertices/Neuro/AllSpikingNeurons_d.cpp @@ -59,20 +59,20 @@ void AllSpikingNeurons::copyToDevice() int cpu_queue_front[count]; for (int i = 0; i < count; i++) { - cpu_queue_front[i] = vertexEvents_[i].bufferFront_; + cpu_queue_front[i] = vertexEvents_[i].getBufferFront(); } HANDLE_ERROR(cudaMemcpy(allVerticesDevice.bufferFront_, cpu_queue_front, count * sizeof(int), cudaMemcpyHostToDevice)); int cpu_queue_end[count]; for (int i = 0; i < count; i++) { - cpu_queue_end[i] = vertexEvents_[i].bufferEnd_; + cpu_queue_end[i] = vertexEvents_[i].getBufferEnd(); } HANDLE_ERROR(cudaMemcpy(allVerticesDevice.bufferEnd_, cpu_queue_end, count * sizeof(int), cudaMemcpyHostToDevice)); int cpu_queue_start[count]; for (int i = 0; i < count; i++) { - cpu_queue_start[i] = vertexEvents_[i].epochStart_; + cpu_queue_start[i] = vertexEvents_[i].getEpochStart(); } HANDLE_ERROR(cudaMemcpy(allVerticesDevice.epochStart_, cpu_queue_start, count * sizeof(int), cudaMemcpyHostToDevice)); @@ -83,9 +83,9 @@ void AllSpikingNeurons::copyToDevice() // All EventBuffers are of the same size, // which is one greater than maxSpikes in GPU spikeHistory array. - int maxSpikes = vertexEvents_[0].dataSeries_.size(); + int maxSpikes = vertexEvents_[0].size(); for (int i = 0; i < count; i++) { - HANDLE_ERROR(cudaMemcpy(pSpikeHistory[i], vertexEvents_[i].dataSeries_.data(), + HANDLE_ERROR(cudaMemcpy(pSpikeHistory[i], vertexEvents_[i].data(), maxSpikes * sizeof(uint64_t), cudaMemcpyHostToDevice)); } } @@ -112,28 +112,28 @@ void AllSpikingNeurons::copyFromDevice() HANDLE_ERROR(cudaMemcpy(cpu_spike_count, allVerticesDevice.numElementsInEpoch_, numVertices * sizeof(int), cudaMemcpyDeviceToHost)); for (int i = 0; i < numVertices; i++) { - vertexEvents_[i].numElementsInEpoch_ = cpu_spike_count[i]; + vertexEvents_[i].setNumElementsInEpoch(cpu_spike_count[i]); } int queue_front[numVertices]; HANDLE_ERROR(cudaMemcpy(queue_front, allVerticesDevice.bufferFront_, numVertices * sizeof(int), cudaMemcpyDeviceToHost)); for (int i = 0; i < numVertices; i++) { - vertexEvents_[i].bufferFront_ = queue_front[i]; + vertexEvents_[i].setBufferFront(queue_front[i]); } int queue_end[numVertices]; HANDLE_ERROR(cudaMemcpy(queue_end, allVerticesDevice.bufferEnd_, numVertices * sizeof(int), cudaMemcpyDeviceToHost)); for (int i = 0; i < numVertices; i++) { - vertexEvents_[i].bufferEnd_ = queue_end[i]; + vertexEvents_[i].setBufferEnd(queue_end[i]); } int epoch_start[numVertices]; HANDLE_ERROR(cudaMemcpy(epoch_start, allVerticesDevice.epochStart_, numVertices * sizeof(int), cudaMemcpyDeviceToHost)); for (int i = 0; i < numVertices; i++) { - vertexEvents_[i].epochStart_ = epoch_start[i]; + vertexEvents_[i].setEpochStart(epoch_start[i]); } uint64_t *pSpikeHistory[numVertices]; @@ -142,9 +142,9 @@ void AllSpikingNeurons::copyFromDevice() // All EventBuffers are of the same size, // which is one greater than maxSpikes in GPU spikeHistory array. - int maxSpikes = vertexEvents_[0].dataSeries_.size(); + int maxSpikes = vertexEvents_[0].size(); for (int i = 0; i < numVertices; i++) { - HANDLE_ERROR(cudaMemcpy(vertexEvents_[i].dataSeries_.data(), pSpikeHistory[i], + HANDLE_ERROR(cudaMemcpy(vertexEvents_[i].data(), pSpikeHistory[i], maxSpikes * sizeof(uint64_t *), cudaMemcpyDeviceToHost)); } } @@ -165,7 +165,7 @@ void AllSpikingNeurons::clearDeviceSpikeCounts(AllSpikingNeuronsDeviceProperties vector epochStart(numVertices); for (int i = 0; i < epochStart.size(); ++i) { - epochStart[i] = vertexEvents_[i].bufferEnd_; + epochStart[i] = vertexEvents_[i].getBufferEnd(); } HANDLE_ERROR(cudaMemcpy(allVerticesDevice.epochStart_, epochStart.data(), numVertices * sizeof(int), cudaMemcpyHostToDevice)); diff --git a/Testing/UnitTesting/EventBufferTests.cpp b/Testing/UnitTesting/EventBufferTests.cpp index cde65c0df..bbfee36c1 100644 --- a/Testing/UnitTesting/EventBufferTests.cpp +++ b/Testing/UnitTesting/EventBufferTests.cpp @@ -10,23 +10,22 @@ #include "gtest/gtest.h" // A buffer which can hold 5 elements -EventBuffer buffer(5); +EventBuffer buffer(5); //GetElement when buffer is empty -//Assuming getElement() returns uint64_t -TEST(EventBufferTest, GetElementFromEmptyBuffer) +TEST(EventBufferTest, GetElementFromEmptyBufferUint64) { EXPECT_EQ(std::get(buffer.getElement(0)), std::numeric_limits::max()); } // GetPastEvent when buffer is empty -TEST(EventBufferTest, GetPastEventFromEmptyBuffer) +TEST(EventBufferTest, GetPastEventFromEmptyBufferUint64) { EXPECT_EQ(buffer.getPastEvent(-1), std::numeric_limits::max()); } // Insert into empty buffer -TEST(EventBufferTest, InsertEventEmptyBuffer) +TEST(EventBufferTest, InsertEventEmptyBufferUint64) { buffer.insertEvent(10); buffer.insertEvent(20); @@ -36,7 +35,7 @@ TEST(EventBufferTest, InsertEventEmptyBuffer) } // Insert when buffer is full, test wrap around -TEST(EventBufferTest, BufferWrapAround) +TEST(EventBufferTest, BufferWrapAroundUint64) { buffer.insertEvent(30); buffer.insertEvent(40); @@ -51,4 +50,48 @@ TEST(EventBufferTest, BufferWrapAround) EXPECT_EQ(std::get(buffer.getElement(2)), 30); EXPECT_EQ(std::get(buffer.getElement(3)), 40); EXPECT_EQ(std::get(buffer.getElement(4)), 50); +} + +// A buffer which can hold 5 elements +EventBuffer bufferDouble(5); + +//GetElement when buffer is empty +//Assuming getElement() returns uint64_t +TEST(EventBufferTest, GetElementFromEmptyBufferDouble) +{ + EXPECT_EQ(std::get(bufferDouble.getElement(0)), std::numeric_limits::max()); +} + +// GetPastEvent when buffer is empty +TEST(EventBufferTest, GetPastEventFromEmptyBufferDouble) +{ + EXPECT_EQ(bufferDouble.getPastEvent(-1), std::numeric_limits::max()); +} + +// Insert into empty buffer +TEST(EventBufferTest, InsertEventEmptyBufferDouble) +{ + bufferDouble.insertEvent(10.0); + bufferDouble.insertEvent(20.0); + + EXPECT_EQ(std::get(bufferDouble.getElement(0)), 10.0); + EXPECT_EQ(std::get(bufferDouble.getElement(1)), 20.0); +} + +// Insert when buffer is full, test wrap around +TEST(EventBufferTest, BufferWrapAroundDouble) +{ + bufferDouble.insertEvent(30.0); + bufferDouble.insertEvent(40.0); + bufferDouble.insertEvent(50.0); + + //Insert into A full buffer + //bufferDouble.insertEvent(60.0); + + // The buffer should have overwritten 60 inplace of 10 + //EXPECT_EQ(std::get(buffer.getElement(0)), 60); + EXPECT_EQ(std::get(bufferDouble.getElement(1)), 20.0); + EXPECT_EQ(std::get(bufferDouble.getElement(2)), 30.0); + EXPECT_EQ(std::get(bufferDouble.getElement(3)), 40.0); + EXPECT_EQ(std::get(bufferDouble.getElement(4)), 50.0); } \ No newline at end of file diff --git a/Testing/UnitTesting/Hdf5RecorderTests.cpp b/Testing/UnitTesting/Hdf5RecorderTests.cpp index 327b989b2..c77d47c7b 100644 --- a/Testing/UnitTesting/Hdf5RecorderTests.cpp +++ b/Testing/UnitTesting/Hdf5RecorderTests.cpp @@ -48,7 +48,7 @@ TEST(Hdf5RecorderTest, RegisterVariableTest) recorder.init(); // Create an EventBuffer for testing - EventBuffer eventBuffer; + EventBuffer eventBuffer; const H5std_string hdf5Name("test_var"); // Register the variable @@ -74,8 +74,8 @@ TEST(Hdf5RecorderTest, RegisterVectorVariableTest) recorder.init(); // Create mock EventBuffer objects for testing - EventBuffer buffer0; - EventBuffer buffer1; + EventBuffer buffer0; + EventBuffer buffer1; // Create a vector of pointers to EventBuffer objects std::vector bufferPointers = {&buffer0, &buffer1}; @@ -136,7 +136,7 @@ TEST(Hdf5RecorderTest, SaveSimDataTest) recorder.init(); // Create and configure EventBuffer for testing - EventBuffer eventBuffer(5); // Initialize with a size that matches the mock data + EventBuffer eventBuffer(5); // Initialize with a size that matches the mock data eventBuffer.insertEvent(1); eventBuffer.insertEvent(2); eventBuffer.insertEvent(3); @@ -226,7 +226,7 @@ TEST(Hdf5RecorderTest, CompileHistoriesTest) recorder.init(); // Create and configure variables for testing - EventBuffer eventBufferInt(5); // Example with int type + EventBuffer eventBufferInt(5); // Example with int type // Register the variable with Hdf5Recorder as DYNAMIC recorder.registerVariable("test_var_int", eventBufferInt, Recorder::UpdatedType::DYNAMIC); @@ -277,7 +277,7 @@ TEST(Hdf5RecorderTest, CompileHistoriesVertexTypeTest) recorder.init(); // Create and configure EventBuffer for testing (stored as int) - EventBuffer eventBufferNeuron(5); + EventBuffer eventBufferNeuron(5); // Register the variable with Hdf5Recorder as DYNAMIC recorder.registerVariable("neuron_types", eventBufferNeuron, Recorder::UpdatedType::DYNAMIC); diff --git a/Testing/UnitTesting/XmlRecorderTests.cpp b/Testing/UnitTesting/XmlRecorderTests.cpp index 2291ff243..afa327ad4 100644 --- a/Testing/UnitTesting/XmlRecorderTests.cpp +++ b/Testing/UnitTesting/XmlRecorderTests.cpp @@ -49,7 +49,7 @@ TEST(XmlRecorderTest, RegisterVariableTest) // Create an instance of XmlRecorder XmlRecorder recorder; // Create an EventBuffer for testing - EventBuffer eventBuffer; + EventBuffer eventBuffer; // Register the EventBuffer variable recorder.registerVariable("eventBuffer", eventBuffer, Recorder::UpdatedType::DYNAMIC); @@ -131,8 +131,8 @@ TEST(XmlRecorderTest, RegisterVectorVariableTest) ASSERT_TRUE(recorderTest_ != nullptr); // Create mock EventBuffer objects for testing - EventBuffer buffer0; - EventBuffer buffer1; + EventBuffer buffer0; + EventBuffer buffer1; // Create a vector of pointers to EventBuffer objects std::vector bufferPointers = {&buffer0, &buffer1}; @@ -159,7 +159,7 @@ TEST(XmlRecorderTest, CompileHistoriesTest) ASSERT_NE(nullptr, vertices); // Create a mock EventBuffer object // buffer size is set to 4 - EventBuffer buffer0(4); + EventBuffer buffer0(4); // Register variables recorderTest_->registerVariable("neuron0", buffer0, Recorder::UpdatedType::DYNAMIC); @@ -223,7 +223,7 @@ TEST(XmlRecorderTest, SaveSimDataTest) = Factory::getInstance().createType("AllLIFNeurons"); ASSERT_NE(nullptr, vertices); // Create a mock EventBuffer object - EventBuffer buffer(4); + EventBuffer buffer(4); // initialize the XmlRecorder object recorderTest_->init(); From 72746832c159fe60aa737e78a48ec5560af4d78b Mon Sep 17 00:00:00 2001 From: NicolasJPosey Date: Sat, 9 Aug 2025 22:05:13 -0700 Subject: [PATCH 2/5] Fix clang format issue --- Simulator/Vertices/EventBuffer.h | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Simulator/Vertices/EventBuffer.h b/Simulator/Vertices/EventBuffer.h index 1133d8ed0..b69d36694 100644 --- a/Simulator/Vertices/EventBuffer.h +++ b/Simulator/Vertices/EventBuffer.h @@ -27,7 +27,6 @@ #include template class EventBuffer : public RecordableVector { - public: /// Create EventBuffer that is sized appropriately /// @@ -85,7 +84,7 @@ template class EventBuffer : public RecordableVector { { return bufferFront_; } - + /// @brief Accessor for the buffer end value. /// @return Returns index of the last event in the queue. int getBufferEnd() const @@ -117,7 +116,7 @@ template class EventBuffer : public RecordableVector { { bufferFront_ = bufferFront; } - + /// @brief Mutator for the buffer end value. void setBufferEnd(int bufferEnd) { @@ -177,7 +176,7 @@ template class EventBuffer : public RecordableVector { numElementsInEpoch_ = 0; } - /// @brief + /// @brief /// @return Returns the size of the buffer. int size() { @@ -242,9 +241,10 @@ template class EventBuffer : public RecordableVector { template void serialize(Archive &archive) { archive(cereal::base_class>(this), - cereal::make_nvp("bufferFront", bufferFront_), cereal::make_nvp("bufferEnd", bufferEnd_), - cereal::make_nvp("epochStart", epochStart_), - cereal::make_nvp("numElementsInEpoch", numElementsInEpoch_)); + cereal::make_nvp("bufferFront", bufferFront_), + cereal::make_nvp("bufferEnd", bufferEnd_), + cereal::make_nvp("epochStart", epochStart_), + cereal::make_nvp("numElementsInEpoch", numElementsInEpoch_)); } private: From a0918e37881ca2336d08602c38b2c1a7f865baed Mon Sep 17 00:00:00 2001 From: NicolasJPosey Date: Mon, 11 Aug 2025 15:07:33 -0700 Subject: [PATCH 3/5] Minor cleanup --- Simulator/Vertices/EventBuffer.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Simulator/Vertices/EventBuffer.h b/Simulator/Vertices/EventBuffer.h index b69d36694..b92026f61 100644 --- a/Simulator/Vertices/EventBuffer.h +++ b/Simulator/Vertices/EventBuffer.h @@ -38,7 +38,6 @@ template class EventBuffer : public RecordableVector { /// @param maxEvents Defaults to zero; otherwise, buffer size is set EventBuffer(int maxEvents = 0) { - //RecordableVector(); this->dataSeries_.assign(maxEvents, numeric_limits::max()); clear(); this->setDataType(); // set up data type for recording purpose @@ -109,7 +108,7 @@ template class EventBuffer : public RecordableVector { return numElementsInEpoch_; } - /// Getters are needed for copying from the GPU. Allows us to remove the friend keyword requirement. + /// Setters are needed for copying from the GPU. Allows us to remove the friend keyword requirement. /// { /// @brief Mutator for the buffer front value. void setBufferFront(int bufferFront) From 365bda72f28926d3abd8d551e96dc6ed27f43f1a Mon Sep 17 00:00:00 2001 From: NicolasJPosey Date: Tue, 12 Aug 2025 10:30:09 -0700 Subject: [PATCH 4/5] Add documentation for this pointer use --- Simulator/Vertices/EventBuffer.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Simulator/Vertices/EventBuffer.h b/Simulator/Vertices/EventBuffer.h index b92026f61..ad2b1ac22 100644 --- a/Simulator/Vertices/EventBuffer.h +++ b/Simulator/Vertices/EventBuffer.h @@ -26,6 +26,8 @@ // cereal #include +// Uses this pointer because we have a template class inheriting from other template class +// All base class references need to be accessed through the this pointer template class EventBuffer : public RecordableVector { public: /// Create EventBuffer that is sized appropriately From d70d71d15191f58044fb00da7772b3f7a2ccc39f Mon Sep 17 00:00:00 2001 From: NicolasJPosey Date: Wed, 28 Jan 2026 18:43:20 -0800 Subject: [PATCH 5/5] Remove unnecessary comment --- Testing/UnitTesting/EventBufferTests.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/Testing/UnitTesting/EventBufferTests.cpp b/Testing/UnitTesting/EventBufferTests.cpp index bbfee36c1..0987e6790 100644 --- a/Testing/UnitTesting/EventBufferTests.cpp +++ b/Testing/UnitTesting/EventBufferTests.cpp @@ -56,7 +56,6 @@ TEST(EventBufferTest, BufferWrapAroundUint64) EventBuffer bufferDouble(5); //GetElement when buffer is empty -//Assuming getElement() returns uint64_t TEST(EventBufferTest, GetElementFromEmptyBufferDouble) { EXPECT_EQ(std::get(bufferDouble.getElement(0)), std::numeric_limits::max());