Telamon
Versioning.hh
Go to the documentation of this file.
1 #ifndef TELAMON_SRC_TELAMON_VERSIONING_HH_
2 #define TELAMON_SRC_TELAMON_VERSIONING_HH_
3 
8 
9 namespace telamon_simulator {
10 
14  public:
15  constexpr static inline int THRESHOLD = 2;
16  constexpr static inline int FAST_PATH_RETRY_THRESHOLD = 3;
17 
18  public:
19  auto detect () -> bool {
20  return (++m_counter > ContentionFailureCounter::THRESHOLD);
21  }
22  [[nodiscard]] auto get () const noexcept -> int { return m_counter; }
23 
24  private:
25  int m_counter{0};
26 };
27 
29 enum class CasStatus : char {
30  Pending,
31  Success,
32  Failure
33 };
34 
40 template<typename Cas>
41 concept CasWithVersioning = requires (Cas cas_, CasStatus status, ContentionFailureCounter &failures, CasStatus expected, CasStatus desired){
42  { cas_.has_modified_bit() } -> std::same_as<bool>;
43  { cas_.clear_bit() };
44  { cas_.state() } -> std::same_as<CasStatus>;
45  { cas_.set_state(status) };
46  { cas_.swap_state(expected, desired) } -> std::same_as<bool>;
47  { cas_.execute(failures) } -> std::same_as<nonstd::expected<bool, std::monostate>>;
48 };
49 
50 
52 namespace versioning {
53 
55 using VersionNum = uint_least64_t;
56 
58 namespace telamon_private {
59 
61 template<typename ValType>
63  ValType value;
64  VersionNum version{0};
65  explicit ReferencedBase (ValType &&t_value, VersionNum t_version = 0, bool mod = false)
66  : value{std::move(t_value)},
67  version{t_version} {}
68 };
69 }
70 
73 template<typename ValType, typename Meta=void>
75  Meta meta;
76 
77  explicit Referenced (ValType t_value, Meta t_meta, VersionNum t_version = 0)
78  : telamon_private::ReferencedBase<ValType>(std::move(t_value), t_version),
79  meta{std::forward<Meta>(t_meta)} {}
80 
81  Referenced (const Referenced &rhs)
82  : meta{rhs.meta}, telamon_private::ReferencedBase<ValType>{rhs.value, rhs.version} {}
83 };
84 
86 template<typename ValType>
87 struct Referenced<ValType, void> : telamon_private::ReferencedBase<ValType> {
88  explicit Referenced (ValType t_value, VersionNum t_version = 0)
89  : telamon_private::ReferencedBase<ValType>(std::move(t_value), t_version) {}
90 
91  Referenced (const Referenced &rhs)
92  : telamon_private::ReferencedBase<ValType>{rhs.value, rhs.version} {}
93 };
94 
98 template<typename ValType, typename Meta=void>
99 class [[maybe_unused]] VersionedAtomic {
100  public:
101 
102  template<typename ...Args>
103  explicit VersionedAtomic (Meta meta, Args &&... args)
104  : m_ptr{std::atomic(new Referenced<ValType, Meta>{ValType{std::forward<Args>(args)...}, std::move(meta)})} {}
105 
106  [[maybe_unused]] explicit VersionedAtomic (ValType value, Meta meta = {})
107  : m_ptr{std::atomic(new Referenced<ValType, Meta>{std::move(value), std::move(meta)})} {}
108 
109  VersionedAtomic (const VersionedAtomic &rhs)
110  : m_ptr{rhs.m_ptr.load()} {}
111 
112  public:
114  [[maybe_unused]] auto load () const noexcept -> Referenced<ValType, Meta> * { return m_ptr.load(); }
115 
117  [[maybe_unused]] auto store (ValType new_value, std::optional<Meta> new_meta = {}) noexcept {
118  auto ptr = load();
119  auto actual = ptr->value;
120  auto actual_version = ptr->version;
121  if (actual == new_value) { return; }
122  auto new_ptr = new Referenced<ValType, Meta>{
123  std::move(new_value),
124  (new_meta.has_value() ? new_meta.value() : ptr->meta),
125  actual_version + 1
126  };
127  m_ptr.store(new_ptr);
128  }
129 
133  template<typename Fun/*, typename Ret*/>
134  [[maybe_unused]] auto transform (Fun fun) const {
135  auto loaded = m_ptr.load();
136  return fun(loaded->value, loaded->version, loaded->meta);
137  }
138 
139  [[nodiscard]] auto version () const noexcept -> VersionNum { return m_ptr.load()->version; }
140 
148  [[maybe_unused]] auto compare_exchange_weak (const ValType &expected,
149  std::optional<versioning::VersionNum> expected_version_opt,
150  ValType desired,
151  Meta desired_meta,
152  ContentionFailureCounter &failures) -> std::optional<bool> {
153  auto ptr = load();
154  auto actual = ptr->value;
155  auto actual_version = ptr->version;
156  auto actual_meta = ptr->meta;
157  if (expected != actual) {
158  return std::make_optional(false);
159  }
160 
161  if (expected_version_opt && expected_version_opt.value() != actual_version) {
162  if (failures.detect()) { return std::nullopt; } //< Contention
163  return std::make_optional(false);
164  }
165 
166  if (actual == desired && actual_meta == desired_meta) {
167  return std::make_optional(true);
168  }
169 
170  // TODO: Hazptr
171  auto new_ref = new Referenced<ValType, Meta>{std::move(desired), std::move(desired_meta), actual_version + 1};
172 
173  auto cas_result = std::make_optional(m_ptr.compare_exchange_strong(ptr, new_ref));
174  if (!cas_result && failures.detect()) { return std::nullopt; } //< Contention
175  if (cas_result && cas_result.value() == true) { m_modified_bit.store(true); }
176  return cas_result;
177  }
178 
179  template<typename ...Args>
180  [[maybe_unused]] auto compare_exchange_strong (Args &&... args) -> bool {
181  while (true) {
182  auto res = compare_exchange_weak(std::forward<Args>(args)...);
183  if (res == std::nullopt) continue;
184  return res.value();
185  }
186  }
187 
188  [[nodiscard]] auto has_modified_bit () const noexcept -> bool { return m_modified_bit.load(); }
189 
190  void clear_modified_bit () noexcept {
191  auto expected = false;
192  auto _ = m_modified_bit.compare_exchange_strong(expected, true);
193  }
194 
195  private:
196  std::atomic<Referenced<ValType, Meta> *> m_ptr{};
197  std::atomic<bool> m_modified_bit{false};
198 };
199 
201 template<typename ValType>
202 class VersionedAtomic<ValType, void> {
203  public:
204  explicit VersionedAtomic (ValType &&value) : m_ptr{std::atomic(new Referenced<ValType>{std::forward<ValType>(value)})} {}
205  VersionedAtomic (const VersionedAtomic &) = delete;
206  VersionedAtomic (VersionedAtomic &&) noexcept = default;
207 
208  public:
210  [[maybe_unused]] auto load () const noexcept -> Referenced<ValType> * { return m_ptr.load(); }
211 
213  [[maybe_unused]] auto store (ValType new_value) noexcept {
214  auto ptr = load();
215  auto actual = ptr->value;
216  auto actual_version = ptr->version;
217  if (actual == new_value) { return; }
218  auto new_ptr = new Referenced<ValType>{std::move(new_value), actual_version + 1};
219  m_ptr.store(new_ptr);
220  }
221 
225  template<typename Fun/*, typename Ret*/>
226  [[maybe_unused]] auto transform (Fun fun) /* -> Ret */ {
227  auto loaded = m_ptr.load();
228  return fun(loaded->value, loaded->version);
229  }
230 
238  [[maybe_unused]] auto compare_exchange_weak (const ValType &expected, std::optional<versioning::VersionNum> expected_version_opt,
239  ValType &&desired, ContentionFailureCounter &failures) -> std::optional<bool> {
240  auto ptr = load();
241  auto actual = ptr->value;
242  auto actual_version = ptr->version;
243  if (expected != actual) {
244  return std::make_optional(false);
245  }
246 
247  if (expected_version_opt && expected_version_opt.value() != actual_version) {
248  if (failures.detect()) { return std::nullopt; } //< Contention
249  return std::make_optional(false);
250  }
251 
252  if (actual == desired) {
253  return std::make_optional(true);
254  }
255 
256  // TODO: Hazptr
257  auto new_ptr = new Referenced<ValType>{std::move(desired), actual_version + 1};
258 
259  auto cas_result = std::make_optional(m_ptr.compare_exchange_strong(ptr, new_ptr));
260  if (!cas_result && failures.detect()) { return std::nullopt; } //< Contention
261  if (cas_result) { m_modified_bit.store(true); }
262  return cas_result;
263  }
264 
265  template<typename ...Args>
266  [[maybe_unused]] auto compare_exchange_strong (Args &&... args) -> bool {
267  while (true) {
268  auto res = compare_exchange_weak(std::forward<Args>(args)...);
269  if (res == std::nullopt) continue;
270  return res.value();
271  }
272  }
273 
274  [[nodiscard]] auto has_modified_bit () const noexcept -> bool { return m_modified_bit.load(); }
275 
276  void clear_modified_bit () noexcept {
277  auto expected = false;
278  auto _ = m_modified_bit.compare_exchange_strong(expected, true);
279  }
280 
281  private:
282  std::atomic<Referenced<ValType> *> m_ptr{};
283  std::atomic<bool> m_modified_bit{false};
284 };
285 
286 }
287 }
288 
289 #endif //TELAMON_SRC_TELAMON_VERSIONING_HH_
Measures the contention which was encountered during simulation.
Definition: Versioning.hh:13
auto compare_exchange_weak(const ValType &expected, std::optional< versioning::VersionNum > expected_version_opt, ValType &&desired, ContentionFailureCounter &failures) -> std::optional< bool >
Performs a CAS on the value stored inside.
Definition: Versioning.hh:238
auto load() const noexcept -> Referenced< ValType > *
Load the value stored inside.
Definition: Versioning.hh:210
auto transform(Fun fun)
Apply a function to the value inside.
Definition: Versioning.hh:226
auto store(ValType new_value) noexcept
Store a value inside.
Definition: Versioning.hh:213
An atomic primitive which support versioning. The type which is wrapper has additional meta data.
Definition: Versioning.hh:99
auto compare_exchange_weak(const ValType &expected, std::optional< versioning::VersionNum > expected_version_opt, ValType desired, Meta desired_meta, ContentionFailureCounter &failures) -> std::optional< bool >
Performs a CAS on the value stored inside.
Definition: Versioning.hh:148
auto transform(Fun fun) const
Apply a function to the value inside.
Definition: Versioning.hh:134
auto store(ValType new_value, std::optional< Meta > new_meta={}) noexcept
Store a value inside.
Definition: Versioning.hh:117
auto load() const noexcept -> Referenced< ValType, Meta > *
Load the value stored inside.
Definition: Versioning.hh:114
uint_least64_t VersionNum
uint_least64_t is used to guarantee (minimize) the chance of the ABA problem occurring
Definition: Versioning.hh:55
This module encapsulates the implementation of the simulator.
Definition: NormalizedRepresentation.hh:25
CasStatus
Represents the status of a CAS primitive.
Definition: Versioning.hh:29
concept CasWithVersioning
Solves the ABA problem.
Definition: Versioning.hh:41
Used to represent a value which is referenced by a "node" from the structure but with additional meta...
Definition: Versioning.hh:74
Base class for the Referenced class which contains the common data between different template classes...
Definition: Versioning.hh:62