Qt measuring rendering time during which application is frozen

Viewed 141

I have a Qt application, where, among other things, there is a function render which goes through a list of objects and creates for each an according (subclassed) QGraphicsPathItem which it then puts as a child in a (subclassed) QGraphicsScene. (It is done in the code below through a visitor GGObjConstructor which gets initialized with the variable scene which is the scene where the items are to be added to).

XTimer timer;

timer.start();

gobjlist gobjlis = ogc._gobjectlis;

GGObjConstructor ggoc(scene, z_value, bkground_color);

for(auto obj: gobjlis) {
    obj->exec( &ggoc );
}

timer.stop();

My class XTimer is used in an obvious way to measure the time for this proceeding.

Now the problem is: Only the time spent in the loop where all the items are prepared and inserted into the scene is measured by timer. For a typical example with ~165000 items this gives about 7.5 sec as timer-value at reaching timer.stop(). But the application is after these 7.5 sec still frozen, with the screen-window where the scene is to by displayed yet invisible and only after about 25 sec (hand-stopped) suddenly the display window appears with all the items to be displayed.

Now of course I would like to measure these "freeze time" (or time till the application becomes responsive again, or maybe time till display window appears). But I found no way to do this although I looked some time through stackoverflow or the net in general. The best hint I found was

stackoverflow question

The answer there seemed to imply, that it would be not really simple to achieve (overriding paintEvent method and such things).

Question: Is this true? Or is there a simple way to measure the time till the application becomes responsive again/the image is really displayed?

1 Answers

I had a similar problem with an application once, where I wanted to measure the time the app freezes to figure out with logging what was causing these freezes. What I came up was to measure how long the Eventloop of the mainthread was not responding, because this directly corresponds to a frozen app.

The basic idea is to not run a QApplication but inherit from QApplication and override the notify() function. Some apps do this anyway to catch exceptions which would otherwise break the eventloop. Here is some pseudo-code which should bring the idea across:

bool MyApplication::notify( QObject * receiver, QEvent *  event ) 
{
    // something like storing current time like:
    // auto start = std::chrono::system_clock::now();
    // auto elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(start - end );
    // if( elapsed.count() > 1000 ){
    // log something like: Mainthread responds again after <elapsed> seconds
    // }
    // Note that end must be a member variable
    // end = start;
    return QApplication::notify(receiver, event);
}

Note 1: If your app does not continuesly run through notify() you can for testing purposes introduce a dummy QTimer which triggers faster than the logging time threshold.

Note 2: if you use multiple threads, esp. QThreads it could be necessary to filter the receiver object and perform that code only if the reciever is in the mainthread.

With this code you can log every freeze of the main-thread (frozen GUI) and determine the length of the freeze. With proper logging you can figure out whats causing the freezes. Keep in mind that this will only log after the freeze has resolved!

Addition: It is more complicated and slow, but for debugging/investigation purposes you can store the last event and Object-Tree of the reciever and log that as well. Than you even know which was the last event which triggered the freeze and the recieving Object.

Related