📜 ⬆️ ⬇️

Comparison of the speed of range-based for, foreach (Qt) and some of the STL when calculating the sum of container elements

I am involved in developing a C ++ project using the Qt framework. In our project, Qt containers are used in many places and the macro foreach is often used to bypass elements. At one point, I wondered how justified the use of this macro was. In addition, I really wanted to "touch" c ++ 11 in action. And that's what I managed to find out at the moment ...

Writing support functions


Containers in STL and Qt do not have a common base class, so an attempt was made to avoid template functions in order not to write a test function for each container, since Qt containers support STL-style iterators.
At the moment, my main function for testing looks like this:
template<typename TEST_CLASS> void runTests(int testCycles) { auto container = makeTestClass<TEST_CLASS>(); using namespace TestProcs; static auto tests = TestProcs::getRegisteredTests<TEST_CLASS>(); std::cout << "Run test for type:" << typeid(TEST_CLASS()).name() << std::endl; for (auto test : tests) { auto warmResultsTest = makeTestResults(*container, test.second, testCycles, true); std::cout << "\"" << test.first << "\" results(ms):" << getResultsString(warmResultsTest) << std::endl; } } 

The testCycles parameter specifies the number of iterations per test. The makeTestClass template function constructs a class for testing. For vectors, it looks like this:
 template<typename TEST_CLASS> std::shared_ptr<TEST_CLASS> makeTestClass() { return std::shared_ptr < TEST_CLASS > (new TEST_CLASS(VECTOR_SIZE, 0)); } 

Well, for QList something like this:
 template<> std::shared_ptr<QList<TestType> > makeTestClass() { return std::shared_ptr < QList<TestType> > (new QList<TestType>( QList<TestType>::fromVector(QVector<TestType>(VECTOR_SIZE)))); } 

TestProcs :: getRegisteredTests returns a vector from the test name and procedure to perform the test on the container.
makeTestResults itself executes the test a specified number of times and returns the vector of the measured execution time for each iteration. According to this data, the average, minimum and maximum value of the test run iteration time is considered.

The list of tests that I conducted



 namespace TestProcs { template<typename CONTAINER> int doAccumulateTest(CONTAINER& container) { typename CONTAINER::value_type sum = typename CONTAINER::value_type(); sum = std::accumulate(container.begin(), container.end(), sum); return sum; } template<typename CONTAINER> int doQtForeachTest(CONTAINER& container) { typename CONTAINER::value_type sum = typename CONTAINER::value_type(); foreach(auto item, container) { sum += item; } return sum; } template<typename CONTAINER> int doNewForTest(CONTAINER& container) { typename CONTAINER::value_type sum = typename CONTAINER::value_type(); for (auto item : container) { sum += item; } return sum; } template<typename CONTAINER> int doSTLForTest(CONTAINER& container) { typename CONTAINER::value_type sum = typename CONTAINER::value_type(); auto it = container.begin(); for (; it != container.end(); ++it) { sum += *it; } return sum; } template<typename CONTAINER> int doSTLForTest2(CONTAINER& container) { typename CONTAINER::value_type sum = typename CONTAINER::value_type(); auto it = container.begin(); auto end = container.end(); for (; it != end; ++it) { sum += *it; } return sum; } template<typename TEST_CLASS> const std::vector<typename Typedefs<TEST_CLASS>::TestProcRecord>& getRegisteredTests() { static const std::vector<typename Typedefs<TEST_CLASS>::TestProcRecord> tests { { "New for", &doNewForTest<TEST_CLASS> }, { "Accumulate", &doAccumulateTest<TEST_CLASS> }, { "Qt foreach", &doQtForeachTest<TEST_CLASS> }, { "STL for", &doSTLForTest<TEST_CLASS> }, { "STL for 2", &doSTLForTest2<TEST_CLASS> } }; return tests; } } 

')

Test results


The list of containers subjected to testing:

The number of iterations for each test = 20.
The size of the container data is 30 megabytes.
Time was measured using the difference in rdtsc divided by
per 100,000.
Actually, the results table (less value means faster):


Graphical presentation of data for the result table:






Total


What I learned for myself by conducting the tests:

My opinion is that you need to stop using the foreach macro in Qt projects.

Thanks for attention.

PS: yes, I know that you can write ">>" without a space.
Source

Source: https://habr.com/ru/post/144905/


All Articles