$search
00001 /*************************************************************************** 00002 tag: Peter Soetens Mon Jan 10 15:59:49 CET 2005 tasks_test.cpp 00003 00004 tasks_test.cpp - description 00005 ------------------- 00006 begin : Mon January 10 2005 00007 copyright : (C) 2005 Peter Soetens 00008 email : peter.soetens@mech.kuleuven.ac.be 00009 00010 *************************************************************************** 00011 * * 00012 * This program is free software; you can redistribute it and/or modify * 00013 * it under the terms of the GNU General Public License as published by * 00014 * the Free Software Foundation; either version 2 of the License, or * 00015 * (at your option) any later version. * 00016 * * 00017 ***************************************************************************/ 00018 00019 00020 #include "unit.hpp" 00021 00022 #include "tasks_test.hpp" 00023 00024 #include <iostream> 00025 00026 #include <extras/PeriodicActivity.hpp> 00027 #include <os/TimeService.hpp> 00028 #include <Logger.hpp> 00029 00030 #include <boost/scoped_ptr.hpp> 00031 00032 using namespace std; 00033 using namespace boost; 00034 using namespace RTT; 00035 using namespace RTT::detail; 00036 00037 #define BOOST_CHECK_EQUAL_MESSAGE(M, v1, v2) BOOST_CHECK_MESSAGE( v1==v2, M) 00038 00039 struct TestOverrun 00040 : public RunnableInterface 00041 { 00042 bool fini; 00043 bool initialize() { fini = false; return true; } 00044 00045 void step() { 00046 //requires that getPeriod() << 1 00047 usleep(200*1000); 00048 // Tried to implement it like this for Xenomai, but the 00049 // underlying rt_task_sleep function always returns immediately 00050 // and returns zero (success). A plain usleep still works. 00051 #if 0 00052 TIME_SPEC timevl; 00053 timevl = ticks2timespec( nano2ticks(200*1000*1000) ); 00054 rtos_nanosleep( &timevl, 0); 00055 #endif 00056 } 00057 00058 void finalize() { 00059 fini = true; 00060 } 00061 }; 00062 00063 struct TestPeriodic 00064 : public RunnableInterface 00065 { 00066 int overfail, underfail, succ; 00067 bool stepped; 00068 00069 TimeService::ticks ts; 00070 // LINUX: cpu of last step(), 0 if not yet set 00071 // non-LINUX: 0 00072 int cpu; 00073 00074 TestPeriodic() 00075 : overfail(0), underfail(0), succ(0), stepped(false), cpu(0) 00076 { 00077 } 00078 00079 bool initialize() { 00080 this->reset(); 00081 return true; 00082 } 00083 void step() { 00084 if (stepped == false ) { 00085 ts = TimeService::Instance()->getTicks(); 00086 stepped = true; 00087 } else { 00088 TimeService::Seconds s = TimeService::Instance()->secondsSince( ts ); 00089 if ( s < this->getThread()->getPeriod() *0.9 ) { // if elapsed time is smaller than 10% of period, something went wrong 00090 ++underfail; 00091 //rtos_printf("UnderFailPeriod: %f \n", s); 00092 } 00093 else if ( s > this->getThread()->getPeriod() *1.1 ) { // if elapsed time is smaller than 10% of period, something went wrong 00094 ++overfail; 00095 //rtos_printf("OverFailPeriod: %f \n", s); 00096 } 00097 else { 00098 ++succ; 00099 //rtos_printf("SuccPeriod: %f \n", s); 00100 } 00101 ts = TimeService::Instance()->getTicks(); 00102 } 00103 #if defined( OROCOS_TARGET_GNULINUX ) 00104 cpu = sched_getcpu(); 00105 BOOST_REQUIRE_NE(ENOSYS, cpu); 00106 #endif 00107 } 00108 void finalize() { 00109 if (overfail || underfail) 00110 cerr <<"overfail is:"<<overfail<<", underfail is:"<<underfail<< " success is: "<<succ<<endl; 00111 } 00112 00113 void reset() { 00114 overfail = 0; 00115 underfail = 0; 00116 succ = 0; 00117 cpu = 0; 00118 stepped = false; 00119 } 00120 }; 00121 00122 struct TestRunnableInterface 00123 : public RunnableInterface 00124 { 00125 bool result, breakl; 00126 bool init, stepped, looped, fini; 00127 00128 TestRunnableInterface(bool res) 00129 { 00130 this->reset(res); 00131 } 00132 00133 bool initialize() { 00134 init = true; 00135 return result; 00136 } 00137 void step() { 00138 stepped = true; 00139 } 00140 void finalize() { 00141 fini = true; 00142 } 00143 00144 void loop() { 00145 looped = true; 00146 while (breakl == false) { 00147 usleep(500*1000); 00148 } 00149 } 00150 00151 bool breakLoop() { 00152 return breakl; 00153 } 00154 00155 void reset(bool res) { 00156 result = res; 00157 init = false; 00158 stepped = false; 00159 fini = false; 00160 looped = false; 00161 breakl = true; 00162 } 00163 }; 00164 00165 struct TestAllocate 00166 : public RunnableInterface 00167 { 00168 std::vector<std::string> v; 00169 char* c; 00170 std::string s; 00171 00172 bool initialize() { 00173 c = 0; 00174 return true; 00175 } 00176 void step() { 00177 v.resize( 0 ); 00178 v.resize( 1025, std::string("Goodbye Memory") ); 00179 delete[] c; 00180 c = new char[1025]; 00181 s = "Hello World "; 00182 s += s; 00183 s += s; 00184 } 00185 void finalize() { 00186 delete[] c; 00187 v.resize(0); 00188 } 00189 }; 00190 00194 struct TestSelfRemove 00195 : public RunnableInterface 00196 { 00197 int c; 00198 bool fini; 00199 bool breakl; 00200 bool initialize() { 00201 c = 0; 00202 fini = false; 00203 breakl = true; 00204 return true; 00205 } 00206 bool breakLoop() { 00207 return breakl; 00208 } 00209 void loop() { 00210 this->getActivity()->stop(); 00211 } 00212 void step() { 00213 ++c; 00214 if (c == 5) 00215 this->getActivity()->stop(); 00216 } 00217 void finalize() { 00218 fini = true; 00219 } 00220 }; 00221 00222 void 00223 ActivitiesTest::setUp() 00224 { 00225 periodic_act = new PeriodicActivity( 15, 0.01 ); 00226 t_act = new Activity(15, 0.01); 00227 00228 t_run_int_prio = new TestRunnableInterface(true); 00229 t_run_int_act = new TestRunnableInterface(true); 00230 t_run_int_fail = new TestRunnableInterface(false); 00231 00232 t_run_allocate = new TestAllocate(); 00233 t_self_remove = new TestSelfRemove(); 00234 00235 t_run_allocate_act = new TestAllocate(); 00236 } 00237 00238 00239 void 00240 ActivitiesTest::tearDown() 00241 { 00242 delete periodic_act; 00243 delete t_act; 00244 00245 delete t_run_int_prio; 00246 delete t_run_int_act; 00247 delete t_run_int_fail; 00248 00249 delete t_run_allocate; 00250 delete t_run_allocate_act; 00251 00252 delete t_self_remove; 00253 } 00254 00255 BOOST_FIXTURE_TEST_SUITE( ActivitiesTestSuite, ActivitiesTest ) 00256 00257 BOOST_AUTO_TEST_CASE( testFailInit ) 00258 { 00259 periodic_act->run( t_run_int_fail ); 00260 00261 BOOST_CHECK( !periodic_act->start() ); 00262 BOOST_CHECK( !periodic_act->stop() ); 00263 00264 BOOST_CHECK( t_act->run( t_run_int_fail ) ); 00265 t_run_int_fail->reset(false); 00266 00267 BOOST_CHECK( !t_act->start() ); 00268 BOOST_CHECK( !t_act->stop() ); 00269 00270 } 00271 00272 #if !defined( OROCOS_TARGET_WIN32 ) && !defined(OROCOS_TARGET_LXRT) 00273 BOOST_AUTO_TEST_CASE( testOverrun ) 00274 { 00275 bool r = false; 00276 // create 00277 boost::scoped_ptr<TestOverrun> run( new TestOverrun() ); 00278 boost::scoped_ptr<Activity> t( new Activity(25, 0.1, 0,"ORThread") ); 00279 //BOOST_CHECK_EQUAL(25,t->getPriority() ); 00280 BOOST_CHECK_EQUAL(0.1,t->getPeriod() ); 00281 t->thread()->setMaxOverrun(1); 00282 00283 t->run( run.get() ); 00284 00285 // prints annoying warning messages... 00286 Logger::LogLevel ll = Logger::log().getLogLevel(); 00287 Logger::log().setLogLevel(Logger::Never); 00288 00289 t->start(); 00290 // In Xenomai (2.5), the first usleep returns immediately. 00291 // We can 'fix' this by adding a log() statement before usleep() .... crap 00292 usleep(100*1000); 00293 usleep(400*1000); 00294 Logger::log().setLogLevel(ll); 00295 00296 r = !t->isRunning(); 00297 00298 t->run(0); 00299 00300 BOOST_REQUIRE_MESSAGE( r, "Failed to detect step overrun in Thread"); 00301 00302 BOOST_CHECK_MESSAGE( run->fini, "Failed to execute finalize in emergencyStop" ); 00303 00304 } 00305 #endif 00306 00307 BOOST_AUTO_TEST_CASE( testThread ) 00308 { 00309 bool r = false; 00310 // create 00311 boost::scoped_ptr<TestPeriodic> run( new TestPeriodic() ); 00312 00313 boost::scoped_ptr<ActivityInterface> t( new Activity(ORO_SCHED_RT, os::HighestPriority, 0.1, 0, "PThread") ); 00314 t->run( run.get() ); 00315 00316 r = t->start(); 00317 BOOST_CHECK_MESSAGE( r, "Failed to start Thread"); 00318 usleep(1000*100); 00319 r = t->stop(); 00320 BOOST_CHECK_MESSAGE( r, "Failed to stop Thread" ); 00321 BOOST_CHECK_MESSAGE( run->stepped == true, "Step not executed" ); 00322 BOOST_CHECK_EQUAL_MESSAGE("Periodic Failure: period of step() too long !", run->overfail, 0); 00323 BOOST_CHECK_EQUAL_MESSAGE("Periodic Failure: period of step() too short!", run->underfail, 0); 00324 t->run(0); 00325 } 00326 00327 #if defined( OROCOS_TARGET_GNULINUX ) 00328 // run on just the target CPU 00329 void testAffinity2(boost::scoped_ptr<TestPeriodic>& run, 00330 boost::scoped_ptr<Activity>& t, 00331 int targetCPU) 00332 { 00333 bool r = false; 00334 00335 t->run( run.get() ); 00336 00337 BOOST_CHECK(t->setCpuAffinity(1 << targetCPU)); 00338 BOOST_CHECK_EQUAL((1 << targetCPU), t->getCpuAffinity()); 00339 00340 if ( t->getScheduler() == os::HighestPriority) { 00341 r = t->start(); 00342 BOOST_CHECK_MESSAGE( r, "Failed to start Thread"); 00343 r = t->stop(); 00344 BOOST_CHECK_MESSAGE( r, "Failed to stop Thread"); 00345 BOOST_CHECK_MESSAGE( run->stepped == true, "Step not executed" ); 00346 BOOST_CHECK_EQUAL(targetCPU, run->cpu); 00347 BOOST_CHECK_LT(0, run->succ); 00348 run->reset(); 00349 } 00350 BOOST_CHECK_EQUAL(0, run->cpu); 00351 r = t->start(); 00352 BOOST_CHECK_MESSAGE( r, "Failed to start Thread"); 00353 sleep(1); 00354 r = t->stop(); 00355 BOOST_CHECK_MESSAGE( r, "Failed to stop Thread" ); 00356 BOOST_CHECK_MESSAGE( run->stepped == true, "Step not executed" ); 00357 BOOST_CHECK_EQUAL(targetCPU, run->cpu); 00358 BOOST_CHECK_LT(0, run->succ); 00359 00360 t->run(0); 00361 } 00362 00363 BOOST_AUTO_TEST_CASE( testAffinity ) 00364 { 00365 // this test is kind of irrelevant with only 1 CPU 00366 int numCPU = sysconf( _SC_NPROCESSORS_ONLN ); 00367 if (1 < numCPU) 00368 { 00369 boost::scoped_ptr<TestPeriodic> run( new TestPeriodic() ); 00370 boost::scoped_ptr<Activity> t( new Activity(ORO_SCHED_RT, os::HighestPriority, 0.1, ~0, 0, "PThread") ); 00371 // returned affinity depends on the number of actual CPUs, and won't be "~0" 00372 unsigned mask=0; 00373 for (int i=0; i<numCPU; ++i) 00374 { 00375 mask |= (1 << i); 00376 } 00377 BOOST_CHECK_EQUAL(mask, t->getCpuAffinity()); 00378 00379 // test just a couple of cases 00380 testAffinity2(run, t, 0); 00381 testAffinity2(run, t, numCPU-1); 00382 } 00383 // else ignore test as insufficient number of CPUs 00384 } 00385 00386 #endif 00387 00388 BOOST_AUTO_TEST_CASE( testNonPeriodic ) 00389 { 00390 scoped_ptr<TestRunnableInterface> t_run_int_nonper 00391 ( new TestRunnableInterface(true) ); 00392 // force ordering of scoped_ptr destruction. 00393 { 00394 scoped_ptr<Activity> t_task_nonper 00395 ( new Activity( 14 ) ); 00396 00397 BOOST_CHECK( t_task_nonper->run( t_run_int_nonper.get() ) ); 00398 BOOST_CHECK( t_task_nonper->start() ); 00399 testPause(); 00400 BOOST_CHECK( t_run_int_nonper->looped ); 00401 BOOST_CHECK( !t_run_int_nonper->stepped ); 00402 BOOST_CHECK( t_run_int_nonper->init ); 00403 BOOST_CHECK( t_task_nonper->stop() ); 00404 BOOST_CHECK( t_run_int_nonper->fini ); 00405 BOOST_CHECK( !t_task_nonper->isRunning() ); 00406 BOOST_CHECK( t_task_nonper->run( 0 ) ); 00407 BOOST_CHECK( t_task_nonper->start() ); 00408 BOOST_CHECK( t_task_nonper->stop() ); 00409 // stop() should be fully synchronising... 00410 BOOST_CHECK( !t_task_nonper->isRunning() ); 00411 } 00412 } 00413 00414 BOOST_AUTO_TEST_CASE( testActivityNP ) 00415 { 00416 scoped_ptr<TestRunnableInterface> t_run_int_nonper 00417 ( new TestRunnableInterface(true) ); 00418 // force ordering of scoped_ptr destruction. 00419 { 00420 scoped_ptr<Activity> t_task_nonper 00421 ( new Activity(15) ); 00422 00423 BOOST_CHECK( t_task_nonper->run( t_run_int_nonper.get() ) ); 00424 BOOST_CHECK( t_task_nonper->start() ); 00425 testPause(); 00426 sleep(1); 00427 BOOST_CHECK( t_run_int_nonper->looped ); 00428 BOOST_CHECK( t_run_int_nonper->init ); 00429 BOOST_CHECK( t_task_nonper->stop() ); 00430 BOOST_CHECK( t_run_int_nonper->fini ); 00431 BOOST_CHECK( !t_task_nonper->isRunning() ); 00432 BOOST_CHECK( t_task_nonper->run( 0 ) ); 00433 BOOST_CHECK( t_task_nonper->start() ); 00434 BOOST_CHECK( t_task_nonper->stop() ); 00435 // stop() should be fully synchronising... 00436 BOOST_CHECK( !t_task_nonper->isRunning() ); 00437 } 00438 } 00439 00440 BOOST_AUTO_TEST_CASE( testActivityBreakLoop ) 00441 { 00442 scoped_ptr<TestRunnableInterface> t_run_int_nonper 00443 ( new TestRunnableInterface(true) ); 00444 // force ordering of scoped_ptr destruction. 00445 { 00446 scoped_ptr<Activity> t_task_nonper 00447 ( new Activity(15) ); 00448 00449 BOOST_CHECK( t_task_nonper->run( t_run_int_nonper.get() ) ); 00450 BOOST_CHECK( t_task_nonper->start() ); 00451 testPause(); 00452 00453 t_run_int_nonper->breakl = false; 00454 BOOST_CHECK( t_task_nonper->start() ); 00455 testPause(); 00456 BOOST_CHECK( t_task_nonper->stop() == false ); 00457 00458 t_run_int_nonper->breakl = true; 00459 BOOST_CHECK( t_task_nonper->stop() ); 00460 BOOST_CHECK( t_run_int_nonper->fini ); 00461 BOOST_CHECK( !t_task_nonper->isRunning() ); 00462 } 00463 } 00464 00465 BOOST_AUTO_TEST_CASE( testSelfRemove ) 00466 { 00467 scoped_ptr<TestSelfRemove> t_run_int_nonper 00468 ( new TestSelfRemove() ); 00469 scoped_ptr<Activity> t_task_nonper 00470 ( new Activity( 14 ) ); 00471 BOOST_CHECK( t_task_nonper->run( t_run_int_nonper.get() ) ); 00472 BOOST_CHECK( t_task_nonper->start() ); 00473 BOOST_CHECK( periodic_act->run(t_self_remove) ); 00474 BOOST_CHECK( periodic_act->start() ); 00475 testPause(); 00476 BOOST_CHECK( !periodic_act->isRunning() ); 00477 BOOST_CHECK( t_self_remove->fini ); 00478 BOOST_CHECK( !t_task_nonper->isRunning() ); 00479 BOOST_CHECK( t_run_int_nonper->fini ); 00480 } 00481 00482 BOOST_AUTO_TEST_CASE( testActivityNPSelfRemove ) 00483 { 00484 scoped_ptr<TestSelfRemove> t_run_int_nonper 00485 ( new TestSelfRemove() ); 00486 scoped_ptr<Activity> t_task_nonper 00487 ( new Activity( 14 ) ); 00488 BOOST_CHECK( t_task_nonper->run( t_run_int_nonper.get() ) ); 00489 BOOST_CHECK( t_task_nonper->start() ); 00490 testPause(); 00491 BOOST_CHECK( !t_task_nonper->isRunning() ); 00492 BOOST_CHECK( t_run_int_nonper->fini ); 00493 } 00494 00495 BOOST_AUTO_TEST_CASE( testActivityPSelfRemove ) 00496 { 00497 scoped_ptr<TestSelfRemove> t_run_int_per 00498 ( new TestSelfRemove() ); 00499 scoped_ptr<Activity> t_task_per 00500 ( new Activity( 14, 0.01 ) ); 00501 BOOST_CHECK( t_task_per->run( t_run_int_per.get() ) ); 00502 BOOST_CHECK( t_task_per->start() ); 00503 testPause(); 00504 BOOST_CHECK( !t_task_per->isRunning() ); 00505 BOOST_CHECK( t_run_int_per->fini ); 00506 } 00507 00508 00509 BOOST_AUTO_TEST_CASE( testStartStop ) 00510 { 00511 testStart(); 00512 testPause(); 00513 testStop(); 00514 } 00515 00516 BOOST_AUTO_TEST_CASE( testRunnableInterface ) 00517 { 00518 testAddRunnableInterface(); 00519 testStart(); 00520 testRunnableInterfaceInit(); 00521 testPause(); 00522 testRunnableInterfaceExecution(); 00523 testStop(); 00524 testRemoveRunnableInterface(); 00525 } 00526 00527 BOOST_AUTO_TEST_CASE( testAllocation ) 00528 { 00529 testAddAllocate(); 00530 testStart(); 00531 testPause(); 00532 testStop(); 00533 testRemoveAllocate(); 00534 } 00535 00536 BOOST_AUTO_TEST_SUITE_END() 00537 00538 void ActivitiesTest::testAddRunnableInterface() 00539 { 00540 bool adding_prio = periodic_act->run( t_run_int_prio ); 00541 BOOST_CHECK( adding_prio ); 00542 00543 bool adding_act = t_act->run( t_run_int_act ); 00544 BOOST_CHECK( adding_act ); 00545 } 00546 00547 void ActivitiesTest::testRemoveRunnableInterface() 00548 { 00549 BOOST_CHECK( t_run_int_prio->fini ); 00550 BOOST_CHECK( periodic_act->run( 0 ) ); 00551 00552 BOOST_CHECK( t_run_int_act->fini ); 00553 BOOST_CHECK( t_act->run( 0 ) ); 00554 } 00555 00556 void ActivitiesTest::testStart() 00557 { 00558 BOOST_CHECK( periodic_act->start()); 00559 BOOST_CHECK( periodic_act->isRunning() ); 00560 00561 BOOST_CHECK( t_act->start()); 00562 BOOST_CHECK( t_act->isRunning() ); 00563 } 00564 00565 void ActivitiesTest::testPause() 00566 { 00567 #if 0 00568 // does not work on Xenomai: 00569 int rv = 0; 00570 BOOST_CHECK( (rv = usleep(100000)) == 0); 00571 if ( rv != 0) 00572 BOOST_CHECK_EQUAL_MESSAGE(errno, 0, "Sleep failed. Errno is not zero."); 00573 #else 00574 TIME_SPEC t; 00575 t.tv_sec = 1; 00576 t.tv_nsec = 0; 00577 BOOST_CHECK( rtos_nanosleep(&t,0) == 0); 00578 #endif 00579 } 00580 00581 void ActivitiesTest::testRunnableInterfaceInit() { 00582 BOOST_CHECK( t_run_int_prio->init ); 00583 BOOST_CHECK( t_run_int_act->init ); 00584 } 00585 00586 void ActivitiesTest::testRunnableInterfaceExecution() { 00587 00588 BOOST_CHECK( t_run_int_prio->stepped ); 00589 BOOST_CHECK( t_run_int_act->stepped ); 00590 } 00591 00592 void ActivitiesTest::testStop() 00593 { 00594 BOOST_CHECK( periodic_act->stop()); 00595 BOOST_CHECK( !periodic_act->isRunning() ); 00596 00597 BOOST_CHECK( t_act->stop()); 00598 BOOST_CHECK( !t_act->isRunning() ); 00599 } 00600 00601 void ActivitiesTest::testAddAllocate() 00602 { 00603 BOOST_CHECK( periodic_act->run( t_run_allocate ) ); 00604 00605 BOOST_CHECK( t_act->run( t_run_allocate_act ) ); 00606 } 00607 00608 void ActivitiesTest::testRemoveAllocate() 00609 { 00610 BOOST_CHECK( periodic_act->run( 0 ) ); 00611 00612 BOOST_CHECK( t_act->run( 0 ) ); 00613 } 00614