My project was based on qpcpp version 7.2.1 and the qp/qpcpp/examples/workstation/dpp example. Running on the Beaglebone black with Linux 5.10.168-g991c5ce91e #1 PREEMPT.
After updating to the latest qp release v7.3.0, my application now loads the cpu up to %95 in both Idle and running states.
To isolate the issue, I downloaded qpcpp v7.3.0 onto the Beaglebone black and run the dpp posix example, which presented the same issue, high cpu usage when running the dpp application.
The qpcpp v7.2.1 dpp example does not have this issue when running in the same conditions. Are there any changes that I need to make for my application to be compatible with qpcpp v7.3.0?
Thanks,
Eddie
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Hi Eddie,
Which POSIX port are you using (the multithreaded POSIX port or the single-threaded POSIX-QV)?
The most implicated change in the POSIX ports between QP 7.2.1 and QP 7.3.0 is in the "ticker" thread that provides a time base for calling the QP time events. The "ticker" thread in the older port used the nanosleep() POSIX call. The problem with nanosleep() was that it caused drift in the clock ticks.
To avoid such drift, the newer QP ports to POSIX use the clock_nanosleep() POSIX call with the absolute time specification.
The clock_nanosleep() seems to behave reasonably on the deskopt Linux (i.e., I don't see high CPU loading on the desktop). You might want to run the DPP example on your Linux computer.
I suspect that in your embedded Linux on your Beaglebone this call might be doing some busy-polling or something. You might want to experiment with that by writing a small application (without QP) that would just call clock_nanosleep() in a loop.
I'm not sure how to square this circle with the POSIX "standard". It seems impossible to get a simple, periodic time base that would work for all POSIX implementations.
--MMS
Last edit: Quantum Leaps 2023-11-16
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
I'm using the multithreaded POSIX port. Testing nanosleep() and clock_nanosleep() with a simple application running on a Beaglebone black, shows clock_nanosleep() loading the CPU. I'm not sure why this is the case. The DDP example on a Linux desktop works as expected.
I will investigate why this is not the case on the Beaglebone black.
Thanks for your time,
Eddie
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Hi Eddie,
It's disturbing to hear that clock_nanosleep() behaves so poorly on some embedded Linux distros.
All that's really needed is a reliable way of periodically calling the QP tick-processing (QTIMEEVT_TICK_X() in QP/C and QTimeEvt::TICK_X() in QP/C++). Still, this is apparently proving surprisingly tricky, which is getting really frustrating. Several methods have been tried over the years, including select(), nanosleep(), etc. The use of clock_nanosleep() was recommended in several posts on stackoverflow to avoid a drift in clock tick.
But anyway, this is actually a minor aspect of the QP ports to POSIX, and this aspect could be handled by the application, where you can use the most suitable method (not necessarily widely portable). This option has been already available in the single-threaded QP port (POSIX-QV). Now, this option is extened to the multi-threaded QP port as well (POSIX). The code has been already checked into GitHub, please see:
- QF_run() in QP/C POSIX port
- QF::run() in QP/C++ POSIX port
Specifically, you can disable the standard clock tick implementation by calling QF_setTickRate(0, 0) in QP/C and QP::QF::setTickRate(0, 0) in QP/C++. (This need to happen before entering QF::run()). With this setting, the QF_onClockTick() callback (defined in the application) will need to be an endless loop that calls QTimeEvt::TICK_X() periodically using any way you see fit.
Hi Miro,
Thanks for the update. TI has just released a new processor sdk for the Beaglebone black, I will try the - qpcpp/examples/posix-win32/dpp-posix example on both the new and older sdk. I will update you on findings.
Thanks
Eddie
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
I have tested the new ~/qpcpp/examples/posix-win32/dpp-posix# example that uses the select() api.
This is the output I get
Dining Philosophers Problem example
QP 7.3.1
Press 'p' to pause
Press 's' to serve
Press ESC to quit...
Philosopher 0 is thinking
Philosopher 1 is thinking
Philosopher 2 is thinking
Philosopher 3 is thinking
Philosopher 4 is thinking
Then the application just freezes and the board becomes unresponsive.
I have added a print statement before select is called as bellow
voidQF::onClockTick(){// NOTE:// The standard clock-tick service has been DISABLED in QF::onStartup()// by setting the clock tick rate to zero.// Therefore QF::onClockTick() must implement an alternative waiting// mechanism for the clock period. This particular implementation is// based on the select() system call to block for the desired timeout.structtimevaltv;tv.tv_sec=0;tv.tv_usec=(1000000/BSP::TICKS_PER_SEC);PRINTF_S("\n%s\n","calling select !");select(0,NULL,NULL,NULL,&tv);// block for the timevalueQTimeEvt::TICK_X(0U,&l_clock_tick);// process time events at rate 0QS_RX_INPUT();// handle the QS-RX inputQS_OUTPUT();// handle the QS output
With this addition I get the same output without the printf, which seems to indicate that the issue is before QF::onClockTick() is called. I have tried using a debugger, but the cpu usage is way too high.
Do you have any ideas as to what could be going on?
I'm testing the code on a beaglebone black
Thanks
Eddie
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
First, have you tried to run the example qpcpp/examples/posix-win32/dpp-posix on your desktop linux? Please do! This will establish a baseline. The example should run with minimal CPU loading.
Next, if it does not work on your Beaglebone, be creative. Use some other blocking call, for instance sleep(1). (Just ignore for a minute that it sleep for a full second):
voidQF::onClockTick(){// NOTE:// The standard clock-tick service has been DISABLED in QF::onStartup()// by setting the clock tick rate to zero.// Therefore QF::onClockTick() must implement an alternative waiting// mechanism for the clock period. This particular implementation is// based on the select() system call to block for the desired timeout.structtimevaltv;tv.tv_sec=0;tv.tv_usec=(1000000/BSP::TICKS_PER_SEC);PRINTF_S("\n%s\n","calling select !");//select(0, NULL, NULL, NULL, &tv); // block for the timevaluesleep(1);// <== for testing only...QTimeEvt::TICK_X(0U,&l_clock_tick);// process time events at rate 0...
If this produces the printf output about every second, it means that it runs. Then you might want to experiment with other sleeping mechanisms. (nanosleep(), microsleep(), etc.)
In the end, please remember that this is POSIX: Nobody knows what it will do...
--MMS
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Sorry for thread-hijacking but this reminds me of the quote:
"The nice thing about standards is that you have so many to choose from; furthermore, if you do not like any of them, you can just wait for next year's model." (Andrew Tanenbaum)
When I worked at a big company that everybody's heard of (2 decades ago), everyone was drinking the POSIX Kool Aid until it turned out to be a clown show.
And then on the ops side, Java promised "write once, run everywhere" (particularly with GUI apps) and that was utter bunk.
Maybe both of these have gotten better since then, but when I hear someone say "it should just work" (no one on this thread is saying that, BTW) I just roll my eyes.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
The example runs fine on a laptop running Ubuntu 20.04. I have also tested in WSL Unbutu 22.04 without any issues.
I did try using poll() blocking call with the same results. I will try sleep() next.
If i replace the clock_nanosleep() with the nanosleep() in the run function in qf_port.cpp, will this be a valid test?
// sleep without drifting till next_time (absolute), see NOTE03if(clock_nanosleep(CLOCK_MONOTONIC,TIMER_ABSTIME,&next_tick,NULL)==0)// success?{// clock tick callback (must call QTIMEEVT_TICK_X())onClockTick();}toif(nanosleep(&next_tick,NULL)==0)// success?{
Eddie
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Hi Eddie,
The whole point of the changes in the QP port to POSIX (multithreaded) was precisely so that you don't need to change the official port. Instead, you can have full control over the sleeping mechanism in your application level. I hope this makes sense to you.
--MMS
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Hi Miro,
Having full control the sleeping mechanism make sense, I was think of options that could help while debugging the issue I'm having.
I have tried just using sleep(1) as suggested got this output
Dining Philosophers Problem example
QP 7.3.1
Press 'p' to pause
Press 's' to serve
Press ESC to quit...
Philosopher 0 is thinking
Philosopher 1 is thinking
Philosopher 2 is thinking
Philosopher 3 is thinking
Philosopher 4 is thinking [ 785.781975] sched: RT throttling activated
the application stops here.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Dining Philosophers Problem example
QP 7.3.1
Press 'p' to pause
Press 's' to serve
Press ESC to quit...
Philosopher 0 is thinking
Philosopher 1 is thinking
Philosopher 2 is thinking
Philosopher 3 is thinking
Philosopher 4 is thinking
run() onStartup()!
run() pthread_mutex_unlock(&l_startupMutex)! [ 213.026072] sched: RT throttling activated
it seems that execution is stuck waiting for this mutex?
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
I have changed the init() mutex initialization from the new recursive mutex back to
non-recursive initializer. This has resolved the issue were the application hangs after calling
pthread_mutex_unlock(&l_startupMutex); and high cpu usage is gone.
// initialize the critical section mutex QF_critSectMutex_ as a// *recursive mutex* in a portable way according to the POSIX Standard// pthread_mutexattr_t attr;// pthread_mutexattr_init(&attr);// pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);// pthread_mutex_init(&critSectMutex_, &attr);// pthread_mutexattr_destroy(&attr);// init the global mutex with the default non-recursive initializerpthread_mutex_init(&critSectMutex_,NULL);// init the startup mutex with the default non-recursive initializerpthread_mutex_init(&l_startupMutex,NULL);pthread_mutex_lock(&l_startupMutex);
On the other hand I have tested the posix dpp example on the standard Debian distro that comes with the Beaglebone black, the example runs fine without any issues. Not sure what changes TI has made to its kernel to cause this issue.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Hi Eddie,
Thank you for identifying the recursive setting of the mutex (used for QF critical sections). In the next QP/C/C++ 7.3.1, this mutex in the POSIX and POSIX-QV ports will be reverted back to non-recursive, but this time around there will be checks (assertions) to make sure that:
- the critical sections indeed never nest
- the critical sections are "balanced" meaning that every entry is matched by exit.
--MMS
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Hi Miro,
My project was based on qpcpp version 7.2.1 and the qp/qpcpp/examples/workstation/dpp example. Running on the Beaglebone black with Linux 5.10.168-g991c5ce91e #1 PREEMPT.
After updating to the latest qp release v7.3.0, my application now loads the cpu up to %95 in both Idle and running states.
To isolate the issue, I downloaded qpcpp v7.3.0 onto the Beaglebone black and run the dpp posix example, which presented the same issue, high cpu usage when running the dpp application.
The qpcpp v7.2.1 dpp example does not have this issue when running in the same conditions. Are there any changes that I need to make for my application to be compatible with qpcpp v7.3.0?
Thanks,
Eddie
Hi Eddie,
Which POSIX port are you using (the multithreaded POSIX port or the single-threaded POSIX-QV)?
The most implicated change in the POSIX ports between QP 7.2.1 and QP 7.3.0 is in the "ticker" thread that provides a time base for calling the QP time events. The "ticker" thread in the older port used the
nanosleep()
POSIX call. The problem with nanosleep() was that it caused drift in the clock ticks.To avoid such drift, the newer QP ports to POSIX use the
clock_nanosleep()
POSIX call with the absolute time specification.The
clock_nanosleep()
seems to behave reasonably on the deskopt Linux (i.e., I don't see high CPU loading on the desktop). You might want to run the DPP example on your Linux computer.I suspect that in your embedded Linux on your Beaglebone this call might be doing some busy-polling or something. You might want to experiment with that by writing a small application (without QP) that would just call
clock_nanosleep()
in a loop.I'm not sure how to square this circle with the POSIX "standard". It seems impossible to get a simple, periodic time base that would work for all POSIX implementations.
--MMS
Last edit: Quantum Leaps 2023-11-16
Hi Miro,
I'm using the multithreaded POSIX port. Testing nanosleep() and clock_nanosleep() with a simple application running on a Beaglebone black, shows clock_nanosleep() loading the CPU. I'm not sure why this is the case. The DDP example on a Linux desktop works as expected.
I will investigate why this is not the case on the Beaglebone black.
Thanks for your time,
Eddie
Hi Eddie,
It's disturbing to hear that
clock_nanosleep()
behaves so poorly on some embedded Linux distros.All that's really needed is a reliable way of periodically calling the QP tick-processing (
QTIMEEVT_TICK_X()
in QP/C andQTimeEvt::TICK_X()
in QP/C++). Still, this is apparently proving surprisingly tricky, which is getting really frustrating. Several methods have been tried over the years, includingselect()
,nanosleep()
, etc. The use ofclock_nanosleep()
was recommended in several posts on stackoverflow to avoid a drift in clock tick.But anyway, this is actually a minor aspect of the QP ports to POSIX, and this aspect could be handled by the application, where you can use the most suitable method (not necessarily widely portable). This option has been already available in the single-threaded QP port (POSIX-QV). Now, this option is extened to the multi-threaded QP port as well (POSIX). The code has been already checked into GitHub, please see:
- QF_run() in QP/C POSIX port
- QF::run() in QP/C++ POSIX port
Specifically, you can disable the standard clock tick implementation by calling
QF_setTickRate(0, 0)
in QP/C andQP::QF::setTickRate(0, 0)
in QP/C++. (This need to happen before enteringQF::run()
). With this setting, theQF_onClockTick()
callback (defined in the application) will need to be an endless loop that callsQTimeEvt::TICK_X()
periodically using any way you see fit.Examples of customizing the clock tick service are provided as follows:
- qpc/examples/posix-win32/dpp-posix
- qpcpp/examples/posix-win32/dpp-posix
Please try it out!
--MMS
Last edit: Quantum Leaps 2023-11-17
Hi Miro,
Thanks for the update. TI has just released a new processor sdk for the Beaglebone black, I will try the - qpcpp/examples/posix-win32/dpp-posix example on both the new and older sdk. I will update you on findings.
Thanks
Eddie
Hi Miro,
I have tested the new ~/qpcpp/examples/posix-win32/dpp-posix# example that uses the select() api.
This is the output I get
Dining Philosophers Problem example
QP 7.3.1
Press 'p' to pause
Press 's' to serve
Press ESC to quit...
Philosopher 0 is thinking
Philosopher 1 is thinking
Philosopher 2 is thinking
Philosopher 3 is thinking
Philosopher 4 is thinking
Then the application just freezes and the board becomes unresponsive.
I have added a print statement before select is called as bellow
With this addition I get the same output without the printf, which seems to indicate that the issue is before QF::onClockTick() is called. I have tried using a debugger, but the cpu usage is way too high.
Do you have any ideas as to what could be going on?
I'm testing the code on a beaglebone black
Thanks
Eddie
Hi Eddie,
First, have you tried to run the example
qpcpp/examples/posix-win32/dpp-posix
on your desktop linux? Please do! This will establish a baseline. The example should run with minimal CPU loading.Next, if it does not work on your Beaglebone, be creative. Use some other blocking call, for instance
sleep(1)
. (Just ignore for a minute that it sleep for a full second):If this produces the printf output about every second, it means that it runs. Then you might want to experiment with other sleeping mechanisms. (
nanosleep()
,microsleep()
, etc.)In the end, please remember that this is POSIX: Nobody knows what it will do...
--MMS
Sorry for thread-hijacking but this reminds me of the quote:
"The nice thing about standards is that you have so many to choose from; furthermore, if you do not like any of them, you can just wait for next year's model." (Andrew Tanenbaum)
When I worked at a big company that everybody's heard of (2 decades ago), everyone was drinking the POSIX Kool Aid until it turned out to be a clown show.
And then on the ops side, Java promised "write once, run everywhere" (particularly with GUI apps) and that was utter bunk.
Maybe both of these have gotten better since then, but when I hear someone say "it should just work" (no one on this thread is saying that, BTW) I just roll my eyes.
The example runs fine on a laptop running Ubuntu 20.04. I have also tested in WSL Unbutu 22.04 without any issues.
I did try using poll() blocking call with the same results. I will try sleep() next.
If i replace the clock_nanosleep() with the nanosleep() in the run function in qf_port.cpp, will this be a valid test?
Eddie
Hi Eddie,
The whole point of the changes in the QP port to POSIX (multithreaded) was precisely so that you don't need to change the official port. Instead, you can have full control over the sleeping mechanism in your application level. I hope this makes sense to you.
--MMS
Hi Miro,
Having full control the sleeping mechanism make sense, I was think of options that could help while debugging the issue I'm having.
I have tried just using sleep(1) as suggested got this output
Dining Philosophers Problem example
QP 7.3.1
Press 'p' to pause
Press 's' to serve
Press ESC to quit...
Philosopher 0 is thinking
Philosopher 1 is thinking
Philosopher 2 is thinking
Philosopher 3 is thinking
Philosopher 4 is thinking
[ 785.781975] sched: RT throttling activated
the application stops here.
I have added some printf code in the run()
It's not elegant, but got this output
Dining Philosophers Problem example
QP 7.3.1
Press 'p' to pause
Press 's' to serve
Press ESC to quit...
Philosopher 0 is thinking
Philosopher 1 is thinking
Philosopher 2 is thinking
Philosopher 3 is thinking
Philosopher 4 is thinking
run() onStartup()!
run() pthread_mutex_unlock(&l_startupMutex)!
[ 213.026072] sched: RT throttling activated
it seems that execution is stuck waiting for this mutex?
I have changed the init() mutex initialization from the new recursive mutex back to
non-recursive initializer. This has resolved the issue were the application hangs after calling
pthread_mutex_unlock(&l_startupMutex); and high cpu usage is gone.
On the other hand I have tested the posix dpp example on the standard Debian distro that comes with the Beaglebone black, the example runs fine without any issues. Not sure what changes TI has made to its kernel to cause this issue.
Hi Eddie,
Thank you for identifying the recursive setting of the mutex (used for QF critical sections). In the next QP/C/C++ 7.3.1, this mutex in the POSIX and POSIX-QV ports will be reverted back to non-recursive, but this time around there will be checks (assertions) to make sure that:
- the critical sections indeed never nest
- the critical sections are "balanced" meaning that every entry is matched by exit.
--MMS