Program Listing for File HostCurve.cu

Return to documentation for file (src/flamegpu/runtime/detail/curve/HostCurve.cu)

#include <cuda_runtime.h>

#include <cstdio>
#include <cassert>
#include <map>
#include <memory>

#include "flamegpu/runtime/detail/curve/HostCurve.cuh"


#include "flamegpu/simulation/detail/CUDAErrorChecking.cuh"
#include "flamegpu/util/nvtx.h"
#include "flamegpu/detail/cuda.cuh"

namespace flamegpu {
namespace detail {
namespace curve {

HostCurve::HostCurve()
    : d_curve_table(nullptr)
    , h_curve_table_ext_count{}
    , message_in_hash(Curve::variableRuntimeHash("_message_in"))
    , message_out_hash(Curve::variableRuntimeHash("_message_out"))
    , agent_out_hash(Curve::variableRuntimeHash("_agent_birth"))
    , environment_hash(Curve::variableRuntimeHash("_environment"))
    , macro_environment_hash(Curve::variableRuntimeHash("_macro_environment"))
    , directed_graph_vertex_hash(Curve::variableRuntimeHash("_environment_directed_graph_vertex"))
    , directed_graph_edge_hash(Curve::variableRuntimeHash("_environment_directed_graph_edge"))  {
    //, h_curve_table_ext_type{std::type_index(typeid(void))}
    // std::fill_n(h_curve_table_ext_type, MAX_VARIABLES, typeid(void));

    // set values of hash table to 0 on host and device
    memset(h_curve_table.hashes, 0, sizeof(VariableHash)* MAX_VARIABLES);
    memset(h_curve_table.type_size, 0, sizeof(unsigned int)* MAX_VARIABLES);
    memset(h_curve_table.elements, 0, sizeof(unsigned int)* MAX_VARIABLES);
    memset(h_curve_table.count, 0, sizeof(unsigned int)* MAX_VARIABLES);
    initialiseDevice();
}
HostCurve::~HostCurve() {
    if (d_curve_table) {
        gpuErrchk(flamegpu::detail::cuda::cudaFree(d_curve_table));
        d_curve_table = nullptr;
    }
}
void HostCurve::initialiseDevice() {
    // Don't lock mutex here, do it in the calling method
    if (!d_curve_table) {
        // get a host pointer to d_hashes and d_variables
        gpuErrchk(cudaMalloc(&d_curve_table, sizeof(CurveTable)));
    }
}

void HostCurve::registerAgentVariable(const std::string& variable_name, const std::type_index type, const size_t type_size, const unsigned int elements) {
    registerVariable(Curve::variableRuntimeHash(variable_name), type, type_size, elements);
}
void HostCurve::registerMessageInputVariable(const std::string& variable_name, const std::type_index type, const size_t type_size, const unsigned int elements) {
    registerVariable(message_in_hash + Curve::variableRuntimeHash(variable_name), type, type_size, elements);
}
void HostCurve::registerMessageOutputVariable(const std::string& variable_name, const std::type_index type, const size_t type_size, const unsigned int elements) {
    registerVariable(message_out_hash + Curve::variableRuntimeHash(variable_name), type, type_size, elements);
}
void HostCurve::registerAgentOutputVariable(const std::string& variable_name, const std::type_index type, const size_t type_size, const unsigned int elements) {
    registerVariable(agent_out_hash + Curve::variableRuntimeHash(variable_name), type, type_size, elements);
}
void HostCurve::registerSetEnvironmentProperty(const std::string& variable_name, const std::type_index type, const size_t type_size, const unsigned int elements, const ptrdiff_t offset) {
    registerVariable(environment_hash + Curve::variableRuntimeHash(variable_name), type, type_size, elements);
    setVariable(environment_hash + Curve::variableRuntimeHash(variable_name), reinterpret_cast<void *>(offset), 1);
}
void HostCurve::registerSetMacroEnvironmentProperty(const std::string& variable_name, std::type_index type, size_t type_size, unsigned int elements, void* d_ptr) {
    registerVariable(macro_environment_hash + Curve::variableRuntimeHash(variable_name), type, type_size, elements);
    setVariable(macro_environment_hash + Curve::variableRuntimeHash(variable_name), d_ptr, 1);
}
void HostCurve::registerEnvironmentDirectedGraphVertexProperty(const std::string &graph_name, const std::string& variable_name, std::type_index type, size_t type_size, unsigned int elements) {
    registerVariable((Curve::variableRuntimeHash(graph_name) ^ directed_graph_vertex_hash) + Curve::variableRuntimeHash(variable_name), type, type_size, elements);
}
void HostCurve::registerEnvironmentDirectedGraphEdgeProperty(const std::string& graph_name, const std::string& variable_name, std::type_index type, size_t type_size, unsigned int elements) {
    registerVariable((Curve::variableRuntimeHash(graph_name) ^ directed_graph_edge_hash) + Curve::variableRuntimeHash(variable_name), type, type_size, elements);
}
void HostCurve::registerVariable(const VariableHash variable_hash, const std::type_index type, const size_t type_size, const unsigned int elements) {
    if (variable_hash == EMPTY_FLAG) {
        THROW exception::CurveException("Unable to register variable, it's hash matches a reserved symbol!");
    }
    unsigned int i = (variable_hash) % MAX_VARIABLES;
    unsigned int n = 0;
    while (h_curve_table.hashes[i] != EMPTY_FLAG) {
        n += 1;
        if (n >= MAX_VARIABLES) {
            THROW exception::CurveException("Unable to register variable, hash table capacity exceeded!");
        }
        i += 1;
        if (i >= MAX_VARIABLES) {
            i = 0;
        }
    }

    h_curve_table.hashes[i] = variable_hash;

    // Initialise the pointer to 0
    h_curve_table.variables[i] = nullptr;

    // set the size of the data type
    h_curve_table.type_size[i] = static_cast<unsigned int>(type_size);

    // set the length of variable
    h_curve_table.elements[i] = elements;

    // set the type_index of the variable
    // h_curve_table_ext_type[i] = type; // @todo
}
void HostCurve::setAgentVariable(const std::string& variable_name, void* d_ptr, const unsigned int count) {
    setVariable(Curve::variableRuntimeHash(variable_name), d_ptr, count);
}
void HostCurve::setMessageInputVariable(const std::string& variable_name, void* d_ptr, const unsigned int count) {
    setVariable(message_in_hash + Curve::variableRuntimeHash(variable_name), d_ptr, count);
}
void HostCurve::setMessageOutputVariable(const std::string& variable_name, void* d_ptr, const unsigned int count) {
    setVariable(message_out_hash + Curve::variableRuntimeHash(variable_name), d_ptr, count);
}
void HostCurve::setAgentOutputVariable(const std::string& variable_name, void* d_ptr, const unsigned int count) {
    setVariable(agent_out_hash + Curve::variableRuntimeHash(variable_name), d_ptr, count);
}
void HostCurve::setEnvironmentDirectedGraphVertexProperty(const std::string& graph_name, const std::string& variable_name, void* d_ptr, const unsigned int count) {
    setVariable((Curve::variableRuntimeHash(graph_name) ^ directed_graph_vertex_hash) + Curve::variableRuntimeHash(variable_name), d_ptr, count);
}
void HostCurve::setEnvironmentDirectedGraphEdgeProperty(const std::string& graph_name, const std::string& variable_name, void* d_ptr, const unsigned int count) {
    setVariable((Curve::variableRuntimeHash(graph_name) ^ directed_graph_edge_hash) + Curve::variableRuntimeHash(variable_name), d_ptr, count);
}
void HostCurve::setVariable(const VariableHash variable_hash, void * d_ptr, const unsigned int count) {
    if (variable_hash == EMPTY_FLAG) {
        THROW exception::CurveException("Unable to set variable, it's hash matches a reserved symbol!");
    }
    unsigned int i = (variable_hash) % MAX_VARIABLES;
    unsigned int n = 0;
    while (h_curve_table.hashes[i] != variable_hash) {
        n += 1;
        if (n >= MAX_VARIABLES) {
            THROW exception::CurveException("Unable to set variable, not found in hash table!");
        }
        i += 1;
        if (i >= MAX_VARIABLES) {
            i = 0;
        }
    }
    // Set the pointer
    h_curve_table.variables[i] = static_cast<char*>(d_ptr);
    // Set the count
    h_curve_table.count[i] = count;
}
int HostCurve::size() const {
    // @todo Could track size as items are inserted to make this 'free'
    int rtn = 0;
    for (unsigned int hash : h_curve_table.hashes) {
        if (hash != EMPTY_FLAG)
            rtn++;
    }
    return rtn;
}
void HostCurve::updateDevice_async(const cudaStream_t stream) {
    flamegpu::util::nvtx::Range range{"HostCurve::updateDevice_async()"};
    // Initialise the device (if required)
    assert(d_curve_table);  // No reason for this to ever fail.
    // Copy
    gpuErrchk(cudaMemcpyAsync(d_curve_table, &h_curve_table, sizeof(CurveTable), cudaMemcpyHostToDevice, stream));
}
const CurveTable *HostCurve::getDevicePtr() const {
    return d_curve_table;
}

}  // namespace curve
}  // namespace detail
}  // namespace flamegpu