CodeQL / Analyze (actions) (push) Canceled after 0s
CodeQL / Analyze (python) (push) Canceled after 0s
pre-commit / pre-commit (push) Canceled after 0s
Multi-Arch CI / setup (push) Canceled after 0s
Publish build_manylinux_x86_64 images / publish_build_manylinux_x86_64 (push) Canceled after 0s
Setup (Multi-Arch) / setup (push) Canceled after 0s
Multi-Arch CI / Linux::${{ fromJSON(needs.setup.outputs.linux_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubi10 image / publish_no_rocm_image_ubi10 (push) Canceled after 0s
Multi-Arch CI / Windows::${{ fromJSON(needs.setup.outputs.windows_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Multi-Arch CI / Manifest Diff (push) Canceled after 0s
TheRock Manifest Diff Report / Generate Manifest Diff Report (push) Canceled after 0s
Multi-Arch CI / CI Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_ocl_rt images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_rocgdb images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Unit Tests / Unit Tests :: ubuntu-24.04 (push) Canceled after 0s
Unit Tests / Unit Tests :: windows-2022 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_media (push) Canceled after 0s
Unit Tests / Unit Tests Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_openmpi (push) Canceled after 0s
1005 lines
37 KiB
C++
1005 lines
37 KiB
C++
// Copyright (c) 2017-2025 Advanced Micro Devices, Inc. All rights reserved.
|
|
//
|
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
// of this software and associated documentation files (the "Software"), to deal
|
|
// in the Software without restriction, including without limitation the rights
|
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
// copies of the Software, and to permit persons to whom the Software is
|
|
// furnished to do so, subject to the following conditions:
|
|
//
|
|
// The above copyright notice and this permission notice shall be included in
|
|
// all copies or substantial portions of the Software.
|
|
//
|
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
// THE SOFTWARE.
|
|
|
|
#include <gtest/gtest.h>
|
|
#include <stdio.h>
|
|
|
|
#include "test_common.hpp"
|
|
#include "test_rocrand_common.hpp"
|
|
|
|
#include <algorithm>
|
|
#include <numeric>
|
|
#include <random>
|
|
|
|
#include <rocrand/rocrand_discrete.h>
|
|
#include <rocrand/rocrand_mtgp32_11213.h>
|
|
#include <vector>
|
|
|
|
#include <hip/hip_runtime.h>
|
|
|
|
struct GlobalSizes
|
|
{
|
|
static constexpr size_t items_per_thread = 256;
|
|
static constexpr size_t block_size = 32;
|
|
static constexpr size_t items_per_block = items_per_thread * block_size;
|
|
static constexpr size_t grid_size = 1234;
|
|
static constexpr size_t size = grid_size * items_per_block;
|
|
};
|
|
|
|
using DiscreteDataType
|
|
= ::testing::Types<double, unsigned int, unsigned long, unsigned long long int>;
|
|
|
|
template<typename DT>
|
|
class InternalDiscreteDistributionTests : public ::testing::Test
|
|
{
|
|
public:
|
|
using T = DT;
|
|
};
|
|
|
|
TYPED_TEST_SUITE(InternalDiscreteDistributionTests, DiscreteDataType);
|
|
|
|
template<typename T, class DiscreteWrapper>
|
|
__global__
|
|
void internal_discrete_kernel(T* device_input,
|
|
unsigned int* device_output,
|
|
rocrand_discrete_distribution_st& dis)
|
|
{
|
|
const size_t items_per_block = GlobalSizes::items_per_thread * GlobalSizes::block_size;
|
|
const size_t offset
|
|
= (items_per_block * blockIdx.x) + (GlobalSizes::items_per_thread * threadIdx.x);
|
|
|
|
for(size_t i = 0; i < GlobalSizes::items_per_thread; i++)
|
|
{
|
|
device_output[offset + i] = DiscreteWrapper{}(device_input[offset + i], dis);
|
|
}
|
|
}
|
|
|
|
template<typename T, class DiscreteWrapper>
|
|
void run_internal_discrete_tests()
|
|
{
|
|
std::vector<std::vector<double>> all_distributions = {
|
|
{10, 10, 10, 10},
|
|
{1, 2, 3, 4, 5, 6, 5, 4, 3, 2, 1},
|
|
{1234, 1677, 1519, 1032, 561, 254, 98, 33, 10, 2},
|
|
{1, 2, 8, 4, 3, 2, 1}
|
|
};
|
|
|
|
std::random_device rd;
|
|
std::mt19937 gen(rd());
|
|
|
|
T* host_input = new T[GlobalSizes::size];
|
|
unsigned int* host_output = new unsigned int[GlobalSizes::size];
|
|
|
|
// Check for different types of data input and generate the input data
|
|
if constexpr(std::is_same_v<T, double>)
|
|
{
|
|
std::uniform_real_distribution<double> dis(0, 1);
|
|
for(size_t i = 0; i < GlobalSizes::size; i++)
|
|
host_input[i] = dis(gen);
|
|
}
|
|
else if constexpr(std::is_same_v<T, unsigned long> || std::is_same_v<T, unsigned int>)
|
|
{
|
|
std::uniform_int_distribution<T> dis(0, std::numeric_limits<unsigned int>::max());
|
|
for(size_t i = 0; i < GlobalSizes::size; i++)
|
|
host_input[i] = dis(gen);
|
|
}
|
|
else
|
|
{
|
|
std::uniform_int_distribution<T> dis(0, std::numeric_limits<T>::max());
|
|
for(size_t i = 0; i < GlobalSizes::size; i++)
|
|
host_input[i] = dis(gen);
|
|
}
|
|
|
|
T* device_input;
|
|
unsigned int* device_output;
|
|
|
|
HIP_CHECK(hipMalloc(&device_input, sizeof(T) * GlobalSizes::size));
|
|
HIP_CHECK(hipMalloc(&device_output, sizeof(unsigned int) * GlobalSizes::size));
|
|
|
|
HIP_CHECK(
|
|
hipMemcpy(device_input, host_input, sizeof(T) * GlobalSizes::size, hipMemcpyHostToDevice));
|
|
|
|
// Generate different discrete distributions and check them against expected
|
|
for(std::vector<double> distribution : all_distributions)
|
|
{
|
|
// Getting expected Results
|
|
double sum = std::accumulate(distribution.begin(), distribution.end(), 0);
|
|
std::vector<double> expected_prob(distribution.size());
|
|
for(size_t i = 0; i < distribution.size(); i++)
|
|
expected_prob[i] = distribution[i] / sum;
|
|
|
|
// Creating the discrete distribution
|
|
rocrand_discrete_distribution discrete_distribution;
|
|
ROCRAND_CHECK(rocrand_create_discrete_distribution(expected_prob.data(),
|
|
expected_prob.size(),
|
|
0,
|
|
&discrete_distribution));
|
|
|
|
internal_discrete_kernel<T, DiscreteWrapper>
|
|
<<<dim3(GlobalSizes::grid_size), dim3(GlobalSizes::block_size), 0, 0>>>(
|
|
device_input,
|
|
device_output,
|
|
*discrete_distribution);
|
|
|
|
HIP_CHECK(hipMemcpy(host_output,
|
|
device_output,
|
|
sizeof(unsigned int) * GlobalSizes::size,
|
|
hipMemcpyDeviceToHost));
|
|
|
|
std::vector<double> histogram(distribution.size());
|
|
|
|
// Calculating the actual results
|
|
for(size_t i = 0; i < GlobalSizes::size; i++)
|
|
histogram[host_output[i]]++;
|
|
|
|
std::vector<double> actual_prob(distribution.size());
|
|
for(size_t i = 0; i < actual_prob.size(); i++)
|
|
actual_prob[i] = histogram[i] / static_cast<double>(GlobalSizes::size);
|
|
|
|
ASSERT_TRUE(ks_test_2(expected_prob, actual_prob));
|
|
|
|
ROCRAND_CHECK(rocrand_destroy_discrete_distribution(discrete_distribution));
|
|
}
|
|
|
|
delete[] host_input;
|
|
delete[] host_output;
|
|
|
|
HIP_CHECK(hipFree(device_input));
|
|
HIP_CHECK(hipFree(device_output));
|
|
}
|
|
|
|
template<typename T>
|
|
struct internal_discrete_alias
|
|
{
|
|
__device__
|
|
auto operator()(T val, rocrand_discrete_distribution_st& dis)
|
|
{
|
|
return rocrand_device::detail::discrete_alias(val, dis);
|
|
}
|
|
};
|
|
|
|
template<typename T>
|
|
struct internal_discrete_cdf
|
|
{
|
|
__device__
|
|
auto operator()(T val, rocrand_discrete_distribution_st& dis)
|
|
{
|
|
return rocrand_device::detail::discrete_cdf(val, dis);
|
|
}
|
|
};
|
|
|
|
TYPED_TEST(InternalDiscreteDistributionTests, InternalDiscreteAliasTest)
|
|
{
|
|
using T = typename TestFixture::T;
|
|
|
|
run_internal_discrete_tests<T, internal_discrete_alias<T>>();
|
|
}
|
|
|
|
TYPED_TEST(InternalDiscreteDistributionTests, InternalDiscreteCDFTest)
|
|
{
|
|
using T = typename TestFixture::T;
|
|
|
|
run_internal_discrete_tests<T, internal_discrete_cdf<T>>();
|
|
}
|
|
|
|
template<class RocRandPrngType>
|
|
__global__
|
|
void block_wide_external_discrete_kernel(RocRandPrngType* states,
|
|
unsigned int* device_output,
|
|
rocrand_discrete_distribution_st& dis,
|
|
size_t items_per_thread,
|
|
size_t block_size)
|
|
{
|
|
const size_t items_per_block = items_per_thread * block_size;
|
|
const size_t offset = (items_per_block * blockIdx.x) + (items_per_thread * threadIdx.x);
|
|
|
|
for(size_t i = 0; i < items_per_thread; i++)
|
|
{
|
|
__shared__
|
|
RocRandPrngType state;
|
|
if(threadIdx.x == 0)
|
|
state = states[blockIdx.x];
|
|
__syncthreads();
|
|
|
|
device_output[offset + i] = rocrand_discrete(&state, &dis);
|
|
|
|
if(threadIdx.x == 0)
|
|
states[blockIdx.x] = state;
|
|
__syncthreads();
|
|
}
|
|
}
|
|
|
|
template<class RocRandPrngType>
|
|
__global__
|
|
void external_discrete_kernel(RocRandPrngType* states,
|
|
unsigned int* device_output,
|
|
rocrand_discrete_distribution_st& dis,
|
|
size_t items_per_thread,
|
|
size_t block_size)
|
|
{
|
|
const size_t items_per_block = items_per_thread * block_size;
|
|
const size_t offset = (items_per_block * blockIdx.x) + (items_per_thread * threadIdx.x);
|
|
|
|
for(size_t i = 0; i < items_per_thread; i++)
|
|
{
|
|
auto local_state = states[offset + i];
|
|
device_output[offset + i] = rocrand_discrete(&local_state, &dis);
|
|
states[offset + i] = local_state;
|
|
}
|
|
}
|
|
|
|
template<bool block_wide, class PrngState>
|
|
void run_external_discrete_tests(PrngState& device_states,
|
|
size_t items_per_thread = GlobalSizes::items_per_thread,
|
|
size_t block_size = GlobalSizes::block_size,
|
|
size_t grid_size = GlobalSizes::grid_size,
|
|
size_t size = GlobalSizes::size)
|
|
{
|
|
|
|
std::vector<std::vector<double>> all_distributions = {
|
|
{10, 10, 10, 10},
|
|
{1, 2, 3, 4, 5, 6, 5, 4, 3, 2, 1},
|
|
{1234, 1677, 1519, 1032, 561, 254, 98, 33, 10, 2},
|
|
{1, 2, 8, 4, 3, 2, 1}
|
|
};
|
|
|
|
unsigned int* host_output = new unsigned int[size];
|
|
unsigned int* device_output;
|
|
HIP_CHECK(hipMalloc(&device_output, sizeof(unsigned int) * size));
|
|
|
|
for(std::vector<double> distribution : all_distributions)
|
|
{
|
|
|
|
// Getting expected Results
|
|
double sum = std::accumulate(distribution.begin(), distribution.end(), 0);
|
|
std::vector<double> expected_prob(distribution.size());
|
|
for(size_t i = 0; i < distribution.size(); i++)
|
|
expected_prob[i] = distribution[i] / sum;
|
|
|
|
// Creating the discrete distribution
|
|
rocrand_discrete_distribution discrete_distribution;
|
|
ROCRAND_CHECK(rocrand_create_discrete_distribution(expected_prob.data(),
|
|
expected_prob.size(),
|
|
0,
|
|
&discrete_distribution));
|
|
|
|
if constexpr(block_wide)
|
|
{
|
|
hipLaunchKernelGGL(HIP_KERNEL_NAME(block_wide_external_discrete_kernel),
|
|
dim3(grid_size),
|
|
dim3(block_size),
|
|
0,
|
|
0,
|
|
device_states,
|
|
device_output,
|
|
*discrete_distribution,
|
|
items_per_thread,
|
|
block_size);
|
|
}
|
|
else
|
|
{
|
|
hipLaunchKernelGGL(HIP_KERNEL_NAME(external_discrete_kernel),
|
|
dim3(grid_size),
|
|
dim3(block_size),
|
|
0,
|
|
0,
|
|
device_states,
|
|
device_output,
|
|
*discrete_distribution,
|
|
items_per_thread,
|
|
block_size);
|
|
}
|
|
|
|
HIP_CHECK(hipMemcpy(host_output,
|
|
device_output,
|
|
sizeof(unsigned int) * size,
|
|
hipMemcpyDeviceToHost));
|
|
std::vector<double> histogram(distribution.size());
|
|
|
|
// Calculating the actual results
|
|
for(size_t i = 0; i < size; i++)
|
|
histogram[host_output[i]]++;
|
|
|
|
std::vector<double> actual_prob(distribution.size());
|
|
for(size_t i = 0; i < actual_prob.size(); i++)
|
|
actual_prob[i] = histogram[i] / static_cast<double>(size);
|
|
|
|
ASSERT_TRUE(ks_test_2(expected_prob, actual_prob));
|
|
ROCRAND_CHECK(rocrand_destroy_discrete_distribution(discrete_distribution));
|
|
}
|
|
|
|
delete[] host_output;
|
|
HIP_CHECK(hipFree(device_output));
|
|
}
|
|
|
|
template<class RocRandPrngType>
|
|
__global__
|
|
void init_rocrand_states_kernel(RocRandPrngType* states)
|
|
{
|
|
constexpr size_t items_per_block = GlobalSizes::items_per_thread * GlobalSizes::block_size;
|
|
const size_t offset
|
|
= (items_per_block * blockIdx.x) + (GlobalSizes::items_per_thread * threadIdx.x);
|
|
|
|
for(size_t i = 0; i < GlobalSizes::items_per_thread; i++)
|
|
{
|
|
rocrand_init(static_cast<unsigned int>(123456 ^ i), offset + i, 0, &states[offset + i]);
|
|
}
|
|
}
|
|
|
|
template<class RocRandPrngType>
|
|
__global__
|
|
void init_rocrand_states_kernel4(RocRandPrngType* states)
|
|
{
|
|
constexpr size_t items_per_block = GlobalSizes::items_per_thread * GlobalSizes::block_size;
|
|
const size_t offset
|
|
= (items_per_block * blockIdx.x) + (GlobalSizes::items_per_thread * threadIdx.x);
|
|
|
|
for(size_t i = 0; i < GlobalSizes::items_per_thread; i++)
|
|
{
|
|
rocrand_init(uint4{static_cast<unsigned int>((123456 ^ i)),
|
|
static_cast<unsigned int>((123456 ^ i) << 1),
|
|
static_cast<unsigned int>((123456 ^ i) << 2),
|
|
static_cast<unsigned int>((123456 ^ i) << 3)},
|
|
offset + i,
|
|
0,
|
|
&states[offset + i]);
|
|
}
|
|
}
|
|
|
|
TEST(ExternalDiscreteDistributionTests, Philox4x32_10Test)
|
|
{
|
|
// Initialize the prng state
|
|
rocrand_state_philox4x32_10* device_states;
|
|
HIP_CHECK(hipMalloc(&device_states, sizeof(rocrand_state_philox4x32_10) * GlobalSizes::size));
|
|
|
|
struct f
|
|
{
|
|
__device__
|
|
static void init(size_t index, size_t offset, rocrand_state_philox4x32_10* state)
|
|
{
|
|
rocrand_init((123456 ^ index), offset + index, 0, state);
|
|
}
|
|
};
|
|
|
|
init_rocrand_states_kernel<<<dim3(GlobalSizes::grid_size),
|
|
dim3(GlobalSizes::block_size),
|
|
0,
|
|
0>>>(device_states);
|
|
|
|
run_external_discrete_tests<false>(device_states);
|
|
|
|
HIP_CHECK(hipFree(device_states));
|
|
}
|
|
|
|
TEST(ExternalDiscreteDistributionTests, Mrg31k3pTest)
|
|
{
|
|
// Initialize the prng state
|
|
rocrand_state_mrg31k3p* device_states;
|
|
HIP_CHECK(hipMalloc(&device_states, sizeof(rocrand_state_mrg31k3p) * GlobalSizes::size));
|
|
|
|
struct f
|
|
{
|
|
__device__
|
|
static void init(size_t index, size_t offset, rocrand_state_mrg31k3p* state)
|
|
{
|
|
rocrand_init((123456 ^ index), offset + index, 0, state);
|
|
}
|
|
};
|
|
|
|
init_rocrand_states_kernel<<<dim3(GlobalSizes::grid_size),
|
|
dim3(GlobalSizes::block_size),
|
|
0,
|
|
0>>>(device_states);
|
|
|
|
run_external_discrete_tests<false>(device_states);
|
|
|
|
HIP_CHECK(hipFree(device_states));
|
|
}
|
|
|
|
TEST(ExternalDiscreteDistributionTests, Mrg32k3aTest)
|
|
{
|
|
// Initialize the prng state
|
|
rocrand_state_mrg32k3a* device_states;
|
|
HIP_CHECK(hipMalloc(&device_states, sizeof(rocrand_state_mrg32k3a) * GlobalSizes::size));
|
|
|
|
init_rocrand_states_kernel<<<dim3(GlobalSizes::grid_size),
|
|
dim3(GlobalSizes::block_size),
|
|
0,
|
|
0>>>(device_states);
|
|
|
|
run_external_discrete_tests<false>(device_states);
|
|
|
|
HIP_CHECK(hipFree(device_states));
|
|
}
|
|
|
|
TEST(ExternalDiscreteDistributionTests, XorwowTest)
|
|
{
|
|
// Initialize the prng state
|
|
rocrand_state_xorwow* device_states;
|
|
HIP_CHECK(hipMalloc(&device_states, sizeof(rocrand_state_xorwow) * GlobalSizes::size));
|
|
|
|
init_rocrand_states_kernel<<<dim3(GlobalSizes::grid_size),
|
|
dim3(GlobalSizes::block_size),
|
|
0,
|
|
0>>>(device_states);
|
|
|
|
run_external_discrete_tests<false>(device_states);
|
|
|
|
HIP_CHECK(hipFree(device_states));
|
|
}
|
|
|
|
TEST(ExternalDiscreteDistributionTests, Mtgp32Test)
|
|
{
|
|
constexpr size_t items_per_thread = 1024;
|
|
constexpr size_t block_size = 256;
|
|
constexpr size_t grid_size = 12;
|
|
constexpr size_t items_per_block = block_size * items_per_thread;
|
|
|
|
constexpr size_t test_size = items_per_block * grid_size;
|
|
rocrand_state_mtgp32* states;
|
|
|
|
HIP_CHECK(hipMalloc(&states, sizeof(rocrand_state_mtgp32) * grid_size));
|
|
rocrand_make_state_mtgp32(states, mtgp32dc_params_fast_11213, grid_size, 123456);
|
|
HIP_CHECK(hipDeviceSynchronize());
|
|
|
|
run_external_discrete_tests<true>(states, items_per_thread, block_size, grid_size, test_size);
|
|
HIP_CHECK(hipFree(states));
|
|
}
|
|
|
|
TEST(ExternalDiscreteDistributionTests, Lfsr113Test)
|
|
{
|
|
// Initialize the prng state
|
|
rocrand_state_lfsr113* device_states;
|
|
HIP_CHECK(hipMalloc(&device_states, sizeof(rocrand_state_lfsr113) * GlobalSizes::size));
|
|
|
|
init_rocrand_states_kernel4<<<dim3(GlobalSizes::grid_size),
|
|
dim3(GlobalSizes::block_size),
|
|
0,
|
|
0>>>(device_states);
|
|
|
|
run_external_discrete_tests<false>(device_states);
|
|
|
|
HIP_CHECK(hipFree(device_states));
|
|
}
|
|
|
|
TEST(ExternalDiscreteDistributionTests, Sobol32Test)
|
|
{
|
|
// Initialize the prng state
|
|
rocrand_state_sobol32* host_states = new rocrand_state_sobol32[GlobalSizes::size];
|
|
const unsigned int* directions;
|
|
ROCRAND_CHECK(
|
|
rocrand_get_direction_vectors32(&directions, ROCRAND_DIRECTION_VECTORS_32_JOEKUO6));
|
|
|
|
// 640000 is the size of directions. This is to prevent overflow stuff
|
|
for(size_t i = 0; i < GlobalSizes::size; i++)
|
|
rocrand_init(directions, i % 640000, host_states + i);
|
|
|
|
rocrand_state_sobol32* device_states;
|
|
HIP_CHECK(hipMalloc(&device_states, sizeof(rocrand_state_sobol32) * GlobalSizes::size));
|
|
HIP_CHECK(hipMemcpy(device_states,
|
|
host_states,
|
|
sizeof(rocrand_state_sobol32) * GlobalSizes::size,
|
|
hipMemcpyHostToDevice));
|
|
|
|
run_external_discrete_tests<false>(device_states);
|
|
|
|
delete[] host_states;
|
|
HIP_CHECK(hipFree(device_states));
|
|
}
|
|
|
|
TEST(ExternalDiscreteDistributionTests, ScrambledSobol32Test)
|
|
{
|
|
// Initialize the prng state
|
|
rocrand_state_scrambled_sobol32* host_states
|
|
= new rocrand_state_scrambled_sobol32[GlobalSizes::size];
|
|
const unsigned int* directions;
|
|
ROCRAND_CHECK(
|
|
rocrand_get_direction_vectors32(&directions, ROCRAND_DIRECTION_VECTORS_32_JOEKUO6));
|
|
|
|
// 640000 is the size of directions. This is to prevent overflow stuff
|
|
for(size_t i = 0; i < GlobalSizes::size; i++)
|
|
rocrand_init(directions, 123456 ^ i, i % 640000, host_states + i);
|
|
|
|
rocrand_state_scrambled_sobol32* device_states;
|
|
HIP_CHECK(
|
|
hipMalloc(&device_states, sizeof(rocrand_state_scrambled_sobol32) * GlobalSizes::size));
|
|
HIP_CHECK(hipMemcpy(device_states,
|
|
host_states,
|
|
sizeof(rocrand_state_scrambled_sobol32) * GlobalSizes::size,
|
|
hipMemcpyHostToDevice));
|
|
|
|
run_external_discrete_tests<false>(device_states);
|
|
|
|
delete[] host_states;
|
|
HIP_CHECK(hipFree(device_states));
|
|
}
|
|
|
|
TEST(ExternalDiscreteDistributionTests, Sobol64Test)
|
|
{
|
|
// Initialize the prng state
|
|
rocrand_state_sobol64* host_states = new rocrand_state_sobol64[GlobalSizes::size];
|
|
const unsigned long long* directions;
|
|
ROCRAND_CHECK(
|
|
rocrand_get_direction_vectors64(&directions, ROCRAND_DIRECTION_VECTORS_64_JOEKUO6));
|
|
|
|
// 1280000 is the size of directions. This is to prevent overflow stuff
|
|
for(size_t i = 0; i < GlobalSizes::size; i++)
|
|
rocrand_init(directions, i % 1280000, host_states + i);
|
|
|
|
rocrand_state_sobol64* device_states;
|
|
HIP_CHECK(hipMalloc(&device_states, sizeof(rocrand_state_sobol64) * GlobalSizes::size));
|
|
HIP_CHECK(hipMemcpy(device_states,
|
|
host_states,
|
|
sizeof(rocrand_state_sobol64) * GlobalSizes::size,
|
|
hipMemcpyHostToDevice));
|
|
|
|
run_external_discrete_tests<false>(device_states);
|
|
|
|
delete[] host_states;
|
|
HIP_CHECK(hipFree(device_states));
|
|
}
|
|
|
|
TEST(ExternalDiscreteDistributionTests, ScrambledSobol64Test)
|
|
{
|
|
// Initialize the prng state
|
|
rocrand_state_scrambled_sobol64* host_states
|
|
= new rocrand_state_scrambled_sobol64[GlobalSizes::size];
|
|
const unsigned long long* directions;
|
|
ROCRAND_CHECK(
|
|
rocrand_get_direction_vectors64(&directions, ROCRAND_DIRECTION_VECTORS_64_JOEKUO6));
|
|
|
|
// 1280000 is the size of directions. This is to prevent overflow stuff
|
|
for(size_t i = 0; i < GlobalSizes::size; i++)
|
|
rocrand_init(directions, 123456 ^ i, i % 1280000, host_states + i);
|
|
|
|
rocrand_state_scrambled_sobol64* device_states;
|
|
HIP_CHECK(
|
|
hipMalloc(&device_states, sizeof(rocrand_state_scrambled_sobol64) * GlobalSizes::size));
|
|
HIP_CHECK(hipMemcpy(device_states,
|
|
host_states,
|
|
sizeof(rocrand_state_scrambled_sobol64) * GlobalSizes::size,
|
|
hipMemcpyHostToDevice));
|
|
|
|
run_external_discrete_tests<false>(device_states);
|
|
|
|
delete[] host_states;
|
|
HIP_CHECK(hipFree(device_states));
|
|
}
|
|
|
|
TEST(ExternalDiscreteDistributionTests, Threefry2x32_20Test)
|
|
{
|
|
// Initialize the prng state
|
|
rocrand_state_threefry2x32_20* device_states;
|
|
HIP_CHECK(hipMalloc(&device_states, sizeof(rocrand_state_threefry2x32_20) * GlobalSizes::size));
|
|
|
|
init_rocrand_states_kernel<<<dim3(GlobalSizes::grid_size),
|
|
dim3(GlobalSizes::block_size),
|
|
0,
|
|
0>>>(device_states);
|
|
|
|
run_external_discrete_tests<false>(device_states);
|
|
|
|
HIP_CHECK(hipFree(device_states));
|
|
}
|
|
|
|
TEST(ExternalDiscreteDistributionTests, Threefry2x64_20Test)
|
|
{
|
|
// Initialize the prng state
|
|
rocrand_state_threefry2x64_20* device_states;
|
|
HIP_CHECK(hipMalloc(&device_states, sizeof(rocrand_state_threefry2x64_20) * GlobalSizes::size));
|
|
|
|
init_rocrand_states_kernel<<<dim3(GlobalSizes::grid_size),
|
|
dim3(GlobalSizes::block_size),
|
|
0,
|
|
0>>>(device_states);
|
|
|
|
run_external_discrete_tests<false>(device_states);
|
|
|
|
HIP_CHECK(hipFree(device_states));
|
|
}
|
|
|
|
TEST(ExternalDiscreteDistributionTests, Threefry4x32_20Test)
|
|
{
|
|
// Initialize the prng state
|
|
rocrand_state_threefry4x32_20* device_states;
|
|
HIP_CHECK(hipMalloc(&device_states, sizeof(rocrand_state_threefry4x32_20) * GlobalSizes::size));
|
|
|
|
init_rocrand_states_kernel<<<dim3(GlobalSizes::grid_size),
|
|
dim3(GlobalSizes::block_size),
|
|
0,
|
|
0>>>(device_states);
|
|
|
|
run_external_discrete_tests<false>(device_states);
|
|
|
|
HIP_CHECK(hipFree(device_states));
|
|
}
|
|
|
|
TEST(ExternalDiscreteDistributionTests, Threefry4x64_20Test)
|
|
{
|
|
// Initialize the prng state
|
|
rocrand_state_threefry4x64_20* device_states;
|
|
HIP_CHECK(hipMalloc(&device_states, sizeof(rocrand_state_threefry4x64_20) * GlobalSizes::size));
|
|
|
|
init_rocrand_states_kernel<<<dim3(GlobalSizes::grid_size),
|
|
dim3(GlobalSizes::block_size),
|
|
0,
|
|
0>>>(device_states);
|
|
|
|
run_external_discrete_tests<false>(device_states);
|
|
|
|
HIP_CHECK(hipFree(device_states));
|
|
}
|
|
|
|
template<size_t items_per_thread, size_t block_size>
|
|
__global__
|
|
void uint4_kernel(rocrand_state_philox4x32_10* states,
|
|
uint4* device_output,
|
|
rocrand_discrete_distribution_st& dis)
|
|
{
|
|
const size_t items_per_block = items_per_thread * block_size;
|
|
const size_t offset = (items_per_block * blockIdx.x) + (items_per_thread * threadIdx.x);
|
|
|
|
for(size_t i = 0; i < items_per_thread; i++)
|
|
{
|
|
auto local_state = states[offset + i];
|
|
device_output[offset + i] = rocrand_discrete4(&local_state, &dis);
|
|
states[offset + i] = local_state;
|
|
}
|
|
}
|
|
|
|
TEST(ExternalDiscreteDistributionTests, Philox4x32_10WithUIN4OutputTest)
|
|
{
|
|
// Initialize the prng state
|
|
rocrand_state_philox4x32_10* device_states;
|
|
HIP_CHECK(hipMalloc(&device_states, sizeof(rocrand_state_philox4x32_10) * GlobalSizes::size));
|
|
|
|
init_rocrand_states_kernel<<<dim3(GlobalSizes::grid_size),
|
|
dim3(GlobalSizes::block_size),
|
|
0,
|
|
0>>>(device_states);
|
|
|
|
std::vector<std::vector<double>> all_distributions = {
|
|
{10, 10, 10, 10},
|
|
{1, 2, 3, 4, 5, 6, 5, 4, 3, 2, 1},
|
|
{1234, 1677, 1519, 1032, 561, 254, 98, 33, 10, 2},
|
|
{1, 2, 8, 4, 3, 2, 1}
|
|
};
|
|
|
|
uint4* host_output = new uint4[GlobalSizes::size];
|
|
uint4* device_output;
|
|
HIP_CHECK(hipMalloc(&device_output, sizeof(uint4) * GlobalSizes::size));
|
|
|
|
for(std::vector<double> distribution : all_distributions)
|
|
{
|
|
|
|
// Getting expected Results
|
|
double sum = std::accumulate(distribution.begin(), distribution.end(), 0);
|
|
std::vector<double> expected_prob(distribution.size());
|
|
for(size_t i = 0; i < distribution.size(); i++)
|
|
expected_prob[i] = distribution[i] / sum;
|
|
|
|
// Creating the discrete distribution
|
|
rocrand_discrete_distribution discrete_distribution;
|
|
ROCRAND_CHECK(rocrand_create_discrete_distribution(expected_prob.data(),
|
|
expected_prob.size(),
|
|
0,
|
|
&discrete_distribution));
|
|
|
|
hipLaunchKernelGGL(
|
|
HIP_KERNEL_NAME(uint4_kernel<GlobalSizes::items_per_thread, GlobalSizes::block_size>),
|
|
dim3(GlobalSizes::grid_size),
|
|
dim3(GlobalSizes::block_size),
|
|
0,
|
|
0,
|
|
device_states,
|
|
device_output,
|
|
*discrete_distribution);
|
|
|
|
HIP_CHECK(hipMemcpy(host_output,
|
|
device_output,
|
|
sizeof(uint4) * GlobalSizes::size,
|
|
hipMemcpyDeviceToHost));
|
|
std::vector<double> histogram(distribution.size());
|
|
|
|
// Calculating the actual results
|
|
for(size_t i = 0; i < GlobalSizes::size; i++)
|
|
{
|
|
histogram[host_output[i].w]++;
|
|
histogram[host_output[i].x]++;
|
|
histogram[host_output[i].y]++;
|
|
histogram[host_output[i].z]++;
|
|
}
|
|
|
|
std::vector<double> actual_prob(distribution.size());
|
|
for(size_t i = 0; i < actual_prob.size(); i++)
|
|
actual_prob[i] = histogram[i] / static_cast<double>(GlobalSizes::size * 4);
|
|
|
|
ASSERT_TRUE(ks_test_2(expected_prob, actual_prob));
|
|
ROCRAND_CHECK(rocrand_destroy_discrete_distribution(discrete_distribution));
|
|
}
|
|
|
|
delete[] host_output;
|
|
HIP_CHECK(hipFree(device_output));
|
|
HIP_CHECK(hipFree(device_states));
|
|
}
|
|
|
|
/* #################################################
|
|
|
|
TEST HOST SIDE
|
|
|
|
###############################################*/
|
|
|
|
#include "rng/distribution/discrete.hpp"
|
|
|
|
template<typename T, class DiscreteFunc>
|
|
void run_internal_host_test(const DiscreteFunc& df)
|
|
{
|
|
constexpr size_t test_size = 100000;
|
|
|
|
std::vector<std::vector<double>> all_distributions = {
|
|
{10, 10, 10, 10},
|
|
{1, 2, 3, 4, 5, 6, 5, 4, 3, 2, 1},
|
|
{1234, 1677, 1519, 1032, 561, 254, 98, 33, 10, 2},
|
|
{1, 2, 8, 4, 3, 2, 1}
|
|
};
|
|
|
|
std::random_device rd;
|
|
std::mt19937 gen(rd());
|
|
|
|
std::vector<T> input(test_size);
|
|
std::vector<unsigned int> histogram(test_size, 0);
|
|
|
|
// Check for different types of data input and generate the input data
|
|
if constexpr(std::is_same_v<T, double>)
|
|
{
|
|
std::uniform_real_distribution<double> dis(0, 1);
|
|
for(size_t i = 0; i < test_size; i++)
|
|
input[i] = dis(gen);
|
|
}
|
|
else if constexpr(std::is_same_v<T, unsigned long> || std::is_same_v<T, unsigned int>)
|
|
{
|
|
std::uniform_int_distribution<T> dis(0, std::numeric_limits<unsigned int>::max());
|
|
for(size_t i = 0; i < test_size; i++)
|
|
input[i] = dis(gen);
|
|
}
|
|
else
|
|
{
|
|
std::uniform_int_distribution<T> dis(0, std::numeric_limits<T>::max());
|
|
for(size_t i = 0; i < test_size; i++)
|
|
input[i] = dis(gen);
|
|
}
|
|
|
|
for(std::vector<double> distribution : all_distributions)
|
|
{
|
|
// Getting expected Results
|
|
double sum = std::accumulate(distribution.begin(), distribution.end(), 0);
|
|
std::vector<double> expected_prob(distribution.size());
|
|
for(size_t i = 0; i < distribution.size(); i++)
|
|
expected_prob[i] = distribution[i] / sum;
|
|
|
|
// Creating the discrete distribution
|
|
rocrand_discrete_distribution_st discrete_dis;
|
|
|
|
using namespace rocrand_impl::host;
|
|
|
|
rocrand_status rocrand_err
|
|
= discrete_distribution_factory<discrete_method::DISCRETE_METHOD_UNIVERSAL,
|
|
true>::create(distribution,
|
|
distribution.size(),
|
|
0,
|
|
discrete_dis);
|
|
|
|
ROCRAND_CHECK(rocrand_err);
|
|
std::vector<double> histogram(distribution.size());
|
|
for(size_t i = 0; i < test_size; i++)
|
|
{
|
|
histogram[df(input[i], discrete_dis)]++;
|
|
}
|
|
|
|
std::vector<double> actual_prob(distribution.size());
|
|
for(size_t i = 0; i < actual_prob.size(); i++)
|
|
actual_prob[i] = histogram[i] / static_cast<double>(test_size);
|
|
|
|
ASSERT_TRUE(ks_test_2(expected_prob, actual_prob));
|
|
|
|
rocrand_err = discrete_distribution_factory<discrete_method::DISCRETE_METHOD_UNIVERSAL,
|
|
true>::deallocate(discrete_dis);
|
|
ROCRAND_CHECK(rocrand_err);
|
|
}
|
|
}
|
|
|
|
template<typename InType, bool UseDiscreteAlias>
|
|
struct InternalHostParams
|
|
{
|
|
using T = InType;
|
|
static constexpr bool uda = UseDiscreteAlias;
|
|
};
|
|
|
|
using InternalDiscreteHostParams
|
|
= ::testing::Types<InternalHostParams<double, true>,
|
|
InternalHostParams<unsigned int, true>,
|
|
InternalHostParams<unsigned long, true>,
|
|
InternalHostParams<unsigned long long int, true>,
|
|
InternalHostParams<double, false>,
|
|
InternalHostParams<unsigned int, false>,
|
|
InternalHostParams<unsigned long, false>,
|
|
InternalHostParams<unsigned long long int, false>>;
|
|
|
|
template<class InternalHostParams>
|
|
class InternalDiscreteHostTest : public ::testing::Test
|
|
{
|
|
public:
|
|
using input_type = typename InternalHostParams::T;
|
|
static constexpr bool use_discrete_alias = InternalHostParams::uda;
|
|
};
|
|
|
|
TYPED_TEST_SUITE(InternalDiscreteHostTest, InternalDiscreteHostParams);
|
|
|
|
TYPED_TEST(InternalDiscreteHostTest, discrete_host_internal)
|
|
{
|
|
using input_type = typename TestFixture::input_type;
|
|
static constexpr bool use_discrete_alias = TestFixture::use_discrete_alias;
|
|
|
|
if constexpr(use_discrete_alias)
|
|
{
|
|
run_internal_host_test<input_type>(
|
|
[=](const input_type& x, rocrand_discrete_distribution_st& dis)
|
|
{ return rocrand_device::detail::discrete_alias(x, dis); });
|
|
}
|
|
else
|
|
{
|
|
run_internal_host_test<input_type>(
|
|
[=](const input_type& x, rocrand_discrete_distribution_st& dis)
|
|
{ return rocrand_device::detail::discrete_cdf(x, dis); });
|
|
}
|
|
}
|
|
|
|
template<class RocrandPRNGType>
|
|
inline void GetRocrandState(RocrandPRNGType* host_state)
|
|
{
|
|
|
|
if constexpr(std::is_same_v<RocrandPRNGType, rocrand_state_sobol32>)
|
|
{
|
|
const unsigned int* directions;
|
|
ROCRAND_CHECK(
|
|
rocrand_get_direction_vectors32(&directions, ROCRAND_DIRECTION_VECTORS_32_JOEKUO6));
|
|
rocrand_init(directions, 123456, host_state);
|
|
}
|
|
// scrambled sobol32 case
|
|
else if constexpr(std::is_same_v<RocrandPRNGType, rocrand_state_scrambled_sobol32>)
|
|
{
|
|
const unsigned int* directions;
|
|
ROCRAND_CHECK(
|
|
rocrand_get_direction_vectors32(&directions, ROCRAND_DIRECTION_VECTORS_32_JOEKUO6));
|
|
rocrand_init(directions, 123456, 654321, host_state);
|
|
}
|
|
// sobol64 case
|
|
else if constexpr(std::is_same_v<RocrandPRNGType, rocrand_state_sobol64>)
|
|
{
|
|
const unsigned long long* directions;
|
|
ROCRAND_CHECK(
|
|
rocrand_get_direction_vectors64(&directions, ROCRAND_DIRECTION_VECTORS_64_JOEKUO6));
|
|
rocrand_init(directions, 123456, host_state);
|
|
}
|
|
// scrambled sobol64 case
|
|
else if constexpr(std::is_same_v<RocrandPRNGType, rocrand_state_scrambled_sobol64>)
|
|
{
|
|
const unsigned long long* directions;
|
|
ROCRAND_CHECK(
|
|
rocrand_get_direction_vectors64(&directions, ROCRAND_DIRECTION_VECTORS_64_JOEKUO6));
|
|
rocrand_init(directions, 123456, 654321, host_state);
|
|
}
|
|
// lfsr113 case
|
|
else if constexpr(std::is_same_v<RocrandPRNGType, rocrand_state_lfsr113>)
|
|
{
|
|
rocrand_init({0xabcd, 0xdabc, 0xcdab, 0xbcda}, 0, 0, host_state);
|
|
}
|
|
else
|
|
{
|
|
rocrand_init(123456, 654321, 0, host_state);
|
|
}
|
|
}
|
|
|
|
template<typename RocrandPRNGType, class DiscreteFunc>
|
|
void run_host_test(const DiscreteFunc& df)
|
|
{
|
|
constexpr size_t test_size = 100000;
|
|
|
|
std::vector<std::vector<double>> all_distributions = {
|
|
{10, 10, 10, 10},
|
|
{1, 2, 3, 4, 5, 6, 5, 4, 3, 2, 1},
|
|
{1234, 1677, 1519, 1032, 561, 254, 98, 33, 10, 2},
|
|
{1, 2, 8, 4, 3, 2, 1}
|
|
};
|
|
|
|
RocrandPRNGType generator;
|
|
GetRocrandState(&generator);
|
|
|
|
for(std::vector<double> distribution : all_distributions)
|
|
{
|
|
// Getting expected Results
|
|
double sum = std::accumulate(distribution.begin(), distribution.end(), 0);
|
|
std::vector<double> expected_prob(distribution.size());
|
|
for(size_t i = 0; i < distribution.size(); i++)
|
|
expected_prob[i] = distribution[i] / sum;
|
|
|
|
// Creating the discrete distribution
|
|
rocrand_discrete_distribution_st discrete_dis;
|
|
|
|
using namespace rocrand_impl::host;
|
|
|
|
rocrand_status rocrand_err
|
|
= discrete_distribution_factory<discrete_method::DISCRETE_METHOD_UNIVERSAL,
|
|
true>::create(distribution,
|
|
distribution.size(),
|
|
0,
|
|
discrete_dis);
|
|
|
|
ROCRAND_CHECK(rocrand_err);
|
|
std::vector<double> histogram(distribution.size());
|
|
for(size_t i = 0; i < test_size; i++)
|
|
{
|
|
histogram[df(&generator, &discrete_dis)]++;
|
|
}
|
|
|
|
std::vector<double> actual_prob(distribution.size());
|
|
for(size_t i = 0; i < actual_prob.size(); i++)
|
|
actual_prob[i] = histogram[i] / static_cast<double>(test_size);
|
|
|
|
ASSERT_TRUE(ks_test_2(expected_prob, actual_prob));
|
|
|
|
rocrand_err = discrete_distribution_factory<discrete_method::DISCRETE_METHOD_UNIVERSAL,
|
|
true>::deallocate(discrete_dis);
|
|
ROCRAND_CHECK(rocrand_err);
|
|
}
|
|
}
|
|
|
|
using DiscreteHostParams = ::testing::Types<rocrand_state_philox4x32_10,
|
|
rocrand_state_mrg31k3p,
|
|
rocrand_state_mrg32k3a,
|
|
rocrand_state_xorwow,
|
|
rocrand_state_sobol32,
|
|
rocrand_state_scrambled_sobol32,
|
|
rocrand_state_sobol64,
|
|
rocrand_state_scrambled_sobol64,
|
|
rocrand_state_lfsr113,
|
|
rocrand_state_threefry2x32_20,
|
|
rocrand_state_threefry2x64_20,
|
|
rocrand_state_threefry4x32_20,
|
|
rocrand_state_threefry4x64_20>;
|
|
|
|
template<typename T>
|
|
class DiscreteHostTest : public ::testing::Test
|
|
{
|
|
public:
|
|
using rocrand_prng_type = T;
|
|
};
|
|
|
|
TYPED_TEST_SUITE(DiscreteHostTest, DiscreteHostParams);
|
|
|
|
TYPED_TEST(DiscreteHostTest, discrete_host)
|
|
{
|
|
using rocrand_prng_type = typename TestFixture::rocrand_prng_type;
|
|
|
|
run_host_test<rocrand_prng_type>(
|
|
[=](rocrand_prng_type* x, rocrand_discrete_distribution_st* dis)
|
|
{ return rocrand_discrete(x, dis); });
|
|
}
|