TimerThread had too much overhead, trying a different approach with Timer

master
Denes Matetelki 14 years ago
parent 8e1dbfa569
commit 03627c0ed5

@ -10,6 +10,7 @@ if(DOXYGEN_FOUND)
endif(DOXYGEN_FOUND)
add_custom_target(reset
COMMAND rm -rf html

@ -1,8 +1,10 @@
cmake_minimum_required (VERSION 2.6)
project (CPP_UTILS_LIB)
set (CXX_FLAGS "-Wall -Wextra -pedantic -Weffc++ -Wshadow -ggdb -fprofile-arcs -ftest-coverage")
set (CXX_FLAGS "-Wall -Wextra -pedantic -Weffc++ -Wshadow "
"-ggdb -fprofile-arcs -ftest-coverage")
add_definitions( ${CXX_FLAGS} )
# add_definitions( -DNO_TRACE )
include_directories (../include)
aux_source_directory(../src CPP_UTILS_LIB_SOURCES)

@ -57,34 +57,33 @@ private:
#ifdef NO_TRACE
#define MAX_LOFLEVEL Logger::DEBUG
#else
#define MAX_LOFLEVEL Logger::FINEST
#endif
#define TRACE (void)0
#define TRACE_STATIC (void)0
#define LOG (void)0
#else
#define TRACE \
if(MAX_LOFLEVEL >= Logger::FINEST && \
Logger::getInstance()->getLoglevel() >= Logger::FINEST ) \
if ( Logger::getInstance()->getLoglevel() >= Logger::FINEST ) \
Logger::getInstance()->log_pointer( \
this, __FILE__, __LINE__, __PRETTY_FUNCTION__); \
else (void)0
#define TRACE_STATIC \
if(MAX_LOFLEVEL >= Logger::FINEST && \
Logger::getInstance()->getLoglevel() >= Logger::FINEST ) \
if ( Logger::getInstance()->getLoglevel() >= Logger::FINEST ) \
Logger::getInstance()->log_pointer( \
0, __FILE__, __LINE__, __PRETTY_FUNCTION__); \
else (void)0
#define LOG(level, msg) \
if (MAX_LOFLEVEL >= level && \
Logger::getInstance()->getLoglevel() >= Logger::FINEST ) \
if ( Logger::getInstance()->getLoglevel() >= Logger::FINEST ) \
Logger::getInstance()->log_string( \
msg, __FILE__, __LINE__, __PRETTY_FUNCTION__); \
else (void)0
#endif
/// @todo remove this
#define MSG(text) Logger::getInstance()->msg(text)

@ -8,7 +8,7 @@ class Thread
{
public:
Thread( const bool softRealTime = false );
Thread();
virtual ~Thread();
void start();
@ -28,7 +28,7 @@ protected:
private:
pthread_t m_threadHandler;
bool m_softRealTime;
};

@ -0,0 +1,40 @@
#ifndef TIMER_HPP
#define TIMER_HPP
#include <signal.h> // sigset_t
#include <time.h> // timer_t
class Timer
{
public:
Timer(const int signal = SIGALRM );
virtual void timerExpired() {}
virtual void periodicTimerExpired() {}
void createTimer(const time_t interval_sec,
const long interval_nsec = 0,
const time_t initExpr_sec = 0,
const long initExpr_nsec = 0);
void wait();
void stopTimer();
private:
int m_signal;
struct sigaction m_sigAction;
timer_t m_timerId;
bool m_periodic;
bool m_running;
}; // class Timer
#endif // TIMER_HPP

@ -84,6 +84,8 @@ bool TimerThread::removeTimerUser ( void* timerUser )
m_users.erase(tmp);
m_condVar.signal();
found = true; // one user can be registered multiple times
} else {
it++;
}
}
return found;

