Skip to content

Commit 5ea0aa5

Browse files
Charlie FraschCharlie Frasch
authored andcommitted
WIP
1 parent 8aec3f8 commit 5ea0aa5

File tree

11 files changed

+212
-207
lines changed

11 files changed

+212
-207
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
build

CMakeLists.txt

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -60,11 +60,19 @@ target_compile_options(fifo4.tsan PRIVATE -fsanitize=thread)
6060
target_link_libraries(fifo4.tsan PRIVATE pthread tsan)
6161

6262

63+
# add_executable(fifo7 fifo7.cpp)
64+
# target_link_libraries(fifo7 pthread)
65+
#
66+
# add_executable(fifo7.tsan fifo7.cpp)
67+
# target_compile_options(fifo7.tsan PRIVATE -fsanitize=thread)
68+
# target_link_libraries(fifo7.tsan PRIVATE pthread tsan)
69+
70+
6371
include(GoogleTest)
6472
enable_testing()
6573

66-
add_executable(tests sanitizers.cpp Fifo1_ut.cpp)
67-
target_compile_options(tests PRIVATE -fsanitize=undefined -fsanitize=address)
68-
target_link_libraries(tests PRIVATE asan ubsan gtest gtest_main)
69-
target_link_options(tests PRIVATE -fsanitize=undefined -fsanitize=address)
70-
gtest_add_tests(TARGET tests)
74+
add_executable(unitTests sanitizers.cpp unitTests.cpp)
75+
target_compile_options(unitTests PRIVATE -fsanitize=undefined -fsanitize=address)
76+
target_link_libraries(unitTests PRIVATE asan ubsan gtest gtest_main)
77+
target_link_options(unitTests PRIVATE -fsanitize=undefined -fsanitize=address)
78+
gtest_add_tests(TARGET unitTests)

Fifo1.hpp

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,15 @@ class Fifo1
1313

1414
explicit Fifo1(std::size_t size)
1515
: size_{size}
16-
, ring_{
17-
static_cast<ValueType*>(std::aligned_alloc(alignof(T), size * sizeof(T))),
18-
&std::free}
16+
, ring_{static_cast<ValueType*>(std::aligned_alloc(alignof(T), size * sizeof(T))), &std::free}
1917
{}
2018

19+
~Fifo1() {
20+
while(not empty()) {
21+
ring_[popCursor_ % size_].~T();
22+
++popCursor_;
23+
}
24+
}
2125

2226
std::size_t size() const { return size_; }
2327
bool empty() const { return popCursor_ == pushCursor_; }
@@ -29,7 +33,6 @@ class Fifo1
2933
}
3034
new (&ring_[pushCursor_ % size_]) T(value);
3135
++pushCursor_;
32-
3336
return true;
3437
}
3538

@@ -42,7 +45,6 @@ class Fifo1
4245
value = ring_[popCursor_ % size_];
4346
ring_[popCursor_ % size_].~T();
4447
++popCursor_;
45-
4648
return true;
4749
}
4850

@@ -52,6 +54,6 @@ class Fifo1
5254
using RingType = std::unique_ptr<ValueType[], decltype(&std::free)>;
5355
RingType ring_;
5456

55-
std::size_t pushCursor_{};
56-
std::size_t popCursor_{};
57+
std::size_t pushCursor_;
58+
std::size_t popCursor_;
5759
};

Fifo1_ut.cpp

Lines changed: 0 additions & 93 deletions
This file was deleted.

Fifo2.hpp

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,10 @@ class Fifo2
1414

1515
explicit Fifo2(std::size_t size)
1616
: size_{size}
17-
, ring_{
18-
static_cast<ValueType*>(std::aligned_alloc(alignof(T), size * sizeof(T))),
17+
, ring_{static_cast<ValueType*>(std::aligned_alloc(alignof(T), size * sizeof(T))),
1918
&std::free}
2019
{}
2120

22-
2321
std::size_t size() const { return size_; }
2422
bool empty() const { return popCursor_ == pushCursor_; }
2523
bool full() const { return (pushCursor_ - popCursor_) == size_; }
@@ -30,7 +28,6 @@ class Fifo2
3028
}
3129
new (&ring_[pushCursor_ % size_]) T(value);
3230
++pushCursor_;
33-
3431
return true;
3532
}
3633

@@ -43,7 +40,6 @@ class Fifo2
4340
value = ring_[popCursor_ % size_];
4441
ring_[popCursor_ % size_].~T();
4542
++popCursor_;
46-
4743
return true;
4844
}
4945

@@ -54,8 +50,8 @@ class Fifo2
5450
RingType ring_;
5551

5652
/// Loaded and stored by the push thread; loaded by the pop thread
57-
std::atomic<std::size_t> pushCursor_{};
53+
std::atomic<std::size_t> pushCursor_;
5854

5955
/// Loaded and stored by the pop thread; loaded by the push thread
60-
std::atomic<std::size_t> popCursor_{};
56+
std::atomic<std::size_t> popCursor_;
6157
};

Fifo3.hpp

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,10 @@ class Fifo3
1515

