Skip to content

Commit

Permalink
lazy vectors ops
Browse files Browse the repository at this point in the history
  • Loading branch information
PhilipDeegan committed Jul 18, 2024
1 parent 3f66327 commit 3f48ac9
Show file tree
Hide file tree
Showing 12 changed files with 369 additions and 50 deletions.
4 changes: 4 additions & 0 deletions .gdbinit
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@

break __assert_fail
break abort
catch throw
4 changes: 2 additions & 2 deletions .github/workflows/build_nix.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,10 @@ jobs:
steps:
- uses: actions/checkout@v2

- name: "Build/Test" # contains slash so use quotes otherwise UB
- name: "Build/Test"
env:
MKN_GCC_PREFERRED: 1
run: |
wget https://github.com/PhilipDeegan/mkn/releases/download/latest/mkn_nix
wget https://github.com/mkn/mkn/releases/download/latest/mkn_nix
chmod +x mkn_nix
KLOG=3 ./mkn_nix clean build run -p test,bench -OtKda "-std=c++17 -fPIC" -l -pthread -g 0
2 changes: 1 addition & 1 deletion LICENSE.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
Copyright (c) 2020, Philip Deegan.
Copyright (c) 2024, Philip Deegan.
All rights reserved.

Redistribution and use in source and binary forms, with or without
Expand Down
2 changes: 0 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,2 @@


# mkn.avx

