Skip to content

Commit 17e8c63

Browse files
Charlie FraschCharlie Frasch
Charlie Frasch
authored and
Charlie Frasch
committed
Clean up; add bench and bench_all apps
1 parent 69c546a commit 17e8c63

File tree

8 files changed

+181
-15
lines changed

8 files changed

+181
-15
lines changed

CMakeLists.txt

+9
Original file line numberDiff line numberDiff line change
@@ -58,3 +58,12 @@ target_compile_options(unitTests PRIVATE -fsanitize=undefined -fsanitize=address
5858
target_link_libraries(unitTests PRIVATE asan ubsan gtest gtest_main)
5959
target_link_options(unitTests PRIVATE -fsanitize=undefined -fsanitize=address)
6060
gtest_add_tests(TARGET unitTests)
61+
62+
63+
find_package(benchmark REQUIRED)
64+
add_executable(bench bench.cpp)
65+
target_compile_options(bench PRIVATE -Wno-interference-size)
66+
target_link_libraries(bench PRIVATE benchmark::benchmark)
67+
68+
add_executable(bench_all bench_all.cpp)
69+
target_compile_options(bench_all PRIVATE -Wno-interference-size)

Fifo3.hpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ class Fifo3 : private Alloc
3232

3333
/// Returns the number of elements in the fifo
3434
auto size() const noexcept {
35-
auto pushCursor = pushCursor_.load(std::memory_order_acquire);
35+
auto pushCursor = pushCursor_.load(std::memory_order_relaxed);
3636
auto popCursor = popCursor_.load(std::memory_order_relaxed);
3737

3838
assert(popCursor <= pushCursor);

Fifo4.hpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ class Fifo4 : private Alloc
3131

3232
/// Returns the number of elements in the fifo
3333
auto size() const noexcept {
34-
auto pushCursor = pushCursor_.load(std::memory_order_acquire);
34+
auto pushCursor = pushCursor_.load(std::memory_order_relaxed);
3535
auto popCursor = popCursor_.load(std::memory_order_relaxed);
3636

3737
assert(popCursor <= pushCursor);

Fifo4a.hpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ class Fifo4a : private Alloc
3131

3232
/// Returns the number of elements in the fifo
3333
auto size() const noexcept {
34-
auto pushCursor = pushCursor_.load(std::memory_order_acquire);
34+
auto pushCursor = pushCursor_.load(std::memory_order_relaxed);
3535
auto popCursor = popCursor_.load(std::memory_order_relaxed);
3636

3737
assert(popCursor <= pushCursor);

Fifo5.hpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ class Fifo5 : private Alloc
4242

4343
/// Returns the number of elements in the fifo
4444
auto size() const noexcept {
45-
auto pushCursor = pushCursor_.load(std::memory_order_acquire);
45+
auto pushCursor = pushCursor_.load(std::memory_order_relaxed);
4646
auto popCursor = popCursor_.load(std::memory_order_relaxed);
4747

4848
assert(popCursor <= pushCursor);

bench.cpp

+101
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
#include "Fifo4.hpp"
2+
#include "Fifo4a.hpp"
3+
#include "Fifo5.hpp"
4+
#include "rigtorp.hpp"
5+
6+
#include <benchmark/benchmark.h>
7+
8+
#include <iostream>
9+
#include <thread>
10+
11+
12+
static void pinThread(int cpu) {
13+
if (cpu < 0) {
14+
return;
15+
}
16+
::cpu_set_t cpuset;
17+
CPU_ZERO(&cpuset);
18+
CPU_SET(cpu, &cpuset);
19+
if (::pthread_setaffinity_np(pthread_self(), sizeof(cpu_set_t), &cpuset) == -1) {
20+
std::perror("pthread_setaffinity_rp");
21+
std::exit(EXIT_FAILURE);
22+
}
23+
}
24+
25+
constexpr auto cpu1 = 1;
26+
constexpr auto cpu2 = 2;
27+
28+
template<typename T>
29+
struct isRigtorp : std::false_type {};
30+
31+
template<typename ValueT>
32+
struct isRigtorp<rigtorp::SPSCQueue<ValueT>> : std::true_type {};
33+
34+
35+
template<template<typename> class FifoT>
36+
void BM_Fifo(benchmark::State& state) {
37+
using fifo_type = FifoT<std::int_fast64_t>;
38+
using value_type = typename fifo_type::value_type;
39+
40+
constexpr auto fifoSize = 131072;
41+
fifo_type fifo(fifoSize);
42+
43+
auto t = std::jthread([&] {
44+
pinThread(cpu1);
45+
for (auto i = value_type{};; ++i) {
46+
value_type val;
47+
if constexpr(isRigtorp<fifo_type>::value) {
48+
while (!fifo.front());
49+
benchmark::DoNotOptimize(val = *fifo.front());
50+
fifo.pop();
51+
} else {
52+
while (not fifo.pop(val)) {
53+
;
54+
}
55+
benchmark::DoNotOptimize(val);
56+
}
57+
if (val == -1) {
58+
break;
59+
}
60+
61+
if (val != i) {
62+
throw std::runtime_error("invalid value");
63+
}
64+
}
65+
});
66+
67+
auto value = value_type{};
68+
pinThread(cpu2);
69+
for (auto _ : state) {
70+
if constexpr(isRigtorp<fifo_type>::value) {
71+
while (not fifo.try_push(value)) {
72+
;
73+
}
74+
} else {
75+
while (not fifo.push(value)) {
76+
;
77+
}
78+
}
79+
++value;
80+
81+
while (not fifo.empty()) {
82+
;
83+
}
84+
}
85+
state.counters["ops/sec"] = benchmark::Counter(double(value), benchmark::Counter::kIsRate);
86+
state.PauseTiming();
87+
if constexpr(isRigtorp<fifo_type>::value) {
88+
while(not fifo.try_push(-1)) {}
89+
} else {
90+
fifo.push(-1);
91+
}
92+
}
93+
94+
95+
BENCHMARK_TEMPLATE(BM_Fifo, Fifo4);
96+
BENCHMARK_TEMPLATE(BM_Fifo, Fifo4a);
97+
BENCHMARK_TEMPLATE(BM_Fifo, Fifo5);
98+
BENCHMARK_TEMPLATE(BM_Fifo, rigtorp::SPSCQueue);
99+
100+
BENCHMARK_MAIN();
101+

bench.hpp

+17-11
Original file line numberDiff line numberDiff line change
@@ -30,12 +30,11 @@ template<typename T>
3030
struct isRigtorp : std::false_type {};
3131

3232
template<typename T>
33-
void bench(char const* name, int cpu1, int cpu2) {
33+
auto bench(char const* name, long iters, int cpu1, int cpu2) {
34+
using namespace std::chrono_literals;
3435
using value_type = typename T::value_type;
3536

3637
constexpr auto fifoSize = 131072;
37-
constexpr auto iters = 200'000'000l;
38-
// constexpr auto iters = 100'000'000l;
3938

4039
T q(fifoSize);
4140
auto t = std::jthread([&] {
@@ -77,21 +76,28 @@ void bench(char const* name, int cpu1, int cpu2) {
7776
;
7877
}
7978
auto stop = std::chrono::steady_clock::now();
80-
auto delta = std::chrono::duration_cast<std::chrono::nanoseconds>(stop - start);
81-
std::cout << std::setw(7) << std::left << name << ": "
82-
<< std::setw(10) << std::right << iters * 1'000'000'000 / delta.count()
83-
<< " ops/s\n";
79+
auto delta = stop - start;
80+
return (iters * 1s)/delta;
8481
}
8582

8683
template<template<typename> class FifoT>
8784
void bench(char const* name, int argc, char* argv[]) {
88-
int cpu1 = -1;
89-
int cpu2 = -1;
85+
int cpu1 = 1;
86+
int cpu2 = 2;
9087
if (argc == 3) {
9188
cpu1 = std::atoi(argv[1]);
9289
cpu2 = std::atoi(argv[2]);
9390
}
94-
// using value_type = std::array<long, 25>;
91+
92+
constexpr auto iters = 400'000'000l;
93+
// constexpr auto iters = 100'000'000l;
94+
9595
using value_type = std::int64_t;
96-
bench<FifoT<value_type>>(name, cpu1, cpu2);
96+
97+
// warmup
98+
bench<FifoT<value_type>>(name, 1'000'000, cpu1, cpu2);
99+
100+
auto opsPerSec = bench<FifoT<value_type>>(name, iters, cpu1, cpu2);
101+
std::cout << std::setw(7) << std::left << name << ": "
102+
<< std::setw(10) << std::right << opsPerSec << " ops/s\n";
97103
}

bench_all.cpp

+50
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
#include "Fifo3.hpp"
2+
#include "Fifo4.hpp"
3+
#include "Fifo4a.hpp"
4+
#include "Fifo5.hpp"
5+
#include "rigtorp.hpp"
6+
#include <boost/lockfree/spsc_queue.hpp> // boost 1.74.0
7+
8+
#include "bench.hpp"
9+
10+
#include <iostream>
11+
12+
13+
template<typename ValueT>
14+
struct isRigtorp<rigtorp::SPSCQueue<ValueT>> : std::true_type {};
15+
16+
17+
// Configuring fixed size to match Fifo5's fixed size
18+
template<typename T>
19+
using boost_spsc_queue = boost::lockfree::spsc_queue<T, boost::lockfree::fixed_sized<true>>;
20+
21+
22+
template<typename ValueT>
23+
void once(long iters, int cpu1, int cpu2) {
24+
std::cout <<
25+
bench<Fifo3<ValueT>>("Fifo3", iters, cpu1, cpu2) << "," <<
26+
bench<Fifo4<ValueT>>("Fifo4", iters, cpu1, cpu2) << "," <<
27+
bench<Fifo4a<ValueT>>("Fifo4a", iters, cpu1, cpu2) << "," <<
28+
bench<Fifo5<ValueT>>("Fifo5", iters, cpu1, cpu2) << "," <<
29+
bench<rigtorp::SPSCQueue<ValueT>>("rigtorp", iters, cpu1, cpu2) << "," <<
30+
bench<boost_spsc_queue<ValueT>>("boost::spsc_queue fixed", iters, cpu1, cpu2) <<
31+
"\n";
32+
}
33+
34+
int main(int argc, char* argv[]) {
35+
constexpr auto cpu1 = 1;
36+
constexpr auto cpu2 = 2;
37+
constexpr auto iters = 400'000'000l;
38+
39+
auto reps = 10;
40+
if (argc == 2) {
41+
reps = std::atoi(argv[1]);
42+
}
43+
44+
using value_type = std::int64_t;
45+
46+
std::cout << "Fifo3,Fifo4,Fifo4a,Fifo5,rigtorp,boost_spsc_queue\n";
47+
for (auto rep = 0; rep < reps; ++rep) {
48+
once<value_type>(iters, cpu1, cpu2);
49+
}
50+
}

0 commit comments

Comments
 (0)