Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
67 commits
Select commit Hold shift + click to select a range
08dd027
Add loadEpochInputs to OperationManager
NicolasJPosey Jun 23, 2025
a34356f
Add vertices device struct to 911 class
NicolasJPosey Jun 23, 2025
b02e61a
Merge remote-tracking branch 'origin/PoseyDevelopment' into issue-858…
NicolasJPosey Jul 5, 2025
aeef7d4
Add total number of events data member to InputManager
NicolasJPosey Jul 16, 2025
f58ad17
Initial CPU GPU architecture documentation
NicolasJPosey Aug 4, 2025
b456abc
Refactor of loadEpochInputs to support loading inputs to GPU
NicolasJPosey Aug 4, 2025
8b54e96
Refactor getEdgeToClosestResponder method to be a All911Vertices meth…
NicolasJPosey Aug 4, 2025
6340556
Forgot CPU code
NicolasJPosey Aug 4, 2025
6cbb595
Some GPU implementations but is incomplete
NicolasJPosey Aug 4, 2025
9209e53
Merge remote-tracking branch 'origin/PoseyDevelopment' into issue-858…
NicolasJPosey Aug 4, 2025
bab8265
Remove reserve call since RecordableVector doesn't implement it
NicolasJPosey Aug 4, 2025
4eba0c1
Refactor internal vector use in PSAP and RESP advance logic
NicolasJPosey Aug 6, 2025
9b7f77f
Convert call metrics to EventBuffers and swap push back for insert ev…
NicolasJPosey Aug 8, 2025
bba175c
Replace numeric bool with actual bool for readability
NicolasJPosey Aug 8, 2025
46f4000
Change vector type from RecordableVector to EventBuffer
NicolasJPosey Aug 8, 2025
03f598d
Merge remote-tracking branch 'origin/PoseyDevelopment' into issue-858…
NicolasJPosey Aug 12, 2025
9d07ab0
Bug fix for copying spike histories from device
NicolasJPosey Aug 23, 2025
d8b74c2
Add a guard and debugging message for GPU random noise
NicolasJPosey Aug 23, 2025
b055214
Updates to support copying to and from GPU
NicolasJPosey Aug 23, 2025
c3893e5
Support for copying to and from GPU and make type float for now
NicolasJPosey Aug 23, 2025
3fcf848
Add GPU 911 vertices to make list
NicolasJPosey Aug 23, 2025
944c941
Implementation runs but results aren't quite right
NicolasJPosey Aug 23, 2025
45d2f31
Fix case sensative copying of call responder types
NicolasJPosey Aug 25, 2025
ba7d73a
Fix bug using wrong size for queue length and utilization histories
NicolasJPosey Aug 27, 2025
815e5b3
Remove debugging printfs and replace asserts with printfs for errors
NicolasJPosey Aug 27, 2025
1b9541e
General cleanup
NicolasJPosey Aug 27, 2025
df7d22b
Free the array used to determine available servers and units in kernels.
NicolasJPosey Aug 28, 2025
d9f1b07
Readd support for getting dropped calls
NicolasJPosey Aug 30, 2025
815f79a
Fix error if a dropped call is found after the first epoch
NicolasJPosey Aug 30, 2025
6da281f
Support for noise in 911 models
NicolasJPosey Aug 30, 2025
0222e4b
Add assert for random number thread count
NicolasJPosey Aug 30, 2025
9c5ab92
Add support for using noise to simulate attempted redials
NicolasJPosey Aug 31, 2025
efe6790
Fix isFull error message to show right buffer size
NicolasJPosey Aug 31, 2025
d1465cc
Fix bug with waiting queue check
NicolasJPosey Aug 31, 2025
9c76eaf
Debugging statements for memory analysis
NicolasJPosey Sep 3, 2025
ce3ebae
Add some larger 911 graphs
NicolasJPosey Sep 4, 2025
6a34f93
Updates to history to support less memory usage on GPU
NicolasJPosey Sep 4, 2025
b228eae
Fix firing rate value
NicolasJPosey Sep 4, 2025
8efb90e
Fix issue using wrong buffer size
NicolasJPosey Sep 4, 2025
6365ff3
Fix getting front index when we want end index for queue length calcu…
NicolasJPosey Sep 4, 2025
a8e49ce
Add back in random redial attempt
NicolasJPosey Sep 4, 2025
1f16f36
More updates to reduce memory usage
NicolasJPosey Sep 6, 2025
495b526
Fix bug with vertex queue size
NicolasJPosey Sep 6, 2025
563c28f
Another CircularBuffer size bug fix
NicolasJPosey Sep 6, 2025
543412c
Fix firing rate and change epoch parameters to reduce memory
NicolasJPosey Sep 6, 2025
2733dfc
Add an approximate state wide, month long configuration
NicolasJPosey Sep 6, 2025
8e2b5c3
General cleanup and adding of comments
NicolasJPosey Sep 6, 2025
464de26
GPU Optimizations
NicolasJPosey Oct 25, 2025
3d17af3
Dataset updates
NicolasJPosey Nov 22, 2025
7a2b6e5
Timing adds, documentation, and updates
NicolasJPosey Nov 22, 2025
62464e7
Add regression testing documentation markdown
NicolasJPosey Jan 16, 2026
50b81d8
Update after changing Abandoned and QueueLength history types
NicolasJPosey Jan 21, 2026
4b6e5b3
Add small 911 test to regression script
NicolasJPosey Jan 21, 2026
f346aa4
Add larger 911 test
NicolasJPosey Jan 21, 2026
ef35442
Merge remote-tracking branch 'origin/PoseyDevelopment' into issue-858…
NicolasJPosey Jan 21, 2026
feab222
Remove testing datasets
NicolasJPosey Jan 21, 2026
19f664a
Remove temp timing changes
NicolasJPosey Jan 21, 2026
032ad01
Merge remote-tracking branch 'origin/PoseyDevelopment' into issue-858…
NicolasJPosey Jan 31, 2026
f1d252a
Correct how 2D arrays are copied from device to host
NicolasJPosey Jan 31, 2026
e32985d
Add noise state logging for debugging
NicolasJPosey Feb 1, 2026
8e6bee0
Noise is now generated and used for graphs with less than 100 vertices
NicolasJPosey Feb 1, 2026
6219a8f
Fix formatting
NicolasJPosey Feb 1, 2026
8a11cb7
Try another clang fix
NicolasJPosey Feb 1, 2026
2e7ef29
Try to fix clang in function node file
NicolasJPosey Feb 1, 2026
ff729f0
clang fix attempt
NicolasJPosey Feb 1, 2026
1e3104e
more clang
NicolasJPosey Feb 1, 2026
c90f9ae
clang
NicolasJPosey Feb 1, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -264,7 +264,8 @@ if(ENABLE_CUDA)
Simulator/Vertices/Neuro/AllLIFNeurons_d.cpp
Simulator/Vertices/Neuro/AllIZHNeurons_d.cpp
Simulator/Vertices/Neuro/AllIFNeurons_d.cpp
Simulator/Vertices/Neuro/AllSpikingNeurons_d.cpp)
Simulator/Vertices/Neuro/AllSpikingNeurons_d.cpp
Simulator/Vertices/NG911/All911Vertices_d.cpp)
set_source_files_properties(${cuda_VerticesSources} PROPERTIES LANGUAGE CUDA)
endif()

