Rayonで並列処理をするとECBモードの暗号化処理がどのぐらい早くなるか試してみた
こんばんは、リテールアプリ共創部のmorimorikochanです。
前回、S-DESというブロック暗号の暗号化の実装をECB
モードで行いました。
ブロック暗号はブロックに分割しそれぞれに対して暗号化を行ないますが、ECBモードはこれらブロックを並列に処理できるため、処理速度が他のモードと比べ高速です。
しかし、全てのブロックで同じ鍵情報を利用するため、データに一定のパターンが存在すると、データを完全に隠蔽することができていない可能性が存在します。
以下のWikipediaに掲載されている画像を見ていただくとイメージできると思います。
そのため、ECBモードが利用される場面は非常に限定されてきています。
ですが、今回はあえてECBモードの持つ並列処理によりどのぐらいS-DESの暗号化が高速になるのかを、実際に実験してみました。
Rayonとは
RayonはRustでデータを並列に扱うことができるライブラリです。
同様の処理を実現するためには通常、レースコンディションやスレッドの制御などの問題を解決する必要が出てきてしまいますが、Rayonではこの問題を隠蔽してくれています。
実験してみた
条件
条件は以下の通りです。
- Apple M1 Pro
- メモリ 16GB
- cargo 1.74.0 (ecb9851af 2023-10-18)
- rustup 1.26.0 (5af9b9484 2023-04-05)
- edition = "2021"
また、実験に利用したソースコードは以下の通りです。
前回のS-DESの実装をベースに使っています。
ちなみに、Rayonの導入がめちゃくちゃ簡単で驚きました。
今回のケースではすんなり書き換えることができましたが、クロージャがFnMut
の場合は大規模な修正が必要になると思われます。
そもそもFnMut
である時点で並列に処理できない(=何らかの副作用がある)と思うので仕方ないと思いますが...
また、テスト用の平文データとして、IMDb Non-Commercial Datasetsのtitle.basics.tsv.gz
を利用させていただきました。ファイルサイズは約955MBです。
結果
結果は以下のようになりました。
Rayonを利用した並列処理の場合の方が圧倒的に処理速度が早く、直列処理の場合と比べ平均5.4倍の速度で暗号化されました
直列処理の場合 | Rayonを利用した 並列処理の場合 |
|
---|---|---|
1 | 102.09s | 18.85s |
2 | 103.48s | 19.07s |
3 | 102.36s | 19.40s |
平均 | 102.64s | 19.11s |
RayonはデフォルトだとCPUと同じ数だけスレッドを利用します。
By default, Rayon uses the same number of threads as the number of CPUs available. Note that on systems with hyperthreading enabled this equals the number of logical cores and not the physical ones.
https://github.com/rayon-rs/rayon/blob/main/FAQ.md#how-many-threads-will-rayon-spawn
私の環境ではスレッドの数が8
であったため、8スレッドが並列処理を行っていたと考えられます。
ですので単純に考えると8倍早く処理されるはずなのですが、実際には並列処理のためのオーバーヘッドが存在し(スレッドの立ち上げ処理、スレッドの完了状態のチェックなど?)、今回計測したように5.4倍あたりに落ち着いたのではないかと考えられます、
ちなみに、Rayonが利用するスレッドの数はrayon::current_num_threads
で確認できました。
直列の方が速い場合がある?
並列処理のためのオーバーヘッドが存在しているということは、場合によっては直列処理の方が処理速度が早い可能性が十分にあります。
そこで、テスト用の平文データを十分に小さくした場合どのように結果が変わるか調べてみます。
前回の記事で利用したこちらをテスト用の平文データとして試してみました。
plain.txt1234567890 hogehoge 私の名前はmorimorikochanです Diggy-mo!!!
結果は以下の通りでした。
直列処理の場合 | Rayonを利用した 並列処理の場合 |
|
---|---|---|
1 | 10.46µs | 97.00µs |
2 | 11.17µs | 73.63µs |
3 | 8.38µs | 230.79µs |
平均 | 10.00µs | 133.81µs |
予想した通り直列処理の場合の方が処理速度が早いことがわかりました。また、その差は平均値で124µs程度でした。
今回実験したケースでは、Rayonを利用した並列処理の場合は少なくとも平均的に124µs以上のオーバーヘッドが生じていることがわかりました。
まとめ・所感
- Rayonで並列処理をするとECBモードの暗号化処理が速くなった
- 今回検証したケースでは約5.4倍
- しかし、処理対象のデータが小さい場合は直列処理の方が速いことがわかった
- どんな場合もRayonで並列処理をすればいいというわけではないので、ワークロードを適切に見積もる必要性を感じた
- 今回のケースではRayonを利用するための修正箇所が少なく済んだ
Instant
のDebug trait
が自動で単位を出力してくれて地味に便利