[論文レビュー] BlockQuicksort: How Branch Mispredictions don't affect Quicksort
BlockQuicksort は、固定サイズのブロック(例:128 要素)にデータを分割し、比較結果をバッファに格納することで、Quicksort における分岐予測誤りを排除する新しい in-place ソーティングアルゴリズムである。このアプローチにより、平均的な分岐予測誤り数が最大で $\epsilon n\log n + \mathcal{O}(n)$ に抑えられ、乱数データに対して GCC の std::sort よりも 80% 以上高速に動作し、特定のワークロードでは Super Scalar Sample Sort 即ち、より高いパフォーマンスを発揮する。
Since the work of Kaligosi and Sanders (2006), it is well-known that Quicksort -- which is commonly considered as one of the fastest in-place sorting algorithms -- suffers in an essential way from branch mispredictions. We present a novel approach to address this problem by partially decoupling control from data flow: in order to perform the partitioning, we split the input in blocks of constant size (we propose 128 data elements); then, all elements in one block are compared with the pivot and the outcomes of the comparisons are stored in a buffer. In a second pass, the respective elements are rearranged. By doing so, we avoid conditional branches based on outcomes of comparisons at all (except for the final Insertionsort). Moreover, we prove that for a static branch predictor the average total number of branch mispredictions is at most $εn \log n + O(n)$ for some small $ε$ depending on the block size when sorting $n$ elements. Our experimental results are promising: when sorting random integer data, we achieve an increase in speed of 80% over the GCC implementation of C++ std::sort. Also for many other types of data and non-random inputs, there is still a significant speedup over std::sort. Only in few special cases like sorted or almost sorted inputs, std::sort can beat out implementation. Moreover, even on random input permutations, our implementation is even slightly faster than an implementation of the highly tuned Super Scalar Sample Sort, which uses a linear amount of additional space.
研究の動機と目的
- 現代のパイipelライン処理機における分岐予測誤りによって引き起こされる Quicksort のパフォーマンス劣化を是正すること。
- 複雑なピボット選択や外部メモリに依存せずに、分岐予測誤りを最小限に抑えた in-place ソーティングアルゴリズムを設計すること。
- 乱数、ほぼソート済み、重複が多いなど多様なデータタイプにおいても高いパフォーマンスを維持すること。
- Super Scalar Sample Sort や高度に最適化されたアルゴリズムと同等のパフォーマンスを達成しながら、in-place なままに保つこと。
提案手法
- 制御フローをデータ依存の比較から分離するために、入力配列を固定サイズのブロック(例:128 要素)に分割する。
- 各ブロックに対して、すべての要素をピボットと比較し、比較結果(例:「小さい」または「大きい」)をバッファに格納する。これにより、比較中は条件分岐を避けることができる。
- すべての比較が終了した後、2 回目のパスで、格納された比較結果に基づいて要素を再配置することで、パーティショニング中にデータ依存の分岐を排除する。
- 再帰のベースケースとして挿入ソートを使用するが、バッファの使用とブロック処理を最適化して、全体の分岐予測誤り数を削減する。
- 静的分岐予測モデルを適用し、分岐予測誤り数を理論的に $\\epsilon n\\log n + \mathcal{O}(n)$ に制限する。ここで $\\epsilon$ はブロックサイズに依存する。
- ピボット選択に median-of-$\\sqrt{n}$ または median-of-5 を使用し、パフォーマンスと予測可能性のバランスを取る。
実験結果
リサーチクエスチョン
- RQ1制御フローの意思決定から比較結果を分離することで、Quicksort における分岐予測誤りを顕著に低減できるか?
- RQ2ブロック単位で比較結果をバッファリングすることで、深いつながりパイプラインを持つ現代プロセッサ上で、測定可能なパフォーマンス向上が得られるか?
- RQ3動的メモリ割り当てを避ける in-place ソーティングアルゴリズムが、Super Scalar Sample Sort や高度に最適化されたアルゴリズムと同等またはそれ以上のパフォーマンスを達成できるか?
- RQ4ブロックベースのアプローチは、乱数、ほぼソート済み、重複が多いなど多様な入力タイプにおいて、どのように動作するか?
- RQ5理論的な分岐予測誤り数の上限は実際の動作でも達成可能か?また、ブロックサイズに応じてスケーリングするか?
主な発見
- 静的分岐予測モデルの下で、BlockQuicksort は平均的な分岐予測誤り数を $\\epsilon n\\log n + \mathcal{O}(n)$ に抑え、$\\epsilon$ は小さくブロックサイズに依存する。
- 乱数整数データに対して、BlockQuicksort は GCC の std::sort よりも 80% 以上の高いスループット(1 秒あたりにソート可能な要素数)を達成する。
- テストされたすべてのデータタイプ(乱数順列、ほぼソート済み配列、重複の多いデータなど)において、std::sort を上回るパフォーマンスを発揮するが、すでにソート済みの入力のような稀なケースを除く。
- 乱数順列においても、線形の追加メモリを必要とする Super Scalar Sample Sort よりもわずかに高速である。これは、より優れた分岐予測とキャッシュ動作によるものである。
- 命令数とキャッシュミス率が低く抑えられ、平均して 1 要素あたり 2.25 回の分岐予測誤りに留まり、std::sort の 10.23 よりも顕著に低い。
- 重複チェック(dc)と median-of-$\\sqrt{n}$ ピボット選択の使用により、重複要素を含むデータにおいてパフォーマンスがさらに向上する。
より良い研究を、今すぐ始めましょう
論文の読解から最終レビューまで、研究時間を劇的に削減しましょう。
クレジットカード登録不要
このレビューはAIが作成し、人間の編集者が確認しました。