PDA

View Full Version : CPU load strongly increasing when making simple animation



DDDIM
27th June 2015, 12:07
I found that my application consumes more and more CPU power it time when making a simple animation.

I wrote a simple program so everyone could check what am i talking about:



import QtQuick 2.3
import QtQuick.Controls 1.2
import QtQuick.Window 2.2


ApplicationWindow {visible: true; width: 640; height: 480;

Window{ height: 100; width: 100; visible: true; objectName: "w1"; id:w1;
Image{anchors.fill: parent; source: sw?"qrc:/images/1":"qrc:/images/2"; }
}

Window{ height: 100; width: 100; visible: true; objectName: "w2"; id:w2;
Image{anchors.fill: parent; source: sw?"qrc:/images/1":"qrc:/images/2"; }
}

Window{ height: 100; width: 100; visible: true; objectName: "w3"; id:w3;
Image{anchors.fill: parent; source: sw?"qrc:/images/1":"qrc:/images/2"; }
}

property bool sw: false;
Timer { interval: 30;running: true;repeat: true;
onTriggered: {sw=!sw;}
}

}

11245

It happens only if animations is in few separate windows.
If i completely reload animated windows with Loader{}, everything resets and CPU load starts to increase from beginning.( but I can't use such quick fix in my program!)
If i reload only Image{} with Loader{}, it does not help.

It happens also if i creating custom QQuickPaintedItem in two or more QQuickWindows and calling them update() method. EVEN WITH NO ACTUAL DRAWING!!!

This issue was tested with Ubuntu 12.04+qt5.4.2+intel_video and ubuntu14.04+qt5.3.2+radeon_video.
I need a quick fix for this!!!

I had already tried to periodically call releaseResources() method and resetOpenGLState() method of QQuickWindow.

Can anyone test this issue or give me an advise?

anda_skoa
27th June 2015, 13:27
Have you tried to not reload images all the time?

Cheers,
_

wysota
27th June 2015, 14:15
Where are the animations?

DDDIM
27th June 2015, 14:52
I am just swapping two images because it is just a test program. In my actual program i were acquiring images from camera. And i spend a day only to understand that this CPU issue is not related with camera, but with image drawing (or maybe even just a window content redrawing). It was very unexpected for me.

Try it yourself. the code is very easy to compile, you just need two images. I was using these
11246
11247

A program should not have these strange behaviour and slowly consume CPU. I could understand if it were RAM consumption, but this CPU consumption is very strange.

anda_skoa
27th June 2015, 15:05
A program should not have these strange behaviour and slowly consume CPU. I could understand if it were RAM consumption, but this CPU consumption is very strange.

You are constantly triggering CPU bound operations, why are you expecting the program to not use CPU?

Data in a Qt resource is compressed, loading requires decompression (CPU bound operation 1).
The image format might not be simple bitmap, loading requires decodign (CPU bound operation 2).
Decoded image data might not have the same channel setup as the display, loading requires conversion (CPU bound operation 3, though some of that might be delegated to the GPU).

Destroying and creating image buffers usually also requires CPU involvment.

Try loading both images into one Image element each, and then switching visibiliy



Window{ height: 100; width: 100; visible: true; objectName: "w1"; id:w1;
Image{anchors.fill: parent; visible: sw; source: "qrc:/images/1"; }
Image{anchors.fill: parent; visible: !sw; source: "qrc:/images/2"; }
}


Cheers,
_

wysota
27th June 2015, 15:10
Or use a SpriteAnimation.

DDDIM
27th June 2015, 15:29
anda_skoa, I fully undenstand what you are talking about, but try to understand me too:

1. this is a test program written for simplicity of explaining my issue, in my actual program, where i faced this issue i was getting images from webcamera, and firstly I thought that it is related with Image acquisition from camera, but i was wrong. Image acqusition was OK. It was a drawing in QQuickWindow. Namely not actual drawing(I commented all the drawing out, but issue has not disappeared) but calling update() method of my custom QQuickPaintedItem. I continued digging and ended with that simple program in first post.
2. In first post i uploaded picture, showing that CPU load starts from less than 20% when the program starts, then I doing nothing, program runs simple image swapping and CPU load increasing linearly over time and in approx. 100 seconds it ends up at 60%. But program still does SAME thing!!! CPU load was increased in 3 times!
3. Also very interesting is that when I apply putenv("LIBGL_ALWAYS_SOFTWARE=1"); in main.cpp this issue goes away and i have CONSTANT low CPU usage. But in my real application I need hardware rendering, so it is not an option for me.
4. I think this is not a hardware or opengl-library-related issue because I tested it on two different machines with different video-adaptors and Ubuntu versions, as I wrote in first post.

wysota
27th June 2015, 22:48
Apparently your GL implementation is broken. And painted items are slow, so it's likely you are hitting some slow code path.

Which doesn't change the fact that your example is not a good test of your problem. The fact that something is "slow" doesn't mean the reason for it being "slow" is the same as in a different situation.

DDDIM
28th June 2015, 11:40
Ok. Here is another example.

main.qml:


import QtQuick 2.3
import QtQuick.Controls 1.2
import QtQuick.Window 2.2

ApplicationWindow {visible: true; width: 640; height: 480;
Window{ height: 100; width: 100; visible: true; objectName: "w1"; id:w1; }
Window{ height: 100; width: 100; visible: true; objectName: "w2"; id:w2; }
Window{ height: 100; width: 100; visible: true; objectName: "w3"; id:w3; }
}


main.cpp:

#include <QApplication>
#include <QQmlApplicationEngine>
#include "worker.h"

QQmlApplicationEngine* engine;

int main(int argc, char *argv[])
{
//putenv("LIBGL_ALWAYS_SOFTWARE=1");
QApplication app(argc, argv);

engine = new QQmlApplicationEngine(QUrl("qrc:/main.qml"));

worker = new Worker();
worker->setConnections();

return app.exec();
}



worker.h:


#ifndef WORKER_H
#define WORKER_H

#include <QObject>
#include "QTimer"

class Worker : public QObject
{
Q_OBJECT
public:
explicit Worker(QObject *parent = 0);
QTimer timer;

public slots:
void setConnections();
void reset();
};

extern Worker* worker;
extern QObject *root;

#endif // WORKER_H


worker.cpp:


#include "worker.h"
#include "QtQuick/QQuickView"
#include "QtQml/QQmlApplicationEngine"
#include "QQuickWindow"

Worker* worker;
extern QQmlApplicationEngine* engine;
QQuickWindow *w1,*w2,*w3;
QObject *root;

Worker::Worker(QObject *parent) :
QObject(parent)
{
root = engine->rootObjects().first();
w1 = root->findChild<QQuickWindow*>(QString("w1"));
w2 = root->findChild<QQuickWindow*>(QString("w2"));
w3 = root->findChild<QQuickWindow*>(QString("w3"));
timer.setInterval(30);
timer.start();
}

void Worker::setConnections(){ connect(&this->timer,SIGNAL(timeout()),this,SLOT(reset())); }

void Worker::reset(){
w1->update();
w2->update();
w3->update();
}


it shows all the same results.

In stackoverflow (http://stackoverflow.com/questions/31088128/cpu-load-strongly-increasing-when-making-simple-animation) forum Ansh helped me to find out that this it opensource-driver-related issue, but I can't use proprietary driver because it does not support my target PC's videoadapter radeon x300 and Intel builtin graphics.

I compiled most fresh mesa release (10.5.8) but it did not helped.

I don't know what to do now.

anda_skoa
28th June 2015, 12:45
Interesing find!

I modifed the example a bit so it can be run with just qmlscene:


import QtQuick 2.3
import QtQuick.Controls 1.2
import QtQuick.Window 2.2

ApplicationWindow {visible: true; width: 640; height: 480;
Window{ height: 100; width: 100; visible: true; objectName: "w1"; id:w1; }
Window{ height: 100; width: 100; visible: true; objectName: "w2"; id:w2; }
Window{ height: 100; width: 100; visible: true; objectName: "w3"; id:w3; }

Timer {
interval: 30
repeat: true
running: true

onTriggered: {
w1.update();
w2.update();
w3.update();
}
}
}

Indeed a constant increase in CPU load on my Intel GPU.
It seems to behave stably if I close two of the three sub windows.

To check if this has anything to do with multithreaded redering, I disabled Qt's GL sanity check (enabling multithreaded rendering despite Mesa being blacklisted):
QT_OPENGL_NO_SANITY_CHECK=1 qmlscene updatetest.qml

On one run it did not crash immediately and seemed to stay at a low CPU usage, but maybe it didn't run long enough yet.
That is with Mesa 10.5.5, you could check if it survives with 10.5.8

Cheers,
_

DDDIM
28th June 2015, 14:53
Just checked on mesa Mesa 8.0.4(from standard 12.04 repo)


putenv("QT_OPENGL_NO_SANITY_CHECK=1");

CPU load was stable low until program crashed with

imageTest: ../../src/xcb_conn.c:180: write_vec: Проверочное утверждение «!c->out.queue_len» не выполнено.

11248

I had already deleted 10.5.8. Reinstalling and rechecking now.

Checked! All the same. CPU load low, but it crashes. If i run some other opengl program(glxgears) in parralel, it crashes much later and I can measure CPU usage.

Added after 53 minutes:

Any suggestions? is this a Qt or MESA issue? Don't have any idea what else should I try. Digging in source code can take forever.

I had tried to analyse the CPU consumption with valgrind, but when I run test program with profiler(even with paused event recording), CPU loading already high (approx 60%) and doesn't changing. I have a feeling that some kind of CPU usage threshold is being reached. :confused:

DDDIM
30th June 2015, 14:19
anda_skoa, please vote a bug on Qt bugtracker: https://bugreports.qt.io/browse/QTBUG-46900