Skip to content

Commit 50c483f

Browse files
committed
Add arangodb
1 parent 47ccacc commit 50c483f

File tree

19 files changed

+4134
-61
lines changed

19 files changed

+4134
-61
lines changed

CMakeLists.txt

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,4 +52,75 @@ if (NOT BENCHMARK_FOUND)
5252
endif ()
5353
endif ()
5454

55+
function(add_bench BENCH_PATH)
56+
string(REPLACE "/" "_" BENCH_NAME ${BENCH_PATH})
57+
add_executable(${BENCH_NAME} ${CMAKE_CURRENT_SOURCE_DIR}/${BENCH_PATH}.cpp)
58+
target_link_libraries(${BENCH_NAME}
59+
PRIVATE ${GTEST_BOTH_LIBRARIES}
60+
PRIVATE benchmark::benchmark
61+
PRIVATE ${PROJECT_NAME}
62+
)
63+
64+
if (STD)
65+
target_compile_definitions(${BENCH_NAME} PUBLIC STD_ENABLE)
66+
endif ()
67+
if (YACLIB)
68+
target_compile_definitions(${BENCH_NAME} PUBLIC YACLIB_ENABLE)
69+
endif ()
70+
if (FOLLY)
71+
target_compile_definitions(${BENCH_NAME} PUBLIC FOLLY_ENABLE)
72+
endif ()
73+
if (ARANGODB)
74+
target_compile_definitions(${BENCH_NAME} PUBLIC ARANGODB_ENABLE)
75+
endif ()
76+
if (BOOST_THREAD)
77+
target_compile_definitions(${BENCH_NAME} PUBLIC BOOST_THREAD_ENABLE)
78+
endif ()
79+
if (QT)
80+
target_compile_definitions(${BENCH_NAME} PUBLIC QT_ENABLE)
81+
endif ()
82+
if (EXPERIMENTAL)
83+
target_compile_definitions(${BENCH_NAME} PUBLIC EXPERIMENTAL_ENABLE)
84+
endif ()
85+
86+
add_test(NAME ${BENCH_NAME} COMMAND ${BENCH_NAME})
87+
endfunction()
88+
89+
find_package(Threads REQUIRED)
90+
link_libraries(Threads::Threads)
91+
include_directories(vendor)
92+
93+
if (YACLIB)
94+
FetchContent_Declare(yaclib
95+
GIT_REPOSITORY https://github.com/YACLib/YACLib.git
96+
GIT_TAG "${YACLIB}"
97+
)
98+
list(APPEND YACLIB_FLAGS "ATOMIC_EVENT")
99+
FetchContent_MakeAvailable(yaclib)
100+
link_libraries(yaclib)
101+
endif ()
102+
if (FOLLY)
103+
find_package(glog CONFIG REQUIRED) # Ad-hoc
104+
find_package(folly CONFIG REQUIRED)
105+
include_directories(${FOLLY_INCLUDE_DIR})
106+
link_libraries(Folly::folly)
107+
endif ()
108+
if (ARANGODB)
109+
add_library(arangodb STATIC
110+
${CMAKE_CURRENT_SOURCE_DIR}/vendor/arangodb/futures/Future.cpp
111+
)
112+
endif ()
113+
if (BOOST_THREAD)
114+
find_package(Boost COMPONENTS thread REQUIRED)
115+
link_libraries(Boost::thread)
116+
endif ()
117+
if (QT)
118+
find_package(Qt6 COMPONENTS Concurrent REQUIRED)
119+
link_libraries(Qt6::Concurrent)
120+
endif ()
121+
if (EXPERIMENTAL)
122+
add_link_options(-lc++experimental)
123+
endif ()
124+
125+
55126
add_subdirectory(future)

future/CMakeLists.txt

