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
191 lines
6.2 KiB
C++
191 lines
6.2 KiB
C++
//===-- Pseudo-random number generation utilities ---------------*- C++ -*-===//
|
|
//
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#ifndef LLVM_LIBC_BENCHMARKS_GPU_RANDOM_H
|
|
#define LLVM_LIBC_BENCHMARKS_GPU_RANDOM_H
|
|
|
|
#include "hdr/stdint_proxy.h"
|
|
#include "src/__support/CPP/algorithm.h"
|
|
#include "src/__support/CPP/optional.h"
|
|
#include "src/__support/CPP/type_traits.h"
|
|
#include "src/__support/FPUtil/FPBits.h"
|
|
#include "src/__support/macros/attributes.h"
|
|
#include "src/__support/macros/config.h"
|
|
#include "src/__support/macros/properties/types.h"
|
|
#include "src/__support/sign.h"
|
|
|
|
namespace LIBC_NAMESPACE_DECL {
|
|
namespace benchmarks {
|
|
|
|
// Pseudo-random number generator (PRNG) that produces unsigned 64-bit, 32-bit,
|
|
// and 16-bit integers. The implementation is based on the xorshift* generator,
|
|
// seeded using SplitMix64 for robust initialization. For more details, see:
|
|
// https://en.wikipedia.org/wiki/Xorshift
|
|
class RandomGenerator {
|
|
uint64_t state;
|
|
|
|
static LIBC_INLINE uint64_t splitmix64(uint64_t x) noexcept {
|
|
x += 0x9E3779B97F4A7C15ULL;
|
|
x = (x ^ (x >> 30)) * 0xBF58476D1CE4E5B9ULL;
|
|
x = (x ^ (x >> 27)) * 0x94D049BB133111EBULL;
|
|
x = (x ^ (x >> 31));
|
|
return x ? x : 0x9E3779B97F4A7C15ULL;
|
|
}
|
|
|
|
public:
|
|
explicit LIBC_INLINE RandomGenerator(uint64_t seed) noexcept
|
|
: state(splitmix64(seed)) {}
|
|
|
|
LIBC_INLINE uint64_t next64() noexcept {
|
|
uint64_t x = state;
|
|
x ^= x >> 12;
|
|
x ^= x << 25;
|
|
x ^= x >> 27;
|
|
state = x;
|
|
return x * 0x2545F4914F6CDD1DULL;
|
|
}
|
|
|
|
LIBC_INLINE uint32_t next32() noexcept {
|
|
return static_cast<uint32_t>(next64() >> 32);
|
|
}
|
|
|
|
LIBC_INLINE uint16_t next16() noexcept {
|
|
return static_cast<uint16_t>(next64() >> 48);
|
|
}
|
|
};
|
|
|
|
// Generates random floating-point numbers where the unbiased binary exponent
|
|
// is sampled uniformly in `[min_exp, max_exp]`. The significand bits are
|
|
// always randomized, while the sign is randomized by default but can be fixed.
|
|
// Evenly covers orders of magnitude; never yields Inf/NaN.
|
|
template <typename T> class UniformExponent {
|
|
static_assert(cpp::is_same_v<T, float16> || cpp::is_same_v<T, float> ||
|
|
cpp::is_same_v<T, double>,
|
|
"UniformExponent supports float16, float, and double");
|
|
|
|
using FPBits = LIBC_NAMESPACE::fputil::FPBits<T>;
|
|
using Storage = typename FPBits::StorageType;
|
|
|
|
public:
|
|
explicit UniformExponent(int min_exp = -FPBits::EXP_BIAS,
|
|
int max_exp = FPBits::EXP_BIAS,
|
|
cpp::optional<Sign> forced_sign = cpp::nullopt)
|
|
: min_exp(clamp_exponent(cpp::min(min_exp, max_exp))),
|
|
max_exp(clamp_exponent(cpp::max(min_exp, max_exp))),
|
|
forced_sign(forced_sign) {}
|
|
|
|
LIBC_INLINE T operator()(RandomGenerator &rng) const noexcept {
|
|
// Sample unbiased exponent e uniformly in [min_exp, max_exp] without modulo
|
|
// bias, using rejection sampling
|
|
auto sample_in_range = [&](uint64_t r) -> int32_t {
|
|
const uint64_t range = static_cast<uint64_t>(
|
|
static_cast<int64_t>(max_exp) - static_cast<int64_t>(min_exp) + 1);
|
|
const uint64_t threshold = (-range) % range;
|
|
while (r < threshold)
|
|
r = rng.next64();
|
|
return static_cast<int32_t>(min_exp + static_cast<int64_t>(r % range));
|
|
};
|
|
const int32_t e = sample_in_range(rng.next64());
|
|
|
|
// Start from random bits to get random sign and mantissa
|
|
FPBits xbits([&] {
|
|
if constexpr (cpp::is_same_v<T, double>)
|
|
return FPBits(rng.next64());
|
|
else if constexpr (cpp::is_same_v<T, float>)
|
|
return FPBits(rng.next32());
|
|
else
|
|
return FPBits(rng.next16());
|
|
}());
|
|
|
|
if (e == -FPBits::EXP_BIAS) {
|
|
// Subnormal: biased exponent must be 0; ensure mantissa != 0 to avoid 0
|
|
xbits.set_biased_exponent(Storage(0));
|
|
if (xbits.get_mantissa() == Storage(0))
|
|
xbits.set_mantissa(Storage(1));
|
|
} else {
|
|
// Normal: biased exponent in [1, 2 * FPBits::EXP_BIAS]
|
|
const int32_t biased = e + FPBits::EXP_BIAS;
|
|
xbits.set_biased_exponent(static_cast<Storage>(biased));
|
|
}
|
|
|
|
if (forced_sign)
|
|
xbits.set_sign(*forced_sign);
|
|
|
|
return xbits.get_val();
|
|
}
|
|
|
|
private:
|
|
static LIBC_INLINE int clamp_exponent(int val) noexcept {
|
|
if (val < -FPBits::EXP_BIAS)
|
|
return -FPBits::EXP_BIAS;
|
|
|
|
if (val > FPBits::EXP_BIAS)
|
|
return FPBits::EXP_BIAS;
|
|
|
|
return val;
|
|
}
|
|
|
|
const int min_exp;
|
|
const int max_exp;
|
|
const cpp::optional<Sign> forced_sign;
|
|
};
|
|
|
|
// Generates random floating-point numbers that are uniformly distributed on
|
|
// a linear scale. Values are sampled from `[min_val, max_val)`.
|
|
template <typename T> class UniformLinear {
|
|
static_assert(cpp::is_same_v<T, float16> || cpp::is_same_v<T, float> ||
|
|
cpp::is_same_v<T, double>,
|
|
"UniformLinear supports float16, float, and double");
|
|
|
|
using FPBits = LIBC_NAMESPACE::fputil::FPBits<T>;
|
|
using Storage = typename FPBits::StorageType;
|
|
|
|
static constexpr T MAX_NORMAL = FPBits::max_normal().get_val();
|
|
|
|
public:
|
|
explicit UniformLinear(T min_val = -MAX_NORMAL, T max_val = MAX_NORMAL)
|
|
: min_val(clamp_val(cpp::min(min_val, max_val))),
|
|
max_val(clamp_val(cpp::max(min_val, max_val))) {}
|
|
|
|
LIBC_INLINE T operator()(RandomGenerator &rng) const noexcept {
|
|
double u = standard_uniform(rng.next64());
|
|
double a = static_cast<double>(min_val);
|
|
double b = static_cast<double>(max_val);
|
|
double y = a + (b - a) * u;
|
|
return static_cast<T>(y);
|
|
}
|
|
|
|
private:
|
|
static LIBC_INLINE T clamp_val(T val) noexcept {
|
|
if (val < -MAX_NORMAL)
|
|
return -MAX_NORMAL;
|
|
|
|
if (val > MAX_NORMAL)
|
|
return MAX_NORMAL;
|
|
|
|
return val;
|
|
}
|
|
|
|
static LIBC_INLINE double standard_uniform(uint64_t x) noexcept {
|
|
constexpr int PREC_BITS =
|
|
LIBC_NAMESPACE::fputil::FPBits<double>::SIG_LEN + 1;
|
|
constexpr int SHIFT_BITS = LIBC_NAMESPACE::fputil::FPBits<double>::EXP_LEN;
|
|
constexpr double INV = 1.0 / static_cast<double>(1ULL << PREC_BITS);
|
|
|
|
return static_cast<double>(x >> SHIFT_BITS) * INV;
|
|
}
|
|
|
|
const T min_val;
|
|
const T max_val;
|
|
};
|
|
|
|
} // namespace benchmarks
|
|
} // namespace LIBC_NAMESPACE_DECL
|
|
|
|
#endif
|