[UNTESTED] Basic queue and fan-in fabric implementation without full template generalization
This commit is contained in:
88
include/weaver/atomic.h
Normal file
88
include/weaver/atomic.h
Normal file
@@ -0,0 +1,88 @@
|
||||
#ifndef THWEAVER_ATOMIC_H
|
||||
#define THWEAVER_ATOMIC_H
|
||||
|
||||
#include <cstdint>
|
||||
#include <concepts>
|
||||
#include <limits>
|
||||
#include <type_traits>
|
||||
|
||||
template <typename T>
|
||||
concept Additive = std::is_integral_v<T> && !std::is_same_v<T, bool>;
|
||||
|
||||
template <typename A, typename T>
|
||||
concept AtomicAdditive =
|
||||
requires(A a, T v) {
|
||||
{
|
||||
a.load()
|
||||
}
|
||||
-> std::same_as<T>;
|
||||
{
|
||||
a.store(v)
|
||||
};
|
||||
{
|
||||
a.fetch_add(v)
|
||||
}
|
||||
-> std::same_as<T>;
|
||||
{
|
||||
a.fetch_sub(v)
|
||||
}
|
||||
-> std::same_as<T>;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
concept Bitwise =
|
||||
(std::is_integral_v<T> || std::is_enum_v<T>) &&
|
||||
!std::is_same_v<T, bool>;
|
||||
|
||||
template <typename A, typename T>
|
||||
concept AtomicBitwise =
|
||||
requires(A a, T v) {
|
||||
{
|
||||
a.load()
|
||||
}
|
||||
-> std::same_as<T>;
|
||||
{
|
||||
a.store(v)
|
||||
};
|
||||
{
|
||||
a.fetch_or(v)
|
||||
}
|
||||
-> std::same_as<T>;
|
||||
{
|
||||
a.fetch_and(v)
|
||||
}
|
||||
-> std::same_as<T>;
|
||||
{
|
||||
a.fetch_xor(v)
|
||||
}
|
||||
-> std::same_as<T>;
|
||||
};
|
||||
|
||||
// Uses the full bitmap
|
||||
template<typename Atomic, typename T, uint32_t NumBits, typename Index = uint32_t>
|
||||
requires Bitwise<T> && AtomicBitwise<Atomic, T> &&
|
||||
Additive<Index> && std::is_unsigned_v<Index>
|
||||
class AtomicBitmap {
|
||||
public:
|
||||
static_assert(NumBits <= std::numeric_limits<T>::digits);
|
||||
|
||||
AtomicBitmap() noexcept
|
||||
: bits(T {}), rotation(0) {}
|
||||
|
||||
void reset(const T &bits, const Index rotation) noexcept;
|
||||
|
||||
bool get_bit(const Index n) const noexcept;
|
||||
void set_bit(const Index n) noexcept;
|
||||
void clear_bit(const Index n) noexcept;
|
||||
|
||||
void rotate(const Index n) noexcept;
|
||||
Index get_rotation() const noexcept;
|
||||
|
||||
Index get_low_bit() const noexcept;
|
||||
Index rotate_to_low_bit(const Index offset = 0) noexcept;
|
||||
private:
|
||||
Atomic bits;
|
||||
Index rotation;
|
||||
};
|
||||
|
||||
#endif
|
||||
35
include/weaver/bitwise.h
Normal file
35
include/weaver/bitwise.h
Normal file
@@ -0,0 +1,35 @@
|
||||
#ifndef THWEAVER_BITWISE_H
|
||||
#define THWEAVER_BITWISE_H
|
||||
|
||||
#include <concepts>
|
||||
|
||||
template <typename T>
|
||||
concept Bitwise =
|
||||
requires(T a, T b) {
|
||||
{
|
||||
a & b
|
||||
}
|
||||
-> std::same_as<T>;
|
||||
{
|
||||
a | b
|
||||
}
|
||||
-> std::same_as<T>;
|
||||
{
|
||||
a ^ b
|
||||
}
|
||||
-> std::same_as<T>;
|
||||
{
|
||||
~a
|
||||
}
|
||||
-> std::same_as<T>;
|
||||
{
|
||||
a << 1
|
||||
}
|
||||
-> std::same_as<T>;
|
||||
{
|
||||
a >> 1
|
||||
}
|
||||
-> std::same_as<T>;
|
||||
};
|
||||
|
||||
#endif
|
||||
114
include/weaver/fabric.h
Normal file
114
include/weaver/fabric.h
Normal file
@@ -0,0 +1,114 @@
|
||||
#ifndef THWEAVER_FABRIC_H
|
||||
#define THWEAVER_FABRIC_H
|
||||
|
||||
#include <array>
|
||||
#include <atomic>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <new>
|
||||
#include <weaver/results.h>
|
||||
|
||||
namespace THWeaver {
|
||||
|
||||
template <typename MessageType, std::size_t qsize_expt> class EndpointQueue {
|
||||
public:
|
||||
static constexpr size_t CLS =
|
||||
std::hardware_destructive_interference_size;
|
||||
static constexpr std::size_t QSIZE = 1 << qsize_expt;
|
||||
static constexpr std::size_t QSIZE_MASK = QSIZE - 1;
|
||||
|
||||
EndpointQueue(const EndpointQueue<MessageType, qsize_expt> &) = delete;
|
||||
EndpointQueue &
|
||||
operator=(const EndpointQueue<MessageType, qsize_expt> &) = delete;
|
||||
EndpointQueue(EndpointQueue<MessageType, qsize_expt> &&) = delete;
|
||||
EndpointQueue &
|
||||
operator=(EndpointQueue<MessageType, qsize_expt> &&) = delete;
|
||||
|
||||
void init() noexcept;
|
||||
void flush() noexcept;
|
||||
|
||||
std::size_t size() const noexcept;
|
||||
bool is_empty() const noexcept;
|
||||
bool is_full() const noexcept;
|
||||
|
||||
std::size_t get_head() const noexcept;
|
||||
std::size_t get_tail() const noexcept;
|
||||
|
||||
EndpointQueueSendResult send(MessageType &&message) noexcept;
|
||||
EndpointQueueRecvResult recv(MessageType &buffer) noexcept;
|
||||
void recv_unsafe(MessageType &buffer, std::size_t old_head) noexcept;
|
||||
|
||||
private:
|
||||
alignas(CLS) std::array<MessageType, QSIZE> buffer;
|
||||
alignas(CLS) std::atomic<std::size_t> head;
|
||||
alignas(CLS) std::atomic<std::size_t> tail;
|
||||
};
|
||||
|
||||
template <typename MessageType, std::size_t qsize_expt,
|
||||
std::size_t IN_THREAD_CNT>
|
||||
class FanInFabric {
|
||||
public:
|
||||
using BitmapType = uint64_t;
|
||||
|
||||
static constexpr size_t CLS =
|
||||
std::hardware_destructive_interference_size;
|
||||
static constexpr std::size_t QSIZE = 1 << qsize_expt;
|
||||
static constexpr std::size_t QSIZE_MASK = QSIZE - 1;
|
||||
static constexpr std::size_t BITMAP_SIZE = sizeof(BitmapType) * 8;
|
||||
static constexpr BitmapType THREAD_BITMAP_MASK =
|
||||
IN_THREAD_CNT == BITMAP_SIZE
|
||||
? ~BitmapType(0)
|
||||
: (BitmapType(1) << IN_THREAD_CNT) - 1;
|
||||
|
||||
static_assert(IN_THREAD_CNT <= BITMAP_SIZE, "Producer limit exceeded");
|
||||
|
||||
FanInFabric(const FanInFabric<MessageType, qsize_expt, IN_THREAD_CNT>
|
||||
&) = delete;
|
||||
FanInFabric &
|
||||
operator=(const FanInFabric<MessageType, qsize_expt, IN_THREAD_CNT> &) =
|
||||
delete;
|
||||
FanInFabric(FanInFabric<MessageType, qsize_expt, IN_THREAD_CNT> &&) =
|
||||
delete;
|
||||
FanInFabric &
|
||||
operator=(FanInFabric<MessageType, qsize_expt, IN_THREAD_CNT> &&) =
|
||||
delete;
|
||||
|
||||
void init() noexcept;
|
||||
template <std::size_t thread_id> void flush() noexcept;
|
||||
void flush_all() noexcept;
|
||||
|
||||
template <std::size_t thread_id>
|
||||
FanInFabricSendResult send(MessageType &&message) noexcept;
|
||||
|
||||
FanInFabricRecvBitmapResult
|
||||
recv_bitmap_only(MessageType &buffer) noexcept;
|
||||
FanInFabricRecvTryResult recv_try(MessageType &buffer) noexcept;
|
||||
FanInFabricRecvAggrResult recv_aggr(MessageType &buffer) noexcept;
|
||||
|
||||
void full_scan(BitmapType &bitmap) noexcept;
|
||||
|
||||
template <std::size_t thread_id> std::size_t size() const noexcept;
|
||||
template <std::size_t thread_id> bool is_empty() const noexcept;
|
||||
template <std::size_t thread_id> bool is_full() const noexcept;
|
||||
|
||||
private:
|
||||
std::array<EndpointQueue<MessageType, qsize_expt>, IN_THREAD_CNT>
|
||||
in_queues;
|
||||
|
||||
alignas(CLS) std::atomic<BitmapType> hint;
|
||||
struct alignas(CLS) DiscoveryList {
|
||||
std::array<uint8_t, IN_THREAD_CNT> next;
|
||||
std::array<uint8_t, IN_THREAD_CNT> prev;
|
||||
uint8_t first;
|
||||
uint8_t last;
|
||||
void init() noexcept;
|
||||
void move_first_to_last() noexcept;
|
||||
void move_to_last(uint8_t index) noexcept;
|
||||
} dl;
|
||||
std::size_t rotation;
|
||||
BitmapType rotate(BitmapType bitmap) const noexcept;
|
||||
};
|
||||
|
||||
} // namespace THWeaver
|
||||
|
||||
#endif
|
||||
21
include/weaver/results.h
Normal file
21
include/weaver/results.h
Normal file
@@ -0,0 +1,21 @@
|
||||
#ifndef THWEAVER_RESULTS_H
|
||||
#define THWEAVER_RESULTS_H
|
||||
|
||||
#include <cstdint>
|
||||
namespace THWeaver {
|
||||
|
||||
enum class EndpointQueueSendResult : uint32_t { Ok = 0, ErrFull = 1 };
|
||||
|
||||
enum class EndpointQueueRecvResult { Ok, ErrEmpty };
|
||||
|
||||
enum class FanInFabricSendResult : uint32_t { Ok = 0, ErrFull = 1 };
|
||||
|
||||
enum class FanInFabricRecvBitmapResult { Ok, ErrBitmapEmpty, ErrBitmapFailed };
|
||||
|
||||
enum class FanInFabricRecvTryResult { Ok, ErrTryFailed };
|
||||
|
||||
enum class FanInFabricRecvAggrResult { Ok, ErrAggrFailed };
|
||||
|
||||
} // namespace THWeaver
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user