2 changes: 1 addition & 1 deletion inc/mkn/avx.hpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/**
Copyright (c) 2020, Philip Deegan.
Copyright (c) 2024, Philip Deegan.
All rights reserved.
Redistribution and use in source and binary forms, with or without
Expand Down
8 changes: 5 additions & 3 deletions inc/mkn/avx/def.hpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/**
Copyright (c) 2020, Philip Deegan.
Copyright (c) 2024, Philip Deegan.
All rights reserved.
Redistribution and use in source and binary forms, with or without
Expand Down Expand Up @@ -64,11 +64,13 @@ struct Options
bool static constexpr AVX = __AVX__;
bool static constexpr AVX2 = __AVX2__;

template<typename T, std::uint16_t operands = 2>
auto static constexpr N()
template<typename T, std::uint16_t operands = 1>
std::uint16_t static constexpr N()
{
if constexpr (AVX2)
return 256 / 8 / sizeof(T) / operands;
else if constexpr (AVX)
return 128 / 8 / sizeof(T) / operands;
else
return 1;
}
Expand Down
237 changes: 237 additions & 0 deletions inc/mkn/avx/lazy.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,237 @@
/**
Copyright (c) 2024, Philip Deegan.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
* Neither the name of Philip Deegan nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _MKN_AVX_LAZY_HPP_
#define _MKN_AVX_LAZY_HPP_

#include "mkn/kul/log.hpp"
#include "mkn/kul/alloc.hpp"
#include "mkn/kul/threads.hpp"
#include "mkn/avx/span.hpp"

#include <tuple>
#include <vector>

namespace mkn::avx
{

template<typename T>
struct LazyOp
{
auto constexpr static N = mkn::avx::Options::N<T>();

T* a;
T const* b;
std::size_t op;
std::uint16_t id;

LazyOp* prev = nullptr;
bool marked = false;
};

template<typename T>
struct LazyVal
{
using value_type = T;
using This = LazyVal<T>;

LazyVal(T& t)
: v{&t}
{
}
LazyVal(LazyVal const& that)
: v{that.v}
{
}
LazyVal(LazyVal&&) = default;

auto& operator+=(This const& that) = delete;
auto operator+(This const& that)
{
operands.emplace_back(v, that.v, 0, operands.size());
return *this;
}
auto operator-(This const& that)
{
operands.emplace_back(v, that.v, 1, operands.size());
return *this;
}

auto& operator*=(This const& that) = delete;
auto operator*(This const& that)
{
operands.emplace_back(v, that.v, 2, operands.size());
return *this;
}
auto operator/(This const& that)
{
operands.emplace_back(v, that.v, 3, operands.size());
return *this;
}

auto& operator()() { return *v; }

T* v;
static inline thread_local std::vector<LazyOp<T>> operands;
};

template<typename LazyVal_t>
struct LazyEvaluator
{
using Vec_t = LazyVal_t::value_type;
using T = Vec_t::value_type;
using Span_t = mkn::avx::Span<T>;
using Span_ct = mkn::avx::Span<T const>;
auto constexpr static N = mkn::avx::Options::N<T>(); // max vector size

~LazyEvaluator()
{
tmps.clear();
LazyVal_t::operands.clear();
}

static constexpr inline auto __add__
= [](Span_t& r, Span_ct const& a, Span_ct const& b) mutable { r.add(a, b); };
static constexpr inline auto __sub__
= [](Span_t& r, Span_ct const& a, Span_ct const& b) mutable { r.sub(a, b); };
static constexpr inline auto __mul__
= [](Span_t& r, Span_ct const& a, Span_ct const& b) mutable { r.mul(a, b); };
static constexpr inline auto __div__
= [](Span_t& r, Span_ct const& a, Span_ct const& b) mutable { r.div(a, b); };

void compile()
{
if (not fns.size())
{
fns.emplace_back(__add__);
fns.emplace_back(__sub__);
fns.emplace_back(__mul__);
fns.emplace_back(__div__);
}
tmps.resize(t.operands.size());
for (size_t i = t.operands.size(); i-- > 0;)
{
auto& op = t.operands[i];
for (size_t j = i; j-- > 0;)
{
auto& jop = t.operands[j];
if (jop.marked)
continue;
if (jop.a == op.b)
{
op.prev = &jop;
jop.marked = 1;
break;
}
}
if (op.prev)
continue;
}
}

auto operator()(bool /*in_place*/)
{
compile();
auto const& size = t.operands[0].a->size();
Vec_t ret = t(); // copy

for (std::size_t i = 0; i < size / N; ++i)
{
std::size_t const off = i * N;
assert(off < size);

for (std::size_t o = 0; o < t.operands.size(); ++o)
{
auto const& op = t.operands[o];
bool const use_tmp = op.a != t.v;
Span_ct const a{op.a->data() + off, N};
Span_ct const b{op.b->data() + off, N};
Span_t r{ret.data() + off, N};

if (use_tmp)
{
if (op.prev)
{
Span_ct const pspan{tmps[op.prev->id].data(), N};
Span_t tspan{tmps[o].data(), N};
fns[op.op](tspan, a, pspan);
}
else
{
Span_t tspan{tmps[o].data(), N};
fns[op.op](tspan, a, b);
}
}
else
{
if (op.prev)
{
Span_ct const tspan{tmps[op.prev->id].data(), N};
fns[op.op](r, r, tspan);
}
else
{
fns[op.op](r, r, b);
}
}
}
}

return ret;
}

LazyVal_t& t;
std::vector<std::function<void(Span_t&, Span_ct const&, Span_ct const&)>> fns{};

template<typename E>
using AVXVec = std::vector<E, mkn::kul::AlignedAllocator<E, 32>>;
static inline thread_local AVXVec<std::array<T, N>> tmps{};
};

template<typename T>
auto eval(LazyVal<T>& v, bool in_place = false)
{
return LazyEvaluator<LazyVal<T>>{v}(in_place);
}
template<typename T>
auto eval(LazyVal<T>&& v, bool in_place = false)
{
return LazyEvaluator<LazyVal<T>>{v}(in_place);
}

template<typename... T>
auto lazy(T&... v)
{
return std::make_tuple(LazyVal<T>{v}...);
}

} // namespace mkn::avx

#endif /* _MKN_AVX_LAZY_HPP_ */
Loading

0 comments on commit 3f48ac9

Please sign in to comment.