Files
derek.holloway 7502bf64a4
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
Flatten subprojects into a single base monorepo
2026-09-02 16:34:47 -07:00

735 lines
22 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_BENCH_UTILS_HPP_
#define ROCTHRUST_BENCHMARKS_BENCH_UTILS_BENCH_UTILS_HPP_
// Utils
#include <thrust/execution_policy.h>
#include "cmdparser.hpp"
#include "common/types.hpp"
#include "custom_reporter.hpp"
#include "generation_utils.hpp"
// HIP/CUDA
#if THRUST_DEVICE_SYSTEM == THRUST_DEVICE_SYSTEM_HIP
# include <hip/hip_runtime.h>
#elif THRUST_DEVICE_SYSTEM == THRUST_DEVICE_SYSTEM_CUDA
# include <cuda_runtime.h>
#endif
// Google Benchmark
#include <benchmark/benchmark.h>
// STL
#include <algorithm>
#include <array>
#include <chrono>
#include <cmath>
#include <cstddef>
#include <cstdint>
#include <iostream>
#include <numeric>
#include <random>
#include <regex>
#include <sstream>
#include <string>
namespace bench_utils
{
#if (THRUST_DEVICE_COMPILER == THRUST_DEVICE_COMPILER_HIP)
# define HIP_CHECK(condition) \
{ \
hipError_t error = condition; \
if (error != hipSuccess) \
{ \
std::cout << "HIP error: " << error << " line: " << __LINE__ << std::endl; \
exit(error); \
} \
}
/// \brief Timer for measuring time from the device's side
class gpu_timer
{
hipEvent_t m_start;
hipEvent_t m_stop;
public:
__forceinline__ gpu_timer()
{
HIP_CHECK(hipEventCreate(&m_start));
HIP_CHECK(hipEventCreate(&m_stop));
}
__forceinline__ ~gpu_timer()
{
HIP_CHECK(hipEventDestroy(m_start));
HIP_CHECK(hipEventDestroy(m_stop));
}
// move-only
gpu_timer(const gpu_timer&) = delete;
gpu_timer(gpu_timer&&) = default;
gpu_timer& operator=(const gpu_timer&) = delete;
gpu_timer& operator=(gpu_timer&&) = default;
__forceinline__ void start(hipStream_t stream)
{
HIP_CHECK(hipEventRecord(m_start, stream));
}
__forceinline__ void stop(hipStream_t stream)
{
HIP_CHECK(hipEventRecord(m_stop, stream));
}
[[nodiscard]] __forceinline__ bool ready() const
{
const hipError_t state = hipEventQuery(m_stop);
if (state == hipErrorNotReady)
{
return false;
}
HIP_CHECK(state);
return true;
}
// In seconds:
[[nodiscard]] __forceinline__ float64_t get_duration() const
{
HIP_CHECK(hipEventSynchronize(m_stop));
float32_t elapsed_time;
// According to docs, this is in ms with a resolution of ~1 microseconds.
HIP_CHECK(hipEventElapsedTime(&elapsed_time, m_start, m_stop));
return elapsed_time / 1000.0;
}
};
#elif (defined(__NVCC__) || defined(_NVHPC_CUDA) \
|| (defined(__CUDA__) && THRUST_HOST_COMPILER == THRUST_HOST_COMPILER_CLANG) \
|| THRUST_HOST_COMPILER == THRUST_HOST_COMPILER_NVRTC)
# define CUDA_SAFE_CALL_NO_SYNC(call) \
do \
{ \
cudaError err = call; \
if (cudaSuccess != err) \
{ \
fprintf(stderr, "CUDA error in file '%s' in line %i : %s.\n", __FILE__, __LINE__, cudaGetErrorString(err)); \
exit(EXIT_FAILURE); \
} \
} while (0)
# define CUDA_SAFE_CALL(call) \
do \
{ \
CUDA_SAFE_CALL_NO_SYNC(call); \
cudaError err = cudaDeviceSynchronize(); \
if (cudaSuccess != err) \
{ \
fprintf(stderr, "CUDA error in file '%s' in line %i : %s.\n", __FILE__, __LINE__, cudaGetErrorString(err)); \
exit(EXIT_FAILURE); \
} \
} while (0)
class gpu_timer
{
cudaEvent_t start_;
cudaEvent_t stop_;
public:
__forceinline__ gpu_timer()
{
CUDA_SAFE_CALL(cudaEventCreate(&start_));
CUDA_SAFE_CALL(cudaEventCreate(&stop_));
}
__forceinline__ ~gpu_timer()
{
CUDA_SAFE_CALL(cudaEventDestroy(start_));
CUDA_SAFE_CALL(cudaEventDestroy(stop_));
}
// move-only
gpu_timer(const gpu_timer&) = delete;
gpu_timer(gpu_timer&&) = default;
gpu_timer& operator=(const gpu_timer&) = delete;
gpu_timer& operator=(gpu_timer&&) = default;
__forceinline__ void start(cudaStream_t stream)
{
CUDA_SAFE_CALL(cudaEventRecord(start_, stream));
}
__forceinline__ void stop(cudaStream_t stream)
{
CUDA_SAFE_CALL(cudaEventRecord(m_stop, stream));
}
[[nodiscard]] __forceinline__ bool ready() const
{
const cudaError_t state = cudaEventQuery(m_stop);
if (state == cudaErrorNotReady)
{
return false;
}
CUDA_SAFE_CALL(state);
return true;
}
// In seconds:
[[nodiscard]] __forceinline__ nvbench::float64_t get_duration() const
{
CUDA_SAFE_CALL(cudaEventSynchronize(m_stop));
float elapsed_time;
// According to docs, this is in ms with a resolution of ~0.5 microseconds.
CUDA_SAFE_CALL(cudaEventElapsedTime(&elapsed_time, m_start, m_stop));
return elapsed_time / 1000.0;
}
};
#endif
//// \brief Gets the peak global memory bus bandwidth in bytes/sec.
std::size_t get_global_memory_bus_bandwidth(int device_id)
{
hipDeviceProp_t props;
HIP_CHECK(hipGetDeviceProperties(&props, device_id));
// Get the peak clock rate of the global memory bus in Hz.
const std::size_t global_memory_bus_peak_clock_rate = static_cast<std::size_t>(props.memoryClockRate) * 1000; /*kHz ->
Hz*/
// Get width of the global memory bus in bits.
const int get_global_memory_bus_width = props.memoryBusWidth;
// Multiply by 2 because of DDR,
// CHAR_BIT to convert bus_width to bytes.
return 2 * global_memory_bus_peak_clock_rate * static_cast<std::size_t>(get_global_memory_bus_width / CHAR_BIT);
}
/// \brief Adds device info and properties to the Google benchmark info
inline void add_common_benchmark_info()
{
hipDeviceProp_t devProp;
int device_id = 0;
HIP_CHECK(hipGetDevice(&device_id));
HIP_CHECK(hipGetDeviceProperties(&devProp, device_id));
auto str = [](const std::string& name, const std::string& val) {
benchmark::AddCustomContext(name, val);
};
auto num = [](const std::string& name, const auto& value) {
benchmark::AddCustomContext(name, std::to_string(value));
};
auto dim2 = [num](const std::string& name, const auto* values) {
num(name + "_x", values[0]);
num(name + "_y", values[1]);
};
auto dim3 = [num, dim2](const std::string& name, const auto* values) {
dim2(name, values);
num(name + "_z", values[2]);
};
str("hdp_name", devProp.name);
num("hdp_total_global_mem", devProp.totalGlobalMem);
num("hdp_shared_mem_per_block", devProp.sharedMemPerBlock);
num("hdp_regs_per_block", devProp.regsPerBlock);
num("hdp_warp_size", devProp.warpSize);
num("hdp_max_threads_per_block", devProp.maxThreadsPerBlock);
dim3("hdp_max_threads_dim", devProp.maxThreadsDim);
dim3("hdp_max_grid_size", devProp.maxGridSize);
num("hdp_clock_rate", devProp.clockRate);
num("hdp_memory_clock_rate", devProp.memoryClockRate);
num("hdp_memory_bus_width", devProp.memoryBusWidth);
num("hdp_peak_global_mem_bus_bandwidth", get_global_memory_bus_bandwidth(device_id));
num("hdp_total_const_mem", devProp.totalConstMem);
num("hdp_major", devProp.major);
num("hdp_minor", devProp.minor);
num("hdp_multi_processor_count", devProp.multiProcessorCount);
num("hdp_l2_cache_size", devProp.l2CacheSize);
num("hdp_max_threads_per_multiprocessor", devProp.maxThreadsPerMultiProcessor);
num("hdp_compute_mode", devProp.computeMode);
num("hdp_clock_instruction_rate", devProp.clockInstructionRate);
num("hdp_concurrent_kernels", devProp.concurrentKernels);
num("hdp_pci_domain_id", devProp.pciDomainID);
num("hdp_pci_bus_id", devProp.pciBusID);
num("hdp_pci_device_id", devProp.pciDeviceID);
num("hdp_max_shared_memory_per_multi_processor", devProp.maxSharedMemoryPerMultiProcessor);
num("hdp_is_multi_gpu_board", devProp.isMultiGpuBoard);
num("hdp_can_map_host_memory", devProp.canMapHostMemory);
str("hdp_gcn_arch_name", devProp.gcnArchName);
num("hdp_integrated", devProp.integrated);
num("hdp_cooperative_launch", devProp.cooperativeLaunch);
num("hdp_cooperative_multi_device_launch", devProp.cooperativeMultiDeviceLaunch);
num("hdp_max_texture_1d_linear", devProp.maxTexture1DLinear);
num("hdp_max_texture_1d", devProp.maxTexture1D);
dim2("hdp_max_texture_2d", devProp.maxTexture2D);
dim3("hdp_max_texture_3d", devProp.maxTexture3D);
num("hdp_mem_pitch", devProp.memPitch);
num("hdp_texture_alignment", devProp.textureAlignment);
num("hdp_texture_pitch_alignment", devProp.texturePitchAlignment);
num("hdp_kernel_exec_timeout_enabled", devProp.kernelExecTimeoutEnabled);
num("hdp_ecc_enabled", devProp.ECCEnabled);
num("hdp_tcc_driver", devProp.tccDriver);
num("hdp_cooperative_multi_device_unmatched_func", devProp.cooperativeMultiDeviceUnmatchedFunc);
num("hdp_cooperative_multi_device_unmatched_grid_dim", devProp.cooperativeMultiDeviceUnmatchedGridDim);
num("hdp_cooperative_multi_device_unmatched_block_dim", devProp.cooperativeMultiDeviceUnmatchedBlockDim);
num("hdp_cooperative_multi_device_unmatched_shared_mem", devProp.cooperativeMultiDeviceUnmatchedSharedMem);
num("hdp_is_large_bar", devProp.isLargeBar);
num("hdp_asic_revision", devProp.asicRevision);
num("hdp_managed_memory", devProp.managedMemory);
num("hdp_direct_managed_mem_access_from_host", devProp.directManagedMemAccessFromHost);
num("hdp_concurrent_managed_access", devProp.concurrentManagedAccess);
num("hdp_pageable_memory_access", devProp.pageableMemoryAccess);
num("hdp_pageable_memory_access_uses_host_page_tables", devProp.pageableMemoryAccessUsesHostPageTables);
const auto arch = devProp.arch;
num("hdp_arch_has_global_int32_atomics", arch.hasGlobalInt32Atomics);
num("hdp_arch_has_global_float_atomic_exch", arch.hasGlobalFloatAtomicExch);
num("hdp_arch_has_shared_int32_atomics", arch.hasSharedInt32Atomics);
num("hdp_arch_has_shared_float_atomic_exch", arch.hasSharedFloatAtomicExch);
num("hdp_arch_has_float_atomic_add", arch.hasFloatAtomicAdd);
num("hdp_arch_has_global_int64_atomics", arch.hasGlobalInt64Atomics);
num("hdp_arch_has_shared_int64_atomics", arch.hasSharedInt64Atomics);
num("hdp_arch_has_doubles", arch.hasDoubles);
num("hdp_arch_has_warp_vote", arch.hasWarpVote);
num("hdp_arch_has_warp_ballot", arch.hasWarpBallot);
num("hdp_arch_has_warp_shuffle", arch.hasWarpShuffle);
num("hdp_arch_has_funnel_shift", arch.hasFunnelShift);
num("hdp_arch_has_thread_fence_system", arch.hasThreadFenceSystem);
num("hdp_arch_has_sync_threads_ext", arch.hasSyncThreadsExt);
num("hdp_arch_has_surface_funcs", arch.hasSurfaceFuncs);
num("hdp_arch_has_3d_grid", arch.has3dGrid);
num("hdp_arch_has_dynamic_parallelism", arch.hasDynamicParallelism);
}
// Binary operators
struct less_t
{
template <typename T>
__host__ __device__ bool operator()(const T& lhs, const T& rhs) const
{
return lhs < rhs;
}
};
struct max_t
{
template <typename T>
__host__ __device__ T operator()(const T& lhs, const T& rhs)
{
less_t less{};
return less(lhs, rhs) ? rhs : lhs;
}
};
struct bench_naming
{
public:
enum format
{
json,
human,
txt
};
static format& get_format()
{
static format storage = human;
return storage;
}
static void set_format(const std::string& argument)
{
format result = human;
if (argument == "json")
{
result = json;
}
else if (argument == "txt")
{
result = txt;
}
get_format() = result;
}
private:
static std::string matches_as_json(std::sregex_iterator& matches)
{
std::stringstream result;
int brackets_count = 1;
result << "{";
bool insert_comma = false;
for (std::sregex_iterator i = matches; i != std::sregex_iterator(); ++i)
{
std::smatch m = *i;
if (insert_comma)
{
result << ",";
}
else
{
insert_comma = true;
}
result << "\"" << m[1].str() << "\":";
if (m[2].length() > 0)
{
if (m[2].str().find_first_not_of("0123456789") == std::string::npos)
{
result << m[2].str();
}
else
{
result << "\"" << m[2].str() << "\"";
}
if (m[3].length() > 0 && brackets_count > 0)
{
int n = std::min(brackets_count, static_cast<int>(m[3].length()));
brackets_count -= n;
for (int c = 0; c < n; c++)
{
result << "}";
}
}
}
else
{
brackets_count++;
result << "{";
insert_comma = false;
}
}
while (brackets_count > 0)
{
brackets_count--;
result << "}";
}
return result.str();
}
static std::string matches_as_human(std::sregex_iterator& matches)
{
std::stringstream result;
int brackets_count = 0;
bool insert_comma = false;
for (std::sregex_iterator i = matches; i != std::sregex_iterator(); ++i)
{
std::smatch m = *i;
if (insert_comma)
{
result << ",";
}
else
{
insert_comma = true;
}
if (m[2].length() > 0)
{
result << m[2].str();
if (m[3].length() > 0 && brackets_count > 0)
{
int n = std::min(brackets_count, static_cast<int>(m[3].length()));
brackets_count -= n;
for (int c = 0; c < n; c++)
{
result << ">";
}
}
}
else
{
brackets_count++;
result << "<";
insert_comma = false;
}
}
while (brackets_count > 0)
{
brackets_count--;
result << ">";
}
return result.str();
}
public:
static std::string format_name(std::string string)
{
format format = get_format();
std::regex r("([A-z0-9_]*):([A-z_:\\(\\)\\.<>\\s0-9\" ]*)");
// First we perform some checks
bool checks[5] = {false};
for (std::sregex_iterator i = std::sregex_iterator(string.begin(), string.end(), r); i != std::sregex_iterator();
++i)
{
std::smatch m = *i;
if (m[1].str() == "algo")
{
checks[0] = true;
}
else if (m[1].str() == "subalgo")
{
checks[1] = true;
}
else if (m[1].str() == "input_type" || m[1].str() == "key_type" || m[1].str() == "value_type")
{
checks[2] = true;
}
else if (m[1].str() == "elements")
{
checks[3] = true;
}
}
std::string string_substitute = std::regex_replace(string, r, "");
checks[4] = string_substitute.find_first_not_of(" ,{}") == std::string::npos;
for (bool check_name_format : checks)
{
if (!check_name_format)
{
std::cout << "string_substitute = " << string_substitute << std::endl;
std::cout
<< "Benchmark name \"" << string
<< "\" not in the correct format (e.g. "
"{algo:reduce,subalgo:by_key} )"
<< std::endl;
exit(1);
}
}
// Now we generate the desired format
std::sregex_iterator matches = std::sregex_iterator(string.begin(), string.end(), r);
switch (format)
{
case format::json:
return matches_as_json(matches);
case format::human:
return matches_as_human(matches);
case format::txt:
return string;
}
return string;
}
};
namespace detail
{
void do_not_optimize(const void* ptr)
{
(void) ptr;
}
} // namespace detail
template <class T>
void do_not_optimize(const T& val)
{
detail::do_not_optimize(&val);
}
auto StatisticsSum = [](const std::vector<double>& v) {
return std::accumulate(v.begin(), v.end(), 0.0);
};
double StatisticsMean(const std::vector<double>& v)
{
if (v.empty())
{
return 0.0;
}
return StatisticsSum(v) * (1.0 / static_cast<double>(v.size()));
}
double StatisticsMedian(const std::vector<double>& v)
{
if (v.size() < 3)
{
return StatisticsMean(v);
}
std::vector<double> copy(v);
auto center = copy.begin() + v.size() / 2;
std::nth_element(copy.begin(), center, copy.end());
// Did we have an odd number of samples? If yes, then center is the median.
// If not, then we are looking for the average between center and the value
// before. Instead of resorting, we just look for the max value before it,
// which is not necessarily the element immediately preceding `center` Since
// `copy` is only partially sorted by `nth_element`.
if (v.size() % 2 == 1)
{
return *center;
}
auto center2 = std::max_element(copy.begin(), center);
return (*center + *center2) / 2.0;
}
// Return the sum of the squares of this sample set
auto SumSquares = [](const std::vector<double>& v) {
return std::inner_product(v.begin(), v.end(), v.begin(), 0.0);
};
auto Sqr = [](const double dat) {
return dat * dat;
};
auto Sqrt = [](const double dat) {
// Avoid NaN due to imprecision in the calculations
if (dat < 0.0)
{
return 0.0;
}
return std::sqrt(dat);
};
double StatisticsStdDev(const std::vector<double>& v)
{
const auto mean = StatisticsMean(v);
if (v.empty())
{
return mean;
}
// Sample standard deviation is undefined for n = 1
if (v.size() == 1)
{
return 0.0;
}
const double avg_squares = SumSquares(v) * (1.0 / static_cast<double>(v.size()));
return Sqrt(static_cast<double>(v.size()) / (static_cast<double>(v.size()) - 1.0) * (avg_squares - Sqr(mean)));
}
double StatisticsCV(const std::vector<double>& v)
{
if (v.size() < 2)
{
return 0.0;
}
const auto stddev = StatisticsStdDev(v);
const auto mean = StatisticsMean(v);
if (std::fpclassify(mean) == FP_ZERO)
{
return 0.0;
}
return stddev / mean;
}
inline const char* get_seed_message()
{
return "seed for input generation, either an unsigned integer value for determinisic results "
"or 'random' for different inputs for each repetition";
}
struct caching_allocator_t
{
using value_type = char;
caching_allocator_t() = default;
~caching_allocator_t()
{
free_all();
}
char* allocate(std::ptrdiff_t num_bytes)
{
value_type* result{};
auto free_block = free_blocks.find(num_bytes);
if (free_block != free_blocks.end())
{
result = free_block->second;
free_blocks.erase(free_block);
}
else
{
HIP_CHECK(hipMalloc(&result, num_bytes));
}
allocated_blocks.emplace(result, num_bytes);
return result;
}
void deallocate(value_type* ptr, size_t)
{
auto iter = allocated_blocks.find(ptr);
if (iter == allocated_blocks.end())
{
throw std::runtime_error("Memory was not allocated by this allocator");
}
std::ptrdiff_t num_bytes = iter->second;
allocated_blocks.erase(iter);
free_blocks.emplace(num_bytes, ptr);
}
private:
using FreeBlocksType = std::multimap<std::ptrdiff_t, value_type*>;
using AllocatedBlocksType = std::map<value_type*, std::ptrdiff_t>;
FreeBlocksType free_blocks;
AllocatedBlocksType allocated_blocks;
void free_all()
{
for (auto free_block : free_blocks)
{
HIP_CHECK(hipFree(free_block.second));
}
for (auto allocated_block : allocated_blocks)
{
HIP_CHECK(hipFree(allocated_block.first));
}
}
};
inline std::string format_pow2(size_t n)
{
unsigned int k = 0;
while (!(n & 1))
{
k++;
n >>= 1;
}
return "1 << " + std::to_string(k);
}
struct sys_info
{
hipDeviceProp_t devProp;
sys_info()
{
int device_id = 0;
HIP_CHECK(hipGetDevice(&device_id));
HIP_CHECK(hipGetDeviceProperties(&devProp, device_id));
}
};
inline sys_info system;
inline constexpr size_t sizes[] = {1u << 16, 1u << 20, 1u << 24, 1u << 28};
} // namespace bench_utils
#endif // ROCTHRUST_BENCHMARKS_BENCH_UTILS_BENCH_UTILS_HPP_