00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
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
00046
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
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
00131 icl_core::TimeStamp burn_until = now + cBURN_THREAD_PERIOD * 0.1;
00132 while (icl_core::TimeStamp::now() < burn_until)
00133 {
00134
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()