diff --git a/redGrapes/resource/resource.hpp b/redGrapes/resource/resource.hpp index 52b23265..57561a62 100644 --- a/redGrapes/resource/resource.hpp +++ b/redGrapes/resource/resource.hpp @@ -30,337 +30,360 @@ #include #ifndef REDGRAPES_RUL_CHUNKSIZE -# define REDGRAPES_RUL_CHUNKSIZE 128 +#define REDGRAPES_RUL_CHUNKSIZE 128 #endif namespace redGrapes { - template - class Resource; +template +class Resource; - struct Task; +struct Task; - class ResourceBase - { - protected: - static unsigned int generateID(); +class ResourceBase +{ +protected: + static unsigned int generateID(); - public: - unsigned int id; - unsigned int scope_level; +public: + ChunkedList< Task*, REDGRAPES_RUL_CHUNKSIZE > users; + SpinLock users_mutex; - SpinLock users_mutex; - ChunkedList users; + uint16_t id; + uint8_t scope_level; - /** - * Create a new resource with an unused ID. - */ - ResourceBase(); + /** + * Create a new resource with an unused ID. + */ + ResourceBase(); - unsigned get_arena_id() const; - }; + unsigned get_arena_id() const; +}; - template - class Resource; +template +class Resource; - class ResourceAccess - { - template - friend class Resource; +class ResourceAccess +{ + template + friend class Resource; - private: - struct AccessBase - { - AccessBase(boost::typeindex::type_index access_type, std::shared_ptr resource) - : access_type(access_type) - , resource(resource) - { - } - - AccessBase(AccessBase&& other) : access_type(other.access_type), resource(std::move(other.resource)) - { - } - - virtual ~AccessBase(){}; - virtual bool operator==(AccessBase const& r) const = 0; - - bool is_same_resource(ResourceAccess::AccessBase const& a) const - { - return this->resource == a.resource; - } - - virtual bool is_synchronizing() const = 0; - virtual bool is_serial(AccessBase const& r) const = 0; - virtual bool is_superset_of(AccessBase const& r) const = 0; - virtual std::string mode_format() const = 0; - - boost::typeindex::type_index access_type; - std::shared_ptr resource; - }; // AccessBase - - // todo use allocator!! - std::shared_ptr obj; - - public: - ResourceAccess(std::shared_ptr obj) : obj(obj) + private: + struct AccessBase + { + AccessBase( boost::typeindex::type_index access_type, std::shared_ptr resource ) + : access_type( access_type ) + , resource( resource ) { } - ResourceAccess(ResourceAccess const& other) : obj(other.obj) - { - } + AccessBase( AccessBase && other ) + : access_type( other.access_type ) + , resource( std::move(other.resource) ) + {} - ResourceAccess(ResourceAccess&& other) : obj(std::move(other.obj)) - { - other.obj.reset(); - } + virtual ~AccessBase() {}; + virtual bool operator==( AccessBase const & r ) const = 0; - ResourceAccess& operator=(ResourceAccess const& other) + bool + is_same_resource( ResourceAccess::AccessBase const & a ) const { - this->obj = other.obj; - return *this; + return this->resource == a.resource; } - static bool is_serial(ResourceAccess const& a, ResourceAccess const& b) - { - if(a.obj->access_type == b.obj->access_type) - return a.obj->is_serial(*b.obj); - else - return false; - } + virtual bool is_synchronizing() const = 0; + virtual bool is_serial( AccessBase const & r ) const = 0; + virtual bool is_superset_of( AccessBase const & r ) const = 0; + virtual std::string mode_format() const = 0; + + boost::typeindex::type_index access_type; + std::shared_ptr< ResourceBase > resource; + }; // AccessBase + + // todo use allocator!! + std::shared_ptr< AccessBase > obj; + + public: + ResourceAccess( std::shared_ptr< AccessBase > obj ) : obj( obj ) {} + ResourceAccess( ResourceAccess const & other ) : obj( other.obj ) {} + ResourceAccess( ResourceAccess && other ) : obj( std::move(other.obj) ) { + other.obj.reset(); + } + + ResourceAccess& operator= (ResourceAccess const & other ) + { + this->obj = other.obj; + return *this; + } + + static bool + is_serial( ResourceAccess const & a, ResourceAccess const & b ) + { + if ( a.obj->access_type == b.obj->access_type ) + return a.obj->is_serial( *b.obj ); + else + return false; + } + + bool + is_superset_of( ResourceAccess const & a ) const + { + //if ( this->obj->resource.scope_level < a.obj->resource.scope_level ) + // return true; + if ( this->obj->access_type == a.obj->access_type ) + return this->obj->is_superset_of( *a.obj ); + else + return false; + } + + bool is_synchronizing() const + { + return this->obj->is_synchronizing(); + } + + unsigned int scope_level() const + { + return this->obj->resource->scope_level; + } + + unsigned int resource_id() const + { + return this->obj->resource->id; + } + + std::string mode_format() const + { + return this->obj->mode_format(); + } + + std::shared_ptr< ResourceBase > get_resource() + { + return obj->resource; + } + + /** + * Check if the associated resource is the same + * + * @param a another ResourceAccess + * @return true if `a` is associated with the same resource as `this` + */ + bool + is_same_resource( ResourceAccess const & a ) const + { + if ( this->obj->access_type == a.obj->access_type ) + return this->obj->is_same_resource( *a.obj ); + return false; + } + + bool + operator== ( ResourceAccess const & a ) const + { + if ( this->obj->access_type == a.obj->access_type ) + return *(this->obj) == *(a.obj); + return false; + } +}; // class ResourceAccess + +namespace trait +{ + +/** + * implements BuildProperties for any type which + * can be casted to a ResourceAccess + */ +template < typename T > +struct BuildProperties< + T, + typename std::enable_if< + std::is_convertible::value + >::type +> +{ + template < typename Builder > + inline static void build( Builder & builder, T const & obj ) + { + builder.add_resource( obj ); + } +}; +} // namespace trait + +struct DefaultAccessPolicy +{ + static bool is_serial(DefaultAccessPolicy, DefaultAccessPolicy) + { + return true; + } +}; + +/** + * @defgroup AccessPolicy + * + * @{ + * + * @par Description + * An implementation of the concept AccessPolicy creates a new resource-type (`Resource`) + * and should define the possible access modes / configurations for this resource-type (e.g. read/write) + * + * @par Required public member functions + * - `static bool is_serial(AccessPolicy, AccessPolicy)` + * check if the two accesses have to be **in order**. (e.g. two reads return false, an occuring write always true) + * + * - `static bool is_superset(AccessPolicy a, AccessPolicy b)` + * check if access `a` is a superset of access `b` (e.g. accessing [0,3] is a superset of accessing [1,2]) + * + * @} + */ - bool is_superset_of(ResourceAccess const& a) const +/** + * @class Resource + * @tparam AccessPolicy Defines the access-modes (e.g. read/write) that are possible + * with this resource. Required to implement the concept @ref AccessPolicy + * + * Represents a concrete resource. + * Copied objects represent the same resource. + */ +template +class Resource +{ +protected: + struct Access : public ResourceAccess::AccessBase + { + Access( std::shared_ptr< ResourceBase > resource, AccessPolicy policy ) + : ResourceAccess::AccessBase( + boost::typeindex::type_id(), + resource + ) + , policy( policy ) + {} + + Access( Access && other ) + : AccessBase(std::move((AccessBase&&)other)) + , policy( std::move(other.policy)) { - // if ( this->obj->resource.scope_level < a.obj->resource.scope_level ) - // return true; - if(this->obj->access_type == a.obj->access_type) - return this->obj->is_superset_of(*a.obj); - else - return false; } + ~Access() {} + bool is_synchronizing() const { - return this->obj->is_synchronizing(); + return policy.is_synchronizing(); } - - unsigned int scope_level() const + + bool + is_serial( ResourceAccess::AccessBase const & a_ ) const { - return this->obj->resource->scope_level; + Access const & a = *static_cast( + &a_ ); // no dynamic cast needed, type checked in ResourceAccess + return this->is_same_resource( a ) && + AccessPolicy::is_serial( this->policy, a.policy ); } - unsigned int resource_id() const + bool + is_superset_of( ResourceAccess::AccessBase const & a_ ) const { - return this->obj->resource->id; + Access const & a = *static_cast( + &a_ ); // no dynamic cast needed, type checked in ResourceAccess + return this->is_same_resource( a ) && + this->policy.is_superset_of( a.policy ); } - std::string mode_format() const + bool + operator==( ResourceAccess::AccessBase const & a_ ) const { - return this->obj->mode_format(); - } + Access const & a = *static_cast( + &a_ ); // no dynamic cast needed, type checked in ResourceAccess - std::shared_ptr get_resource() - { - return obj->resource; + return ( this->is_same_resource(a_) && this->policy == a.policy ); } - /** - * Check if the associated resource is the same - * - * @param a another ResourceAccess - * @return true if `a` is associated with the same resource as `this` - */ - bool is_same_resource(ResourceAccess const& a) const + std::string mode_format() const { - if(this->obj->access_type == a.obj->access_type) - return this->obj->is_same_resource(*a.obj); - return false; + return fmt::format("{}", policy); } - bool operator==(ResourceAccess const& a) const - { - if(this->obj->access_type == a.obj->access_type) - return *(this->obj) == *(a.obj); - return false; - } - }; // class ResourceAccess + AccessPolicy policy; + }; // struct ThisResourceAccess - namespace trait + friend class ResourceBase; + + std::shared_ptr< ResourceBase > base; + + Resource( std::shared_ptr base ) + : base( base ) { + } - /** - * implements BuildProperties for any type which - * can be casted to a ResourceAccess - */ - template - struct BuildProperties::value>::type> - { - template - static inline void build(Builder& builder, T const& obj) - { - builder.add_resource(obj); - } - }; - } // namespace trait - - struct DefaultAccessPolicy + public: + Resource() { - static bool is_serial(DefaultAccessPolicy, DefaultAccessPolicy) - { - return true; - } - }; + static unsigned i = 0; - /** - * @defgroup AccessPolicy - * - * @{ - * - * @par Description - * An implementation of the concept AccessPolicy creates a new resource-type (`Resource`) - * and should define the possible access modes / configurations for this resource-type (e.g. read/write) - * - * @par Required public member functions - * - `static bool is_serial(AccessPolicy, AccessPolicy)` - * check if the two accesses have to be **in order**. (e.g. two reads return false, an occuring write always true) - * - * - `static bool is_superset(AccessPolicy a, AccessPolicy b)` - * check if access `a` is a superset of access `b` (e.g. accessing [0,3] is a superset of accessing [1,2]) - * - * @} - */ + /* NOTE: Because of #include loops we cannot access Context and thus not worker_pool->size(). + * for this reason the modulo is done in constructor of Allocator() + */ + dispatch::thread::WorkerId worker_id = i++; // % SingletonContext::get().worker_pool->size(); + base = redGrapes::memory::alloc_shared_bind< ResourceBase >( worker_id ); + } /** - * @class Resource - * @tparam AccessPolicy Defines the access-modes (e.g. read/write) that are possible - * with this resource. Required to implement the concept @ref AccessPolicy + * Create an ResourceAccess, which represents an concrete + * access configuration associated with this resource. * - * Represents a concrete resource. - * Copied objects represent the same resource. + * @param pol AccessPolicy object, containing all access information + * @return ResourceAccess on this resource */ - template - class Resource + ResourceAccess + make_access( AccessPolicy pol ) const { - protected: - struct Access : public ResourceAccess::AccessBase - { - Access(std::shared_ptr resource, AccessPolicy policy) - : ResourceAccess::AccessBase(boost::typeindex::type_id(), resource) - , policy(policy) - { - } - - Access(Access&& other) : AccessBase(std::move((AccessBase&&) other)), policy(std::move(other.policy)) - { - } - - ~Access() - { - } - - bool is_synchronizing() const - { - return policy.is_synchronizing(); - } - - bool is_serial(ResourceAccess::AccessBase const& a_) const - { - Access const& a - = *static_cast(&a_); // no dynamic cast needed, type checked in ResourceAccess - return this->is_same_resource(a) && AccessPolicy::is_serial(this->policy, a.policy); - } - - bool is_superset_of(ResourceAccess::AccessBase const& a_) const - { - Access const& a - = *static_cast(&a_); // no dynamic cast needed, type checked in ResourceAccess - return this->is_same_resource(a) && this->policy.is_superset_of(a.policy); - } - - bool operator==(ResourceAccess::AccessBase const& a_) const - { - Access const& a - = *static_cast(&a_); // no dynamic cast needed, type checked in ResourceAccess - - return (this->is_same_resource(a_) && this->policy == a.policy); - } - - std::string mode_format() const - { - return fmt::format("{}", policy); - } - - AccessPolicy policy; - }; // struct ThisResourceAccess - - friend class ResourceBase; - - std::shared_ptr base; - - Resource(std::shared_ptr base) : base(base) - { - } - - public: - Resource() - { - static unsigned i = 0; - - /* NOTE: Because of #include loops we cannot access Context and thus not worker_pool->size(). - * for this reason the modulo is done in constructor of Allocator() - */ - dispatch::thread::WorkerId worker_id = i++; // % SingletonContext::get().worker_pool->size(); - base = redGrapes::memory::alloc_shared_bind(worker_id); - } + auto a = redGrapes::memory::alloc_shared_bind< Access >( base->get_arena_id(), base, pol ); + return ResourceAccess( a ); + } +}; // class Resource - /** - * Create an ResourceAccess, which represents an concrete - * access configuration associated with this resource. - * - * @param pol AccessPolicy object, containing all access information - * @return ResourceAccess on this resource - */ - ResourceAccess make_access(AccessPolicy pol) const - { - auto a = redGrapes::memory::alloc_shared_bind(base->get_arena_id(), base, pol); - return ResourceAccess(a); - } - }; // class Resource - template - struct SharedResourceObject : Resource - { - // protected: - std::shared_ptr obj; +template < + typename T, + typename AccessPolicy +> +struct SharedResourceObject : Resource< AccessPolicy > +{ + //protected: + std::shared_ptr< T > obj; - SharedResourceObject(std::shared_ptr obj) : obj(obj) - { - } + SharedResourceObject( std::shared_ptr obj ) + : obj(obj) {} - SharedResourceObject(SharedResourceObject const& other) : Resource(other), obj(other.obj) - { - } - }; // struct SharedResourceObject + SharedResourceObject( SharedResourceObject const & other ) + : Resource< AccessPolicy >( other ) + , obj( other.obj ) + {} +}; // struct SharedResourceObject } // namespace redGrapes -template<> -struct fmt::formatter +template <> +struct fmt::formatter< + redGrapes::ResourceAccess +> { - constexpr auto parse(format_parse_context& ctx) + constexpr auto parse( format_parse_context& ctx ) { return ctx.begin(); } - template - auto format(redGrapes::ResourceAccess const& acc, FormatContext& ctx) + template < typename FormatContext > + auto format( + redGrapes::ResourceAccess const & acc, + FormatContext & ctx + ) { return fmt::format_to( - ctx.out(), - "{{ \"resourceID\" : {}, \"scopeLevel\" : {}, \"mode\" : {} }}", - acc.resource_id(), - acc.scope_level(), - acc.mode_format()); + ctx.out(), + "{{ \"resourceID\" : {}, \"scopeLevel\" : {}, \"mode\" : {} }}", + acc.resource_id(), + acc.scope_level(), + acc.mode_format()); } }; + diff --git a/redGrapes/resource/resource_user.hpp b/redGrapes/resource/resource_user.hpp index 3edf6082..4720c444 100644 --- a/redGrapes/resource/resource_user.hpp +++ b/redGrapes/resource/resource_user.hpp @@ -22,65 +22,71 @@ namespace redGrapes { - unsigned scope_depth(); +unsigned scope_depth(); - struct Task; - struct ResourceBase; - struct ResourceAccess; +struct Task; +struct ResourceBase; +struct ResourceAccess; - struct ResourceUsageEntry - { - std::shared_ptr resource; - typename ChunkedList::MutBackwardIterator task_entry; - - bool operator==(ResourceUsageEntry const& other) const; - }; - - class ResourceUser - { - public: - ResourceUser(); - ResourceUser(ResourceUser const& other); - ResourceUser(std::initializer_list list); - - void add_resource_access(ResourceAccess ra); - void rm_resource_access(ResourceAccess ra); - void build_unique_resource_list(); - bool has_sync_access(std::shared_ptr res); - bool is_superset_of(ResourceUser const& a) const; - static bool is_superset(ResourceUser const& a, ResourceUser const& b); - static bool is_serial(ResourceUser const& a, ResourceUser const& b); +struct ResourceUsageEntry +{ + std::shared_ptr< ResourceBase > resource; + typename ChunkedList< Task*, REDGRAPES_RUL_CHUNKSIZE >::MutBackwardIterator task_entry; - uint8_t scope_level; + bool operator==( ResourceUsageEntry const & other ) const; +}; - ChunkedList access_list; - ChunkedList unique_resources; - }; // class ResourceUser +class ResourceUser +{ + public: + ResourceUser(); + ResourceUser( ResourceUser const& other ); + ResourceUser( std::initializer_list< ResourceAccess > list ); + + void add_resource_access( ResourceAccess ra ); + void rm_resource_access( ResourceAccess ra ); + void build_unique_resource_list(); + bool has_sync_access( std::shared_ptr< ResourceBase > res ); + bool is_superset_of( ResourceUser const & a ) const; + static bool is_superset( ResourceUser const & a, ResourceUser const & b ); + static bool is_serial( ResourceUser const & a, ResourceUser const & b ); + + ChunkedList access_list; + ChunkedList unique_resources; + + uint8_t scope_level; +}; // class ResourceUser } // namespace redGrapes -template<> -struct fmt::formatter +template <> +struct fmt::formatter< + redGrapes::ResourceUser +> { - constexpr auto parse(format_parse_context& ctx) + constexpr auto parse( format_parse_context& ctx ) { return ctx.begin(); } - template - auto format(redGrapes::ResourceUser const& r, FormatContext& ctx) + template < typename FormatContext > + auto format( + redGrapes::ResourceUser const & r, + FormatContext & ctx + ) { auto out = ctx.out(); - out = fmt::format_to(out, "["); + out = fmt::format_to( out, "[" ); - for(auto it = r.access_list.rbegin(); it != r.access_list.rend();) + for( auto it = r.access_list.rbegin(); it != r.access_list.rend(); ) { - out = fmt::format_to(out, "{}", *it); - if(++it != r.access_list.rend()) - out = fmt::format_to(out, ","); + out = fmt::format_to( out, "{}", *it ); + if( ++it != r.access_list.rend() ) + out = fmt::format_to( out, "," ); } - out = fmt::format_to(out, "]"); + out = fmt::format_to( out, "]" ); return out; } }; + diff --git a/redGrapes/scheduler/event.hpp b/redGrapes/scheduler/event.hpp index f876e63a..fbae8015 100644 --- a/redGrapes/scheduler/event.hpp +++ b/redGrapes/scheduler/event.hpp @@ -92,17 +92,17 @@ struct EventPtr */ struct Event { + //! the set of subsequent events + ChunkedList< EventPtr, REDGRAPES_EVENT_FOLLOWER_LIST_CHUNKSIZE > followers; + /*! number of incoming edges * state == 0: event is reached and can be removed */ - std::atomic_uint16_t state; + std::atomic< uint16_t > state; //! waker that is waiting for this event WakerId waker_id; - //! the set of subsequent events - ChunkedList< EventPtr, REDGRAPES_EVENT_FOLLOWER_LIST_CHUNKSIZE > followers; - Event(); Event(Event &); Event(Event &&); diff --git a/redGrapes/task/property/graph.hpp b/redGrapes/task/property/graph.hpp index a45589aa..556d0754 100644 --- a/redGrapes/task/property/graph.hpp +++ b/redGrapes/task/property/graph.hpp @@ -56,11 +56,6 @@ struct GraphProperty return task; } - Task * task; - - //! number of parents - uint8_t scope_depth; - //! task space that contains this task, must not be null memory::Refcounted< TaskSpace, TaskSpaceDeleter >::Guard space; @@ -80,6 +75,11 @@ struct GraphProperty scheduler::Event result_set_event; scheduler::Event result_get_event; + Task * task; + + //! number of parents + uint8_t scope_depth; + inline scheduler::EventPtr get_pre_event() { return scheduler::EventPtr { nullptr, this->task, scheduler::T_EVT_PRE };