Trolltech Home | Qt-interest Home | Recent Threads | All Threads | Author | Date
All threads index page 3

Qt-interest Archive, April 2008
Signals and GUI speed


Message 1 in thread

I'm using Qt's signal/slots mechanism for communicating events from a 
worker thread to the main application. The main application receives 
these events and updates a related model (which again updates a view). 
With lots of events from the main application, the GUI of the 
application appears slow/sluggish (menu selection, popup menus, repaints 
and similar), probably because the events from the GUI itself is queued 
in the same queue as the events from the worker thread.

Does anybody have any suggestion on what would be a good strategy for 
making the GUI of the application appear faster (i.e. not 
slow/sluggish)? Any way to prioritize "normal" GUI events, or turn the 
priority for signals from the worked thread down?

Thanks,

Marius K.

--
 [ signature omitted ] 

Message 2 in thread

Am Dienstag, 15. April 2008 schrieb Marius Kjeldahl:
> I'm using Qt's signal/slots mechanism for communicating events from a
> worker thread to the main application. The main application receives
> these events and updates a related model (which again updates a view).
> With lots of events from the main application, the GUI of the
> application appears slow/sluggish (menu selection, popup menus, repaints
> and similar), probably because the events from the GUI itself is queued
> in the same queue as the events from the worker thread.
> Does anybody have any suggestion on what would be a good strategy for
> making the GUI of the application appear faster (i.e. not
> slow/sluggish)? Any way to prioritize "normal" GUI events, or turn the
> priority for signals from the worked thread down?

You should try to compact changes.

From my own usage I know that sending around 400 events per second for several 
hours doesn't slow down qt at all. And here each of these events means a 
model-update. But if you emit the model-changed event the same number of 
times, all the views on it have to update and repaint. And there it becomes 
slow. So it it wise to cache the model-updates and emit the model-changed 
signal only once a second (for example).

That way I can process 400 datasets per second where each dataset gets send 
through 4 threads via events for hours. I tested this with a 10.000.000 to 
1.000.000.000 datasets. (Where each dataset means around 5 events including 
pushing the final data into a model.)

Have fun,

Arnold
-- 
 [ signature omitted ] 

Attachment: signature.asc
Description: This is a digitally signed message part.


Message 3 in thread

Arnold Krille wrote:
> From my own usage I know that sending around 400 events per second for several 
> hours doesn't slow down qt at all. And here each of these events means a 
> model-update. But if you emit the model-changed event the same number of 
> times, all the views on it have to update and repaint. And there it becomes 
> slow. So it it wise to cache the model-updates and emit the model-changed 
> signal only once a second (for example).

Just did a test; I'm currently at 550 events per second being sent from 
one thread to another through the signal/slot mechanism. The sending and 
receiving threads are different, with the added complexities and 
slowdowns that brings for moving events into and out of shared queue 
buffers.

I've also verified that it is not the model updates and/or repaints 
themselves that cause the slowdown, by having the signal receiver simply 
  return without actually doing anything.

Unless I find additional data that suggest that the signal/slot sending 
across threads is not the cause of the slowdowns of the main GUI 
updates, I will try to attempt an alternative method of communicating 
events between the threads. Like having a GUI main thread idle method 
that only acts on "worked thread" events when the main GUI thread is idle.

Thanks,

Marius K.

--
 [ signature omitted ] 

Message 4 in thread

Marius Kjeldahl wrote:
> I've also verified that it is not the model updates and/or repaints 
> themselves that cause the slowdown, by having the signal receiver 
> simply  return without actually doing anything.

If your worker threads have their own event loops and timers, did you 
remember to use moveToThread()? If not, your timers may actually be 
running in the main thread's event loop. I've stumbled over this gotcha 
several times.

--Dave

--
 [ signature omitted ] 

Message 5 in thread

Dave Smith wrote:
 > If your worker threads have their own event loops and timers, did you
 > remember to use moveToThread()? If not, your timers may actually be
 > running in the main thread's event loop. I've stumbled over this gotcha
 > several times.

Yes, I've made sure they are running in their own threads and not in the 
main/GUI thread, and that the worked threads do not call any GUI stuff 
at all. I've also verified this by "sleeping" the main thread and 
verifying that ticks are still being sent from the worked thread.

Thanks,

Marius K.

--
 [ signature omitted ] 

Message 6 in thread

Marius Kjeldahl wrote:
> I'm using Qt's signal/slots mechanism for communicating events from a
> worker thread to the main application. The main application receives
> these events and updates a related model (which again updates a view).
> With lots of events from the main application, the GUI of the
> application appears slow/sluggish (menu selection, popup menus,
> repaints and similar), probably because the events from the GUI itself
> is queued in the same queue as the events from the worker thread.
>
> Does anybody have any suggestion on what would be a good strategy for
> making the GUI of the application appear faster (i.e. not
> slow/sluggish)? Any way to prioritize "normal" GUI events, or turn the
> priority for signals from the worked thread down?
>
> Thanks,
>
> Marius K.
>
> -- 
> To unsubscribe - send a mail to qt-interest-request@xxxxxxxxxxxxx with
> "unsubscribe" in the subject or the body.
> List archive and information: http://lists.trolltech.com/qt-interest/
>
>
It may seem a simplistic and brush off answer, but have you run a
profiler over your code? Sometimes it highlights surprising results.
Under linux, try valgrind -tool=callgrind and kcachegrind to view,
windows/osx I'm not familiar with the tools, so can't offer any
suggestions there.

-- 
 [ signature omitted ] 

Message 7 in thread

Bill KING wrote:
 > It may seem a simplistic and brush off answer, but have you run a
 > profiler over your code? Sometimes it highlights surprising results.
 > Under linux, try valgrind -tool=callgrind and kcachegrind to view,
 > windows/osx I'm not familiar with the tools, so can't offer any
 > suggestions there.

Hey, I appreciate all suggestions! Yes, I have run profiling using 
gprof/kprof, together with the in-code profiling that I am doing. Now 
I've also run it inside vagrlind/kcachegrind as you suggested and I've 
attached a screenshot. The "deep-down" processing of events seems to 
dominate the top of the list, which I guess confirms my suspicions:

My current theory is that signal/slots isn't suitable for high-bandwidth 
worker threads. One other poster here suggested a more direct approach 
using postEvent which I haven't tried yet (but will). Another method 
would be to implement my own cross-thread mechanism which doesn't have 
to deal with the qt metatype system (which I suspect is to blame).

The behaviour of the application itself leads me to believe that the 
actual GUI events gets posted at the "far back" of the queue of signals 
containing the worked thread events, and therefore it takes some time 
for the event loop to get to them, which makes it appear sluggish. I've 
run the application over night as well and it still runs with similar 
performance as shortly after starting it, so I doubt there's any 
resource leakage or similar that makes it slower. It also indicates that 
the application is able to process all the events _eventually_, or I 
guess there would be resource starvation.

If you can read anything else from the provided screenshot feel free to 
share it with me.

Thanks,

Marius K.

PNG image

PNG image


Message 8 in thread

Marius Kjeldahl wrote:

> attached a screenshot. The "deep-down" processing of events seems to
> dominate the top of the list, which I guess confirms my suspicions:
No, 56% is spent in calculating the geometry of items.
I.e.: for each update that you signal (no matter if you use signals or any
other means of communication) you cause a change and cause a re-layout of
your item-view (or whatever you are using).

The (main) bottleneck here is not signal/slots (although that has some cost,
too), but rather that the gui can't do millions of updates.

Some post has suggested to reduce the number of updates.
You can achieve that by things like
* not invalidating the whole model every time (I am not saying you do),
  but using dataChanged for only relevant indices
* using setUpdatesEnabled - i.e. block updates during heavy change ops and
reenable later for a block update
* dont trigger an update on each change but periodically poll your model for
changes

HTH
Christoph

--
 [ signature omitted ] 

Message 9 in thread

Christoph Duelli wrote:

> Marius Kjeldahl wrote:
> 
>> attached a screenshot. The "deep-down" processing of events seems to
>> dominate the top of the list, which I guess confirms my suspicions:
> No, 56% is spent in calculating the geometry of items.
> I.e.: for each update that you signal (no matter if you use signals or any
> other means of communication) you cause a change and cause a re-layout of
> your item-view (or whatever you are using).

and repeated calls to itemHeight might be prevented by using
uniformRowHeights in the view (if they *are* uniform, of course)

--
 [ signature omitted ] 

Message 10 in thread

