Skip to content

Commit

Permalink
Merge pull request #1400 from ccotter/relacy
Browse files Browse the repository at this point in the history
Proof of concept: Relacy tests
  • Loading branch information
ericniebler authored Sep 16, 2024
2 parents 2de858b + 37ef4c4 commit fbd384d
Show file tree
Hide file tree
Showing 8 changed files with 203 additions and 6 deletions.
4 changes: 2 additions & 2 deletions include/exec/__detail/__bwos_lifo_queue.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ namespace exec::bwos {
block_type(block_size, allocator),
allocator_of_t<block_type>(allocator))
, mask_(blocks_.size() - 1) {
blocks_[owner_block_].reclaim();
blocks_[owner_block_.load()].reclaim();
}

template <class Tp, class Allocator>
Expand Down Expand Up @@ -468,4 +468,4 @@ namespace exec::bwos {
auto lifo_queue<Tp, Allocator>::block_type::is_stealable() const noexcept -> bool {
return steal_tail_.load(std::memory_order_acquire) != block_size();
}
} // namespace exec::bwos
} // namespace exec::bwos
2 changes: 1 addition & 1 deletion include/exec/async_scope.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -780,7 +780,7 @@ namespace exec {
// after this, which means we can rely on its self-ownership to ensure
// that it is eventually deleted
stdexec::start(
*new __op_t{nest(static_cast<_Sender&&>(__sndr)), static_cast<_Env&&>(__env), &__impl_});
*(new __op_t{nest(static_cast<_Sender&&>(__sndr)), static_cast<_Env&&>(__env), &__impl_}));
}

template <__movable_value _Env = empty_env, sender_in<__env_t<_Env>> _Sender>
Expand Down
2 changes: 1 addition & 1 deletion include/exec/start_now.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ namespace exec {
}