1616
explicit Fifo3(std::size_t size)
1717
: size_{size}
18-
, ring_{
19-
static_cast<ValueType*>(std::aligned_alloc(alignof(T), size * sizeof(T))),
18+
, ring_{static_cast<ValueType*>(std::aligned_alloc(alignof(T), size * sizeof(T))),
2019
&std::free}
2120
{}
2221

23-
2422
std::size_t size() const { return size_; }
2523
bool empty() const { return popCursor_ == pushCursor_; }
2624
bool full() const { return (pushCursor_ - popCursor_) == size_; }
@@ -68,8 +66,8 @@ class Fifo3
6866
static constexpr auto hardware_destructive_interference_size = std::size_t{128};
6967

7068
/// Loaded and stored by the push thread; loaded by the pop thread
71-
alignas(hardware_destructive_interference_size) std::atomic<std::size_t> pushCursor_{};
69+
alignas(hardware_destructive_interference_size) std::atomic<std::size_t> pushCursor_;
7270

7371
/// Loaded and stored by the pop thread; loaded by the push thread
74-
alignas(hardware_destructive_interference_size) std::atomic<std::size_t> popCursor_{};
72+
alignas(hardware_destructive_interference_size) std::atomic<std::size_t> popCursor_;
7573
};

Fifo4.hpp

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
#include <new>
77

88

9-
/// Threadsafe, efficient circular FIFO
9+
/// Threadsafe, efficient circular FIFO with cached cursors
1010
template<typename T>
1111
class Fifo4
1212
{
@@ -15,12 +15,10 @@ class Fifo4
1515

1616
explicit Fifo4(std::size_t size)
1717
: size_{size}
18-
, ring_{
19-
static_cast<ValueType*>(std::aligned_alloc(alignof(T), size * sizeof(T))),
18+
, ring_{static_cast<ValueType*>(std::aligned_alloc(alignof(T), size * sizeof(T))),
2019
&std::free}
2120
{}
2221

23-
2422
std::size_t size() const { return size_; }
2523
bool empty() const { return popCursor_ == pushCursor_; }
2624
bool full() const { return (pushCursor_ - popCursor_) == size_; }
@@ -74,7 +72,6 @@ class Fifo4
7472
static constexpr auto hardware_destructive_interference_size = std::size_t{128};
7573

7674
/// Loaded and stored by the push thread; loaded by the pop thread
77-
// TODO fix initialization on the others
7875
alignas(hardware_destructive_interference_size) std::atomic<std::size_t> pushCursor_;
7976

8077
/// Exclusive to the pop thread

Fifo7.hpp

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
#pragma once
2+
3+
#include <cstdlib>
4+
#include <functional>
5+
#include <memory>
6+
7+
8+
/// adds allocator
9+
// TODO make same as others esp thread safety
10+
template<typename T, typename Allocator = std::allocator<T>>
11+
class Fifo7 : private Allocator
12+
{
13+
public:
14+
using ValueType = T;
15+
using allocator_traits = std::allocator_traits<Allocator>;
16+
17+
using RingType = std::unique_ptr<ValueType[], std::function<void(ValueType*)>>;
18+
19+
explicit Fifo7(std::size_t size, const Allocator& alloc = Allocator())
20+
: Allocator(alloc)
21+
, size_{size}
22+
, ring_{
23+
allocator_traits::allocate(*this, size_),
24+
[this](ValueType* ring) {
25+
allocator_traits::deallocate(*this, ring, size_);
26+
}}
27+
{}
28+
29+
~Fifo7() {
30+
while(not empty()) {
31+
ring_[popCursor_ % size_].~T();
32+
++popCursor_;
33+
}
34+
}
35+
36+
std::size_t size() const { return size_; }
37+
bool empty() const { return popCursor_ == pushCursor_; }
38+
bool full() const { return (pushCursor_ - popCursor_) == size_; }
39+
40+
bool push(T const& value) {
41+
if (full()) {
42+
return false;
43+
}
44+
new (&ring_[pushCursor_ % size_]) T(value);
45+
++pushCursor_;
46+
return true;
47+
}
48+
49+
/// Pop one object from the fifo.
50+
/// @return `true` if the pop operation is successful; `false` if fifo was empty.
51+
bool pop(T& value) {
52+
if (empty()) {
53+
return false;
54+
}
55+
value = ring_[popCursor_ % size_];
56+
ring_[popCursor_ % size_].~T();
57+
++popCursor_;
58+
return true;
59+
}
60+
61+
private:
62+
std::size_t size_;
63+
RingType ring_;
64+
std::size_t pushCursor_;
65+
std::size_t popCursor_;
66+
};

bench.hpp

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
#include <cstdint>
66
#include <cstdio>
77
#include <cstdlib>
8+
#include <iomanip>
89
#include <iostream>
910
#include <stdexcept>
1011
#include <thread>
@@ -42,7 +43,7 @@ void bench(char const* name, int cpu1, int cpu2) {
4243
;
4344
}
4445
if (val[0] != i) {
45-
throw std::runtime_error("foo");
46+
throw std::runtime_error("invalid value");
4647
}
4748
}
4849
});
@@ -59,8 +60,9 @@ void bench(char const* name, int cpu1, int cpu2) {
5960
}
6061
auto stop = std::chrono::steady_clock::now();
6162
t.join();
62-
std::cout << name << ": " << iters * 1'000'000'000 /
63-
std::chrono::duration_cast<std::chrono::nanoseconds>(stop - start).count()
63+
auto delta = std::chrono::duration_cast<std::chrono::nanoseconds>(stop - start);
64+
std::cout << name << ": "
65+
<< std::setw(8) << std::right << iters * 1'000'000'000 / delta.count()
6466
<< " ops/s\n";
6567
}
6668

0 commit comments

Comments
 (0)