ts_PeriodicThread.cpp
Go to the documentation of this file.
00001 // this is for emacs file handling -*- mode: c++; indent-tabs-mode: nil -*-
00002 
00003 // -- BEGIN LICENSE BLOCK ----------------------------------------------
00004 // This file is part of FZIs ic_workspace.
00005 //
00006 // This program is free software licensed under the LGPL
00007 // (GNU LESSER GENERAL PUBLIC LICENSE Version 3).
00008 // You can find a copy of this license in LICENSE folder in the top
00009 // directory of the source code.
00010 //
00011 // © Copyright 2016 FZI Forschungszentrum Informatik, Karlsruhe, Germany
00012 //
00013 // -- END LICENSE BLOCK ------------------------------------------------
00014 
00015 //----------------------------------------------------------------------
00022 //----------------------------------------------------------------------
00023 #include <boost/test/unit_test.hpp>
00024 #include <icl_core/BaseTypes.h>
00025 #include <icl_core/internal_raw_debug.h>
00026 #include <icl_core/os_lxrt.h>
00027 #include <icl_core/TimeSpan.h>
00028 #include <icl_core/TimeStamp.h>
00029 #include <icl_core_thread/PeriodicThread.h>
00030 
00031 using icl_core::TimeSpan;
00032 using icl_core::TimeStamp;
00033 using icl_core::thread::PeriodicThread;
00034 
00035 BOOST_AUTO_TEST_SUITE(ts_PeriodicThread)
00036 
00037 const icl_core::TimeSpan cBURN_THREAD_PERIOD(0, 100000000);
00038 
00039 #ifdef _SYSTEM_LXRT_
00040 const icl_core::ThreadPriority cTEST_THREAD_PRIORITY = -10;
00041 const icl_core::ThreadPriority cBURN_THREAD_PRIORITY = 8;
00042 const icl_core::ThreadPriority cRUN_THREAD_PRIORITY = 19;
00043 const double cMAX_DEVIATION_FACTOR = 0.05;
00044 const double cMEAN_DEVIATION_FACTOR = 0.02;
00045 // Attention: Don't increase this beyond 9 (90% CPU time), because
00046 // the test-suite will not terminate otherwise!
00047 const size_t cNUMBER_OF_BURN_THREADS = 9;
00048 
00049 # define RUN_HARD_REALTIME_TESTS
00050 
00051 #else
00052 const icl_core::ThreadPriority cTEST_THREAD_PRIORITY = 19;
00053 const icl_core::ThreadPriority cBURN_THREAD_PRIORITY = 8;
00054 const icl_core::ThreadPriority cRUN_THREAD_PRIORITY = 18;
00055 const double cMAX_DEVIATION_FACTOR = 1;
00056 const double cMEAN_DEVIATION_FACTOR = 1;
00057 const size_t cNUMBER_OF_BURN_THREADS = 10;
00058 #endif
00059 
00062 class PeriodicTestThread : public PeriodicThread
00063 {
00064 public:
00065   PeriodicTestThread(const TimeSpan& period, size_t runs)
00066     : PeriodicThread("Test Thread", period, cTEST_THREAD_PRIORITY),
00067       m_has_run(false),
00068       m_runs(runs)
00069   { }
00070   virtual ~PeriodicTestThread() {}
00071 
00072   virtual void run()
00073   {
00074     m_has_run = true;
00075 
00076     // Wait for the first period so that the timing is in sync.
00077     waitPeriod();
00078 
00079     TimeStamp last_run = TimeStamp::now();
00080     for (size_t run = 0; run < m_runs; ++run)
00081     {
00082       waitPeriod();
00083 
00084       TimeStamp now = TimeStamp::now();
00085       TimeSpan deviation = abs(now - last_run - period());
00086       if (deviation > m_max_deviation)
00087       {
00088         m_max_deviation = deviation;
00089       }
00090       m_accumulated_deviation += deviation;
00091 
00092       last_run = now;
00093     }
00094   }
00095 
00096   bool hasRun() const { return m_has_run; }
00097   TimeSpan maxDeviation() const { return m_max_deviation; }
00098   TimeSpan accumulatedDeviation() const { return m_accumulated_deviation; }
00099   TimeSpan meanDeviation() const { return m_accumulated_deviation / m_runs; }
00100 
00101 private:
00102   bool m_has_run;
00103   size_t m_runs;
00104   TimeSpan m_max_deviation;
00105   TimeSpan m_accumulated_deviation;
00106 };
00107 
00110 class BurnThread : public icl_core::thread::PeriodicThread,
00111                    virtual protected icl_core::Noncopyable
00112 {
00113 public:
00114   BurnThread(size_t num)
00115     : PeriodicThread("Burn Thread", cBURN_THREAD_PERIOD, cBURN_THREAD_PRIORITY),
00116       m_num(num)
00117   { }
00118 
00119   virtual ~BurnThread()
00120   { }
00121 
00122   virtual void run()
00123   {
00124     while (execute())
00125     {
00126       waitPeriod();
00127 
00128       icl_core::TimeStamp now = icl_core::TimeStamp::now();
00129 
00130       // Burn 10% CPU time.
00131       icl_core::TimeStamp burn_until = now + cBURN_THREAD_PERIOD * 0.1;
00132       while (icl_core::TimeStamp::now() < burn_until)
00133       {
00134         // Just do nothing ;-)
00135       }
00136     }
00137   }
00138 
00139 private:
00140   size_t m_num;
00141 };
00142 
00143 void runPeriodicThread(const TimeSpan& period, size_t runs,
00144                        const TimeSpan& max_deviation, const TimeSpan& mean_deviation,
00145                        bool burn = false)
00146 {
00147   PeriodicTestThread test_thread(period, runs);
00148   BurnThread *burn_threads[cNUMBER_OF_BURN_THREADS];
00149   memset(burn_threads, 0, sizeof(burn_threads));
00150   if (burn)
00151   {
00152     for (size_t i = 0; i < cNUMBER_OF_BURN_THREADS; ++i)
00153     {
00154       burn_threads[i] = new BurnThread(i);
00155     }
00156   }
00157 
00158   BOOST_CHECK(!test_thread.hasRun());
00159 
00160   test_thread.start();
00161   test_thread.stop();
00162 
00163   if (burn)
00164   {
00165     for (size_t i = 0; i < cNUMBER_OF_BURN_THREADS; ++i)
00166     {
00167       burn_threads[i]->start();
00168     }
00169   }
00170 
00171   test_thread.join();
00172 
00173   if (burn)
00174   {
00175     for (size_t i = 0; i < cNUMBER_OF_BURN_THREADS; ++i)
00176     {
00177       burn_threads[i]->stop();
00178       burn_threads[i]->join();
00179       delete burn_threads[i];
00180       burn_threads[i] = NULL;
00181     }
00182   }
00183 
00184   BOOST_REQUIRE(test_thread.hasRun());
00185   BOOST_MESSAGE("max deviation=" << test_thread.maxDeviation().toNSec() << "ns" <<
00186                 ", accumulated deviation=" << test_thread.accumulatedDeviation().toNSec() << "ns" <<
00187                 ", mean deviation=" << test_thread.meanDeviation().toNSec() << "ns");
00188   BOOST_CHECK(test_thread.maxDeviation() < max_deviation);
00189   BOOST_CHECK(test_thread.meanDeviation() < mean_deviation);
00190 }
00191 
00192 BOOST_AUTO_TEST_CASE(RunPeriodicThread_1s)
00193 {
00194   TimeSpan period(1, 0);
00195   runPeriodicThread(period, 10, period * cMAX_DEVIATION_FACTOR, period * cMEAN_DEVIATION_FACTOR);
00196 }
00197 
00198 BOOST_AUTO_TEST_CASE(RunPeriodicThread_100ms)
00199 {
00200   TimeSpan period(0, 100000000);
00201   runPeriodicThread(period, 100, period * cMAX_DEVIATION_FACTOR, period * cMEAN_DEVIATION_FACTOR);
00202 }
00203 
00204 #ifdef RUN_HARD_REALTIME_TESTS
00205 
00206 BOOST_AUTO_TEST_CASE(RunPeriodicThread_10ms)
00207 {
00208   TimeSpan period(0, 10000000);
00209   runPeriodicThread(period, 1000, period * cMAX_DEVIATION_FACTOR, period * cMEAN_DEVIATION_FACTOR);
00210 }
00211 
00212 BOOST_AUTO_TEST_CASE(RunPeriodicThread_1ms)
00213 {
00214   TimeSpan period(0, 1000000);
00215   runPeriodicThread(period, 10000, period * cMAX_DEVIATION_FACTOR, period * cMEAN_DEVIATION_FACTOR);
00216 }
00217 
00218 BOOST_AUTO_TEST_CASE(BurnPeriodicThread_1s)
00219 {
00220   TimeSpan period(1, 0);
00221   runPeriodicThread(period, 10, period * cMAX_DEVIATION_FACTOR, period * cMEAN_DEVIATION_FACTOR, true);
00222 }
00223 
00224 BOOST_AUTO_TEST_CASE(BurnPeriodicThread_100ms)
00225 {
00226   TimeSpan period(0, 100000000);
00227   runPeriodicThread(period, 100, period * cMAX_DEVIATION_FACTOR, period * cMEAN_DEVIATION_FACTOR, true);
00228 }
00229 
00230 BOOST_AUTO_TEST_CASE(BurnPeriodicThread_10ms)
00231 {
00232   TimeSpan period(0, 10000000);
00233   runPeriodicThread(period, 1000, period * cMAX_DEVIATION_FACTOR, period * cMEAN_DEVIATION_FACTOR, true);
00234 }
00235 
00236 BOOST_AUTO_TEST_CASE(BurnPeriodicThread_1ms)
00237 {
00238   TimeSpan period(0, 1000000);
00239   runPeriodicThread(period, 10000, period * cMAX_DEVIATION_FACTOR, period * cMEAN_DEVIATION_FACTOR, true);
00240 }
00241 
00242 #endif
00243 
00244 BOOST_AUTO_TEST_SUITE_END()


fzi_icl_core
Author(s):
autogenerated on Tue Aug 8 2017 02:28:04