diff --git a/examples/1_resources.cpp b/examples/1_resources.cpp index a7a79f89..1c7a0fc0 100644 --- a/examples/1_resources.cpp +++ b/examples/1_resources.cpp @@ -6,6 +6,8 @@ */ #include +#include +#include #include @@ -13,13 +15,13 @@ int main(int, char*[]) { auto rg = redGrapes::init(1); - auto a = rg.createFieldResource>(); - auto b = rg.createIOResource(); - auto c = rg.createIOResource(); + auto a = redGrapes::FieldResource>(); + auto b = redGrapes::IOResource(); + auto c = redGrapes::IOResource(); redGrapes::ResourceUser user1( {a.read(), // complete resource - a.write().area({0}, {10}), // write only indices 0 to 10 + a.write({0}, {10}), // write only indices 0 to 10 b.write()}, 0, 0); diff --git a/examples/3_functors_with_resources.cpp b/examples/3_functors_with_resources.cpp index 8fc35cb1..cf4271da 100644 --- a/examples/3_functors_with_resources.cpp +++ b/examples/3_functors_with_resources.cpp @@ -17,8 +17,8 @@ int main(void) spdlog::set_level(spdlog::level::trace); auto rg = redGrapes::init(); - auto a = rg.createIOResource(); - auto b = rg.createIOResource(); + auto a = redGrapes::IOResource(); + auto b = redGrapes::IOResource(); for(int i = 0; i < 1; ++i) { diff --git a/examples/5_access_demotion.cpp b/examples/5_access_demotion.cpp index 66b101df..975663aa 100644 --- a/examples/5_access_demotion.cpp +++ b/examples/5_access_demotion.cpp @@ -7,8 +7,8 @@ #include #include -#include #include +#include #include #include @@ -20,23 +20,26 @@ int main(int, char*[]) { spdlog::set_level(spdlog::level::trace); auto rg = rg::init(); - auto a = rg.createIOResource(); - - rg.emplace_task( - [&](auto a) - { - std::cout << "f1 writes A" << std::endl; - std::this_thread::sleep_for(std::chrono::seconds(1)); - - std::cout << "f1 now only reads A" << std::endl; - rg.update_properties(decltype(rg)::RGTask::TaskProperties::Patch::Builder() - .remove_resources({a}) - .add_resources({rg::newAccess(a, rg::access::IOAccess(rg::access::IOAccess::read))})); - std::this_thread::sleep_for(std::chrono::seconds(1)); - - std::cout << "f1 done" << std::endl; - }, - a.write()); + auto a = redGrapes::IOResource(); + + // Access demotion is not implemented + + // rg.emplace_task( + // [&](auto a) + // { + // std::cout << "f1 writes A" << std::endl; + // std::this_thread::sleep_for(std::chrono::seconds(1)); + + // std::cout << "f1 now only reads A" << std::endl; + // rg.update_properties(decltype(rg)::RGTask::TaskProperties::Patch::Builder() + // .remove_resources({a}) + // .add_resources({rg::newAccess(a, + // rg::access::IOAccess(rg::access::IOAccess::read))})); + // std::this_thread::sleep_for(std::chrono::seconds(1)); + + // std::cout << "f1 done" << std::endl; + // }, + // a.write()); rg.emplace_task( []([[maybe_unused]] auto a) diff --git a/examples/6_resource_scope.cpp b/examples/6_resource_scope.cpp index 283c9737..eba02ef3 100644 --- a/examples/6_resource_scope.cpp +++ b/examples/6_resource_scope.cpp @@ -15,13 +15,13 @@ namespace rg = redGrapes; int main() { auto rg = rg::init(1); - auto a = rg.createIOResource(); // scope-level=0 + auto a = redGrapes::IOResource(); // scope-level=0 rg.emplace_task( [&]([[maybe_unused]] auto a) { std::cout << "scope = " << rg.scope_depth() << std::endl; - auto b = rg.createIOResource(); // scope-level=1 + auto b = redGrapes::IOResource(); // scope-level=1 rg.emplace_task( [&](auto b) diff --git a/examples/7_event.cpp b/examples/7_event.cpp index 3012a146..855d7051 100644 --- a/examples/7_event.cpp +++ b/examples/7_event.cpp @@ -8,6 +8,7 @@ #define SPDLOG_ACTIVE_LEVEL SPDLOG_LEVEL_OFF #include +#include #include #include diff --git a/examples/8_child_destruction.cpp b/examples/8_child_destruction.cpp index 7ff57ada..7c848486 100644 --- a/examples/8_child_destruction.cpp +++ b/examples/8_child_destruction.cpp @@ -17,35 +17,35 @@ int main() spdlog::set_level(spdlog::level::off); auto rg = redGrapes::init(1); - auto a = rg.createIOResource(1); + auto a = redGrapes::IOResource(1); rg.emplace_task( [&rg]([[maybe_unused]] auto a) { std::cout << "scope = " << rg.scope_depth() << " a = " << *a << std::endl; - + auto a2 = redGrapes::IOResource(a); rg.emplace_task( [&rg](auto a) { *a = 2; std::cout << "scope = " << rg.scope_depth() << " a = " << *a << std::endl; }, - a); + a2.write()); rg.emplace_task( [&rg](auto a) { *a = 3; std::cout << "scope = " << rg.scope_depth() << " a = " << *a << std::endl; - auto b = redGrapes::IOResource(a.first); + auto a3 = redGrapes::IOResource(a); rg.emplace_task( - [&rg](auto b) + [&rg](auto a) { - std::cout << "scope = " << rg.scope_depth() << " a = " << *b << std::endl; - *b = 4; + std::cout << "scope = " << rg.scope_depth() << " a = " << *a << std::endl; + *a = 4; }, - b.write()); + a3.write()); }, - a); + a2.write()); *a = 4; std::cout << "scope = " << rg.scope_depth() << " a = " << *a << std::endl; diff --git a/examples/cholesky.cpp b/examples/cholesky.cpp index 93640c6e..e80fd82d 100644 --- a/examples/cholesky.cpp +++ b/examples/cholesky.cpp @@ -23,7 +23,7 @@ void print_matrix(std::vector> A, int nblks, int { for(int jb = 0; jb < blocksize; ++jb) { - std::cout << (*A[ja * nblks + ia].read())[jb * blocksize + ib] << "; "; + std::cout << (*A[ja * nblks + ia].getObject())[jb * blocksize + ib] << "; "; } } std::cout << std::endl; @@ -85,7 +85,8 @@ int main(int argc, char* argv[]) for(size_t ib = 0; ib < blksz; ++ib) for(size_t ja = 0; ja < nblks; ++ja) for(size_t jb = 0; jb < blksz; ++jb) - (*A[ja * nblks + ia].write())[jb * blksz + ib] = Alin[(ia * blksz + ib) + (ja * blksz + jb) * N]; + (*A[ja * nblks + ia].getObject())[jb * blksz + ib] + = Alin[(ia * blksz + ib) + (ja * blksz + jb) * N]; print_matrix(A, nblks, blksz); diff --git a/examples/game_of_life.cpp b/examples/game_of_life.cpp index 1c5d29ba..6b85a880 100644 --- a/examples/game_of_life.cpp +++ b/examples/game_of_life.cpp @@ -123,8 +123,8 @@ int main(int, char*[]) dst[{x + xi, y + yi}] = next_state((Cell const(*)[size.x + 2]) & (src[{x + xi, y + yi}])); }, - buffers[next].write().area({x, y}, {x + chunk_size.x, y + chunk_size.y}), - buffers[current].read().area({x - 1, y - 1}, {x + chunk_size.x + 2, y + chunk_size.y + 2})); + buffers[next].write({x, y}, {x + chunk_size.x, y + chunk_size.y}), + buffers[current].read({x - 1, y - 1}, {x + chunk_size.x + 2, y + chunk_size.y + 2})); current = next; } diff --git a/examples/mpi.cpp b/examples/mpi.cpp index d3afcd05..078e48f3 100644 --- a/examples/mpi.cpp +++ b/examples/mpi.cpp @@ -140,7 +140,7 @@ int main() mpi_request_pool->get_status(request); }, - field[current].at({3}).read(), + field[current].read({3}), mpi_config.read()) .enable_stack_switching(); @@ -158,18 +158,18 @@ int main() int recv_data_count; MPI_Get_count(&status, MPI_CHAR, &recv_data_count); }, - field[current].at({0}).write(), + field[current].write({0}), mpi_config.read()) .enable_stack_switching(); /* * Compute iteration */ - for(size_t i = 1; i < field[current]->size(); ++i) + for(size_t i = 1; i < field[current].getObject()->size(); ++i) rg.emplace_task( [i](auto dst, auto src) { dst[{i}] = src[{i - 1}]; }, - field[next].at({i}).write(), - field[current].at({i - 1}).read()); + field[next].write({i}), + field[current].read({i - 1})); /* * Write Output diff --git a/redGrapes/redGrapes.hpp b/redGrapes/redGrapes.hpp index 43c0c119..28797347 100644 --- a/redGrapes/redGrapes.hpp +++ b/redGrapes/redGrapes.hpp @@ -10,8 +10,6 @@ #include "redGrapes/SchedulerDescription.hpp" #include "redGrapes/TaskFreeCtx.hpp" #include "redGrapes/globalSpace.hpp" -#include "redGrapes/resource/fieldresource.hpp" -#include "redGrapes/resource/ioresource.hpp" #include "redGrapes/scheduler/event.hpp" #include "redGrapes/scheduler/pool_scheduler.hpp" #include "redGrapes/task/task.hpp" @@ -139,7 +137,10 @@ namespace redGrapes SPDLOG_TRACE("emplace task to worker {}", worker_id); - using Impl = typename std::invoke_result_t, Callable, Args...>; + using Impl = typename std::invoke_result_t< + BindArgs()))...>, + Callable, + decltype(forward_arg(std::declval()))...>; // this is not set to nullptr. But it goes out of scope. Memory is managed by allocate FunTask* task; memory::Allocator alloc(worker_id); @@ -177,30 +178,6 @@ namespace redGrapes return getScheduler(); } - template - auto createFieldResource(Container* c) -> FieldResource - { - return FieldResource(c); - } - - template - auto createFieldResource(Args&&... args) -> FieldResource - { - return FieldResource(std::forward(args)...); - } - - template - auto createIOResource(std::shared_ptr const& o) -> IOResource - { - return IOResource(o); - } - - template - auto createIOResource(Args&&... args) -> IOResource - { - return IOResource(std::forward(args)...); - } - template auto createResource() -> Resource { diff --git a/redGrapes/resource/access/field.hpp b/redGrapes/resource/access/field.hpp index ffbfb704..79293f65 100644 --- a/redGrapes/resource/access/field.hpp +++ b/redGrapes/resource/access/field.hpp @@ -11,9 +11,9 @@ #pragma once -#include "redGrapes/resource/access/area.hpp" #include "redGrapes/resource/access/combine.hpp" #include "redGrapes/resource/access/io.hpp" +#include "redGrapes/resource/access/range.hpp" namespace redGrapes { @@ -21,7 +21,7 @@ namespace redGrapes { template - using FieldAccess = CombineAccess, And_t>; + using FieldAccess = CombineAccess, And_t>; } // namespace access diff --git a/redGrapes/resource/access/area.hpp b/redGrapes/resource/access/range.hpp similarity index 73% rename from redGrapes/resource/access/area.hpp rename to redGrapes/resource/access/range.hpp index b1e2062b..271ec68a 100644 --- a/redGrapes/resource/access/area.hpp +++ b/redGrapes/resource/access/range.hpp @@ -20,16 +20,16 @@ namespace redGrapes { namespace access { - - struct AreaAccess : std::array + // Must be in increasing order + struct RangeAccess : std::array { - AreaAccess() + RangeAccess() { (*this)[0] = std::numeric_limits::min(); (*this)[1] = std::numeric_limits::max(); } - AreaAccess(std::array a) : std::array(a) + RangeAccess(std::array a) : std::array(a) { } @@ -39,17 +39,17 @@ namespace redGrapes && (*this)[1] == std::numeric_limits::max(); } - static bool is_serial(AreaAccess const& a, AreaAccess const& b) + static bool is_serial(RangeAccess const& a, RangeAccess const& b) { return !((a[1] <= b[0]) || (a[0] >= b[1])); } - bool is_superset_of(AreaAccess const& a) const + bool is_superset_of(RangeAccess const& a) const { return (((*this)[0] <= a[0]) && ((*this)[1] >= a[1])); } - bool operator==(AreaAccess const& other) const + bool operator==(RangeAccess const& other) const { return (*this)[0] == other[0] && (*this)[1] == other[1]; } @@ -62,7 +62,7 @@ namespace redGrapes } // namespace redGrapes template<> -struct fmt::formatter +struct fmt::formatter { constexpr auto parse(format_parse_context& ctx) { @@ -70,7 +70,7 @@ struct fmt::formatter } template - auto format(redGrapes::access::AreaAccess const& acc, FormatContext& ctx) + auto format(redGrapes::access::RangeAccess const& acc, FormatContext& ctx) { return fmt::format_to(ctx.out(), "{{ \"area\" : {{ \"begin\" : {}, \"end\" : {} }} }}", acc[0], acc[1]); } diff --git a/redGrapes/resource/fieldresource.hpp b/redGrapes/resource/fieldresource.hpp index 67b04363..f0c16c39 100644 --- a/redGrapes/resource/fieldresource.hpp +++ b/redGrapes/resource/fieldresource.hpp @@ -11,11 +11,12 @@ #pragma once -#include "redGrapes/TaskFreeCtx.hpp" #include "redGrapes/resource/access/field.hpp" #include "redGrapes/resource/resource.hpp" #include "redGrapes/util/traits.hpp" +#include + namespace redGrapes { @@ -38,280 +39,263 @@ namespace redGrapes return {v.size()}; } - static Item& get(std::vector& v, std::array index) + static Item& get(std::vector& v, std::array const& index) { return v[index[0]]; } }; - template - struct Field> + template + struct Field const> { using Item = T; static constexpr size_t dim = 1; - static Item& get(std::array& array, std::array index) + static std::array extent(std::vector& v) { - return array[index[0]]; + return {v.size()}; } - }; - template - struct Field, Ny>> - { - using Item = T; - static constexpr size_t dim = 2; - - static Item& get(std::array, Ny>& array, std::array index) + static Item const& get(std::vector const& v, std::array const& index) { - return array[index[1]][index[0]]; + return v[index[0]]; } }; - }; // namespace trait - - namespace fieldresource - { - - template - struct AreaGuard : SharedResourceObject::dim>> + template + struct Field> { - static constexpr size_t dim = trait::Field::dim; - using Item = typename trait::Field::Item; - using Index = std::array; + using Item = T; + static constexpr size_t dim = 1; - bool contains(Index index) const noexcept + static Item& get(std::array& array, std::array const& index) { - for(size_t d = 0; d < dim; d++) - { - if(index[d] < m_area[d][0] || index[d] >= m_area[d][1]) - return false; - } - return true; + return array[index[0]]; } + }; - protected: - AreaGuard(ResourceId id, std::shared_ptr const& obj) - : SharedResourceObject>(id, obj) - { - } + template + struct Field const> + { + using Item = T; + static constexpr size_t dim = 1; - template - AreaGuard(ResourceId id, Args&&... args) - : SharedResourceObject>(id, std::forward(args)...) + static Item const& get(std::array const& array, std::array const& index) { + return array[index[0]]; } + }; - AreaGuard( - Resource::dim>> const& res, - std::shared_ptr const& obj) - : SharedResourceObject>(res, obj) - { - } + template + struct Field, Ny>> + { + using Item = T; + static constexpr size_t dim = 2; - template - AreaGuard(Resource::dim>> const& res, Args&&... args) - : SharedResourceObject>(res, std::forward(args)...) + static Item& get(std::array, Ny>& array, std::array const& index) { + return array[index[1]][index[0]]; } + }; - AreaGuard(AreaGuard const& other, Index begin, Index end) - : SharedResourceObject>(other) - , m_area(other.make_area(begin, end)) - { - } + template + struct Field, Ny> const> + { + using Item = T; + static constexpr size_t dim = 2; - Item& get(Index index) const + static Item const& get( + std::array, Ny> const& array, + std::array const& index) { - if(!contains(index)) - throw std::out_of_range("invalid area access"); - - return trait::Field::get(*this->obj, index); + return array[index[1]][index[0]]; } + }; - access::ArrayAccess make_area(Index begin, Index end) const - { - std::array sub_area; - for(int d = 0; d < dim; ++d) - sub_area[d] = access::AreaAccess({begin[d], end[d]}); - - if(!m_area.is_superset_of(sub_area)) - throw std::out_of_range("invalid sub area"); - return access::ArrayAccess(sub_area); - } + }; // namespace trait - access::ArrayAccess m_area; - }; + namespace fieldaccess + { template - struct ReadGuard : AreaGuard + struct FieldAccessWrapper { static constexpr size_t dim = trait::Field::dim; - using typename AreaGuard::Index; - using typename AreaGuard::Item; - - ReadGuard read() const noexcept - { - return *this; - } + using Index = std::array; - ReadGuard area(Index begin, Index end) const + FieldAccessWrapper(std::shared_ptr container) : container(std::move(container)), m_area{} { - return ReadGuard(*this, begin, end); } - ReadGuard at(Index pos) const + FieldAccessWrapper( + std::shared_ptr container, + access::ArrayAccess area) + : container(std::move(container)) + , m_area{area} { - Index end = pos; - for(size_t d = 0; d < dim; ++d) - end[d]++; - return ReadGuard(*this, pos, end); } - Item const& operator[](Index index) const + auto* operator->() const noexcept { - return this->get(index); + return container.get(); } - Container const* operator->() const noexcept + auto& operator[](Index const& index) const { - return this->obj.get(); + return get(index); } - operator ResourceAccess() const noexcept + auto& get(Index const& index) const noexcept { - return this->res.make_access(access::FieldAccess(access::IOAccess::read, this->m_area)); - } + if(!contains(index)) + throw std::out_of_range("invalid area access"); - protected: - ReadGuard(ReadGuard const& other, Index begin, Index end) : AreaGuard(other, begin, end) - { + return trait::Field::get(*container, index); } - ReadGuard(ResourceId id, std::shared_ptr const& obj) : AreaGuard(id, obj) + private: + bool contains(Index index) const noexcept { + for(size_t d = 0; d < dim; d++) + { + if(index[d] < m_area[d][0] || index[d] >= m_area[d][1]) + return false; + } + return true; } - template - ReadGuard(ResourceId id, Args&&... args) : AreaGuard(id, std::forward(args)...) - { - } + std::shared_ptr container; + access::ArrayAccess m_area; + }; - ReadGuard( - Resource::dim>> const& res, - std::shared_ptr const& obj) - : AreaGuard(res, obj) - { - } + } // namespace fieldaccess - template - ReadGuard(Resource::dim>> const& res, Args&&... args) - : AreaGuard(res, std::forward(args)...) - { - } - }; + namespace fieldresource + { template - struct WriteGuard : ReadGuard + struct AreaGuard : SharedResourceObject::dim>> { static constexpr size_t dim = trait::Field::dim; - using typename ReadGuard::Index; - using typename ReadGuard::Item; - - WriteGuard write() const noexcept - { - return *this; - } - - WriteGuard area(Index begin, Index end) const - { - return WriteGuard(*this, begin, end); - } + using Item = typename trait::Field::Item; + using Index = std::array; - WriteGuard at(Index pos) const + AreaGuard(std::shared_ptr const& obj) + : SharedResourceObject>(obj) + , m_area{} { - Index end = pos; - for(size_t d = 0; d < dim; ++d) - end[d]++; - return WriteGuard(*this, pos, end); } - Item& operator[](Index index) const - { - return this->get(index); - } + template + requires(!(traits::is_specialization_of_v>, AreaGuard> + || std::is_same_v>, Container*>) ) - Container* operator->() const noexcept + AreaGuard(Args&&... args) + : SharedResourceObject>(std::forward(args)...) + , m_area{} { - return this->obj.get(); } - operator ResourceAccess() const noexcept + template + AreaGuard(AreaGuard const& res, std::shared_ptr const& obj) + : SharedResourceObject>(res, obj) + , m_area{} { - return this->res.make_access(access::FieldAccess(access::IOAccess::write, this->m_area)); } - protected: - WriteGuard(WriteGuard const& other, Index begin, Index end) : ReadGuard(other, begin, end) + template + AreaGuard(AreaGuard const& res, Args&&... args) + : SharedResourceObject>(res, std::forward(args)...) + , m_area{} { } - WriteGuard(ResourceId id, std::shared_ptr const& obj) : ReadGuard(id, obj) + access::ArrayAccess make_area(Index begin, Index end) const { - } + std::array sub_area; + for(int d = 0; d < dim; ++d) + sub_area[d] = access::RangeAccess({begin[d], end[d]}); - template - WriteGuard(ResourceId id, Args&&... args) : ReadGuard(id, std::forward(args)...) - { - } + if(!m_area.is_superset_of(sub_area)) + throw std::out_of_range("invalid sub area"); - WriteGuard( - Resource::dim>> const& res, - std::shared_ptr const& obj) - : ReadGuard(res, obj) - { + return access::ArrayAccess(sub_area); } - template - WriteGuard(Resource::dim>> const& res, Args&&... args) - : ReadGuard(res, std::forward(args)...) - { - } + protected: + access::ArrayAccess m_area; }; + } // namespace fieldresource template - struct FieldResource : fieldresource::WriteGuard + struct FieldResource : fieldresource::AreaGuard { static constexpr size_t dim = trait::Field::dim; + using typename fieldresource::AreaGuard::Index; + using typename fieldresource::AreaGuard::Item; - FieldResource(Container* c) - : fieldresource::WriteGuard(TaskFreeCtx::create_resource_uid(), std::make_shared(c)) + using fieldresource::AreaGuard::AreaGuard; + + auto access(access::FieldAccess mode) const noexcept { + return ResourceAccessPair>{ + this->obj, + this->res.make_access(mode)}; } - template - requires( - !(traits::is_specialization_of_v>, FieldResource> - || std::is_same_v>, Container*>) ) + auto read() const noexcept + { + return ResourceAccessPair>{ + this->obj, + this->res.make_access(access::FieldAccess( + access::IOAccess::read, + access::ArrayAccess{}))}; + } + + auto read(Index begin, Index end) const noexcept + { + return ResourceAccessPair>{ + this->obj, + this->res.make_access(access::FieldAccess(access::IOAccess::read, this->make_area(begin, end)))}; + } + + auto read(Index pos) const noexcept + { + Index end = pos; + for(size_t d = 0; d < dim; ++d) + end[d]++; + return ResourceAccessPair>{ + {this->obj, this->make_area(pos, end)}, + this->res.make_access(access::FieldAccess(access::IOAccess::read, this->make_area(pos, end)))}; + } - FieldResource(Args&&... args) - : fieldresource::WriteGuard(TaskFreeCtx::create_resource_uid(), std::forward(args)...) + auto write() const noexcept { + return ResourceAccessPair>{ + this->obj, + this->res.make_access(access::FieldAccess( + access::IOAccess::write, + access::ArrayAccess{}))}; } - template - FieldResource(FieldResource const& res, Container* c) - : fieldresource::WriteGuard(res, std::make_shared(c)) + auto write(Index begin, Index end) const noexcept { + return ResourceAccessPair>{ + this->obj, + this->res.make_access(access::FieldAccess(access::IOAccess::write, this->make_area(begin, end)))}; } - template - FieldResource(FieldResource const& res, Args&&... args) - : fieldresource::WriteGuard(res, std::forward(args)...) + auto write(Index pos) const noexcept { + Index end = pos; + for(size_t d = 0; d < dim; ++d) + end[d]++; + return ResourceAccessPair>{ + this->obj, + this->res.make_access(access::FieldAccess(access::IOAccess::write, this->make_area(pos, end)))}; } }; diff --git a/redGrapes/resource/ioresource.hpp b/redGrapes/resource/ioresource.hpp index 4dc17b76..502dfddb 100644 --- a/redGrapes/resource/ioresource.hpp +++ b/redGrapes/resource/ioresource.hpp @@ -11,13 +11,10 @@ #pragma once -#include "redGrapes/TaskFreeCtx.hpp" #include "redGrapes/resource/access/io.hpp" #include "redGrapes/resource/resource.hpp" -#include "redGrapes/util/traits.hpp" #include -#include #include namespace redGrapes @@ -26,34 +23,22 @@ namespace redGrapes template struct IOResource : public SharedResourceObject { - IOResource(std::shared_ptr const& o) - : SharedResourceObject(TaskFreeCtx::create_resource_uid(), o) - { - } - - template - requires( - !(traits::is_specialization_of_v>, IOResource> - || std::is_same_v>, std::shared_ptr>) ) - IOResource(Args&&... args) - : SharedResourceObject( - TaskFreeCtx::create_resource_uid(), - std::forward(args)...) - { - } + using SharedResourceObject::SharedResourceObject; - template - IOResource(IOResource const& res, std::shared_ptr const& obj) - : SharedResourceObject(res, obj) + auto read() const noexcept { + return ResourceAccessPair>{ + this->obj, + this->res.make_access(access::IOAccess::read)}; } - template - IOResource(IOResource const& res, Args&&... args) - : SharedResourceObject(res, std::forward(args)...) + auto write() const noexcept { + return ResourceAccessPair>{this->obj, this->res.make_access(access::IOAccess::write)}; } - }; // struct IOResource + template + IOResource(std::shared_ptr) -> IOResource; + } // namespace redGrapes diff --git a/redGrapes/resource/resource.hpp b/redGrapes/resource/resource.hpp index e949fd08..274c7cdf 100644 --- a/redGrapes/resource/resource.hpp +++ b/redGrapes/resource/resource.hpp @@ -16,6 +16,7 @@ #include "redGrapes/sync/spinlock.hpp" #include "redGrapes/task/property/trait.hpp" #include "redGrapes/util/chunked_list.hpp" +#include "redGrapes/util/traits.hpp" #include #include @@ -273,30 +274,16 @@ namespace redGrapes bool is_serial(ResourceAccess const& a, ResourceAccess const& b); template - struct ResourceAccessPair : public std::pair, ResourceAccess> + struct ResourceAccessPair : public std::pair { - using std::pair, ResourceAccess>::pair; + using std::pair::pair; operator ResourceAccess() const { return this->second; } - auto& operator*() const noexcept - { - return *(this->first); - } - - auto* operator->() const noexcept - { - return this->first.get(); - } - - auto* get() const noexcept - { - return this->first.get(); - } - }; + }; // namespace std::pair namespace trait { @@ -394,23 +381,31 @@ namespace redGrapes template struct SharedResourceObject { - SharedResourceObject(ResourceId id, std::shared_ptr obj) : res{id}, obj(std::move(obj)) + SharedResourceObject(std::shared_ptr obj) : res{TaskFreeCtx::create_resource_uid()}, obj(std::move(obj)) { } template - SharedResourceObject(ResourceId id, Args&&... args) - : res{id} - , obj{memory::alloc_shared_bind(mapping::map_resource_to_worker(id), std::forward(args)...)} + requires(!(traits::is_specialization_of_v>, SharedResourceObject> + || std::is_same_v>, std::shared_ptr>) ) + SharedResourceObject(Args&&... args) + : res{TaskFreeCtx::create_resource_uid()} + , obj{memory::alloc_shared_bind( + mapping::map_resource_to_worker(res.resource_id()), + std::forward(args)...)} { } - SharedResourceObject(Resource const& res, std::shared_ptr obj) : res{res}, obj{std::move(obj)} + template + SharedResourceObject(SharedResourceObject const& res, std::shared_ptr obj) + : res{res} + , obj{std::move(obj)} { } - template - SharedResourceObject(Resource const& res, Args&&... args) + template + requires(!(std::is_same_v>, std::shared_ptr>) ) + SharedResourceObject(SharedResourceObject const& res, Args&&... args) : res{res} , obj{memory::alloc_shared_bind( mapping::map_resource_to_worker(res.resource_id()), @@ -418,22 +413,17 @@ namespace redGrapes { } - auto read() const noexcept + // DANGER! Gives access to ibject being held as a resource without any synchronization and scheduling + // Only to be used when you know what you are doing + auto& getObject() { - return ResourceAccessPair{obj, res.make_access(AccessPolicy::read)}; + return obj; } - auto write() const noexcept - { - return ResourceAccessPair{obj, res.make_access(AccessPolicy::write)}; - } - - protected: Resource res; std::shared_ptr obj; - }; // struct SharedResourceObject } // namespace redGrapes diff --git a/redGrapes/scheduler/pool_scheduler.hpp b/redGrapes/scheduler/pool_scheduler.hpp index c8119d14..38e2c701 100644 --- a/redGrapes/scheduler/pool_scheduler.hpp +++ b/redGrapes/scheduler/pool_scheduler.hpp @@ -55,7 +55,7 @@ namespace redGrapes WorkerId getNextWorkerID(); - void init(WorkerId base_id); + void init(WorkerId base_id) override; void startExecution(); diff --git a/redGrapes/scheduler/thread_scheduler.hpp b/redGrapes/scheduler/thread_scheduler.hpp index 09d988c7..83c1a99f 100644 --- a/redGrapes/scheduler/thread_scheduler.hpp +++ b/redGrapes/scheduler/thread_scheduler.hpp @@ -86,7 +86,7 @@ namespace redGrapes return m_base_id; } - virtual void init(WorkerId base_id) + void init(WorkerId base_id) override { m_base_id = base_id; // TODO check if it was already initalized diff --git a/redGrapes/task/property/resource.hpp b/redGrapes/task/property/resource.hpp index cd847d08..b5d10ee3 100644 --- a/redGrapes/task/property/resource.hpp +++ b/redGrapes/task/property/resource.hpp @@ -49,7 +49,7 @@ namespace redGrapes return builder; } - inline PropertiesBuilder& add_resource(ResourceAccess access) + inline PropertiesBuilder& add_resource(ResourceAccess const& access) { (*builder.task) += access; return builder; diff --git a/redGrapes/task/task_builder.hpp b/redGrapes/task/task_builder.hpp index 5855155b..ac03fc4b 100644 --- a/redGrapes/task/task_builder.hpp +++ b/redGrapes/task/task_builder.hpp @@ -14,6 +14,7 @@ #include #include +#include namespace redGrapes { @@ -38,13 +39,37 @@ namespace redGrapes } }; + // Helper function to conditionally forward the argument + template + constexpr auto forward_arg(T&& arg) + { + if constexpr(traits::is_derived_from_pair_v>) + { + if constexpr(std::is_same_v::second_type, ResourceAccess>) + { + return std::forward(arg.first); + } + else + { + return std::forward(arg); + } + } + else + { + return std::forward(arg); + } + } + /* TASK BUILDER */ template struct TaskBuilder : TTask::TaskProperties::template Builder> { - using Impl = typename std::invoke_result_t, Callable, Args...>; - using Result = typename std::invoke_result_t; + using Impl = typename std::invoke_result_t< + BindArgs()))...>, + Callable, + decltype(forward_arg(std::declval()))...>; + using Result = typename std::invoke_result_t()))...>; std::shared_ptr space; FunTask* task; @@ -66,7 +91,9 @@ namespace redGrapes this->init_id(); // set impl - task->impl.emplace(BindArgs{}(std::move(f), std::forward(args)...)); + task->impl.emplace(BindArgs()))...>{}( + std::move(f), + forward_arg(std::forward(args))...)); } TaskBuilder(TaskBuilder& other) diff --git a/redGrapes/util/traits.hpp b/redGrapes/util/traits.hpp index 0c16d1a6..33afb12c 100644 --- a/redGrapes/util/traits.hpp +++ b/redGrapes/util/traits.hpp @@ -1,5 +1,14 @@ +/* Copyright 2024 Tapish Narwal + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + #pragma once + #include +#include namespace redGrapes::traits { @@ -29,4 +38,32 @@ namespace redGrapes::traits template using first_type_t = typename first_type::type; + template + struct is_pair : std::false_type + { + }; + + template + struct is_pair> : std::true_type + { + }; + + template + inline constexpr bool is_pair_v = is_pair::value; + + template + struct is_derived_from_pair : std::false_type + { + }; + + // Specialization for std::pair + template + struct is_derived_from_pair> : std::true_type + { + }; + + // Helper variable template for is_derived_from_pair + template + constexpr bool is_derived_from_pair_v = is_derived_from_pair::value; + } // namespace redGrapes::traits diff --git a/test/access.cpp b/test/access.cpp index 352a1346..c510356f 100644 --- a/test/access.cpp +++ b/test/access.cpp @@ -1,8 +1,8 @@ -#include #include #include #include +#include #include @@ -52,86 +52,86 @@ TEST_CASE("IOAccess") REQUIRE(IOAccess{IOAccess::amul}.is_superset_of(IOAccess{IOAccess::amul}) == true); } -TEST_CASE("AreaAccess") +TEST_CASE("RangeAccess") { // --[-----]--(-----)-- - REQUIRE(AreaAccess::is_serial(AreaAccess({10, 20}), AreaAccess({30, 40})) == false); - REQUIRE(AreaAccess({10, 20}).is_superset_of(AreaAccess({30, 40})) == false); + REQUIRE(RangeAccess::is_serial(RangeAccess({10, 20}), RangeAccess({30, 40})) == false); + REQUIRE(RangeAccess({10, 20}).is_superset_of(RangeAccess({30, 40})) == false); // --(-----)--[-----]-- - REQUIRE(AreaAccess::is_serial(AreaAccess({30, 40}), AreaAccess({10, 20})) == false); - REQUIRE(AreaAccess({30, 40}).is_superset_of(AreaAccess({10, 20})) == false); + REQUIRE(RangeAccess::is_serial(RangeAccess({30, 40}), RangeAccess({10, 20})) == false); + REQUIRE(RangeAccess({30, 40}).is_superset_of(RangeAccess({10, 20})) == false); // --[--(--]--)-- - REQUIRE(AreaAccess::is_serial(AreaAccess({10, 20}), AreaAccess({15, 25})) == true); - REQUIRE(AreaAccess({10, 20}).is_superset_of(AreaAccess({15, 25})) == false); + REQUIRE(RangeAccess::is_serial(RangeAccess({10, 20}), RangeAccess({15, 25})) == true); + REQUIRE(RangeAccess({10, 20}).is_superset_of(RangeAccess({15, 25})) == false); // --(--[--)--]-- - REQUIRE(AreaAccess::is_serial(AreaAccess({15, 25}), AreaAccess({10, 20})) == true); - REQUIRE(AreaAccess({15, 15}).is_superset_of(AreaAccess({10, 20})) == false); + REQUIRE(RangeAccess::is_serial(RangeAccess({15, 25}), RangeAccess({10, 20})) == true); + REQUIRE(RangeAccess({15, 15}).is_superset_of(RangeAccess({10, 20})) == false); // --[--(--)--]-- - REQUIRE(AreaAccess::is_serial(AreaAccess({10, 30}), AreaAccess({15, 25})) == true); - REQUIRE(AreaAccess({10, 30}).is_superset_of(AreaAccess({15, 25})) == true); + REQUIRE(RangeAccess::is_serial(RangeAccess({10, 30}), RangeAccess({15, 25})) == true); + REQUIRE(RangeAccess({10, 30}).is_superset_of(RangeAccess({15, 25})) == true); // --(--[--]--)-- - REQUIRE(AreaAccess::is_serial(AreaAccess({15, 25}), AreaAccess({10, 30})) == true); - REQUIRE(AreaAccess({15, 25}).is_superset_of(AreaAccess({10, 30})) == false); + REQUIRE(RangeAccess::is_serial(RangeAccess({15, 25}), RangeAccess({10, 30})) == true); + REQUIRE(RangeAccess({15, 25}).is_superset_of(RangeAccess({10, 30})) == false); } TEST_CASE("CombineAccess") { - using A = CombineAccess; + using A = CombineAccess; REQUIRE( A::is_serial( - A(IOAccess{IOAccess::read}, AreaAccess({10, 20})), - A(IOAccess{IOAccess::read}, AreaAccess({15, 25}))) + A(IOAccess{IOAccess::read}, RangeAccess({10, 20})), + A(IOAccess{IOAccess::read}, RangeAccess({15, 25}))) == false); REQUIRE( A::is_serial( - A(IOAccess{IOAccess::read}, AreaAccess({10, 20})), - A(IOAccess{IOAccess::write}, AreaAccess({15, 25}))) + A(IOAccess{IOAccess::read}, RangeAccess({10, 20})), + A(IOAccess{IOAccess::write}, RangeAccess({15, 25}))) == true); REQUIRE( A::is_serial( - A(IOAccess{IOAccess::read}, AreaAccess({10, 20})), - A(IOAccess{IOAccess::write}, AreaAccess({30, 40}))) + A(IOAccess{IOAccess::read}, RangeAccess({10, 20})), + A(IOAccess{IOAccess::write}, RangeAccess({30, 40}))) == false); REQUIRE( - A(IOAccess{IOAccess::read}, AreaAccess({10, 20})) - .is_superset_of(A(IOAccess{IOAccess::read}, AreaAccess({15, 25}))) + A(IOAccess{IOAccess::read}, RangeAccess({10, 20})) + .is_superset_of(A(IOAccess{IOAccess::read}, RangeAccess({15, 25}))) == false); REQUIRE( - A(IOAccess{IOAccess::write}, AreaAccess({10, 30})) - .is_superset_of(A(IOAccess{IOAccess::read}, AreaAccess({15, 25}))) + A(IOAccess{IOAccess::write}, RangeAccess({10, 30})) + .is_superset_of(A(IOAccess{IOAccess::read}, RangeAccess({15, 25}))) == true); - using B = CombineAccess; + using B = CombineAccess; REQUIRE( B::is_serial( - B(IOAccess{IOAccess::read}, AreaAccess({10, 20})), - B(IOAccess{IOAccess::read}, AreaAccess({30, 40}))) + B(IOAccess{IOAccess::read}, RangeAccess({10, 20})), + B(IOAccess{IOAccess::read}, RangeAccess({30, 40}))) == false); REQUIRE( B::is_serial( - B(IOAccess{IOAccess::read}, AreaAccess({10, 20})), - B(IOAccess{IOAccess::read}, AreaAccess({15, 25}))) + B(IOAccess{IOAccess::read}, RangeAccess({10, 20})), + B(IOAccess{IOAccess::read}, RangeAccess({15, 25}))) == true); REQUIRE( B::is_serial( - B(IOAccess{IOAccess::read}, AreaAccess({10, 20})), - B(IOAccess{IOAccess::write}, AreaAccess({15, 25}))) + B(IOAccess{IOAccess::read}, RangeAccess({10, 20})), + B(IOAccess{IOAccess::write}, RangeAccess({15, 25}))) == true); REQUIRE( B::is_serial( - B(IOAccess{IOAccess::read}, AreaAccess({10, 20})), - B(IOAccess{IOAccess::write}, AreaAccess({30, 40}))) + B(IOAccess{IOAccess::read}, RangeAccess({10, 20})), + B(IOAccess{IOAccess::write}, RangeAccess({30, 40}))) == true); } @@ -191,24 +191,24 @@ TEST_CASE("ArrayAccess") TEST_CASE("FieldAccess") { - using Arr = ArrayAccess; + using Arr = ArrayAccess; REQUIRE( FieldAccess<3>::is_serial( FieldAccess<3>( IOAccess{IOAccess::read}, - Arr({AreaAccess({0, 10}), AreaAccess({0, 10}), AreaAccess({0, 10})})), + Arr({RangeAccess({0, 10}), RangeAccess({0, 10}), RangeAccess({0, 10})})), FieldAccess<3>( IOAccess{IOAccess::read}, - Arr({AreaAccess({0, 10}), AreaAccess({0, 10}), AreaAccess({0, 10})}))) + Arr({RangeAccess({0, 10}), RangeAccess({0, 10}), RangeAccess({0, 10})}))) == false); REQUIRE( FieldAccess<3>::is_serial( FieldAccess<3>( IOAccess{IOAccess::write}, - Arr({AreaAccess({0, 10}), AreaAccess({0, 10}), AreaAccess({0, 10})})), + Arr({RangeAccess({0, 10}), RangeAccess({0, 10}), RangeAccess({0, 10})})), FieldAccess<3>( IOAccess{IOAccess::read}, - Arr({AreaAccess({0, 10}), AreaAccess({0, 10}), AreaAccess({0, 10})}))) + Arr({RangeAccess({0, 10}), RangeAccess({0, 10}), RangeAccess({0, 10})}))) == true); } diff --git a/test/random_graph.cpp b/test/random_graph.cpp index 75a818e8..d4dc5e4e 100644 --- a/test/random_graph.cpp +++ b/test/random_graph.cpp @@ -186,6 +186,6 @@ TEST_CASE("RandomGraph") rg.barrier(); for(unsigned i = 0; i < n_resources; ++i) - REQUIRE(*resources[i].read() == expected_hash[i]); + REQUIRE(*resources[i].getObject() == expected_hash[i]); } }