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
652 lines
19 KiB
C++
652 lines
19 KiB
C++
// MIT License
|
|
//
|
|
// Copyright (c) 2024-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.
|
|
|
|
#ifndef ROCTHRUST_BENCHMARKS_BENCH_UTILS_GENERATION_UTILS_HPP_
|
|
#define ROCTHRUST_BENCHMARKS_BENCH_UTILS_GENERATION_UTILS_HPP_
|
|
|
|
// Utils
|
|
#include "common/types.hpp"
|
|
|
|
// Thrust
|
|
#include <thrust/detail/config.h>
|
|
|
|
#include <thrust/copy.h>
|
|
#include <thrust/detail/raw_pointer_cast.h>
|
|
#include <thrust/device_vector.h>
|
|
#include <thrust/distance.h>
|
|
#include <thrust/execution_policy.h>
|
|
#include <thrust/fill.h>
|
|
#include <thrust/find.h>
|
|
#include <thrust/generate.h>
|
|
#include <thrust/host_vector.h>
|
|
#include <thrust/iterator/constant_iterator.h>
|
|
#include <thrust/iterator/counting_iterator.h>
|
|
#include <thrust/iterator/transform_output_iterator.h>
|
|
#include <thrust/iterator/zip_iterator.h>
|
|
#include <thrust/scan.h>
|
|
#include <thrust/sequence.h>
|
|
#include <thrust/tuple.h>
|
|
|
|
// rocPRIM
|
|
#include <rocprim/rocprim.hpp>
|
|
|
|
// rocRAND
|
|
#include <rocrand/rocrand.h>
|
|
|
|
// Google Benchmark
|
|
#include <benchmark/benchmark.h>
|
|
|
|
// STL
|
|
#include <algorithm>
|
|
#include <cstdint>
|
|
#include <limits>
|
|
#include <random>
|
|
#include <string>
|
|
#include <type_traits>
|
|
|
|
#define ROCRAND_CHECK(condition) \
|
|
{ \
|
|
rocrand_status _status = condition; \
|
|
if (_status != ROCRAND_STATUS_SUCCESS) \
|
|
{ \
|
|
std::cout << "rocRAND error: " << _status << " line: " << __LINE__ << std::endl; \
|
|
exit(_status); \
|
|
} \
|
|
}
|
|
|
|
namespace bench_utils
|
|
{
|
|
/// \brief Provides a sequence of seeds.
|
|
class managed_seed
|
|
{
|
|
public:
|
|
/// \param[in] seed_string Either "random" to get random seeds,
|
|
/// or an unsigned integer to get (a sequence) of deterministic seeds.
|
|
managed_seed(const std::string& seed_string)
|
|
{
|
|
is_random = seed_string == "random";
|
|
if (!is_random)
|
|
{
|
|
const unsigned int seed = std::stoul(seed_string);
|
|
std::seed_seq seq{seed};
|
|
seq.generate(seeds.begin(), seeds.end());
|
|
}
|
|
}
|
|
|
|
managed_seed()
|
|
: managed_seed("random"){};
|
|
|
|
unsigned int get_0() const
|
|
{
|
|
return is_random ? std::random_device{}() : seeds[0];
|
|
}
|
|
|
|
unsigned int get_1() const
|
|
{
|
|
return is_random ? std::random_device{}() : seeds[1];
|
|
}
|
|
|
|
unsigned int get_2() const
|
|
{
|
|
return is_random ? std::random_device{}() : seeds[2];
|
|
}
|
|
|
|
private:
|
|
std::array<unsigned int, 3> seeds;
|
|
bool is_random;
|
|
};
|
|
|
|
float get_entropy_percentage(int entropy_reduction)
|
|
{
|
|
switch (entropy_reduction)
|
|
{
|
|
case 0:
|
|
return 100.0;
|
|
case 1:
|
|
return 81.1;
|
|
case 2:
|
|
return 54.4;
|
|
case 3:
|
|
return 33.7;
|
|
case 4:
|
|
return 20.1;
|
|
default:
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
template <typename T>
|
|
T value_from_entropy(float64_t percentage)
|
|
{
|
|
if (percentage == 100.0)
|
|
{
|
|
return std::numeric_limits<T>::max();
|
|
}
|
|
|
|
percentage /= 100; // convert percentage to per one
|
|
|
|
// Select value from the line between the lowest and the highest representable
|
|
// values of type T based on the entropy value.
|
|
const auto max_val = static_cast<double>(std::numeric_limits<T>::max());
|
|
const auto min_val = static_cast<double>(std::numeric_limits<T>::lowest());
|
|
const auto result = min_val + percentage * (max_val - min_val);
|
|
return static_cast<T>(result);
|
|
}
|
|
|
|
const int entropy_reductions[] = {0, 2, 4, 6};
|
|
|
|
namespace detail
|
|
{
|
|
// std::uniform_int_distribution is undefined for anything other than:
|
|
// short, int, long, long long, unsigned short, unsigned int, unsigned long, or unsigned long long
|
|
template <typename T>
|
|
struct is_valid_for_int_distribution
|
|
: std::integral_constant<bool,
|
|
std::is_same<short, T>::value || std::is_same<unsigned short, T>::value
|
|
|| std::is_same<int, T>::value || std::is_same<unsigned int, T>::value
|
|
|| std::is_same<long, T>::value || std::is_same<unsigned long, T>::value
|
|
|| std::is_same<long long, T>::value || std::is_same<unsigned long long, T>::value>
|
|
{};
|
|
|
|
template <class T, class Enable = void>
|
|
struct random_to_item_t
|
|
{};
|
|
|
|
// Floating point types
|
|
template <typename T>
|
|
struct random_to_item_t<T, typename std::enable_if<std::is_floating_point<T>::value>::type>
|
|
{
|
|
double m_min;
|
|
double m_max;
|
|
|
|
__host__ __device__ random_to_item_t(T min, T max)
|
|
: m_min(static_cast<double>(min))
|
|
, m_max(static_cast<double>(max))
|
|
{}
|
|
|
|
__host__ __device__ auto operator()(double random_value) const
|
|
{
|
|
return static_cast<T>((m_max - m_min) * random_value + m_min);
|
|
}
|
|
};
|
|
|
|
// Integral types
|
|
template <typename T>
|
|
struct random_to_item_t<T, typename std::enable_if<!std::is_floating_point<T>::value>::type>
|
|
{
|
|
#if THRUST_BENCHMARKS_HAVE_INT128_SUPPORT
|
|
using CastT =
|
|
typename std::conditional<std::is_same<T, int128_t>::value || std::is_same<T, uint128_t>::value,
|
|
typename std::conditional<std::is_signed<T>::value, long, unsigned long>::type,
|
|
T>::type;
|
|
#else
|
|
using CastT = typename std::conditional<std::is_signed<T>::value, long, unsigned long>::type;
|
|
#endif
|
|
|
|
double m_min;
|
|
double m_max;
|
|
|
|
__host__ __device__ random_to_item_t(T min, T max)
|
|
: m_min(static_cast<double>(min))
|
|
, m_max(static_cast<double>(max))
|
|
{}
|
|
|
|
__host__ __device__ auto operator()(double random_value) const
|
|
{
|
|
return static_cast<CastT>(floor((m_max - m_min + 1) * random_value + m_min));
|
|
}
|
|
};
|
|
|
|
struct and_t
|
|
{
|
|
template <class T>
|
|
__host__ __device__ T operator()(T a, T b) const
|
|
{
|
|
return a & b;
|
|
}
|
|
|
|
__host__ __device__ float operator()(float a, float b) const
|
|
{
|
|
const std::uint32_t result = reinterpret_cast<std::uint32_t&>(a) & reinterpret_cast<std::uint32_t&>(b);
|
|
return reinterpret_cast<const float&>(result);
|
|
}
|
|
|
|
__host__ __device__ double operator()(double a, double b) const
|
|
{
|
|
const std::uint64_t result = reinterpret_cast<std::uint64_t&>(a) & reinterpret_cast<std::uint64_t&>(b);
|
|
return reinterpret_cast<const double&>(result);
|
|
}
|
|
};
|
|
|
|
template <class T>
|
|
struct geq_t
|
|
{
|
|
T val;
|
|
|
|
__host__ __device__ bool operator()(T x)
|
|
{
|
|
return x >= val;
|
|
}
|
|
};
|
|
|
|
template <class T>
|
|
class value_wrapper_t
|
|
{
|
|
T m_val{};
|
|
|
|
public:
|
|
explicit value_wrapper_t(T val)
|
|
: m_val(val)
|
|
{}
|
|
|
|
T get() const
|
|
{
|
|
return m_val;
|
|
}
|
|
|
|
value_wrapper_t& operator++()
|
|
{
|
|
m_val++;
|
|
return *this;
|
|
}
|
|
};
|
|
|
|
class seed_t : public value_wrapper_t<unsigned long long int>
|
|
{
|
|
public:
|
|
using value_wrapper_t::value_wrapper_t;
|
|
using value_wrapper_t::operator++;
|
|
|
|
seed_t()
|
|
: value_wrapper_t(42)
|
|
{}
|
|
};
|
|
|
|
struct device_generator_base_t
|
|
{
|
|
const std::size_t elements{0};
|
|
const std::string seed_type{"random"};
|
|
seed_t seed{};
|
|
const int entropy_reduction{0 /*bit_entropy::_1_000*/};
|
|
|
|
device_generator_base_t(std::size_t m_elements, const std::string& m_seed_type, int m_entropy_reduction)
|
|
: elements(m_elements)
|
|
, seed_type(m_seed_type)
|
|
, entropy_reduction(m_entropy_reduction)
|
|
{
|
|
ROCRAND_CHECK(rocrand_create_generator(&gen, ROCRAND_RNG_PSEUDO_DEFAULT));
|
|
const managed_seed managed_seed{seed_type};
|
|
seed = seed_t{managed_seed.get_0()};
|
|
}
|
|
|
|
~device_generator_base_t()
|
|
{
|
|
ROCRAND_CHECK(rocrand_destroy_generator(gen));
|
|
}
|
|
|
|
template <typename T>
|
|
thrust::device_vector<T> generate(T min, T max)
|
|
{
|
|
thrust::device_vector<T> data(elements);
|
|
const thrust::detail::device_t policy{};
|
|
|
|
if (entropy_reduction == 0) /*bit_entropy::_1_000*/
|
|
{
|
|
const double* uniform_distribution = this->new_uniform_distribution(seed, data.size());
|
|
|
|
thrust::transform(
|
|
policy, uniform_distribution, uniform_distribution + data.size(), data.data(), random_to_item_t<T>(min, max));
|
|
return data;
|
|
}
|
|
else if (entropy_reduction >= 5) /*bit_entropy::_0_000*/
|
|
{
|
|
std::mt19937 rng;
|
|
rng.seed(static_cast<std::mt19937::result_type>(seed.get()));
|
|
std::uniform_real_distribution<float> dist(0.0f, 1.0f);
|
|
T random_value = detail::random_to_item_t<T>(min, max)(dist(rng));
|
|
thrust::fill(policy, data.data(), data.data() + data.size(), random_value);
|
|
return data;
|
|
}
|
|
else
|
|
{
|
|
const double* uniform_distribution = this->new_uniform_distribution(seed, data.size());
|
|
++seed;
|
|
|
|
thrust::transform(
|
|
policy, uniform_distribution, uniform_distribution + data.size(), data.data(), random_to_item_t<T>(min, max));
|
|
|
|
const int number_of_steps = entropy_reduction;
|
|
|
|
thrust::device_vector<T> tmp(data.size());
|
|
|
|
for (int i = 0; i < number_of_steps; i++, ++seed)
|
|
{
|
|
this->no_entropy_generate(tmp, min, max);
|
|
|
|
thrust::transform(policy, data.data(), data.data() + data.size(), tmp.data(), data.data(), detail::and_t{});
|
|
}
|
|
return data;
|
|
}
|
|
}
|
|
|
|
const double* new_uniform_distribution(seed_t seed, std::size_t num_items)
|
|
{
|
|
distribution.resize(num_items);
|
|
double* d_distribution = thrust::raw_pointer_cast(distribution.data());
|
|
|
|
ROCRAND_CHECK(rocrand_set_seed(gen, seed.get()));
|
|
ROCRAND_CHECK(rocrand_generate_uniform_double(gen, d_distribution, num_items));
|
|
|
|
hipError_t error = hipDeviceSynchronize();
|
|
if (error != hipSuccess)
|
|
{
|
|
std::cout
|
|
<< "HIP error: " << hipGetErrorString(error) << " file: " << __FILE__ << " line: " << __LINE__ << std::endl;
|
|
exit(error);
|
|
}
|
|
|
|
return d_distribution;
|
|
}
|
|
|
|
private:
|
|
rocrand_generator gen;
|
|
thrust::device_vector<double> distribution;
|
|
|
|
template <typename T, typename Policy = thrust::detail::device_t>
|
|
void no_entropy_generate(thrust::device_vector<T>& data, T m_min, T m_max)
|
|
{
|
|
const double* uniform_distribution = this->new_uniform_distribution(seed, data.size());
|
|
|
|
thrust::transform(
|
|
Policy{},
|
|
uniform_distribution,
|
|
uniform_distribution + data.size(),
|
|
data.data(),
|
|
detail::random_to_item_t<T>(m_min, m_max));
|
|
return;
|
|
}
|
|
};
|
|
|
|
template <class T>
|
|
struct device_vector_generator_t : device_generator_base_t
|
|
{
|
|
const T min{std::numeric_limits<T>::min()};
|
|
const T max{std::numeric_limits<T>::max()};
|
|
|
|
device_vector_generator_t(
|
|
std::size_t m_elements, const std::string& m_seed_type, int m_entropy_reduction, T m_min, T m_max)
|
|
: device_generator_base_t(m_elements, m_seed_type, m_entropy_reduction)
|
|
, min(m_min)
|
|
, max(m_max)
|
|
{}
|
|
|
|
operator thrust::device_vector<T>()
|
|
{
|
|
return device_generator_base_t::generate(min, max);
|
|
}
|
|
};
|
|
|
|
template <>
|
|
struct device_vector_generator_t<void> : device_generator_base_t
|
|
{
|
|
device_vector_generator_t(std::size_t m_elements, const std::string& m_seed_type, int m_entropy_reduction)
|
|
: device_generator_base_t(m_elements, m_seed_type, m_entropy_reduction)
|
|
{}
|
|
|
|
template <typename T>
|
|
operator thrust::device_vector<T>()
|
|
{
|
|
return device_generator_base_t::generate(std::numeric_limits<T>::min(), std::numeric_limits<T>::max());
|
|
}
|
|
};
|
|
|
|
template <typename T>
|
|
std::size_t gen_uniform_offsets(
|
|
const std::string seed_type,
|
|
thrust::device_vector<T>& segment_offsets,
|
|
const std::size_t min_segment_size,
|
|
const std::size_t max_segment_size)
|
|
{
|
|
const T elements = segment_offsets.size() - 2;
|
|
|
|
segment_offsets = device_generator_base_t(segment_offsets.size(), seed_type, 0 /*bit_entropy::_1_000*/)
|
|
.generate(static_cast<T>(min_segment_size), static_cast<T>(max_segment_size));
|
|
|
|
// Find the range of contiguous offsets starting from index 0 which sum is greater or
|
|
// equal than 'elements'.
|
|
const thrust::detail::device_t policy{};
|
|
|
|
// Add the offset 'elements + 1' to the array of segment offsets to make sure that
|
|
// there is at least one offset greater than 'elements'.
|
|
thrust::fill_n(policy, segment_offsets.data() + elements, 1, elements + 1);
|
|
|
|
// Perform an exclusive prefix sum scan with first value 0, so what we compute is
|
|
// scan[i + 1] = \sum_{i=0}^{i} segment_offsets[i] for i \in [0, elements+1]
|
|
// and scan[0] = 0.
|
|
thrust::exclusive_scan(
|
|
policy,
|
|
segment_offsets.data(),
|
|
segment_offsets.data() + segment_offsets.size(),
|
|
segment_offsets.data() /*, thrust::plus<>{}*/);
|
|
|
|
// Find first sum of offsets greater than 'elements', we are sure that there is
|
|
// going to be one because we added elements + 1 at the end of the segment_offsets.
|
|
auto iter = thrust::find_if(
|
|
policy, segment_offsets.data(), segment_offsets.data() + segment_offsets.size(), geq_t<T>{elements});
|
|
|
|
// Compute the element's index.
|
|
auto dist = thrust::distance(segment_offsets.data(), iter);
|
|
// Fill next item with 'elements'.
|
|
thrust::fill_n(policy, segment_offsets.data() + dist, 1, elements);
|
|
// Return next item's index.
|
|
return dist + 1;
|
|
}
|
|
|
|
template <class T>
|
|
struct constant_op
|
|
{
|
|
std::size_t val;
|
|
|
|
__device__ __forceinline__ T operator()(const T& /*key*/) const
|
|
{
|
|
return static_cast<T>(val);
|
|
}
|
|
};
|
|
|
|
template <class T>
|
|
struct idx_to_op
|
|
{
|
|
T* keys = nullptr;
|
|
std::size_t* segment_offsets = nullptr;
|
|
|
|
__device__ __forceinline__ std::size_t operator()(std::size_t i)
|
|
{
|
|
const std::size_t init_offset = segment_offsets[i];
|
|
const std::size_t end_offset = segment_offsets[i + 1];
|
|
thrust::transform(thrust::device, keys + init_offset, keys + end_offset, keys + init_offset, constant_op<T>{i});
|
|
return i;
|
|
}
|
|
};
|
|
|
|
// Temporal approach for generation of key segments.
|
|
template <typename T>
|
|
void gen_key_segments(thrust::device_vector<T>& keys, thrust::device_vector<size_t>& segment_offsets)
|
|
{
|
|
const std::size_t total_segments = segment_offsets.size() - 1;
|
|
|
|
thrust::counting_iterator<int> iota(0);
|
|
thrust::device_vector<std::size_t> segment_indices(iota, iota + total_segments);
|
|
|
|
idx_to_op<T> op{thrust::raw_pointer_cast(keys.data()), thrust::raw_pointer_cast(segment_offsets.data())};
|
|
|
|
thrust::transform(segment_indices.begin(), segment_indices.end(), segment_indices.begin(), op);
|
|
}
|
|
|
|
// TODO: use this approach for gen_key_segments when rocPRIM allows it.
|
|
// template <class T>
|
|
// struct repeat_index_t
|
|
// {
|
|
// __host__ __device__ __forceinline__ thrust::constant_iterator<T> operator()(std::size_t i)
|
|
// {
|
|
// return thrust::constant_iterator<T>(static_cast<T>(i));
|
|
// }
|
|
// };
|
|
|
|
// template <typename T>
|
|
// struct offset_to_iterator_t
|
|
// {
|
|
// T* base_it;
|
|
|
|
// __host__ __device__ __forceinline__ T* operator()(std::size_t offset) const
|
|
// {
|
|
// return base_it + offset;
|
|
// }
|
|
// };
|
|
|
|
// struct offset_to_size_t
|
|
// {
|
|
// std::size_t* offsets = nullptr;
|
|
|
|
// __host__ __device__ __forceinline__ std::size_t operator()(std::size_t i)
|
|
// {
|
|
// return offsets[i + 1] - offsets[i];
|
|
// }
|
|
// };
|
|
//
|
|
// template <typename T>
|
|
// void gen_key_segments(thrust::device_vector<T>& keys,
|
|
// thrust::device_vector<std::size_t>& segment_offsets)
|
|
// {
|
|
|
|
// const std::size_t total_segments = segment_offsets.size() - 1;
|
|
|
|
// thrust::counting_iterator<int> iota(0);
|
|
// repeat_index_t<T> src_transform_op {};
|
|
// offset_to_iterator_t<T> dst_transform_op {thrust::raw_pointer_cast(keys.data())};
|
|
// offset_to_size_t size_transform_op {thrust::raw_pointer_cast(segment_offsets.data())};
|
|
|
|
// auto d_range_srcs = thrust::make_transform_iterator(iota, src_transform_op);
|
|
// auto d_range_dsts
|
|
// = thrust::make_transform_iterator(segment_offsets.begin(), dst_transform_op);
|
|
// auto d_range_sizes = thrust::make_transform_iterator(iota, size_transform_op);
|
|
|
|
// std::uint8_t* d_temp_storage = nullptr;
|
|
// std::size_t temp_storage_bytes = 0;
|
|
|
|
// rocprim::batch_copy(d_temp_storage,
|
|
// temp_storage_bytes,
|
|
// d_range_srcs,
|
|
// d_range_dsts,
|
|
// d_range_sizes,
|
|
// total_segments);
|
|
|
|
// thrust::device_vector<std::uint8_t> temp_storage(temp_storage_bytes);
|
|
// d_temp_storage = thrust::raw_pointer_cast(temp_storage.data());
|
|
|
|
// rocprim::batch_copy(d_temp_storage,
|
|
// temp_storage_bytes,
|
|
// d_range_srcs,
|
|
// d_range_dsts,
|
|
// d_range_sizes,
|
|
// total_segments);
|
|
// hipDeviceSynchronize();
|
|
// }
|
|
|
|
struct device_uniform_key_segments_generator_t
|
|
{
|
|
const std::size_t elements{0};
|
|
const std::string seed_type{"random"};
|
|
const std::size_t min_segment_size{0};
|
|
const std::size_t max_segment_size{0};
|
|
|
|
device_uniform_key_segments_generator_t(
|
|
std::size_t m_elements,
|
|
const std::string m_seed_type,
|
|
const std::size_t m_min_segment_size,
|
|
const std::size_t m_max_segment_size)
|
|
: elements(m_elements)
|
|
, seed_type(m_seed_type)
|
|
, min_segment_size(m_min_segment_size)
|
|
, max_segment_size(m_max_segment_size)
|
|
{}
|
|
|
|
template <class KeyT>
|
|
operator thrust::device_vector<KeyT>()
|
|
{
|
|
thrust::device_vector<KeyT> keys(elements);
|
|
|
|
thrust::device_vector<std::size_t> segment_offsets(keys.size() + 2);
|
|
const std::size_t offsets_size =
|
|
gen_uniform_offsets(seed_type, segment_offsets, min_segment_size, max_segment_size);
|
|
segment_offsets.resize(offsets_size);
|
|
|
|
gen_key_segments(keys, segment_offsets);
|
|
|
|
return keys;
|
|
}
|
|
};
|
|
|
|
struct gen_uniform_key_segments_t
|
|
{
|
|
device_uniform_key_segments_generator_t operator()(
|
|
const std::size_t elements,
|
|
const std::string seed_type,
|
|
const std::size_t min_segment_size,
|
|
const std::size_t max_segment_size) const
|
|
{
|
|
return {elements, seed_type, min_segment_size, max_segment_size};
|
|
}
|
|
};
|
|
|
|
struct gen_uniform_t
|
|
{
|
|
gen_uniform_key_segments_t key_segments{};
|
|
};
|
|
|
|
struct gen_t
|
|
{
|
|
template <class T>
|
|
device_vector_generator_t<T> operator()(
|
|
std::size_t elements,
|
|
const std::string seed_type,
|
|
const int entropy = 0 /*100*/,
|
|
T min = std::numeric_limits<T>::min,
|
|
T max = std::numeric_limits<T>::max()) const
|
|
{
|
|
return {elements, seed_type, entropy, min, max};
|
|
}
|
|
|
|
device_vector_generator_t<void>
|
|
operator()(std::size_t elements, const std::string seed_type, const int entropy = 0 /*100*/) const
|
|
{
|
|
return {elements, seed_type, entropy};
|
|
}
|
|
|
|
gen_uniform_t uniform{};
|
|
};
|
|
} // namespace detail
|
|
|
|
detail::gen_t generate;
|
|
|
|
} // namespace bench_utils
|
|
#endif // ROCTHRUST_BENCHMARKS_BENCH_UTILS_GENERATION_UTILS_HPP_
|