2D performance hit when upgrading runtime environment from 5.8 to 5.15
-
I am using NXP silicon i.MX6UL (which lacks video accelerator), coupled with 512MB of RAM and an 8GB flash.
Current Linux is built with Yocto Pyro, kernel 4.1.43 and Qt 5.8.
The new build I’m trying to make uses Yocto Gatesgarth, kernel 5.10.9 and Qt 5.15.I benchmarked the new build by checking interrupt response times when polling a sysfs endpoint from CLI in user space, and I discovered that the later kernel is way faster, which is good.
Conversely, when I run my Qt app it feels notably sluggish compared to the old build: it can be seen that the few
QPropertyAnimation
s that I’m using to create a fade and a slide effect on twoQGraphicsObject
s inside aQWidget
fall below 30FPS, stuttering is clearly visible.In Gatesgarth I tried both with the application compiled on 5.8 (from the Pyro build system), and with the application recompiled against the 5.15 libraries (in the Gatesgarth build system); I get the same performance difference and the same RAM footprint of about 150MB, while
top
reports that CPU usage is significantly higher (in Gatesgarth, compared to Pyro) when the animations play.
So far I have no definitive proof that the newer library is the culprit, I am basing my assumption solely on the higher CPU usage reported bytop
.I am looking to understand if there is a known performance reduction introduced in a later release (after 5.8).
Perhaps there are some settings that can be tweaked? Is there any Qt doc that covers performance? -
The oldest supported Qt version is 5.15, and we don’t keep any recent performance data for ancient versions around. Furthermore, you’re leaving us in the dark about which submodules you are actually using for which kind of application.
It’s impossible to give any sort of guidance with so many unknown factors. -
Sure, i will give any info i can, just tell me what do you need to know (though i might need some guidance on how to retreive something specific).
The application .pro file in Qt Creator contains the following:QT += core gui serialport greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
so i guess these are the modules the application actually uses, right?
I am assuming the modules/submodules installed in each runtime can be guessed by reading the Yocto recipes, this follows.
On the Pyro build i have:
- qtbase-dev
- qtbase-mkspecs
- qtbase-plugins
- qtbase-staticdev
- packagegroup-qt5-eng-qtcreator-debug
- qtimageformats-plugins
- qtsvg-dev
- qtsvg-mkspecs
- qtsvg-plugins
- qtxmlpatterns-dev
- qtxmlpatterns-mkspecs
- qtserialport
While on the Gatesgarth build i have:
- qtbase-dev
- qtbase-mkspecs
- qtbase-plugins
- qtbase-staticdev
- packagegroup-qt5-eng-qtcreator-debug
- qtimageformats-dev
- qtimageformats-plugins
- qtsvg-dev
- qtsvg-mkspecs
- qtsvg-plugins
- qtxmlpatterns-dev
- qtxmlpatterns-mkspecs
- qtserialport
- qtwebengine
- qtwebview
Please let me know if i can give you any further info.
-
For the animation itself: analyzing only the case where the user scrolls forward, as backward is just the same in reverse, this is what happens:
- the top drawing, let's say index i, starts to fade; fading time is
ANIM_FADE_TIME_MSEC
- when the fading is complete, the bottom drawing which is i+1 starts moving upwards; at the same time, using
QParallelAnimationGroup
, i take the drawing in position i+2 and bring it on screen; both animations run forANIM_SCROLL_TIME_MSEC
- at this point, the old topDwg is gone, new topDwg is i+1, and the image that just came on screen is going to be the new bottomDwg (i+2), so i can repeat the animation on the next user request
Everything starts with calling the
StartTransitionForward()
function.
This is what i think is the most relevant code:MyQWidget::MyQWidget(QWidget *parent) : QWidget(parent) { m_grapScene = new QGraphicsScene(this); m_grapScene->setSceneRect(0,0,SCREEN_WIDTH,SCREEN_HEIGHT); topDwg = new QGraphicsObject(); bottomDwg = new QGraphicsObject(); fadeAnimationTransitionForward = new QPropertyAnimation(this); fadeAnimationTransitionForward->setDuration(ANIM_FADE_TIME_MSEC); fadeAnimationTransitionForward->setPropertyName("opacity"); fadeAnimationTransitionForward->setStartValue(0.8); fadeAnimationTransitionForward->setEndValue(0.0); connect(fadeAnimationTransitionForward, SIGNAL(finished()), this, SLOT(on_FadeAnimationFinishNextDwg()), Qt::UniqueConnection); topDwgSlideAnimation = new QPropertyAnimation(); topDwgSlideAnimation->setDuration(ANIM_SCROLL_TIME_MSEC); topDwgSlideAnimation->setEasingCurve(QEasingCurve::OutQuad); bottomDwgSlideAnimation = new QPropertyAnimation(); bottomDwgSlideAnimation->setDuration(ANIM_SCROLL_TIME_MSEC); bottomDwgSlideAnimation->setEasingCurve(QEasingCurve::OutQuad); slideDwgAnimGroup = new QParallelAnimationGroup(this); slideDwgAnimGroup->addAnimation(topDwgSlideAnimation); slideDwgAnimGroup->addAnimation(bottomDwgSlideAnimation); } void MyQWidget::StartTransitionForward() { if (dwgDisplayed < (drawings.size() - 1)) { dwgDisplayed++; dwgFadeAnimationTransitionForward->setTargetObject(topDwg); dwgFadeAnimationTransitionForward->start(); } } void MyQWidget::on_FadeAnimationFinishNextDwg() { if (dwgDisplayed < drawings.size()) InsertDwgUp(dwgDisplayed); } void MyQWidget::InsertDwgUp(int idx) { m_grapScene->clear(); topDwg = GetNewDrawing(idx); topDwg->setPos(QPoint(0, DWG_DISPLAY_HEIGHT + 5)); m_grapScene->addItem(topDwg); bottomDwg = GetNewDrawing(idx + 1); bottomDwg->setPos(QPoint(0, SCREEN_HEIGHT)); m_grapScene->addItem(bottomDwg); AnimationSlideForward(); } void MyQWidget::AnimationSlideForward() { if (slideDwgAnimGroup->state() != QAbstractAnimation::Stopped) slideDwgAnimGroup->stop(); topDwgSlideAnimation->setTargetObject(topDwg); topDwgSlideAnimation->setPropertyName("pos"); topDwgSlideAnimation->setStartValue(QPoint(0, DWG_DISPLAY_HEIGHT + 5)); topDwgSlideAnimation->setEndValue(QPoint(0, 0)); bottomDwgSlideAnimation->setTargetObject(bottomDwg); bottomDwgSlideAnimation->setPropertyName("pos"); bottomDwgSlideAnimation->setStartValue(QPoint(0, SCREEN_HEIGHT)); bottomDwgSlideAnimation->setEndValue(QPoint(0, DWG_DISPLAY_HEIGHT + 5)); slideDwgAnimGroup->start(); }
- the top drawing, let's say index i, starts to fade; fading time is
-
@Axel-Spoerl
Are the additional informations i have provided completely useless?
Would you require more, or is the question simply not solvable? -
Hi @JeKK666,
as I said, there are unfortunately no benchmark data available for anything older than 5.15. It seems to be a complex application with a lot of submodules. I can't give you more than general hints.
In my experience, Qt 6 is faster than Qt 5 on a fairly recent desktop environment with sufficient RAM (>=32GB) and a fast SDD.
In a RAM-constrained environment, the opposite can be the case.
That's simply because Qt 6 has more features, resulting in larger libraries. Newer versions of the pixmap cache are faster and consume more memory, that's why I asked for submodules - you are using SVG.It would help to clarify things, if you boil the sluttering effects of property animation down to a minimal reproducer, which I can look at. Maybe it goes away with some code optimization. The application code shown in the post above is too large to use it as a reproducer.
-
@Axel-Spoerl
Many thanks for your inputs so far; I'm not even sure all the modules are used, i inherited the project and I'm not an expert Qt dev.
I'll try to create an SSCE in the next few days :)Meanwhile, is there something in the Qt docs which describes performance optimization?
-
There is nothing general in the docs, that would say: This is faster, because….
Qt 6 follows a general trend: Use more caching for the sake of speed. There were some optimisations in container classes and string views. We fixed a mem leak in the Quick pixmap cache.The downside of more caching, in other words higher memory consumption, is that older memory constrained setups (mainly embedded) need to swap out and actually become slower.
But I guess that’s not a Qt specific phenomenon. All frameworks and other tools I use on a daily basis, have increased their appetite for memory as RAM becomes cheaper and larger.