FARGOS/VISTA Object Management Environment Core  ..
FARGOS/VISTA Object Management Environment Core Table of Contents
rate_counter.hpp
Go to the documentation of this file.
1 #ifndef _RATE_COUNTER_HPP_
2 #define _RATE_COUNTER_HPP_ "$Id: rate_counter.hpp 454 2020-07-23 20:22:23Z geoff $"
4 // Copyright (C) 2008 - 2019 FARGOS Development, LLC
6 
7 /* O(1) rate counter
8  */
9 
10 #include <utils/time/tick_time.h>
12 #include <memory.h>
13 
39 template <typename EVENT_COUNT_TYPE=int32_t, uint64_t UNITS_PER_SECOND=1> class RateCounterForInterval {
40 private:
41  enum {
42  ONE_BILLION = 1000000000UL,
43  NS_PER_UNITS = ONE_BILLION / UNITS_PER_SECOND
44  };
45  EVENT_COUNT_TYPE *event_slots;
46  EVENT_COUNT_TYPE events_in_interval;
47  EVENT_COUNT_TYPE rate_threshold;
48  uint64_t interval_in_units;
51  struct timespec last_time_used;
52  uint32_t last_slot_used;
53  bool changed_slot;
54 
55 public:
64  void set_interval(uint64_t units) OME_ALWAYS_INLINE {
65  interval_in_units = units;
67  if (UNITS_PER_SECOND == 1) {
69  } else {
71  }
72  delete[] event_slots;
73  event_slots = new EVENT_COUNT_TYPE[interval_in_units];
74  for(uint_fast32_t i=0;i<interval_in_units;i+=1) {
76  }
77  last_time_used.tv_sec = 0;
78  last_time_used.tv_nsec = 0;
79  last_slot_used = 0;
80  changed_slot = false;
82  }
83 
91  RateCounterForInterval(EVENT_COUNT_TYPE max_events, uint64_t units)
92  {
93  rate_threshold = max_events;
94  event_slots = nullptr;
95  set_interval(units);
96  }
97 
99  delete[] event_slots;
100  }
101 
105  inline uint32_t get_interval() const OME_ALWAYS_INLINE {
106  return (interval_in_units);
107  }
108 
112  return (interval_in_nanoseconds);
113  }
114 
117  inline EVENT_COUNT_TYPE get_events_in_interval() const OME_ALWAYS_INLINE {
118  return (events_in_interval);
119  }
120 
123  inline EVENT_COUNT_TYPE get_maximum_rate() const OME_ALWAYS_INLINE {
124  return (rate_threshold);
125  }
126 
129  inline void set_maximum_rate(EVENT_COUNT_TYPE max_events) OME_ALWAYS_INLINE {
130  rate_threshold = max_events;
131  }
132 
133 
145  EVENT_COUNT_TYPE add_events_to_slot(EVENT_COUNT_TYPE count=1,
146  const struct timespec *now = nullptr)
147  {
148  struct timespec system_time;
149  const struct timespec *current_time;
150 
151  if (now != nullptr) {
152  current_time = now;
153  } else {
154  clock_gettime_via_tick(&system_time, false);
155  current_time = &system_time;
156  }
157 
158  int64_t delta_secs = current_time->tv_sec - last_time_used.tv_sec;
159  int64_t delta_ns = current_time->tv_nsec - last_time_used.tv_nsec;
160  last_time_used = *current_time;
161  // fast path for initialization and events beyond the interval window
162  // First test avoids possible overflow,
163  // while second test updates delta_ns as a side-effect
164  if ((delta_secs >= static_cast<int64_t>(interval_threshold_in_seconds)) ||
165  ((delta_ns += (ONE_BILLION * delta_secs)) >= static_cast<int64_t>(interval_in_nanoseconds))) {
166  if (changed_slot == true) {
167  memset(event_slots, 0, sizeof(EVENT_COUNT_TYPE) * interval_in_units);
168  changed_slot = false;
169  }
170  last_slot_used = 0;
171  event_slots[0] = count; // really event_slots[last_slot_used] = count;
172  events_in_interval = count;
174  }
175  if (OME_EXPECT_FALSE(delta_ns < 0)) { // very unexpected, but treat as now
176  delta_ns = 0;
177  }
178  uint64_t delta = delta_ns / NS_PER_UNITS;
179  uint_fast32_t slot = last_slot_used;
180  EVENT_COUNT_TYPE newTotal = events_in_interval;
181  for(uint_fast32_t i = static_cast<uint_fast32_t>(delta); i > 0; --i) {
182  changed_slot = true;
183  // everything prior to this was a no-op...
184  if (++slot >= interval_in_units) { // wrap to next round-robin slot
185  slot = 0;
186  }
187  newTotal -= event_slots[slot];
188  assignToZero(event_slots[slot]); // fade it away...
189  }
190  newTotal += count;
191  events_in_interval = newTotal;
192  event_slots[slot] += count;
193  last_slot_used = slot;
195  }
196 }; // end class RateCounterForInterval<>
197 
198 // mandatory typedef for compatibility
200 
201 // optional typedef for convenience
203 
207 #endif
208 /* vim: set expandtab shiftwidth=4 tabstop=4: */
RateCounterForInterval::NS_PER_UNITS
@ NS_PER_UNITS
Definition: rate_counter.hpp:43
clock_gettime_via_tick
int clock_gettime_via_tick(struct timespec *result, bool force) OME_ALWAYS_INLINE OME_ALWAYS_OPTIMIZE("-O3")
Definition: tick_time.h:290
RateCounterForInterval::last_slot_used
uint32_t last_slot_used
round-robin subscript for slot table
Definition: rate_counter.hpp:52
RateCounterForInterval::last_time_used
struct timespec last_time_used
time of last recorded event
Definition: rate_counter.hpp:51
RateCounterForInterval::get_interval
uint32_t get_interval() const OME_ALWAYS_INLINE
Get the length of the interval in units of UNITS_PER_SECOND.
Definition: rate_counter.hpp:105
RateCounterForInterval::get_maximum_rate
EVENT_COUNT_TYPE get_maximum_rate() const OME_ALWAYS_INLINE
Get the maximum permitted events per interval.
Definition: rate_counter.hpp:123
RateCounterForInterval::get_events_in_interval
EVENT_COUNT_TYPE get_events_in_interval() const OME_ALWAYS_INLINE
Get total number of events in the interval.
Definition: rate_counter.hpp:117
assignToZero.hpp
RateCounterForInterval::events_in_interval
EVENT_COUNT_TYPE events_in_interval
total events currently in the interval
Definition: rate_counter.hpp:46
RateCounterForInterval::event_slots
EVENT_COUNT_TYPE * event_slots
storage for events-per-interval counters
Definition: rate_counter.hpp:45
RateCounterForInterval::add_events_to_slot
EVENT_COUNT_TYPE add_events_to_slot(EVENT_COUNT_TYPE count=1, const struct timespec *now=nullptr)
Add events to an interval.
Definition: rate_counter.hpp:145
srcID
const char srcID[]
Definition: catSym.c:17
RateCounter64
RateCounterForInterval< int64_t > RateCounter64
Definition: rate_counter.hpp:202
RateCounter
RateCounterForInterval< int32_t > RateCounter
Definition: rate_counter.hpp:199
RateCounterForInterval::interval_in_nanoseconds
uint64_t interval_in_nanoseconds
interval duration in nanoseconds
Definition: rate_counter.hpp:49
RateCounterForInterval::~RateCounterForInterval
~RateCounterForInterval()
Definition: rate_counter.hpp:98
rate_counter.hpp
OME_USED
const char srcID[] OME_USED
Definition: tick_time.cpp:24
RateCounterForInterval::set_interval
void set_interval(uint64_t units) OME_ALWAYS_INLINE
Set the size of the interval window in units of UNITS_PER_SECOND.
Definition: rate_counter.hpp:64
RateCounterForInterval::RateCounterForInterval
RateCounterForInterval(EVENT_COUNT_TYPE max_events, uint64_t units)
Construct an O(1) RateCounterForInterval object.
Definition: rate_counter.hpp:91
compiler_hints.h
Compiler-specific macros to provide performance-related hints.
OME_EXPECT_FALSE
#define OME_EXPECT_FALSE(expr)
Annotation macro for conditional expression expected to be false.
Definition: compiler_hints.h:540
OME_ALWAYS_INLINE
#define OME_ALWAYS_INLINE
Tell the compiler to alway inline a function, regardless of optimization level.
Definition: compiler_hints.h:364
RateCounterForInterval::interval_threshold_in_seconds
uint64_t interval_threshold_in_seconds
coarse interval duration in seconds
Definition: rate_counter.hpp:50
RateCounterForInterval::get_interval_in_nanoseconds
uint32_t get_interval_in_nanoseconds() const OME_ALWAYS_INLINE
Get the length of the interval in nanoseconds.
Definition: rate_counter.hpp:111
RateCounterForInterval::changed_slot
bool changed_slot
enables optimization if events are widely spaced
Definition: rate_counter.hpp:53
tick_time.h
FARGOS CPU tick routines.
RateCounterForInterval::rate_threshold
EVENT_COUNT_TYPE rate_threshold
maximum permitted events in the interval
Definition: rate_counter.hpp:47
RateCounterForInterval::set_maximum_rate
void set_maximum_rate(EVENT_COUNT_TYPE max_events) OME_ALWAYS_INLINE
Set the maximum permitted events per interval.
Definition: rate_counter.hpp:129
assignToZero
void assignToZero(int32_t &n) OME_ALWAYS_INLINE
Assigns 0 to a 32-bit integer.
Definition: assignToZero.hpp:48
RateCounterForInterval::interval_in_units
uint64_t interval_in_units
interval duration in UNITS_PER_SECOND
Definition: rate_counter.hpp:48
RateCounterForInterval::ONE_BILLION
@ ONE_BILLION
Definition: rate_counter.hpp:42
RateCounterForInterval
Sliding window rate counter that takes O(1) time.
Definition: rate_counter.hpp:39
Generated: Fri Jul 31 2020 18:19:15
Support Information