コンテナー要素の合計を計算する際の、範囲ベースのfor、foreach(Qt)、およびSTLの一部の速度の比較

Qtフレームワークを使用してC ++プロジェクトの開発に携わっています。 このプロジェクトでは、Qtコンテナが多くの場所で使用されており、要素を走査するためにforeachマクロがよく使用されます。 ある時点で、このマクロの使用がどの程度正当化されるのか疑問に思いました。 さらに、実際にc ++ 11を「感じ」たいと思いました。 そして、ここに私が現時点で見つけたものがあります...



ヘルパー関数の作成



STLとQtのコンテナには共通の基本クラスがないため、QtコンテナはSTLスタイルのイテレータをサポートしているため、各コンテナにテスト関数を記述しないようにテンプレート関数を省こうとしました。

現時点では、テストの主な機能は次のようになっています。

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; } }
      
      





testCyclesパラメーターは、1つのテストの反復回数を設定します。 makeTestClassテンプレート関数は、テスト用のクラスを構築します。 ベクトルの場合、次のようになります。

 template<typename TEST_CLASS> std::shared_ptr<TEST_CLASS> makeTestClass() { return std::shared_ptr < TEST_CLASS > (new TEST_CLASS(VECTOR_SIZE, 0)); }
      
      





さて、QListの場合は次のようになります。

 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は、テストの名前とコンテナーでテストを実行する手順からベクトルを返します。

makeTestResultsは、実際に指定された回数だけテストを起動し、各反復の測定された実行時間のベクトルを返します。 これらのデータによると、テストの反復実行時間の平均値、最小値、および最大値が考慮されます。



私が実施したテストのリスト





 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; } }
      
      







試験結果



テストされたコンテナのリスト:



各テストの反復回数= 20。

コンテナのデータサイズは30メガバイトです。

rdtscを除算して時間を測定しました

100,000あたり。

実際、結果テーブル(値が小さいほど高速になります):





結果表のデータのグラフィカル表現:













まとめ



テストを実施することで自分自身で実現したこと:



私の意見では、Qtプロジェクトでforeachマクロの使用を拒否すべきだと思います。



ご清聴ありがとうございました。



PS:はい、スペースなしで ">>"を書くことができることを知っています。

ソースコード



All Articles