Compare commits
No commits in common. "2010504e84e0db2245b24afac69838d0d85353b2" and "fd917bffba1f746024a0e5401083ae8b6ea5f685" have entirely different histories.
2010504e84
...
fd917bffba
@ -20,17 +20,6 @@ static std::vector<vec4> make_vecs(int n, unsigned seed)
|
|||||||
return v;
|
return v;
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::vector<vec4> make_points(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), 1.0f });
|
|
||||||
return v;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void BM_Naive_Dot3_Latency(benchmark::State& state)
|
static void BM_Naive_Dot3_Latency(benchmark::State& state)
|
||||||
{
|
{
|
||||||
vec4 a { 1.0f, 2.0f, 3.0f, 0.0f };
|
vec4 a { 1.0f, 2.0f, 3.0f, 0.0f };
|
||||||
@ -101,32 +90,3 @@ static void BM_Naive_FacingSameWay(benchmark::State& state)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
BENCHMARK(BM_Naive_FacingSameWay);
|
BENCHMARK(BM_Naive_FacingSameWay);
|
||||||
|
|
||||||
static void BM_Naive_Dot4_Latency(benchmark::State& state)
|
|
||||||
{
|
|
||||||
vec4 a{ 1.0f, 2.0f, 3.0f, 1.0f };
|
|
||||||
vec4 b{ 0.5f, 0.5f, 0.5f, 0.5f };
|
|
||||||
float acc = 0.0f;
|
|
||||||
for (auto _ : state)
|
|
||||||
{
|
|
||||||
vec4 bb = b + vec4{ acc, 0.0f, 0.0f, 0.0f };
|
|
||||||
float d = dot4(a, bb);
|
|
||||||
acc = d * 1e-7f;
|
|
||||||
benchmark::DoNotOptimize(acc);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
BENCHMARK(BM_Naive_Dot4_Latency);
|
|
||||||
|
|
||||||
static void BM_Naive_Dot4_Throughput(benchmark::State& state)
|
|
||||||
{
|
|
||||||
const auto a = make_points(1024, 1);
|
|
||||||
const auto b = make_points(1024, 2);
|
|
||||||
std::size_t i = 0;
|
|
||||||
for (auto _ : state)
|
|
||||||
{
|
|
||||||
float d = dot4(a[i], b[i]);
|
|
||||||
benchmark::DoNotOptimize(d);
|
|
||||||
i = (i + 1) & 1023;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
BENCHMARK(BM_Naive_Dot4_Throughput);
|
|
||||||
|
|||||||
@ -20,17 +20,6 @@ static std::vector<vec4> make_vecs(int n, unsigned seed)
|
|||||||
return v;
|
return v;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline std::vector<tnvx::vec4> make_points(int n, unsigned seed)
|
|
||||||
{
|
|
||||||
std::mt19937 rng(seed);
|
|
||||||
std::uniform_real_distribution<float> d(-1.0f, 1.0f);
|
|
||||||
std::vector<tnvx::vec4> v;
|
|
||||||
v.reserve(n);
|
|
||||||
for (int i = 0; i < n; ++i)
|
|
||||||
v.push_back(tnvx::vec4{ d(rng), d(rng), d(rng), 1.0f }); // w=1: point
|
|
||||||
return v;
|
|
||||||
}
|
|
||||||
|
|
||||||
// =====================================================================
|
// =====================================================================
|
||||||
// LATENCY: each iteration depends on the previous result (serial chain).
|
// LATENCY: each iteration depends on the previous result (serial chain).
|
||||||
// This is the metric for scattered everyday math: the result is needed
|
// This is the metric for scattered everyday math: the result is needed
|
||||||
@ -144,32 +133,3 @@ static void BM_FacingSameWay(benchmark::State& state)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
BENCHMARK(BM_FacingSameWay);
|
BENCHMARK(BM_FacingSameWay);
|
||||||
|
|
||||||
static void BM_Dot4_Latency(benchmark::State& state)
|
|
||||||
{
|
|
||||||
vec4 a{ 1.0f, 2.0f, 3.0f, 1.0f };
|
|
||||||
vec4 b{ 0.5f, 0.5f, 0.5f, 0.5f };
|
|
||||||
float acc = 0.0f;
|
|
||||||
for (auto _ : state)
|
|
||||||
{
|
|
||||||
vec4 bb = b + vec4{ acc, 0.0f, 0.0f, 0.0f };
|
|
||||||
float d = dot4(a, bb);
|
|
||||||
acc = d * 1e-7f;
|
|
||||||
benchmark::DoNotOptimize(acc);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
BENCHMARK(BM_Dot4_Latency);
|
|
||||||
|
|
||||||
static void BM_Dot4_Throughput(benchmark::State& state)
|
|
||||||
{
|
|
||||||
const auto a = make_points(1024, 1);
|
|
||||||
const auto b = make_points(1024, 2);
|
|
||||||
std::size_t i = 0;
|
|
||||||
for (auto _ : state)
|
|
||||||
{
|
|
||||||
float d = dot4(a[i], b[i]);
|
|
||||||
benchmark::DoNotOptimize(d);
|
|
||||||
i = (i + 1) & 1023;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
BENCHMARK(BM_Dot4_Throughput);
|
|
||||||
|
|||||||
@ -54,11 +54,6 @@ private:
|
|||||||
return a.x() * b.x() + a.y() * b.y() + a.z() * b.z();
|
return a.x() * b.x() + a.y() * b.y() + a.z() * b.z();
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] inline float dot4(vec4 a, vec4 b) noexcept
|
|
||||||
{
|
|
||||||
return a.x() * b.x() + a.y() * b.y() + a.z() * b.z() + a.w() * b.w();
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] inline vec4 cross3(vec4 a, vec4 b) noexcept
|
[[nodiscard]] inline vec4 cross3(vec4 a, vec4 b) noexcept
|
||||||
{
|
{
|
||||||
return {
|
return {
|
||||||
|
|||||||
@ -87,14 +87,6 @@ vf4 dot3(vf4 l, vf4 r) noexcept
|
|||||||
return _mm_shuffle_ps(xyz, xyz, _MM_SHUFFLE(0, 0, 0, 0));
|
return _mm_shuffle_ps(xyz, xyz, _MM_SHUFFLE(0, 0, 0, 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] TNVX_INLINE
|
|
||||||
vf4 dot4(vf4 l, vf4 r) noexcept
|
|
||||||
{
|
|
||||||
vf4 t = _mm_mul_ps(l, r);
|
|
||||||
vf4 h = _mm_hadd_ps(t, t);
|
|
||||||
return _mm_hadd_ps(h, h);
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] TNVX_INLINE
|
[[nodiscard]] TNVX_INLINE
|
||||||
vf4 magnitude3(vf4 v) noexcept
|
vf4 magnitude3(vf4 v) noexcept
|
||||||
{
|
{
|
||||||
|
|||||||
@ -1,43 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include "core.h"
|
|
||||||
#include "expression.h"
|
|
||||||
#include "traits.h"
|
|
||||||
#include "concepts.h"
|
|
||||||
|
|
||||||
namespace tnvx
|
|
||||||
{
|
|
||||||
|
|
||||||
template<vec_expr L, vec_expr R>
|
|
||||||
struct Dot4 : Expr<Dot4<L, R>>
|
|
||||||
{
|
|
||||||
TNVX_INLINE
|
|
||||||
Dot4(const L& TNVX_RESTRICT l, const R& TNVX_RESTRICT r) noexcept;
|
|
||||||
|
|
||||||
[[nodiscard]] TNVX_INLINE
|
|
||||||
vf4 eval() const noexcept;
|
|
||||||
|
|
||||||
[[nodiscard]] TNVX_INLINE
|
|
||||||
operator float() const noexcept;
|
|
||||||
|
|
||||||
private:
|
|
||||||
tnvx_ref_or_value_t<L> _l;
|
|
||||||
tnvx_ref_or_value_t<R> _r;
|
|
||||||
};
|
|
||||||
|
|
||||||
template<vec_expr L, vec_expr R> inline constexpr bool is_scalar_expr<Dot4<L, R>> = true;
|
|
||||||
|
|
||||||
template<vec_expr L, vec_expr R>
|
|
||||||
[[nodiscard]] TNVX_INLINE
|
|
||||||
Dot3<L, R> dot4(const L& l, const R& r) noexcept;
|
|
||||||
|
|
||||||
template<vec_expr L, vec_expr R>
|
|
||||||
TNVX_INLINE
|
|
||||||
Dot3<L, R> dot4(const L& l, const R& r) noexcept
|
|
||||||
{
|
|
||||||
return { l, r };
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#include "dot4_impl.hpp"
|
|
||||||
@ -1,30 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include "dot4.h"
|
|
||||||
|
|
||||||
namespace tnvx
|
|
||||||
{
|
|
||||||
|
|
||||||
template<vec_expr L, vec_expr R>
|
|
||||||
TNVX_INLINE
|
|
||||||
Dot4<L, R>::Dot4(const L& TNVX_RESTRICT l, const R& TNVX_RESTRICT r) noexcept
|
|
||||||
: _l(l)
|
|
||||||
, _r(r)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
template<vec_expr L, vec_expr R>
|
|
||||||
TNVX_INLINE
|
|
||||||
vf4 Dot4<L, R>::eval() const noexcept
|
|
||||||
{
|
|
||||||
return detail::dot4(_l.eval(), _r.eval());
|
|
||||||
}
|
|
||||||
|
|
||||||
template<vec_expr L, vec_expr R>
|
|
||||||
TNVX_INLINE
|
|
||||||
Dot4<L, R>::operator float() const noexcept
|
|
||||||
{
|
|
||||||
return detail::to_float(eval());
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -7,7 +7,6 @@
|
|||||||
#include "expressions/mul.h"
|
#include "expressions/mul.h"
|
||||||
#include "expressions/div.h"
|
#include "expressions/div.h"
|
||||||
#include "expressions/dot3.h"
|
#include "expressions/dot3.h"
|
||||||
#include "expressions/dot4.h"
|
|
||||||
#include "expressions/magnitude3.h"
|
#include "expressions/magnitude3.h"
|
||||||
#include "expressions/norm3.h"
|
#include "expressions/norm3.h"
|
||||||
#include "expressions/cross3.h"
|
#include "expressions/cross3.h"
|
||||||
|
|||||||
@ -283,40 +283,4 @@ TEST(naive_vec4, neg_compound)
|
|||||||
EXPECT_TRUE(approx_eq(a + (-b), a - b));
|
EXPECT_TRUE(approx_eq(a + (-b), a - b));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(naive_vec4, dot4_basic)
|
|
||||||
{
|
|
||||||
vec4 a = { 1.0f, 2.0f, 3.0f, 4.0f };
|
|
||||||
vec4 b = { 1.0f, 2.0f, 3.0f, 4.0f };
|
|
||||||
EXPECT_FLOAT_EQ(dot4(a, b), 30.0f);
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(naive_vec4, dot4_w_matters)
|
|
||||||
{
|
|
||||||
vec4 a = { 1.0f, 2.0f, 3.0f, 4.0f };
|
|
||||||
vec4 b = { 1.0f, 2.0f, 3.0f, 4.0f };
|
|
||||||
EXPECT_FLOAT_EQ(dot3(a, b), 14.0f);
|
|
||||||
EXPECT_FLOAT_EQ(dot4(a, b), 30.0f);
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(naive_vec4, dot4_w_only)
|
|
||||||
{
|
|
||||||
vec4 a = { 0.0f, 0.0f, 0.0f, 5.0f };
|
|
||||||
vec4 b = { 0.0f, 0.0f, 0.0f, 3.0f };
|
|
||||||
EXPECT_FLOAT_EQ(dot4(a, b), 15.0f);
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(naive_vec4, dot4_commutative)
|
|
||||||
{
|
|
||||||
vec4 a = { 1.0f, 2.0f, 3.0f, 4.0f };
|
|
||||||
vec4 b = { 4.0f, 3.0f, 2.0f, 1.0f };
|
|
||||||
EXPECT_FLOAT_EQ(dot4(a, b), dot4(b, a));
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(naive_vec4, dot4_w_zero_matches_dot3)
|
|
||||||
{
|
|
||||||
vec4 a = { 1.0f, 2.0f, 3.0f, 0.0f };
|
|
||||||
vec4 b = { 4.0f, 5.0f, 6.0f, 0.0f };
|
|
||||||
EXPECT_FLOAT_EQ(dot4(a, b), dot3(a, b));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -337,71 +337,4 @@ TEST(vec4, neg_scalar_in_expression)
|
|||||||
EXPECT_TRUE(approx_eq(check, result));
|
EXPECT_TRUE(approx_eq(check, result));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(vec4, dot4_basic)
|
|
||||||
{
|
|
||||||
vec4 a = { 1.0f, 2.0f, 3.0f, 4.0f };
|
|
||||||
vec4 b = { 1.0f, 2.0f, 3.0f, 4.0f };
|
|
||||||
float check = 30.0f;
|
|
||||||
float result = dot4(a, b);
|
|
||||||
|
|
||||||
EXPECT_FLOAT_EQ(check, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(vec4, dot4_w_zero_matches_dot3)
|
|
||||||
{
|
|
||||||
vec4 a = { 1.0f, 2.0f, 3.0f, 0.0f };
|
|
||||||
vec4 b = { 4.0f, 5.0f, 6.0f, 0.0f };
|
|
||||||
|
|
||||||
EXPECT_FLOAT_EQ(float(dot4(a, b)), float(dot3(a, b)));
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(vec4, dot4_w_matters)
|
|
||||||
{
|
|
||||||
vec4 a = { 1.0f, 2.0f, 3.0f, 4.0f };
|
|
||||||
vec4 b = { 1.0f, 2.0f, 3.0f, 4.0f };
|
|
||||||
float check1 = 14.0f;
|
|
||||||
float result1 = dot3(a, b);
|
|
||||||
float check2 = 30.0f;
|
|
||||||
float result2 = dot4(a, b);
|
|
||||||
|
|
||||||
EXPECT_FLOAT_EQ(check1, result1);
|
|
||||||
EXPECT_FLOAT_EQ(check2, result2);
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(vec4, dot4_w_only)
|
|
||||||
{
|
|
||||||
vec4 a = { 0.0f, 0.0f, 0.0f, 5.0f };
|
|
||||||
vec4 b = { 0.0f, 0.0f, 0.0f, 3.0f };
|
|
||||||
float check = 15.0f;
|
|
||||||
float result = dot4(a, b);
|
|
||||||
|
|
||||||
EXPECT_FLOAT_EQ(check, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(vec4, dot4_perpendicular)
|
|
||||||
{
|
|
||||||
vec4 a = { 1.0f, 0.0f, 0.0f, 0.0f };
|
|
||||||
vec4 b = { 0.0f, 1.0f, 0.0f, 0.0f };
|
|
||||||
float check = 0.0f;
|
|
||||||
float result = dot4(a, b);
|
|
||||||
|
|
||||||
EXPECT_FLOAT_EQ(check, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(vec4, dot4_commutative)
|
|
||||||
{
|
|
||||||
vec4 a = { 1.0f, 2.0f, 3.0f, 4.0f };
|
|
||||||
vec4 b = { 4.0f, 3.0f, 2.0f, 1.0f };
|
|
||||||
|
|
||||||
EXPECT_FLOAT_EQ(float(dot4(a, b)), float(dot4(b, a)));
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(vec4, dot4_collapses)
|
|
||||||
{
|
|
||||||
vec4 a = { 1.0f, 0.0f, 0.0f, 0.0f };
|
|
||||||
vec4 b = { 0.0f, 1.0f, 0.0f, 0.0f };
|
|
||||||
|
|
||||||
EXPECT_TRUE((scalar_expr<decltype(dot4(a, b) * 2.0f)>));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user