RateTest.cpp
Go to the documentation of this file.
1 // std
2 #include <cmath>
3 #include <thread>
4 
5 // gtest
6 #include <gtest/gtest.h>
7 
8 // bota_worker
9 #include "bota_worker/Rate.hpp"
10 
11 // Local and build server tolerances.
12 #define RATE_TEST_TOL_LOCAL 0.001
13 #define RATE_TEST_TOL_BUILD_SERVER 0.007
14 
15 // Use the build server tolerance.
16 #define RATE_TEST_TOL RATE_TEST_TOL_BUILD_SERVER
17 
22 void doSomething(const double duration)
23 {
24  std::this_thread::sleep_for(std::chrono::nanoseconds(static_cast<int64_t>(1e9 * duration)));
25 }
26 
27 TEST(RateTest, Initialization)
28 { // NOLINT
29  const std::string name = "Test";
30  const double time_step = 0.1;
31  bota_worker::Rate rate(name, time_step);
32 
33  EXPECT_EQ(rate.getOptions().name_, name);
34  EXPECT_EQ(rate.getOptions().timeStep_, time_step);
35  EXPECT_EQ(rate.getOptions().maxTimeStepFactorWarning_, 1.0);
36  EXPECT_EQ(rate.getOptions().maxTimeStepFactorError_, 10.0);
37  EXPECT_EQ(rate.getOptions().enforceRate_, true);
38  EXPECT_EQ(rate.getOptions().clockId_, CLOCK_MONOTONIC);
39  EXPECT_EQ(rate.getNumTimeSteps(), 0u);
40  EXPECT_EQ(rate.getNumWarnings(), 0u);
41  EXPECT_EQ(rate.getNumErrors(), 0u);
42  EXPECT_TRUE(std::isnan(rate.getAwakeTime()));
43  EXPECT_TRUE(std::isnan(rate.getAwakeTimeMean()));
44  EXPECT_TRUE(std::isnan(rate.getAwakeTimeStdDev()));
45 }
46 
47 TEST(RateTest, Reset)
48 { // NOLINT
49  const double time_step = 0.1;
50  const double processing_time = 0.05;
51 
52  // Run for one time step and reset.
53  bota_worker::Rate rate("Test", time_step);
54  doSomething(processing_time);
55  rate.sleep();
56  rate.reset();
57 
58  EXPECT_EQ(rate.getNumTimeSteps(), 0u);
59  EXPECT_EQ(rate.getNumWarnings(), 0u);
60  EXPECT_EQ(rate.getNumErrors(), 0u);
61  EXPECT_TRUE(std::isnan(rate.getAwakeTime()));
62  EXPECT_TRUE(std::isnan(rate.getAwakeTimeMean()));
63  EXPECT_TRUE(std::isnan(rate.getAwakeTimeStdDev()));
64 }
65 
66 TEST(RateTest, SleepWithEnforceRate)
67 { // NOLINT
68  const double time_step = 0.1;
69  bota_worker::Rate rate("Test", time_step);
70  rate.getOptions().enforceRate_ = true;
71 
72  timespec start{};
73  timespec end{};
74  const double processing_time = 0.05;
75  std::vector<double> processing_times;
76  std::vector<double> summed_step_times;
77 
78  // Test sleep() without processing.
79  clock_gettime(CLOCK_MONOTONIC, &start);
80  rate.reset();
81  rate.sleep();
82  clock_gettime(CLOCK_MONOTONIC, &end);
83  EXPECT_NEAR(bota_worker::Rate::getDuration(start, end), time_step, RATE_TEST_TOL);
84 
85  // Test sleep() with processing additionally.
86  clock_gettime(CLOCK_MONOTONIC, &start);
87  rate.reset();
88  doSomething(processing_time);
89  rate.sleep();
90  clock_gettime(CLOCK_MONOTONIC, &end);
91  EXPECT_NEAR(bota_worker::Rate::getDuration(start, end), time_step, RATE_TEST_TOL);
92 
93  // Test sleep() with where one step takes too long, recovery within one step.
94  processing_times = { 0.02, 0.02, 0.15, 0.02, 0.02 };
95  summed_step_times = { 0.0, 0.1, 0.2, 0.35, 0.4, 0.5 };
96  rate.reset();
97  clock_gettime(CLOCK_MONOTONIC, &start);
98  for (unsigned int i = 0; i < processing_times.size(); i++)
99  {
100  clock_gettime(CLOCK_MONOTONIC, &end);
101  EXPECT_NEAR(bota_worker::Rate::getDuration(start, end), summed_step_times[i], 2.0 * RATE_TEST_TOL);
102  doSomething(processing_times[i]);
103  rate.sleep();
104  }
105  clock_gettime(CLOCK_MONOTONIC, &end);
106  EXPECT_NEAR(bota_worker::Rate::getDuration(start, end), summed_step_times[processing_times.size()],
107  2.0 * RATE_TEST_TOL);
108 
109  // Test sleep() with where one step takes too long, recovery within two steps.
110  processing_times = { 0.02, 0.02, 0.19, 0.02, 0.02, 0.02 };
111  summed_step_times = { 0.0, 0.1, 0.2, 0.39, 0.41, 0.5, 0.6 };
112  rate.reset();
113  clock_gettime(CLOCK_MONOTONIC, &start);
114  for (unsigned int i = 0; i < processing_times.size(); i++)
115  {
116  clock_gettime(CLOCK_MONOTONIC, &end);
117  EXPECT_NEAR(bota_worker::Rate::getDuration(start, end), summed_step_times[i], 2.0 * RATE_TEST_TOL);
118  doSomething(processing_times[i]);
119  rate.sleep();
120  }
121  clock_gettime(CLOCK_MONOTONIC, &end);
122  EXPECT_NEAR(bota_worker::Rate::getDuration(start, end), summed_step_times[processing_times.size()],
123  2.0 * RATE_TEST_TOL);
124 
125  // Test sleep() with where two steps take too long, recovery within one step.
126  processing_times = { 0.02, 0.02, 0.12, 0.12, 0.02, 0.02 };
127  summed_step_times = { 0.0, 0.1, 0.2, 0.32, 0.44, 0.5, 0.6 };
128  rate.reset();
129  clock_gettime(CLOCK_MONOTONIC, &start);
130  for (unsigned int i = 0; i < processing_times.size(); i++)
131  {
132  clock_gettime(CLOCK_MONOTONIC, &end);
133  EXPECT_NEAR(bota_worker::Rate::getDuration(start, end), summed_step_times[i], 2.0 * RATE_TEST_TOL);
134  doSomething(processing_times[i]);
135  rate.sleep();
136  }
137  clock_gettime(CLOCK_MONOTONIC, &end);
138  EXPECT_NEAR(bota_worker::Rate::getDuration(start, end), summed_step_times[processing_times.size()],
139  2.0 * RATE_TEST_TOL);
140 
141  // Test sleep() with where two steps take too long, recovery within two steps.
142  processing_times = { 0.02, 0.02, 0.12, 0.12, 0.08, 0.02, 0.02 };
143  summed_step_times = { 0.0, 0.1, 0.2, 0.32, 0.44, 0.52, 0.6, 0.7 };
144  rate.reset();
145  clock_gettime(CLOCK_MONOTONIC, &start);
146  for (unsigned int i = 0; i < processing_times.size(); i++)
147  {
148  clock_gettime(CLOCK_MONOTONIC, &end);
149  EXPECT_NEAR(bota_worker::Rate::getDuration(start, end), summed_step_times[i], 2.0 * RATE_TEST_TOL);
150  doSomething(processing_times[i]);
151  rate.sleep();
152  }
153  clock_gettime(CLOCK_MONOTONIC, &end);
154  EXPECT_NEAR(bota_worker::Rate::getDuration(start, end), summed_step_times[processing_times.size()],
155  2.0 * RATE_TEST_TOL);
156 }
157 
158 TEST(RateTest, SleepWithoutEnforceRate)
159 { // NOLINT
160  const double time_step = 0.1;
161  bota_worker::Rate rate("Test", time_step);
162  rate.getOptions().enforceRate_ = false;
163 
164  timespec start{};
165  timespec end{};
166  const double processing_time = 0.05;
167  std::vector<double> processing_times;
168  std::vector<double> summed_step_times;
169 
170  // Test sleep() without processing.
171  clock_gettime(CLOCK_MONOTONIC, &start);
172  rate.reset();
173  rate.sleep();
174  clock_gettime(CLOCK_MONOTONIC, &end);
175  EXPECT_NEAR(bota_worker::Rate::getDuration(start, end), time_step, RATE_TEST_TOL);
176 
177  // Test sleep() with processing.
178  clock_gettime(CLOCK_MONOTONIC, &start);
179  rate.reset();
180  doSomething(processing_time);
181  rate.sleep();
182  clock_gettime(CLOCK_MONOTONIC, &end);
183  EXPECT_NEAR(bota_worker::Rate::getDuration(start, end), time_step, RATE_TEST_TOL);
184 
185  // Test sleep() with where one step takes too long.
186  processing_times = { 0.02, 0.02, 0.15, 0.02, 0.02 };
187  summed_step_times = { 0.0, 0.1, 0.2, 0.35, 0.45, 0.55 };
188  rate.reset();
189  clock_gettime(CLOCK_MONOTONIC, &start);
190  for (unsigned int i = 0; i < processing_times.size(); i++)
191  {
192  clock_gettime(CLOCK_MONOTONIC, &end);
193  EXPECT_NEAR(bota_worker::Rate::getDuration(start, end), summed_step_times[i], 2.0 * RATE_TEST_TOL);
194  doSomething(processing_times[i]);
195  rate.sleep();
196  }
197  clock_gettime(CLOCK_MONOTONIC, &end);
198  EXPECT_NEAR(bota_worker::Rate::getDuration(start, end), summed_step_times[processing_times.size()],
199  2.0 * RATE_TEST_TOL);
200 
201  // Test sleep() with where two steps take too long.
202  processing_times = { 0.02, 0.02, 0.12, 0.12, 0.02, 0.02 };
203  summed_step_times = { 0.0, 0.1, 0.2, 0.32, 0.44, 0.54, 0.64 };
204  rate.reset();
205  clock_gettime(CLOCK_MONOTONIC, &start);
206  for (unsigned int i = 0; i < processing_times.size(); i++)
207  {
208  clock_gettime(CLOCK_MONOTONIC, &end);
209  EXPECT_NEAR(bota_worker::Rate::getDuration(start, end), summed_step_times[i], 4.0 * RATE_TEST_TOL);
210  doSomething(processing_times[i]);
211  rate.sleep();
212  }
213  clock_gettime(CLOCK_MONOTONIC, &end);
214  EXPECT_NEAR(bota_worker::Rate::getDuration(start, end), summed_step_times[processing_times.size()],
215  4.0 * RATE_TEST_TOL);
216 }
217 
218 TEST(RateTest, WarningsAndErrors)
219 { // NOLINT
220  const double time_step = 0.1;
221  bota_worker::Rate rate("Test", time_step);
222  doSomething(0.5 * time_step); // Ok
223  rate.sleep();
224  doSomething(2.0 * time_step); // Warning
225  rate.sleep();
226  doSomething(3.0 * time_step); // Warning
227  rate.sleep();
228  doSomething(11.0 * time_step); // Error
229  rate.sleep();
230 
231  EXPECT_EQ(rate.getNumTimeSteps(), 4u);
232  EXPECT_EQ(rate.getNumWarnings(), 2u);
233  EXPECT_EQ(rate.getNumErrors(), 1u);
234 }
235 
236 TEST(RateTest, StatisticsWithEnforceRate)
237 { // NOLINT
238  const double time_step = 0.1;
239  bota_worker::Rate rate("Test", time_step);
240  rate.getOptions().enforceRate_ = true;
241 
242  // Test 1 time step.
243  const double processing_time = 0.05;
244  rate.reset();
245  doSomething(processing_time);
246  rate.sleep();
247 
248  EXPECT_EQ(rate.getNumTimeSteps(), 1u);
249  EXPECT_NEAR(rate.getAwakeTime(), processing_time, 2.0 * RATE_TEST_TOL);
250  EXPECT_NEAR(rate.getAwakeTimeMean(), processing_time, RATE_TEST_TOL);
251  EXPECT_TRUE(std::isnan(rate.getAwakeTimeStdDev()));
252 
253  // Test 10 time steps with similar processing times.
254  const unsigned int num_time_steps = 10;
255  rate.reset();
256  for (unsigned int i = 0; i < num_time_steps; i++)
257  {
258  doSomething(processing_time);
259  rate.sleep();
260  }
261 
262  EXPECT_EQ(rate.getNumTimeSteps(), num_time_steps);
263  EXPECT_NEAR(rate.getAwakeTime(), processing_time, 2.0 * RATE_TEST_TOL);
264  EXPECT_NEAR(rate.getAwakeTimeMean(), processing_time, RATE_TEST_TOL);
265  EXPECT_LE(rate.getAwakeTimeStdDev(), RATE_TEST_TOL);
266  EXPECT_FALSE(rate.getAwakeTimeStdDev() == 0.0); // If it is 0.0 something is fishy.
267 
268  // Test 9 time steps with different processing times.
269  const std::vector<double> processing_times = { 0.04, 0.02, 0.04, 0.07, 0.05, 0.05, 0.04, 0.09, 0.05 };
270  rate.reset();
271  for (double processing_time : processing_times)
272  {
273  doSomething(processing_time);
274  rate.sleep();
275  }
276 
277  EXPECT_EQ(rate.getNumTimeSteps(), processing_times.size());
278  EXPECT_NEAR(rate.getAwakeTime(), *processing_times.rbegin(), 2.0 * RATE_TEST_TOL);
279  EXPECT_NEAR(rate.getAwakeTimeMean(), 0.05, RATE_TEST_TOL);
280  EXPECT_NEAR(rate.getAwakeTimeStdDev(), 0.02, RATE_TEST_TOL);
281 
282  // Test again with time step violation.
283  rate.getOptions().timeStep_ = 0.035;
284  rate.reset();
285  for (double processing_time : processing_times)
286  {
287  doSomething(processing_time);
288  rate.sleep();
289  }
290 
291  EXPECT_EQ(rate.getNumTimeSteps(), processing_times.size());
292  EXPECT_NEAR(rate.getAwakeTime(), *processing_times.rbegin(), 2.0 * RATE_TEST_TOL);
293  EXPECT_NEAR(rate.getAwakeTimeMean(), 0.05, RATE_TEST_TOL);
294  EXPECT_NEAR(rate.getAwakeTimeStdDev(), 0.02, RATE_TEST_TOL);
295 }
296 
297 TEST(RateTest, StatisticsWithoutEnforceRate)
298 { // NOLINT
299  const double time_step = 0.1;
300  bota_worker::Rate rate("Test", time_step);
301  rate.getOptions().enforceRate_ = false;
302 
303  // Test 1 time step.
304  const double processing_time = 0.05;
305  rate.reset();
306  doSomething(processing_time);
307  rate.sleep();
308 
309  EXPECT_EQ(rate.getNumTimeSteps(), 1u);
310  EXPECT_NEAR(rate.getAwakeTime(), processing_time, 2.0 * RATE_TEST_TOL);
311  EXPECT_NEAR(rate.getAwakeTimeMean(), processing_time, RATE_TEST_TOL);
312  EXPECT_TRUE(std::isnan(rate.getAwakeTimeStdDev()));
313 
314  // Test 10 time steps with similar processing times.
315  const unsigned int num_time_steps = 10;
316  rate.reset();
317  for (unsigned int i = 0; i < num_time_steps; i++)
318  {
319  doSomething(processing_time);
320  rate.sleep();
321  }
322 
323  EXPECT_EQ(rate.getNumTimeSteps(), num_time_steps);
324  EXPECT_NEAR(rate.getAwakeTime(), processing_time, 2.0 * RATE_TEST_TOL);
325  EXPECT_NEAR(rate.getAwakeTimeMean(), processing_time, RATE_TEST_TOL);
326  EXPECT_LE(rate.getAwakeTimeStdDev(), RATE_TEST_TOL);
327  EXPECT_FALSE(rate.getAwakeTimeStdDev() == 0.0); // If it is 0.0 something is fishy.
328 
329  // Test 9 time steps with different processing times.
330  const std::vector<double> processing_times = { 0.04, 0.02, 0.04, 0.07, 0.05, 0.05, 0.04, 0.09, 0.05 };
331  rate.reset();
332  for (double processing_time : processing_times)
333  {
334  doSomething(processing_time);
335  rate.sleep();
336  }
337 
338  EXPECT_EQ(rate.getNumTimeSteps(), processing_times.size());
339  EXPECT_NEAR(rate.getAwakeTime(), *processing_times.rbegin(), 2.0 * RATE_TEST_TOL);
340  EXPECT_NEAR(rate.getAwakeTimeMean(), 0.05, RATE_TEST_TOL);
341  EXPECT_NEAR(rate.getAwakeTimeStdDev(), 0.02, RATE_TEST_TOL);
342 
343  // Test again with time step violation.
344  rate.getOptions().timeStep_ = 0.035;
345  rate.reset();
346  for (double processing_time : processing_times)
347  {
348  doSomething(processing_time);
349  rate.sleep();
350  }
351 
352  EXPECT_EQ(rate.getNumTimeSteps(), processing_times.size());
353  EXPECT_NEAR(rate.getAwakeTime(), *processing_times.rbegin(), 2.0 * RATE_TEST_TOL);
354  EXPECT_NEAR(rate.getAwakeTimeMean(), 0.05, RATE_TEST_TOL);
355  EXPECT_NEAR(rate.getAwakeTimeStdDev(), 0.02, RATE_TEST_TOL);
356 }
double getAwakeTimeMean() const
Definition: Rate.cpp:185
ROSCPP_DECL void start()
double getAwakeTime() const
Definition: Rate.cpp:173
TEST(RateTest, Initialization)
Definition: RateTest.cpp:27
unsigned int getNumWarnings() const
Definition: Rate.hpp:204
unsigned int getNumTimeSteps() const
Definition: Rate.hpp:195
double getAwakeTimeStdDev() const
Definition: Rate.cpp:209
std::atomic< double > maxTimeStepFactorError_
If the awake time is bigger than the time step multiplied by this factor, it counts as an error...
Definition: RateOptions.hpp:63
void sleep()
Definition: Rate.cpp:96
void doSomething(const double duration)
Definition: RateTest.cpp:22
std::atomic< double > timeStep_
Time step in seconds.
Definition: RateOptions.hpp:59
RateOptions & getOptions()
Definition: Rate.hpp:140
std::atomic< bool > enforceRate_
Boolean indicating whether the rate should be enforced.
Definition: RateOptions.hpp:65
#define RATE_TEST_TOL
Definition: RateTest.cpp:16
std::string name_
Name for printing.
Definition: RateOptions.hpp:57
unsigned int getNumErrors() const
Definition: Rate.hpp:213
std::atomic< clockid_t > clockId_
Linux clock ID.
Definition: RateOptions.hpp:67
static double getDuration(const timespec &start, const timespec &end)
Definition: Rate.cpp:214
std::atomic< double > maxTimeStepFactorWarning_
If the awake time is bigger than the time step multiplied by this factor, it counts as an warning...
Definition: RateOptions.hpp:61
void reset()
Definition: Rate.cpp:74


bota_worker
Author(s):
autogenerated on Wed Mar 3 2021 03:09:10