1 #ifndef TELAMON_SRC_TELAMON_VERSIONING_HH_
2 #define TELAMON_SRC_TELAMON_VERSIONING_HH_
15 constexpr
static inline int THRESHOLD = 2;
16 constexpr
static inline int FAST_PATH_RETRY_THRESHOLD = 3;
19 auto detect () ->
bool {
20 return (++m_counter > ContentionFailureCounter::THRESHOLD);
22 [[nodiscard]]
auto get ()
const noexcept ->
int {
return m_counter; }
40 template<
typename Cas>
42 { cas_.has_modified_bit() } -> std::same_as<bool>;
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>>;
52 namespace versioning {
58 namespace telamon_private {
61 template<
typename ValType>
66 : value{std::move(t_value)},
73 template<
typename ValType,
typename Meta=
void>
79 meta{std::forward<Meta>(t_meta)} {}
86 template<
typename ValType>
98 template<
typename ValType,
typename Meta=
void>
102 template<
typename ...Args>
106 [[maybe_unused]]
explicit VersionedAtomic (ValType value, Meta meta = {})
110 : m_ptr{rhs.m_ptr.load()} {}
114 [[maybe_unused]]
auto load () const noexcept ->
Referenced<ValType, Meta> * {
return m_ptr.load(); }
117 [[maybe_unused]]
auto store (ValType new_value, std::optional<Meta> new_meta = {}) noexcept {
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),
127 m_ptr.store(new_ptr);
133 template<
typename Fun>
135 auto loaded = m_ptr.load();
136 return fun(loaded->value, loaded->version, loaded->meta);
139 [[nodiscard]]
auto version () const noexcept ->
VersionNum {
return m_ptr.load()->version; }
149 std::optional<versioning::VersionNum> expected_version_opt,
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);
161 if (expected_version_opt && expected_version_opt.value() != actual_version) {
162 if (failures.detect()) {
return std::nullopt; }
163 return std::make_optional(
false);
166 if (actual == desired && actual_meta == desired_meta) {
167 return std::make_optional(
true);
173 auto cas_result = std::make_optional(m_ptr.compare_exchange_strong(ptr, new_ref));
174 if (!cas_result && failures.detect()) {
return std::nullopt; }
175 if (cas_result && cas_result.value() ==
true) { m_modified_bit.store(
true); }
179 template<
typename ...Args>
180 [[maybe_unused]]
auto compare_exchange_strong (Args &&... args) ->
bool {
182 auto res = compare_exchange_weak(std::forward<Args>(args)...);
183 if (res == std::nullopt)
continue;
188 [[nodiscard]]
auto has_modified_bit () const noexcept ->
bool {
return m_modified_bit.load(); }
190 void clear_modified_bit () noexcept {
191 auto expected =
false;
192 auto _ = m_modified_bit.compare_exchange_strong(expected,
true);
196 std::atomic<Referenced<ValType, Meta> *> m_ptr{};
197 std::atomic<bool> m_modified_bit{
false};
201 template<
typename ValType>
210 [[maybe_unused]]
auto load () const noexcept ->
Referenced<ValType> * {
return m_ptr.load(); }
213 [[maybe_unused]]
auto store (ValType new_value) noexcept {
215 auto actual = ptr->value;
216 auto actual_version = ptr->version;
217 if (actual == new_value) {
return; }
219 m_ptr.store(new_ptr);
225 template<
typename Fun>
227 auto loaded = m_ptr.load();
228 return fun(loaded->value, loaded->version);
238 [[maybe_unused]]
auto compare_exchange_weak (
const ValType &expected, std::optional<versioning::VersionNum> expected_version_opt,
241 auto actual = ptr->value;
242 auto actual_version = ptr->version;
243 if (expected != actual) {
244 return std::make_optional(
false);
247 if (expected_version_opt && expected_version_opt.value() != actual_version) {
248 if (failures.detect()) {
return std::nullopt; }
249 return std::make_optional(
false);
252 if (actual == desired) {
253 return std::make_optional(
true);
259 auto cas_result = std::make_optional(m_ptr.compare_exchange_strong(ptr, new_ptr));
260 if (!cas_result && failures.detect()) {
return std::nullopt; }
261 if (cas_result) { m_modified_bit.store(
true); }
265 template<
typename ...Args>
266 [[maybe_unused]]
auto compare_exchange_strong (Args &&... args) ->
bool {
269 if (res == std::nullopt)
continue;
274 [[nodiscard]]
auto has_modified_bit () const noexcept ->
bool {
return m_modified_bit.load(); }
276 void clear_modified_bit () noexcept {
277 auto expected =
false;
278 auto _ = m_modified_bit.compare_exchange_strong(expected,
true);
282 std::atomic<Referenced<ValType> *> m_ptr{};
283 std::atomic<bool> m_modified_bit{
false};
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