void __complete() noexcept {
if (--__pending_ == 0) {
if (__pending_.fetch_sub(1) == 1) {
auto __joiner = __joiner_.exchange(nullptr);
if (__joiner) {
__joiner->join();
Expand Down
4 changes: 2 additions & 2 deletions include/stdexec/__detail/__when_all.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,7 @@ namespace stdexec {

template <class _Receiver>
void __arrive(_Receiver& __rcvr) noexcept {
if (0 == --__count_) {
if (1 == __count_.fetch_sub(1)) {
__complete(__rcvr);
}
}
Expand Down Expand Up @@ -361,7 +361,7 @@ namespace stdexec {
} else if constexpr (!__same_as<decltype(_State::__values_), __ignore>) {
// We only need to bother recording the completion values
// if we're not already in the "error" or "stopped" state.
if (__state.__state_ == __started) {
if (__state.__state_.load() == __started) {
auto& __opt_values = __tup::get<__v<_Index>>(__state.__values_);
using _Tuple = __decayed_tuple<_Args...>;
static_assert(
Expand Down
59 changes: 59 additions & 0 deletions test/rrd/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
# User-customizable variables:
CXX ?= c++
CXX_STD ?= c++20
CXXFLAGS ?= -I relacy -I relacy/relacy/fakestd -O1 -std=$(CXX_STD) -I ../../include -I ../../test -g
DEPFLAGS ?= -MD -MF $(@).d -MP -MT $(@)
build_dir = build

.SECONDARY:

test_programs = split async_scope

test_exe_files = $(foreach name,$(test_programs),$(build_dir)/$(name))

exe_files = $(test_exe_files)
o_files = $(exe_files:=.cpp.o)

ansi_term_csi = [
ansi_term_bold = $(ansi_term_csi)1m
ansi_term_green = $(ansi_term_csi)32m
ansi_term_red = $(ansi_term_csi)31m
ansi_term_reset = $(ansi_term_csi)m

COMPILE.cpp = $(CXX) $(DEPFLAGS) $(CXXFLAGS) -c
LINK.cpp = $(CXX) $(CXXFLAGS)

.PHONY: all
all: tests

.PHONY: tests
tests: $(test_exe_files)

$(build_dir)/%.check-result: $(build_dir)/% always-run
@ \
printf '%s%s ...%s\n' $(ansi_term_bold) $(*) $(ansi_term_reset) >&2; \
$(<); \
status="$${?}"; \
printf %d "$${status}" >$(@); \
if [ "$${status}" -eq 0 ]; then \
printf '%s%s %s%s\n' $(ansi_term_green) $(*) OK $(ansi_term_reset); \
else \
printf '%s%s %s%s\n' $(ansi_term_red) $(*) FAIL $(ansi_term_reset); \
fi >&2; \
exit "$${status}"

$(build_dir)/%: $(build_dir)/%.cpp.o
$(LINK.cpp) $(^) -o $(@)

$(build_dir)/%.cpp.o: %.cpp
@mkdir -p $(dir $(@))
$(COMPILE.cpp) -o $(@) $(<)

.PHONY: clean
clean:
rm -fr -- $(build_dir)/

.PHONY: always-run
always-run:

-include $(o_files:=.d)
42 changes: 42 additions & 0 deletions test/rrd/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
## Relacy tests

[Relacy (RRD)](https://www.1024cores.net/home/relacy-race-detector/rrd-introduction)
is a data race detector. It replaces the OS scheduler with an scheduler that
explores many different thread interleavings, and logs detected races or assertion
failures. Relacy can also simulate relaxed hardware by simulating old values of a
variable as allowed by the C++11 memory model.

Relacy requires a specialized build. In particular, it is a header only library that
replaces the standard library and pthread APIs at compile time. Since it places some
standard library includes, writing new tests may require working around certain
limitations in terms of what the replacement headers and accompanying runtime can
support. For example, Relacy's atomic replacements cannot support `++x`, so the
stdexec library could needs to use `x.fetch_add(1)` to be compatible with Relacy.

## Instructions

Run the following commands from within this directory (`./tests/rrd`).

```
# TODO: Merge patches into upstream Relacy @ dvyukov's version
git clone -b stdexec https://github.com/ccotter/relacy
CXX=g++-11 make -j 4
./build/split
```

## Recommended use

The Relacy tests can be manually built and executed. New tests can be written for
new algorithms, or new use cases in the stdexec library.

At this time, integrating the tests into CI is not yet recommended. If we can figure
out a more stable build on all environments/compilers, we should revisit this.

## Supported platforms

The stdexec Relacy tests have been verified to build and run on
* Linux based GCC+11 with libstdc++ (`x86_64`)
* Mac with Apple Clang 15 with libc++ (`x86_64`)

G++12 and newer are known to have issues that could be addressed with patches
to Relacy.
51 changes: 51 additions & 0 deletions test/rrd/async_scope.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
#include "../../relacy/relacy_std.hpp"
#include "../../relacy/relacy_cli.hpp"

#include <stdexec/execution.hpp>
#include <exec/async_scope.hpp>
#include <exec/static_thread_pool.hpp>
#include <test_common/schedulers.hpp>
#include <test_common/type_helpers.hpp>

#include <chrono>
#include <random>
#include <iostream>

using rl::nvar;
using rl::nvolatile;
using rl::mutex;

namespace ex = stdexec;
using exec::async_scope;

struct async_scope_bug : rl::test_suite<async_scope_bug, 1>
{
static size_t const dynamic_thread_count = 2;

void thread(unsigned)
{
exec::static_thread_pool ctx{1};

ex::scheduler auto sch = ctx.get_scheduler();

exec::async_scope scope;
std::atomic_bool produced{false};
ex::sender auto begin = ex::schedule(sch);
{
ex::sender auto ftr = scope.spawn_future(begin | stdexec::then([&]() { produced.store(true); }));
(void) ftr;
}
stdexec::sync_wait(scope.on_empty() | stdexec::then([&]() {
RL_ASSERT(produced.load());
}));
}
};

int main()
{
rl::test_params p;
p.iteration_count = 50000;
p.execution_depth_limit = 10000;
rl::simulate<async_scope_bug>(p);
return 0;
}
45 changes: 45 additions & 0 deletions test/rrd/split.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
#include "../../relacy/relacy_std.hpp"
#include "../../relacy/relacy_cli.hpp"

#include <stdexec/execution.hpp>
#include <exec/async_scope.hpp>
#include <exec/static_thread_pool.hpp>
#include <test_common/schedulers.hpp>

#include <chrono>
#include <random>
#include <iostream>

using rl::nvar;
using rl::nvolatile;
using rl::mutex;

namespace ex = stdexec;
using exec::async_scope;

struct split_bug : rl::test_suite<split_bug, 1>
{
static size_t const dynamic_thread_count = 2;

void thread(unsigned)
{
exec::static_thread_pool pool{1};
auto split = ex::schedule(pool.get_scheduler()) //
| ex::then([] {
return 42;
})
| ex::split();

auto [val] = ex::sync_wait(split).value();
RL_ASSERT(val == 42);
}
};

int main()
{
rl::test_params p;
p.iteration_count = 50000;
p.execution_depth_limit = 10000;
rl::simulate<split_bug>(p);
return 0;
}

0 comments on commit fbd384d

Please sign in to comment.