thesis version
This commit is contained in:
5
tests/common.cpp
Normal file
5
tests/common.cpp
Normal file
@ -0,0 +1,5 @@
|
||||
#include "common.h"
|
||||
|
||||
std::size_t _copy{};
|
||||
std::size_t _move{};
|
||||
|
138
tests/common.h
Normal file
138
tests/common.h
Normal file
@ -0,0 +1,138 @@
|
||||
#ifndef ALSK_TESTS_COMMON_H
|
||||
#define ALSK_TESTS_COMMON_H
|
||||
|
||||
#include <numeric>
|
||||
#include <initializer_list>
|
||||
#include <tuple>
|
||||
#include <utility>
|
||||
|
||||
extern std::size_t _copy;
|
||||
extern std::size_t _move;
|
||||
|
||||
template<typename T>
|
||||
struct Measure {
|
||||
using value_type = T;
|
||||
|
||||
T v;
|
||||
|
||||
Measure() = default;
|
||||
explicit Measure(int n): v(n) {}
|
||||
|
||||
Measure(T const& v): v{v} { ++_copy; }
|
||||
Measure(T&& v): v{std::move(v)} { ++_move; }
|
||||
Measure(Measure const& o): v{o.v} { ++_copy; }
|
||||
Measure(Measure&& o): v{std::move(o.v)} { ++_move; }
|
||||
|
||||
Measure& operator=(T const& v) {
|
||||
this->v = v;
|
||||
++_copy;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Measure& operator=(T&& v) {
|
||||
this->v = std::move(v);
|
||||
++_move;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Measure& operator=(Measure const& o) {
|
||||
if(this == &o) return *this;
|
||||
this->v = o.v;
|
||||
++_copy;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Measure& operator=(Measure&& o) {
|
||||
if(this == &o) return *this;
|
||||
this->v = std::move(o.v);
|
||||
++_move;
|
||||
return *this;
|
||||
}
|
||||
|
||||
decltype(auto) begin() const { return v.begin(); }
|
||||
decltype(auto) end() const { return v.end(); }
|
||||
decltype(auto) size() const { return v.size(); }
|
||||
|
||||
decltype(auto) operator[](std::size_t i) const { return v[i]; }
|
||||
decltype(auto) operator[](std::size_t i) { return v[i]; }
|
||||
};
|
||||
|
||||
|
||||
struct Add {
|
||||
template<typename T>
|
||||
T operator()(T const& lhs, T const& rhs) { return lhs+rhs; }
|
||||
};
|
||||
|
||||
struct Mult {
|
||||
template<typename T>
|
||||
T operator()(T const& lhs, T const& rhs) { return lhs*rhs; }
|
||||
};
|
||||
|
||||
struct Div {
|
||||
template<typename T>
|
||||
T operator()(T const& lhs, T const& rhs) { return lhs/rhs; }
|
||||
};
|
||||
|
||||
struct Sqrt {
|
||||
template<typename T>
|
||||
T operator()(T const& lhs) { return sqrt(lhs); }
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct MultC {
|
||||
T m;
|
||||
|
||||
template<typename U>
|
||||
auto operator()(U const& lhs) { return lhs*m; }
|
||||
};
|
||||
|
||||
struct Tupler {
|
||||
template<typename... Ts>
|
||||
auto operator()(Ts const&... values) { return std::make_tuple(values...); }
|
||||
};
|
||||
|
||||
/* for copy/move count test */
|
||||
template<typename Vector>
|
||||
struct MultiplyBy {
|
||||
Vector coeffs;
|
||||
|
||||
MultiplyBy() = default;
|
||||
MultiplyBy(Vector const& coeffs): coeffs{coeffs} {}
|
||||
MultiplyBy(Vector&& coeffs): coeffs{std::move(coeffs)} {}
|
||||
|
||||
int operator()(int v) const {
|
||||
return std::accumulate(std::begin(coeffs), std::end(coeffs), v,
|
||||
[](int a, int b) { return a*b; });
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Vector>
|
||||
struct Process {
|
||||
Vector operator()(int n, int a) const {
|
||||
Vector v(n);
|
||||
for(int i = 0; i < n; ++i)
|
||||
v[i] = a+i;
|
||||
return v;
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Vector>
|
||||
struct ProdVect {
|
||||
void operator()(int& r, Vector const& a, Vector const& b) const {
|
||||
r = 0;
|
||||
for(std::size_t i = 0; i < a.size(); ++i)
|
||||
r += a[i] * b[i];
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Vector>
|
||||
struct Sum {
|
||||
Vector operator()(Vector const& a, Vector const& b) const {
|
||||
Vector r(a.size());
|
||||
for(std::size_t i = 0; i < a.size(); ++i)
|
||||
r[i] = a[i] * b[i];
|
||||
return r;
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
75
tests/copy.cpp
Normal file
75
tests/copy.cpp
Normal file
@ -0,0 +1,75 @@
|
||||
#include <catch.hpp>
|
||||
#include <alsk/alsk.h>
|
||||
#include <numeric>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
using namespace alsk;
|
||||
|
||||
namespace {
|
||||
|
||||
using Data = Measure<int>;
|
||||
|
||||
struct Opv {
|
||||
template<typename... Ts>
|
||||
void operator()(Ts&&...) {}
|
||||
};
|
||||
|
||||
struct Op {
|
||||
template<typename... Ts>
|
||||
Data operator()(Ts&&...) { return {}; }
|
||||
};
|
||||
|
||||
/* NOTE:
|
||||
* `Data const&` causes a copy when then stored in Data
|
||||
* to avoid: simply return `Data` instead or store in `Data&`
|
||||
* hw uses one `auto` to enables this
|
||||
*/
|
||||
struct Opr {
|
||||
template<typename... Ts>
|
||||
Data const& operator()(Data const& a, Ts&&...) { return a; }
|
||||
};
|
||||
|
||||
using Struct = S<Serial, Opv, Op, Opr, Op>;
|
||||
using Links =
|
||||
L<Serial, arg::R<3>(Data const&),
|
||||
void(arg::P<0>),
|
||||
Data(arg::P<0>),
|
||||
Data(arg::R<1> const&),
|
||||
Data(arg::P<0>, arg::R<1> const&, arg::R<2> const&)
|
||||
>;
|
||||
|
||||
using Test = BuildSkeletonT<Struct, Links>;
|
||||
|
||||
void hw(Data const& p0) {
|
||||
Opv{}(p0);
|
||||
decltype(auto) r1 = Op{}(p0);
|
||||
auto r2 = Opr{}(r1);
|
||||
decltype(auto) r3 = Op{}(p0, r1, r2);
|
||||
|
||||
static_cast<void>(r3);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
TEST_CASE("Copy") {
|
||||
std::size_t bCopy, bMove, sCopy, sMove;
|
||||
|
||||
_copy = _move = 0;
|
||||
hw({});
|
||||
bCopy = _copy;
|
||||
bMove = _move;
|
||||
|
||||
auto test = implement<exec::Sequential, Test>();
|
||||
|
||||
_copy = _move = 0;
|
||||
test({});
|
||||
sCopy = _copy;
|
||||
sMove = _move;
|
||||
|
||||
CAPTURE(bCopy);
|
||||
CAPTURE(sCopy);
|
||||
|
||||
REQUIRE(bCopy >= sCopy);
|
||||
REQUIRE(bMove <= sMove);
|
||||
}
|
127
tests/edsl/edsl.cpp
Normal file
127
tests/edsl/edsl.cpp
Normal file
@ -0,0 +1,127 @@
|
||||
#include <catch.hpp>
|
||||
#include <alsk/alsk.h>
|
||||
|
||||
using namespace alsk::arg;
|
||||
using namespace alsk::edsl;
|
||||
|
||||
static int counterDo, counterThen, counterDone;
|
||||
|
||||
struct Do { void operator()() { ++counterDo; } };
|
||||
struct Then { void operator()() { ++counterThen; } };
|
||||
struct Done { void operator()() { ++counterDone; } };
|
||||
|
||||
struct Produce0 { int operator()(int x) { return x+1; } };
|
||||
struct Produce1 { int operator()(int x) { return x-2; } };
|
||||
struct Consume { int operator()(int x, int y) { return x*y; } };
|
||||
|
||||
// TODO? avoid copies so it is truly stateful
|
||||
struct Generate { int value; int operator()(int b) { return ++value+b; } };
|
||||
struct Transform0 { int operator()(int x) { return x+1; } };
|
||||
struct Transform1 { int operator()(int x) { return x-2; } };
|
||||
struct Produce { int operator()(int x, int y) { return x*y; } };
|
||||
struct Select {
|
||||
int mod;
|
||||
int operator()(int a, int b) { if(a%mod == b%mod) return std::min(a, b); return (a%mod > b%mod)? a : b; }
|
||||
};
|
||||
|
||||
TEST_CASE("edsl") {
|
||||
auto aDo = makeOperand<Do>();
|
||||
auto aThen = makeOperand<Then>();
|
||||
auto aDone = makeOperand<Done>();
|
||||
|
||||
auto aProduce0 = makeOperand<Produce0>();
|
||||
auto aProduce1 = makeOperand<Produce1>();
|
||||
auto aConsume = makeOperand<Consume>();
|
||||
|
||||
auto e0 = aDo & (5*aThen) & aDone;
|
||||
using E0 = decltype(e0);
|
||||
using S0 = alsk::S<alsk::Serial, Do, alsk::S<alsk::Farm, Then>, Done>;
|
||||
using L0 = alsk::L<alsk::Serial, void(), void(), alsk::L<alsk::Farm, void(), void()>, void()>;
|
||||
|
||||
auto e1 = 5*(aDo, 2*aThen, aDone);
|
||||
using E1 = decltype(e1);
|
||||
using S1 = alsk::S<alsk::Farm, alsk::S<alsk::Serial, Do, alsk::S<alsk::Farm, Then>, Done>>;
|
||||
using L1 = alsk::L<alsk::Farm, void(), alsk::L<alsk::Serial, void(), void(), alsk::L<alsk::Farm, void(), void()>, void()>>;
|
||||
|
||||
auto e2 = link<R<2>(int)>(
|
||||
link<int(P<0>)>(aProduce0),
|
||||
link<int(P<0>)>(aProduce1),
|
||||
link<int(R<1>, R<0>)>(aConsume)
|
||||
);
|
||||
|
||||
SECTION("Construction") {
|
||||
REQUIRE(std::is_same<E0::Signature, void()>{});
|
||||
REQUIRE(std::is_same<E0::Struct, S0>{});
|
||||
REQUIRE(std::is_same<E0::Links, L0>{});
|
||||
|
||||
REQUIRE(std::is_same<E1::Signature, void()>{});
|
||||
REQUIRE(std::is_same<E1::Struct, S1>{});
|
||||
REQUIRE(std::is_same<E1::Links, L1>{});
|
||||
}
|
||||
|
||||
SECTION("Linking") {
|
||||
{
|
||||
auto f2 = implement<alsk::exec::Sequential>(e2);
|
||||
|
||||
REQUIRE(f2(0) == -2);
|
||||
REQUIRE(f2(2) == 0);
|
||||
REQUIRE(f2(5) == 18);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
SECTION("Setup") {
|
||||
auto f0 = implement<alsk::exec::Sequential>(e0);
|
||||
|
||||
REQUIRE(f0.skeleton.task<1>().n == 5);
|
||||
}
|
||||
|
||||
SECTION("Check run") {
|
||||
{
|
||||
auto f0 = implement<alsk::exec::Sequential>(e0);
|
||||
|
||||
counterDo = counterThen = counterDone = 0;
|
||||
f0();
|
||||
|
||||
REQUIRE(counterDo == 1);
|
||||
REQUIRE(counterThen == 5);
|
||||
REQUIRE(counterDone == 1);
|
||||
}
|
||||
|
||||
{
|
||||
auto f1 = implement<alsk::exec::Sequential>(e1);
|
||||
|
||||
counterDo = counterThen = counterDone = 0;
|
||||
f1();
|
||||
|
||||
REQUIRE(counterDo == 5);
|
||||
REQUIRE(counterThen == 10);
|
||||
REQUIRE(counterDone == 5);
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("Complex case") {
|
||||
auto generate = makeOperand<Generate>();
|
||||
auto transform0 = makeOperand<Transform0>();
|
||||
auto transform1 = makeOperand<Transform1>();
|
||||
auto produce = makeOperand<Produce>();
|
||||
auto select = makeOperand<int(int, int), Select>();
|
||||
|
||||
auto innerTask = link<R<3>(int)>(
|
||||
link<int(P<0>)>(generate),
|
||||
link<int(R<0>)>(transform0),
|
||||
link<int(R<0>)>(transform1),
|
||||
link<int(R<2>, R<1>)>(produce)
|
||||
);
|
||||
auto task = link<int(int)>(10 * link<R<3>(P<0>)>(innerTask)) ->* select;
|
||||
|
||||
auto f = implement<alsk::exec::Sequential>(task);
|
||||
f.skeleton.select.mod = 5;
|
||||
|
||||
REQUIRE(f(4) == 18);
|
||||
REQUIRE(f(5) == 28);
|
||||
REQUIRE(f(6) == 40);
|
||||
REQUIRE(f(7) == 54);
|
||||
REQUIRE(f(8) == 70);
|
||||
}
|
||||
}
|
62
tests/edsl/op/farm.cpp
Normal file
62
tests/edsl/op/farm.cpp
Normal file
@ -0,0 +1,62 @@
|
||||
#include <catch.hpp>
|
||||
#include <alsk/alsk.h>
|
||||
|
||||
using namespace alsk::edsl;
|
||||
|
||||
struct Do { void operator()() { std::puts("Do"); } };
|
||||
|
||||
TEST_CASE("edsl::Farm") {
|
||||
auto aDo = makeOperand<Do>();
|
||||
|
||||
auto e0 = *aDo;
|
||||
using E0 = decltype(e0);
|
||||
using S0 = alsk::S<alsk::Farm, Do>;
|
||||
using L0 = alsk::L<alsk::Farm, void(), void()>;
|
||||
|
||||
auto e1 = 5*aDo;
|
||||
using E1 = decltype(e1);
|
||||
using S1 = alsk::S<alsk::Farm, Do>;
|
||||
using L1 = alsk::L<alsk::Farm, void(), void()>;
|
||||
|
||||
auto e2 = aDo*3;
|
||||
using E2 = decltype(e2);
|
||||
using S2 = alsk::S<alsk::Farm, Do>;
|
||||
using L2 = alsk::L<alsk::Farm, void(), void()>;
|
||||
|
||||
auto e3 = farm(aDo, 3);
|
||||
using E3 = decltype(e3);
|
||||
using S3 = alsk::S<alsk::Farm, Do>;
|
||||
using L3 = alsk::L<alsk::Farm, void(), void()>;
|
||||
|
||||
SECTION("Construction") {
|
||||
REQUIRE(std::is_same<E0::Struct, S0>{});
|
||||
REQUIRE(std::is_same<E0::Links, L0>{});
|
||||
REQUIRE(std::is_same<E0::Signature, void()>{});
|
||||
|
||||
REQUIRE(std::is_same<E1::Struct, S1>{});
|
||||
REQUIRE(std::is_same<E1::Links, L1>{});
|
||||
REQUIRE(std::is_same<E1::Signature, void()>{});
|
||||
|
||||
REQUIRE(std::is_same<E2::Struct, S2>{});
|
||||
REQUIRE(std::is_same<E2::Links, L2>{});
|
||||
REQUIRE(std::is_same<E2::Signature, void()>{});
|
||||
|
||||
REQUIRE(std::is_same<E3::Struct, S3>{});
|
||||
REQUIRE(std::is_same<E3::Links, L3>{});
|
||||
REQUIRE(std::is_same<E3::Signature, void()>{});
|
||||
}
|
||||
|
||||
SECTION("Setup") {
|
||||
auto f0 = implement<alsk::exec::Sequential>(e0);
|
||||
REQUIRE(f0.skeleton.n == 0);
|
||||
|
||||
auto f1 = implement<alsk::exec::Sequential>(e1);
|
||||
REQUIRE(f1.skeleton.n == 5);
|
||||
|
||||
auto f2 = implement<alsk::exec::Sequential>(e2);
|
||||
REQUIRE(f2.skeleton.n == 3);
|
||||
|
||||
auto f3 = implement<alsk::exec::Sequential>(e3);
|
||||
REQUIRE(f3.skeleton.n == 3);
|
||||
}
|
||||
}
|
52
tests/edsl/op/farmsel.cpp
Normal file
52
tests/edsl/op/farmsel.cpp
Normal file
@ -0,0 +1,52 @@
|
||||
#include <catch.hpp>
|
||||
#include <alsk/alsk.h>
|
||||
|
||||
using namespace alsk::edsl;
|
||||
|
||||
struct Generate { int operator()() { return 0; } };
|
||||
struct Select { int operator()(int a, int b) { return std::max(a, b); } };
|
||||
|
||||
TEST_CASE("edsl::FarmSel") {
|
||||
auto generate = makeOperand<int(), Generate>();
|
||||
auto select = makeOperand<int(int, int), Select>();
|
||||
|
||||
auto e0 = (10 * generate) ->* select;
|
||||
using E0 = decltype(e0);
|
||||
using S0 = alsk::S<alsk::FarmSel, Generate, Select>;
|
||||
using L0 = alsk::L<alsk::FarmSel, int(), int(), int(int, int)>;
|
||||
|
||||
auto e1 = link<void(int)>(*generate) ->* select;
|
||||
using E1 = decltype(e1);
|
||||
using S1 = alsk::S<alsk::FarmSel, Generate, Select>;
|
||||
using L1 = alsk::L<alsk::FarmSel, int(int), int(), int(int, int)>;
|
||||
|
||||
auto e2 = farm(generate).select(select);
|
||||
using E2 = decltype(e2);
|
||||
using S2 = alsk::S<alsk::FarmSel, Generate, Select>;
|
||||
using L2 = alsk::L<alsk::FarmSel, int(), int(), int(int, int)>;
|
||||
|
||||
SECTION("Construction") {
|
||||
REQUIRE(std::is_same<E0::Struct, S0>{});
|
||||
REQUIRE(std::is_same<E0::Links, L0>{});
|
||||
REQUIRE(std::is_same<E0::Signature, int()>{});
|
||||
|
||||
REQUIRE(std::is_same<E1::Struct, S1>{});
|
||||
REQUIRE(std::is_same<E1::Links, L1>{});
|
||||
REQUIRE(std::is_same<E1::Signature, int(int)>{});
|
||||
|
||||
REQUIRE(std::is_same<E2::Struct, S2>{});
|
||||
REQUIRE(std::is_same<E2::Links, L2>{});
|
||||
REQUIRE(std::is_same<E2::Signature, int()>{});
|
||||
}
|
||||
|
||||
SECTION("Setup") {
|
||||
auto f0 = implement<alsk::exec::DynamicPool>(e0);
|
||||
REQUIRE(f0.skeleton.n == 10);
|
||||
|
||||
auto f1 = implement<alsk::exec::DynamicPool>(e1);
|
||||
REQUIRE(f1.skeleton.n == 0);
|
||||
|
||||
auto f2 = implement<alsk::exec::DynamicPool>(e2);
|
||||
REQUIRE(f2.skeleton.n == 0);
|
||||
}
|
||||
}
|
52
tests/edsl/op/itersel.cpp
Normal file
52
tests/edsl/op/itersel.cpp
Normal file
@ -0,0 +1,52 @@
|
||||
#include <catch.hpp>
|
||||
#include <alsk/alsk.h>
|
||||
|
||||
using namespace alsk::edsl;
|
||||
|
||||
struct Generate { int operator()() { return 0; } };
|
||||
struct Select { int operator()(int a, int b) { return std::max(a, b); } };
|
||||
|
||||
TEST_CASE("edsl::IterSel") {
|
||||
auto generate = makeOperand<int(), Generate>();
|
||||
auto select = makeOperand<int(int, int), Select>();
|
||||
|
||||
auto e0 = iter(generate, 10).select(select);
|
||||
using E0 = decltype(e0);
|
||||
using S0 = alsk::S<alsk::IterSel, Generate, Select>;
|
||||
using L0 = alsk::L<alsk::IterSel, int(), int(), int(int, int)>;
|
||||
|
||||
auto e1 = &(link<void(int)>(*generate) ->* select);
|
||||
using E1 = decltype(e1);
|
||||
using S1 = alsk::S<alsk::IterSel, Generate, Select>;
|
||||
using L1 = alsk::L<alsk::IterSel, int(int), int(), int(int, int)>;
|
||||
|
||||
auto e2 = seq(link<void(int)>(*generate) ->* select);
|
||||
using E2 = decltype(e2);
|
||||
using S2 = alsk::S<alsk::IterSel, Generate, Select>;
|
||||
using L2 = alsk::L<alsk::IterSel, int(int), int(), int(int, int)>;
|
||||
|
||||
SECTION("Construction") {
|
||||
REQUIRE(std::is_same<E0::Struct, S0>{});
|
||||
REQUIRE(std::is_same<E0::Links, L0>{});
|
||||
REQUIRE(std::is_same<E0::Signature, int()>{});
|
||||
|
||||
REQUIRE(std::is_same<E1::Struct, S1>{});
|
||||
REQUIRE(std::is_same<E1::Links, L1>{});
|
||||
REQUIRE(std::is_same<E1::Signature, int(int)>{});
|
||||
|
||||
REQUIRE(std::is_same<E2::Struct, S2>{});
|
||||
REQUIRE(std::is_same<E2::Links, L2>{});
|
||||
REQUIRE(std::is_same<E2::Signature, int(int)>{});
|
||||
}
|
||||
|
||||
SECTION("Setup") {
|
||||
auto f0 = implement<alsk::exec::DynamicPool>(e0);
|
||||
REQUIRE(f0.skeleton.n == 10);
|
||||
|
||||
auto f1 = implement<alsk::exec::DynamicPool>(e1);
|
||||
REQUIRE(f1.skeleton.n == 0);
|
||||
|
||||
auto f2 = implement<alsk::exec::DynamicPool>(e2);
|
||||
REQUIRE(f2.skeleton.n == 0);
|
||||
}
|
||||
}
|
50
tests/edsl/op/loop.cpp
Normal file
50
tests/edsl/op/loop.cpp
Normal file
@ -0,0 +1,50 @@
|
||||
#include <catch.hpp>
|
||||
#include <alsk/alsk.h>
|
||||
|
||||
using namespace alsk::edsl;
|
||||
|
||||
struct Do { void operator()() { std::puts("Do"); } };
|
||||
|
||||
TEST_CASE("edsl::Loop") {
|
||||
auto aDo = makeOperand<Do>();
|
||||
|
||||
auto e0 = loop(aDo);
|
||||
using E0 = decltype(e0);
|
||||
using S0 = alsk::S<alsk::Loop, Do>;
|
||||
using L0 = alsk::L<alsk::Loop, void(), void()>;
|
||||
|
||||
auto e1 = seq(5*aDo);
|
||||
using E1 = decltype(e1);
|
||||
using S1 = alsk::S<alsk::Loop, Do>;
|
||||
using L1 = alsk::L<alsk::Loop, void(), void()>;
|
||||
|
||||
auto e2 = &(aDo*3);
|
||||
using E2 = decltype(e2);
|
||||
using S2 = alsk::S<alsk::Loop, Do>;
|
||||
using L2 = alsk::L<alsk::Loop, void(), void()>;
|
||||
|
||||
SECTION("Construction") {
|
||||
REQUIRE(std::is_same<E0::Struct, S0>{});
|
||||
REQUIRE(std::is_same<E0::Links, L0>{});
|
||||
REQUIRE(std::is_same<E0::Signature, void()>{});
|
||||
|
||||
REQUIRE(std::is_same<E1::Struct, S1>{});
|
||||
REQUIRE(std::is_same<E1::Links, L1>{});
|
||||
REQUIRE(std::is_same<E1::Signature, void()>{});
|
||||
|
||||
REQUIRE(std::is_same<E2::Struct, S2>{});
|
||||
REQUIRE(std::is_same<E2::Links, L2>{});
|
||||
REQUIRE(std::is_same<E2::Signature, void()>{});
|
||||
}
|
||||
|
||||
SECTION("Setup") {
|
||||
auto f0 = implement<alsk::exec::Sequential>(e0);
|
||||
REQUIRE(f0.skeleton.n == 0);
|
||||
|
||||
auto f1 = implement<alsk::exec::Sequential>(e1);
|
||||
REQUIRE(f1.skeleton.n == 5);
|
||||
|
||||
auto f2 = implement<alsk::exec::Sequential>(e2);
|
||||
REQUIRE(f2.skeleton.n == 3);
|
||||
}
|
||||
}
|
46
tests/edsl/op/operand.cpp
Normal file
46
tests/edsl/op/operand.cpp
Normal file
@ -0,0 +1,46 @@
|
||||
#include <catch.hpp>
|
||||
#include <alsk/alsk.h>
|
||||
|
||||
using namespace alsk::edsl;
|
||||
|
||||
struct A { void operator()() {} };
|
||||
struct B { int operator()(float) { return {}; } };
|
||||
|
||||
void f() {}
|
||||
|
||||
TEST_CASE("edsl::Operand") {
|
||||
SECTION("from function-object") {
|
||||
{
|
||||
auto x = makeOperand<A>();
|
||||
using X = decltype(x);
|
||||
|
||||
REQUIRE(std::is_same<X::Struct, A>{});
|
||||
REQUIRE(std::is_same<X::Links, void()>{});
|
||||
}
|
||||
{
|
||||
auto x = makeOperand<int(alsk::arg::P<0>), B>();
|
||||
using X = decltype(x);
|
||||
|
||||
REQUIRE(std::is_same<X::Struct, B>{});
|
||||
REQUIRE(std::is_same<X::Links, int(alsk::arg::P<0>)>{});
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("from function") {
|
||||
{
|
||||
auto x = alskMakeOperand(f);
|
||||
using X = decltype(x);
|
||||
|
||||
REQUIRE(std::is_same<X::Struct, Fn<void(&)(), f>>{});
|
||||
REQUIRE(std::is_same<X::Links, void()>{});
|
||||
}
|
||||
{
|
||||
using Signature = int const&(&)(int const&, int const&);
|
||||
auto x = makeOperand<Signature, std::min<int>>();
|
||||
using X = decltype(x);
|
||||
|
||||
REQUIRE(std::is_same<X::Struct, Fn<Signature, std::min<int>>>{});
|
||||
REQUIRE(std::is_same<X::Links, int const&(int const&, int const&)>{});
|
||||
}
|
||||
}
|
||||
}
|
37
tests/edsl/op/serial.cpp
Normal file
37
tests/edsl/op/serial.cpp
Normal file
@ -0,0 +1,37 @@
|
||||
#include <catch.hpp>
|
||||
#include <alsk/alsk.h>
|
||||
|
||||
using namespace alsk::edsl;
|
||||
|
||||
struct Do { void operator()() { std::puts("Do"); } };
|
||||
struct Then { void operator()() { std::puts("Then"); } };
|
||||
struct Done { void operator()() { std::puts("Done"); } };
|
||||
|
||||
TEST_CASE("edsl::Serial") {
|
||||
auto aDo = makeOperand<Do>();
|
||||
auto aThen = makeOperand<Then>();
|
||||
auto aDone = makeOperand<Done>();
|
||||
|
||||
using E0 = decltype(aDo & aThen);
|
||||
using E1 = decltype(aDo, aThen, aDone);
|
||||
|
||||
using S0 = alsk::S<alsk::Serial, Do, Then>;
|
||||
using S1 = alsk::S<alsk::Serial, Do, Then, Done>;
|
||||
|
||||
using L0 = alsk::L<alsk::Serial, void(), void(), void()>;
|
||||
using L1 = alsk::L<alsk::Serial, void(), void(), void(), void()>;
|
||||
|
||||
SECTION("Construction") {
|
||||
REQUIRE(std::is_same<E0::Signature, void()>{});
|
||||
REQUIRE(std::is_same<E1::Signature, void()>{});
|
||||
|
||||
REQUIRE(std::is_same<E0::Struct, S0>{});
|
||||
REQUIRE(std::is_same<E1::Struct, S1>{});
|
||||
|
||||
REQUIRE(std::is_same<E0::Links, L0>{});
|
||||
REQUIRE(std::is_same<E1::Links, L1>{});
|
||||
}
|
||||
|
||||
SECTION("Setup") {
|
||||
}
|
||||
}
|
23
tests/edsl/op/while.cpp
Normal file
23
tests/edsl/op/while.cpp
Normal file
@ -0,0 +1,23 @@
|
||||
#include <catch.hpp>
|
||||
#include <alsk/alsk.h>
|
||||
|
||||
using namespace alsk::edsl;
|
||||
|
||||
struct Pred { int n; bool operator()() { return --n; } };
|
||||
struct Do { void operator()() { std::puts("Do"); } };
|
||||
|
||||
TEST_CASE("edsl::While") {
|
||||
auto aPred = makeOperand<bool(), Pred>();
|
||||
auto aDo = makeOperand<Do>();
|
||||
|
||||
auto e0 = while_(aPred).do_(aDo);
|
||||
using E0 = decltype(e0);
|
||||
using S0 = alsk::S<alsk::While, Pred, Do>;
|
||||
using L0 = alsk::L<alsk::While, void(), bool(), void()>;
|
||||
|
||||
SECTION("Construction") {
|
||||
REQUIRE(std::is_same<E0::Struct, S0>{});
|
||||
REQUIRE(std::is_same<E0::Links, L0>{});
|
||||
REQUIRE(std::is_same<E0::Signature, void()>{});
|
||||
}
|
||||
}
|
43
tests/executor/base.cpp
Normal file
43
tests/executor/base.cpp
Normal file
@ -0,0 +1,43 @@
|
||||
#include <catch.hpp>
|
||||
#include <alsk/alsk.h>
|
||||
|
||||
TEST_CASE("ExecutorBase") {
|
||||
alsk::exec::ExecutorBase e;
|
||||
SECTION("Repeatability") {
|
||||
auto& r = e.repeatability;
|
||||
auto const& cl = r.coresList;
|
||||
|
||||
SECTION("upTo") {
|
||||
SECTION("disabled") {
|
||||
r.upTo(0);
|
||||
REQUIRE(cl.empty());
|
||||
|
||||
r.upTo(1);
|
||||
REQUIRE(cl.empty());
|
||||
}
|
||||
|
||||
SECTION("enabled") {
|
||||
for(std::size_t k = 10; k < 20; ++k) {
|
||||
r.upTo(k);
|
||||
REQUIRE(cl.size() == k-1);
|
||||
for(std::size_t i = 0; i < cl.size(); ++i)
|
||||
REQUIRE(cl[i] == 2+i);
|
||||
|
||||
for(std::size_t m = 3; m < 10; ++m) {
|
||||
r.upTo(k, m);
|
||||
REQUIRE(cl.size() == k-m+1);
|
||||
for(std::size_t i = 0; i < cl.size(); ++i)
|
||||
REQUIRE(cl[i] == m+i);
|
||||
|
||||
for(std::size_t s = 2; s < 5; ++s) {
|
||||
r.upTo(k, m, s);
|
||||
REQUIRE(cl.size() == (k-m+1+s-1)/s);
|
||||
for(std::size_t i = 0; i < cl.size(); ++i)
|
||||
REQUIRE(cl[i] == m+i*s);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
161
tests/executor/common.cpp
Normal file
161
tests/executor/common.cpp
Normal file
@ -0,0 +1,161 @@
|
||||
#include <catch.hpp>
|
||||
#include <tmp/debug.h>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
std::atomic_ullong CallCounterV::count{};
|
||||
std::atomic_ullong CallCounterII::count{};
|
||||
|
||||
namespace expar {
|
||||
|
||||
auto buildTestFunction() {
|
||||
auto callCounterv = alsk::edsl::makeOperand<int(), CallCounterV>();
|
||||
auto callCounterii = alsk::edsl::makeOperand<int(int, int), CallCounterII>();
|
||||
|
||||
auto loop = seq(3*callCounterv);
|
||||
auto serial = link<R<0>()>(callCounterv, loop);
|
||||
auto itersel = (callCounterv, &link<int(R<0>)>(5*link<R<0>(int)>(serial)) ->* callCounterii);
|
||||
auto farmsel = link<int()>(7*link<R<1>()>(itersel, callCounterv)) ->* callCounterii;
|
||||
auto farm = 11*farmsel;
|
||||
|
||||
return farm;
|
||||
}
|
||||
|
||||
constexpr auto countV() { return 11 * 7 * (1 + 5 * (1 + 3) + 1); }
|
||||
constexpr auto countII() { return 11 * ((7 - 1) + 7 * 5); }
|
||||
|
||||
constexpr auto maxCores = 11*7 * 64;
|
||||
constexpr std::array<decltype(maxCores), 8> coresList{1, 2, 3, 7, 11*7-1, 11*7, 11*7+1, maxCores};
|
||||
|
||||
}
|
||||
|
||||
namespace exacc {
|
||||
|
||||
auto buildTestFunction() {
|
||||
auto callCounterv = alsk::edsl::makeOperand<int(), CallCounterV>();
|
||||
auto callCounterii = alsk::edsl::makeOperand<int(int, int), CallCounterII>();
|
||||
|
||||
auto loop = seq(3*callCounterv);
|
||||
auto serial = link<R<0>()>(callCounterv, loop);
|
||||
auto itersel = (callCounterv, &link<int(R<0>)>(5*link<R<0>(int)>(serial)) ->* callCounterii);
|
||||
auto farm = link<R<1>()>(7*itersel, callCounterv);
|
||||
auto farmsel = link<int()>(11*farm) ->* callCounterii;
|
||||
|
||||
return farmsel;
|
||||
}
|
||||
|
||||
constexpr auto countV() { return 11 * (7 * (1 + 5 * (1 + 3)) + 1); }
|
||||
constexpr auto countII() { return (11-1) + 11 * 7 * 5; }
|
||||
|
||||
constexpr auto maxCores = 11*7 * 64;
|
||||
constexpr std::array<decltype(maxCores), 8> coresList{1, 2, 3, 7, 11*7-1, 11*7, 11*7+1, maxCores};
|
||||
|
||||
}
|
||||
|
||||
namespace repeatability {
|
||||
|
||||
using PRNG = std::mt19937;
|
||||
int task(PRNG& rng, std::size_t) {
|
||||
std::uniform_int_distribution<int> dist(-100, 100);
|
||||
|
||||
int a = dist(rng);
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(0));
|
||||
int b = dist(rng);
|
||||
|
||||
return a - b;
|
||||
}
|
||||
|
||||
int sel(int a, int b) { return a + b; }
|
||||
|
||||
auto buildTestFunction() {
|
||||
auto etask = alsk::edsl::makeOperand<int(RNG, CtxId), FN(task)>();
|
||||
auto esel = alsk::edsl::makeOperand<int(int, int), FN(sel)>();
|
||||
|
||||
auto loop = seq(3*etask);
|
||||
auto serial = link<R<0>()>(etask, (2*loop));
|
||||
auto farmsel = link<int()>(5*serial) ->* esel;
|
||||
|
||||
return link<R<1>()>(farmsel, farmsel);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
using namespace alsk;
|
||||
|
||||
using Executors = std::tuple<
|
||||
exec::DynamicPool<void>,
|
||||
exec::FirstLevelEqui<void>,
|
||||
exec::FirstLevelGreedy<void>,
|
||||
exec::FirstLevelNoOpti<void>,
|
||||
exec::Sequential<void>,
|
||||
exec::StaticPool<void>,
|
||||
exec::StaticPoolId<void>,
|
||||
exec::StaticThread<void>
|
||||
>;
|
||||
TEMPLATE_LIST_TEST_CASE("Executors", "[executors]", Executors) {
|
||||
CAPTURE(tmp::typeName<TestType>());
|
||||
|
||||
SECTION("executeParallel") {
|
||||
using namespace expar;
|
||||
|
||||
auto e = buildTestFunction();
|
||||
for(auto cores: coresList) {
|
||||
auto f = edsl::implement<GetExecutor<TestType>::template Template>(e);
|
||||
f.executor.cores = cores;
|
||||
|
||||
CallCounterV::count = 0;
|
||||
CallCounterII::count = 0;
|
||||
|
||||
f();
|
||||
|
||||
REQUIRE(CallCounterV::count == countV());
|
||||
REQUIRE(CallCounterII::count == countII());
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("executeParallelAccumulate") {
|
||||
using namespace exacc;
|
||||
|
||||
auto e = buildTestFunction();
|
||||
for(auto cores: coresList) {
|
||||
auto f = edsl::implement<GetExecutor<TestType>::template Template>(e);
|
||||
f.executor.cores = cores;
|
||||
|
||||
CallCounterV::count = 0;
|
||||
CallCounterII::count = 0;
|
||||
|
||||
f();
|
||||
|
||||
REQUIRE(CallCounterV::count == countV());
|
||||
REQUIRE(CallCounterII::count == countII());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEMPLATE_LIST_TEST_CASE("Repeatability", "[executors][repeatability]", Executors) {
|
||||
using namespace repeatability;
|
||||
|
||||
CAPTURE(tmp::typeName<TestType>());
|
||||
|
||||
auto e = buildTestFunction();
|
||||
for(std::size_t upTo: {2, 3, 4, 5, 6, 7, 8}) {
|
||||
CAPTURE(upTo);
|
||||
|
||||
auto f = edsl::implement<GetExecutor<TestType>::template Template>(e);
|
||||
f.executor.repeatability.upTo(upTo);
|
||||
|
||||
f.executor.cores = 1;
|
||||
|
||||
auto expected = f();
|
||||
f.state.context.reset();
|
||||
|
||||
for(std::size_t cores = 2; cores <= upTo; ++cores) {
|
||||
CAPTURE(cores);
|
||||
|
||||
f.executor.cores = cores;
|
||||
|
||||
REQUIRE(f() == expected);
|
||||
f.state.context.reset();
|
||||
}
|
||||
}
|
||||
}
|
21
tests/executor/common.h
Normal file
21
tests/executor/common.h
Normal file
@ -0,0 +1,21 @@
|
||||
#include <alsk/alsk.h>
|
||||
|
||||
using namespace alsk::arg;
|
||||
using alsk::edsl::link;
|
||||
|
||||
template<typename> struct GetExecutor;
|
||||
template<template<typename> class TT, typename Arg>
|
||||
struct GetExecutor<TT<Arg>> {
|
||||
template<typename T>
|
||||
using Template = TT<T>;
|
||||
};
|
||||
|
||||
struct CallCounterV {
|
||||
static std::atomic_ullong count;
|
||||
int operator()() { ++count; return {}; }
|
||||
};
|
||||
|
||||
struct CallCounterII {
|
||||
static std::atomic_ullong count;
|
||||
int operator()(int, int) { ++count; return {}; }
|
||||
};
|
5
tests/executor/dynamicpool.cpp
Normal file
5
tests/executor/dynamicpool.cpp
Normal file
@ -0,0 +1,5 @@
|
||||
#include <catch.hpp>
|
||||
#include "common.h"
|
||||
|
||||
TEST_CASE("DynamicPool") {
|
||||
}
|
5
tests/executor/firstlevel/equi.cpp
Normal file
5
tests/executor/firstlevel/equi.cpp
Normal file
@ -0,0 +1,5 @@
|
||||
#include <catch.hpp>
|
||||
#include "../common.h"
|
||||
|
||||
TEST_CASE("FirstLevelEqui") {
|
||||
}
|
5
tests/executor/firstlevel/greedy.cpp
Normal file
5
tests/executor/firstlevel/greedy.cpp
Normal file
@ -0,0 +1,5 @@
|
||||
#include <catch.hpp>
|
||||
#include "../common.h"
|
||||
|
||||
TEST_CASE("FirstLevelGreedy") {
|
||||
}
|
5
tests/executor/firstlevel/noopti.cpp
Normal file
5
tests/executor/firstlevel/noopti.cpp
Normal file
@ -0,0 +1,5 @@
|
||||
#include <catch.hpp>
|
||||
#include "../common.h"
|
||||
|
||||
TEST_CASE("FirstLevelNoOpti") {
|
||||
}
|
5
tests/executor/sequential.cpp
Normal file
5
tests/executor/sequential.cpp
Normal file
@ -0,0 +1,5 @@
|
||||
#include <catch.hpp>
|
||||
#include "common.h"
|
||||
|
||||
TEST_CASE("Sequential") {
|
||||
}
|
106
tests/farmsel.cpp
Normal file
106
tests/farmsel.cpp
Normal file
@ -0,0 +1,106 @@
|
||||
#include <catch.hpp>
|
||||
|
||||
#include <atomic>
|
||||
#include <alsk/alsk.h>
|
||||
#include <random>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
using namespace alsk;
|
||||
|
||||
TEST_CASE("FarmSel") {
|
||||
constexpr std::size_t n = 1024;
|
||||
|
||||
SECTION("basic test") {
|
||||
using Data = int;
|
||||
|
||||
using Task = std::function<Data()>;
|
||||
using Accu = std::function<Data(Data const&, Data const&)>;
|
||||
|
||||
std::atomic_size_t countTask, countAccu;
|
||||
|
||||
Task task = [&]{
|
||||
++countTask;
|
||||
return 42;
|
||||
};
|
||||
Accu accu = [&](Data const& a, Data const& b) {
|
||||
++countAccu;
|
||||
return std::min(a, b);
|
||||
};
|
||||
|
||||
using Skel = decltype(getSkeleton((*edsl::makeOperand<Data(), Task>()) ->* edsl::makeOperand<Data(Data, Data), Accu>()));
|
||||
|
||||
auto f = implement<exec::FirstLevelEqui, Skel>();
|
||||
f.skeleton.n = n;
|
||||
f.skeleton.task = task;
|
||||
f.skeleton.select = accu;
|
||||
|
||||
countTask = countAccu = 0;
|
||||
|
||||
SECTION("cores = 1") {
|
||||
f.executor.cores = 1;
|
||||
|
||||
Data d = f();
|
||||
REQUIRE(d == 42);
|
||||
REQUIRE(countTask == f.skeleton.n);
|
||||
REQUIRE(countAccu == f.skeleton.n-1);
|
||||
}
|
||||
|
||||
SECTION("cores = 2") {
|
||||
f.executor.cores = 2;
|
||||
|
||||
Data d = f();
|
||||
REQUIRE(d == 42);
|
||||
REQUIRE(countTask == f.skeleton.n);
|
||||
REQUIRE(countAccu == f.skeleton.n-1);
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("repeatability") {
|
||||
using Data = std::tuple<int, std::string>;
|
||||
using RNG = std::mt19937;
|
||||
|
||||
using Task = std::function<Data(RNG&)>;
|
||||
using Accu = std::function<Data(Data const&, Data const&)>;
|
||||
|
||||
std::atomic_size_t countTask, countAccu;
|
||||
|
||||
Task task = [&](RNG& rng) {
|
||||
std::uniform_int_distribution<int> dist{0, 32};
|
||||
std::uniform_int_distribution<int> text{0, n*n};
|
||||
++countTask;
|
||||
return Data{dist(rng), std::to_string(text(rng))};
|
||||
};
|
||||
Accu accu = [&](Data const& a, Data const& b) {
|
||||
++countAccu;
|
||||
return std::get<0>(a) < std::get<0>(b)? a:b;
|
||||
};
|
||||
|
||||
using Struct = S<FarmSel, Task, Accu>;
|
||||
using Links = L<FarmSel, Data(), Data(arg::RNG), Data(Data, Data)>;
|
||||
using Skel = BuildSkeletonT<Struct, Links>;
|
||||
|
||||
auto f = implement<exec::FirstLevelEqui, Skel>();
|
||||
f.skeleton.n = n;
|
||||
f.skeleton.task = task;
|
||||
f.skeleton.select = accu;
|
||||
f.executor.cores = 1;
|
||||
|
||||
Data expected = f();
|
||||
|
||||
countTask = countAccu = 0;
|
||||
|
||||
for(std::size_t k = 1; k <= 2; k *= 2) {
|
||||
SECTION("cores = "+std::to_string(k)) {
|
||||
f.executor.cores = k;
|
||||
|
||||
f.state.context.reset();
|
||||
Data d = f();
|
||||
REQUIRE(std::get<0>(d) == std::get<0>(expected));
|
||||
REQUIRE(std::get<1>(d) == std::get<1>(expected));
|
||||
REQUIRE(countTask == f.skeleton.n);
|
||||
REQUIRE(countAccu == f.skeleton.n-1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
2
tests/main.cpp
Normal file
2
tests/main.cpp
Normal file
@ -0,0 +1,2 @@
|
||||
#define CATCH_CONFIG_MAIN
|
||||
#include <catch.hpp>
|
152
tests/serial.cpp
Normal file
152
tests/serial.cpp
Normal file
@ -0,0 +1,152 @@
|
||||
#include <catch.hpp>
|
||||
#include <alsk/alsk.h>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
using namespace alsk;
|
||||
|
||||
namespace {
|
||||
|
||||
using Vector = Measure<std::vector<int>>;
|
||||
|
||||
using Struct =
|
||||
S<Serial,
|
||||
S<Serial, Mult, Mult, MultC<double>, Add>,
|
||||
MultC<double>,
|
||||
Sqrt,
|
||||
S<Serial, Add, Div>,
|
||||
S<Serial, MultC<double>, Add, Div>,
|
||||
Tupler
|
||||
>;
|
||||
|
||||
using Links =
|
||||
L<Serial, arg::R<5>(double, double, double),
|
||||
L<Serial, arg::R<3>(arg::P<0>, arg::P<1>, arg::P<2>), // a, b, c
|
||||
double(arg::P<1>, arg::P<1>), // b*b
|
||||
double(arg::P<0>, arg::P<2>), // a*c
|
||||
double(arg::R<1>), // a*c*#
|
||||
double(arg::R<0>, arg::R<2>) // b*b + a*c*# = D
|
||||
>,
|
||||
double(arg::P<0>), // a*#
|
||||
double(arg::R<0>), // sqrt(D)
|
||||
L<Serial, arg::R<1>(arg::P<1>, arg::R<2>, arg::R<1>), // b, sqrt(D), a*#
|
||||
double(arg::P<0>, arg::P<1>), // +
|
||||
double(arg::R<0>, arg::P<2>) // ^/(a*#)
|
||||
>,
|
||||
L<Serial, arg::R<2>(arg::P<1>, arg::R<2>, arg::R<1>), // b, sqrt(D), a*#
|
||||
double(arg::P<1>), // sqrt(D)*#
|
||||
double(arg::R<0>, arg::P<0>), // ^+b
|
||||
double(arg::R<1>, arg::P<2>) // ^/(a*#)
|
||||
>,
|
||||
std::tuple<double, double>(arg::R<3>, arg::R<4>)
|
||||
>;
|
||||
|
||||
using Solver = BuildSkeletonT<Struct, Links>;
|
||||
|
||||
constexpr std::initializer_list<int> benchVec1{5, 2, 3, 7, 8, 9, 1, 2, 7, 6, 3, 2, 7};
|
||||
constexpr std::initializer_list<int> benchVec2{2, 2, 3, 5, 2, 1, 1, 4, 7, 9, 2, 3, 5, 6, 1};
|
||||
|
||||
using MultiplyByV = MultiplyBy<Vector>;
|
||||
using ProcessV = Process<Vector>;
|
||||
using SumV = Sum<Vector>;
|
||||
using ProdVectV = ProdVect<Vector>;
|
||||
|
||||
using CMTestStruct = S<Serial, MultiplyByV, MultiplyByV, ProcessV, ProcessV, SumV, ProdVectV>;
|
||||
using CMTestLinks =
|
||||
L<Serial, arg::R<4>(int, int, int, int&),
|
||||
int(arg::P<0>), int(arg::P<1>),
|
||||
Vector(arg::P<2>, arg::R<0>), Vector(arg::P<2>, arg::R<1>),
|
||||
Vector(arg::R<2> const&, arg::R<3> const&),
|
||||
void(arg::P<3>, arg::R<2> const&, arg::R<3> const&)
|
||||
>;
|
||||
|
||||
using CMTest = BuildSkeletonT<CMTestStruct, CMTestLinks>;
|
||||
|
||||
decltype(auto) cmTest(int a, int b, int n, int& r) {
|
||||
decltype(auto) r0 = MultiplyByV{Vector::value_type{benchVec1}}(a);
|
||||
decltype(auto) r1 = MultiplyByV{Vector::value_type{benchVec2}}(b);
|
||||
decltype(auto) r2 = ProcessV{}(n, r0);
|
||||
decltype(auto) r3 = ProcessV{}(n, r1);
|
||||
decltype(auto) r4 = SumV{}(r2, r3);
|
||||
ProdVectV{}(r, r2, r3);
|
||||
return r4;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
TEST_CASE("Serial") {
|
||||
SECTION("basic test") {
|
||||
using F0 = std::function<int()>;
|
||||
using FN = std::function<int(int)>;
|
||||
using FX = std::function<int(int, int)>;
|
||||
|
||||
std::size_t count;
|
||||
|
||||
F0 f0 = [&]{ ++count; return 0; };
|
||||
FN f1 = [&](int v) { ++count; return v+1; };
|
||||
FN f2 = [&](int v) { ++count; return v*2; };
|
||||
FX f3 = [&](int v, int x) { ++count; return v<<x; };
|
||||
|
||||
using Struct = S<Serial, F0, S<Serial, FN, FN>, FX>;
|
||||
using Links = L<Serial, arg::R<2>(int), int(), L<Serial, arg::R<1>(arg::R<0>), int(arg::P<0>), int(arg::R<0>)>, int(arg::R<1>, arg::P<0>)>;
|
||||
using Skel = BuildSkeletonT<Struct, Links>;
|
||||
|
||||
auto f = implement<exec::FirstLevelEqui, Skel>();
|
||||
f.skeleton.task<0>() = f0;
|
||||
f.skeleton.task<1>().task<0>() = f1;
|
||||
f.skeleton.task<1>().task<1>() = f2;
|
||||
f.skeleton.task<2>() = f3;
|
||||
|
||||
count = 0;
|
||||
REQUIRE(f(3) == 16);
|
||||
REQUIRE(count == 4);
|
||||
}
|
||||
|
||||
SECTION("serial") {
|
||||
auto solver = implement<exec::StaticPool, Solver>();
|
||||
solver.skeleton.task<0>().task<2>().m = -4;
|
||||
solver.skeleton.task<1>().m = -2;
|
||||
solver.skeleton.task<4>().task<0>().m = -1;
|
||||
|
||||
double x0 = -2.63;
|
||||
double x1 = 3.77;
|
||||
|
||||
double a = 3.7;
|
||||
double b = -a*(x0+x1);
|
||||
double c = a*x0*x1;
|
||||
|
||||
auto sol = solver(a, b, c);
|
||||
|
||||
REQUIRE(std::get<0>(sol) == Approx{x0});
|
||||
REQUIRE(std::get<1>(sol) == Approx{x1});
|
||||
}
|
||||
|
||||
SECTION("copy/moves") {
|
||||
int a{500}, b{100}, n{1'000}, r;
|
||||
int cpBase, mvBase, cpSkel, mvSkel;
|
||||
|
||||
_copy = _move = 0;
|
||||
cmTest(a, b, n, r);
|
||||
cpBase = _copy;
|
||||
mvBase = _move;
|
||||
|
||||
std::printf("[base] copy: %zu, move: %zu\n", _copy, _move);
|
||||
|
||||
_copy = _move = 0;
|
||||
|
||||
auto cmTestSkel = implement<exec::Sequential, CMTest>();
|
||||
// cmTestSkel(a, b);
|
||||
cmTestSkel.skeleton.task<0>() = MultiplyByV{Vector::value_type{benchVec1}};
|
||||
cmTestSkel.skeleton.task<1>() = MultiplyByV{Vector::value_type{benchVec2}};
|
||||
|
||||
cmTestSkel(a, b, n, r);
|
||||
|
||||
cpSkel = _copy;
|
||||
mvSkel = _move;
|
||||
|
||||
std::printf("[skel] copy: %zu, move: %zu\n", _copy, _move);
|
||||
|
||||
REQUIRE(cpBase >= cpSkel);
|
||||
REQUIRE(mvBase <= mvSkel);
|
||||
}
|
||||
}
|
264
tests/skeleton.cpp
Normal file
264
tests/skeleton.cpp
Normal file
@ -0,0 +1,264 @@
|
||||
#include <catch.hpp>
|
||||
#include <alsk/skeleton/skeleton.h>
|
||||
|
||||
using namespace alsk;
|
||||
using tmp::Pack;
|
||||
|
||||
struct Int {
|
||||
int v;
|
||||
Int(int v): v{v} {}
|
||||
operator int() const { return v; }
|
||||
};
|
||||
|
||||
struct A: Int {};
|
||||
struct B: Int {};
|
||||
struct C: Int {};
|
||||
struct D: Int {};
|
||||
struct E: Int {};
|
||||
struct F: Int {};
|
||||
struct G: Int {};
|
||||
struct H: Int {};
|
||||
struct I: Int {};
|
||||
|
||||
template<typename R>
|
||||
struct Unary {
|
||||
template<typename T>
|
||||
R operator()(T a) { return{a+1}; }
|
||||
};
|
||||
|
||||
template<typename R>
|
||||
struct Binary {
|
||||
template<typename T, typename U>
|
||||
R operator()(T a, U b) { return{a+b}; }
|
||||
};
|
||||
|
||||
template<>
|
||||
struct Binary<void> {
|
||||
template<typename T, typename U>
|
||||
void operator()(T, U) {}
|
||||
};
|
||||
|
||||
using S_ =
|
||||
S<Serial,
|
||||
S<Serial, Unary<D>, Binary<E>>,
|
||||
Unary<F>,
|
||||
S<Serial,
|
||||
Unary<G>,
|
||||
S<Serial, Unary<H>, Binary<void>>,
|
||||
Unary<I>
|
||||
>
|
||||
>;
|
||||
|
||||
using L1 =
|
||||
L<Serial, arg::R<1>(arg::P<1>, arg::P<2>),
|
||||
D(arg::P<1>),
|
||||
E(arg::R<0>, arg::P<0>)
|
||||
>;
|
||||
|
||||
using L2 = F(arg::P<2>);
|
||||
|
||||
using L31 = G(arg::P<0>, arg::P<2>);
|
||||
using L32 =
|
||||
L<Serial, arg::R<0>(arg::R<0>, arg::P<1>),
|
||||
H(arg::P<0>),
|
||||
void(arg::P<0>, arg::P<1>)
|
||||
>;
|
||||
|
||||
using L33 = I(arg::R<0>);
|
||||
|
||||
using L3 =
|
||||
L<Serial, arg::R<2>(arg::R<1>, arg::P<0>, arg::R<0>),
|
||||
L31, L32, L33
|
||||
>;
|
||||
|
||||
using L_ =
|
||||
L<Serial, arg::R<2>(A, B, C),
|
||||
L1, L2, L3
|
||||
>;
|
||||
|
||||
TEST_CASE("LinksToReturnTypes") {
|
||||
REQUIRE(std::is_same<Pack<E>, impl::LinksToReturnTypes<L1>::type>{});
|
||||
REQUIRE(std::is_same<Pack<F>, impl::LinksToReturnTypes<L2>::type>{});
|
||||
REQUIRE(std::is_same<Pack<G>, impl::LinksToReturnTypes<L31>::type>{});
|
||||
REQUIRE(std::is_same<Pack<H>, impl::LinksToReturnTypes<L32>::type>{});
|
||||
REQUIRE(std::is_same<Pack<I>, impl::LinksToReturnTypes<L33>::type>{});
|
||||
REQUIRE(std::is_same<Pack<I>, impl::LinksToReturnTypes<L3>::type>{});
|
||||
REQUIRE(std::is_same<Pack<I>, impl::LinksToReturnTypes<L_>::type>{});
|
||||
|
||||
REQUIRE(std::is_same<Pack<E, F, I>, impl::LinksToReturnTypes<L1, L2, L3>::type>{});
|
||||
}
|
||||
|
||||
using T_ =
|
||||
Serial<arg::R<2>(A, B, C),
|
||||
// 1
|
||||
Fun<Serial<arg::R<1>(B, C),
|
||||
Fun<Unary<D>, D(arg::P<1>)>,
|
||||
Fun<Binary<E>, E(arg::R<0>, arg::P<0>)>
|
||||
>, E(arg::P<1>, arg::P<2>)>,
|
||||
// 2
|
||||
Fun<Unary<F>, F(arg::P<2>)>,
|
||||
// 3
|
||||
Fun<Serial<arg::R<2>(F, A, E),
|
||||
Fun<Unary<G>, G(arg::P<0>, arg::P<2>)>,
|
||||
Fun<Serial<arg::R<0>(G, A),
|
||||
Fun<Unary<H>, H(arg::P<0>)>,
|
||||
Fun<Binary<void>, void(arg::P<0>, arg::P<1>)>
|
||||
>, H(arg::R<0>, arg::P<1>)>,
|
||||
Fun<Unary<I>, I(arg::R<0>)>
|
||||
>, I(arg::R<1>, arg::P<0>, arg::R<0>)>
|
||||
>;
|
||||
|
||||
template<typename...>
|
||||
using TS_ = S_;
|
||||
|
||||
template<typename...>
|
||||
using TL_ = L_;
|
||||
|
||||
TEST_CASE("BuildSkeleton") {
|
||||
using T1 = BuildSkeleton<TS_, TL_>::skeleton<Pack<>, Pack<>>;
|
||||
using T2 = BuildSkeletonT<S_, L_>;
|
||||
|
||||
REQUIRE(std::is_same<T_, T1>{});
|
||||
REQUIRE(std::is_same<T_, T2>{});
|
||||
}
|
||||
|
||||
TEST_CASE("TreeFromSkeleton") {
|
||||
SECTION("simple") {
|
||||
struct F {};
|
||||
|
||||
using Struct = S<Serial, F>;
|
||||
using Links = L<Serial, void(), void()>;
|
||||
using Skel = BuildSkeletonT<Struct, Links>;
|
||||
using Expected =
|
||||
tmp::Tree<
|
||||
Branch<Serial, void ()>,
|
||||
tmp::Tree<Leaf<F, void ()>>
|
||||
>;
|
||||
|
||||
using Result = TreeFromSkeleton<Skel>;
|
||||
|
||||
REQUIRE(std::is_same<Expected, Result>{});
|
||||
}
|
||||
|
||||
SECTION("with links") {
|
||||
struct F {}; struct G {};
|
||||
|
||||
using Struct = S<Serial, S<Serial, F, G>>;
|
||||
using Links = L<Serial, arg::R<0>(int&, int), L<Serial, arg::R<1>(arg::P<1>, arg::P<0>), long(arg::P<1>, arg::P<0>), int(arg::R<0>)>>;
|
||||
using Skel = BuildSkeletonT<Struct, Links>;
|
||||
using Expected =
|
||||
tmp::Tree<
|
||||
Branch<Serial, arg::R<0>(int&, int)>,
|
||||
tmp::Tree<
|
||||
Branch<Serial, arg::R<1>(int, int&), int(arg::P<1>, arg::P<0>)>,
|
||||
tmp::Tree<Leaf<F, long(arg::P<1>, arg::P<0>)>>,
|
||||
tmp::Tree<Leaf<G, int(arg::R<0>)>>
|
||||
>
|
||||
>;
|
||||
|
||||
using Result = TreeFromSkeleton<Skel>;
|
||||
|
||||
REQUIRE(std::is_same<Expected, Result>{});
|
||||
}
|
||||
|
||||
SECTION("complex") {
|
||||
struct A0 {}; struct A1 {}; struct A2 {}; struct A3 {}; struct R {};
|
||||
|
||||
using Struct = S<Serial, A0, S<Farm, S<Serial, A1, A2>>, A0, S<Serial, A3, A3>>;
|
||||
using Links = L<Serial, void(), R(), L<Farm, bool(), L<Serial, char(), short(), int()>>, R(), L<Serial, long(), float(), double()>>;
|
||||
using Skel = BuildSkeletonT<Struct, Links>;
|
||||
using Expected =
|
||||
tmp::Tree<
|
||||
Branch<Serial, void()>,
|
||||
tmp::Tree<Leaf<A0, R()>>,
|
||||
tmp::Tree<
|
||||
Branch<Farm, bool()>,
|
||||
tmp::Tree<
|
||||
Branch<Serial, char()>,
|
||||
tmp::Tree<Leaf<A1, short()>>,
|
||||
tmp::Tree<Leaf<A2, int()>>
|
||||
>
|
||||
>,
|
||||
tmp::Tree<Leaf<A0, R()>>,
|
||||
tmp::Tree<
|
||||
Branch<Serial, long()>,
|
||||
tmp::Tree<Leaf<A3, float()>>,
|
||||
tmp::Tree<Leaf<A3, double()>>
|
||||
>
|
||||
>;
|
||||
|
||||
using Result = TreeFromSkeleton<Skel>;
|
||||
|
||||
REQUIRE(std::is_same<Expected, Result>{});
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("ToSkeleton") {
|
||||
struct A0 {}; struct A1 {}; struct A2 {}; struct A3 {}; struct R {};
|
||||
using Struct = S<Serial, A0, S<Farm, S<Serial, A1, A2>>, A0, S<Serial, A3, A3>>;
|
||||
using Links = L<Serial, void(), R(), L<Farm, bool(), L<Serial, char(), short(), int()>>, R(), L<Serial, long(), float(), double()>>;
|
||||
using Expected = BuildSkeletonT<Struct, Links>;
|
||||
|
||||
using Input =
|
||||
tmp::Tree<
|
||||
Branch<Serial, void()>,
|
||||
tmp::Tree<Leaf<A0, R()>>,
|
||||
tmp::Tree<
|
||||
Branch<Farm, bool()>,
|
||||
tmp::Tree<
|
||||
Branch<Serial, char()>,
|
||||
tmp::Tree<Leaf<A1, short()>>,
|
||||
tmp::Tree<Leaf<A2, int()>>
|
||||
>
|
||||
>,
|
||||
tmp::Tree<Leaf<A0, R()>>,
|
||||
tmp::Tree<
|
||||
Branch<Serial, long()>,
|
||||
tmp::Tree<Leaf<A3, float()>>,
|
||||
tmp::Tree<Leaf<A3, double()>>
|
||||
>
|
||||
>;
|
||||
|
||||
using Result = SkeletonFromTree<Input>;
|
||||
|
||||
REQUIRE(std::is_same<Expected, Result>{});
|
||||
REQUIRE(std::is_same<Expected, SkeletonFromTree<TreeFromSkeleton<Expected>>>{});
|
||||
}
|
||||
|
||||
TEST_CASE("SkeletonParallelHeight") {
|
||||
SECTION("serial") {
|
||||
struct F {}; struct G {};
|
||||
using Struct = S<Serial, S<Serial, F, G>>;
|
||||
using Links = L<Serial, arg::R<0>(int&, int), L<Serial, arg::R<1>(arg::P<1>, arg::P<0>), long(arg::P<1>, arg::P<0>), int(arg::R<0>)>>;
|
||||
using Skel = BuildSkeletonT<Struct, Links>;
|
||||
|
||||
REQUIRE(skeletonParallelHeight<Skel> == 0);
|
||||
}
|
||||
|
||||
SECTION("par2") {
|
||||
struct A0 {}; struct A1 {}; struct A2 {};
|
||||
using Struct = S<Serial, A0, S<Farm, S<Farm, A1>>, S<Farm, A2>>;
|
||||
using Links = L<Serial, int(), int(), L<Farm, int(), L<Farm, int(), int()>>, L<Farm, int(), int()>>;
|
||||
using Skel = BuildSkeletonT<Struct, Links>;
|
||||
|
||||
REQUIRE(skeletonParallelHeight<Skel> == 2);
|
||||
}
|
||||
|
||||
SECTION("par4") {
|
||||
struct A0 {};
|
||||
using Struct = S<Farm, S<Farm, S<Farm, S<Farm, A0>>>>;
|
||||
using Links = L<Farm, int(), L<Farm, int(), L<Farm, int(), L<Farm, int(), int()>>>>;
|
||||
using Skel = BuildSkeletonT<Struct, Links>;
|
||||
|
||||
REQUIRE(skeletonParallelHeight<Skel> == 4);
|
||||
}
|
||||
|
||||
SECTION("complex") {
|
||||
struct A0 {};
|
||||
using Struct = S<Farm, S<Serial, S<Farm, S<Farm, A0>>, S<Farm, S<Serial, S<Farm, A0>>>>>;
|
||||
using Links = L<Farm, int(), L<Serial, int(), L<Farm, int(), L<Farm, int(), int()>>, L<Farm, int(), L<Serial, int(), L<Farm, int(), int()>>>>>;
|
||||
using Skel = BuildSkeletonT<Struct, Links>;
|
||||
|
||||
REQUIRE(skeletonParallelHeight<Skel> == 3);
|
||||
}
|
||||
}
|
71
tests/skeleton/link/args.cpp
Normal file
71
tests/skeleton/link/args.cpp
Normal file
@ -0,0 +1,71 @@
|
||||
#include <catch.hpp>
|
||||
#include <alsk/skeleton/link/args.h>
|
||||
#include <alsk/context/context.h>
|
||||
|
||||
using namespace alsk;
|
||||
using tmp::Pack;
|
||||
|
||||
TEST_CASE("ArgType") {
|
||||
using P = Pack<struct A, struct B, struct C>;
|
||||
using R = Pack<struct D, struct E, struct F>;
|
||||
using X = Pack<struct G, struct H>;
|
||||
|
||||
using Placeholders = arg::Placeholders<P, R, X>;
|
||||
|
||||
REQUIRE(std::is_same<struct A, ArgType<arg::P<0>, Placeholders>>{});
|
||||
REQUIRE(std::is_same<struct B, ArgType<arg::P<1>, Placeholders>>{});
|
||||
REQUIRE(std::is_same<struct C, ArgType<arg::P<2>, Placeholders>>{});
|
||||
REQUIRE(std::is_same<struct D, ArgType<arg::R<0>, Placeholders>>{});
|
||||
REQUIRE(std::is_same<struct E, ArgType<arg::R<1>, Placeholders>>{});
|
||||
REQUIRE(std::is_same<struct F, ArgType<arg::R<2>, Placeholders>>{});
|
||||
REQUIRE(std::is_same<struct H, ArgType<arg::RNG, Placeholders>>{});
|
||||
}
|
||||
|
||||
TEST_CASE("ArgGet") {
|
||||
std::tuple<int, int, int> p{0, 1, 2};
|
||||
std::tuple<int, int, int> r{3, 4, 5};
|
||||
std::tuple<int, int> x{6, 7};
|
||||
|
||||
REQUIRE(std::get<0>(p) == ArgGet<arg::P<0>>::get(p, r, x));
|
||||
REQUIRE(std::get<1>(p) == ArgGet<arg::P<1>>::get(p, r, x));
|
||||
REQUIRE(std::get<2>(p) == ArgGet<arg::P<2>>::get(p, r, x));
|
||||
REQUIRE(std::get<0>(r) == ArgGet<arg::R<0>>::get(p, r, x));
|
||||
REQUIRE(std::get<1>(r) == ArgGet<arg::R<1>>::get(p, r, x));
|
||||
REQUIRE(std::get<2>(r) == ArgGet<arg::R<2>>::get(p, r, x));
|
||||
REQUIRE(std::get<1>(x) == ArgGet<arg::RNG>::get(p, r, x));
|
||||
}
|
||||
|
||||
TEST_CASE("PRFilter") {}
|
||||
|
||||
TEST_CASE("RealType") {
|
||||
using P = Pack<struct A, struct B, struct C>;
|
||||
using R = Pack<struct D, struct E, struct F>;
|
||||
using X = Pack<struct G, struct H>;
|
||||
|
||||
using Placeholders = arg::Placeholders<P, R, X>;
|
||||
|
||||
REQUIRE(std::is_same<struct A, RealType<arg::P<0>, Placeholders>>{});
|
||||
REQUIRE(std::is_same<struct B, RealType<arg::P<1>, Placeholders>>{});
|
||||
REQUIRE(std::is_same<struct C, RealType<arg::P<2>, Placeholders>>{});
|
||||
REQUIRE(std::is_same<struct D, RealType<arg::R<0>, Placeholders>>{});
|
||||
REQUIRE(std::is_same<struct E, RealType<arg::R<1>, Placeholders>>{});
|
||||
REQUIRE(std::is_same<struct F, RealType<arg::R<2>, Placeholders>>{});
|
||||
REQUIRE(std::is_same<struct H, RealType<arg::RNG, Placeholders>>{});
|
||||
REQUIRE(std::is_same<struct _, RealType<struct _, Placeholders>>{});
|
||||
}
|
||||
|
||||
TEST_CASE("RealSignature") {
|
||||
using P = Pack<struct A, struct B, struct C>;
|
||||
using R = Pack<struct D, struct E, struct F>;
|
||||
using X = Pack<struct G, struct H>;
|
||||
|
||||
using Placeholders = arg::Placeholders<P, R, X>;
|
||||
|
||||
using S = int&(arg::P<0>, arg::R<1>, arg::P<2>, arg::RNG, struct _);
|
||||
using Q = std::function<int&(struct A, struct E, struct C, struct H, struct _)>;
|
||||
|
||||
REQUIRE(std::is_same<Q, RealSignature<S, Placeholders>>{});
|
||||
}
|
||||
|
||||
TEST_CASE("Returns") {}
|
||||
TEST_CASE("Execute") {}
|
Reference in New Issue
Block a user