Rate.cpp
Go to the documentation of this file.
1 /**********************************************************************
2  * Software License Agreement (BSD License)
3  *
4  * Copyright (c) 2018, Remo Diethelm
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  *
11  * * Redistributions of source code must retain the above copyright
12  * notice, this list of conditions and the following disclaimer.
13  * * Redistributions in binary form must reproduce the above
14  * copyright notice, this list of conditions and the following
15  * disclaimer in the documentation and/or other materials provided
16  * with the distribution.
17  * * Neither the name of Robotic Systems Lab nor ETH Zurich
18  * nor the names of its contributors may be used to endorse or
19  * promote products derived from this software without specific
20  * prior written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
25  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
26  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
27  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
28  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
29  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
30  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
32  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33  * POSSIBILITY OF SUCH DAMAGE.
34  */
35 
42 // bota_worker
43 #include "bota_worker/Rate.hpp"
44 
45 #include <ros/ros.h>
46 namespace bota_worker
47 {
48 Rate::Rate(const std::string& name, const double timeStep) : Rate(RateOptions(name, timeStep))
49 {
50 }
51 
52 Rate::Rate(RateOptions options) : options_(std::move(options))
53 {
54  reset();
55 }
56 
57 Rate::Rate(Rate&& other) noexcept
58  : options_(std::move(other.options_))
61  , stepTime_(other.stepTime_)
63  , numWarnings_(other.numWarnings_)
64  , numErrors_(other.numErrors_)
67  , awakeTime_(other.awakeTime_)
69  , awakeTimeM2_(other.awakeTimeM2_)
70 {
71  reset();
72 }
73 
75 {
76  // Reset the counters and statistics.
77  numTimeSteps_ = 0;
78  numWarnings_ = 0;
79  numErrors_ = 0;
80  awakeTime_ = 0.0;
81  awakeTimeMean_ = 0.0;
82  awakeTimeM2_ = 0.0;
83  lastWarningPrintTime_.tv_sec = 0;
84  lastWarningPrintTime_.tv_nsec = 0;
85  lastErrorPrintTime_.tv_sec = 0;
86  lastErrorPrintTime_.tv_nsec = 0;
87 
88  // Update the sleep time to the current time.
89  timespec now{};
90  clock_gettime(options_.clockId_, &now);
91  sleepStartTime_ = now;
92  sleepEndTime_ = now;
93  stepTime_ = now;
94 }
95 
97 {
98  // Get the current time and compute the time which the thread has been awake.
99  clock_gettime(options_.clockId_, &sleepStartTime_);
101 
102  // Update the statistics. The algorithm is described here:
103  // https://en.wikipedia.org/wiki/Algorithms_for_calculating_variance
104  numTimeSteps_++;
105  const double delta = awakeTime_ - awakeTimeMean_;
106  awakeTimeMean_ += delta / numTimeSteps_;
107  const double delta2 = awakeTime_ - awakeTimeMean_;
108  awakeTimeM2_ += delta * delta2;
109 
110  if (options_.timeStep_ == 0.0)
111  {
113  }
114  else
115  {
116  // Check if the awake exceeds the threshold for warnings or errors.
118  {
119  // Count and print the error.
120  numErrors_++;
122  {
123  ROS_ERROR_STREAM("Rate '" << options_.name_ << "': "
124  << "Processing took too long (" << awakeTime_ << " s > " << options_.timeStep_.load()
125  << " s). "
126  << "Number of errors: " << numErrors_ << ".");
128  }
129  }
131  {
132  // Print and count the warning (only if no error).
133  numWarnings_++;
135  {
136  ROS_WARN_STREAM("Rate '" << options_.name_ << "': "
137  << "Processing took too long (" << awakeTime_ << " s > " << options_.timeStep_.load()
138  << " s). "
139  << "Number of warnings: " << numWarnings_ << ".");
141  }
142  }
143 
144  // Compute the next desired step time.
146 
147  // Get the current time again and check if the step time has already past.
148  clock_gettime(options_.clockId_, &sleepEndTime_);
149  const bool is_behind = (getDuration(sleepEndTime_, stepTime_) < 0.0);
150  if (is_behind)
151  {
152  if (!options_.enforceRate_)
153  {
154  // We are behind schedule but do not enforce the rate, so we increase the length of
155  // the current time step by setting the desired step time to when sleep() ends.
157  }
158  }
159  else
160  {
161  // sleep() will finish in time. The end of the function will be at
162  // the target time of clock_nanosleep(..).
164 
165  // Sleep until the step time is reached.
166  clock_nanosleep(options_.clockId_, TIMER_ABSTIME, &stepTime_, NULL); // NOLINT
167 
168  // Do nothing here to ensure sleep() does not consume time after clock_nanosleep(..).
169  }
170  }
171 }
172 
173 double Rate::getAwakeTime() const
174 {
175  if (numTimeSteps_ == 0)
176  {
177  return std::numeric_limits<double>::quiet_NaN();
178  }
179  else
180  {
181  return awakeTime_;
182  }
183 }
184 
186 {
187  if (numTimeSteps_ == 0)
188  {
189  return std::numeric_limits<double>::quiet_NaN();
190  }
191  else
192  {
193  return awakeTimeMean_;
194  }
195 }
196 
197 double Rate::getAwakeTimeVar() const
198 {
199  if (numTimeSteps_ <= 1)
200  {
201  return std::numeric_limits<double>::quiet_NaN();
202  }
203  else
204  {
205  return awakeTimeM2_ / (numTimeSteps_ - 1);
206  }
207 }
208 
210 {
211  return std::sqrt(getAwakeTimeVar());
212 }
213 
214 double Rate::getDuration(const timespec& start, const timespec& end)
215 { // NOLINT(readability-identifier-naming)
216  return (end.tv_sec - start.tv_sec) + (end.tv_nsec - start.tv_nsec) * SEC_PER_N_SEC;
217 }
218 
219 void Rate::addDuration(timespec& time, const double duration)
220 { // NOLINT(readability-identifier-naming)
221  time.tv_nsec += static_cast<long int>(duration * N_SEC_PER_SEC);
222  time.tv_sec += time.tv_nsec / N_SEC_PER_SEC;
223  time.tv_nsec = time.tv_nsec % N_SEC_PER_SEC;
224 }
225 
226 } // namespace bota_worker
double getAwakeTimeMean() const
Definition: Rate.cpp:185
static void addDuration(timespec &time, const double duration)
Definition: Rate.cpp:219
unsigned int numWarnings_
Counter storing how many times a time step took longer than the warning threshold.
Definition: Rate.hpp:100
timespec stepTime_
Definition: Rate.hpp:96
double getAwakeTime() const
Definition: Rate.cpp:173
double awakeTime_
Most recent time which elapsed between subsequent calls of sleep().
Definition: Rate.hpp:108
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
unsigned int numTimeSteps_
Counter storing how many times sleep has been called.
Definition: Rate.hpp:98
static constexpr long int N_SEC_PER_SEC
Factor storing nanoseconds per seconds.
Definition: Rate.hpp:83
std::atomic< double > timeStep_
Time step in seconds.
Definition: RateOptions.hpp:59
Rate(const std::string &name, const double timeStep)
Definition: Rate.cpp:48
#define ROS_WARN_STREAM(args)
RateOptions options_
Rate options.
Definition: Rate.hpp:88
timespec lastErrorPrintTime_
Point in time when the last error message was printed.
Definition: Rate.hpp:106
timespec lastWarningPrintTime_
Point in time when the last warning message was printed.
Definition: Rate.hpp:104
std::atomic< bool > enforceRate_
Boolean indicating whether the rate should be enforced.
Definition: RateOptions.hpp:65
double awakeTimeMean_
Mean of the time which elapsed between subsequent calls of sleep().
Definition: Rate.hpp:110
double getAwakeTimeVar() const
Definition: Rate.cpp:197
double awakeTimeM2_
Helper variable to compute the variance of the time step which elapsed between subsequent calls of sl...
Definition: Rate.hpp:112
timespec sleepStartTime_
Point in time when the most recent sleep() started.
Definition: Rate.hpp:91
unsigned int numErrors_
Counter storing how many times a time step took longer than the error threshold, not considering warn...
Definition: Rate.hpp:102
timespec sleepEndTime_
Point in time when the most recent sleep() ended.
Definition: Rate.hpp:93
std::string name_
Name for printing.
Definition: RateOptions.hpp:57
#define ROS_ERROR_STREAM(args)
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
static constexpr double SEC_PER_N_SEC
Factor storing seconds per nanoseconds.
Definition: Rate.hpp:85
void reset()
Definition: Rate.cpp:74


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