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


rtt
Author(s): RTT Developers
autogenerated on Thu Jan 2 2014 11:35:40