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 seconds

    Release
    Test1 ( 1 font ): 3.791 seconds
    Test2 (13 fonts): 3.880 seconds
    Test3 ( 4 fonts): 3.879 seconds
    Test4 ( 3 fonts): 3.944 seconds

    QT 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 seconds

    Release
    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 seconds

    My 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 512GB

    Operating System:
    Windows 10 Pro 64bit Build (Version 1511 Build 10586.420)

    Compiler:
    Visual Studio 2013 Update 5

    Example 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();
    }
    

  • Qt Champions 2016

    Hi
    Mingw compiler, Win 7, i7. Qt 5.5.1, 32 bit, debug

    release



  • 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
    debug

    Qt 5.7.0, Linux 64Bit, gcc 5.3.1, release
    release

    Looks good; might be due to something having changed in 5.7 or due to me using the linux version of Qt.


  • Qt Champions 2016

    Hi
    Tested with Qt 5.6 ( just upgraded)
    Test 2 is MUCH slower

    debug

    release


  • Lifetime Qt Champion

    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.


  • Qt Champions 2016

    Just for completeness.
    This is same pc, with Qt 5.7.

    debug

    release



  • 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.



  • Qt 5.7.0 x86 Release VS 2015 U2, Win 8.1 x64, i7-4770 using internal Intel graphics

    1920x1200 primary Display
    Test1 3.356
    Test2 13.741
    Test3 2.921
    Test4 2.931

    3840x2160 secondary Display
    Test1 13.568
    Test2 20.904
    Test3 18.167
    Test4 13.397



  • MarkusR,

    many thanks for your (propably release version) results. They also show the slow down (Test2 = 12 times font switching): If fonts are changed often.



  • 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.686

    QT 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.01

    New 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


  • Qt Champions 2016

    @mireiner
    Thank you.


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.