4 #ifndef _UTIL_SLIDING_COUNTER_H 5 #define _UTIL_SLIDING_COUNTER_H 10 #include "base/atomic_wrapper.h" 11 #include "base/integral_types.h" 12 #include "base/logging.h" 18 static void SetCurrentTime_Test(uint32 time);
23 static uint32 CurrentTime();
25 mutable base::atomic_wrapper<uint32> last_ts_;
32 mutable base::atomic_wrapper<T> count_[NUM];
37 int32 MoveTsIfNeeded()
const;
40 static constexpr
unsigned SIZE = NUM;
41 static constexpr
unsigned SPAN = PRECISION*NUM;
44 static_assert(NUM > 1,
"Invalid window size");
48 void Inc() { IncBy(1); }
50 T IncBy(int32 delta) {
51 int32 bin = MoveTsIfNeeded();
52 T tmp = count_[bin].fetch_add(delta, std::memory_order_acq_rel);
59 T DecIfNotLess(int32 delta) {
60 int32 bin = MoveTsIfNeeded();
63 val = count_[bin].load(std::memory_order_acquire);
67 }
while(!count_[bin].compare_exchange_weak(val, val - delta, std::memory_order_acq_rel));
73 T SumLast(
unsigned offset,
unsigned count =
unsigned(-1))
const;
78 for (
unsigned i = 0; i < NUM; ++i)
79 sum += count_[i].load(std::memory_order_acquire);
84 for (
unsigned i = 0; i < NUM; ++i)
85 count_[i].store(0, std::memory_order_release);
88 uint32 last_ts()
const {
return last_ts_; }
89 static unsigned span() {
return SPAN; }
90 static unsigned bin_span() {
return PRECISION; }
101 static constexpr
unsigned kNum = 10;
102 static constexpr
unsigned kPrecision = 1;
108 void Reset() { window_.Reset(); }
123 template<
typename T,
unsigned NUM,
unsigned PRECISION>
125 uint32 current_time = CurrentTime() / PRECISION;
126 uint32 last_ts = last_ts_.load(std::memory_order_acquire);
127 if (last_ts >= current_time) {
130 return last_ts % NUM;
132 if (last_ts + NUM <= current_time) {
134 for (uint32 i = 0; i < NUM; ++i) {
135 count_[i].store(0, std::memory_order_release);
139 for (uint32 i = last_ts + 1; i <= current_time; ++i) {
140 count_[i % NUM].store(0, std::memory_order_release);
143 if (last_ts_.compare_exchange_strong(last_ts, current_time, std::memory_order_acq_rel)) {
144 return current_time % NUM;
146 return last_ts % NUM;
149 template<
typename T,
unsigned NUM,
unsigned PRECISION>
150 T SlidingSecondCounterT<T, NUM, PRECISION>::SumLast(
unsigned offset,
unsigned count)
const {
151 if (count > NUM - offset) {
152 count = NUM - offset;
155 int32 start = MoveTsIfNeeded() - offset - count + 1;
156 if (start < 0) start += NUM;
157 for (
unsigned i = 0; i < count; ++i) {
158 sum += count_[ (start + i) % NUM ].load(std::memory_order_acquire);
165 #endif // _UTIL_SLIDING_COUNTER_H