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 <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 


rtt
Author(s): RTT Developers
autogenerated on Mon Oct 6 2014 03:13:54