Program Listing for File CUDAEnvironmentDirectedGraphBuffers.cuh
↰ Return to documentation for file (include/flamegpu/simulation/detail/CUDAEnvironmentDirectedGraphBuffers.cuh
)
#ifndef INCLUDE_FLAMEGPU_SIMULATION_DETAIL_CUDAENVIRONMENTDIRECTEDGRAPHBUFFERS_CUH_
#define INCLUDE_FLAMEGPU_SIMULATION_DETAIL_CUDAENVIRONMENTDIRECTEDGRAPHBUFFERS_CUH_
#include <string>
#include <map>
#include <list>
#include <memory>
#include <vector>
#include <unordered_map>
#include <utility>
#include <limits>
#include "flamegpu/model/EnvironmentDirectedGraphData.cuh"
#include "flamegpu/defines.h"
#include "flamegpu/simulation/detail/CUDAErrorChecking.cuh"
#include "flamegpu/detail/type_decode.h"
#include "flamegpu/util/StringPair.h"
namespace flamegpu {
#ifdef FLAMEGPU_VISUALISATION
namespace visualiser {
struct ModelVisData;
}
#endif
namespace detail {
class CUDAScatter;
namespace curve {
class HostCurve;
class CurveRTCHost;
}
class CUDAEnvironmentDirectedGraphBuffers {
struct Buffer {
enum Ready { None = 0, Host = 1, Device = 2, Both = 3};
size_t element_size;
void *d_ptr = nullptr;
void* d_ptr_swap = nullptr;
void *h_ptr = nullptr;
mutable Ready ready = None;
void swap() { std::swap(d_ptr, d_ptr_swap); }
void updateHostBuffer(size_type edge_count, cudaStream_t stream) const;
};
const EnvironmentDirectedGraphData &graph_description;
std::map<std::string, Buffer> vertex_buffers;
std::map<std::string, Buffer> edge_buffers;
std::list<std::weak_ptr<detail::curve::HostCurve>> curve_instances;
std::list<std::weak_ptr<detail::curve::CurveRTCHost>> rtc_curve_instances;
#ifdef FLAMEGPU_VISUALISATION
mutable std::weak_ptr<visualiser::ModelVisData> visualisation;
#endif
size_type vertex_count;
size_type edge_count;
bool requires_rebuild;
uint64_t *d_keys = nullptr, *d_keys_swap = nullptr;
uint32_t *d_vals = nullptr, *d_vals_swap = nullptr;
// CSR/VBM (edgesLeaving())
unsigned int *d_pbm = nullptr, *d_pbm_swap = nullptr;
// CSC/invertedVBM (edgesJoining()), shares d_pbm_swap
unsigned int *d_ipbm = nullptr;
// Copy of the vals list from constructing ipbm, required to lookup edges
unsigned int *d_ipbm_edges = nullptr;
// Vertex ID -> index map, ?? has been reserved, otherwise any ID is valid
// However, the ID->index map does not utilise any compression, so non-contiguous ID ranges may lead to out of memory errors.
unsigned int *d_vertex_index_map = nullptr;
void allocateVertexBuffers(size_type count, cudaStream_t stream);
void allocateEdgeBuffers(size_type count);
void deallocateVertexBuffers();
void deallocateEdgeBuffers();
/*
* Reset the internal vertex ID range tracking variables as though no vertices have been assigned IDs
*/
void resetVertexIDBounds();
unsigned int vertex_id_min = std::numeric_limits<unsigned int>::max();
unsigned int vertex_id_max = std::numeric_limits<unsigned int>::min();
std::map<id_t, unsigned int> h_vertex_index_map;
util::PairMap<id_t, id_t, unsigned int> h_edge_index_map;
public:
explicit CUDAEnvironmentDirectedGraphBuffers(const EnvironmentDirectedGraphData &description);
~CUDAEnvironmentDirectedGraphBuffers();
void registerCurveInstance(const std::shared_ptr<detail::curve::HostCurve>& curve);
void registerCurveInstance(const std::shared_ptr<detail::curve::CurveRTCHost>& curve);
const EnvironmentDirectedGraphData& getDescription() const { return graph_description; }
void setVertexCount(size_type count, cudaStream_t stream);
void setEdgeCount(size_type count);
size_type getVertexCount() const { return vertex_count; }
size_type getEdgeCount() const { return edge_count; }
unsigned int createIfNotExistVertex(id_t vertex_id, cudaStream_t stream);
unsigned int createIfNotExistEdge(id_t source_vertex_id, id_t dest_vertex_id, cudaStream_t stream);
id_t* getVertexIDBuffer(cudaStream_t stream);
template<typename T>
const T* getVertexPropertyBuffer(const std::string& property_name, size_type &N, cudaStream_t stream) const;
template<typename T>
T* getVertexPropertyBuffer(const std::string& property_name, size_type &N, cudaStream_t stream);
template<typename T>
const T *getEdgePropertyBuffer(const std::string &property_name, size_type &N, cudaStream_t stream) const;
template<typename T>
T* getEdgePropertyBuffer(const std::string& property_name, size_type &N, cudaStream_t stream);
#ifdef SWIG
template<typename T>
std::vector<T> getVertexPropertyArray(const std::string& property_name, const unsigned int vertex_index, cudaStream_t stream) const;
template<typename T>
std::vector<T> getEdgePropertyArray(const std::string& property_name, const unsigned int edge_index, cudaStream_t stream) const;
#endif
void markForRebuild() { requires_rebuild = true; }
void syncDevice_async(detail::CUDAScatter& scatter, unsigned int streamID, cudaStream_t stream);
void setVertexID(unsigned int vertex_index, id_t vertex_id, cudaStream_t stream);
unsigned int getVertexIndex(id_t vertex_id) const;
void setEdgeSourceDestination(unsigned int edge_index, id_t src_vertex_id, id_t dest_vertex_id);
unsigned int getEdgeIndex(id_t src_vertex_id, id_t dest_vertex_id) const;
#ifdef FLAMEGPU_VISUALISATION
void setVisualisation(std::shared_ptr<visualiser::ModelVisData> &_visualisation) const {
this->visualisation = _visualisation;
}
#endif
};
template<typename T>
const T* CUDAEnvironmentDirectedGraphBuffers::getVertexPropertyBuffer(const std::string& property_name, size_type &N, cudaStream_t stream) const {
if (!vertex_count) {
THROW exception::OutOfBoundsException("Vertex buffers not yet allocated, in CUDAEnvironmentDirectedGraphBuffers::getVertexPropertyBuffer()");
}
const auto &vv = graph_description.vertexProperties.find(property_name);
if (vv == graph_description.vertexProperties.end()) {
THROW exception::InvalidGraphProperty("Vertex property with name '%s' not found, in CUDAEnvironmentDirectedGraphBuffers::getVertexPropertyBuffer()", property_name.c_str());
} else if (vv->second.type != std::type_index(typeid(typename detail::type_decode<T>::type_t))) {
THROW exception::InvalidGraphProperty("Vertex property with name '%s' type mismatch '%s' != '%s', in CUDAEnvironmentDirectedGraphBuffers::getVertexPropertyBuffer()",
property_name.c_str(), vv->second.type.name(), std::type_index(typeid(typename detail::type_decode<T>::type_t)).name());
} else if (N == 0) {
N = vv->second.elements;
} else if (vv->second.elements != N) {
THROW exception::InvalidGraphProperty("Vertex property with name '%s' length mismatch '%u' != '%u', in CUDAEnvironmentDirectedGraphBuffers::getVertexPropertyBuffer()",
property_name.c_str(), N, vv->second.elements);
}
auto& vb = vertex_buffers.at(property_name);
vb.updateHostBuffer(vertex_count, stream);
return static_cast<T*>(vb.h_ptr);
}
template<typename T>
T* CUDAEnvironmentDirectedGraphBuffers::getVertexPropertyBuffer(const std::string& property_name, size_type &N, cudaStream_t stream) {
if (!vertex_count) {
THROW exception::OutOfBoundsException("Vertex buffers not yet allocated, in CUDAEnvironmentDirectedGraphBuffers::getVertexPropertyBuffer()");
}
const auto& vv = graph_description.vertexProperties.find(property_name);
if (vv == graph_description.vertexProperties.end()) {
THROW exception::InvalidGraphProperty("Vertex property with name '%s' not found, in CUDAEnvironmentDirectedGraphBuffers::getVertexPropertyBuffer()", property_name.c_str());
} else if (vv->second.type != std::type_index(typeid(typename detail::type_decode<T>::type_t))) {
THROW exception::InvalidGraphProperty("Vertex property with name '%s' type mismatch '%s' != '%s', in CUDAEnvironmentDirectedGraphBuffers::getVertexPropertyBuffer()",
property_name.c_str(), vv->second.type.name(), std::type_index(typeid(typename detail::type_decode<T>::type_t)).name());
} else if (N == 0) {
N = vv->second.elements;
} else if (vv->second.elements != N) {
THROW exception::InvalidGraphProperty("Vertex property with name '%s' length mismatch '%u' != '%u', in CUDAEnvironmentDirectedGraphBuffers::getVertexPropertyBuffer()",
property_name.c_str(), N, vv->second.elements);
}
auto &vb = vertex_buffers.at(property_name);
vb.updateHostBuffer(vertex_count, stream);
vb.ready = Buffer::Host;
return static_cast<T*>(vb.h_ptr);
}
template<typename T>
const T* CUDAEnvironmentDirectedGraphBuffers::getEdgePropertyBuffer(const std::string& property_name, size_type &N, cudaStream_t stream) const {
if (!edge_count) {
THROW exception::OutOfBoundsException("Edge buffers not yet allocated, in CUDAEnvironmentDirectedGraphBuffers::getEdgePropertyBuffer()");
}
const auto& ev = graph_description.edgeProperties.find(property_name);
if (ev == graph_description.edgeProperties.end()) {
THROW exception::InvalidGraphProperty("Edge property with name '%s' not found, in CUDAEnvironmentDirectedGraphBuffers::getEdgePropertyBuffer()", property_name.c_str());
} else if (ev->second.type != std::type_index(typeid(typename detail::type_decode<T>::type_t))) {
THROW exception::InvalidGraphProperty("Edge property with name '%s' type mismatch '%s' != '%s', in CUDAEnvironmentDirectedGraphBuffers::getEdgePropertyBuffer()",
property_name.c_str(), ev->second.type.name(), std::type_index(typeid(typename detail::type_decode<T>::type_t)).name());
} else if (N == 0) {
N = ev->second.elements;
} else if (ev->second.elements != N) {
THROW exception::InvalidGraphProperty("Edge property with name '%s' length mismatch '%u' != '%u', in CUDAEnvironmentDirectedGraphBuffers::getEdgePropertyBuffer()",
property_name.c_str(), N, ev->second.elements);
}
auto &eb = edge_buffers.at(property_name);
eb.updateHostBuffer(edge_count, stream);
return static_cast<T*>(eb.h_ptr);
}
template<typename T>
T* CUDAEnvironmentDirectedGraphBuffers::getEdgePropertyBuffer(const std::string& property_name, size_type &N, cudaStream_t stream) {
if (!edge_count) {
THROW exception::OutOfBoundsException("Edge buffers not yet allocated, in CUDAEnvironmentDirectedGraphBuffers::getEdgePropertyBuffer()");
}
const auto& ev = graph_description.edgeProperties.find(property_name);
if (ev == graph_description.edgeProperties.end()) {
THROW exception::InvalidGraphProperty("Edge property with name '%s' not found, in CUDAEnvironmentDirectedGraphBuffers::getEdgePropertyBuffer()", property_name.c_str());
} else if (ev->second.type != std::type_index(typeid(typename detail::type_decode<T>::type_t))) {
THROW exception::InvalidGraphProperty("Edge property with name '%s' type mismatch '%s' != '%s', in CUDAEnvironmentDirectedGraphBuffers::getEdgePropertyBuffer()",
property_name.c_str(), ev->second.type.name(), std::type_index(typeid(typename detail::type_decode<T>::type_t)).name());
} else if (N == 0) {
N = ev->second.elements;
} else if (ev->second.elements != N) {
THROW exception::InvalidGraphProperty("Edge property with name '%s' length mismatch '%u' != '%u', in CUDAEnvironmentDirectedGraphBuffers::getEdgePropertyBuffer()",
property_name.c_str(), N, ev->second.elements);
}
auto &eb = edge_buffers.at(property_name);
eb.updateHostBuffer(edge_count, stream);
eb.ready = Buffer::Host;
return static_cast<T*>(eb.h_ptr);
}
#ifdef SWIG
template<typename T>
std::vector <T> CUDAEnvironmentDirectedGraphBuffers::getVertexPropertyArray(const std::string& property_name, const unsigned int vertex_index, cudaStream_t stream) const {
if (!vertex_count) {
THROW exception::OutOfBoundsException("Vertex buffers not yet allocated, in CUDAEnvironmentDirectedGraphBuffers::getVertexPropertyArray()");
}
const auto& vv = graph_description.vertexProperties.find(property_name);
if (vv == graph_description.vertexProperties.end()) {
THROW exception::InvalidGraphProperty("Vertex property with name '%s' not found, in CUDAEnvironmentDirectedGraphBuffers::getVertexPropertyArray()", property_name.c_str());
} else if (vv->second.type != std::type_index(typeid(typename detail::type_decode<T>::type_t))) {
THROW exception::InvalidGraphProperty("Vertex property with name '%s' type mismatch '%s' != '%s', in CUDAEnvironmentDirectedGraphBuffers::getVertexPropertyArray()",
property_name.c_str(), vv->second.type.name(), std::type_index(typeid(typename detail::type_decode<T>::type_t)).name());
} else if (vertex_index >= vertex_count) {
THROW exception::OutOfBoundsException("Vertex index %u is out of range %u, in CUDAEnvironmentDirectedGraphBuffers::getVertexPropertyArray()\n",
vertex_index, vertex_count);
}
std::vector<T> rtn(vv->second.elements);
auto& vb = vertex_buffers.at(property_name);
vb.updateHostBuffer(vertex_count, stream);
memcpy(rtn.data(), static_cast<T*>(vb.h_ptr) + vertex_index * vv->second.elements, vv->second.type_size * vv->second.elements);
return rtn;
}
template<typename T>
std::vector<T> CUDAEnvironmentDirectedGraphBuffers::getEdgePropertyArray(const std::string& property_name, const unsigned int edge_index, cudaStream_t stream) const {
if (!edge_count) {
THROW exception::OutOfBoundsException("Edge buffers not yet allocated, in CUDAEnvironmentDirectedGraphBuffers::getEdgePropertyArray()");
}
const auto& ev = graph_description.edgeProperties.find(property_name);
if (ev == graph_description.edgeProperties.end()) {
THROW exception::InvalidGraphProperty("Edge property with name '%s' not found, in CUDAEnvironmentDirectedGraphBuffers::getEdgePropertyArray()", property_name.c_str());
} else if (ev->second.type != std::type_index(typeid(typename detail::type_decode<T>::type_t))) {
THROW exception::InvalidGraphProperty("Edge property with name '%s' type mismatch '%s' != '%s', in CUDAEnvironmentDirectedGraphBuffers::getEdgePropertyArray()",
property_name.c_str(), ev->second.type.name(), std::type_index(typeid(typename detail::type_decode<T>::type_t)).name());
} else if (edge_index >= edge_count) {
THROW exception::OutOfBoundsException("Edge index %u is out of range %u, in CUDAEnvironmentDirectedGraphBuffers::getEdgePropertyArray()\n",
edge_index, edge_count);
}
std::vector<T> rtn(ev->second.elements);
auto& eb = edge_buffers.at(property_name);
eb.updateHostBuffer(edge_count, stream);
memcpy(rtn.data(), static_cast<T*>(eb.h_ptr) + edge_index * ev->second.elements, ev->second.type_size * ev->second.elements);
return rtn;
}
#endif
} // namespace detail
} // namespace flamegpu
#endif // INCLUDE_FLAMEGPU_SIMULATION_DETAIL_CUDAENVIRONMENTDIRECTEDGRAPHBUFFERS_CUH_