Lines changed: 3 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -1,63 +1,3 @@
1-
function(add_bench BENCH_PATH)
2-
string(REPLACE "/" "_" BENCH_NAME ${BENCH_PATH})
3-
add_executable(${BENCH_NAME} ${CMAKE_CURRENT_SOURCE_DIR}/${BENCH_PATH}.cpp)
4-
target_link_libraries(${BENCH_NAME}
5-
PRIVATE ${GTEST_BOTH_LIBRARIES}
6-
PRIVATE benchmark::benchmark
7-
PRIVATE ${PROJECT_NAME}
8-
)
9-
10-
if (STD)
11-
target_compile_definitions(${BENCH_NAME} PUBLIC STD_ENABLE)
12-
endif ()
13-
if (YACLIB)
14-
target_compile_definitions(${BENCH_NAME} PUBLIC YACLIB_ENABLE)
15-
endif ()
16-
if (FOLLY)
17-
target_compile_definitions(${BENCH_NAME} PUBLIC FOLLY_ENABLE)
18-
endif ()
19-
if (BOOST_THREAD)
20-
target_compile_definitions(${BENCH_NAME} PUBLIC BOOST_THREAD_ENABLE)
21-
endif ()
22-
if (QT)
23-
target_compile_definitions(${BENCH_NAME} PUBLIC QT_ENABLE)
24-
endif ()
25-
if (EXPERIMENTAL)
26-
target_compile_definitions(${BENCH_NAME} PUBLIC EXPERIMENTAL_ENABLE)
27-
endif ()
28-
29-
add_test(NAME ${BENCH_NAME} COMMAND ${BENCH_NAME})
30-
endfunction()
31-
32-
find_package(Threads REQUIRED)
33-
link_libraries(Threads::Threads)
34-
35-
if (YACLIB)
36-
FetchContent_Declare(yaclib
37-
GIT_REPOSITORY https://github.com/YACLib/YACLib.git
38-
GIT_TAG "${YACLIB}"
39-
)
40-
list(APPEND YACLIB_FLAGS "ATOMIC_EVENT")
41-
FetchContent_MakeAvailable(yaclib)
42-
link_libraries(yaclib)
43-
endif ()
44-
if (FOLLY)
45-
find_package(glog CONFIG REQUIRED) # Ad-hoc
46-
find_package(folly CONFIG REQUIRED)
47-
include_directories(${FOLLY_INCLUDE_DIR})
48-
link_libraries(Folly::folly)
49-
endif ()
50-
if (BOOST_THREAD)
51-
find_package(Boost COMPONENTS thread REQUIRED)
52-
link_libraries(Boost::thread)
53-
endif ()
54-
if (QT)
55-
find_package(Qt6 COMPONENTS Concurrent REQUIRED)
56-
link_libraries(Qt6::Concurrent)
57-
endif ()
58-
if (EXPERIMENTAL)
59-
add_link_options(-lc++experimental)
60-
endif ()
611
# Bench ################################################################################################################
622
macro(add_files)
633
set(BENCH_HEADERS ${BENCH_HEADERS} PARENT_SCOPE)
@@ -75,6 +15,9 @@ endif ()
7515
if (YACLIB)
7616
add_subdirectory(bind/yaclib)
7717
endif ()
18+
if (ARANGODB)
19+
add_subdirectory(bind/arangodb)
20+
endif ()
7821
if (FOLLY)
7922
add_subdirectory(bind/folly)
8023
endif ()

future/bind/all.hpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,10 @@
1212
#include <bind/folly/future.hpp>
1313
#endif
1414

15+
#ifdef ARANGODB_ENABLE
16+
#include <bind/arangodb/future.hpp>
17+
#endif
18+
1519
#ifdef BOOST_THREAD_ENABLE
1620
#include <bind/boost_thread/future.hpp>
1721
#endif
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
list(APPEND BENCH_HEADERS
2+
${CMAKE_CURRENT_SOURCE_DIR}/future.hpp
3+
)
4+
list(APPEND BENCH_SOURCES
5+
${CMAKE_CURRENT_SOURCE_DIR}/future.cpp
6+
)
7+
8+
add_files()

future/bind/arangodb/future.cpp

