Skip to content

Instantly share code, notes, and snippets.

@alifahrri
Last active December 29, 2024 03:08
Show Gist options
  • Select an option

  • Save alifahrri/108b549edd7fec5f5480c419539e4ec4 to your computer and use it in GitHub Desktop.

Select an option

Save alifahrri/108b549edd7fec5f5480c419539e4ec4 to your computer and use it in GitHub Desktop.
benchmark code
// run on https://quick-bench.com/
#include <vector>
#include <tuple>
#include <cmath>
#include <type_traits>
template <typename T>
class Vector
{
using data_type = T;
using buffer_type = std::vector<data_type>;
using size_type = size_t;
buffer_type buffer_;
size_type size_;
public:
Vector(size_type size)
{
size_ = size;
buffer_.resize(size);
}
Vector& operator=(const Vector& other)
{
size_ = other.size_;
buffer_.resize(size_);
for (size_t i=0; i<size_; i++) {
buffer_[i] = other.buffer_[i];
}
return *this;
}
Vector operator+(const Vector& other) const
{
Vector result(other.size_);
for (size_t i=0; i<result.size_; i++) {
result.buffer_[i] = this->buffer_[i] + other.buffer_[i];
}
return result;
}
Vector operator*(const Vector& other) const
{
Vector result(other.size_);
for (size_t i=0; i<result.size_; i++) {
result.buffer_[i] = this->buffer_[i] * other.buffer_[i];
}
return result;
}
const T& operator[](size_type i) const
{
return buffer_[i];
}
T& operator[](size_type i)
{
return buffer_[i];
}
size_type size() const
{
return size_;
}
};
struct Add
{
template <typename Lhs, typename Rhs>
auto operator()(const Lhs& lhs, const Rhs& rhs) const noexcept
{
return lhs + rhs;
}
};
struct Mul
{
template <typename Lhs, typename Rhs>
auto operator()(const Lhs& lhs, const Rhs& rhs) const noexcept
{
return lhs * rhs;
}
};
template <typename Op, typename...Operands>
class Expr
{
static constexpr auto Arity = sizeof...(Operands);
using OperandsType = std::tuple<const Operands&...>;
OperandsType operands_;
Op op_;
public:
Expr(const Op op, const Operands&...operands)
: operands_(operands...)
, op_(op)
{}
template <auto...Is>
auto apply(size_t i, std::integer_sequence<size_t,Is...>) const
{
return op_(std::get<Is>(operands_)[i]...);
}
auto operator[](size_t i) const
{
return apply(i,std::make_integer_sequence<size_t,Arity>{});
}
const auto& operands() const
{
return operands_;
}
auto size() const
{
// assume lhs size == rhs size
return std::get<0>(operands_).size();
}
};
template <typename T>
class Vector2
{
using data_type = T;
using buffer_type = std::vector<data_type>;
using size_type = size_t;
buffer_type buffer_;
size_type size_;
public:
Vector2(size_t size)
{
size_ = size;
buffer_.resize(size);
}
template <typename Other>
auto operator+(const Other& rhs) const
{
return Expr<Add,Vector2<T>,Other>(Add(),*this,rhs);
}
template <typename Other>
auto operator*(const Other& rhs) const
{
return Expr<Mul,Vector2<T>,Other>(Mul(),*this,rhs);
}
const T& operator[](size_type i) const
{
return buffer_[i];
}
T& operator[](size_type i)
{
return buffer_[i];
}
size_type size() const
{
return size_;
}
template <typename Other>
auto operator=(const Other& rhs)
{
assert( rhs.size() == this->size() );
for (size_t i=0; i<this->size(); i++) {
(*this)[i] = rhs[i];
}
return *this;
}
};
template <typename T>
void assign_add(Vector<T>& out, const Vector<T>& lhs, const Vector<T>& rhs)
{
auto size = out.size();
for (size_t i=0; i<size; i++) {
out[i] = lhs[i] + rhs[i];
}
}
#define N 1'000'000
static void VectorAddition(benchmark::State& state) {
Vector<float> a(N), b(N), c(N);
for (auto _ : state) {
c = a + b;
benchmark::DoNotOptimize(c);
}
}
BENCHMARK(VectorAddition);
static void VectorAdditionAssign(benchmark::State& state) {
Vector<float> a(N), b(N), c(N);
for (auto _ : state) {
assign_add(c,a,b);
benchmark::DoNotOptimize(c);
}
}
BENCHMARK(VectorAdditionAssign);
static void Vector2Addition(benchmark::State& state) {
Vector2<float> a(N), b(N), c(N);
for (auto _ : state) {
c = a + b;
benchmark::DoNotOptimize(c);
}
}
BENCHMARK(Vector2Addition);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment