0

これは、この MICの質問に対するフォローアップの質問です。参照ラッパーのベクトルにアイテムを追加するとき、選択した反復アプローチに関係なく、約 80% の時間を ++ 演算子内で費やします。
クエリは次のように機能します

VersionView getVersionData(int subdeliveryGroupId, int retargetingId,
                             const std::wstring &flightName) const {
    VersionView versions;
    for (auto i = 0; i < 3; ++i) {
      for (auto j = 0; j < 3; ++j) {
        versions.insert(m_data.get<mvKey>().equal_range(boost::make_tuple(subdeliveryGroupId + i, retargetingId + j,
                                 flightName)));
      }
    }
    return versions;
  }

参照ラッパーを埋めるために次の方法を試しました

template <typename InputRange> void insert(const InputRange &rng) {
    // 1)   base::insert(end(), rng.first, rng.second); // 12ms
    // 2)   std::copy(rng.first, rng.second, std::back_inserter(*this)); // 6ms
    /* 3)   size_t start = size();  // 12ms
                    auto tmp = std::reference_wrapper<const
       VersionData>(VersionData(0,0,L""));
                    resize(start + boost::size(rng), tmp);
                    auto beg = rng.first;
                    for (;beg != rng.second; ++beg, ++start)
                    {
                         this->operator[](start) = std::reference_wrapper<const VersionData>(*beg);
                    }
    */
    std::copy(rng.first, rng.second, std::back_inserter(*this));
  }

何をするにしても、演算子 ++ またはイテレータをインクリメントするだけの size メソッドの料金を支払います。つまり、まだ ++ で立ち往生しています。したがって、問題は、結果の範囲をより速く反復する方法があるかどうかです。そのような方法がない場合は、範囲を作成する代わりに結果で満たされる reference_wrapper のコンテナへの参照を保持する新しい引数を追加する equal_range の実​​装を試す価値がありますか?

編集 1: サンプル コード http://coliru.stacked-crooked.com/a/8b82857d302e4a06/
このバグのため、Coliru ではコンパイルされません
編集 2: コール ツリー、演算子 ++ で費やされた時間
コールツリー ホットパス 編集 3: いくつかの具体的なもの。まず第一に、operator++ が全体の実行時間に時間がかかりすぎるという理由だけでこのスレッドを開始しませんでした。単に「という理由で」好きではありませんが、現時点ではパフォーマンス テストの主要なボトルネックになっています。通常、各リクエストは数百マイクロ秒で処理されますが、これと同様のリクエスト (やや複雑です) は 1000 ~ 1500 マイクロ秒で処理され、それでも許容されます。元々の問題は、データ構造の項目数が数十万に達すると、パフォーマンスが 20 ミリ秒程度に低下することでした。MIC に切り替えた後 (コードの可読性、保守性、および全体的なエレガンスが大幅に改善されました)、リクエストごとに 13 ミリ秒程度に達することができ、そのうち 80% ~ 90% が operator++ に費やされました。これをどうにかして改善できるかどうか、それともタールと羽毛を探すべきかという質問です。:)

4

4 に答える 4

1

vector@kreuzerkrieg、あなたのサンプルコードはofへのいかなる種類の挿入も実行しませんstd::reference_wrapper! 代わりに、の結果equal_rangeを aboost::any_rangeに射影しています。これは、反復時にかなり遅くなると予想されます。基本的に、ops の増分は仮想呼び出しに解決されます。

したがって、ここで何かを深刻に見逃していない限り、サンプル コードのパフォーマンスまたはその欠如は、実際のコードでの問題とは何の関係もありません (VersionViewコードを表示していない が を使用していないと仮定しますboost::any_range)。

とはいえ、順序付けられたインデックスを同等のハッシュ化されたインデックスに置き換える余裕がある場合、反復はおそらく高速になりますが、実際のものを表示していないことを考えると、これは暗闇の中での完全なショットです.

于 2014-12-24T19:20:09.260 に答える
1

あなたは完全に間違ったものを測定していると思います。3x3x11111 から 10x10x111111 (つまり、インデックス内の項目数が 111 倍) にスケールアップしても、290 ミリ秒で実行されます。

そして、データを取り込むには桁違いに時間がかかります。コンテナの割り当て解除にも時間がかかるようです。

重要でないことは何ですか?

私はいくつかのトレードオフを伴うバージョンを寄稿しました。これは主に、微調整に意味がないことを示しています。View On Coliru

  • を回避するためのスイッチがありany_rangeます(パフォーマンスを気にする場合は、それを使用しても意味がありません)
  • フライウェイトを微調整するスイッチがあります。

    #define USE_FLYWEIGHT 0 // 0: none 1: full 2: no tracking 3: no tracking no locking
    

    繰り返しますが、これはなくても簡単にできることを示しているだけであり、文字列 (?) のメモリ最適化が必要でない限り、そうすることを検討する必要があります。OPTIMIZE_ATOMSその場合は、次のアプローチの使用を検討してください。

  • 基本的にそこにOPTIMIZE_ATOMSウェイトを飛ばしwstringます。すべての文字列がここで繰り返されるため、ストレージ効率が大幅に向上します (ただし、実装は迅速かつダーティであり、改善する必要があります)。このアイデアは、ここでより適切に適用されます:ブースト interval_map ルックアップのパフォーマンスを向上させる方法

基本的なタイミングは次のとおりです。

ここに画像の説明を入力

ご覧のとおり、基本的に、クエリ/反復のパフォーマンスにとって実際には何も重要ではありません

任意のイテレータ: それらは重要ですか?

コンパイラの原因である可能性があります。私のコンパイル (gcc 4.8.2) では、それほど大きなものではありませんでしたが、反復子を使用しない累積ループの逆アセンブリを確認してください。

ここに画像の説明を入力

私がハイライトしたセクションからわかるように、アルゴリズム、ラムダ、イテレータ トラバーサルからはあまり太っていないようです。現在 any_iterator を使用すると、状況はあまり明確ではなくなります。コンパイルの最適化が不十分な場合、基本操作をインライン化できず、反復が遅くなることが想像できます。(今はちょっと推測です)

于 2014-12-25T01:59:15.983 に答える
1

getVersionDataの実行時間の80% が に費やされているという事実は、operator++それ自体がパフォーマンスの問題を示しているわけではありません。別の言い方をすれば、コードの一部をプロファイリングすると、通常、最も時間がかかる場所が見つかりますが、これが問題になるかどうかは、必要な全体的なパフォーマンスによって異なります。equal_rangestd::reference_wrapper

于 2014-12-24T12:09:55.073 に答える