Results 1 to 6 of 6

Thread: Qt EventLoop Duty Cycle (Blocking vs Spinning)

  1. #1
    Join Date
    Nov 2010
    Posts
    122
    Thanks
    62
    Thanked 3 Times in 3 Posts
    Qt products
    Qt4 Qt/Embedded
    Platforms
    Unix/X11 Windows

    Smile Qt EventLoop Duty Cycle (Blocking vs Spinning)

    There has been a general discussion about the efficiency of the Qt event loop, and whether or not the application or thread event loops block or spin burning CPU cycles. I desire to write an application that is patterned more after an RTOS type of construct wherein secondary threads pend until they actually have data to process or exit. Intuitively, it would seem that any Qt application or thread that implements event handling, must have the event loop running. This subject has been discussed on these forums, that is the necessity to have an event loop running for a thread to receive and process emitted signals.

    In my current design, I anticipate using a Qt console based application (running exec()) running the Qt state machine framework (running exec()) with several secondary threads which will NOT run event loops. Per previous dialog, the general rule was a thread can emit signals without an event loop, but the receiver must be running an event loop to propertly detect the event.

    When I think of characterizing the efficiency of a thread, it really comes down to a duty cycle calculation, that is, how often is the thread running burning CPU cycles relative to the time it spends blocking. Certainly this duty cycle will change as a function of activity, but I want to characterize the behavior for a more nominal condition where the application/thread running exec() is not being actively tickled by signals or events.

    To that end, I am trying to come up with a methodology to characterize the efficiency of the QCoreApplication::exec() call as well as the QThread::exec() call. By inspection of the Qt source code, exec() will eventually call QEventLoop:rocessEvents, and
    the QAbstractEventDispatcher calls a Windows or Linux specific implementation.

    Qt Code:
    1. QtCored4.dll!QEventDispatcherWin32::processEvents(QFlags<enum QEventLoop::ProcessEventsFlag> flags={...}) Line 834 C++
    2. QtGuid4.dll!QGuiEventDispatcherWin32::processEvents(QFlags<enum QEventLoop::ProcessEventsFlag> flags={...}) Line 1170 + 0x15 bytes C++
    3. QtCored4.dll!QEventLoop::processEvents(QFlags<enum QEventLoop::ProcessEventsFlag> flags={...}) Line 150 C++
    4. QtCored4.dll!QEventLoop::exec(QFlags<enum QEventLoop::ProcessEventsFlag> flags={...}) Line 201 + 0x2d bytes C+
    To copy to clipboard, switch view to plain text mode 

    Under Windows, (file C:\Qt\4.7.3\src\corelib\kernel\qeventdispatcher_wi n.cpp), QEventDispatcherWin32:rocessEvents() is called. Within the method, there are conditions wherre MsgWaitForMultipleObjectsEx() is called blocking the thread. The aboutToBlock() signal is emited prior to the thread blocking, and conversely, the awake() signal is emitted when the thread unblocks.

    Under Linux (file C:\Qt\4.7.3\src\corelib\kernel\qeventdispatcher_un ix.cpp), the doSelect() API is called to pend the thread, and the aboutToBlock() and awake() signals are emitted to frame the blocking session.

    My original idea on characterizing the duty cycle was to implement handlers for these two signals and record the time at each point so a duty cycle calculation of thread "blocking" time could be determined relative to thread active time burning CPU cycles.

    However, the eventloop for the main application is implemented within QCoreApplication::exec() as a local stack based variable QEventLoop. I am unable to override the implementation of QCoreApplication::exec() without access to the
    private members of the base class.

    Perhaps I am approaching this incorrectly, and there some profiling tool available to characterize the exec() event loop to get a metric on its efficiency (or lack thereof).

    Anybody have any thoughts on this or have already characterized exec()'s behavior?
    Last edited by bob2oneil; 19th July 2011 at 17:08.

  2. #2
    Join Date
    Mar 2011
    Location
    Hyderabad, India
    Posts
    1,882
    Thanks
    3
    Thanked 452 Times in 435 Posts
    Qt products
    Qt4 Qt5
    Platforms
    MacOS X Unix/X11 Windows
    Wiki edits
    15

    Default Re: Qt EventLoop Duty Cycle (Blocking vs Spinning)

    Even if you able to get into private sections of Qt code and plant dome profiling hooks, I don't think you will get any extra information than what you get from "Task Manager".

    Blocking exec() or scheduing (running / spinning) exec() is completly in OS resposibility. Qt exec() may block by itself, if it requires some resource from OS. Also, even in cases where exec() is ready and want to run, OS may still block it for many scheduing reasons, which Qt / programmer may not have control on, things like thread affinity, process proprity, process resource limitation, system load, etc.

    I think if Qt event loop is the only thread (in the only process) running on the the CPU, it would never stop, and use 100% processor.

  3. The following user says thank you to Santosh Reddy for this useful post:

    bob2oneil (19th July 2011)

  4. #3
    Join Date
    Nov 2010
    Posts
    122
    Thanks
    62
    Thanked 3 Times in 3 Posts
    Qt products
    Qt4 Qt/Embedded
    Platforms
    Unix/X11 Windows

    Cool Re: Qt EventLoop Duty Cycle (Blocking vs Spinning)

    Thanks for your input, I agree with your assessment. Still, I would like to metric the nominal duty cycle since there seems to be some attempt at blocking within the Qt code base event loop code to determine just how "bad" a particular thread can be in terms of yielding CPU time to other threads so I can determine if and where it is worth replacing the Qt exec() loop with one that actually pends/blocking until useful work can be performed.

  5. #4
    Join Date
    Nov 2010
    Posts
    122
    Thanks
    62
    Thanked 3 Times in 3 Posts
    Qt products
    Qt4 Qt/Embedded
    Platforms
    Unix/X11 Windows

    Default Re: Qt EventLoop Duty Cycle (Blocking vs Spinning)

    I did some further experimenting by intercepting the two signals mentioned in my thread. The following source code was used in a console application where I derived a class from QCoreApplication as App.

    The results were logged to a file. Under Windows, since the ability to read time with high accuracy is a known issue, I am using the GetSystemTimeAsFileTime() API, which is accurate to only 15 ms. Time information is written to the log time in format similar to the Linux timespec (as sec.microseconds).

    Regardless of the inaccuracy of time, the Windows XP task manager indicates CPU consumption of the running console as 00, and what is interesting in the logging is that the triad pattern of awake(), awake(), and then aboutToBlock() suggests that the thread is indeed blocking for most of the time.

    The seems to suggest to me that perhaps the Qt event loop is not as inefficient as I perhaps thought it might be. If the thread is spending most of its time in a blocked state, then it is not constantly spinning for new events.

    Now I could be misunderstanding the results, and perhaps I need to test it out in a different manner.

    Looking for suggestions or perhaps a Qt kernel expert who can shed some light on this behavior.

    I will repeat this under Linux (much better time accuracy) and convey those results to the community.

    Test results are as follows:


    1311112841.765625 INFO: Entering Event Loop
    1311112842.0 INFO: awake()
    1311112842.15625 INFO: awake()
    1311112842.15625 INFO: aboutToBlock()
    1311112909.125000 INFO: awake()
    1311112910.375000 INFO: awake()
    1311112910.375000 INFO: aboutToBlock()
    1311112971.296875 INFO: awake()
    1311112971.312500 INFO: awake()
    1311112971.312500 INFO: aboutToBlock()
    1311113022.46875 INFO: awake()
    1311113022.78125 INFO: awake()
    1311113022.78125 INFO: aboutToBlock()
    1311113023.125000 INFO: awake()
    1311113023.156250 INFO: awake()
    1311113023.156250 INFO: aboutToBlock()

    Source code is as follows:

    Qt Code:
    1. int main(int argc, char *argv[])
    2. {
    3. App app (argc, argv);
    4.  
    5. QString logFile = QCoreApplication::arguments().at(0) + ".txt";
    6. QFile::remove(logFile);
    7. FILELog::ReportingLevel() = logDEBUG2;
    8. FILE* pFile = fopen(qPrintable(logFile), "a");
    9. Output2FILE::Stream() = pFile;
    10.  
    11. QAbstractEventDispatcher *eventDispatcher = QAbstractEventDispatcher::instance();
    12. if (eventDispatcher)
    13. {
    14. QObject::connect(eventDispatcher, SIGNAL(aboutToBlock()), &app, SLOT(aboutToBlock()));
    15. QObject::connect(eventDispatcher, SIGNAL(awake()), &app, SLOT(awake()));
    16. }
    17.  
    18. FILE_LOG(logINFO) << "Entering Event Loop";
    19. int returnCode = app.exec();
    20. FILE_LOG(logINFO) << "Exiting Event Loop";
    21.  
    22. if (eventDispatcher)
    23. {
    24. QObject::disconnect(eventDispatcher, SIGNAL(aboutToBlock()), &app, SLOT(aboutToBlock()));
    25. QObject::disconnect(eventDispatcher, SIGNAL(awake()), &app, SLOT(awake()));
    26. }
    27.  
    28. return returnCode;
    29. }
    To copy to clipboard, switch view to plain text mode 


    In the App class, the two slots are defined as:


    Qt Code:
    1. void App::aboutToBlock()
    2. {
    3. FILE_LOG(logINFO) << "aboutToBlock()";
    4. }
    5.  
    6. void App::awake()
    7. {
    8. FILE_LOG(logINFO) << "awake()";
    9. }
    To copy to clipboard, switch view to plain text mode 
    Last edited by bob2oneil; 19th July 2011 at 23:27. Reason: Add more code

  6. #5
    Join Date
    Mar 2011
    Location
    Hyderabad, India
    Posts
    1,882
    Thanks
    3
    Thanked 452 Times in 435 Posts
    Qt products
    Qt4 Qt5
    Platforms
    MacOS X Unix/X11 Windows
    Wiki edits
    15

    Default Re: Qt EventLoop Duty Cycle (Blocking vs Spinning)

    also try adding a QTimer of 0 ms, connect a slot to it, have a log in slot, and see how results vary

  7. The following user says thank you to Santosh Reddy for this useful post:

    bob2oneil (20th July 2011)

  8. #6
    Join Date
    Nov 2010
    Posts
    122
    Thanks
    62
    Thanked 3 Times in 3 Posts
    Qt products
    Qt4 Qt/Embedded
    Platforms
    Unix/X11 Windows

    Default Re: Qt EventLoop Duty Cycle (Blocking vs Spinning)

    Not sure what the intention was with your suggestion, but here are the results.

    According to the documentation, a QTimer with a timeout interval of 0 will time out as soon as all the events in the window system's event queue have been processed.

    This keeps the event loop constantly busy and will not enter the blocking state.

    1311193072.781250 INFO: awake()
    1311193072.781250 INFO: awake()
    1311193072.781250 INFO: awake()
    1311193072.781250 INFO: awake()
    1311193072.796875 INFO: awake()
    1311193072.796875 INFO: awake()
    1311193072.796875 INFO: awake()
    1311193072.796875 INFO: awake()
    1311193072.796875 INFO: awake()
    1311193072.796875 INFO: awake()
    1311193072.796875 INFO: awake()
    1311193072.796875 INFO: awake()
    1311193072.796875 INFO: awake()
    1311193072.796875 INFO: awake()
    1311193072.812500 INFO: awake()
    1311193072.812500 INFO: awake()
    1311193072.812500 INFO: awake()
    1311193072.812500 INFO: awake()
    1311193072.812500 INFO: awake()
    1311193072.812500 INFO: awake()
    1311193072.812500 INFO: awake()
    1311193072.828125 INFO: awake()
    1311193072.828125 INFO: awake()
    1311193072.828125 INFO: awake()
    1311193072.828125 INFO: awake()
    1311193072.828125 INFO: awake()
    1311193072.828125 INFO: awake()
    1311193072.828125 INFO: awake()
    1311193072.828125 INFO: awake()
    1311193072.843750 INFO: awake()
    1311193072.843750 INFO: awake()
    1311193072.843750 INFO: awake()
    1311193072.843750 INFO: awake()
    1311193072.843750 INFO: awake()
    1311193072.843750 INFO: awake()
    1311193072.843750 INFO: awake()
    1311193072.843750 INFO: awake()
    1311193072.843750 INFO: awake()
    1311193072.843750 INFO: awake()
    1311193072.843750 INFO: awake()
    1311193072.859375 INFO: awake()
    1311193072.859375 INFO: awake()
    1311193072.859375 INFO: awake()
    1311193072.859375 INFO: awake()
    1311193072.859375 INFO: awake()
    1311193072.859375 INFO: awake()
    1311193072.859375 INFO: awake()
    1311193072.859375 INFO: awake()
    1311193072.875000 INFO: awake()
    1311193072.875000 INFO: awake()
    1311193072.875000 INFO: awake()
    1311193072.875000 INFO: awake()
    1311193072.875000 INFO: awake()
    1311193072.875000 INFO: awake()
    1311193072.890625 INFO: awake()
    1311193072.890625 INFO: awake()
    1311193072.890625 INFO: awake()
    1311193072.890625 INFO: awake()
    1311193072.890625 INFO: awake()


    Added after 41 minutes:


    Here are the Linux results, both with and without the QTimer(0). This test is performed on a faster machine than the original results.

    Interested in your interpretation of the results. I am pleased to see some blocking calls under Linux for QTimer(0). Looking at the results, under Linux with QTimer(0), the duty cycle of blocking is approximately 50% based on the timing information.

    Linux without timer running

    1311195116.648288 INFO: Entering Event Loop
    1311195116.648568 INFO: aboutToBlock()
    1311195116.648708 INFO: awake()
    1311195116.648757 INFO: aboutToBlock()

    With QTimer(0)

    1311194967.250633 INFO: Entering Event Loop
    1311194967.250723 INFO: Starting timer
    1311194967.250763 INFO: aboutToBlock()
    1311194967.250813 INFO: awake()
    1311194967.250825 INFO: aboutToBlock()
    1311194967.250840 INFO: awake()
    1311194967.250850 INFO: aboutToBlock()
    1311194967.250864 INFO: awake()
    1311194967.250924 INFO: aboutToBlock()
    1311194967.250938 INFO: awake()
    1311194967.250950 INFO: aboutToBlock()
    1311194967.250965 INFO: awake()
    1311194967.250977 INFO: aboutToBlock()
    1311194967.250991 INFO: awake()
    1311194967.251002 INFO: aboutToBlock()
    1311194967.251016 INFO: awake()
    1311194967.251030 INFO: aboutToBlock()
    1311194967.251046 INFO: awake()
    1311194967.251060 INFO: aboutToBlock()
    1311194967.251075 INFO: awake()
    1311194967.251088 INFO: aboutToBlock()
    1311194967.251103 INFO: awake()
    1311194967.251116 INFO: aboutToBlock()
    1311194967.251129 INFO: awake()
    1311194967.251140 INFO: aboutToBlock()
    Last edited by bob2oneil; 20th July 2011 at 22:06.

Similar Threads

  1. Qt TimePicker // Spinning ListView
    By luke_dirtwalker in forum Qt for Embedded and Mobile
    Replies: 1
    Last Post: 18th May 2011, 20:59
  2. MainWindow::resizeEvent - Infinite Cycle
    By metRo_ in forum Qt Programming
    Replies: 2
    Last Post: 1st June 2010, 23:33
  3. How use Model view with a tree wich have Cycle ?
    By weepdoo in forum Qt Programming
    Replies: 2
    Last Post: 9th December 2008, 17:05
  4. Thread eventLoop and run
    By ^NyAw^ in forum Qt Programming
    Replies: 2
    Last Post: 8th May 2008, 19:36

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  
Digia, Qt and their respective logos are trademarks of Digia Plc in Finland and/or other countries worldwide.