* Copyright (C) 2013-2021 Canonical, Ltd.
* Copyright (C) 2022-2025 Colin Ian King.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#include "stress-ng.h"
#include "core-arch.h"
#include "core-attribute.h"
#include "core-bitops.h"
#include "core-builtin.h"
#include "core-cpu.h"
#include "core-pragma.h"
#include "core-put.h"
#include "core-target-clones.h"
#include <math.h>
#include <sched.h>
#include <time.h>
#if defined(HAVE_SYS_SELECT_H)
#include <sys/select.h>
#endif
#if defined(HAVE_COMPLEX_H)
#include <complex.h>
#endif
* S390x on QEMU (and maybe H/W) trips SIGILL for decimal
* math with some compilers, so disable this for now
*/
#if defined(STRESS_ARCH_S390)
#undef HAVE_Decimal32
#undef HAVE_Decimal64
#undef HAVE_Decimal128
#endif
#define GAMMA (0.57721566490153286060651209008240243104215933593992L)
#define OMEGA (0.56714329040978387299996866221035554975381578718651L)
#define PSI (3.35988566624317755317201130291892717968890513373197L)
#define PI (3.14159265358979323846264338327950288419716939937511L)
#define STATS_MAX (250)
#define FFT_SIZE (4096)
#define STRESS_CPU_DITHER_X (1024)
#define STRESS_CPU_DITHER_Y (768)
#define MATRIX_PROD_SIZE (128)
#define CORRELATE_DATA_LEN (8192)
#define CORRELATE_LEN (CORRELATE_DATA_LEN / 16)
#define SIEVE_SIZE (104730)
#if defined(HAVE_ASM_NOP)
#define FORCE_DO_NOTHING() stress_asm_nop()
#elif defined(HAVE_ASM_NOTHING)
#define FORCE_DO_NOTHING() stress_asm_nothing()
#else
#define FORCE_DO_NOTHING() while (0)
#endif
#if defined(HAVE_INT128_T)
#define STRESS_UINT128(hi, lo) ((((__uint128_t)hi << 64) | (__uint128_t)lo))
#endif
* the CPU stress test has different classes of cpu stressor
*/
typedef int (*stress_cpu_func)(const char *name);
typedef struct {
const char *name;
const stress_cpu_func func;
const double bogo_op_rate;
} stress_cpu_method_info_t;
static const stress_help_t help[] = {
{ "c N", "cpu N", "start N workers that perform CPU only loading" },
{ "l P", "cpu-load P", "load CPU by P %, 0=sleep, 100=full load (see -c)" },
{ NULL, "cpu-load-slice S", "specify time slice during busy load" },
{ NULL, "cpu-method M", "specify stress cpu method M, default is all" },
{ NULL, "cpu-old-metrics", "use old CPU metrics instead of normalized metrics" },
{ NULL, "cpu-ops N", "stop after N cpu bogo operations" },
{ NULL, NULL, NULL }
};
static const stress_cpu_method_info_t stress_cpu_methods[];
uint8_t pixels[STRESS_CPU_DITHER_X][STRESS_CPU_DITHER_Y];
* stress_cpu_sqrt()
* stress CPU on square roots
*/
static int TARGET_CLONES stress_cpu_sqrt(const char *name)
{
int i;
for (i = 0; i < 16384; i++) {
const uint64_t rnd = stress_mwc32();
double r_d = shim_sqrt((double)rnd) * shim_sqrt((double)rnd);
long double r_ld = shim_sqrtl((long double)rnd) * shim_sqrtl((long double)rnd);
register uint64_t tmp;
r_d = shim_rint(r_d);
tmp = (uint64_t)r_d;
if (UNLIKELY((g_opt_flags & OPT_FLAGS_VERIFY) && (tmp != rnd))) {
pr_fail("%s: sqrt error detected on "
"sqrt(%" PRIu64 ")\n", name, rnd);
return EXIT_FAILURE;
}
r_ld = shim_rintl(r_ld);
tmp = (uint64_t)r_ld;
if (UNLIKELY((g_opt_flags & OPT_FLAGS_VERIFY) && (tmp != rnd))) {
pr_fail("%s: sqrtf error detected on "
"sqrt(%" PRIu64 ")\n", name, rnd);
return EXIT_FAILURE;
}
}
return EXIT_SUCCESS;
}
static bool stress_is_affinity_set(void)
{
#if defined(HAVE_SCHED_GETAFFINITY)
cpu_set_t mask;
int i;
const int cpus_online = (int)stress_get_processors_online();
CPU_ZERO(&mask);
if (sched_getaffinity(0, sizeof(mask), &mask) < 0)
return false;
* If any of the CPU affinities across all the CPUs
* are zero then we know the stressor as been pinned
* to some CPUs and not to others, so affinity has been
* set which can lead to load balancing difficulties
*/
for (i = 0; i < cpus_online; i++) {
if (!CPU_ISSET(i, &mask))
return true;
}
return false;
#else
return false;
#endif
}
* stress_cpu_loop()
* simple CPU busy loop
*/
static int OPTIMIZE0 stress_cpu_loop(const char *name)
{
uint32_t i, i_sum = 0;
const uint32_t sum = 134209536UL;
for (i = 0; LIKELY(i < 16384); i++) {
i_sum += i;
FORCE_DO_NOTHING();
}
if ((g_opt_flags & OPT_FLAGS_VERIFY) && (i_sum != sum)) {
pr_fail("%s: cpu loop 0..16383 sum was %" PRIu32 " and "
"did not match the expected value of %" PRIu32 "\n",
name, i_sum, sum);
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
* stress_cpu_gcd()
* compute Greatest Common Divisor
*/
static int OPTIMIZE3 TARGET_CLONES stress_cpu_gcd(const char *name)
{
uint32_t i, gcd_sum = 0;
const uint32_t gcd_checksum = 63000868UL;
uint64_t lcm_sum = 0;
const uint64_t lcm_checksum = 41637399273ULL;
for (i = 0; i < 16384; i++) {
register uint32_t a = i, b = i % (3 + (1997 ^ i));
register uint64_t lcm = ((uint64_t)a * b);
while (b != 0) {
register const uint32_t r = b;
b = a % b;
a = r;
}
if (a)
lcm_sum += (lcm / a);
gcd_sum += a;
FORCE_DO_NOTHING();
}
if ((g_opt_flags & OPT_FLAGS_VERIFY) &&
(gcd_sum != gcd_checksum) &&
(lcm_sum != lcm_checksum)) {
pr_fail("%s: gcd error detected, failed modulo "
"or assignment operations\n", name);
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
* stress_cpu_bitops()
* various bit manipulation hacks from bithacks
* https://graphics.stanford.edu/~seander/bithacks.html
*/
static int OPTIMIZE3 TARGET_CLONES stress_cpu_bitops(const char *name)
{
uint32_t i, i_sum = 0;
const uint32_t sum = 0x8aac4aab;
for (i = 0; i < 16384; i++) {
i_sum += stress_bitreverse32(i);
i_sum += stress_parity32(i);
i_sum += stress_popcount32(i);
i_sum += stress_nextpwr2(i);
}
if ((g_opt_flags & OPT_FLAGS_VERIFY) && (i_sum != sum)) {
pr_fail("%s: bitops error detected, failed "
"bitops operations\n", name);
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
* stress_cpu_trig()
* simple sin, cos trig functions
*/
static int OPTIMIZE_FAST_MATH stress_cpu_trig(const char *name)
{
int i;
long double d_sum = 0.0L;
(void)name;
for (i = 0; i < 1500; i++) {
const long double theta = (2.0L * PI * (long double)i) / 1500.0L;
{
const double thetad = (double)theta;
const float thetaf = (float)theta;
d_sum += (shim_cosl(theta) * shim_sinl(theta));
d_sum += ((long double)shim_cos(thetad) * (long double)shim_sin(thetad));
d_sum += ((long double)shim_cosf(thetaf) * (long double)shim_sinf(thetaf));
}
{
const long double thetal = theta * 2.0L;
const double thetad = (double)thetal;
const float thetaf = (float)thetal;
d_sum += shim_cosl(thetal);
d_sum += (long double)shim_cos(thetad);
d_sum += (long double)shim_cosf(thetaf);
}
{
const long double thetal = theta * 3.0L;
const double thetad = (double)thetal;
const float thetaf = (float)thetal;
d_sum += shim_sinl(thetal);
d_sum += (long double)shim_sin(thetad);
d_sum += (long double)shim_sinf(thetaf);
}
}
stress_long_double_put(d_sum);
return EXIT_SUCCESS;
}
* stress_cpu_hyperbolic()
* simple hyperbolic sinh, cosh functions
*/
static int OPTIMIZE_FAST_MATH stress_cpu_hyperbolic(const char *name)
{
int i;
long double d_sum = 0.0L;
(void)name;
for (i = 0; i < 1500; i++) {
const long double theta = (2.0L * PI * (long double)i) / 1500.0L;
{
const double thetad = (double)theta;
const float thetaf = (float)theta;
d_sum += (shim_coshl(theta) * shim_sinhl(theta));
d_sum += ((long double)cosh(thetad) * (long double)shim_sinh(thetad));
d_sum += ((long double)coshf(thetaf) * (long double)shim_sinhf(thetaf));
}
{
const long double thetal = theta * 2.0L;
const double thetad = (double)theta;
const float thetaf = (float)theta;
d_sum += shim_coshl(thetal);
d_sum += (long double)shim_cosh(thetad);
d_sum += (long double)shim_coshf(thetaf);
}
{
const long double thetal = theta * 3.0L;
const double thetad = (double)theta;
const float thetaf = (float)theta;
d_sum += shim_sinhl(thetal);
d_sum += (long double)shim_sinh(thetad);
d_sum += (long double)shim_sinhf(thetaf);
}
}
stress_long_double_put(d_sum);
return EXIT_SUCCESS;
}
* stress_cpu_rand()
* generate lots of pseudo-random integers
*/
static int OPTIMIZE3 stress_cpu_rand(const char *name)
{
int i;
uint32_t i_sum = 0;
const uint32_t sum = 0xc253698c;
stress_mwc_seed();
PRAGMA_UNROLL_N(8)
for (i = 0; LIKELY(i < 16384); i++)
i_sum += stress_mwc32();
if ((g_opt_flags & OPT_FLAGS_VERIFY) && (i_sum != sum)) {
pr_fail("%s: rand error detected, failed sum of "
"pseudo-random values\n", name);
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
* stress_cpu_logmap()
* Compute logistic map of x = r * x * (x - 1.0) where r is the
* accumulation point based on A098587. Data is scaled in the
* range 0..255
*/
static int OPTIMIZE3 stress_cpu_logmap(const char *name)
{
static double x = 0.4;
* Use an accumulation point that is slightly larger
* than the point where chaotic behaviour starts
*/
const double r = 3.569945671870944901842L * 1.0999999L;
register int i;
(void)name;
PRAGMA_UNROLL_N(8)
for (i = 0; i < 16384; i++) {
* Scale up a fractional part of x
* by an arbitrary value and take
* the bottom 8 bits of the result
* to make a quasi-chaotic random-ish
* value
*/
x = x * r * (1.0 - x);
}
stress_double_put(x);
return EXIT_SUCCESS;
}
#if defined(HAVE_SRAND48) && \
defined(HAVE_LRAND48) && \
defined(HAVE_DRAND48)
* Some libc's such as OpenBSD don't implement rand48 the same
* as linux's glibc, so beware of different implementations with
* the verify mode checking.
*/
#if defined(__linux__) && \
defined(__GLIBC__)
#define STRESS_CPU_RAND48_VERIFY
#endif
* stress_cpu_rand48()
* generate random values using rand48 family of functions
*/
static int OPTIMIZE3 stress_cpu_rand48(const char *name)
{
int i;
double d = 0;
long long int l = 0;
#if defined(STRESS_CPU_RAND48_VERIFY)
const double d_expected_sum = 8184.618041L;
const long long int l_expected_sum = 17522760427916;
#endif
(void)name;
srand48(0x0defaced);
for (i = 0; LIKELY(i < 16384); i++) {
d += drand48();
l += lrand48();
}
#if defined(STRESS_CPU_RAND48_VERIFY)
if (g_opt_flags & OPT_FLAGS_VERIFY) {
double d_error = d - d_expected_sum;
if (shim_fabs(d_error) > 0.0001) {
pr_fail("%s: drand48 error detected, failed sum\n", name);
return EXIT_FAILURE;
}
if (l != l_expected_sum) {
pr_fail("%s: lrand48 error detected, failed sum\n", name);
return EXIT_FAILURE;
}
}
#endif
stress_double_put(d);
stress_uint64_put((uint64_t)l);
return EXIT_SUCCESS;
}
#endif
* stress_cpu_lfsr32()
* generate 16384 values from the Galois polynomial
* x^32 + x^31 + x^29 + x + 1
*/
static int OPTIMIZE3 stress_cpu_lfsr32(const char *name)
{
static uint32_t lfsr = 0xf63acb01;
register int i;
(void)name;
PRAGMA_UNROLL_N(8)
for (i = 0; LIKELY(i < 16384); i++) {
lfsr = (lfsr >> 1) ^ (unsigned int)(-(lfsr & 1u) & 0xd0000001U);
}
stress_uint32_put(lfsr);
return EXIT_SUCCESS;
}
* stress_cpu_nsqrt()
* iterative Newton-Raphson square root
*/
static int OPTIMIZE3 TARGET_CLONES stress_cpu_nsqrt(const char *name)
{
int i;
const long double precision = 1.0e-12L;
const int max_iter = 56;
for (i = 16300; i < 16384; i++) {
const long double n = (long double)i;
long double lo = (n < 1.0L) ? n : 1.0L;
long double hi = (n < 1.0L) ? 1.0L : n;
long double rt;
int j = 0;
while ((j++ < max_iter) && ((hi - lo) > precision)) {
const long double g = (lo + hi) / 2.0L;
if ((g * g) > n)
hi = g;
else
lo = g;
}
rt = (lo + hi) / 2.0L;
if (g_opt_flags & OPT_FLAGS_VERIFY) {
const long double r2 = shim_rintl(rt * rt);
if (j >= max_iter) {
pr_fail("%s: Newton-Raphson sqrt "
"computation took more iterations "
"than expected\n", name);
return EXIT_FAILURE;
}
if ((int)r2 != i) {
pr_fail("%s: Newton-Raphson sqrt not "
"accurate enough\n", name);
return EXIT_FAILURE;
}
}
}
return EXIT_SUCCESS;
}
* stress_cpu_phi()
* compute the Golden Ratio
*/
static int OPTIMIZE3 TARGET_CLONES stress_cpu_phi(const char *name)
{
long double phi;
const long double precision = 1.0e-15L;
const long double phi_ = (1.0L + shim_sqrtl(5.0L)) / 2.0L;
register uint64_t a, b;
const uint64_t mask = 1ULL << 63;
int i;
a = stress_mwc64modn(99);
b = stress_mwc64modn(99);
for (i = 0; (i < 64) && !((a | b) & mask); i++) {
register const uint64_t c = a + b;
a = b;
b = c;
}
phi = (long double)b / (long double)a;
if ((g_opt_flags & OPT_FLAGS_VERIFY) &&
(shim_fabsl(phi - phi_) > precision)) {
pr_fail("%s: Golden Ratio phi not accurate enough\n",
name);
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
* stress_cpu_apery()
* compute Apéry's constant
*/
static int OPTIMIZE3 stress_cpu_apery(const char *name)
{
uint32_t n;
long double a = 0.0L, a_ = a;
const long double precision = 1.0e-14L;
(void)name;
for (n = 1; LIKELY(n < 100000); n++) {
register long double n3 = (long double)n;
a_ = a;
n3 = n3 * n3 * n3;
a += (1.0L / n3);
if (shim_fabsl(a - a_) < precision)
break;
}
if (shim_fabsl(a - a_) > precision) {
pr_fail("%s: Apéry's constant not accurate enough\n", name);
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
#if defined(HAVE_COMPLEX_H) && \
defined(HAVE_COMPLEX) && \
defined(__STDC_IEC_559_COMPLEX__) &&\
!defined(__UCLIBC__)
* fft_partial()
* partial Fast Fourier Transform
*/
static void OPTIMIZE3 fft_partial(
double complex * RESTRICT data,
double complex * RESTRICT tmp,
const int n,
const int m)
{
if (m < n) {
const int m2 = m * 2;
int i;
fft_partial(tmp, data, n, m2);
fft_partial(tmp + m, data + m, n, m2);
for (i = 0; i < n; i += m2) {
const double complex negI = -(double complex)I;
register double complex v = tmp[i];
register double complex t =
shim_cexp((negI * (double)PI * (double)i) /
(double)n) * tmp[i + m];
data[i / 2] = v + t;
data[(i + n) / 2] = v - t;
}
}
}
* stress_cpu_fft()
* Fast Fourier Transform
*/
static int TARGET_CLONES stress_cpu_fft(const char *name)
{
static double complex buf[FFT_SIZE] ALIGN64, tmp[FFT_SIZE] ALIGN64;
int i;
(void)name;
for (i = 0; i < FFT_SIZE; i++)
buf[i] = (double complex)(i % 63);
(void)shim_memcpy(tmp, buf, sizeof(*tmp) * FFT_SIZE);
fft_partial(buf, tmp, FFT_SIZE, 1);
return EXIT_SUCCESS;
}
#else
UNEXPECTED
#endif
* stress_cpu_euler()
* compute e using series
*/
static int OPTIMIZE3 TARGET_CLONES stress_cpu_euler(const char *name)
{
long double e = 1.0L, last_e;
long double fact = 1.0L;
const long double precision = 1.0e-20L;
int n = 1;
do {
last_e = e;
fact *= n;
n++;
e += (1.0L / fact);
} while ((n < 25) && (shim_fabsl(e - last_e) > precision));
if ((g_opt_flags & OPT_FLAGS_VERIFY) && (n >= 25)) {
pr_fail("%s: Euler computation took more iterations "
"than expected\n", name);
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
* random_buffer()
* fill a uint8_t buffer full of random data
* buffer *must* be multiple of 4 bytes in size
*/
static void random_buffer(uint8_t *data, const size_t len)
{
size_t i;
for (i = 0; i < len / 4; i++) {
register uint32_t v = stress_mwc32();
*data++ = (uint8_t)v;
v >>= 8;
*data++ = (uint8_t)v;
v >>= 8;
*data++ = (uint8_t)v;
v >>= 8;
*data++ = (uint8_t)v;
}
}
* stress_cpu_collatz()
* stress test integer collatz conjecture
*/
static int OPTIMIZE3 TARGET_CLONES stress_cpu_collatz(const char *name)
{
register uint64_t n = 989345275647ULL;
register uint64_t s = stress_mwc8();
register int i;
* We need to put in the accumulation of s to force the compiler
* to generate code that does the following computation at run time.
*/
for (i = 0; n != 1; i++) {
n = (n & 1) ? (3 * n) + 1 : n / 2;
s += n;
}
stress_uint64_put(s);
if ((g_opt_flags & OPT_FLAGS_VERIFY) && (i != 1348)) {
pr_fail("%s: error detected, failed collatz progression\n",
name);
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
* stress_cpu_idct()
* compute 8x8 Inverse Discrete Cosine Transform
*/
static int OPTIMIZE3 TARGET_CLONES stress_cpu_idct(const char *name)
{
#define IDCT_SIZE (8)
const double invsqrt2 = 1.0 / shim_sqrt(2.0);
const double pi_over_16 = (double)PI / 16.0;
int i, j, u, v;
float data[IDCT_SIZE][IDCT_SIZE];
float idct[IDCT_SIZE][IDCT_SIZE];
* Set up DCT
*/
for (i = 0; i < IDCT_SIZE; i++) {
PRAGMA_UNROLL_N(8)
for (j = 0; j < IDCT_SIZE; j++) {
data[i][j] = (i + j == 0) ? 2040: 0;
}
}
for (i = 0; i < IDCT_SIZE; i++) {
const double pi_i = (i + i + 1) * pi_over_16;
for (j = 0; j < IDCT_SIZE; j++) {
const double pi_j = (j + j + 1) * pi_over_16;
double sum = 0.0;
for (u = 0; u < IDCT_SIZE; u++) {
const double cos_pi_i_u = shim_cos(pi_i * u);
const double tmp = cos_pi_i_u * (u ? 1.0 : invsqrt2);
for (v = 0; v < IDCT_SIZE; v++) {
const double cos_pi_j_v = shim_cos(pi_j * v);
sum += (double)data[u][v] *
(v ? 1.0 : invsqrt2) * cos_pi_j_v * tmp;
}
}
idct[i][j] = (float)(0.25 * sum);
}
}
if (g_opt_flags & OPT_FLAGS_VERIFY) {
for (i = 0; i < IDCT_SIZE; i++) {
for (j = 0; j < IDCT_SIZE; j++) {
if ((int)idct[i][j] != 255) {
pr_fail("%s: IDCT error detected, "
"IDCT[%d][%d] was %d, "
"expecting 255\n",
name, i, j, (int)idct[i][j]);
return EXIT_FAILURE;
}
}
if (UNLIKELY(!stress_continue_flag()))
return EXIT_SUCCESS;
}
}
#undef IDCT_SIZE
return EXIT_SUCCESS;
}
#define int_ops(type, a, b, c1, c2, c3) \
do { \
a += b; \
b ^= a; \
a >>= 1; \
b <<= 2; \
b -= a; \
a ^= (type)~0; \
b ^= ~(c1); \
a *= 3; \
b *= 7; \
a += 2; \
b -= 3; \
a /= 77; \
b /= 3; \
a <<= 1; \
b <<= 2; \
a |= 1; \
b |= 3; \
a *= stress_mwc32(); \
b ^= stress_mwc32(); \
a += stress_mwc32(); \
b -= stress_mwc32(); \
a /= 7; \
b /= 9; \
a |= (c2); \
b &= (c3); \
} while (0);
#define C1 (0xf0f0f0f0f0f0f0f0ULL)
#define C2 (0x1000100010001000ULL)
#define C3 (0xffeffffefebefffeULL)
* Generic int stressor macro
*/
#define stress_cpu_int(type, sz, int_a, int_b, int_c1, int_c2, int_c3) \
static int OPTIMIZE3 TARGET_CLONES stress_cpu_int ## sz(const char *name)\
{ \
const type mask = (type)~(type)0; \
const type a_final = int_a; \
const type b_final = int_b; \
const type c1 = int_c1 & mask; \
const type c2 = int_c2 & mask; \
const type c3 = int_c3 & mask; \
register type a, b; \
int i; \
\
stress_mwc_seed(); \
a = (type)stress_mwc32(); \
b = (type)stress_mwc32(); \
\
for (i = 0; i < 1000; i++) { \
int_ops(type, a, b, c1, c2, c3) \
} \
\
if ((g_opt_flags & OPT_FLAGS_VERIFY) && \
((a != a_final) || (b != b_final))) { \
pr_fail("%s: int" # sz " error detected, " \
"failed int" # sz \
" math operations\n", name); \
return EXIT_FAILURE; \
} \
return EXIT_SUCCESS; \
} \
#if defined(HAVE_INT128_T)
stress_cpu_int(__uint128_t, 128,
STRESS_UINT128(0x132af604d8b9183a,0x5e3af8fa7a663d74),
STRESS_UINT128(0x62f086e6160e4e,0xd84c9f800365858),
STRESS_UINT128(C1, C1), STRESS_UINT128(C2, C2), STRESS_UINT128(C3, C3))
#endif
stress_cpu_int(uint64_t, 64, \
0x013f7f6dc1d79197cULL, 0x01863d2c6969a51ceULL,
C1, C2, C3)
stress_cpu_int(uint32_t, 32, \
0x1ce9b547UL, 0xa24b33aUL,
C1, C2, C3)
stress_cpu_int(uint16_t, 16, \
0x1871, 0x07f0,
C1, C2, C3)
stress_cpu_int(uint8_t, 8, \
0x12, 0x1a,
C1, C2, C3)
#define float_thresh(x, type) x = (type) \
((shim_fabs((double)x) > 1.0) ? \
((type)(0.1 + (double)x - (double)(long)x)) : \
((type)(x)))
#define float_ops(type, a, b, c, d, f_sin, f_cos) \
do { \
a = a + b; \
b = a * c; \
c = a - b; \
d = a / (type)8.1; \
float_thresh(d, type); \
a = c / (type)5.1923; \
float_thresh(a, type); \
float_thresh(c, type); \
b = c + a; \
c = b * (type)f_sin(b); \
d = d + b + (type)f_sin(a); \
a = (type)f_cos(b + c); \
b = b * c; \
c = c + (type)1.5; \
d = d - (type)f_sin(c); \
a = a * (type)f_cos(b); \
b = b + (type)f_cos(c); \
c = (type)f_sin(a + b) / (type)2.344; \
b = d - (type)0.5; \
} while (0)
* Generic floating point stressor macro
*/
#define stress_cpu_fp(type, fp_name, f_sin, f_cos) \
static int OPTIMIZE3 TARGET_CLONES stress_cpu_ ## fp_name(const char *name)\
{ \
int i; \
const uint32_t r1 = stress_mwc32(), \
r2 = stress_mwc32(); \
type a = (type)0.18728L, \
b = (type)((double)r1 / 65536.0), \
c = (type)((double)r2 / 65536.0), \
d = (type)0.0, \
r; \
\
(void)name; \
\
for (i = 0; i < 1000; i++) { \
float_ops(type, a, b, c, d, \
f_sin, f_cos); \
} \
r = a + b + c + d; \
stress_double_put((double)r); \
return EXIT_SUCCESS; \
}
stress_cpu_fp(float, float, shim_sinf, shim_cosf)
stress_cpu_fp(double, double, shim_sin, shim_cos)
stress_cpu_fp(long double, longdouble, shim_sinl, shim_cosl)
#if defined(HAVE_Decimal32) && \
!defined(HAVE_COMPILER_CLANG)
stress_cpu_fp(_Decimal32, decimal32, shim_sinf, shim_cosf)
#endif
#if defined(HAVE_Decimal64) && \
!defined(HAVE_COMPILER_CLANG)
stress_cpu_fp(_Decimal64, decimal64, shim_sin, shim_cos)
#endif
#if defined(HAVE_Decimal128) && \
!defined(HAVE_COMPILER_CLANG)
stress_cpu_fp(_Decimal128, decimal128, shim_sinl, shim_cosl)
#endif
#if defined(HAVE_fp16) && \
!defined(HAVE_COMPILER_CLANG)
stress_cpu_fp(__fp16, float16, shim_sin, shim_cos)
#endif
#if defined(HAVE_Float32) && \
!defined(HAVE_COMPILER_CLANG)
stress_cpu_fp(_Float32, float32, shim_sin, shim_cos)
#endif
#if defined(HAVE_Float64) && \
!defined(HAVE_COMPILER_CLANG)
stress_cpu_fp(_Float64, float64, shim_sin, shim_cos)
#endif
#if defined(HAVE__float80) && \
!defined(HAVE_COMPILER_CLANG)
stress_cpu_fp(__float80, float80, shim_sinl, shim_cosl)
#endif
#if defined(HAVE__float128) && \
!defined(HAVE_COMPILER_CLANG)
stress_cpu_fp(__float128, float128, shim_sinl, shim_cosl)
#elif defined(HAVE_Float128) && \
!defined(HAVE_COMPILER_CLANG)
stress_cpu_fp(_Float128, float128, shim_sinl, shim_cosl)
#endif
#define FP(val, ltype) val ## ltype
#if defined(HAVE_COMPLEX_H) && \
defined(HAVE_COMPLEX) && \
defined(__STDC_IEC_559_COMPLEX__) &&\
!defined(__UCLIBC__)
static inline void stress_cpu_complex_float_put(complex float v)
{
stress_float_put((float)(v * v));
}
static inline void stress_cpu_complex_double_put(complex double v)
{
stress_double_put((double)(v * v));
}
static inline void stress_cpu_complex_long_double_put(complex long double v)
{
stress_long_double_put((long double)(v * v));
}
* Generic complex stressor macro
*/
#define stress_cpu_complex(type, ltype, c_name, f_csin, f_ccos, f_put) \
static int OPTIMIZE3 TARGET_CLONES stress_cpu_ ## c_name(const char *name) \
{ \
int i; \
const uint32_t r1 = stress_mwc32(), \
r2 = stress_mwc32(); \
type cI = (type)I; \
type a = FP(0.18728, ltype) + \
cI * FP(0.2762, ltype), \
b = (type)((double)r1/(double)(1UL<<31)) - cI * FP(0.11121, ltype), \
c = (type)((double)r2/(double)(1UL<<31)) + cI * stress_mwc32(), \
d = (type)0.5, \
r; \
\
(void)name; \
\
for (i = 0; i < 1000; i++) { \
float_ops(type, a, b, c, d, f_csin, f_ccos); \
} \
r = a + b + c + d; \
f_put(r); \
return EXIT_SUCCESS; \
}
stress_cpu_complex(complex float, f, complex_float, shim_csinf, shim_ccosf, stress_cpu_complex_float_put)
stress_cpu_complex(complex double, , complex_double, shim_csin, shim_ccos, stress_cpu_complex_double_put)
stress_cpu_complex(complex long double, l, complex_long_double, shim_csinl, shim_ccosl, stress_cpu_complex_long_double_put)
#endif
#define int_float_ops(ftype, flt_a, flt_b, flt_c, flt_d, \
f_sin, f_cos, inttype, int_a, int_b, \
int_c1, int_c2, int_c3) \
\
do { \
int_a += int_b; \
int_b ^= int_a; \
flt_a = flt_a + flt_b; \
int_a >>= 1; \
int_b <<= 2; \
flt_b = flt_a * flt_c; \
int_b -= int_a; \
int_a ^= ~(inttype)0; \
flt_c = flt_a - flt_b; \
int_b ^= ~(int_c1); \
int_a *= 3; \
flt_d = flt_a / flt_b; \
int_b *= 7; \
int_a += 2; \
flt_a = flt_c / (ftype)0.1923L; \
int_b -= 3; \
int_a /= 77; \
flt_b = flt_c + flt_a; \
int_b /= 3; \
int_a <<= 1; \
flt_c = flt_b * (ftype)3.12L; \
int_b <<= 2; \
int_a |= 1; \
flt_d = flt_d + flt_b + (ftype)f_sin(flt_a); \
int_b |= 3; \
int_a *= stress_mwc32(); \
flt_a = (flt_b + flt_c) / flt_c; \
int_b ^= stress_mwc32(); \
int_a += stress_mwc32(); \
flt_b = flt_b * flt_c; \
int_b -= stress_mwc32(); \
int_a /= 7; \
flt_c = flt_c + (ftype)1.0L; \
int_b /= 9; \
flt_d = flt_d - (ftype)f_sin(flt_c); \
int_a |= (int_c2); \
flt_a = flt_a * (ftype)f_cos(flt_b); \
flt_b = flt_b + (ftype)f_cos(flt_c); \
int_b &= (int_c3); \
flt_c = (ftype)f_sin(flt_a + flt_b) / (ftype)2.344L; \
flt_b = flt_d - (ftype)1.0L; \
} while (0)
* Generic integer and floating point stressor macro
*/
#define stress_cpu_int_fp(inttype, sz, ftype, fp_name, \
int_a, int_b, int_c1, int_c2, int_c3, f_sinf, f_cosf) \
static int OPTIMIZE3 TARGET_CLONES stress_cpu_int ## sz ## _ ## fp_name(const char *name)\
{ \
int i; \
inttype a, b; \
const inttype mask = (inttype)~0; \
const inttype a_final = int_a; \
const inttype b_final = int_b; \
const inttype c1 = int_c1 & mask; \
const inttype c2 = int_c2 & mask; \
const inttype c3 = int_c3 & mask; \
const uint32_t r1 = stress_mwc32(), \
r2 = stress_mwc32(); \
ftype flt_a = (ftype)0.18728L, \
flt_b = (ftype)r1, \
flt_c = (ftype)r2, \
flt_d = (ftype)0.0, \
flt_r; \
\
stress_mwc_seed(); \
a = stress_mwc32(); \
b = stress_mwc32(); \
\
for (i = 0; i < 1000; i++) { \
int_float_ops(ftype, flt_a, flt_b, flt_c, \
flt_d,f_sinf, f_cosf, inttype, \
a, b, c1, c2, c3); \
} \
if ((g_opt_flags & OPT_FLAGS_VERIFY) && \
((a != a_final) || (b != b_final))) { \
pr_fail("%s: int" # sz " error detected, " \
"failed int" # sz "" # ftype \
" math operations\n", name); \
return EXIT_FAILURE; \
} \
\
flt_r = flt_a + flt_b + flt_c + flt_d; \
stress_double_put((double)flt_r); \
return EXIT_SUCCESS; \
}
stress_cpu_int_fp(uint32_t, 32, float, float,
0x1ce9b547UL, 0xa24b33aUL,
C1, C2, C3, shim_sinf, shim_cosf)
stress_cpu_int_fp(uint32_t, 32, double, double,
0x1ce9b547UL, 0xa24b33aUL,
C1, C2, C3, shim_sin, shim_cos)
stress_cpu_int_fp(uint32_t, 32, long double, longdouble,
0x1ce9b547UL, 0xa24b33aUL,
C1, C2, C3, shim_sinl, shim_cosl)
stress_cpu_int_fp(uint64_t, 64, float, float,
0x13f7f6dc1d79197cULL, 0x1863d2c6969a51ceULL,
C1, C2, C3, shim_sinf, shim_cosf)
stress_cpu_int_fp(uint64_t, 64, double, double,
0x13f7f6dc1d79197cULL, 0x1863d2c6969a51ceULL,
C1, C2, C3, shim_sin, shim_cos)
stress_cpu_int_fp(uint64_t, 64, long double, longdouble,
0x13f7f6dc1d79197cULL, 0x1863d2c6969a51ceULL,
C1, C2, C3, shim_sinl, shim_cosl)
#if defined(HAVE_INT128_T)
stress_cpu_int_fp(__uint128_t, 128, float, float,
STRESS_UINT128(0x132af604d8b9183a,0x5e3af8fa7a663d74),
STRESS_UINT128(0x0062f086e6160e4e,0x0d84c9f800365858),
STRESS_UINT128(C1, C1), STRESS_UINT128(C2, C2), STRESS_UINT128(C3, C3),
shim_sinf, shim_cosf)
stress_cpu_int_fp(__uint128_t, 128, double, double,
STRESS_UINT128(0x132af604d8b9183a,0x5e3af8fa7a663d74),
STRESS_UINT128(0x0062f086e6160e4e,0x0d84c9f800365858),
STRESS_UINT128(C1, C1), STRESS_UINT128(C2, C2), STRESS_UINT128(C3, C3),
shim_sin, shim_cos)
stress_cpu_int_fp(__uint128_t, 128, long double, longdouble,
STRESS_UINT128(0x132af604d8b9183a,0x5e3af8fa7a663d74),
STRESS_UINT128(0x0062f086e6160e4e,0x0d84c9f800365858),
STRESS_UINT128(C1, C1), STRESS_UINT128(C2, C2), STRESS_UINT128(C3, C3),
shim_sinl, shim_cosl)
#if defined(HAVE_Decimal32) && \
!defined(HAVE_COMPILER_CLANG)
stress_cpu_int_fp(__uint128_t, 128, _Decimal32, decimal32,
STRESS_UINT128(0x132af604d8b9183a,0x5e3af8fa7a663d74),
STRESS_UINT128(0x0062f086e6160e4e,0x0d84c9f800365858),
STRESS_UINT128(C1, C1), STRESS_UINT128(C2, C2), STRESS_UINT128(C3, C3),
(_Decimal32)shim_sinf, (_Decimal32)shim_cosf)
#endif
#if defined(HAVE_Decimal64) && \
!defined(HAVE_COMPILER_CLANG)
stress_cpu_int_fp(__uint128_t, 128, _Decimal64, decimal64,
STRESS_UINT128(0x132af604d8b9183a,0x5e3af8fa7a663d74),
STRESS_UINT128(0x0062f086e6160e4e,0x0d84c9f800365858),
STRESS_UINT128(C1, C1), STRESS_UINT128(C2, C2), STRESS_UINT128(C3, C3),
(_Decimal64)shim_sin, (_Decimal64)shim_cos)
#endif
#if defined(HAVE_Decimal128) && \
!defined(HAVE_COMPILER_CLANG)
stress_cpu_int_fp(__uint128_t, 128, _Decimal128, decimal128,
STRESS_UINT128(0x132af604d8b9183a,0x5e3af8fa7a663d74),
STRESS_UINT128(0x0062f086e6160e4e,0x0d84c9f800365858),
STRESS_UINT128(C1, C1), STRESS_UINT128(C2, C2), STRESS_UINT128(C3, C3),
(_Decimal128)shim_sinl, (_Decimal128)shim_cosl)
#endif
#endif
* stress_cpu_rgb()
* CCIR 601 RGB to YUV to RGB conversion
*/
static int OPTIMIZE3 TARGET_CLONES stress_cpu_rgb(const char *name)
{
int i;
uint32_t rgb = stress_mwc32() & 0xffffff;
uint8_t r = (uint8_t)(rgb >> 16);
uint8_t g = (uint8_t)(rgb >> 8);
uint8_t b = (uint8_t)rgb;
(void)name;
PRAGMA_UNROLL_N(8)
for (i = 0; i < 1000; i++) {
float y, u, v;
y = (0.299f * r) + (0.587f * g) + (0.114f * b);
u = (b - y) * 0.565f;
v = (r - y) * 0.713f;
r = (uint8_t)(y + (1.403f * v));
g = (uint8_t)(y - (0.344f * u) - (0.714f * v));
b = (uint8_t)(y + (1.770f * u));
r += 1;
g += 2;
b += 3;
stress_uint64_put(r + g + b);
}
return EXIT_SUCCESS;
}
* stress_cpu_matrix_prod(void)
* matrix product
*/
static int OPTIMIZE3 TARGET_CLONES stress_cpu_matrix_prod(const char *name)
{
int i, j, k;
static long double a[MATRIX_PROD_SIZE][MATRIX_PROD_SIZE] ALIGN64,
b[MATRIX_PROD_SIZE][MATRIX_PROD_SIZE] ALIGN64,
r[MATRIX_PROD_SIZE][MATRIX_PROD_SIZE] ALIGN64;
const long double v = 1 / (long double)((uint32_t)~0);
long double sum = 0.0L;
(void)name;
for (i = 0; i < MATRIX_PROD_SIZE; i++) {
for (j = 0; j < MATRIX_PROD_SIZE; j++) {
const uint32_t r1 = stress_mwc32();
const uint32_t r2 = stress_mwc32();
a[i][j] = (long double)r1 * v;
b[i][j] = (long double)r2 * v;
r[i][j] = 0.0L;
}
}
for (i = 0; i < MATRIX_PROD_SIZE; i++) {
for (j = 0; j < MATRIX_PROD_SIZE; j++) {
for (k = 0; k < MATRIX_PROD_SIZE; k++) {
r[i][j] += a[i][k] * b[k][j];
}
}
}
for (i = 0; i < MATRIX_PROD_SIZE; i++)
PRAGMA_UNROLL_N(8)
for (j = 0; j < MATRIX_PROD_SIZE; j++)
sum += r[i][j];
stress_long_double_put(sum);
return EXIT_SUCCESS;
}
* stress_cpu_fibonacci()
* compute fibonacci series
*/
static int OPTIMIZE3 stress_cpu_fibonacci(const char *name)
{
const uint64_t fn_res = 0xa94fad42221f2702ULL;
register uint64_t f1 = 0, f2 = 1, fn;
do {
fn = f1 + f2;
f1 = f2;
f2 = fn;
} while (!(fn & 0x8000000000000000ULL));
if ((g_opt_flags & OPT_FLAGS_VERIFY) && (fn_res != fn)) {
pr_fail("%s: fibonacci error detected, summation "
"or assignment failure\n", name);
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
* stress_cpu_psi
* compute the constant psi,
* the reciprocal Fibonacci constant
*/
static int OPTIMIZE3 stress_cpu_psi(const char *name)
{
long double f1 = 0.0L, f2 = 1.0L;
long double psi = 0.0L, last_psi;
const long double precision = 1.0e-20L;
int i = 0;
const int max_iter = 100;
do {
const long double fn = f1 + f2;
f1 = f2;
f2 = fn;
last_psi = psi;
psi += 1.0L / f1;
i++;
} while ((i < max_iter) && (shim_fabsl(psi - last_psi) > precision));
if (g_opt_flags & OPT_FLAGS_VERIFY) {
if (shim_fabsl(psi - PSI) > 1.0e-15L) {
pr_fail("%s: calculation of reciprocal "
"Fibonacci constant phi not as accurate "
"as expected\n", name);
return EXIT_FAILURE;
}
if (i >= max_iter) {
pr_fail("%s: calculation of reciprocal "
"Fibonacci constant took more iterations "
"than expected\n", name);
return EXIT_FAILURE;
}
}
stress_long_double_put(psi);
return EXIT_SUCCESS;
}
* stress_cpu_ln2
* compute ln(2) using series
*/
static int OPTIMIZE3 TARGET_CLONES OPTIMIZE_FAST_MATH stress_cpu_ln2(const char *name)
{
long double ln2 = 0.0L, last_ln2 = 0.0L;
const long double precision = 1.0e-7L;
register int n = 1;
const int max_iter = 10000;
do {
last_ln2 = ln2;
ln2 += (long double)1.0L / (long double)n++;
ln2 -= (long double)1.0L / (long double)n++;
ln2 += (long double)1.0L / (long double)n++;
ln2 -= (long double)1.0L / (long double)n++;
ln2 += (long double)1.0L / (long double)n++;
ln2 -= (long double)1.0L / (long double)n++;
ln2 += (long double)1.0L / (long double)n++;
ln2 -= (long double)1.0L / (long double)n++;
} while ((n < max_iter) && (shim_fabsl(ln2 - last_ln2) > precision));
if ((g_opt_flags & OPT_FLAGS_VERIFY) && (n >= max_iter)) {
pr_fail("%s: calculation of ln(2) took more "
"iterations than expected\n", name);
return EXIT_FAILURE;
}
stress_long_double_put(ln2);
return EXIT_SUCCESS;
}
* ackermann()
* a naive/simple implementation of the ackermann function
*/
static uint32_t ackermann(const uint32_t m, const uint32_t n)
{
if (m == 0)
return n + 1;
else if (n == 0)
return ackermann(m - 1, 1);
else
return ackermann(m - 1, ackermann(m, n - 1));
}
* stress_cpu_ackermann
* compute ackermann function
*/
static int stress_cpu_ackermann(const char *name)
{
uint32_t a = ackermann(3, 7);
if ((g_opt_flags & OPT_FLAGS_VERIFY) && (a != 1021)) {
pr_fail("%s: ackermann error detected, "
"ackermann(3, 7) miscalculated, got %" PRIu32
", expected %" PRIu32 "\n", name, a, 1021);
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
* stress_cpu_explog
* compute exp(log(n))
*/
static int OPTIMIZE_FAST_MATH stress_cpu_explog(const char *name)
{
uint32_t i;
double n = 1e6 + (double)stress_mwc8();
double m = 0.0;
(void)name;
for (i = 1; LIKELY(i < 100000); i++) {
n = shim_log(n) / 1.00002;
m += n;
n = shim_exp(n);
m += n;
}
stress_double_put(m);
stress_double_put(n);
return EXIT_SUCCESS;
}
* This could be a ternary operator, v = (v op val) ? a : b
* but it may be optimised down, so force a compare and jmp
* with -O0 and a if/else construct
*/
#define JMP(v, op, val, a, b) \
do { \
if (v op val) \
v = a; \
else \
v = b; \
stress_uint32_put((uint32_t)(next + i));\
} while (0)
* stress_cpu_jmp
* jmp conditionals
*/
static int OPTIMIZE0 stress_cpu_jmp(const char *name)
{
register int i, next = 0;
(void)name;
for (i = 1; i < 1000; i++) {
JMP(next, ==, 1, 2, 3);
JMP(next, >, 2, 0, 1);
JMP(next, <, 1, 1, 0);
JMP(next, ==, 1, 2, 3);
JMP(next, >, 2, 0, 1);
JMP(next, <, 1, 1, 0);
JMP(next, ==, 1, 2, 3);
JMP(next, >, 2, 0, 1);
JMP(next, <, 1, 1, 0);
JMP(next, ==, 1, 2, 3);
JMP(next, >, 2, 0, 1);
JMP(next, <, 1, 1, 0);
}
return EXIT_SUCCESS;
}
* ccitt_crc16()
* perform naive CCITT CRC16
*/
static uint16_t PURE OPTIMIZE3 ccitt_crc16(const uint8_t *data, size_t n)
{
* The CCITT CRC16 polynomial is
* 16 12 5
* x + x + x + 1
*
* which is 0x11021, but to make the computation
* simpler, this has been reversed to 0x8408 and
* the top bit ignored..
* We can get away with a 17 bit polynomial
* being represented by a 16 bit value because
* we are assuming the top bit is always set.
*/
const uint16_t polynomial = 0x8408;
register uint16_t crc = 0xffff;
if (!n)
return 0;
for (; n; n--) {
register uint8_t i;
register uint8_t val = (uint16_t)0xff & *data++;
for (i = 8; i; --i, val >>= 1) {
bool do_xor = 1 & (val ^ crc);
crc >>= 1;
crc ^= do_xor ? polynomial : 0;
}
}
crc = ~crc;
return ((uint16_t)(crc << 8)) | (crc >> 8);
}
* stress_cpu_crc16
* compute 1024 rounds of CCITT CRC16
*/
static int stress_cpu_crc16(const char *name)
{
uint8_t buffer[1024];
size_t i;
(void)name;
random_buffer(buffer, sizeof(buffer));
for (i = 1; i < sizeof(buffer); i++)
stress_uint64_put(ccitt_crc16(buffer, i));
return EXIT_SUCCESS;
}
* fletcher16
* naive implementation of fletcher16 checksum
*/
static uint16_t PURE OPTIMIZE3 fletcher16(const uint8_t *data, const size_t len)
{
register uint16_t sum1 = 0, sum2 = 0;
register size_t i;
for (i = 0; i < len; i++) {
sum1 = (sum1 + data[i]) % 255;
sum2 = (sum2 + sum1) % 255;
}
return ((uint16_t)(sum2 << 8)) | sum1;
}
* stress_cpu_fletcher16()
* compute 1024 rounds of fletcher16 checksum
*/
static int stress_cpu_fletcher16(const char *name)
{
uint8_t buffer[1024];
size_t i;
(void)name;
random_buffer((uint8_t *)buffer, sizeof(buffer));
for (i = 1; i < sizeof(buffer); i++)
stress_uint16_put(fletcher16(buffer, i));
return EXIT_SUCCESS;
}
* stress_cpu_ipv4checksum
* compute 1024 rounds of IPv4 checksum
*/
static int stress_cpu_ipv4checksum(const char *name)
{
uint16_t buffer[512];
size_t i;
(void)name;
random_buffer((uint8_t *)buffer, sizeof(buffer));
for (i = 1; i < sizeof(buffer); i++)
stress_uint16_put(stress_ipv4_checksum(buffer, i));
return EXIT_SUCCESS;
}
#if defined(HAVE_COMPLEX_H) && \
defined(HAVE_COMPLEX) && \
defined(__STDC_IEC_559_COMPLEX__) &&\
!defined(__UCLIBC__)
* zeta()
* Riemann zeta function
*/
static inline long double complex PURE OPTIMIZE3 OPTIMIZE_FAST_MATH zeta(
const long double complex s,
long double precision)
{
int i = 1;
long double complex z = 0.0L, zold = 0.0L;
do {
const double complex pwr = shim_cpow(i++, (complex double)s);
zold = z;
z += 1.0L / (long double complex)pwr;
} while (shim_cabsl(z - zold) > precision);
return z;
}
* stress_cpu_zeta()
* stress test Zeta(2.0)..Zeta(10.0)
*/
static int OPTIMIZE3 OPTIMIZE_FAST_MATH stress_cpu_zeta(const char *name)
{
long double precision = 0.00000001L;
int i;
(void)name;
for (i = 2; i < 11; i++) {
const long double complex z = zeta((long double complex)i, precision);
stress_long_double_put((long double)z);
}
return EXIT_SUCCESS;
}
#else
UNEXPECTED
#endif
* stress_cpu_gamma()
* stress Euler-Mascheroni constant gamma
*/
static int OPTIMIZE3 OPTIMIZE_FAST_MATH stress_cpu_gamma(const char *name)
{
const long double precision = 1.0e-10L;
long double sum = 0.0L, k = 1.0L, gammanew = 0.0L, gammaold;
do {
gammaold = gammanew;
sum += 1.0L / k;
gammanew = sum - shim_logl(k);
k += 1.0L;
} while ((k < 1e6L) && shim_fabsl(gammanew - gammaold) > precision);
stress_long_double_put(gammanew);
if (g_opt_flags & OPT_FLAGS_VERIFY) {
if (shim_fabsl(gammanew - GAMMA) > 1.0e-5L) {
pr_fail("%s: calculation of Euler-Mascheroni "
"constant not as accurate as expected\n", name);
return EXIT_FAILURE;
}
if (k > 80000.0L) {
pr_fail("%s: calculation of Euler-Mascheroni "
"constant took more iterations than "
"expected\n", name);
return EXIT_FAILURE;
}
}
return EXIT_SUCCESS;
}
* stress_cpu_correlate()
*
* Introduction to Signal Processing,
* Prentice-Hall, 1995, ISBN: 0-13-209172-0.
*/
static int OPTIMIZE3 stress_cpu_correlate(const char *name)
{
size_t i, j;
double data_average = 0.0;
static double data[CORRELATE_DATA_LEN];
static double corr[CORRELATE_LEN + 1];
(void)name;
for (i = 0; i < CORRELATE_DATA_LEN; i++) {
const uint64_t r = stress_mwc64();
data[i] = (double)r;
data_average += data[i];
}
data_average /= (double)CORRELATE_DATA_LEN;
for (i = 0; i <= CORRELATE_LEN; i++) {
corr[i] = 0.0;
for (j = 0; j < CORRELATE_DATA_LEN - i; j++) {
corr[i] += (data[i + j] - data_average) *
(data[j] - data_average);
}
corr[i] /= (double)CORRELATE_LEN;
stress_double_put(corr[i]);
}
return EXIT_SUCCESS;
}
* stress_cpu_sieve()
* slightly optimised Sieve of Eratosthenes
*/
static int OPTIMIZE3 stress_cpu_sieve(const char *name)
{
const double dsqrt = shim_sqrt(SIEVE_SIZE);
const uint32_t nsqrt = (uint32_t)dsqrt;
static uint32_t sieve[(SIEVE_SIZE + 31) / 32];
uint32_t i, j;
(void)shim_memset(sieve, 0xff, sizeof(sieve));
for (i = 2; i < nsqrt; i++)
if (STRESS_GETBIT(sieve, i))
for (j = i * i; j < SIEVE_SIZE; j += i)
STRESS_CLRBIT(sieve, j);
PRAGMA_UNROLL_N(8)
for (j = 0, i = 2; i < SIEVE_SIZE; i++) {
if (STRESS_GETBIT(sieve, i))
j++;
}
if ((g_opt_flags & OPT_FLAGS_VERIFY) && (j != 10000)) {
pr_fail("%s: sieve error detected, number of "
"primes has been miscalculated\n", name);
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
* is_prime()
* return true if n is prime
* http://en.wikipedia.org/wiki/Primality_test
*/
static inline PURE OPTIMIZE3 ALWAYS_INLINE uint32_t is_prime(uint32_t n)
{
register uint32_t i, max;
double dsqrt;
if (UNLIKELY(n <= 3))
return n >= 2;
if ((n % 2 == 0) || (n % 3 == 0))
return 0;
dsqrt = shim_sqrt(n);
max = (uint32_t)dsqrt + 1;
for (i = 5; i < max; i += 6)
if ((n % i == 0) || (n % (i + 2) == 0))
return 0;
return 1;
}
* stress_cpu_prime()
*
*/
static int stress_cpu_prime(const char *name)
{
uint32_t i, nprimes = 0;
for (i = 0; i < SIEVE_SIZE; i++) {
nprimes += is_prime(i);
}
if ((g_opt_flags & OPT_FLAGS_VERIFY) && (nprimes != 10000)) {
pr_fail("%s: prime error detected, number of primes "
"has been miscalculated\n", name);
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
* stress_cpu_gray()
* compute gray codes
*/
static int OPTIMIZE3 TARGET_CLONES stress_cpu_gray(const char *name)
{
register uint32_t i;
register uint64_t sum = 0;
for (i = 0; LIKELY(i < 0x10000); i++) {
register uint32_t gray_code;
gray_code = (i >> 1) ^ i;
sum += gray_code;
#if 0
{
register uint32_t mask;
for (mask = gray_code >> 1; mask; mask >>= 1)
gray_code ^= mask;
}
#else
gray_code ^= (gray_code >> 1);
gray_code ^= (gray_code >> 2);
gray_code ^= (gray_code >> 4);
gray_code ^= (gray_code >> 8);
gray_code ^= (gray_code >> 16);
#endif
sum += gray_code;
}
if ((g_opt_flags & OPT_FLAGS_VERIFY) && (sum != 0xffff0000)) {
pr_fail("%s: gray code error detected, sum of gray "
"codes between 0x00000 and 0x10000 miscalculated\n",
name);
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
* hanoi()
* do a Hanoi move
*/
static uint32_t hanoi(
const uint16_t n,
const char p1,
const char p2,
const char p3)
{
if (UNLIKELY(n == 0)) {
return 1;
} else {
uint32_t m = hanoi(n - 1, p1, p3, p2);
m += hanoi(n - 1, p3, p2, p1);
return m;
}
}
* stress_cpu_hanoi
* stress with recursive Towers of Hanoi
*/
static int stress_cpu_hanoi(const char *name)
{
const uint32_t n = hanoi(20, 'X', 'Y', 'Z');
if ((g_opt_flags & OPT_FLAGS_VERIFY) && (n != 1048576)) {
pr_fail("%s: number of hanoi moves different from "
"the expected number\n", name);
return EXIT_FAILURE;
}
stress_uint64_put(n);
return EXIT_SUCCESS;
}
* stress_floatconversion
* exercise conversion to/from different floating point values
*/
static int TARGET_CLONES OPTIMIZE_FAST_MATH stress_cpu_floatconversion(const char *name)
{
float f_sum = 0.0;
double d_sum = 0.0;
long double ld_sum = 0.0L;
register uint32_t i, j_sum = 0;
(void)name;
for (i = 0; i < 65536; i++) {
float f;
double d;
long double ld;
f = (float)i;
d = (double)f;
ld = (long double)d;
f_sum += f;
d_sum += d;
ld_sum += ld;
j_sum += (uint32_t)ld;
f = (float)(double)i;
f_sum += f;
f = (float)(long double)i;
f_sum += f;
f = (float)(double)(long double)i;
f_sum += f;
f = (float)(long double)(double)i;
f_sum += f;
d = (double)(long double)f;
d_sum += d;
d = (double)(float)f;
d_sum += d;
d = (double)(long double)(float)f;
d_sum += d;
d = (double)(float)(long double)f;
d_sum += d;
ld = (long double)(float)d;
ld_sum += ld;
ld = (long double)(double)d;
ld_sum += ld;
ld = (long double)(float)(double)d;
ld_sum += ld;
ld = (long double)(double)(float)d;
ld_sum += ld;
}
stress_long_double_put(ld_sum);
stress_double_put(d_sum);
stress_float_put(f_sum);
stress_uint32_put(j_sum);
return EXIT_SUCCESS;
}
* stress_intconversion
* exercise conversion to/from different int values
*/
static int stress_cpu_intconversion(const char *name)
{
int16_t i16_sum = (int16_t)stress_mwc16();
int32_t i32_sum = (int32_t)stress_mwc32();
int64_t i64_sum = (int64_t)stress_mwc64();
register uint32_t i;
(void)name;
for (i = 0; i < 65536; i++) {
int16_t i16;
int32_t i32;
int64_t i64;
i16 = (int16_t)i;
i32 = (int32_t)i;
i64 = (int64_t)i;
i16_sum += i16;
i32_sum += i32;
i64_sum += i64;
i16 = -(int16_t)(uint32_t)-(int64_t)(uint64_t)i64_sum;
i16_sum -= i16;
i32 = -(int16_t)(uint32_t)-(int64_t)(uint64_t)i16_sum;
i32_sum -= i32;
i64 = -(int16_t)(uint32_t)-(int64_t)(uint64_t)i32_sum;
i64_sum -= i64;
i16 = -(int16_t)(uint64_t)-(int32_t)(uint64_t)i64_sum;
i16_sum += i16;
i32 = -(int16_t)(uint64_t)-(int32_t)(uint64_t)i16_sum;
i32_sum += i32;
i64 = -(int16_t)(uint64_t)-(int32_t)(uint64_t)i32_sum;
i64_sum += i64;
i16 = (int16_t)-((int32_t)(uint16_t)-(int64_t)(uint64_t)i64_sum);
i16_sum -= i16;
i32 = -(int32_t)(uint16_t)-(int64_t)(uint64_t)i16_sum;
i32_sum -= i32;
i64 = -(int32_t)(uint16_t)-(int64_t)(uint64_t)i32_sum;
i64_sum -= i64;
i16 = (int16_t)-((int32_t)(uint64_t)-(int16_t)(uint64_t)i64_sum);
i16_sum += i16;
i32 = -(int32_t)(uint64_t)-(int16_t)(uint64_t)i16_sum;
i32_sum += i32;
i64 = -(int32_t)(uint64_t)-(int16_t)(uint64_t)i32_sum;
i64_sum += i64;
i16 = (int16_t)-((int64_t)(uint16_t)-(int32_t)(uint64_t)i64_sum);
i16_sum -= i16;
i32 = (int32_t)-((int64_t)(uint16_t)-(int32_t)(uint64_t)i16_sum);
i32_sum -= i32;
i64 = (int64_t)(uint16_t)-(int32_t)(uint64_t)i32_sum;
i64_sum -= i64;
i16 = (int16_t)-((int64_t)(uint32_t)-(int16_t)(uint64_t)i64_sum);
i16_sum += i16;
i32 = (int32_t)-((int64_t)(uint32_t)-(int16_t)(uint64_t)i16_sum);
i32_sum += i32;
i64 = -(int64_t)(uint32_t)-(int16_t)(uint64_t)i32_sum;
i64_sum += i64;
}
stress_uint16_put((uint16_t)i16_sum);
stress_uint32_put((uint32_t)i32_sum);
stress_uint64_put((uint64_t)i64_sum);
return EXIT_SUCCESS;
}
* factorial()
* compute n!
*/
static inline long double PURE OPTIMIZE3 factorial(int n)
{
static const long double factorials[] = {
1.0L,
1.0L,
2.0L,
6.0L,
24.0L,
120.0L,
720.0L,
5040.0L,
40320.0L,
362880.0L,
3628800.0L,
39916800.0L,
479001600.0L,
6227020800.0L,
87178291200.0L,
1307674368000.0L,
20922789888000.0L,
355687428096000.0L,
6402373705728000.0L,
121645100408832000.0L,
2432902008176640000.0L,
51090942171709440000.0L,
1124000727777607680000.0L,
25852016738884976640000.0L,
620448401733239439360000.0L,
15511210043330985984000000.0L,
403291461126605635592388608.0L,
10888869450418352161430700032.0L,
304888344611713860511469666304.0L,
8841761993739701954695181369344.0L,
265252859812191058647452510846976.0L,
8222838654177922818071027836256256.0L,
263130836933693530178272890760200192.0L
};
if (n < (int)SIZEOF_ARRAY(factorials))
return factorials[n];
return shim_roundl(shim_expl(shim_lgammal((long double)(n + 1))));
}
* stress_cpu_pi()
* compute pi using the Srinivasa Ramanujan
* fast convergence algorithm
*/
static int OPTIMIZE3 stress_cpu_pi(const char *name)
{
long double s = 0.0L, pi = 0.0L, last_pi = 0.0L;
const long double precision = 1.0e-20L;
const long double c = 2.0L * shim_sqrtl(2.0L) / 9801.0L;
const int max_iter = 5;
int k = 0;
do {
last_pi = pi;
s += (factorial(4 * k) *
((26390.0L * (long double)k) + 1103)) /
(shim_powl(factorial(k), 4.0L) * shim_powl(396.0L, 4.0L * k));
pi = 1.0 / (s * c);
k++;
} while ((k < max_iter) && (shim_fabsl(pi - last_pi) > precision));
if (g_opt_flags & OPT_FLAGS_VERIFY) {
if (k >= max_iter) {
pr_fail("%s: number of iterations to compute "
"pi was more than expected\n", name);
return EXIT_FAILURE;
}
if (shim_fabsl(pi - PI) > 1.0e-15L) {
pr_fail("%s: accuracy of computed pi is not "
"as good as expected\n", name);
return EXIT_FAILURE;
}
}
stress_long_double_put(pi);
return EXIT_SUCCESS;
}
* stress_cpu_omega()
* compute the constant omega
* See http://en.wikipedia.org/wiki/Omega_constant
*/
static int OPTIMIZE3 OPTIMIZE_FAST_MATH stress_cpu_omega(const char *name)
{
long double omega = 0.5 + ((double)stress_mwc16() * 1.0E-9), last_omega = 0.0L;
const long double precision = 1.0e-20L;
const int max_iter = 6;
int n = 0;
* Omega converges very quickly, on most CPUs it is
* within 6 iterations.
*/
do {
last_omega = omega;
omega = (1.0L + omega) / (1.0L + shim_expl(omega));
n++;
} while ((n < max_iter) && (shim_fabsl(omega - last_omega) > precision));
if (g_opt_flags & OPT_FLAGS_VERIFY) {
if (n > max_iter) {
pr_fail("%s: number of iterations to compute "
"omega was more than expected (%d vs %d)\n",
name, n, max_iter);
return EXIT_FAILURE;
}
if (shim_fabsl(omega - OMEGA) > 1.0e-16L) {
pr_fail("%s: accuracy of computed omega is "
"not as good as expected\n", name);
return EXIT_FAILURE;
}
}
stress_long_double_put(omega);
return EXIT_SUCCESS;
}
#define HAMMING(G, i, nybble, code) \
do { \
int8_t res; \
\
res = (((G[3] >> i) & (nybble >> 3)) & 1) ^ \
(((G[2] >> i) & (nybble >> 2)) & 1) ^ \
(((G[1] >> i) & (nybble >> 1)) & 1) ^ \
(((G[0] >> i) & (nybble >> 0)) & 1); \
code ^= ((res & 1) << i); \
} while (0)
* hamming84()
* compute Hamming (8,4) codes
*/
static uint8_t PURE OPTIMIZE3 hamming84(const uint8_t nybble)
{
* Hamming (8,4) Generator matrix
* (4 parity bits, 4 data bits)
*
* p1 p2 p3 p4 d1 d2 d3 d4
* 0 1 1 1 1 0 0 0
* 1 0 1 1 0 1 0 0
* 1 1 0 1 0 0 1 0
* 1 1 1 0 0 0 0 1
*
* Where:
* d1..d4 = 4 data bits
* p1..p4 = 4 parity bits:
* p1 = d2 + d3 + d4
* p2 = d1 + d3 + d4
* p3 = d1 + d2 + d4
* p4 = d1 + d2 + d3
*
* G[] is reversed to turn G[3-j] into G[j] to save a subtraction
*/
static const uint8_t G[] = {
0xf1,
0xd2,
0xb4,
0x78,
};
register uint8_t code = 0;
HAMMING(G, 7, nybble, code);
HAMMING(G, 6, nybble, code);
HAMMING(G, 5, nybble, code);
HAMMING(G, 4, nybble, code);
HAMMING(G, 3, nybble, code);
HAMMING(G, 2, nybble, code);
HAMMING(G, 1, nybble, code);
HAMMING(G, 0, nybble, code);
return code;
}
* stress_cpu_hamming()
* compute hamming code on 65536 x 4 nybbles
*/
static int OPTIMIZE3 TARGET_CLONES stress_cpu_hamming(const char *name)
{
uint32_t i;
uint32_t sum = 0;
for (i = 0; i < 65536; i++) {
register const uint32_t encoded =
(uint32_t)(hamming84((i >> 12) & 0xf) << 24) |
(uint32_t)(hamming84((i >> 8) & 0xf) << 16) |
(uint32_t)(hamming84((i >> 4) & 0xf) << 8) |
(uint32_t)(hamming84((i >> 0) & 0xf) << 0);
sum += encoded;
}
if ((g_opt_flags & OPT_FLAGS_VERIFY) && (sum != 0xffff8000)) {
pr_fail("%s: hamming error detected, sum of 65536 "
"hamming codes not correct\n", name);
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
static ptrdiff_t stress_cpu_callfunc_func(
ssize_t n,
uint64_t u64arg,
uint32_t u32arg,
uint16_t u16arg,
uint8_t u8arg,
uint64_t *p_u64arg,
uint32_t *p_u32arg,
uint16_t *p_u16arg,
uint8_t *p_u8arg)
{
if (LIKELY(n > 0))
return stress_cpu_callfunc_func(n - 1,
u64arg + (uint64_t)u32arg,
u32arg,
u16arg,
u8arg,
p_u64arg,
p_u32arg,
p_u16arg,
p_u8arg);
else
return &u64arg - p_u64arg;
}
* stress_cpu_callfunc()
* deep function calls
*/
static int stress_cpu_callfunc(const char *name)
{
uint64_t u64arg = stress_mwc64();
uint32_t u32arg = stress_mwc32();
uint16_t u16arg = stress_mwc16();
uint8_t u8arg = stress_mwc8();
ptrdiff_t ret;
(void)name;
ret = stress_cpu_callfunc_func(1024,
u64arg, u32arg, u16arg, u8arg,
&u64arg, &u32arg, &u16arg, &u8arg);
stress_uint64_put((uint64_t)ret);
return EXIT_SUCCESS;
}
#define P2(n) n, n^1, n^1, n
#define P4(n) P2(n), P2(n^1), P2(n^1), P2(n)
#define P6(n) P4(n), P4(n^1), P4(n^1), P4(n)
static const bool stress_cpu_parity_table[256] = {
P6(0), P6(1), P6(1), P6(0)
};
* stress_cpu_parity
* compute parity different ways
*/
static int stress_cpu_parity(const char *name)
{
uint32_t val = 0x83fb5acf;
size_t i;
for (i = 0; i < 1000; i++, val++) {
register uint32_t parity, p;
uint32_t v;
union {
uint32_t v32;
uint8_t v8[4];
} u;
* Naive way
*/
v = val;
parity = 0;
while (v) {
if (v & 1)
parity = !parity;
v >>= 1;
}
* Naive way with Brian Kernigan's bit counting optimisation
* https://graphics.stanford.edu/~seander/bithacks.html
*/
v = val;
p = 0;
while (v) {
p = !p;
v = v & (v - 1);
}
if ((g_opt_flags & OPT_FLAGS_VERIFY) && (p != parity)) {
pr_fail("%s: parity error detected, using "
"optimised naive method\n", name);
return EXIT_FAILURE;
}
* "Compute parity of a word with a multiply"
* the Andrew Shapira method,
* https://graphics.stanford.edu/~seander/bithacks.html
*/
v = val;
v ^= v >> 1;
v ^= v >> 2;
v = (v & 0x11111111U) * 0x11111111U;
p = (v >> 28) & 1;
if ((g_opt_flags & OPT_FLAGS_VERIFY) && (p != parity)) {
pr_fail("%s: parity error detected, using the "
"multiply Shapira method\n", name);
return EXIT_FAILURE;
}
* "Compute parity in parallel"
* https://graphics.stanford.edu/~seander/bithacks.html
*/
v = val;
v ^= v >> 16;
v ^= v >> 8;
v ^= v >> 4;
v &= 0xf;
p = (0x6996 >> v) & 1;
if ((g_opt_flags & OPT_FLAGS_VERIFY) && (p != parity)) {
pr_fail("%s: parity error detected, using "
"the parallel method\n", name);
return EXIT_FAILURE;
}
* "Compute parity by lookup table"
* https://graphics.stanford.edu/~seander/bithacks.html
* Variation #1
*/
v = val;
v ^= v >> 16;
v ^= v >> 8;
p = stress_cpu_parity_table[v & 0xff];
if ((g_opt_flags & OPT_FLAGS_VERIFY) && (p != parity)) {
pr_fail("%s: parity error detected, using "
"the lookup method, variation 1\n", name);
return EXIT_FAILURE;
}
* "Compute parity by lookup table"
* https://graphics.stanford.edu/~seander/bithacks.html
* Variation #2
*/
u.v32 = val;
p = stress_cpu_parity_table[u.v8[0] ^ u.v8[1] ^ u.v8[2] ^ u.v8[3]];
if ((g_opt_flags & OPT_FLAGS_VERIFY) && (p != parity)) {
pr_fail("%s: parity error detected, using the "
"lookup method, variation 2\n", name);
return EXIT_FAILURE;
}
#if defined(HAVE_BUILTIN_PARITY)
* Compute parity using built-in function
*/
p = (uint32_t)__builtin_parity((unsigned int)val);
if ((g_opt_flags & OPT_FLAGS_VERIFY) && (p != parity)) {
pr_fail("%s: parity error detected, using "
"the __builtin_parity function\n", name);
return EXIT_FAILURE;
}
#endif
}
return EXIT_SUCCESS;
}
* stress_cpu_dither
* perform 8 bit to 1 bit gray scale
* Floyd-Steinberg dither
*/
static int TARGET_CLONES stress_cpu_dither(const char *name)
{
size_t x, y;
(void)name;
* Generate some random 8 bit image
*/
for (y = 0; y < STRESS_CPU_DITHER_Y; y += 8) {
PRAGMA_UNROLL_N(8)
for (x = 0; x < STRESS_CPU_DITHER_X; x ++) {
register uint32_t v1, v2;
v1 = stress_mwc32();
pixels[x][y + 0] = (uint8_t)v1;
v1 >>= 8;
pixels[x][y + 1] = (uint8_t)v1;
v1 >>= 8;
pixels[x][y + 2] = (uint8_t)v1;
v1 >>= 8;
pixels[x][y + 3] = (uint8_t)v1;
v2 = stress_mwc32();
pixels[x][y + 4] = (uint8_t)v2;
v2 >>= 8;
pixels[x][y + 5] = (uint8_t)v2;
v2 >>= 8;
pixels[x][y + 6] = (uint8_t)v2;
v2 >>= 8;
pixels[x][y + 7] = (uint8_t)v2;
}
}
* ..and dither
*/
for (y = 0; y < STRESS_CPU_DITHER_Y; y++) {
for (x = 0; x < STRESS_CPU_DITHER_X; x++) {
const uint8_t pixel = pixels[x][y];
const uint8_t quant = (pixel < 128) ? 0 : 255;
const int32_t error = pixel - quant;
const bool xok1 = x < (STRESS_CPU_DITHER_X - 1);
const bool xok2 = x > 0;
const bool yok1 = y < (STRESS_CPU_DITHER_Y - 1);
if (xok1)
pixels[x + 1][y] +=
(error * 7) >> 4;
if (xok2 && yok1)
pixels[x - 1][y + 1] +=
(error * 3) >> 4;
if (yok1)
pixels[x][y + 1] +=
(error * 5) >> 4;
if (xok1 && yok1)
pixels[x + 1][y + 1] +=
error >> 4;
}
}
return EXIT_SUCCESS;
}
* stress_cpu_div8
* perform 50000 x 8 bit divisions, these are traditionally
* slow ops
*/
static int TARGET_CLONES stress_cpu_div8(const char *name)
{
register uint16_t i = 50000, j = 0;
const uint8_t delta = 0xff / 224;
uint8_t sum = 0;
(void)name;
while (i > 0) {
const uint8_t n = (uint8_t)STRESS_MINIMUM(i, 224);
register uint8_t k, l;
for (l = 0, k = 1; l < n; l++, k += delta) {
register uint8_t r = (uint8_t)(j / k);
sum += r;
}
i -= n;
j += delta;
}
stress_uint8_put(sum);
return EXIT_SUCCESS;
}
* stress_cpu_div16
* perform 50000 x 16 bit divisions, these are traditionally
* slow ops
*/
static int TARGET_CLONES stress_cpu_div16(const char *name)
{
register uint16_t i = 50000, j = 0;
const uint16_t delta = 0xffff / 224;
uint16_t sum = 0;
(void)name;
while (i > 0) {
const uint16_t n = STRESS_MINIMUM(i, 224);
register uint16_t k, l;
for (l = 0, k = 1; l < n; l++, k += delta) {
register const uint16_t r = j / k;
sum += r;
}
i -= n;
j += delta;
}
stress_uint16_put(sum);
return EXIT_SUCCESS;
}
* stress_cpu_div32
* perform 50000 x 32 bit divisions, these are traditionally
* slow ops
*/
static int TARGET_CLONES stress_cpu_div32(const char *name)
{
register uint32_t i = 50000, j = 0;
const uint32_t delta = 0xffffffff / 224;
uint32_t sum = 0;
(void)name;
while (i > 0) {
const uint32_t n = STRESS_MINIMUM(i, 224);
register uint32_t k, l;
for (l = 0, k = 1; l < n; l++, k += delta) {
register const uint32_t r = j / k;
sum += r;
}
i -= n;
j += delta;
}
stress_uint32_put(sum);
return EXIT_SUCCESS;
}
* stress_cpu_div64
* perform 50000 x 64 bit divisions, these are traditionally
* slow ops
*/
static int TARGET_CLONES stress_cpu_div64(const char *name)
{
register uint64_t i = 50000, j = 0;
const uint64_t delta = 0xffffffffffffffffULL / 224;
uint64_t sum = 0;
(void)name;
while (i > 0) {
const uint64_t n = STRESS_MINIMUM(i, 224);
register uint64_t k, l;
for (l = 0, k = 1; l < n; l++, k += delta) {
register const uint64_t r = j / k;
sum += r;
}
i -= n;
j += delta;
}
stress_uint64_put(sum);
return EXIT_SUCCESS;
}
#if defined(HAVE_INT128_T)
* stress_cpu_div128
* perform 50000 x 128 bit divisions, these are traditionally
* slow ops
*/
static int TARGET_CLONES stress_cpu_div128(const char *name)
{
register __uint128_t i = 50000, j = 0;
const uint64_t delta64 = 0xffffffffffffffffULL;
const __uint128_t delta = STRESS_UINT128(delta64, delta64) / 224;
__uint128_t sum = 0;
(void)name;
while (i > 0) {
const __uint128_t n = STRESS_MINIMUM(i, 224);
register __uint128_t k, l;
for (l = 0, k = 1; l < n; l++, k += delta) {
register const __uint128_t r = j / k;
sum += r;
}
i -= n;
j += delta;
}
stress_uint64_put((uint64_t)sum);
return EXIT_SUCCESS;
}
#endif
* stress_cpu_union
* perform bit field operations on a union
*/
static int TARGET_CLONES stress_cpu_union(const char *name)
{
typedef union {
struct {
uint64_t b1:1;
uint64_t b10:10;
uint64_t b2:2;
uint64_t b9:9;
uint64_t b3:3;
uint64_t b8:8;
uint64_t b4:4;
uint64_t b7:7;
uint64_t b5:5;
uint64_t b6:6;
} bits64;
uint64_t u64:64;
union {
uint8_t b1:1;
uint8_t b7:7;
uint8_t b8:8;
} bits8;
struct {
uint16_t b15:15;
uint16_t b1:1;
} bits16;
struct {
uint32_t b10:10;
uint32_t b20:20;
#if defined(HAVE_COMPILER_TCC)
uint32_t f:1;
#else
uint32_t :1;
#endif
uint32_t b1:1;
} bits32;
uint32_t u32:30;
} stress_u_t;
static stress_u_t u;
size_t i;
(void)name;
for (i = 0; i < 1000; i++) {
u.bits64.b1 ^= 1;
u.bits64.b2--;
u.bits32.b10 ^= ~0;
u.bits64.b3++;
u.bits16.b1--;
u.bits8.b1++;
u.bits64.b4 *= 2;
u.bits32.b20 += 3;
u.u64 += 0x1037fc2ae21ef829ULL;
u.bits64.b6--;
u.bits8.b7 *= 3;
u.bits64.b5 += (u.bits64.b4 << 1);
u.bits32.b1 ^= 1;
u.bits64.b7++;
* The following operation on .b8 causes an assembler
* warning with pcc:
* "/tmp/ctm.sd7Pfx:12897: Warning: 0xffffffffffffff00 shortened to 0x0"
*/
u.bits8.b8 ^= 0xaa;
u.bits64.b8--;
u.bits16.b15 ^= 0xbeef;
u.bits64.b9++;
u.bits64.b10 *= 5;
u.u32 += 1;
}
return EXIT_SUCCESS;
}
* Solution from http://www.cl.cam.ac.uk/~mr10/backtrk.pdf
* see section 2.1
*/
static uint32_t queens_try(
uint32_t left_diag,
uint32_t cols,
uint32_t right_diag,
uint32_t all)
{
register uint32_t solutions = 0;
register uint32_t poss = ~(left_diag | cols | right_diag) & all;
while (poss) {
register uint32_t inv = -poss;
register uint32_t bit = poss & inv;
register uint32_t new_cols = cols | bit;
poss -= bit;
solutions += (new_cols == all) ?
1 : queens_try((left_diag | bit) << 1,
new_cols, (right_diag | bit) >> 1, all);
}
return solutions;
}
* stress_cpu_queens
* solve the queens problem for sizes 1..11
*/
static int stress_cpu_queens(const char *name)
{
uint32_t all, n;
static const uint32_t queens_solutions[] = {
0, 1, 0, 0, 2, 10, 4, 40, 92, 352, 724, 2680, 14200
};
for (all = 1, n = 1; n < 12; n++) {
const uint32_t solutions = queens_try(0, 0, 0, all);
if ((g_opt_flags & OPT_FLAGS_VERIFY) &&
(solutions != queens_solutions[n])) {
pr_fail("%s: queens solution error detected "
"on board size %" PRIu32 "\n",
name, n);
return EXIT_FAILURE;
}
all = (all + all) + 1;
}
return EXIT_SUCCESS;
}
* stress_cpu_factorial
* find factorials from 1..150 using
* Stirling's and Ramanujan's Approximations.
*/
static int OPTIMIZE_FAST_MATH stress_cpu_factorial(const char *name)
{
int n;
long double f = 1.0L;
const long double precision = 1.0e-6L;
const long double sqrt_pi = shim_sqrtl(PI);
for (n = 1; n < 150; n++) {
const long double np1 = (long double)(n + 1);
long double fact = shim_roundl(shim_expl(shim_lgammal(np1)));
long double dn;
f *= (long double)n;
if ((g_opt_flags & OPT_FLAGS_VERIFY) &&
((f - fact) / fact > precision)) {
pr_fail("%s: Stirling's approximation of factorial(%d) out of range\n",
name, n);
return EXIT_FAILURE;
}
dn = (long double)n;
fact = sqrt_pi * shim_powl((dn / (long double)M_E), dn);
fact *= shim_powl((((((((8 * dn) + 4)) * dn) + 1) * dn) + 1.0L / 30.0L), (1.0L / 6.0L));
if ((g_opt_flags & OPT_FLAGS_VERIFY) &&
((f - fact) / fact > precision)) {
pr_fail("%s: Ramanujan's approximation of factorial(%d) out of range\n",
name, n);
return EXIT_FAILURE;
}
}
return EXIT_SUCCESS;
}
* stress_cpu_stats
* Exercise some standard stats computations on random data
*/
static int stress_cpu_stats(const char *name)
{
size_t i;
double data[STATS_MAX];
double min, max, am = 0.0, gm, hm = 0.0, stddev = 0.0;
int64_t expon = 0;
double mant = 1.0;
const double inverse_n = 1.0 / (double)STATS_MAX;
for (i = 0; i < STATS_MAX; i++)
data[i] = ((double)(stress_mwc32() + 1)) / 4294967296.0;
min = max = data[0];
for (i = 0; i < STATS_MAX; i++) {
int e;
const double d = data[i];
const double f = frexp(d, &e);
mant *= f;
expon += e;
if (min > d)
min = d;
if (max < d)
max = d;
am += d;
hm += 1 / d;
}
am = am / STATS_MAX;
gm = pow(mant, inverse_n) *
pow(2.0, (double)expon * inverse_n);
hm = STATS_MAX / hm;
for (i = 0; i < STATS_MAX; i++) {
const double d = data[i] - am;
stddev += (d * d);
}
stddev = shim_sqrt(stddev);
stress_double_put(am);
stress_double_put(gm);
stress_double_put(hm);
stress_double_put(stddev);
if (min > hm) {
pr_fail("%s: stats: minimum %f > harmonic mean %f\n",
name, min, hm);
return EXIT_FAILURE;
}
if (hm > gm) {
pr_fail("%s: stats: harmonic mean %f > geometric mean %f\n",
name, hm, gm);
return EXIT_FAILURE;
}
if (gm > am) {
pr_fail("%s: stats: geometric mean %f > arithmetic mean %f\n",
name, gm, am);
return EXIT_FAILURE;
}
if (am > max) {
pr_fail("%s: stats: arithmetic mean %f > maximum %f\n",
name, am, max);
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
* stress_cpu_all()
* dummy function, not called
*/
static int OPTIMIZE3 stress_cpu_all(const char *name)
{
(void)name;
return EXIT_SUCCESS;
}
* Table of cpu stress methods
*/
static const stress_cpu_method_info_t stress_cpu_methods[] = {
{ "all", stress_cpu_all, 10000.0 },
{ "ackermann", stress_cpu_ackermann, 2008.64 },
{ "apery", stress_cpu_apery, 9344.95 },
{ "bitops", stress_cpu_bitops, 6573.24 },
{ "callfunc", stress_cpu_callfunc, 1246.34 },
#if defined(HAVE_COMPLEX_H) && \
defined(HAVE_COMPLEX) && \
defined(__STDC_IEC_559_COMPLEX__) &&\
!defined(__UCLIBC__)
{ "cdouble", stress_cpu_complex_double, 8969.40 },
{ "cfloat", stress_cpu_complex_float, 2656.19 },
{ "clongdouble", stress_cpu_complex_long_double, 794.78 },
#else
UNEXPECTED
#endif
{ "collatz", stress_cpu_collatz, 860193.45 },
{ "correlate", stress_cpu_correlate, 216.02 },
{ "crc16", stress_cpu_crc16, 249.93 },
#if defined(HAVE_Decimal32) && \
!defined(HAVE_COMPILER_CLANG)
{ "decimal32", stress_cpu_decimal32, 724.47 },
#endif
#if defined(HAVE_Decimal64) && \
!defined(HAVE_COMPILER_CLANG)
{ "decimal64", stress_cpu_decimal64, 916.39 },
#endif
#if defined(HAVE_Decimal128) && \
!defined(HAVE_COMPILER_CLANG)
{ "decimal128", stress_cpu_decimal128, 330.52 },
#endif
{ "dither", stress_cpu_dither, 234.77 },
{ "div8", stress_cpu_div8, 8815.50 },
{ "div16", stress_cpu_div16, 8843.39 },
{ "div32", stress_cpu_div32, 9937.25 },
{ "div64", stress_cpu_div64, 2833.72 },
#if defined(HAVE_INT128_T)
{ "div128", stress_cpu_div128, 1536.66 },
#endif
{ "double", stress_cpu_double, 11172.11 },
{ "euler", stress_cpu_euler, 26895846.22 },
{ "explog", stress_cpu_explog, 343.85 },
{ "factorial", stress_cpu_factorial, 9474.40 },
{ "fibonacci", stress_cpu_fibonacci, 35976352.02 },
#if defined(HAVE_COMPLEX_H) && \
defined(HAVE_COMPLEX) && \
defined(__STDC_IEC_559_COMPLEX__) &&\
!defined(__UCLIBC__)
{ "fft", stress_cpu_fft, 1516.20 },
#endif
{ "fletcher16", stress_cpu_fletcher16, 650.59 },
{ "float", stress_cpu_float, 11085.77 },
#if defined(HAVE_fp16) && \
!defined(HAVE_COMPILER_CLANG)
{ "float16", stress_cpu_float16, 8885.55 },
#endif
#if defined(HAVE_Float32) && \
!defined(HAVE_COMPILER_CLANG)
{ "float32", stress_cpu_float32, 8885.55 },
#endif
#if defined(HAVE_Float64) && \
!defined(HAVE_COMPILER_CLANG)
{ "float64", stress_cpu_float64, 10582.13},
#endif
#if defined(HAVE__float80) && \
!defined(HAVE_COMPILER_CLANG)
{ "float80", stress_cpu_float80, 1699.80 },
#endif
#if defined(HAVE__float128) && \
!defined(HAVE_COMPILER_CLANG)
{ "float128", stress_cpu_float128, 725.41 },
#elif defined(HAVE_Float128) && \
!defined(HAVE_COMPILER_CLANG)
{ "float128", stress_cpu_float128, 725.41 },
#endif
{ "floatconversion", stress_cpu_floatconversion, 2705.07 },
{ "gamma", stress_cpu_gamma, 492.74 },
{ "gcd", stress_cpu_gcd, 1586.81 },
{ "gray", stress_cpu_gray, 62248.86 },
{ "hamming", stress_cpu_hamming, 1036.58 },
{ "hanoi", stress_cpu_hanoi, 54804.26 },
{ "hyperbolic", stress_cpu_hyperbolic, 1556.08 },
{ "idct", stress_cpu_idct, 71989.07 },
#if defined(HAVE_INT128_T)
{ "int128", stress_cpu_int128, 30658.82 },
#endif
{ "int64", stress_cpu_int64, 61950.47 },
{ "int32", stress_cpu_int32, 65527.15 },
{ "int16", stress_cpu_int16, 65656.46 },
{ "int8", stress_cpu_int8, 65610.66 },
#if defined(HAVE_INT128_T)
{ "int128float", stress_cpu_int128_float, 18312.51 },
{ "int128double", stress_cpu_int128_double, 9798.38 },
{ "int128longdouble", stress_cpu_int128_longdouble, 1397.33 },
#if defined(HAVE_Decimal32) && \
!defined(HAVE_COMPILER_CLANG)
{ "int128decimal32", stress_cpu_int128_decimal32, 1696.86 },
#endif
#if defined(HAVE_Decimal64) && \
!defined(HAVE_COMPILER_CLANG)
{ "int128decimal64", stress_cpu_int128_decimal64, 2242.01 },
#endif
#if defined(HAVE_Decimal128) && \
!defined(HAVE_COMPILER_CLANG)
{ "int128decimal128", stress_cpu_int128_decimal128, 347.19 },
#endif
#endif
{ "int64float", stress_cpu_int64_float, 25297.02 },
{ "int64double", stress_cpu_int64_double, 11390.72 },
{ "int64longdouble", stress_cpu_int64_longdouble, 1399.64 },
{ "int32float", stress_cpu_int32_float, 26033.76 },
{ "int32double", stress_cpu_int32_double, 11617.23 },
{ "int32longdouble", stress_cpu_int32_longdouble, 1408.24 },
{ "intconversion", stress_cpu_intconversion, 1390.75 },
{ "ipv4checksum", stress_cpu_ipv4checksum, 23394.01 },
{ "jmp", stress_cpu_jmp, 122704.94 },
{ "lfsr32", stress_cpu_lfsr32, 52110.43 },
{ "ln2", stress_cpu_ln2, 118136.97 },
{ "logmap", stress_cpu_logmap, 23417.85 },
{ "longdouble", stress_cpu_longdouble, 1801.60 },
{ "loop", stress_cpu_loop, 31424.67 },
{ "matrixprod", stress_cpu_matrix_prod, 263.84 },
{ "nsqrt", stress_cpu_nsqrt, 32783.07 },
{ "omega", stress_cpu_omega, 4038977.72 },
{ "parity", stress_cpu_parity, 30013.93 },
{ "phi", stress_cpu_phi, 20462354.45 },
{ "pi", stress_cpu_pi, 469787.65 },
{ "prime", stress_cpu_prime, 443.99 },
{ "psi", stress_cpu_psi, 6121992.09 },
{ "queens", stress_cpu_queens, 637.03 },
{ "rand", stress_cpu_rand, 16530.45 },
#if defined(HAVE_SRAND48) && \
defined(HAVE_LRAND48) && \
defined(HAVE_DRAND48)
{ "rand48", stress_cpu_rand48, 5037.84 },
#endif
{ "rgb", stress_cpu_rgb, 71888.49 },
{ "sieve", stress_cpu_sieve, 3437.93 },
{ "stats", stress_cpu_stats, 428002.41 },
{ "sqrt", stress_cpu_sqrt, 5821.64 },
{ "trig", stress_cpu_trig, 1200.32 },
{ "union", stress_cpu_union, 30434.40 },
#if defined(HAVE_COMPLEX_H) && \
defined(HAVE_COMPLEX) && \
defined(__STDC_IEC_559_COMPLEX__) &&\
!defined(__UCLIBC__)
{ "zeta", stress_cpu_zeta, 1339.96 },
#endif
};
static double stress_cpu_counter_scale[SIZEOF_ARRAY(stress_cpu_methods)];
static int stress_call_cpu_method(size_t method, stress_args_t *args, double *counter)
{
int rc;
if (method == 0) {
static size_t i = 1;
method = i;
i++;
if (i >= SIZEOF_ARRAY(stress_cpu_methods))
i = 1;
}
rc = stress_cpu_methods[method].func(args->name);
*counter += stress_cpu_counter_scale[method];
stress_bogo_set(args, (uint64_t)*counter);
return rc;
}
* stress_per_cpu_time()
* try to get accurage CPU time from CPUTIME clock,
* or fall back to wall clock time if not possible.
*/
static double stress_per_cpu_time(void)
{
#if defined(CLOCK_PROCESS_CPUTIME_ID)
struct timespec ts;
static bool use_clock_gettime = true;
* Where possible try to get time used on the CPU
* rather than wall clock time to get more accurate
* CPU consumption measurements
*/
if (use_clock_gettime) {
if (clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &ts) == 0) {
return (double)ts.tv_sec + ((double)ts.tv_nsec) / (double)STRESS_NANOSECOND;
} else {
use_clock_gettime = false;
}
}
#endif
* Can't get CPU clock time, fall back to wall clock time
*/
return stress_time_now();
}
* stress_cpu()
* stress CPU by doing floating point math ops
*/
static int OPTIMIZE3 stress_cpu(stress_args_t *args)
{
double bias;
size_t cpu_method = 0;
int32_t cpu_load = 100;
int32_t cpu_load_slice = -64;
double counter = 0.0;
bool cpu_old_metrics = false;
size_t i;
int rc = EXIT_SUCCESS;
stress_catch_sigill();
(void)stress_get_setting("cpu-load-slice", &cpu_load_slice);
(void)stress_get_setting("cpu-old-metrics", &cpu_old_metrics);
(void)stress_get_setting("cpu-method", &cpu_method);
if (stress_get_setting("cpu-load", &cpu_load)) {
if (cpu_method == 0)
pr_inf("%s: for stable load results, select a "
"specific cpu stress method with "
"--cpu-method other than 'all'\n",
args->name);
}
if (cpu_old_metrics) {
for (i = 0; i < SIZEOF_ARRAY(stress_cpu_counter_scale); i++)
stress_cpu_counter_scale[i] = 1.0;
} else {
for (i = 0; i < SIZEOF_ARRAY(stress_cpu_counter_scale); i++)
stress_cpu_counter_scale[i] = 1484.50 / stress_cpu_methods[i].bogo_op_rate;
}
if (stress_instance_zero(args))
pr_dbg("%s: using method '%s'\n", args->name, stress_cpu_methods[cpu_method].name);
* It is unlikely, but somebody may request to do a zero
* load stress test(!)
*/
if (cpu_load == 0) {
(void)sleep((unsigned int)g_opt_timeout);
stress_set_proc_state(args->name, STRESS_STATE_DEINIT);
return EXIT_SUCCESS;
}
stress_set_proc_state(args->name, STRESS_STATE_SYNC_WAIT);
stress_sync_start_wait(args);
stress_set_proc_state(args->name, STRESS_STATE_RUN);
* Normal use case, 100% load, simple spinning on CPU
*/
if (cpu_load == 100) {
stress_cpu_disable_fp_subnormals();
do {
rc = stress_call_cpu_method(cpu_method, args, &counter);
} while ((rc == EXIT_SUCCESS) && stress_continue(args));
stress_cpu_enable_fp_subnormals();
stress_set_proc_state(args->name, STRESS_STATE_DEINIT);
return rc;
}
* More complex percentage CPU utilisation. This is
* not intended to be 100% accurate timing, it is good
* enough for most purposes.
*/
stress_cpu_disable_fp_subnormals();
bias = 0.0;
do {
double delay_cpu_clock, t1_cpu_clock, t2_cpu_clock;
double delay_wall_clock, t1_wall_clock, t2_wall_clock;
double delay;
#if defined(HAVE_SELECT)
struct timeval tv;
#endif
t1_wall_clock = stress_time_now();
t1_cpu_clock = stress_per_cpu_time();
if (cpu_load_slice < 0) {
int j;
for (j = 0; j < -cpu_load_slice; j++) {
rc = stress_call_cpu_method(cpu_method, args, &counter);
if ((rc != EXIT_SUCCESS) || !stress_continue_flag())
break;
}
t2_wall_clock = stress_time_now();
t2_cpu_clock = stress_per_cpu_time();
} else if (cpu_load_slice == 0) {
const uint16_t r = stress_mwc16();
double slice_end = t1_cpu_clock + ((double)r / 131072.0);
do {
rc = stress_call_cpu_method(cpu_method, args, &counter);
t2_wall_clock = stress_time_now();
t2_cpu_clock = stress_per_cpu_time();
if ((rc != EXIT_SUCCESS) || !stress_continue_flag())
break;
} while (t2_cpu_clock < slice_end);
} else {
const double slice_end = t1_cpu_clock + ((double)cpu_load_slice / STRESS_DBL_MILLISECOND);
do {
rc = stress_call_cpu_method(cpu_method, args, &counter);
t2_wall_clock = stress_time_now();
t2_cpu_clock = stress_per_cpu_time();
if ((rc != EXIT_SUCCESS) || !stress_continue_flag())
break;
} while (t2_cpu_clock < slice_end);
}
delay_cpu_clock = t2_cpu_clock - t1_cpu_clock;
delay_wall_clock = t2_wall_clock - t1_wall_clock;
delay = (((100 - cpu_load) * delay_cpu_clock) / (double)cpu_load) + (delay_cpu_clock - delay_wall_clock);
delay -= bias;
if (delay < 0.0) {
bias = 0.0;
} else {
* We need to sleep for a small amount of
* time, measurements need to be based on
* wall clock time and NOT on cpu time used.
*/
double t3_wall_clock;
t2_wall_clock = stress_time_now();
#if defined(HAVE_SELECT)
tv.tv_sec = (time_t)delay;
tv.tv_usec = (long)((delay - (double)tv.tv_sec) * STRESS_DBL_MICROSECOND);
(void)select(0, NULL, NULL, NULL, &tv);
#else
(void)shim_nanosleep_uint64((uint64_t)(delay * STRESS_DBL_NANOSECOND));
#endif
t3_wall_clock = stress_time_now();
bias = (t3_wall_clock - t2_wall_clock) - delay;
}
} while ((rc == EXIT_SUCCESS) && stress_continue(args));
stress_cpu_enable_fp_subnormals();
if (stress_is_affinity_set() && (stress_instance_zero(args))) {
pr_inf("%s: CPU affinity probably set, this can affect CPU loading\n",
args->name);
}
stress_set_proc_state(args->name, STRESS_STATE_DEINIT);
return rc;
}
static const char *stress_cpu_method(const size_t i)
{
return (i < SIZEOF_ARRAY(stress_cpu_methods)) ? stress_cpu_methods[i].name : NULL;
}
static const stress_opt_t opts[] = {
{ OPT_cpu_load, "cpu-load", TYPE_ID_INT32, 0, 100, NULL },
{ OPT_cpu_load_slice, "cpu-load-slice", TYPE_ID_INT32, (uint64_t)-5000, (uint64_t)5000, NULL },
{ OPT_cpu_method, "cpu-method", TYPE_ID_SIZE_T_METHOD, 0, 0, stress_cpu_method },
{ OPT_cpu_old_metrics, "cpu-old-metrics", TYPE_ID_BOOL, 0, 1, NULL },
END_OPT,
};
const stressor_info_t stress_cpu_info = {
.stressor = stress_cpu,
.classifier = CLASS_CPU | CLASS_COMPUTE,
.opts = opts,
.verify = VERIFY_OPTIONAL,
.help = help
};