PDA

View Full Version : Very slow QCoreApplication::removePostedEvents in Qt 4.6



andre
2nd December 2009, 16:01
Hi,

I just compiled my code against the official Qt 4.6 (self compiled under Mac OS X 10.5 using gcc 4.2 with cocoa support and for 32bit).

The same code that ran just fine against the 4.6-tp1 is now experiencing dramatic slow downs. Here is the sample:


QObject **qls = new QObject*[COUNT];
for(int i=0; i<COUNT; i++) {
qls[i] = new QObject;
qls[i]->setParent(&a);
}

for(int i=0; i<COUNT; i++) {
qls[i]->setParent(0);
delete qls[i];
}

delete[] qls;

runs like this:


creation of 10000 objects: 20.294 ms = 2.0293 µs per object
destruction of 10000 objects: 743.141 ms = 74.3141 µs per object

2µs for creation is just fine. but 74.3µs for the destruction process is crazy. In the 4.6-tp1 the destruction was always faster than creation.

I took the Mac Process Analyzer and figured out that it stuck 95% of the time in


QCoreApplication::removePostedEvents()

What am I doing wrong?

wysota
3rd December 2009, 09:26
Apparently there are some events waiting in the queue for your objects. First I would get rid of the setParent(0) call, it's completely useless. Then I would change your qls variable from QObject** to QObjectList. Then you have to tell us if you do anything with the objects apart from creating and destroying them.

andre
5th December 2009, 03:05
The thing I am trying to achieve here is to make a statement of the performance of Qt object creation and destruction. If you remember, I asked a couple of weeks ago what would be the disadvantage of making every object (model or view or whatever) a QObject. Since a QObject does something useful, there must be clearly ome overhead involved.

I must mention that I am a fan of generating code. And, in the meantime, I worked on a prototype which generates a QObject for each and every class in my UML tool. In addition to that, I also generate a QObject for each and every property of that UML class. Reason is, I later want to be able to connect to the attribute of the concrete instance of that class and receive events via signals/slots. However, my first test showed me that the performance was not good. And especially memory consumption was a killer. Creation of an object (QObject) with 20 such property objects (also QObjects) took ~20µs. So I decided to step back and do the old school approach and map the UML properties onto C++ plain old data members.

Anyhow, once I changed the code generator I switched over to the new Qt 4.6 from the previous Qt-4.6-tp1 and recognized a significant drop in performance of the destruction process. That is why I stripped down my code to a presentable minimum without using too many Qt features at once, like QObjectList or something. Plain QObjects should be constructable and destructable, right? It doesn't matter, where I keep them. I just wanted to make sure that the compiler doesn't optimize them out.

I'm still not through to this. But I have recognized so far that as soon as I do not wire the objects together via parent-child all is fine. If I connect them, performance drop to inacceptible level.


int main(int argc, char *argv[])
{
const int COUNT = 30000;
QCoreApplication a(argc, argv);

Timer clock;
clock.start();

QObject *parent = new QObject;
QObject **qls = new QObject*[COUNT];
for(int i=0; i<COUNT; i++) {
qls[i] = new QObject(parent);
}
qDebug() << "creation of" << COUNT << "objects: " << clock.getElapsedTimeInMilliSec() << "ms = "
<< clock.getElapsedTimeInMicroSec() / COUNT << "us per object";


clock.start();
for(int i=0; i<COUNT; i++) {
qls[i]->setParent(0);
delete qls[i];
}
delete[] qls;
delete parent;
qDebug() << "destruction of" << COUNT << "objects: " << clock.getElapsedTimeInMilliSec() << "ms = "
<< clock.getElapsedTimeInMicroSec() / COUNT << "us per object";

return 0;
}

compiled and run against "Qt 4.6 technology preview" takes


creation of 30000 objects: 14.759 ms = 0.491933 us per object
destruction of 30000 objects: 16.539 ms = 0.5513 us per object

whereas run under Qt-4.6 GA takes


creation of 30000 objects: 18.028 ms = 0.6009 us per object
destruction of 30000 objects: 2127.7 ms = 70.9234 us per object

But: if I don't connect the objects via parent-child, like here



QObject *parent = new QObject;
QObject **qls = new QObject*[COUNT];
for(int i=0; i<COUNT; i++) {
qls[i] = new QObject;
}

for(int i=0; i<COUNT; i++) {
delete qls[i];
}

then I get excellent performance, even in the GA version:


creation of 30000 objects: 9.654 ms = 0.321767 us per object
destruction of 30000 objects: 14.067 ms = 0.468867 us per object

May be this is a bug which has no consequence in a UI application due to low amounts of objects and low response time expectancy during human interactions. I don't even know who to ask or where to go at Qt's website to open a ticket for that. ???

Lesiok
5th December 2009, 07:59
Qt Bug Tracker (http://bugreports.qt.nokia.com/secure/Dashboard.jspa)