Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. Mobile and Embedded
  4. Performance of QVector append
Forum Updated to NodeBB v4.3 + New Features

Performance of QVector append

Scheduled Pinned Locked Moved Unsolved Mobile and Embedded
7 Posts 4 Posters 682 Views 1 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • K Offline
    K Offline
    Kanndalf
    wrote on last edited by
    #1

    Hi,

    I have the task of adding multiple data classes to QVector (Qt 5.14.2) and experiencing performance problems.

    The data class consists of multiple members (see code below).

    The code is running on an iMX6 processor (ARM Cortex A9 Quad), and is much slower than on a desktop computer (factor 10).

    My question: How can I optimize the append, either by another container or by optimizing the data class (reordering of the members would be possible)?

    I already tried QList and QLinkedList but that does not make a big difference.

    Thanks for any ideas.

    #ifndef ITEM_H
    #define ITEM_H
    
    #include <QtCore>
    
    class Item
    {
    public:
    	typedef QByteArray Path;
    	typedef QByteArray Name;
    	typedef QByteArray Value;
    	typedef QByteArray Time;
    	typedef bool GoodQuality;
    
    	explicit Item() {}
    	explicit Item(const Path &p, const Name &n, const Value &v, const Time &t, const GoodQuality gq)
    	{
    		m_path = p; m_name = n; m_value = v; m_time = t; m_goodQuality = gq;
    	}
    
    private:
    	Path m_path;
    	Name m_name;
    	Value m_value;
    	Time m_time;
    	GoodQuality m_goodQuality = false;
    };
    
    typedef QList<Item> ItemList;
    // typedef QVector<Item> ItemList;
    
    #endif // ITEM_H
    
    // main.cpp
    #include "main.h"
    
    #include <QDebug>
    #include <QElapsedTimer>
    
    #include "item.h"
    #include "qelapsedtimer.h"
    
    ItemList Example::generateSubItems(const QByteArray &path)
    {
    	static int j = 0;
    	const ItemList result = {
    		Item(path + ":" + QByteArray::number(++j), "Name", "Value", "Time", true),
    		Item(path + ":" + QByteArray::number(++j), "Name", "Value", "Time", true),
    		Item(path + ":" + QByteArray::number(++j), "Name", "Value", "Time", true),
    		Item(path + ":" + QByteArray::number(++j), "Name", "Value", "Time", true),
    		Item(path + ":" + QByteArray::number(++j), "Name", "Value", "Time", true),
    		Item(path + ":" + QByteArray::number(++j), "Name", "Value", "Time", true),
    		Item(path + ":" + QByteArray::number(++j), "Name", "Value", "Time", true),
    		Item(path + ":" + QByteArray::number(++j), "Name", "Value", "Time", true),
    		Item(path + ":" + QByteArray::number(++j), "Name", "Value", "Time", true),
    		Item(path + ":" + QByteArray::number(++j), "Name", "Value", "Time", true),
    		Item(path + ":" + QByteArray::number(++j), "Name", "Value", "Time", true),
    		Item(path + ":" + QByteArray::number(++j), "Name", "Value", "Time", true),
    		Item(path + ":" + QByteArray::number(++j), "Name", "Value", "Time", true),
    		Item(path + ":" + QByteArray::number(++j), "Name", "Value", "Time", true),
    		Item(path + ":" + QByteArray::number(++j), "Name", "Value", "Time", true),
    		Item(path + ":" + QByteArray::number(++j), "Name", "Value", "Time", true)
    	};
    
    	return result;
    }
    
    ItemList Example::generateItems(const QByteArray &path)
    {
    	const Item foo("Path", "Name", "Value", "Time", true);
    
    	const ItemList bar = {foo};
    	return generateSubItems(path) + generateSubItems(path) + bar;
    }
    
    int Example::run()
    {
    	QElapsedTimer timer;
    	ItemList result;
    
    	timer.start();
    	result << Item();
    	for (int i = 0; i < 1000; ++i) {
    		result << generateItems(QByteArray::number(i));
    	}
    	result << generateItems("end");
    	const int time = timer.nsecsElapsed() / 1000;
    	qDebug() << "Needed" << time << "us for" << result.size() << "elements.";
    
    	return 0;
    }
    
    int main()
    {
    	Example example;
    	example.run();
    }
    
    #ifndef MAIN_H
    #define MAIN_H
    
    #include <QCoreApplication>
    #include <QObject>
    
    #include "item.h"
    
    class Example : public QObject
    {
    	Q_OBJECT
    public:
    	explicit Example(QObject *parent = nullptr) {Q_UNUSED(parent)};
    
    	int run();
    private:
    	ItemList generateSubItems(const QByteArray &path);
    	ItemList generateItems(const QByteArray &path);
    };
    
    #endif // MAIN_H
    
    JonBJ 1 Reply Last reply
    0
    • K Kanndalf

      Hi,

      I have the task of adding multiple data classes to QVector (Qt 5.14.2) and experiencing performance problems.

      The data class consists of multiple members (see code below).

      The code is running on an iMX6 processor (ARM Cortex A9 Quad), and is much slower than on a desktop computer (factor 10).

      My question: How can I optimize the append, either by another container or by optimizing the data class (reordering of the members would be possible)?

      I already tried QList and QLinkedList but that does not make a big difference.

      Thanks for any ideas.

      #ifndef ITEM_H
      #define ITEM_H
      
      #include <QtCore>
      
      class Item
      {
      public:
      	typedef QByteArray Path;
      	typedef QByteArray Name;
      	typedef QByteArray Value;
      	typedef QByteArray Time;
      	typedef bool GoodQuality;
      
      	explicit Item() {}
      	explicit Item(const Path &p, const Name &n, const Value &v, const Time &t, const GoodQuality gq)
      	{
      		m_path = p; m_name = n; m_value = v; m_time = t; m_goodQuality = gq;
      	}
      
      private:
      	Path m_path;
      	Name m_name;
      	Value m_value;
      	Time m_time;
      	GoodQuality m_goodQuality = false;
      };
      
      typedef QList<Item> ItemList;
      // typedef QVector<Item> ItemList;
      
      #endif // ITEM_H
      
      // main.cpp
      #include "main.h"
      
      #include <QDebug>
      #include <QElapsedTimer>
      
      #include "item.h"
      #include "qelapsedtimer.h"
      
      ItemList Example::generateSubItems(const QByteArray &path)
      {
      	static int j = 0;
      	const ItemList result = {
      		Item(path + ":" + QByteArray::number(++j), "Name", "Value", "Time", true),
      		Item(path + ":" + QByteArray::number(++j), "Name", "Value", "Time", true),
      		Item(path + ":" + QByteArray::number(++j), "Name", "Value", "Time", true),
      		Item(path + ":" + QByteArray::number(++j), "Name", "Value", "Time", true),
      		Item(path + ":" + QByteArray::number(++j), "Name", "Value", "Time", true),
      		Item(path + ":" + QByteArray::number(++j), "Name", "Value", "Time", true),
      		Item(path + ":" + QByteArray::number(++j), "Name", "Value", "Time", true),
      		Item(path + ":" + QByteArray::number(++j), "Name", "Value", "Time", true),
      		Item(path + ":" + QByteArray::number(++j), "Name", "Value", "Time", true),
      		Item(path + ":" + QByteArray::number(++j), "Name", "Value", "Time", true),
      		Item(path + ":" + QByteArray::number(++j), "Name", "Value", "Time", true),
      		Item(path + ":" + QByteArray::number(++j), "Name", "Value", "Time", true),
      		Item(path + ":" + QByteArray::number(++j), "Name", "Value", "Time", true),
      		Item(path + ":" + QByteArray::number(++j), "Name", "Value", "Time", true),
      		Item(path + ":" + QByteArray::number(++j), "Name", "Value", "Time", true),
      		Item(path + ":" + QByteArray::number(++j), "Name", "Value", "Time", true)
      	};
      
      	return result;
      }
      
      ItemList Example::generateItems(const QByteArray &path)
      {
      	const Item foo("Path", "Name", "Value", "Time", true);
      
      	const ItemList bar = {foo};
      	return generateSubItems(path) + generateSubItems(path) + bar;
      }
      
      int Example::run()
      {
      	QElapsedTimer timer;
      	ItemList result;
      
      	timer.start();
      	result << Item();
      	for (int i = 0; i < 1000; ++i) {
      		result << generateItems(QByteArray::number(i));
      	}
      	result << generateItems("end");
      	const int time = timer.nsecsElapsed() / 1000;
      	qDebug() << "Needed" << time << "us for" << result.size() << "elements.";
      
      	return 0;
      }
      
      int main()
      {
      	Example example;
      	example.run();
      }
      
      #ifndef MAIN_H
      #define MAIN_H
      
      #include <QCoreApplication>
      #include <QObject>
      
      #include "item.h"
      
      class Example : public QObject
      {
      	Q_OBJECT
      public:
      	explicit Example(QObject *parent = nullptr) {Q_UNUSED(parent)};
      
      	int run();
      private:
      	ItemList generateSubItems(const QByteArray &path);
      	ItemList generateItems(const QByteArray &path);
      };
      
      #endif // MAIN_H
      
      JonBJ Offline
      JonBJ Offline
      JonB
      wrote on last edited by
      #2

      @Kanndalf said in Performance of QVector append:

      The code is running on an iMX6 processor (ARM Cortex A9 Quad), and is much slower than on a desktop computer (factor 10).

      For a difference as large as a factor of 10 are you sure you are not testing a Debug vs a Release version? Make sure you are using the same compiler and Release builds on both?

      1 Reply Last reply
      0
      • K Offline
        K Offline
        Kanndalf
        wrote on last edited by
        #3

        Hello,
        thanks for your idea. I have now double-checked it. Both builds are set to "release" and it is compiled with the compiler option -O2. A crosscompiler is used for the imx6.

        x64:
        Needed 13816 us for 33034 elements.

        arm:
        Needed 275473 us for 33034 elements.

        1 Reply Last reply
        0
        • S Offline
          S Offline
          SimonSchroeder
          wrote on last edited by
          #4

          I am not sure if the append is your problem. A general optimization approach is to use reserve() to avoid additional re-allocations when adding items one-by-one. However, you are constructing intermediate ItemLists and append those at once. This should not pose a huge problem.

          However, you are constructing a lot of QByteArray objects. I don't know if these have a small string optimization. But, in general you'd have to expect an allocation for each QByteArray. Furthermore, you create a QByteArray object when you pass the parameters and then once again you copy (instead of move) the QByteArray. (And you do that even inside the constructor's body instead of the member initializer list which means you first default construct all the QByteArrays.) My bet is that your allocator on the embedded platform is slow. Avoid it wherever possible. And learn to use a profiler to figure out where all that time is actually spent.

          1 Reply Last reply
          5
          • K Offline
            K Offline
            Kanndalf
            wrote on last edited by
            #5

            Thank you for your thoughts.

            First of all: The example code here is greatly simplified. In my production code, an Item consists of different classes. I have taken your comment as an opportunity to improve the constructor and copy-constructor. The production code now runs much better, thank you for that @SimonSchroeder.

            As a next step I would like to use a move-constructor to assemble the result vector. As I understand it, this should already be implemented for QByteArray. The QVector can also use this for appending individual elements. For the class Item I have now also provided this, hopefully correctly. But it seems that it is not used when two QVectors are concatenated. I hope for further tips regarding this optimization.

            Below is the modified code:

            //item.h
            #ifndef ITEM_H
            #define ITEM_H
            
            #include <QtCore>
            
            class Item
            {
            public:
            	typedef QByteArray Path;
            	typedef QByteArray Name;
            	typedef QByteArray Value;
            	typedef QByteArray Time;
            	typedef bool GoodQuality;
            
            	explicit Item() {}
            	explicit Item(const Path &p, const Name &n, const Value &v, const Time &t, const GoodQuality gq) :
            		m_path(p), m_name(n), m_value(v), m_time(t), m_goodQuality(gq) {}
            	Item (const Item &i) noexcept :
            		m_path(i.m_path),
            		m_name(i.m_name),
            		m_value(i.m_value),
            		m_time(i.m_time),
            		m_goodQuality(i.m_goodQuality) {}
            	Item (Item &&i) noexcept:
            		m_path(std::move(i.m_path)),
            		m_name(std::move(i.m_name)),
            		m_value(std::move(i.m_value)),
            		m_time(std::move(i.m_time)),
            		m_goodQuality(std::move(i.m_goodQuality)) {}
            
            	// Item &operator=(const Item &i) = default;
            	// Item &operator=(Item &&i) = default;
            	Item &operator=(const Item &i) noexcept
            	{
            		m_path = i.m_path;
            		m_name = i.m_name;
            		m_value = i.m_value;
            		m_time = i.m_time;
            		m_goodQuality = i.m_goodQuality;
            		return *this;
            	}
            
            private:
            	Path m_path;
            	Name m_name;
            	Value m_value;
            	Time m_time;
            	GoodQuality m_goodQuality = false;
            };
            
            // typedef QList<Item> ItemList;
            typedef QVector<Item> ItemList;
            
            #endif // ITEM_H
            
            //main.cpp
            [...]
            
            ItemList Example::generateItems(const QByteArray &path)
            {
            	const Item foo("Path", "Name", "Value", "Time", true);
            
            	ItemList bar = {foo};
            	return std::move(generateSubItems(path)) << std::move(generateSubItems(path)) << std::move(bar);
            }
            
            int Example::run()
            {
            	QElapsedTimer timer;
            	ItemList result;
            	result.reserve(35000);
            
            	timer.start();
            	result << Item();
            	for (int i = 0; i < 1000; ++i) {
            		result.append(std::move(generateItems(QByteArray::number(i))));
            	}
            	result << generateItems("end");
            	const int time = timer.nsecsElapsed() / 1000;
            	qDebug() << "Needed" << time << "us for" << result.size() << "elements.";
            
            	return 0;
            }
            
            [...]
            

            x64:
            Needed 12071 us for 33034 elements.

            arm:
            Needed 217584 us for 33034 elements. <- Better, but I had hoped for more.

            1 Reply Last reply
            0
            • SeDiS Offline
              SeDiS Offline
              SeDi
              wrote on last edited by
              #6

              A QVector<Item*> is not feasible?

              S 1 Reply Last reply
              0
              • SeDiS SeDi

                A QVector<Item*> is not feasible?

                S Offline
                S Offline
                SimonSchroeder
                wrote on last edited by
                #7

                @SeDi said in Performance of QVector append:

                A QVector<Item*> is not feasible?

                Pointers mean more allocations. And allocations are slow. If you don't have any specific reason for pointers, prefer QVector<Item> over QVector<Item*>.

                1 Reply Last reply
                1

                • Login

                • Login or register to search.
                • First post
                  Last post
                0
                • Categories
                • Recent
                • Tags
                • Popular
                • Users
                • Groups
                • Search
                • Get Qt Extensions
                • Unsolved