ts_PeriodicThread.cpp
Go to the documentation of this file.
1 // this is for emacs file handling -*- mode: c++; indent-tabs-mode: nil -*-
2 
3 // -- BEGIN LICENSE BLOCK ----------------------------------------------
4 // This file is part of FZIs ic_workspace.
5 //
6 // This program is free software licensed under the LGPL
7 // (GNU LESSER GENERAL PUBLIC LICENSE Version 3).
8 // You can find a copy of this license in LICENSE folder in the top
9 // directory of the source code.
10 //
11 // © Copyright 2016 FZI Forschungszentrum Informatik, Karlsruhe, Germany
12 //
13 // -- END LICENSE BLOCK ------------------------------------------------
14 
15 //----------------------------------------------------------------------
22 //----------------------------------------------------------------------
23 #include <boost/test/unit_test.hpp>
24 #include <icl_core/BaseTypes.h>
26 #include <icl_core/os_lxrt.h>
27 #include <icl_core/TimeSpan.h>
28 #include <icl_core/TimeStamp.h>
30 
31 using icl_core::TimeSpan;
34 
35 BOOST_AUTO_TEST_SUITE(ts_PeriodicThread)
36 
37 const icl_core::TimeSpan cBURN_THREAD_PERIOD(0, 100000000);
38 
39 #ifdef _SYSTEM_LXRT_
43 const double cMAX_DEVIATION_FACTOR = 0.05;
44 const double cMEAN_DEVIATION_FACTOR = 0.02;
45 // Attention: Don't increase this beyond 9 (90% CPU time), because
46 // the test-suite will not terminate otherwise!
47 const size_t cNUMBER_OF_BURN_THREADS = 9;
48 
49 # define RUN_HARD_REALTIME_TESTS
50 
51 #else
52 const icl_core::ThreadPriority cTEST_THREAD_PRIORITY = 19;
53 const icl_core::ThreadPriority cBURN_THREAD_PRIORITY = 8;
54 const icl_core::ThreadPriority cRUN_THREAD_PRIORITY = 18;
55 const double cMAX_DEVIATION_FACTOR = 1;
56 const double cMEAN_DEVIATION_FACTOR = 1;
57 const size_t cNUMBER_OF_BURN_THREADS = 10;
58 #endif
59 
63 {
64 public:
65  PeriodicTestThread(const TimeSpan& period, size_t runs)
66  : PeriodicThread("Test Thread", period, cTEST_THREAD_PRIORITY),
67  m_has_run(false),
68  m_runs(runs)
69  { }
70  virtual ~PeriodicTestThread() {}
71 
72  virtual void run()
73  {
74  m_has_run = true;
75 
76  // Wait for the first period so that the timing is in sync.
77  waitPeriod();
78 
79  TimeStamp last_run = TimeStamp::now();
80  for (size_t run = 0; run < m_runs; ++run)
81  {
82  waitPeriod();
83 
84  TimeStamp now = TimeStamp::now();
85  TimeSpan deviation = abs(now - last_run - period());
86  if (deviation > m_max_deviation)
87  {
88  m_max_deviation = deviation;
89  }
90  m_accumulated_deviation += deviation;
91 
92  last_run = now;
93  }
94  }
95 
96  bool hasRun() const { return m_has_run; }
100 
101 private:
102  bool m_has_run;
103  size_t m_runs;
106 };
107 
111  virtual protected icl_core::Noncopyable
112 {
113 public:
114  BurnThread(size_t num)
115  : PeriodicThread("Burn Thread", cBURN_THREAD_PERIOD, cBURN_THREAD_PRIORITY),
116  m_num(num)
117  { }
118 
119  virtual ~BurnThread()
120  { }
121 
122  virtual void run()
123  {
124  while (execute())
125  {
126  waitPeriod();
127 
129 
130  // Burn 10% CPU time.
131  icl_core::TimeStamp burn_until = now + cBURN_THREAD_PERIOD * 0.1;
132  while (icl_core::TimeStamp::now() < burn_until)
133  {
134  // Just do nothing ;-)
135  }
136  }
137  }
138 
139 private:
140  size_t m_num;
141 };
142 
143 void runPeriodicThread(const TimeSpan& period, size_t runs,
144  const TimeSpan& max_deviation, const TimeSpan& mean_deviation,
145  bool burn = false)
146 {
147  PeriodicTestThread test_thread(period, runs);
148  BurnThread *burn_threads[cNUMBER_OF_BURN_THREADS];
149  memset(burn_threads, 0, sizeof(burn_threads));
150  if (burn)
151  {
152  for (size_t i = 0; i < cNUMBER_OF_BURN_THREADS; ++i)
153  {
154  burn_threads[i] = new BurnThread(i);
155  }
156  }
157 
158  BOOST_CHECK(!test_thread.hasRun());
159 
160  test_thread.start();
161  test_thread.stop();
162 
163  if (burn)
164  {
165  for (size_t i = 0; i < cNUMBER_OF_BURN_THREADS; ++i)
166  {
167  burn_threads[i]->start();
168  }
169  }
170 
171  test_thread.join();
172 
173  if (burn)
174  {
175  for (size_t i = 0; i < cNUMBER_OF_BURN_THREADS; ++i)
176  {
177  burn_threads[i]->stop();
178  burn_threads[i]->join();
179  delete burn_threads[i];
180  burn_threads[i] = NULL;
181  }
182  }
183 
184  BOOST_REQUIRE(test_thread.hasRun());
185  BOOST_MESSAGE("max deviation=" << test_thread.maxDeviation().toNSec() << "ns" <<
186  ", accumulated deviation=" << test_thread.accumulatedDeviation().toNSec() << "ns" <<
187  ", mean deviation=" << test_thread.meanDeviation().toNSec() << "ns");
188  BOOST_CHECK(test_thread.maxDeviation() < max_deviation);
189  BOOST_CHECK(test_thread.meanDeviation() < mean_deviation);
190 }
191 
192 BOOST_AUTO_TEST_CASE(RunPeriodicThread_1s)
193 {
194  TimeSpan period(1, 0);
195  runPeriodicThread(period, 10, period * cMAX_DEVIATION_FACTOR, period * cMEAN_DEVIATION_FACTOR);
196 }
197 
198 BOOST_AUTO_TEST_CASE(RunPeriodicThread_100ms)
199 {
200  TimeSpan period(0, 100000000);
201  runPeriodicThread(period, 100, period * cMAX_DEVIATION_FACTOR, period * cMEAN_DEVIATION_FACTOR);
202 }
203 
204 #ifdef RUN_HARD_REALTIME_TESTS
205 
206 BOOST_AUTO_TEST_CASE(RunPeriodicThread_10ms)
207 {
208  TimeSpan period(0, 10000000);
209  runPeriodicThread(period, 1000, period * cMAX_DEVIATION_FACTOR, period * cMEAN_DEVIATION_FACTOR);
210 }
211 
212 BOOST_AUTO_TEST_CASE(RunPeriodicThread_1ms)
213 {
214  TimeSpan period(0, 1000000);
215  runPeriodicThread(period, 10000, period * cMAX_DEVIATION_FACTOR, period * cMEAN_DEVIATION_FACTOR);
216 }
217 
218 BOOST_AUTO_TEST_CASE(BurnPeriodicThread_1s)
219 {
220  TimeSpan period(1, 0);
221  runPeriodicThread(period, 10, period * cMAX_DEVIATION_FACTOR, period * cMEAN_DEVIATION_FACTOR, true);
222 }
223 
224 BOOST_AUTO_TEST_CASE(BurnPeriodicThread_100ms)
225 {
226  TimeSpan period(0, 100000000);
227  runPeriodicThread(period, 100, period * cMAX_DEVIATION_FACTOR, period * cMEAN_DEVIATION_FACTOR, true);
228 }
229 
230 BOOST_AUTO_TEST_CASE(BurnPeriodicThread_10ms)
231 {
232  TimeSpan period(0, 10000000);
233  runPeriodicThread(period, 1000, period * cMAX_DEVIATION_FACTOR, period * cMEAN_DEVIATION_FACTOR, true);
234 }
235 
236 BOOST_AUTO_TEST_CASE(BurnPeriodicThread_1ms)
237 {
238  TimeSpan period(0, 1000000);
239  runPeriodicThread(period, 10000, period * cMAX_DEVIATION_FACTOR, period * cMEAN_DEVIATION_FACTOR, true);
240 }
241 
242 #endif
243 
244 BOOST_AUTO_TEST_SUITE_END()
BOOST_AUTO_TEST_CASE(RunPeriodicThread_1s)
Represents absolute times.
Definition: TimeStamp.h:61
static TimeStamp now()
Definition: TimeStamp.cpp:111
TimeSpan abs(const TimeSpan &span)
Definition: TimeSpan.h:222
BurnThread(size_t num)
const double cMAX_DEVIATION_FACTOR
const size_t cNUMBER_OF_BURN_THREADS
Contains a system independet PRINTF macro.
Contains icl_core::thread::PeriodicThread.
TimeSpan meanDeviation() const
int64_t toNSec() const
Definition: TimeSpan.cpp:173
const icl_core::TimeSpan cBURN_THREAD_PERIOD(0, 100000000)
void runPeriodicThread(const TimeSpan &period, size_t runs, const TimeSpan &max_deviation, const TimeSpan &mean_deviation, bool burn=false)
Contains global LXRT functions.
Repesents absolute times.
Definition: TimeSpan.h:46
TimeSpan accumulatedDeviation() const
virtual void run()
Contains Interface base classes and base types.
void * memset(void *dest, int c, size_t count)
Definition: os_mem.h:46
const icl_core::ThreadPriority cRUN_THREAD_PRIORITY
PeriodicTestThread(const TimeSpan &period, size_t runs)
icl_core::TimeSpan period() const
virtual ~BurnThread()
Contains TimeStamp.
const double cMEAN_DEVIATION_FACTOR
int32_t ThreadPriority
Definition: os_thread.h:50
const icl_core::ThreadPriority cBURN_THREAD_PRIORITY
TimeSpan maxDeviation() const
const icl_core::ThreadPriority cTEST_THREAD_PRIORITY


fzi_icl_core
Author(s):
autogenerated on Mon Jun 10 2019 13:17:58