Expand Down Expand Up @@ -296,6 +297,7 @@ else()
list(REMOVE_ITEM Vertices_Source "${CMAKE_CURRENT_SOURCE_DIR}/Simulator/Vertices/Neuro/AllIZHNeurons_d.cpp")
list(REMOVE_ITEM Vertices_Source "${CMAKE_CURRENT_SOURCE_DIR}/Simulator/Vertices/Neuro/AllIFNeurons_d.cpp")
list(REMOVE_ITEM Vertices_Source "${CMAKE_CURRENT_SOURCE_DIR}/Simulator/Vertices/Neuro/AllSpikingNeurons_d.cpp")
list(REMOVE_ITEM Vertices_Source "${CMAKE_CURRENT_SOURCE_DIR}/Simulator/Vertices/NG911/All911Vertices_d.cpp")

add_library(Vertices STATIC ${Vertices_Source})

Expand Down
46 changes: 0 additions & 46 deletions Simulator/Connections/NG911/Connections911.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -96,52 +96,6 @@ bool Connections911::updateConnections()
}


/// Finds the outgoing edge from the given vertex to the Responder closest to
/// the emergency call location
BGSIZE Connections911::getEdgeToClosestResponder(const Call &call, BGSIZE vertexIdx)
{
All911Edges &edges911 = dynamic_cast<All911Edges &>(*edges_);

vertexType requiredType;
if (call.type == "Law")
requiredType = vertexType::LAW;
else if (call.type == "EMS")
requiredType = vertexType::EMS;
else if (call.type == "Fire")
requiredType = vertexType::FIRE;

// loop over the outgoing edges looking for the responder with the shortest
// Euclidean distance to the call's location.
BGSIZE startOutEdg = synapseIndexMap_->outgoingEdgeBegin_[vertexIdx];
BGSIZE outEdgCount = synapseIndexMap_->outgoingEdgeCount_[vertexIdx];
Layout911 &layout911
= dynamic_cast<Layout911 &>(Simulator::getInstance().getModel().getLayout());

BGSIZE resp, respEdge;
double minDistance = numeric_limits<double>::max();
for (BGSIZE eIdxMap = startOutEdg; eIdxMap < startOutEdg + outEdgCount; ++eIdxMap) {
BGSIZE outEdg = synapseIndexMap_->outgoingEdgeIndexMap_[eIdxMap];
assert(edges911.inUse_[outEdg]); // Edge must be in use

BGSIZE dstVertex = edges911.destVertexIndex_[outEdg];
if (layout911.vertexTypeMap_[dstVertex] == requiredType) {
double distance = layout911.getDistance(dstVertex, call.x, call.y);

if (distance < minDistance) {
minDistance = distance;
resp = dstVertex;
respEdge = outEdg;
}
}
}

// We must have found the closest responder of the right type
assert(minDistance < numeric_limits<double>::max());
assert(layout911.vertexTypeMap_[resp] == requiredType);
return respEdge;
}


