Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
12 changes: 10 additions & 2 deletions graph_framework/jit.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,8 @@ namespace jit {

/// GPU Context.
gpu_context_type gpu_context;
/// Used random.
bool used_random;

public:
/// Size of random state needed.
Expand All @@ -96,7 +98,7 @@ namespace jit {
///
/// @param[in] index Concurrent index. Not used.
//------------------------------------------------------------------------------
context(const size_t index) : gpu_context(index) {
context(const size_t index) : gpu_context(index), used_random(false) {
source_buffer << std::setprecision(max_digits10<T> ());
gpu_context.create_header(source_buffer);
}
Expand All @@ -121,6 +123,12 @@ namespace jit {
const size_t size) {
kernel_names.push_back(name);

if (state.get() && !used_random) {
used_random = true;
graph::random_state_node<T>::compile_random_state(source_buffer);
graph::random_node<T>::compile_random(source_buffer);
}

std::vector<bool> is_constant(inputs.size(), true);
visiter_map visited;
register_usage usage;
Expand Down Expand Up @@ -225,7 +233,7 @@ namespace jit {
/// @brief Compile the kernel.
///
/// @param[in] add_reduction Optional argument to generate the reduction
/// kernel.
/// kernel.
//------------------------------------------------------------------------------
void compile(const bool add_reduction=false) {
#ifdef SAVE_KERNEL_SOURCE
Expand Down
90 changes: 53 additions & 37 deletions graph_framework/random.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,21 @@ namespace graph {
class random_state_node final : public leaf_node<T, SAFE_MATH> {
public:
//------------------------------------------------------------------------------
/// @brief Write the preamble for the random state struct.
///
/// @param[in,out] stream String buffer stream.
//------------------------------------------------------------------------------
static void compile_random_state(std::ostringstream &stream) {
stream << "struct mt_state {" << std::endl
<< " array<uint32_t, 624> array;" << std::endl
<< " uint16_t index;" << std::endl
#ifdef USE_CUDA
<< " uint16_t padding[3];" << std::endl
#endif
<< "};" << std::endl;
}

//------------------------------------------------------------------------------
/// @brief Random state structure.
//------------------------------------------------------------------------------
struct mt_state {
Expand Down Expand Up @@ -90,14 +105,6 @@ namespace graph {
jit::texture2d_list &textures2d,
int &avail_const_mem) {
if (visited.find(this) == visited.end()) {
stream << "struct mt_state {" << std::endl
<< " array<uint32_t, 624> array;" << std::endl
<< " uint16_t index;" << std::endl
#ifdef USE_CUDA
<< " uint16_t padding[3];" << std::endl
#endif
<< "};" << std::endl;

visited.insert(this);
#ifdef SHOW_USE_COUNT
usage[this] = 1;
Expand Down Expand Up @@ -300,6 +307,39 @@ namespace graph {

public:
//------------------------------------------------------------------------------
/// @brief Write the preamble for the random function.
///
/// @param[in,out] stream String buffer stream.
//------------------------------------------------------------------------------
static void compile_random(std::ostringstream &stream) {
jit::add_type<T> (stream);
stream << " random(";
if constexpr (jit::use_metal<T> ()) {
stream << "device ";
}
stream <<"mt_state &state) {" << std::endl
<< " uint16_t k = state.index;" << std::endl
<< " uint16_t j = (k + 1) % 624;" << std::endl
<< " uint32_t x = (state.array[k] & 0x80000000U) |" << std::endl
<< " (state.array[j] & 0x7fffffffU);" << std::endl
<< " uint32_t xA = x >> 1;" << std::endl
<< " if (x & 0x00000001U) {" << std::endl
<< " xA ^= 0x9908b0dfU;" << std::endl
<< " }" << std::endl
<< " j = (k + 397) % 624;" << std::endl
<< " x = state.array[j]^xA;" << std::endl
<< " state.array[k] = x;" << std::endl
<< " state.index = (k + 1) % 624;" << std::endl
<< " uint32_t y = x^(x >> 11);" << std::endl
<< " y = y^((y << 7) & 0x9d2c5680U);" << std::endl
<< " y = y^((y << 15) & 0xefc60000U);" << std::endl
<< " return static_cast<";
jit::add_type<T> (stream);
stream << "> (y^(y >> 18));" << std::endl
<< "}" << std::endl;
}

//------------------------------------------------------------------------------
/// @brief Construct a constant node from a vector.
///
/// @param[in] x Argument.
Expand Down Expand Up @@ -353,32 +393,6 @@ namespace graph {
textures1d, textures2d,
avail_const_mem);

jit::add_type<T> (stream);
stream << " random(";
if constexpr (jit::use_metal<T> ()) {
stream << "device ";
}
stream <<"mt_state &state) {" << std::endl
<< " uint16_t k = state.index;" << std::endl
<< " uint16_t j = (k + 1) % 624;" << std::endl
<< " uint32_t x = (state.array[k] & 0x80000000U) |" << std::endl
<< " (state.array[j] & 0x7fffffffU);" << std::endl
<< " uint32_t xA = x >> 1;" << std::endl
<< " if (x & 0x00000001U) {" << std::endl
<< " xA ^= 0x9908b0dfU;" << std::endl
<< " }" << std::endl
<< " j = (k + 397) % 624;" << std::endl
<< " x = state.array[j]^xA;" << std::endl
<< " state.array[k] = x;" << std::endl
<< " state.index = (k + 1) % 624;" << std::endl
<< " uint32_t y = x^(x >> 11);" << std::endl
<< " y = y^((y << 7) & 0x9d2c5680U);" << std::endl
<< " y = y^((y << 15) & 0xefc60000U);" << std::endl
<< " return static_cast<";
jit::add_type<T> (stream);
stream << "> (y^(y >> 18));" << std::endl
<< "}" << std::endl;

visited.insert(this);
#ifdef SHOW_USE_COUNT
usage[this] = 1;
Expand Down Expand Up @@ -419,8 +433,8 @@ namespace graph {
///
/// Arithmetic and math operations on random number umber distributions have
/// the effect of changing the distribution. For instance rand1 + rand2 will
/// to a pyramid shaped distribution function. Assume random numbers never
/// match as a consequence.
/// change to a pyramid shaped distribution function. Assume random numbers
/// never match as a consequence.
///
/// @param[in] x Other graph to check if it is a match.
/// @returns True if the nodes are a match.
Expand All @@ -433,7 +447,9 @@ namespace graph {
/// @brief Convert the node to latex.
//------------------------------------------------------------------------------
virtual void to_latex() const {
std::cout << "state";
std::cout << "random(";
this->arg->to_latex();
std::cout << ")";
}

//------------------------------------------------------------------------------
Expand Down
16 changes: 16 additions & 0 deletions graph_tests/random_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,21 @@ template<jit::float_scalar T> void test_graph() {
"Expected atan node.");
}

//------------------------------------------------------------------------------
/// @brief Test multiple randoms in a single kernel.
//------------------------------------------------------------------------------
template<jit::float_scalar T> void test_multi() {
auto state = graph::random_state<T> (jit::context<T>::random_state_size, 0);
auto random1 = graph::random<T> (graph::random_state_cast(state));
auto random2 = graph::random<T> (graph::random_state_cast(state));

workflow::manager<T> work(0);
work.add_item({}, {
random1, random2
}, {}, graph::random_state_cast(state), "multi_random", 1);
work.compile();
}

//------------------------------------------------------------------------------
/// @brief Run tests.
///
Expand All @@ -145,6 +160,7 @@ template<jit::float_scalar T> void test_graph() {
template<jit::float_scalar T, size_t N> void run_tests() {
test_dist<T, N> ();
test_graph<T> ();
test_multi<T> ();
}

//------------------------------------------------------------------------------
Expand Down