Add basic benchmark for tenvex
This commit is contained in:
parent
53fe4960e5
commit
a6f937f0be
3
src/benchmarks/bench_main.cpp
Normal file
3
src/benchmarks/bench_main.cpp
Normal file
@ -0,0 +1,3 @@
|
||||
#include <benchmark/benchmark.h>
|
||||
|
||||
BENCHMARK_MAIN();
|
||||
135
src/benchmarks/bench_vec4.cpp
Normal file
135
src/benchmarks/bench_vec4.cpp
Normal file
@ -0,0 +1,135 @@
|
||||
#include "tenvex.h"
|
||||
|
||||
#include <benchmark/benchmark.h>
|
||||
|
||||
#include <vector>
|
||||
#include <random>
|
||||
#include <smmintrin.h>
|
||||
|
||||
using namespace tnvx;
|
||||
|
||||
// Runtime data so nothing folds to a compile-time constant.
|
||||
static std::vector<vec4> make_vecs(int n, unsigned seed)
|
||||
{
|
||||
std::mt19937 rng(seed);
|
||||
std::uniform_real_distribution<float> d(-1.0f, 1.0f);
|
||||
std::vector<vec4> v;
|
||||
v.reserve(n);
|
||||
for (int i = 0; i < n; ++i)
|
||||
v.push_back(vec4 { d(rng), d(rng), d(rng), 0.0f });
|
||||
return v;
|
||||
}
|
||||
|
||||
// =====================================================================
|
||||
// LATENCY: each iteration depends on the previous result (serial chain).
|
||||
// This is the metric for scattered everyday math: the result is needed
|
||||
// before moving on.
|
||||
// =====================================================================
|
||||
static void BM_Dot3_Latency(benchmark::State& state)
|
||||
{
|
||||
vec4 a { 1.0f, 2.0f, 3.0f, 0.0f };
|
||||
vec4 b { 0.5f, 0.5f, 0.5f, 0.0f };
|
||||
float acc = 0.0f;
|
||||
for (auto _ : state)
|
||||
{
|
||||
vec4 bb = b + vec4 { acc, 0.0f, 0.0f, 0.0f }; // depends on previous result
|
||||
float d = dot3(a, bb);
|
||||
acc = d * 1e-7f; // feedback = dependency chain
|
||||
benchmark::DoNotOptimize(acc);
|
||||
}
|
||||
}
|
||||
BENCHMARK(BM_Dot3_Latency);
|
||||
|
||||
static void BM_Norm3_Latency(benchmark::State& state)
|
||||
{
|
||||
vec4 v { 1.0f, 2.0f, 3.0f, 1.0f };
|
||||
for (auto _ : state)
|
||||
{
|
||||
v = norm3(v) + vec4 { 1e-3f, 2e-3f, 3e-3f, 0.0f }; // chain through v
|
||||
benchmark::DoNotOptimize(v);
|
||||
}
|
||||
}
|
||||
BENCHMARK(BM_Norm3_Latency);
|
||||
|
||||
// =====================================================================
|
||||
// THROUGHPUT: independent inputs, no cross-iteration dependency, so the
|
||||
// CPU can pipeline. Contrast to latency.
|
||||
// =====================================================================
|
||||
static void BM_Dot3_Throughput(benchmark::State& state)
|
||||
{
|
||||
const auto a = make_vecs(1024, 1);
|
||||
const auto b = make_vecs(1024, 2);
|
||||
std::size_t i = 0;
|
||||
for (auto _ : state)
|
||||
{
|
||||
float d = dot3(a[i], b[i]);
|
||||
benchmark::DoNotOptimize(d);
|
||||
i = (i + 1) & 1023;
|
||||
}
|
||||
}
|
||||
BENCHMARK(BM_Dot3_Throughput);
|
||||
|
||||
// =====================================================================
|
||||
// Compound expression: tenvex vs hand-written intrinsics.
|
||||
// If the numbers are roughly equal, the abstraction is zero-cost.
|
||||
// =====================================================================
|
||||
static void BM_Compound_tenvex(benchmark::State& state)
|
||||
{
|
||||
const auto va = make_vecs(1024, 1);
|
||||
const auto vb = make_vecs(1024, 2);
|
||||
const auto vc = make_vecs(1024, 3);
|
||||
std::size_t i = 0;
|
||||
for (auto _ : state)
|
||||
{
|
||||
vec4 r = norm3(va[i] + vb[i] * 2.0f) * dot3(vb[i], vc[i]) + vc[i] * 3.0f;
|
||||
benchmark::DoNotOptimize(r);
|
||||
i = (i + 1) & 1023;
|
||||
}
|
||||
}
|
||||
BENCHMARK(BM_Compound_tenvex);
|
||||
|
||||
static __m128 dp3_raw(__m128 a, __m128 b) { return _mm_dp_ps(a, b, 0x7F); }
|
||||
|
||||
static __m128 norm3_raw(__m128 v)
|
||||
{
|
||||
__m128 len = _mm_sqrt_ps(dp3_raw(v, v));
|
||||
return _mm_blend_ps(_mm_div_ps(v, len), v, 0b1000);
|
||||
}
|
||||
|
||||
static void BM_Compound_intrinsics(benchmark::State& state)
|
||||
{
|
||||
const auto va = make_vecs(1024, 1);
|
||||
const auto vb = make_vecs(1024, 2);
|
||||
const auto vc = make_vecs(1024, 3);
|
||||
std::size_t i = 0;
|
||||
for (auto _ : state)
|
||||
{
|
||||
__m128 a = va[i].eval(), b = vb[i].eval(), c = vc[i].eval();
|
||||
__m128 t = norm3_raw(_mm_add_ps(a, _mm_mul_ps(b, _mm_set1_ps(2.0f))));
|
||||
__m128 d = dp3_raw(b, c);
|
||||
__m128 r = _mm_add_ps(_mm_mul_ps(t, d), _mm_mul_ps(c, _mm_set1_ps(3.0f)));
|
||||
benchmark::DoNotOptimize(r);
|
||||
i = (i + 1) & 1023;
|
||||
}
|
||||
}
|
||||
BENCHMARK(BM_Compound_intrinsics);
|
||||
|
||||
// =====================================================================
|
||||
// Gameplay-style query: do two units face roughly the same way?
|
||||
// Latency-bound - the answer is needed before branching on it.
|
||||
// =====================================================================
|
||||
static void BM_FacingSameWay(benchmark::State& state)
|
||||
{
|
||||
vec4 fa = norm3(vec4 { 1.0f, 0.0f, 0.2f, 0.0f });
|
||||
vec4 fb = vec4 { 0.9f, 0.1f, 0.1f, 0.0f };
|
||||
float jitter = 0.0f;
|
||||
for (auto _ : state)
|
||||
{
|
||||
vec4 f = norm3(fb + vec4 { jitter, 0.0f, 0.0f, 0.0f });
|
||||
float c = dot3(fa, f);
|
||||
bool same = c > 0.95f;
|
||||
jitter = c * 1e-6f;
|
||||
benchmark::DoNotOptimize(same);
|
||||
}
|
||||
}
|
||||
BENCHMARK(BM_FacingSameWay);
|
||||
Loading…
Reference in New Issue
Block a user