Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .clang-format
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,6 @@ SpacesInCStyleCastParentheses: false
SpacesInContainerLiterals: false
SpacesInParentheses: false
SpacesInSquareBrackets: false
Standard: c++11
Standard: c++20
TabWidth: 4
UseTab: Never
UseTab: Never
8 changes: 8 additions & 0 deletions .github/workflows/c-cpp.yml
Original file line number Diff line number Diff line change
Expand Up @@ -45,3 +45,11 @@ jobs:
cd builds/build_ubsan
chmod +x tests/tests
tests/tests
format:
runs-on: ubuntu-latest
steps:
- name: Install clang-format
run: sudo apt install -y clang-format
- uses: actions/checkout@v4
- name: Check clang-format
run: find ./ -iname '*.h' -o -iname '*.cpp' | xargs clang-format -n --Werror
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -31,4 +31,4 @@
*.out
*.app

build/
build/
4 changes: 2 additions & 2 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ option(ENABLE_UBSAN "Enable UndefinedBehaviorSanitizer" OFF)

message("ASAN: " ${ENABLE_ASAN})
message("MSAN: " ${ENABLE_MSAN})
message("TSAB: " ${ENABLE_TSAN})
message("TSAN: " ${ENABLE_TSAN})
message("UBSAN: " ${ENABLE_UBSAN})
if(ENABLE_ASAN)
message(STATUS "Enabling AddressSanitizer")
Expand Down Expand Up @@ -51,4 +51,4 @@ FetchContent_Declare(
FetchContent_MakeAvailable(googletest)

target_include_directories(ciri PUBLIC src)
add_subdirectory(tests)
add_subdirectory(tests)
6 changes: 3 additions & 3 deletions src/metrics/counter_basic.cpp
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
#include "metrics/counter_basic.h"

#include <atomic>
#include <mutex>

namespace ciri {
namespace metrics {
}
}
namespace metrics {}
} // namespace ciri
126 changes: 64 additions & 62 deletions src/metrics/counter_basic.h
Original file line number Diff line number Diff line change
@@ -1,82 +1,84 @@
#pragma once
#include <array>
#include <atomic>
#include <cassert>
#include <concepts>
#include <vector>
#include <array>
#include <cstdlib>
#include <thread>
#include <cassert>
#include <cstring>
#include <thread>
#include <vector>

namespace ciri {
namespace metrics {

template<std::default_initializable T>
template <std::default_initializable T>
class CounterBasic {
public:
static const size_t alignment = 64;
CounterBasic(size_t capacity) :
fast_module((capacity & (capacity - 1)) == 0)
, capacity_(capacity) {
assert(capacity_ > 0);
counters_ = static_cast<std::atomic<T>*>(std::aligned_alloc(alignment, capacity * sizeof(decltype(counters_[0]))));
assert(counters_ != nullptr);
for (size_t i = 0; i < capacity_; ++i) {
new (counters_ + i) std::atomic<T>();
}
for (size_t i = 0; i < capacity_; ++i) {
counters_[i].store(0);
}
public:
static const size_t alignment = 64;
CounterBasic(size_t capacity)
: fast_module((capacity & (capacity - 1)) == 0), capacity_(capacity) {
assert(capacity_ > 0);
counters_ = static_cast<std::atomic<T>*>(std::aligned_alloc(
alignment, capacity * sizeof(decltype(counters_[0]))));
assert(counters_ != nullptr);
for (size_t i = 0; i < capacity_; ++i) {
new (counters_ + i) std::atomic<T>();
}
void increase(T inc) {
size_t thread_hash = std::hash<std::thread::id>{}(std::this_thread::get_id());
counters_[get_index(thread_hash)].fetch_add(inc, std::memory_order_relaxed);
}
void decrease(T dec) {
size_t thread_hash = std::hash<std::thread::id>{}(std::this_thread::get_id());
counters_[get_index(thread_hash)].fetch_sub(dec, std::memory_order_relaxed);
}
void set(T value) {
size_t thread_hash = std::hash<std::thread::id>{}(std::this_thread::get_id());
counters_[get_index(thread_hash)].store(value, std::memory_order_relaxed);
for (size_t i = 0; i < capacity_; ++i) {
counters_[i].store(0);
}
}
void increase(T inc) {
size_t thread_hash =
std::hash<std::thread::id>{}(std::this_thread::get_id());
counters_[get_index(thread_hash)].fetch_add(inc, std::memory_order_relaxed);
}
void decrease(T dec) {
size_t thread_hash =
std::hash<std::thread::id>{}(std::this_thread::get_id());
counters_[get_index(thread_hash)].fetch_sub(dec, std::memory_order_relaxed);
}
void set(T value) {
size_t thread_hash =
std::hash<std::thread::id>{}(std::this_thread::get_id());
counters_[get_index(thread_hash)].store(value, std::memory_order_relaxed);
}

template<std::invocable<std::atomic<T>&> F>
void call(F&& callback) {
size_t thread_hash = std::hash<std::thread::id>{}(std::this_thread::get_id());
callback(counters_[get_index(thread_hash)]);
}
template <std::invocable<std::atomic<T>&> F>
void call(F&& callback) {
size_t thread_hash =
std::hash<std::thread::id>{}(std::this_thread::get_id());
callback(counters_[get_index(thread_hash)]);
}

inline void get_index() const {
size_t thread_hash = std::hash<std::thread::id>{}(std::this_thread::get_id());
return get_index(thread_hash);
}
inline void get_index() const {
size_t thread_hash =
std::hash<std::thread::id>{}(std::this_thread::get_id());
return get_index(thread_hash);
}


template<std::invocable<std::atomic<T>&> F>
void iterate(F&& func) {
for (size_t i = 0; i < capacity_; ++i) {
func(counters_[i]);
}
template <std::invocable<std::atomic<T>&> F>
void iterate(F&& func) {
for (size_t i = 0; i < capacity_; ++i) {
func(counters_[i]);
}
}

template<std::invocable<const std::atomic<T>&> F>
void iterate(F&& func) const {
for (size_t i = 0; i < capacity_; ++i) {
func(counters_[i]);
}
}

~CounterBasic() {
std::free(counters_);
template <std::invocable<const std::atomic<T>&> F>
void iterate(F&& func) const {
for (size_t i = 0; i < capacity_; ++i) {
func(counters_[i]);
}
}

inline size_t get_index(size_t i) const {
return fast_module ? (i & (capacity_ - 1)) : (i % capacity_);
}
const bool fast_module = false;
const size_t capacity_{0};
alignas(alignment) std::atomic<T>* counters_{nullptr};
~CounterBasic() { std::free(counters_); }

inline size_t get_index(size_t i) const {
return fast_module ? (i & (capacity_ - 1)) : (i % capacity_);
}
const bool fast_module = false;
const size_t capacity_{0};
alignas(alignment) std::atomic<T>* counters_{nullptr};
};
}
}
} // namespace metrics
} // namespace ciri
100 changes: 50 additions & 50 deletions src/metrics/counter_minmax.h
Original file line number Diff line number Diff line change
@@ -1,64 +1,64 @@
#pragma once
#include <concepts>
#include <type_traits>

#include "metrics/counter_basic.h"
namespace ciri {
namespace metrics {

template<std::totally_ordered T>
template <std::totally_ordered T>
class CounterMinMax {
public:
enum Mode {
Min,
Max
};
struct CompareCallback {
Mode mode;
T upd;
void operator()(std::atomic<T>& element) {
while (true) {
T value = element.load(std::memory_order_relaxed);
if ((value <= upd && mode == Mode::Min) || (value >= upd && mode == Mode::Max)) {
break;
}
if (element.compare_exchange_strong(value, upd, std::memory_order_relaxed)) {
break;
}
}
public:
enum Mode { Min, Max };
struct CompareCallback {
Mode mode;
T upd;
void operator()(std::atomic<T>& element) {
while (true) {
T value = element.load(std::memory_order_relaxed);
if ((value <= upd && mode == Mode::Min) ||
(value >= upd && mode == Mode::Max)) {
break;
}
};
CounterMinMax(Mode mode, size_t capacity = 1) : mode_(mode), counter_(capacity) {

if (element.compare_exchange_strong(value, upd,
std::memory_order_relaxed)) {
break;
}
}
}
};
CounterMinMax(Mode mode, size_t capacity = 1)
: mode_(mode), counter_(capacity) {}

void update(T upd) {
CompareCallback callback{.mode = mode_, .upd = std::move(upd)};
counter_.call(callback);
}
void update(T upd) {
CompareCallback callback{.mode = mode_, .upd = std::move(upd)};
counter_.call(callback);
}

T get() const {
T result = T{};
auto max_func = [&](const std::atomic<T>& element) {
T value = element.load(std::memory_order_relaxed);
result = result > value ? result : value;
};
auto min_func = [&](const std::atomic<T>& element) {
T value = element.load(std::memory_order_relaxed);
result = result < value ? result : value;
};
switch (mode_) {
case Mode::Max:
counter_.iterate(max_func);
return result;
case Mode::Min:
counter_.iterate(min_func);
return result;
}
assert(false);
T get() const {
T result = T{};
auto max_func = [&](const std::atomic<T>& element) {
T value = element.load(std::memory_order_relaxed);
result = result > value ? result : value;
};
auto min_func = [&](const std::atomic<T>& element) {
T value = element.load(std::memory_order_relaxed);
result = result < value ? result : value;
};
switch (mode_) {
case Mode::Max:
counter_.iterate(max_func);
return result;
case Mode::Min:
counter_.iterate(min_func);
return result;
}
private:
Mode mode_;
CounterBasic<T> counter_;
assert(false);
}

private:
Mode mode_;
CounterBasic<T> counter_;
};
}
}
} // namespace metrics
} // namespace ciri
55 changes: 26 additions & 29 deletions src/metrics/counter_sum.h
Original file line number Diff line number Diff line change
@@ -1,42 +1,39 @@
#pragma once
#include <array>
#include <atomic>
#include <cassert>
#include <concepts>
#include <vector>
#include <array>
#include <cstdlib>
#include <thread>
#include <cassert>
#include <cstring>
#include <thread>
#include <vector>

#include "metrics/counter_basic.h"

namespace ciri {
namespace metrics {
template<std::integral T = size_t>
template <std::integral T = size_t>
class CounterSum {
public:
static const size_t alignment = 64;
CounterSum(size_t capacity = 1) : counter_(capacity) {
}
void increase(T inc) {
counter_.increase(inc);
}
void decrease(T dec) {
counter_.decrease(dec);
}
T get() const {
T sum = T{};
auto f = [&](const std::atomic<T>& element) {
sum += element.load(std::memory_order_relaxed);
};
counter_.iterate(f);
return sum;
}
public:
static const size_t alignment = 64;
CounterSum(size_t capacity = 1) : counter_(capacity) {}
void increase(T inc) { counter_.increase(inc); }
void decrease(T dec) { counter_.decrease(dec); }
T get() const {
T sum = T{};
auto f = [&](const std::atomic<T>& element) {
sum += element.load(std::memory_order_relaxed);
};
counter_.iterate(f);
return sum;
}

~CounterSum() = default;

~CounterSum() = default;
private:
const bool fast_module = false;
ciri::metrics::CounterBasic<T> counter_;
private:
const bool fast_module = false;
ciri::metrics::CounterBasic<T> counter_;
};

}
}
} // namespace metrics
} // namespace ciri
2 changes: 1 addition & 1 deletion tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,4 @@ if(ENABLE_ASAN)
endif()

include(GoogleTest)
gtest_discover_tests(tests)
gtest_discover_tests(tests)
Loading