Skip to content

Commit

Permalink
Attempt fix on GitHub Action error
Browse files Browse the repository at this point in the history
  • Loading branch information
seanmiddleditch committed Nov 9, 2019
1 parent 29b6a2e commit 7392550
Show file tree
Hide file tree
Showing 7 changed files with 102 additions and 55 deletions.
13 changes: 6 additions & 7 deletions .github/workflows/main.yml
Expand Up @@ -19,16 +19,16 @@ jobs:
- name: Checkout
uses: actions/checkout@master
- name: Set Environment
run: echo ::set-env name=DEPS::%HOME%\deps
run: echo "::set-env name=DEPS::$Env:HOME\deps"
- name: Install SDL2 SDK
run: |
curl -s -S -o SDL2-devel-2.0.9-VC.zip -L https://www.libsdl.org/release/SDL2-devel-2.0.9-VC.zip
unzip SDL2-devel-2.0.9-VC.zip -d %DEPS%
echo ::set-env name=SDL2DIR::%DEPS%\SDL2-2.0.9
unzip SDL2-devel-2.0.9-VC.zip -d "$Env:DEPS"
echo "::set-env name=SDL2DIR::$Env:DEPS\SDL2-2.0.9"
- name: Install Assimp SDK
run: |
curl -s -S -o assimp-4.1.0.zip -L https://grimmdeps.blob.core.windows.net/deps/assimp-4.1.0.zip
unzip assimp-4.1.0.zip -d %DEPS%
unzip assimp-4.1.0.zip -d "$Env:DEPS"
- name: Install Ninja
uses: seanmiddleditch/gha-setup-ninja@master
- name: Setup VS Environment
Expand All @@ -41,7 +41,7 @@ jobs:
run: |
mkdir build
cd build
cmake -G Ninja -DCMAKE_BUILD_TYPE:STRING=${{ matrix.config }} -DBUILD_SHARED_LIBS=YES -DASSIMP_ROOT_DIR:PATH="%DEPS%/assimp-4.1.0" .. || exit /b 1
cmake -G Ninja -DCMAKE_BUILD_TYPE:STRING=${{ matrix.config }} -DBUILD_SHARED_LIBS=YES -DASSIMP_ROOT_DIR:PATH="$Env:DEPS/assimp-4.1.0" ..
- name: Build
run: cmake --build build --parallel
- name: Test
Expand All @@ -62,7 +62,6 @@ jobs:
cc: gcc-7
- name: macOS
os: macos-latest
xcode: 10.3
cxxflags: -Wall -Werror
cxx: clang++
cc: clang
Expand All @@ -76,7 +75,7 @@ jobs:
uses: seanmiddleditch/gha-setup-ninja@master
- name: Select XCode
run: sudo /usr/bin/xcode-select -switch /Applications/Xcode_${{ matrix.xcode }}.app
if: success() && runner.os == 'macOS'
if: success() && matrix.xcode != ''
- name: Install uuid-dev
run: |
sudo apt-get -yq update
Expand Down
3 changes: 1 addition & 2 deletions source/libassetdb/public/potato/assetdb/hash_cache.h
Expand Up @@ -16,8 +16,7 @@
namespace up {
class HashCache {
public:
HashCache() = default;
HashCache(FileSystem& fileSystem) : _fileSystem(fileSystem) {}
explicit HashCache(FileSystem& fileSystem) : _fileSystem(fileSystem) {}

static UP_ASSETDB_API uint64 hashAssetContent(span<byte const> contents) noexcept;
static UP_ASSETDB_API uint64 hashAssetStream(Stream& stream);
Expand Down
4 changes: 2 additions & 2 deletions source/libruntime/public/potato/runtime/filesystem.h
Expand Up @@ -15,8 +15,8 @@ namespace up {
public:
virtual ~FileSystem() = default;

FileSystem(FileSystem const&) = default;
FileSystem& operator=(FileSystem const&) = default;
FileSystem(FileSystem const&) = delete;
FileSystem& operator=(FileSystem const&) = delete;

virtual bool fileExists(zstring_view path) const noexcept = 0;
virtual bool directoryExists(zstring_view path) const noexcept = 0;
Expand Down
49 changes: 32 additions & 17 deletions source/libruntime/public/potato/runtime/lock_free_queue.h
Expand Up @@ -11,42 +11,57 @@
namespace up {
template <typename T, std::size_t CacheLineWidth = 64>
struct alignas(CacheLineWidth) AlignedAtomic : std::atomic<T> {
using std::atomic<T>::atomic;
char _padding[CacheLineWidth - sizeof(std::atomic<T>)];
};

template <typename T, std::size_t Size = 512, std::size_t CacheLineWidth = 64>
template <typename T, std::size_t Capacity = 512, std::size_t CacheLineWidth = 64>
class LockFreeQueue {
static constexpr std::uint32_t kBufferSize = Size;
static constexpr std::uint32_t kBufferSize = Capacity;
static constexpr std::uint32_t kBufferMask = kBufferSize - 1;

static_assert((kBufferSize & kBufferMask) == 0, "ConcurrentQueue size must be a power of 2");

AlignedAtomic<std::uint32_t, CacheLineWidth> _sequence[kBufferSize];
AlignedAtomic<std::uint32_t, CacheLineWidth> _enque;
AlignedAtomic<std::uint32_t, CacheLineWidth> _deque;
std::aligned_storage_t<sizeof(T), alignof(T)> _buffer[kBufferSize];
static_assert((kBufferSize & kBufferMask) == 0, "LockFreeQueue size must be a power of 2");

public:
inline LockFreeQueue() noexcept;
LockFreeQueue();
~LockFreeQueue();

LockFreeQueue(LockFreeQueue const&) = delete;
LockFreeQueue& operator=(LockFreeQueue const&) = delete;

constexpr auto capacity() const noexcept { return Capacity; }

template <typename InsertT>
[[nodiscard]] inline bool tryEnque(InsertT&& value);
[[nodiscard]] inline bool tryDeque(T& out);

private:
AlignedAtomic<std::uint32_t, CacheLineWidth> _enque;
AlignedAtomic<std::uint32_t, CacheLineWidth> _deque;
AlignedAtomic<std::uint32_t, CacheLineWidth>* _sequence = nullptr;
std::aligned_storage_t<sizeof(T), alignof(T)>* _buffer = nullptr;
};

template <typename T, std::size_t Size, std::size_t CacheLineWidth>
LockFreeQueue<T, Size, CacheLineWidth>::LockFreeQueue() noexcept {
_enque.store(0, std::memory_order_relaxed);
_deque.store(0, std::memory_order_relaxed);
template <typename T, std::size_t Capacity, std::size_t CacheLineWidth>
LockFreeQueue<T, Capacity, CacheLineWidth>::LockFreeQueue()
: _enque(0)
, _deque(0)
, _sequence(new AlignedAtomic<std::uint32_t, CacheLineWidth>[kBufferSize])
, _buffer(new std::aligned_storage_t<sizeof(T), alignof(T)>[kBufferSize])
{
for (std::uint32_t i = 0; i != kBufferSize; ++i)
_sequence[i].store(i, std::memory_order_relaxed);
}

template <typename T, std::size_t Size, std::size_t CacheLineWidth>
template <typename T, std::size_t Capacity, std::size_t CacheLineWidth>
LockFreeQueue<T, Capacity, CacheLineWidth>::~LockFreeQueue() {
delete[] _sequence;
delete[] _buffer;
}

template <typename T, std::size_t Capacity, std::size_t CacheLineWidth>
template <typename InsertT>
bool LockFreeQueue<T, Size, CacheLineWidth>::tryEnque(InsertT&& value) {
bool LockFreeQueue<T, Capacity, CacheLineWidth>::tryEnque(InsertT&& value) {
std::uint32_t target = _enque.load(std::memory_order_relaxed);
std::uint32_t id = _sequence[target & kBufferMask].load(std::memory_order_acquire);
std::int32_t delta = id - target;
Expand All @@ -66,8 +81,8 @@ namespace up {
return true;
}

template <typename T, std::size_t Size, std::size_t CacheLineWidth>
bool LockFreeQueue<T, Size, CacheLineWidth>::tryDeque(T& out) {
template <typename T, std::size_t Capacity, std::size_t CacheLineWidth>
bool LockFreeQueue<T, Capacity, CacheLineWidth>::tryDeque(T& out) {
std::uint32_t target = _deque.load(std::memory_order_relaxed);
std::uint32_t id = _sequence[target & kBufferMask].load(std::memory_order_acquire);
std::int32_t delta = id - (target + 1);
Expand Down
4 changes: 2 additions & 2 deletions source/libruntime/public/potato/runtime/task_worker.h
Expand Up @@ -18,8 +18,8 @@ namespace up {
UP_RUNTIME_API explicit TaskWorker(TaskQueue& queue, zstring_view name);
UP_RUNTIME_API ~TaskWorker();

TaskWorker(TaskWorker&&) = default;
TaskWorker& operator=(TaskWorker&&) = default;
TaskWorker(TaskWorker&&) = delete;
TaskWorker& operator=(TaskWorker&&) = delete;

SmallThreadId smallThreadId() const noexcept { return _threadId; }

Expand Down
80 changes: 57 additions & 23 deletions source/libruntime/tests/test_lock_free_queue.cpp
Expand Up @@ -4,48 +4,82 @@

DOCTEST_TEST_SUITE("[potato][runtime] LockFreeQueue") {
using namespace up;
using namespace up;

DOCTEST_TEST_CASE("default") {
LockFreeQueue<int> queue;
}

DOCTEST_TEST_CASE("thread") {
constexpr int size = 1024;
LockFreeQueue<int, size> queue;
DOCTEST_TEST_CASE("fill") {
LockFreeQueue<std::size_t> queue;

for (std::size_t i = 0; i < queue.capacity(); ++i) {
DOCTEST_CHECK(queue.tryEnque(i));
}

for (int i = 0; i < size; ++i) {
DOCTEST_CHECK(!queue.tryEnque(0));
}

DOCTEST_TEST_CASE("sequential") {
LockFreeQueue<std::size_t> queue;

for (std::size_t i = 0; i < queue.capacity(); ++i) {
DOCTEST_CHECK(queue.tryEnque(i));
}

int total1 = 0;
DOCTEST_CHECK(!queue.tryEnque(0));

for (std::size_t i = 0; i < queue.capacity(); ++i) {
std::size_t result;
DOCTEST_CHECK(queue.tryDeque(result));
DOCTEST_CHECK_EQ(i, result);
}

std::size_t empty;
DOCTEST_CHECK(!queue.tryDeque(empty));
}

DOCTEST_TEST_CASE("thread") {
LockFreeQueue<std::size_t> queue;

std::size_t total1 = 0;
auto thread1 = std::thread([&] {
int count;
while (queue.tryDeque(count)) {
total1 += count;
for (;;) {
std::size_t count;
if (queue.tryDeque(count)) {
if (count == 0) {
break;
}
total1 += count;
}
}
});

int total2 = 0;
std::size_t total2 = 0;
auto thread2 = std::thread([&] {
int count;
while (queue.tryDeque(count)) {
total2 += count;
for (;;) {
std::size_t count;
if (queue.tryDeque(count)) {
if (count == 0) {
break;
}
total2 += count;
}
}
});

std::size_t expected = 0;
for (std::size_t i = 2; i < queue.capacity(); ++i) {
DOCTEST_CHECK(queue.tryEnque(i));
expected += i;
}

// signals end to threads
DOCTEST_CHECK(queue.tryEnque(0));
DOCTEST_CHECK(queue.tryEnque(0));

thread1.join();
thread2.join();

// sum of [0, size] is sum(0...size-1)
// identities:
// sum(1...N) = N(N+1)/2
// 0+N=N
// expand identities:
// sum(0...N-1) = sum(1...N-1)
// sum(1...N-1) = (N-1)(N-1+1)/2
// simplify:
// (N-1)(N-1+1)/2 = N(N-1)/2
DOCTEST_CHECK_EQ(total1 + total2, (size * (size - 1)) / 2);
DOCTEST_CHECK_EQ(total1 + total2, expected);
}
}
4 changes: 2 additions & 2 deletions source/spud/public/potato/spud/traits.h
Expand Up @@ -43,11 +43,11 @@ namespace up {
template <bool C, typename T = void>
using enable_if_t = typename std::enable_if_t<C, T>;

#if defined(__cpp_lib_invoke)
#if defined(__cpp_lib_constexpr_invoke)
using std::invoke;
#else
template <class Class, class Return, class First, class... Rest>
decltype(auto) invoke(Return Class::*func, First&& first, Rest&&... rest) {
constexpr decltype(auto) invoke(Return Class::*func, First&& first, Rest&&... rest) {
if constexpr (std::is_member_function_pointer_v<decltype(func)>) {
return (std::forward<First>(first).*func)(std::forward<Rest>(rest)...);
}
Expand Down

0 comments on commit 7392550

Please sign in to comment.