Commit b9bb90a4 by FritzFlorian

Add ttas_spinlock.

parent 14cc1155
Pipeline #1153 passed with stages
in 3 minutes 29 seconds
......@@ -34,7 +34,7 @@ long fib(long n) {
int main() {
PROFILE_ENABLE
pls::scheduler scheduler{&my_scheduler_memory, 2};
pls::scheduler scheduler{&my_scheduler_memory, 8};
long result;
scheduler.perform_work([&] {
......
......@@ -5,7 +5,9 @@ add_library(pls STATIC
include/pls/algorithms/invoke_parallel.h
include/pls/algorithms/invoke_parallel_impl.h
include/pls/internal/base/spin_lock.h src/internal/base/spin_lock.cpp
include/pls/internal/base/spin_lock.h
include/pls/internal/base/tas_spin_lock.h src/internal/base/tas_spin_lock.cpp
include/pls/internal/base/ttas_spin_lock.h src/internal/base/ttas_spin_lock.cpp
include/pls/internal/base/thread.h src/internal/base/thread.cpp
include/pls/internal/base/thread_impl.h
include/pls/internal/base/barrier.h src/internal/base/barrier.cpp
......@@ -20,6 +22,7 @@ add_library(pls STATIC
include/pls/internal/helpers/prohibit_new.h
include/pls/internal/helpers/profiler.h
include/pls/internal/helpers/mini_benchmark.h
include/pls/internal/helpers/unique_id.h
include/pls/internal/scheduling/root_task.h src/internal/scheduling/root_task.cpp
include/pls/internal/scheduling/thread_state.h src/internal/scheduling/thread_state.cpp
......@@ -29,7 +32,7 @@ add_library(pls STATIC
include/pls/internal/scheduling/run_on_n_threads_task.h src/internal/scheduling/run_on_n_threads_task.cpp
include/pls/internal/scheduling/fork_join_task.h src/internal/scheduling/fork_join_task.cpp
include/pls/internal/scheduling/scheduler_memory.h src/internal/scheduling/scheduler_memory.cpp
include/pls/internal/helpers/unique_id.h)
)
# Add everything in `./include` to be in the include path of this project
target_include_directories(pls
......
......@@ -2,32 +2,14 @@
#ifndef PLS_SPINLOCK_H
#define PLS_SPINLOCK_H
#include <atomic>
#include <iostream>
#include "pls/internal/base/thread.h"
#include "tas_spin_lock.h"
#include "ttas_spin_lock.h"
namespace pls {
namespace internal {
namespace base {
/**
* A simple set and test_and_set based spin lock implementation.
*
* PORTABILITY:
* Current implementation is based on C++ 11 atomic_flag.
*/
class spin_lock {
std::atomic_flag flag_;
unsigned int yield_at_tries_;
public:
spin_lock(): flag_{ATOMIC_FLAG_INIT}, yield_at_tries_{1024} {};
spin_lock(const spin_lock& other): flag_{ATOMIC_FLAG_INIT}, yield_at_tries_{other.yield_at_tries_} {}
void lock();
void unlock();
};
// Default Spin-Lock implementation for this project.
using spin_lock = tas_spin_lock;
}
}
}
......
#ifndef PLS_TAS_SPIN_LOCK_H
#define PLS_TAS_SPIN_LOCK_H
#include "tas_spin_lock.h"
#include <atomic>
#include <iostream>
#include "pls/internal/base/thread.h"
namespace pls {
namespace internal {
namespace base {
/**
* A simple set and test_and_set based spin lock implementation.
*
* PORTABILITY:
* Current implementation is based on C++ 11 atomic_flag.
*/
class tas_spin_lock {
std::atomic_flag flag_;
unsigned int yield_at_tries_;
public:
tas_spin_lock(): flag_{ATOMIC_FLAG_INIT}, yield_at_tries_{1024} {};
tas_spin_lock(const tas_spin_lock& other): flag_{ATOMIC_FLAG_INIT}, yield_at_tries_{other.yield_at_tries_} {}
void lock();
bool try_lock();
void unlock();
};
}
}
}
#endif //PLS_TAS_SPIN_LOCK_H
#ifndef PLS_TTAS_SPIN_LOCK_H
#define PLS_TTAS_SPIN_LOCK_H
#include "tas_spin_lock.h"
#include <atomic>
#include <iostream>
#include "pls/internal/base/thread.h"
namespace pls {
namespace internal {
namespace base {
/**
* A simple set and test_and_set based spin lock implementation.
*
* PORTABILITY:
* Current implementation is based on C++ 11 atomic_flag.
*/
class ttas_spin_lock {
std::atomic<int> flag_;
unsigned int yield_at_tries_;
public:
ttas_spin_lock(): flag_{0}, yield_at_tries_{1024} {};
ttas_spin_lock(const ttas_spin_lock& other): flag_{0}, yield_at_tries_{other.yield_at_tries_} {}
void lock();
bool try_lock();
void unlock();
};
}
}
}
#endif //PLS_TTAS_SPIN_LOCK_H
#include "pls/internal/helpers/profiler.h"
#include "pls/internal/base/spin_lock.h"
#include "pls/internal/base/tas_spin_lock.h"
namespace pls {
namespace internal {
namespace base {
// TODO: Research/Measure how the memory fences/orders influence this.
// For now we simply try to be safe by forcing this lock to
// also act as a strict memory fence.
void spin_lock::lock() {
void tas_spin_lock::lock() {
PROFILE_LOCK("Acquire Lock")
int tries = 0;
while (flag_.test_and_set(std::memory_order_seq_cst)) {
while (flag_.test_and_set(std::memory_order_acquire)) {
tries++;
if (tries % yield_at_tries_ == 0) {
this_thread::yield();
......@@ -18,8 +15,12 @@ namespace pls {
}
}
void spin_lock::unlock() {
flag_.clear(std::memory_order_seq_cst);
bool tas_spin_lock::try_lock() {
return flag_.test_and_set(std::memory_order_acquire) == 0;
}
void tas_spin_lock::unlock() {
flag_.clear(std::memory_order_release);
}
}
}
......
#include "pls/internal/helpers/profiler.h"
#include "pls/internal/base/ttas_spin_lock.h"
namespace pls {
namespace internal {
namespace base {
void ttas_spin_lock::lock() {
PROFILE_LOCK("Acquire Lock")
int tries = 0;
int expected = 0;
do {
while (flag_.load(std::memory_order_relaxed) == 1) {
tries++;
if (tries % yield_at_tries_ == 0) {
this_thread::yield();
}
}
expected = 0;
} while (!flag_.compare_exchange_weak(expected, 1, std::memory_order_acquire));
}
bool ttas_spin_lock::try_lock() {
int expected = 0;
return flag_.load(std::memory_order_relaxed) == 0 && flag_.compare_exchange_weak(expected, 1, std::memory_order_acquire);
}
void ttas_spin_lock::unlock() {
flag_.store(0, std::memory_order_release);
}
}
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment