diff --git a/feature.h b/feature.h index 8997691..f865594 100644 --- a/feature.h +++ b/feature.h @@ -272,47 +272,6 @@ class HashedRingBuffer { size_t hash_; // XOR of all elements in buffer_. }; -// A simple fixed-size byte array. -// Each element is an 8-bit counter that can be incremented concurrently. -// The counters are allowed to overflow (i.e. are not saturating). -// Thread-compatible. -// The main use case is to increment an execution counter of a given PC. -template -class CounterArray { - public: - // Constructs an empty counter array. - CounterArray() = default; - - // Clears all counters. - void Clear() { memset(data_, 0, sizeof(data_)); } - - // Increments the counter that corresponds to idx. - // Idx is taken modulo kSize. - void Increment(size_t idx) { - // An atomic increment is quite expensive, even if relaxed. - // We do a non-atomic increment instead, with the full understanding - // that if the increment of the same `idx` happens concurrently the result - // will be unreliable. This is a trade-off between correctness and speed. - // This behavior is similar to that of Clang Coverage and inline counters: - // https://clang.llvm.org/docs/SourceBasedCodeCoverage.html - // https://clang.llvm.org/docs/SanitizerCoverage.html#inline-8bit-counters - // There is also a risk of contention if the same hot code is executed - // concurrently. Both atomic and non-atomic increment will be bad. - uint8_t *ptr = &data_[idx % kSize]; - uint8_t value{}; - __atomic_load(ptr, &value, __ATOMIC_RELAXED); - ++value; - __atomic_store(ptr, &value, __ATOMIC_RELAXED); - } - - // Accessors. - const uint8_t *data() const { return &data_[0]; } - size_t size() const { return kSize; } - - private: - uint8_t data_[kSize] = {}; -}; - // A simple fixed-capacity array with push_back. // Thread-compatible. template