JayBeams  0.1
Another project to have fun coding.
ut_event_rate_estimator.cpp
Go to the documentation of this file.
2 
3 #include <boost/test/unit_test.hpp>
4 
5 /**
6  * @test Test default construction and basic operations.
7  */
8 BOOST_AUTO_TEST_CASE(event_rate_estimator_base) {
9  jb::event_rate_estimator<> stats(std::chrono::microseconds(100));
10 
11  std::chrono::microseconds c(1000000);
12 
13  int calls = 0;
14  int nsamples = 0;
15  std::uint64_t last = 0;
16  std::uint64_t repeats = 0;
17  auto f = [&](std::uint64_t c, std::uint64_t r) {
18  ++calls;
19  nsamples += r;
20  last = c;
21  repeats = r;
22  };
23 
24  stats.sample(c, f);
25  stats.sample(c, f);
26  stats.sample(c, f);
27  BOOST_CHECK_EQUAL(nsamples, 0);
28  stats.sample(++c, f);
29  BOOST_CHECK_EQUAL(nsamples, 1);
30  BOOST_CHECK_EQUAL(last, 3);
31  stats.sample(++c, f);
32  BOOST_CHECK_EQUAL(nsamples, 2);
33  BOOST_CHECK_EQUAL(last, 4);
34  c = std::chrono::microseconds(1000000) + std::chrono::microseconds(99);
35  stats.sample(c, f);
36  BOOST_CHECK_EQUAL(nsamples, 99);
37  BOOST_CHECK_EQUAL(last, 5);
38  stats.sample(c, f);
39  BOOST_CHECK_EQUAL(nsamples, 99);
40  BOOST_CHECK_EQUAL(last, 5);
41  stats.sample(++c, f);
42  BOOST_CHECK_EQUAL(nsamples, 100);
43  BOOST_CHECK_EQUAL(last, 7);
44  stats.sample(++c, f);
45  BOOST_CHECK_EQUAL(nsamples, 101);
46  BOOST_CHECK_EQUAL(last, 5);
47 }
48 
49 /**
50  * @test Verify that event_rate_estimator optimizes big jumps in time.
51  */
52 BOOST_AUTO_TEST_CASE(event_rate_estimator_jump) {
53  std::chrono::microseconds period(100);
54  jb::event_rate_estimator<> stats(period);
55 
56  std::chrono::microseconds ts(1000000);
57 
58  int calls = 0;
59  int nsamples = 0;
60  std::uint64_t last = 0;
61  std::uint64_t repeats = 0;
62  auto f = [&](std::uint64_t c, std::uint64_t r) {
63  ++calls;
64  nsamples += r;
65  last = c;
66  repeats = r;
67  };
68 
69  // Record one sample ...
70  stats.sample(ts, f);
71  BOOST_CHECK_EQUAL(calls, 0);
72  // ... move time one tick ...
73  stats.sample(++ts, f);
74  BOOST_CHECK_EQUAL(calls, 1);
75  BOOST_CHECK_EQUAL(nsamples, 1);
76  BOOST_CHECK_EQUAL(last, 1);
77  // ... move time another tick ...
78  stats.sample(++ts, f);
79  BOOST_CHECK_EQUAL(calls, 2);
80  BOOST_CHECK_EQUAL(nsamples, 2);
81  BOOST_CHECK_EQUAL(last, 2);
82 
83  // ... now skip forward 5 periods ..
84  ts += 15 * period;
85  stats.sample(ts, f);
86  // ... we expect 98 calls to clear the period, then a single call to
87  // move the period forward 14.98 times ...
88  BOOST_CHECK_EQUAL(calls, 2 + 100 + 1);
89  // ... we expect 15 * period + 3 samples ...
90  BOOST_CHECK_EQUAL(nsamples, 2 + 15 * period.count());
91  BOOST_CHECK_EQUAL(last, 0);
92  BOOST_CHECK_EQUAL(repeats, 14 * period.count());
93 
94  // .. move time forward one interval at a time ...
95  stats.sample(++ts, f);
96  stats.sample(++ts, f);
97  stats.sample(++ts, f);
98  stats.sample(++ts, f);
99  BOOST_CHECK_EQUAL(calls, 103 + 4);
100  BOOST_CHECK_EQUAL(nsamples, 1502 + 4);
101  BOOST_CHECK_EQUAL(last, 4);
102  BOOST_CHECK_EQUAL(repeats, 1);
103 
104  // ... and make a huge jump with some weird additions ...
105  ts += 137 * period + std::chrono::microseconds(7);
106  stats.sample(ts, f);
107  BOOST_CHECK_EQUAL(calls, 107 + 100 + 1);
108  BOOST_CHECK_EQUAL(nsamples, 1506 + 137 * period.count() + 7);
109  BOOST_CHECK_EQUAL(last, 0);
110  BOOST_CHECK_EQUAL(repeats, 136 * period.count() + 7);
111 }
112 
113 /**
114  * @test Verify that estimators can use a different bucket size.
115  */
116 BOOST_AUTO_TEST_CASE(event_rate_estimator_milliseconds) {
117  typedef std::chrono::milliseconds duration_type;
118  jb::event_rate_estimator<duration_type> stats(duration_type(100));
119 
120  duration_type c(1000);
121 
122  int calls = 0;
123  int nsamples = 0;
124  std::uint64_t last = 0;
125  std::uint64_t repeats = 0;
126  auto f = [&](std::uint64_t c, std::uint64_t r) {
127  ++calls;
128  nsamples += r;
129  last = c;
130  repeats = r;
131  };
132 
133  stats.sample(c, f);
134  stats.sample(c, f);
135  stats.sample(c, f);
136  BOOST_CHECK_EQUAL(nsamples, 0);
137  stats.sample(++c, f);
138  BOOST_CHECK_EQUAL(nsamples, 1);
139  BOOST_CHECK_EQUAL(last, 3);
140  stats.sample(++c, f);
141  BOOST_CHECK_EQUAL(nsamples, 2);
142  BOOST_CHECK_EQUAL(last, 4);
143  c = std::chrono::milliseconds(1000) + std::chrono::milliseconds(99);
144  stats.sample(c, f);
145  BOOST_CHECK_EQUAL(nsamples, 99);
146  BOOST_CHECK_EQUAL(last, 5);
147  stats.sample(c, f);
148  BOOST_CHECK_EQUAL(nsamples, 99);
149  BOOST_CHECK_EQUAL(last, 5);
150  stats.sample(++c, f);
151  BOOST_CHECK_EQUAL(nsamples, 100);
152  BOOST_CHECK_EQUAL(last, 7);
153  stats.sample(++c, f);
154  BOOST_CHECK_EQUAL(nsamples, 101);
155  BOOST_CHECK_EQUAL(last, 5);
156 }
157 
158 /**
159  * @test Test error cases
160  */
161 BOOST_AUTO_TEST_CASE(event_rate_estimator_errors) {
162  using namespace std::chrono;
164 
165  BOOST_CHECK_THROW(tested(seconds(10), seconds(20)), std::invalid_argument);
166  BOOST_CHECK_THROW(tested(seconds(10), seconds(0)), std::invalid_argument);
167  BOOST_CHECK_THROW(tested(seconds(10), seconds(3)), std::invalid_argument);
168 
169  typedef std::chrono::duration<std::size_t> ticks;
170  typedef jb::event_rate_estimator<ticks> testbig;
171  auto big = std::numeric_limits<std::size_t>::max();
172  BOOST_CHECK_THROW(testbig(ticks(big), ticks(1)), std::invalid_argument);
173 }
Estimate event rates over a trailing measurement period.
BOOST_AUTO_TEST_CASE(event_rate_estimator_base)
void sample(duration_type ts, functor update)
Record a sample.
std::size_t nsamples(container_type const &a)
Count the elements in the last dimension of a vector-like container.