Program Listing for File CUDAMacroEnvironment.h
↰ Return to documentation for file (include/flamegpu/simulation/detail/CUDAMacroEnvironment.h
)
#ifndef INCLUDE_FLAMEGPU_SIMULATION_DETAIL_CUDAMACROENVIRONMENT_H_
#define INCLUDE_FLAMEGPU_SIMULATION_DETAIL_CUDAMACROENVIRONMENT_H_
#include <cuda_runtime.h>
#include <map>
#include <utility>
#include <string>
#include <typeindex>
#include <array>
#include <vector>
#include <memory>
#include "flamegpu/simulation/detail/CUDAErrorChecking.cuh"
#include "flamegpu/runtime/detail/curve/HostCurve.cuh"
#include "flamegpu/runtime/environment/HostMacroProperty.cuh"
#include "flamegpu/detail/cuda.cuh"
// forward declare classes from other modules
namespace flamegpu {
struct SubEnvironmentData;
struct AgentFunctionData;
struct EnvironmentData;
class CUDASimulation;
namespace detail {
namespace curve {
class CurveRTCHost;
} // namespace curve
class CUDAMacroEnvironment {
public:
struct MacroEnvProp {
MacroEnvProp(const std::type_index& _type, const size_t _type_size, const std::array<unsigned int, 4> &_elements)
: type(_type)
, type_size(_type_size)
, elements(_elements)
, d_ptr(nullptr)
, is_sub(false) { }
~MacroEnvProp() {
if (d_ptr && !is_sub) {
gpuErrchk(flamegpu::detail::cuda::cudaFree(d_ptr));
}
}
MacroEnvProp(const MacroEnvProp& other) = delete;
MacroEnvProp(MacroEnvProp&& other)
: type(other.type)
, type_size(other.type_size)
, elements(other.elements)
, d_ptr(other.d_ptr)
, is_sub(other.is_sub) {
other.d_ptr = nullptr;
}
std::type_index type;
size_t type_size;
std::array<unsigned int, 4> elements;
void *d_ptr;
// Denotes whether d_ptr is owned by this struct or not
bool is_sub;
// ptrdiff_t rtc_offset; // This is set by buildRTCOffsets();
};
CUDAMacroEnvironment(const EnvironmentData& description, const CUDASimulation& _cudaSimulation);
CUDAMacroEnvironment(CUDAMacroEnvironment&) = delete;
CUDAMacroEnvironment(CUDAMacroEnvironment&&) = delete;
void init(cudaStream_t stream);
void init(const SubEnvironmentData& mapping, std::shared_ptr<const detail::CUDAMacroEnvironment> master_macro_env, cudaStream_t stream);
void free();
void mapRTCVariables(detail::curve::CurveRTCHost& curve_header) const;
void unmapRTCVariables(detail::curve::CurveRTCHost& curve_header) const;
void registerCurveVariables(detail::curve::HostCurve &curve) const;
#if !defined(FLAMEGPU_SEATBELTS) || FLAMEGPU_SEATBELTS
void resetFlagsAsync(const std::vector<cudaStream_t>& streams);
bool getDeviceReadFlag(const std::string& property_name);
bool getDeviceWriteFlag(const std::string& property_name);
unsigned int getDeviceRWFlags(const std::string& property_name);
#endif
template<typename T, unsigned int I, unsigned int J, unsigned int K, unsigned int W>
HostMacroProperty<T, I, J, K, W> getProperty(const std::string& name);
#ifdef SWIG
template<typename T>
HostMacroProperty_swig<T> getProperty_swig(const std::string& name);
#endif
const std::map<std::string, MacroEnvProp>& getPropertiesMap() const;
std::shared_ptr<HostMacroProperty_MetaData> getHostPropertyMetadata(const std::string property_name);
private:
const CUDASimulation& cudaSimulation;
std::map<std::string, MacroEnvProp> properties;
std::map<std::string, std::weak_ptr<HostMacroProperty_MetaData>> host_cache;
cudaStream_t stream = nullptr;
};
template<typename T, unsigned int I, unsigned int J, unsigned int K, unsigned int W>
HostMacroProperty<T, I, J, K, W> CUDAMacroEnvironment::getProperty(const std::string& name) {
// Validation
auto prop = properties.find(name);
if (prop == properties.end()) {
THROW flamegpu::exception::InvalidEnvProperty("Environment macro property with name '%s' not found, "
"in HostEnvironment::getMacroProperty()\n",
name.c_str());
} else if (prop->second.type != std::type_index(typeid(T))) {
THROW flamegpu::exception::InvalidEnvProperty("Environment macro property '%s' type mismatch '%s' != '%s', "
"in HostEnvironment::getMacroProperty()\n",
name.c_str(), std::type_index(typeid(T)).name(), prop->second.type.name());
} else if (prop->second.elements != std::array<unsigned int, 4>{I, J, K, W}) {
THROW flamegpu::exception::InvalidEnvProperty("Environment macro property '%s' dimensions mismatch (%u, %u, %u, %u) != (%u, %u, %u, %u), "
"in HostEnvironment::getMacroProperty()\n",
name.c_str(), I, J, K, W, prop->second.elements[0], prop->second.elements[1], prop->second.elements[2], prop->second.elements[3]);
}
#if !defined(FLAMEGPU_SEATBELTS) || FLAMEGPU_SEATBELTS
const unsigned int flags = getDeviceWriteFlag(name);
if (flags & (1 << 1)) {
THROW flamegpu::exception::InvalidOperation("Environment macro property '%s' was written to by an agent function in the same layer, "
"accessing it with a host function in the same layer could cause a race condition, in CUDAMacroEnvironment::getProperty().",
name.c_str());
}
const bool read_flag = flags & (1 << 0);
#else
const bool read_flag = false;
#endif
// See if there is a live metadata in cache
auto cache = host_cache.find(name);
if (cache != host_cache.end()) {
if (cache->second.lock()) {
return HostMacroProperty<T, I, J, K, W>(cache->second.lock());
}
host_cache.erase(cache);
}
auto ret = std::make_shared<HostMacroProperty_MetaData>(prop->second.d_ptr, prop->second.elements, sizeof(T), read_flag, name, stream);
host_cache.emplace(name, ret);
return HostMacroProperty<T, I, J, K, W>(ret);
}
#ifdef SWIG
template<typename T>
HostMacroProperty_swig<T> CUDAMacroEnvironment::getProperty_swig(const std::string& name) {
// Validation
auto prop = properties.find(name);
if (prop == properties.end()) {
THROW flamegpu::exception::InvalidEnvProperty("Environment macro property with name '%s' not found, "
"in HostEnvironment::getMacroProperty()\n",
name.c_str());
} else if (prop->second.type != std::type_index(typeid(T))) {
THROW flamegpu::exception::InvalidEnvProperty("Environment macro property '%s' type mismatch '%s' != '%s', "
"in HostEnvironment::getMacroProperty()\n",
name.c_str(), std::type_index(typeid(T)).name(), prop->second.type.name());
}
#if !defined(FLAMEGPU_SEATBELTS) || FLAMEGPU_SEATBELTS
const unsigned int flags = getDeviceWriteFlag(name);
if (flags & (1 << 1)) {
THROW flamegpu::exception::InvalidOperation("Environment macro property '%s' was written to by an agent function in the same layer, "
"accessing it with a host function in the same layer could cause a race condition, in CUDAMacroEnvironment::getProperty().",
name.c_str());
}
const bool read_flag = flags & (1 << 0);
#else
const bool read_flag = false;
#endif
// See if there is a live metadata in cache
auto cache = host_cache.find(name);
if (cache != host_cache.end()) {
if (cache->second.lock()) {
return HostMacroProperty_swig<T>(cache->second.lock());
}
host_cache.erase(cache);
}
auto ret = std::make_shared<HostMacroProperty_MetaData>(prop->second.d_ptr, prop->second.elements, sizeof(T), read_flag, name, stream);
host_cache.emplace(name, ret);
return HostMacroProperty_swig<T>(ret);
}
#endif
} // namespace detail
} // namespace flamegpu
#endif // INCLUDE_FLAMEGPU_SIMULATION_DETAIL_CUDAMACROENVIRONMENT_H_