Lines changed: 201 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,201 @@
1+
#include <bind/arangodb/future.hpp>
2+
#include <semaphore.hpp>
3+
4+
#include <future>
5+
#include <vector>
6+
7+
#include <arangodb/futures/Future.h>
8+
#include <arangodb/futures/Promise.h>
9+
#include <arangodb/futures/Try.h>
10+
#include <arangodb/futures/Utilities.h>
11+
#include <benchmark/benchmark.h>
12+
13+
namespace bench {
14+
namespace {
15+
16+
template <typename T>
17+
T Incr(arangodb::futures::Try<T>&& t) {
18+
return std::move(t).get() + 1;
19+
}
20+
21+
arangodb::futures::Future<int> Thens(arangodb::futures::Future<int> f, std::size_t n,
22+
detail::adb::TestExecutor* executor) {
23+
for (std::size_t i = 0; i != n; ++i) {
24+
if (executor != nullptr) {
25+
arangodb::futures::Promise<int> outer_p;
26+
auto outer_f = outer_p.getFuture();
27+
std::move(f).then([executor, outer_p = std::move(outer_p)](arangodb::futures::Try<int>&& t) mutable {
28+
executor->add([outer_p = std::move(outer_p), t = std::move(t)]() mutable {
29+
std::move(outer_p).setValue(Incr<int>(std::move(t)));
30+
// TODO possible exception ignored now
31+
});
32+
}) /*implicit detach*/;
33+
f = std::move(outer_f);
34+
} else {
35+
f = std::move(f).then /*inline*/ (Incr<int>);
36+
}
37+
}
38+
return f;
39+
}
40+
41+
} // namespace
42+
namespace detail::adb {
43+
44+
TestExecutor::TestExecutor(std::size_t num_threads) {
45+
num_threads = std::max(std::size_t{1}, num_threads);
46+
_workers.reserve(num_threads);
47+
for (std::size_t i = 0; i != num_threads; ++i) {
48+
_workers.emplace_back([this] {
49+
std::unique_lock lock{_m};
50+
while (true) {
51+
while (!_jobs.empty()) {
52+
auto work = std::move(_jobs.front());
53+
_jobs.pop();
54+
lock.unlock();
55+
work();
56+
lock.lock();
57+
}
58+
if (_stop) {
59+
return;
60+
}
61+
_cv.wait(lock);
62+
}
63+
});
64+
}
65+
}
66+
67+
void TestExecutor::Restart() {
68+
std::lock_guard lock{_m};
69+
_jobs = {};
70+
}
71+
72+
void TestExecutor::Join() {
73+
{
74+
std::lock_guard lock{_m};
75+
_stop = true;
76+
}
77+
_cv.notify_all();
78+
for (auto& worker : _workers) {
79+
if (worker.joinable()) {
80+
worker.join();
81+
}
82+
}
83+
}
84+
85+
TestExecutor::~TestExecutor() {
86+
Join();
87+
}
88+
89+
void TestExecutor::add(Job job) {
90+
{
91+
std::lock_guard lock{_m};
92+
_jobs.push(std::move(job));
93+
}
94+
_cv.notify_one();
95+
}
96+
97+
} // namespace detail::adb
98+
99+
void ArangoDB::CreateFuture() {
100+
std::ignore = arangodb::futures::makeFuture<int>(42);
101+
}
102+
103+
void ArangoDB::PromiseAndFuture() {
104+
arangodb::futures::Promise<int> p;
105+
arangodb::futures::Future<int> f = p.getFuture();
106+
std::move(p).setValue(42);
107+
std::ignore = std::move(f).get();
108+
}
109+
110+
detail::adb::TestExecutor* ArangoDB::AcquireExecutor(std::size_t threads) {
111+
if (threads != 0) {
112+
return new detail::adb::TestExecutor{threads};
113+
}
114+
return nullptr;
115+
}
116+
117+
void ArangoDB::ReleaseExecutor(std::size_t threads, detail::adb::TestExecutor* e) {
118+
if (threads != 0) {
119+
delete e;
120+
}
121+
}
122+
123+
void ArangoDB::SomeThens(detail::adb::TestExecutor* executor, size_t n, bool no_inline) {
124+
const bool is_executor = executor != nullptr;
125+
auto f = arangodb::futures::makeFuture(42);
126+
f = Thens(std::move(f), n, (is_executor && no_inline ? executor : nullptr));
127+
f = Thens(std::move(f), 1, (is_executor ? executor : nullptr));
128+
f = Thens(std::move(f), n, (is_executor && no_inline ? executor : nullptr));
129+
f.wait();
130+
}
131+
132+
void ArangoDB::NoContention(benchmark::State& state) {
133+
state.PauseTiming();
134+
135+
std::vector<arangodb::futures::Promise<int>> promises(kContentionIteration);
136+
std::vector<arangodb::futures::Future<int>> futures;
137+
futures.reserve(kContentionIteration);
138+
139+
std::promise<void> p_producer;
140+
auto f_producer = p_producer.get_future();
141+
142+
for (auto& p : promises) {
143+
futures.push_back(p.getFuture().then(Incr<int>));
144+
}
145+
146+
std::thread producer{[&] {
147+
p_producer.set_value();
148+
for (auto& p : promises) {
149+
std::move(p).setValue(42);
150+
}
151+
}};
152+
153+
f_producer.wait();
154+
155+
state.ResumeTiming();
156+
157+
producer.join();
158+
}
159+
160+
void ArangoDB::Contention(benchmark::State& state) {
161+
state.PauseTiming();
162+
163+
std::vector<arangodb::futures::Promise<int>> promises(kContentionIteration);
164+
std::vector<arangodb::futures::Future<int>> futures;
165+
futures.reserve(kContentionIteration);
166+
167+
for (auto& p : promises) {
168+
futures.push_back(p.getFuture());
169+
}
170+
171+
BusySemaphoreSPSC semaphore;
172+
std::promise<void> p_consumer;
173+
auto f_consumer = p_consumer.get_future();
174+
std::promise<void> p_producer;
175+
auto f_producer = p_producer.get_future();
176+
177+
auto producer = std::thread([&] {
178+
p_producer.set_value();
179+
for (auto& p : promises) {
180+
semaphore.Release();
181+
std::move(p).setValue(42);
182+
}
183+
});
184+
auto consumer = std::thread([&] {
185+
p_consumer.set_value();
186+
for (auto& f : futures) {
187+
semaphore.Acquire();
188+
f = std::move(f).then(Incr<int>);
189+
}
190+
});
191+
192+
f_consumer.wait();
193+
f_producer.wait();
194+
195+
state.ResumeTiming();
196+
197+
producer.join();
198+
consumer.join();
199+
}
200+
201+
} // namespace bench

0 commit comments

Comments
 (0)