+ RTS -sstderrから開始すると、わずかなショックが発生しました。ほぼ半分の時間がガベージコレクションに費やされました。
ヒープに割り当てられた13,902,917,208バイト
GCでコピーされた3,275,041,156バイト
MUT時間26.69秒(40.10秒経過)
GC時間27.84秒(32.47秒経過)
GC時間の割合51.1%(44.7%経過)
ヒーププロファイラーと集合的マインドへの訴えは、ヒープ内のハッシュテーブルデータを計算の中間結果とインターリーブするとGCを混乱させ、内部テーブルを増やしてコピーするとパフォーマンスが完全に失われると説明しました。 中間データの量を減らすための読み取りコードの最適化ではほとんど何も得られなかったため、ハッシュテーブルを変更する必要があります。
まず、Data.HashTableは、Basic、Cuckoo、およびLinearの3つのハッシュテーブルに置き換えられました。 結果はやや驚くべきものでした。ベーシックとカッコウは全体の動作時間を変更しませんでしたが、同時にGCは最大70%の時間を費やし始めました。 ネイティブコードの動作が速くなり、残りの時間はGCにかかっていました。 メモリのコピーは大幅に少なくなりました。
基本:
ヒープに割り当てられた12,781,006,960バイト
GC中にコピーされた408,935,780バイト
MUT時間15.00秒(15.16秒経過)
GC時間43.29秒(43.79秒経過)
GC時間の割合74.3%(74.3%経過)
カッコウ:
ヒープに割り当てられた11,611,257,712バイト
GC中にコピーされた419,308,168バイト
MUT時間17.31秒(17.65秒経過)
GC時間38.08秒(38.42秒経過)
%GC時間68.7%(68.5%経過)
線形テーブルは、予想されるとおり、完全に異なるシナリオを対象としており、すぐに競合他社から離れます。
ヒープに割り当てられた12,547,294,380バイト
GC中にコピーされた17,997,812,764バイト
MUT時間26.65秒(27.16秒経過)
GC時間123.72秒(124.30秒経過)
GC時間の割合82.3%(82.1%経過)
テーブルとCuckooHashTableの最初の正しいサイズを示す読み取りコードの最適化がさらにいくつか行われ、自信を持ってリードしました。
ヒープに割り当てられた3,835,164,148バイト
GC中にコピーされた179,941,588バイト
MUT時間7.84秒(7.97秒経過)
GC時間20.05秒(20.18秒経過)
GC時間の割合71.9%(71.7%経過)
合計ランタイムはすでに半分になっていますが、GCで70%ですか? コンサバトリーで何かを変更する必要があります。
Data.Judyはjudyテーブル実装のラッパーであり、GCに完全には該当せず、ゲームのルールを決定的に変更します。
ヒープに割り当てられた5,366,256,252バイト
GC中にコピーされた3,725,456バイト
MUT時間8.99秒(9.12秒経過)
GC時間1.44秒(1.45秒経過)
%GC時間13.4%(経過13.3%)
ヒーププロファイルは、割り当てられたメモリの量がまったく変わらないことを示しています。水平な水平線、すべてのデータはGCアクセス外です。
3つの欠点:
- -fvia-Cをスローしてパッケージにパッチを適用する必要がありますが、この完全に理解できないリンクエラーは発生しません。
- WordからWordに厳密にマッピングするため、Word64キーの場合は配列の配列を作成する必要があります。 ByteStringの格納例はソースにありますが、それでも不要な作業です。
- そして最後に、Cでは、これらすべてを直接書くことができます! Haskellは私たちと一緒に、どこで?
残っているものは何ですか? もちろん、Data.Map。 IOなし、Cなし、きれいに見える真のhaskellコード。 結果は突然です:
ヒープに割り当てられた5,569,024,484バイト
GC中にコピーされた4,241,345,748バイト
MUT時間18.55秒(18.77秒経過)
GC時間12.66秒(13.07秒経過)
%GC時間40.6%(41.1%経過)
CuckooHashTableよりも10%だけ遅く、Data.HashTableとの比較はまったくありません。 「考える必要はありません、振るだけ」の既製のイラスト:完全に簡単なコードを書くことができ、損失がほとんど見えないのに、なぜこれらすべてのダンスですか?
そして、Data.HashMap.Strictを使用した順序付けられていないコンテナの最後のコードは、Data.Mapの即座の置き換えです。インポートと構造タイプを変更するだけで、残りは互換性があります。
ヒープに割り当てられた5,688,939,936バイト
GC中にコピーされた3,659,088,964バイト
最大227,864,212バイトの常駐(23サンプル(s))
MUT時間10.16秒(10.75秒経過)
GC時間8.93秒(9.61秒経過)
GC時間の割合46.8%(47.2%経過)
コピーされた多くの、プロファイル上の明確に目に見えるテーブルの再割り当て。 + RTS -A250Mを使用して、もう少し多くのメモリをスリップしてみましょう。
ヒープに割り当てられた5,663,421,460バイト
GC中にコピーされた887,689,168バイト
MUT時間11.40秒(11.70秒経過)
GC時間3.61秒(3.83秒経過)
%GC時間24.1%(24.7%経過)
多田! ジュディは足りませんが、他のすべてのオプションは残されています。 無料のボーナスとして、Data.Mapと同じバンズ:ハッシュテーブルのように、キーをハッシュ変換に書き込む必要はありません。モナドにすべてを入れる必要はありません。コードは2倍短くなります。
まあ、伝統的な結論:時期尚早な最適化はすべての悪の根源です。 正面のソリューションは、他のソリューションよりも高速です。