Christoph Duelli wrote:
> Christoph Duelli wrote:
>
>   
>> Marius Kjeldahl wrote:
>>
>>     
>>> attached a screenshot. The "deep-down" processing of events seems to
>>> dominate the top of the list, which I guess confirms my suspicions:
>>>       
>> No, 56% is spent in calculating the geometry of items.
>> I.e.: for each update that you signal (no matter if you use signals or any
>> other means of communication) you cause a change and cause a re-layout of
>> your item-view (or whatever you are using).
>>     
>
> and repeated calls to itemHeight might be prevented by using
> uniformRowHeights in the view (if they *are* uniform, of course)
>
> --
> To unsubscribe - send a mail to qt-interest-request@xxxxxxxxxxxxx with "unsubscribe" in the subject or the body.
> List archive and information: http://lists.trolltech.com/qt-interest/
>
>
>   
I second this modification/information.
To Marius:Without the callgrind output file to inspect in depth, it
definately looks like it's spending a lot of time recalculating the
itemheights (of interest are the QStyle calls). If you can reduce the
number of updates, and definately set uniformRowHeights if they're
definately uniform, then you may see some significant improvements. A
tiny little note: The event queue is heavily locked, there's work in
progress for 4.5 to try and speed up cross thread event processing, and
yes it is a bit of a bottleneck, but I think in this case, reducing the
size related calls will give you a good boost
(QTreeViewPrivate::itemHeight, QCommonStylePrivate::viewItemSize for
example will reduce both number of calls and time spent in that function
and it's children).

-- 
 [ signature omitted ] 

Message 11 in thread

(previously the "Signals and GUI speed" thread)

Further testing indicates it may no necessarily be related to 
signals/slots at all. I've now tried disabling all updates to the model 
after the intial model setup (some 10-15 rows with some 3-5 children 
each), and it still feels sluggish.

I've now traced it down to this; even without any updates or visible 
changes to the view, the view generates continuous paint events when I 
move the mouse over the view. I've tracked it down by overriding the 
paintEvent method, pushing dots to stderr before calling the 
QTreeView::paintEvent handler directly in the overridden method.

Any idea what is causing the continuous repaint behaviour from just 
moving the mouse around? I realize it would probably be possible to add 
some hovering decoration or similar, and that this may be the reason why 
paint methods are called when moving the mouse around, but triggering 
these when no visible updates are happening doesn't seem right (and 
causes massive sluggishness in the GUI).

Thanks,

Marius K.

--
 [ signature omitted ] 

Message 12 in thread

Marius Kjeldahl wrote:
> (previously the "Signals and GUI speed" thread)

Well, no wonder things were running slowly... After barking up the wrong 
trees for a while, and after staring on profiling data for a while, I 
got really suspicious about all the "sync" calls showing up in the 
profiling tree when I finally figured out that moving the mouse around 
on top of the widget was essential for getting useful profiling data.

Turns out there was a leftover in my code that forced X11 to sync all 
updates continously with the X server. This is what was causing the 
sluggish behaviour I experienced. The code was left over after I was 
tracking down another bug demonstrating some trouble with qt's qpixmap 
caching. Here's the "culprit", which I believe is similar to running 
with "-sync":

   extern int _Xdebug;
   _Xdebug = 1;

After removing this, the application seems quite snappy again, despite 
the high bandwidth signal/slot calls that I've talked about earlier. 
Until the current speed becomes a problem again, there are other things 
to test.

Thanks,

Marius K.

--
 [ signature omitted ] 

Message 13 in thread

Marius Kjeldahl wrote:
> Marius Kjeldahl wrote:
>> (previously the "Signals and GUI speed" thread)
>
> Well, no wonder things were running slowly... After barking up the
> wrong trees for a while, and after staring on profiling data for a
> while, I got really suspicious about all the "sync" calls showing up
> in the profiling tree when I finally figured out that moving the mouse
> around on top of the widget was essential for getting useful profiling
> data.
>
> Turns out there was a leftover in my code that forced X11 to sync all
> updates continously with the X server. This is what was causing the
> sluggish behaviour I experienced. The code was left over after I was
> tracking down another bug demonstrating some trouble with qt's qpixmap
> caching. Here's the "culprit", which I believe is similar to running
> with "-sync":
>
>   extern int _Xdebug;
>   _Xdebug = 1;
>
> After removing this, the application seems quite snappy again, despite
> the high bandwidth signal/slot calls that I've talked about earlier.
> Until the current speed becomes a problem again, there are other
> things to test.
>
> Thanks,
>
> Marius K.
>
> -- 
> To unsubscribe - send a mail to qt-interest-request@xxxxxxxxxxxxx with
> "unsubscribe" in the subject or the body.
> List archive and information: http://lists.trolltech.com/qt-interest/
>
>
Good news ;) And I know I learned something today :)

-- 
 [ signature omitted ] 

Message 14 in thread

Am Mittwoch, 16. April 2008 schrieb Marius Kjeldahl:
> My current theory is that signal/slots isn't suitable for high-bandwidth
> worker threads. One other poster here suggested a more direct approach
> using postEvent which I haven't tried yet (but will). Another method
> would be to implement my own cross-thread mechanism which doesn't have
> to deal with the qt metatype system (which I suspect is to blame).

Signal/Slot could be the one to blame. I use events directly. And I only push 
the pointer to the data around. (Last one in the chain deletes it...)

But never underestimate the gui. It could be that because the gui is a little 
slow on update/repaint the main event-loop isn't handled fast enough to push 
the events to the sub-threads event-loops...

Arnold
-- 
 [ signature omitted ] 

Attachment: signature.asc
Description: This is a digitally signed message part.