@ -34,7 +34,7 @@ private:
public:
void testBasic( void )
void nemtestBasic( void )
{
TEST_HEADER;
TimerThread* tt = new TimerThread();
@ -54,7 +54,7 @@ public:
delete user;
}
void testBasicTimeSpec( void )
void nemtestBasicTimeSpec( void )
{
TEST_HEADER;
TimerThread* tt = new TimerThread();
@ -75,7 +75,7 @@ public:
delete user;
}
void testPeriodic( void )
void nemtestPeriodic( void )
{
TEST_HEADER;
TimerThread* tt = new TimerThread();
@ -98,32 +98,36 @@ public:
void testPeriodicTimeSpec( void )
{
TEST_HEADER;
// Logger::getInstance()->setLogLevel(Logger::DEBUG);
TimerThread* tt = new TimerThread();
tt->start();
sleep(1);
DummyTimerUser *user = new DummyTimerUser();
timespec ts = { 2, 3 };
timespec tsperiod = { 1, 2 };
timespec ts = { 2, 0 };
timespec tsperiod = { 1, 0 };
tt->addTimerUser( user, ts, tsperiod );
/// @bug What is wrong here?
// DummyTimerUser *user2 = new DummyTimerUser();
// timespec ts2 = { 0, 100000000 };
// tt->addTimerUser( user2, ts, ts2 );
DummyTimerUser *user2 = new DummyTimerUser();
int perMinute = 2000;
timespec ts2 = { 0, 1000000000 / perMinute };
tt->addTimerUser( user2, ts, ts2 );
sleep(6);
tt->stop();
sleep(1);
TS_ASSERT_EQUALS( user->m_counter, 104 );
// TS_ASSERT_EQUALS( user2->m_counter, 110 );
TS_ASSERT_EQUALS( user->m_counter, 100 + 4 ); // 4 times
TS_ASSERT_EQUALS( user2->m_counter, 100 + perMinute*4 );
delete tt;
delete user;
}
void testDestroyed( void )
void nemtestDestroyed( void )
{
TEST_HEADER;
TimerThread* tt = new TimerThread();
@ -143,7 +147,7 @@ public:
delete user;
}
void testRemoved( void )
void nemtestRemoved( void )
{
TEST_HEADER;
TimerThread* tt = new TimerThread();
@ -151,14 +155,29 @@ public:
sleep(1);
DummyTimerUser *user = new DummyTimerUser();
DummyTimerUser *user2 = new DummyTimerUser();
DummyTimerUser *user3 = new DummyTimerUser();
tt->addTimerUser( user, 10 );
tt->addTimerUser( user2, 13 );
tt->addTimerUser( user3, 15 );
sleep(2);
TS_ASSERT_EQUALS( tt->m_users.size(), 3 );
tt->removeTimerUser( user2 );
sleep(1);
TS_ASSERT_EQUALS( tt->m_users.size(), 2 );
tt->removeTimerUser( user3 );
sleep(1);
TS_ASSERT_EQUALS( tt->m_users.size(), 1 );
tt->removeTimerUser( user2 );
sleep(1);
TS_ASSERT_EQUALS( tt->m_users.size(), 1 );
tt->removeTimerUser( user );
sleep(1);
TS_ASSERT_EQUALS( tt->m_users.size(), 0 );
@ -167,9 +186,11 @@ public:
delete tt;
delete user;
delete user2;
delete user3;
}
void testRemovedMultiple( void )
void nemtestRemovedMultiple( void )
{
TEST_HEADER;
TimerThread* tt = new TimerThread();

@ -8,10 +8,9 @@
#include <sched.h> // sched_param
Thread::Thread(const bool softRealTime)
Thread::Thread()
: m_isRunning(false)
, m_threadHandler( 0 )
, m_softRealTime(softRealTime)
{
TRACE;
}
@ -27,22 +26,8 @@ void Thread::start()
{
TRACE;
m_isRunning = true;
if ( m_softRealTime ) {
pthread_attr_t attr;
sched_param param;
pthread_attr_init(&attr);
pthread_attr_setschedpolicy( &attr, SCHED_RR );
param.sched_priority = 50;
pthread_attr_setschedparam( &attr, &param );
pthread_create( &m_threadHandler, &attr, threadStarter, ( void* )this );
} else {
pthread_create( &m_threadHandler, 0, threadStarter, ( void* )this );
}
}
void* Thread::join() const

@ -0,0 +1,88 @@
#include "Timer.hpp"
#include "Common.hpp"
#include <signal.h> // sigset_t
// #include <assert.h> // assert
#include <time.h> // timer_t
// #include <errno.h> // EINVAL, EAGAIN, EINTR
// #include <set>
#include <string.h> // strerror
// #include <iostream>
// #include <stdio.h>
Timer::Timer(const int signal)
: m_signal(signal)
, m_periodic(false)
, m_running(true)
{
TRACE;
m_sigAction.sa_flags = SA_SIGINFO;
sigemptyset(&m_sigAction.sa_mask);
sigaddset( &m_sigAction.sa_mask, m_signal );
sigaction( m_signal, &m_sigAction, 0 );
}
void Timer::createTimer(const time_t interval_sec,
const long interval_nsec,
const time_t initExpr_sec,
const long initExpr_nsec)
{
TRACE;
// create timer
struct sigevent sigev;
sigev.sigev_notify = SIGEV_SIGNAL;
sigev.sigev_signo = m_signal;
sigev.sigev_value.sival_ptr = &m_timerId;
if ( timer_create( CLOCK_MONOTONIC, &sigev, &m_timerId ) == -1 ) {
// std::cout << "Error from timer_create: " << strerror(errno) << std::endl;
LOG ( Logger::FINEST, "Error from timer_create: " /*strerror(errno)*/ );
return;
}
// arm it
struct itimerspec its;
its.it_value.tv_sec = interval_sec;
its.it_value.tv_nsec = interval_nsec;
its.it_interval.tv_sec = initExpr_sec;
its.it_interval.tv_nsec = initExpr_nsec;
if ( initExpr_sec != 0 or initExpr_nsec != 0 ) m_periodic = true;
if ( timer_settime( m_timerId, 0, &its, 0 ) == -1 ) {
// std::cout << "Error from timer_settime: " << strerror(errno) << std::endl;
LOG ( Logger::FINEST, "Error from timer_settime: " /*strerror(errno)*/ );
return;
}
}
void Timer::wait()
{
TRACE;
int sig;
sigwait( &m_sigAction.sa_mask, &sig );
timerExpired();
if ( m_periodic ) {
while ( m_running ) {
sigwait( &m_sigAction.sa_mask, &sig );
periodicTimerExpired();
}
}
}
void Timer::stopTimer()
{
TRACE;
struct itimerspec its;
its.it_value.tv_sec = 0;
its.it_value.tv_nsec = 0;
timer_settime( m_timerId, 0, &its, 0 );
m_running = false;
}

@ -1,5 +1,9 @@
set (CXX_FLAGS "-Wall -Wextra -pedantic -Weffc++ -Wshadow -ggdb -fprofile-arcs -ftest-coverage")
set (CXX_FLAGS "-Wall -Wextra -pedantic -Weffc++ -Wshadow "
"-ggdb -fprofile-arcs -ftest-coverage " )
add_definitions( ${CXX_FLAGS} )
# add_definitions( -DNO_TRACE )
find_package(CxxTest)
if(CXXTEST_FOUND)
@ -19,7 +23,7 @@ if(CXXTEST_FOUND)
test_Thread.hpp
test_ThreadPool.hpp
test_Semaphore.hpp
test_TimerThread.hpp
test_Timer.hpp
test_Common.hpp
)
target_link_libraries(test CppUtils gcov)

@ -61,6 +61,10 @@ valgrind \
--suppressions=valgrind.supp \
$test | tee $test.out; retval=$PIPESTATUS
# NOTE to gen suppressions run:
# valgrind --leak-check=full --show-reachable=yes --show-below-main=no --track-origins=yes --num-callers=30 --malloc-fill=0xaa --free-fill=0xdd --gen-suppressions=yes ./test
# retval is 0 on success
# or the number of failed cases
# or 137 if segfault happens

@ -0,0 +1,79 @@
#include <cxxtest/TestSuite.h>
#include "Fixture.hpp"
// #define private public // reach TimerThread's private multimap
#include "Timer.hpp"
// #include <time.h>
class TestTimer : public CxxTest::TestSuite
{
private:
class DummyTimer : public Timer
{
public:
DummyTimer(int maxPeriodicCount = 5)
: m_counter(0)
, m_maxPeriodicCount(maxPeriodicCount)
{
TRACE;
}
void timerExpired()
{
TRACE;
m_counter += 100;
}
void periodicTimerExpired()
{
TRACE;
static int count = 0;
m_counter++;
count++;
if ( count >= m_maxPeriodicCount ) {
stopTimer();
}
}
int m_counter;
private:
int m_maxPeriodicCount;
};
public:
void testBasic( void )
{
TEST_HEADER;
DummyTimer t;
t.createTimer(2);
t.wait();
TS_ASSERT_EQUALS( t.m_counter, 100 );
}
void testBasicPeriodic( void )
{
TEST_HEADER;
DummyTimer t;
t.createTimer(2,0,1);
t.wait();
TS_ASSERT_EQUALS( t.m_counter, 105 );
}
};

@ -76,6 +76,36 @@
fun:calloc
fun:allocate_dtv
fun:_dl_allocate_tls
fun:pthread_create@@GLIBC_2.1
fun:pthread_create@@GLIBC_*.*.*
fun:_ZN6Thread5startEv
...
fun:_ZN7CxxTest19RealTestDescription3runEv
fun:_ZN7CxxTest10TestRunner7runTestERNS_15TestDescriptionE
fun:_ZN7CxxTest10TestRunner8runSuiteERNS_16SuiteDescriptionE
fun:_ZN7CxxTest10TestRunner8runWorldEv
fun:_ZN7CxxTest10TestRunner11runAllTestsERNS_12TestListenerE
fun:_ZN7CxxTest14ErrorFormatter3runEv
fun:main
}
{
sigaction handling
Memcheck:Param
rt_sigaction(act->sa_handler)
fun:__libc_sigaction
}
{
timer create
Memcheck:Param
timer_create(evp)
fun:timer_create@@GLIBC_2.3.3
}
{
timer create 2
Memcheck:Leak
fun:malloc
fun:timer_create@@GLIBC_2.3.3
}

Loading…
Cancel
Save