/// Randomly delete 1 PSAP and rewire all the edges around it.
bool Connections911::erasePSAP(AllVertices &vertices, Layout &layout)
{
Expand Down
8 changes: 0 additions & 8 deletions Simulator/Connections/NG911/Connections911.h
Original file line number Diff line number Diff line change
Expand Up @@ -79,14 +79,6 @@ class Connections911 : public Connections {
/// @return true if successful, false otherwise.
virtual bool updateConnections() override;

/// Finds the outgoing edge from the given vertex to the Responder closest to
/// the emergency call location
///
/// @param call The call that needs a Responder
/// @param vertexIdx The index of the vertex serving the call (A PSAP)
/// @return The index of the outgoing edge to the closest Responder
BGSIZE getEdgeToClosestResponder(const Call &call, BGSIZE vertexIdx);

/// Returns the complete list of all deleted or added edges as a string.
/// @return xml representation of all deleted or added edges
string changedEdgesToXML(bool added);
Expand Down
8 changes: 7 additions & 1 deletion Simulator/Core/FunctionNodes/GenericFunctionNode.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,13 @@ class GenericFunctionNode : public IFunctionNode {
~GenericFunctionNode() = default;

/// Invokes the stored function if the sent operation type matches the operation type the function is stored as.
bool invokeFunction(const Operations &operation) const override;
virtual bool invokeFunction(const Operations &operation) const override;

/// TODO: Remove when IFunctionNode supports functions with non-empty signatures
virtual bool invokeFunction(const Operations &operation, uint64_t arg1, uint64_t arg2) const
{
return false;
}

private:
std::function<void()> function_; ///< Stored function.
Expand Down
6 changes: 6 additions & 0 deletions Simulator/Core/FunctionNodes/IFunctionNode.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#pragma once

#include "Operations.h"
#include <cstdint> ///for uint64_t

using namespace std;

Expand All @@ -18,9 +19,14 @@ class IFunctionNode {
/// Destructor.
virtual ~IFunctionNode() = default;

/// TODO: Need to refactor to allow for passing in arguments. Otherwise, FunctionNode classes can not support
/// non-empty signatures.
/// Invokes the stored function if the sent operation type matches the operation type the function is stored as.
virtual bool invokeFunction(const Operations &operation) const = 0;

/// Invokes the stored function using the two arguments as input
virtual bool invokeFunction(const Operations &operation, uint64_t arg1, uint64_t arg2) const = 0;

protected:
/// The operation type of the stored function.
Operations operationType_;
Expand Down
33 changes: 33 additions & 0 deletions Simulator/Core/FunctionNodes/TwoUint64ArgFunctionNode.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/**
* @file TwoUint64ArgFunctionNode.cpp
*
* @ingroup Simulator/Core/FunctionNodes
*
* @brief Stores a function with two uint64_t args to invoke. Used by operation manager to store functions to defined by an operation type.
*
* Function Signature supported : void (uint64_t,uint64_t)
*
*/

#include "TwoUint64ArgFunctionNode.h"
#include "Operations.h"
#include <functional>

/// Constructor, Function Signature: void (uint64_t, uint64_t)
TwoUint64ArgFunctionNode::TwoUint64ArgFunctionNode(
const Operations &operation, const std::function<void(uint64_t, uint64_t)> &func)
{
operationType_ = operation;
function_ = func;
}

/// Invokes the stored function if the sent operation type matches the operation type the function is stored as.
bool TwoUint64ArgFunctionNode::invokeFunction(const Operations &operation, uint64_t arg1,
uint64_t arg2) const
{
if (operation == operationType_) {
__invoke(function_, arg1, arg2);
return true;
}
return false;
}
38 changes: 38 additions & 0 deletions Simulator/Core/FunctionNodes/TwoUint64ArgFunctionNode.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/**
* @file TwoUint64ArgFunctionNode.h
*
* @ingroup Simulator/Core/FunctionNodes
*
* @brief Stores a function with two uint64_t args to invoke. Used by operation manager to store functions to defined by an operation type.
*
*/

#pragma once

#include "IFunctionNode.h"
#include <functional>

using namespace std;

class TwoUint64ArgFunctionNode : public IFunctionNode {
public:
/// Constructor, Function Signature: void ()
TwoUint64ArgFunctionNode(const Operations &operationType,
const std::function<void(uint64_t, uint64_t)> &function);

/// Destructor
~TwoUint64ArgFunctionNode() = default;

/// TODO: Remove when IFunctionNode supports functions with non-empty signatures
virtual bool invokeFunction(const Operations &operation) const
{
return false;
}

/// Invokes the stored function if the sent operation type matches the operation type the function is stored as.
virtual bool invokeFunction(const Operations &operation, uint64_t arg1,
uint64_t arg2) const override;

private:
std::function<void(uint64_t, uint64_t)> function_; ///< Stored function.
};
39 changes: 32 additions & 7 deletions Simulator/Core/GPUModel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#include "AllVertices.h"
#include "Connections.h"
#include "Global.h"
#include "MersenneTwister_d.h"
#include "OperationManager.h"

#ifdef VALIDATION_MODE
Expand Down Expand Up @@ -52,12 +53,15 @@ GPUModel::GPUModel() :
void GPUModel::allocDeviceStruct()
{
// Allocate memory for random noise array
int numVertices = Simulator::getInstance().getTotalVertices();
BGSIZE randNoise_d_size = numVertices * sizeof(float); // size of random noise array
int numVerticesNeedingNoise = layout_->getVertices().getNumberOfVerticesNeedingDeviceNoise();
int numberOfNoiseElements = roundUpNumberOfNoiseElements(numVerticesNeedingNoise);
LOG4CPLUS_DEBUG(fileLogger_,
"Number of elements allocated for noise: " << numberOfNoiseElements);
BGSIZE randNoise_d_size = numberOfNoiseElements * sizeof(float); // size of random noise array
HANDLE_ERROR(cudaMalloc((void **)&randNoise_d, randNoise_d_size));

// Allocate synapse inverse map in device memory
allocEdgeIndexMap(numVertices);
allocEdgeIndexMap(Simulator::getInstance().getTotalVertices());
}

/// Copies device memories to host memories and deallocates them.
Expand Down Expand Up @@ -91,9 +95,20 @@ void GPUModel::setupSim()
int rng_blocks = 25; //# of blocks the kernel will use
int rng_nPerRng
= 4; //# of iterations per thread (thread granularity, # of rands generated per thread)
int rng_mt_rng_count = Simulator::getInstance().getTotalVertices()
/ rng_nPerRng; //# of threads to generate for numVertices rand #s
int numVerticesNeedingNoise = layout_->getVertices().getNumberOfVerticesNeedingDeviceNoise();
int numberOfNoiseElements = roundUpNumberOfNoiseElements(numVerticesNeedingNoise);
int rng_mt_rng_count
= numberOfNoiseElements / rng_nPerRng; //# of threads to generate for numVertices rand #s
assert(rng_mt_rng_count <= MT_RNG_COUNT);
int rng_threads = rng_mt_rng_count / rng_blocks; //# threads per block needed
LOG4CPLUS_DEBUG(fileLogger_, "initMTGPU state: " << endl
<< "Noise seed: "
<< Simulator::getInstance().getNoiseRngSeed()
<< endl
<< "RNG_blocks: " << rng_blocks << endl
<< "RNG_threads: " << rng_threads << endl
<< "RNG_nPerRng: " << rng_nPerRng << endl
<< "Count: " << rng_mt_rng_count);
initMTGPU(Simulator::getInstance().getNoiseRngSeed(), rng_blocks, rng_threads, rng_nPerRng,
rng_mt_rng_count);

Expand Down Expand Up @@ -165,7 +180,6 @@ void GPUModel::advance()
cudaLapTime(t_gpu_rndGeneration);
cudaStartTimer();
#endif // PERFORMANCE_METRICS

// display running info to console
// Advance vertices ------------->
vertices.advanceVertices(edges, allVerticesDevice_, allEdgesDevice_, randNoise_d,
Expand Down Expand Up @@ -217,7 +231,6 @@ void GPUModel::advance()
cudaLapTime(t_gpu_advanceSynapses);
cudaStartTimer();
#endif // PERFORMANCE_METRICS

// integrate the inputs of the vertices
vertices.integrateVertexInputs(allVerticesDevice_, edgeIndexMapDevice_, allEdgesDevice_);

Expand Down Expand Up @@ -342,4 +355,16 @@ AllVerticesDeviceProperties *&GPUModel::getAllVerticesDevice()
AllEdgesDeviceProperties *&GPUModel::getAllEdgesDevice()
{
return allEdgesDevice_;
}

int GPUModel::roundUpNumberOfNoiseElements(int input)
{
// MersenneTwister requires the number of elements to be 100 or more and a multiple of 100
// To deal with this, we take the input and round it up to the nearest multiple of 100.
assert(input > 0);
// Already a multiple of 100 so return
if (input % 100 == 0)
return input;
// Return the next highest multiple of 100
return ((input + 99) / 100) * 100;
}
4 changes: 4 additions & 0 deletions Simulator/Core/GPUModel.h
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,10 @@ class GPUModel : public Model {
/// Deallocates device memories.
virtual void deleteDeviceStruct();

/// Takes the input and returns a rounded up number of elements to
/// use for generating device noise.
int roundUpNumberOfNoiseElements(int input);

/// Pointer to device random noise array.
float *randNoise_d;

Expand Down
34 changes: 34 additions & 0 deletions Simulator/Core/OperationManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@

#include "OperationManager.h"
#include "GenericFunctionNode.h"
#include "TwoUint64ArgFunctionNode.h"
#include <list>
#include <memory>
#include <string>
Expand Down Expand Up @@ -40,13 +41,44 @@ void OperationManager::registerOperation(const Operations &operation,
}
}

/// @brief Handles function signature: void (uint64_t,uint64_t).
/// @param operation The Operation type that will use the input function.
/// @param function The function invoked for the operation. Takes in two arguments of type uint64_t
void OperationManager::registerOperation(const Operations &operation,
const function<void(uint64_t, uint64_t)> &function)
{
try {
functionList_.push_back(
unique_ptr<IFunctionNode>(new TwoUint64ArgFunctionNode(operation, function)));
} catch (exception e) {
LOG4CPLUS_FATAL(logger_, string(e.what())
+ ". Push back failed in OperationManager::registerOperation");
throw runtime_error(string(e.what()) + " in OperationManager::registerOperation");
}
}

/// Takes in a operation type and invokes all registered functions that are classified as that operation type.
void OperationManager::executeOperation(const Operations &operation) const
{
LOG4CPLUS_INFO(logger_, "Executing operation " + operationToString(operation));
if (functionList_.size() > 0) {
for (auto i = functionList_.begin(); i != functionList_.end(); ++i) {
(*i)->invokeFunction(operation);
//TODO: Throw fatal if false
}
}
}

/// Take in a operation type and invokes all registered functions that are classified as that operation type using the input arguments.
void OperationManager::executeOperation(const Operations &operation, uint64_t arg1,
uint64_t arg2) const
{
LOG4CPLUS_INFO(logger_, "Executing operation " + operationToString(operation));
/// TODO: Should we check anything about arg1 and arg2 before passing to the invoke???
if (functionList_.size() > 0) {
for (auto i = functionList_.begin(); i != functionList_.end(); ++i) {
(*i)->invokeFunction(operation, arg1, arg2);
//TODO: Throw fatal if false
}
}
}
Expand All @@ -73,6 +105,8 @@ string OperationManager::operationToString(const Operations &operation) const
return "copyFromGPU";
case Operations::allocateGPU:
return "allocateGPU";
case Operations::loadEpochInputs:
return "loadEpochInputs";
default:
return "Operation isn't in OperationManager::operationToString()";
}
Expand Down
7 changes: 7 additions & 0 deletions Simulator/Core/OperationManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,16 @@ class OperationManager {
/// Handles function signature: void ()
void registerOperation(const Operations &operation, const function<void()> &function);

/// Handles function signature: void (uint64_t,uint64_t)
void registerOperation(const Operations &operation,
const function<void(uint64_t, uint64_t)> &function);

/// Takes in a operation type and invokes all registered functions that are classified as that operation type.
void executeOperation(const Operations &operation) const;

/// Take in a operation type and invokes all registered functions that are classified as that operation type using the input arguments.
void executeOperation(const Operations &operation, uint64_t arg1, uint64_t arg2) const;

/// Takes in the operation enum and returns the enum as a string. Used for debugging purposes.
string operationToString(const Operations &operation) const;

Expand Down
3 changes: 2 additions & 1 deletion Simulator/Core/Operations.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,5 +22,6 @@ enum class Operations {
copyToGPU,
copyFromGPU,
allocateGPU,
registerHistoryVariables
registerHistoryVariables,
loadEpochInputs
};
3 changes: 2 additions & 1 deletion Simulator/Core/Simulator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,8 @@ void Simulator::advanceEpoch(int currentEpoch) const
uint64_t count = 0;
// Compute step number at end of this simulation epoch
uint64_t endStep = g_simulationStep + static_cast<uint64_t>(epochDuration_ / deltaT_);
model_->getLayout().getVertices().loadEpochInputs(g_simulationStep, endStep);
OperationManager::getInstance().executeOperation(Operations::loadEpochInputs, g_simulationStep,
endStep);
// DEBUG_MID(model->logSimStep();) // Generic model debug call
uint64_t onePercent = (epochDuration_ / deltaT_) * numEpochs_ * 0.01;
while (g_simulationStep < endStep) {
Expand Down
Loading