- UnixパイプのLinuxにおける実装と、パイプ経由でデータを書き込み・読み出しするテストプログラムの最適化方法を探る
- 初期のプログラムは約3.5GiB/sのスループットを持っており、さまざまな最適化によってこれを20倍に向上
- こうした最適化は、Linuxの
perfツールを使ってプログラムをプロファイリングすることで実現
- 本文は、約35GiB/sの速度でパイプに出力を流し込む最適化済みFizzBuzzプログラムに触発されている
- パイプの内部動作、それらへの書き込みと読み出しが遅い理由、そして
vmspliceおよびspliceシステムコールがどのように性能を向上させるかを深く掘り下げる
- Linuxのページングとhuge pagesの使用が、どのようにしてプログラムのより高速なバージョンにつながるかを議論
- 最終的な最適化には、ポーリングをビジーループに置き換えることが含まれる
- テストはIntel Skylake i7-8550U CPUとLinux 5.17で実施
- 本文は、メモリが一定サイズの塊であるページで構成される仕組みと、CPUがページテーブルを用いて仮想アドレスを物理アドレスへ変換する方法を詳しく説明
- 本文は、プログラムでhuge pagesへ切り替えると性能が約50%向上するという観察で結論づけている
- 本文は、CPUにおけるhuge pagesの利用とTranslation Lookaside Buffer (TLB)ミスを減らす方法について議論しており、これが性能向上につながる可能性がある
- カーネルコードは
struct pageが現在のアーキテクチャにおける標準サイズのページを指すと仮定している。huge pagesの場合、"head" struct pageには実際の物理ページに関する情報が含まれ、連続する"tail"ページにはheadページを指すポインタだけが含まれる
- 最近のカーネル(5.17以降)には、headページを明示的に識別する新しい型
struct folioが含まれる。これにより、実行時にstruct pageがheadページかtailページかを確認する必要が減り、性能が向上する
- 本文は、同期コストを回避するためのビジーループという概念について議論している。これは、パイプに書き込めない場合に
vmspliceが返るよう要求し、準備ができるまでビジーループを回し続けるもの。25%の性能向上をもたらしうる一方で、vmspliceの準備が整うまでCPUコアを完全に占有するコストを伴う
- 著者は本文で扱った主要テーマとして、ゼロコピー処理、リングバッファ、ページングと仮想メモリ、同期オーバーヘッドを要約
- 著者はまた、本文で議論していない多くの選択肢や詳細があることも認めており、その理由は関連性が低いか関心の対象外だからだとしている
- 本文は読者から好評を得ており、有益かつ興味深い内容だと受け止められている
1件のコメント
Hacker Newsの意見
vmspliceに焦点を当てているvmspliceの使用では、読み書き時にバッファを慎重に扱う必要があり、複雑ではあるが効率的になりうるsplice()やvmsplice()のようなAPIにも言及しており、これらは大半のプログラムでは使いにくく、活用されていないとされるstdoutから別のプログラムのstdinへマッピングすることで、処理を zerocopy、あるいは最適化が弱い場合でも高速な onecopy にしているperfを使った性能分析に結び付け、そのスループットに対する重要性を強調しているcat、sed、awk、cut、grep、uniq、jqなどのコマンドを繰り返し使い、組み合わせるのに十分だとみなされている