Qt 5.6.1 QPainter::setFont() benchmark - please help and join
-
With Qt 5.6.0 and later I noticed a significant performance breakdown when changing fonts during multiple QPainter::drawText() calls. But I'm not sure if this is Qt related or related to my hardware.
It would be a great help if some of you can run the following short example code and give a little feadback about the results on their hardware here. The example code should be run with Qt 5.6.0 or later or Qt 5.5.1 or prior versions.
The provided example code (see below) runs on my machine:
QT 5.5.1 x64 VS_2013:
Debug
Test1 ( 1 font ): 5.243 seconds
Test2 (13 fonts): 5.200 seconds
Test3 ( 4 fonts): 5.249 seconds
Test4 ( 3 fonts): 5.470 secondsRelease
Test1 ( 1 font ): 3.791 seconds
Test2 (13 fonts): 3.880 seconds
Test3 ( 4 fonts): 3.879 seconds
Test4 ( 3 fonts): 3.944 secondsQT 5.6.1-1 x64 VS_2013:
Debug
Test1 ( 1 font ): 5.291 seconds
Test2 (13 fonts): 43.682 seconds ==> slow
Test3 ( 4 fonts): 24.804 seconds ==> slow
Test4 ( 3 fonts): 5.834 secondsRelease
Test1 ( 1 font ): 3.773 seconds
Test2 (13 fonts): 20.354 seconds ==> slow
Test3 ( 4 fonts): 13.592 seconds ==> slow
Test4 ( 3 fonts): 4.009 secondsMy hardware and software specs:
Hardware:
CPU: Intel Core 2 Duo E8400 @3.00GHz
RAM: 8GB Dual Channal DDR2 @445MHz (5-5-5-15)
Graphic card: ATI Radeon HD 3600 512MB (Directx 10.1 - non Gamer card)
Harddrive: Samsung Evo Pro 850 512GBOperating System:
Windows 10 Pro 64bit Build (Version 1511 Build 10586.420)Compiler:
Visual Studio 2013 Update 5Example code:
#include <QApplication> #include <QWidget> #include <QPainter> #include <QElapsedTimer> class Widget : public QWidget { public: Widget(); protected: void timerEvent(QTimerEvent *event); void paintEvent(QPaintEvent *); private: QElapsedTimer elapsedTimer; int timerId; int elapsedTime1, elapsedTime2, elapsedTime3, elapsedTime4; bool isFinished1, isFinished2, isFinished3, isFinished4, isFinished5; int i, x1, x2, x3, x4, y1, y2, y3, y4; static QFont Arial, Caladea, Tomaha, Consolas, Calibri, Impact; static QFont Courier_New, Gorgia, Verdana, Times_New_Roman; static QFont Microsoft_Sans_Serif, Segoe_UI, Trebuchet_MS; }; QFont Widget::Arial("Arial", 14); QFont Widget::Caladea("Caladea", 14); QFont Widget::Tomaha("Tomaha", 14); QFont Widget::Consolas("Consolas", 14); QFont Widget::Calibri("Calibri", 14); QFont Widget::Impact("Impact", 14); QFont Widget::Segoe_UI("Segoe UI", 14); QFont Widget::Gorgia("Gorgia", 14); QFont Widget::Verdana("Verdana", 14); QFont Widget::Trebuchet_MS("Trebuchet MS", 14); QFont Widget::Courier_New("Courier New", 14); QFont Widget::Times_New_Roman("Times New Roman", 14); QFont Widget::Microsoft_Sans_Serif("Microsoft Sans Serif", 14); Widget::Widget() { setAutoFillBackground(true); setPalette(Qt::white); timerId = startTimer(1); elapsedTimer.start(); i=0; x1=0; x2=0, x3=0, x4=0; isFinished1 = isFinished2 = isFinished3 = isFinished4 = isFinished5 = false; } void Widget::timerEvent(QTimerEvent* /* event */) { update(); } void Widget::paintEvent(QPaintEvent *) { QPainter painter(this); if (i > 0 && i < 800) { y1 = 10; painter.setFont(Arial); painter.drawText(x1, y1 += 30, "Test 1"); painter.drawText(x1, y1 += 30, "row 01"); painter.drawText(x1, y1 += 30, "row 02"); painter.drawText(x1, y1 += 30, "row 03"); painter.drawText(x1, y1 += 30, "row 04"); painter.drawText(x1, y1 += 30, "row 05"); painter.drawText(x1, y1 += 30, "row 06"); painter.drawText(x1, y1 += 30, "row 07"); painter.drawText(x1, y1 += 30, "row 08"); painter.drawText(x1, y1 += 30, "row 09"); painter.drawText(x1, y1 += 30, "row 10"); painter.drawText(x1, y1 += 30, "row 11"); painter.drawText(x1, y1 += 30, "row 12"); x1++; elapsedTime1 = elapsedTimer.elapsed(); } else if (i > 800 && i < 1600) { isFinished1 = true; y2 = 160; painter.setFont(Arial); painter.drawText(x2, y2 += 30, "Test 2"); painter.setFont(Caladea); painter.drawText(x2, y2 += 30, "row 01"); painter.setFont(Tomaha); painter.drawText(x2, y2 += 30, "row 02"); painter.setFont(Consolas); painter.drawText(x2, y2 += 30, "row 03"); painter.setFont(Calibri); painter.drawText(x2, y2 += 30, "row 04"); painter.setFont(Impact); painter.drawText(x2, y2 += 30, "row 05"); painter.setFont(Segoe_UI); painter.drawText(x2, y2 += 30, "row 06"); painter.setFont(Gorgia); painter.drawText(x2, y2 += 30, "row 07"); painter.setFont(Verdana); painter.drawText(x2, y2 += 30, "row 08"); painter.setFont(Trebuchet_MS); painter.drawText(x2, y2 += 30, "row 09"); painter.setFont(Courier_New); painter.drawText(x2, y2 += 30, "row 10"); painter.setFont(Times_New_Roman); painter.drawText(x2, y2 += 30, "row 11"); painter.setFont(Microsoft_Sans_Serif); painter.drawText(x2, y2 += 30, "row 12"); x2++; elapsedTime2 = elapsedTimer.elapsed(); } else if (i > 1600 && i < 2400) { isFinished2 = true; y3 = 310; painter.setFont(Arial); painter.drawText(x3, y3 += 30, "Test 3"); painter.drawText(x3, y3 += 30, "row 01"); painter.drawText(x3, y3 += 30, "row 02"); painter.drawText(x3, y3 += 30, "row 03"); painter.setFont(Consolas); painter.drawText(x3, y3 += 30, "row 04"); painter.drawText(x3, y3 += 30, "row 05"); painter.drawText(x3, y3 += 30, "row 06"); painter.setFont(Impact); painter.drawText(x3, y3 += 30, "row 07"); painter.drawText(x3, y3 += 30, "row 08"); painter.drawText(x3, y3 += 30, "row 09"); painter.setFont(Courier_New); painter.drawText(x3, y3 += 30, "row 10"); painter.drawText(x3, y3 += 30, "row 11"); painter.drawText(x3, y3 += 30, "row 12"); x3++; elapsedTime3 = elapsedTimer.elapsed(); } else if (i > 2400 && i < 3200) { isFinished3 = true; y4 = 460; painter.setFont(Arial); painter.drawText(x4, y4 += 30, "Test 4"); painter.drawText(x4, y4 += 30, "row 01"); painter.drawText(x4, y4 += 30, "row 02"); painter.drawText(x4, y4 += 30, "row 03"); painter.drawText(x4, y4 += 30, "row 04"); painter.setFont(Impact); painter.drawText(x4, y4 += 30, "row 05"); painter.drawText(x4, y4 += 30, "row 06"); painter.drawText(x4, y4 += 30, "row 07"); painter.drawText(x4, y4 += 30, "row 08"); painter.setFont(Courier_New); painter.drawText(x4, y4 += 30, "row 09"); painter.drawText(x4, y4 += 30, "row 10"); painter.drawText(x4, y4 += 30, "row 11"); painter.drawText(x4, y4 += 30, "row 12"); x4++; elapsedTime4 = elapsedTimer.elapsed(); } else if (i > 3200) { isFinished4 = true; } i++; if (isFinished1) { painter.setFont(QFont("Arial", 12.0, QFont::Bold)); painter.drawText(QPoint(200, 100), "Test1 (1 font) elapsed time in seconds: " + QString::number(elapsedTime1/1000.0)); } if (isFinished2) { painter.drawText(QPoint(200, 200), "Test2 (12 fonts) elapsed time in seconds: " + QString::number((elapsedTime2-elapsedTime1)/1000.0)); } if (isFinished3) { painter.drawText(QPoint(200, 300), "Test3 (4 fonts) elapsed time in seconds: " + QString::number((elapsedTime3-elapsedTime2)/1000.0)); } if (isFinished4) { painter.drawText(QPoint(200, 400), "Test4 (3 fonts) elapsed time in seconds: " + QString::number((elapsedTime4-elapsedTime3)/1000.0)); } } int main(int argc, char *argv[]) { QApplication app(argc, argv); Widget widget; widget.showMaximized(); return app.exec(); }
-
Hi
Mingw compiler, Win 7, i7. Qt 5.5.1, 32 bit, debugrelease
-
Not sure if you were interested to see how Qt 5.7 performs, but I thought it might be interesting to see it.
Qt 5.7.0, Linux 64Bit, gcc 5.3.1, debug
Qt 5.7.0, Linux 64Bit, gcc 5.3.1, release
Looks good; might be due to something having changed in 5.7 or due to me using the linux version of Qt.
-
Hi
Tested with Qt 5.6 ( just upgraded)
Test 2 is MUCH slowerdebug
release
-
Hi,
Can you check it's still the case with 5.7.0 ?
In any case, you should check the bug report system to see if it's something known. If not please consider creating a new report providing your benchmark application.
-
mrjj and thEClaw thank you very much for contributing your results here. That is very helpfull!
It seams the problem is only related to Windows operating systems, because thEClaws results on Linux are fine. Linux does freetype font rendering, Windows not - that might be the reason.
The hardware might also affect the issue. Because on my 7 year old machine with slow graphics card the test with 3 fonts and 4 fonts did already slow down. Whereas mrjjs results on Windows 7 are still fine with Qt 5.6.0 and Qt 5.7.0 in that case.
mrjj is on Windows 7 and I'm on Windows 10 so there is another difference.
Would be great if another one on Windows could contribute his Qt 5.6.0 or later results here to find out.
-
The slow down happens also using just 1 font and switching different sizes of it.
But if only two sizes of the same font are used - switching its size alternating in every row with setFont() - there is no slow down (see last test in the code below).
So the problem may not be only QPainter::setFont related. But there is probably some font cache / memory managment issue involved too.Here is my benchmark of the new example code below:
QT 5.7.0_x64 VS_2013 Debug
Arial font, 4 sizes, seconds 4.860
Arial font, 6 sizes, seconds 34.763
Arial font, 8 sizes, seconds 40.807
Arial font, 12 sizes, seconds 46.776
Arial font, 2 sizes alternating, seconds 5.686QT 5.7.0_x64 VS_2013 Release
Arial font, 4 sizes, seconds 3.799
Arial font, 6 sizes, seconds 19.368
Arial font, 8 sizes, seconds 22.037
Arial font, 12 sizes, seconds 24.620
Arial font, 2 sizes alternating, seconds 4.01New example code with only 1 font:
#include <QApplication> #include <QWidget> #include <QPainter> #include <QElapsedTimer> class Widget : public QWidget { public: Widget(); protected: void timerEvent(QTimerEvent *event); void paintEvent(QPaintEvent *); private: QElapsedTimer elapsedTimer; int timerId; int elapsedTime1, elapsedTime2, elapsedTime3, elapsedTime4, elapsedTime5; bool isFinished1, isFinished2, isFinished3, isFinished4, isFinished5, isFinished6; int i, x1, x2, x3, x4, x5, y1, y2, y3, y4, y5; static QFont Arial7, Arial8, Arial9, Arial10, Arial11, Arial12; static QFont Arial13, Arial14, Arial15, Arial16, Arial17, Arial18; }; QFont Widget::Arial7("Arial", 7); QFont Widget::Arial8("Arial", 8); QFont Widget::Arial9("Arial", 9); QFont Widget::Arial10("Arial", 10); QFont Widget::Arial11("Arial", 11); QFont Widget::Arial12("Arial", 12); QFont Widget::Arial13("Arial", 13); QFont Widget::Arial14("Arial", 14); QFont Widget::Arial15("Arial", 15); QFont Widget::Arial16("Arial", 16); QFont Widget::Arial17("Arial", 17); QFont Widget::Arial18("Arial", 18); Widget::Widget() { setAutoFillBackground(true); setPalette(Qt::white); timerId = startTimer(1); elapsedTimer.start(); i=0; x1=0; x2=0, x3=0, x4=0, x5=0; isFinished1 = isFinished2 = isFinished3 = false; isFinished4 = isFinished5 = isFinished6 = false; } void Widget::timerEvent(QTimerEvent* /* event */) { update(); } void Widget::paintEvent(QPaintEvent *) { QPainter painter(this); if (i > 0 && i < 800) { y1 = 10; painter.setFont(Arial18); painter.drawText(x1, y1 += 30, "Arial 4 sizes"); painter.drawText(x1, y1 += 30, "row 01"); painter.drawText(x1, y1 += 30, "row 02"); painter.drawText(x1, y1 += 30, "row 03"); painter.setFont(Arial10); painter.drawText(x1, y1 += 30, "row 04"); painter.drawText(x1, y1 += 30, "row 05"); painter.drawText(x1, y1 += 30, "row 06"); painter.setFont(Arial12); painter.drawText(x1, y1 += 30, "row 07"); painter.drawText(x1, y1 += 30, "row 08"); painter.drawText(x1, y1 += 30, "row 09"); painter.setFont(Arial14); painter.drawText(x1, y1 += 30, "row 10"); painter.drawText(x1, y1 += 30, "row 11"); painter.drawText(x1, y1 += 30, "row 12"); x1++; elapsedTime1 = elapsedTimer.elapsed(); } else if (i > 800 && i < 1600) { isFinished1 = true; y2 = 110; painter.setFont(Arial18); painter.drawText(x2, y2 += 30, "Arial font 6 sizes"); painter.drawText(x2, y2 += 30, "row 01"); painter.drawText(x2, y2 += 30, "row 02"); painter.setFont(Arial8); painter.drawText(x2, y2 += 30, "row 03"); painter.drawText(x2, y2 += 30, "row 04"); painter.setFont(Arial10); painter.drawText(x2, y2 += 30, "row 05"); painter.drawText(x2, y2 += 30, "row 06"); painter.setFont(Arial12); painter.drawText(x2, y2 += 30, "row 07"); painter.drawText(x2, y2 += 30, "row 08"); painter.setFont(Arial14); painter.drawText(x2, y2 += 30, "row 09"); painter.drawText(x2, y2 += 30, "row 10"); painter.setFont(Arial16); painter.drawText(x2, y2 += 30, "row 11"); painter.drawText(x2, y2 += 30, "row 12"); x2++; elapsedTime2 = elapsedTimer.elapsed(); } else if (i > 1600 && i < 2400) { isFinished2 = true; y3 = 210; painter.setFont(Arial18); painter.drawText(x3, y3 += 30, "Arial 8 sizes"); painter.setFont(Arial9); painter.drawText(x3, y3 += 30, "row 01"); painter.drawText(x3, y3 += 30, "row 02"); painter.setFont(Arial10); painter.drawText(x3, y3 += 30, "row 03"); painter.setFont(Arial11); painter.drawText(x3, y3 += 30, "row 04"); painter.drawText(x3, y3 += 30, "row 05"); painter.setFont(Arial12); painter.drawText(x3, y3 += 30, "row 06"); painter.drawText(x3, y3 += 30, "row 07"); painter.setFont(Arial13); painter.drawText(x3, y3 += 30, "row 08"); painter.drawText(x3, y3 += 30, "row 09"); painter.setFont(Arial14); painter.drawText(x3, y3 += 30, "row 10"); painter.drawText(x3, y3 += 30, "row 11"); painter.setFont(Arial15); painter.drawText(x3, y3 += 30, "row 12"); x3++; elapsedTime3 = elapsedTimer.elapsed(); } else if (i > 2400 && i < 3200) { isFinished3 = true; y4 = 310; painter.setFont(Arial18); painter.drawText(x4, y4 += 30, "Arial 12 sizes"); painter.setFont(Arial8); painter.drawText(x4, y4 += 30, "row 02"); painter.setFont(Arial9); painter.drawText(x4, y4 += 30, "row 03"); painter.setFont(Arial10); painter.drawText(x4, y4 += 30, "row 04"); painter.setFont(Arial11); painter.drawText(x4, y4 += 30, "row 05"); painter.setFont(Arial12); painter.drawText(x4, y4 += 30, "row 06"); painter.setFont(Arial13); painter.drawText(x4, y4 += 30, "row 07"); painter.setFont(Arial14); painter.drawText(x4, y4 += 30, "row 08"); painter.setFont(Arial15); painter.drawText(x4, y4 += 30, "row 09"); painter.setFont(Arial16); painter.drawText(x4, y4 += 30, "row 10"); painter.setFont(Arial17); painter.drawText(x4, y4 += 30, "row 11"); painter.setFont(Arial18); painter.drawText(x4, y4 += 30, "row 12"); x4++; elapsedTime4 = elapsedTimer.elapsed(); } else if (i > 3200 && i < 4000) { isFinished4 = true; y5 = 410; painter.setFont(Arial18); painter.drawText(x5, y5 += 30, "Arial 12 sizes"); painter.setFont(Arial10); painter.drawText(x5, y5 += 30, "row 02"); painter.setFont(Arial18); painter.drawText(x5, y5 += 30, "row 03"); painter.setFont(Arial10); painter.drawText(x5, y5 += 30, "row 04"); painter.setFont(Arial18); painter.drawText(x5, y5 += 30, "row 05"); painter.setFont(Arial10); painter.drawText(x5, y5 += 30, "row 06"); painter.setFont(Arial18); painter.drawText(x5, y5 += 30, "row 07"); painter.setFont(Arial10); painter.drawText(x5, y5 += 30, "row 08"); painter.setFont(Arial18); painter.drawText(x5, y5 += 30, "row 09"); painter.setFont(Arial10); painter.drawText(x5, y5 += 30, "row 10"); painter.setFont(Arial18); painter.drawText(x5, y5 += 30, "row 11"); painter.setFont(Arial10); painter.drawText(x5, y5 += 30, "row 12"); x5++; elapsedTime5 = elapsedTimer.elapsed(); } else if (i > 4000) { isFinished5 = true; } i++; if (isFinished1) { painter.setFont(QFont("Arial", 12.0, QFont::Bold)); painter.drawText(QPoint(200, 50), "Arial font: 4 sizes, seconds: " + QString::number(elapsedTime1/1000.0)); } if (isFinished2) { painter.drawText(QPoint(200, 100), "Arial font: 6 sizes, seconds: " + QString::number((elapsedTime2-elapsedTime1)/1000.0)); } if (isFinished3) { painter.drawText(QPoint(200, 150), "Arial font: 8 sizes, seconds: " + QString::number((elapsedTime3-elapsedTime2)/1000.0)); } if (isFinished4) { painter.drawText(QPoint(200, 200), "Arial font: 12 sizes, seconds: " + QString::number((elapsedTime4-elapsedTime3)/1000.0)); } if (isFinished5) { painter.drawText(QPoint(200, 250), "Arial font: 2 sizes alternating, seconds: " + QString::number((elapsedTime5-elapsedTime4)/1000.0)); } } int main(int argc, char *argv[]) { QApplication app(argc, argv); Widget widget; widget.showMaximized(); return app.exec(); }
-
This is the related Qt Bug report:
https://bugreports.qt.io/browse/QTBUG-54180