Slide 1

Slide 1 text

1 Rustのパフォーマンスに関するTips Osuke Sudo 2020/11/24 @下町.rs#4

Slide 2

Slide 2 text

2 @zoom_zoomzo Osuke ソフトウェアエンジニア@LayerX ● 暗号技術・TEEを用いたデータのプライバシー保護 ・改ざん耐性手法の研究開発 ● Anonifyの開発

Slide 3

Slide 3 text

3 アジェンダ ● Inlining ● Smaller enum size ● SmallVec / ArrayVec ● Cow

Slide 4

Slide 4 text

4 Inlining

Slide 5

Slide 5 text

5 ● インライン展開: ○ 呼び出される関数のコードをインラインで展開することで関数呼び出しのオーバーヘッドを 削減 ○ バイナリコードサイズは増加 ● 頻繁に呼び出す小さい関数はインライン展開するとパフォーマンスが改善することもある ● 最適化レベルや関数のサイズなどに基づきコンパイラがインライン展開を最適化 Inlining https://github.com/rust-lang/rust/pull/50564/commits/77c40f8c6f8cc472f6438f7724d60bf3b7718a0c

Slide 6

Slide 6 text

6 ● アノテーションをつけることで特定の関数をマニュアルでインライン展開 ● #[inline] ○ crate境界内で、その関数を(できるだけ)インライン展開 ● #[inline(always)] ○ crate境界内で、ほとんどの場合でその関数をインライン展開 ● #[inline(never)] ○ その関数を(できるだけ)インライン展開しない Inlining

Slide 7

Slide 7 text

7 Inlining 同じ関数でも頻繁に呼ばれる箇所はインライン展開、逆にあまり呼ばれない箇所はインライン展開しない https://github.com/rust-lang/rust/pull/64420/commits/a2261ad66400c3145f96ebff0d9b75e910fa89dd

Slide 8

Slide 8 text

8 Smaller enums

Slide 9

Slide 9 text

9 ● Enumの要素のうち、他の要素と比べて大きなサイズの型をBox化 ○ A::Zにヒープ割り当てが必要になる代わりにAのサイズが削減 ■ assert_eq!(std::mem::size_of::(), 108); ■ assert_eq!(std::mem::size_of::(), 16); ○ 特にA::Zの使用が比較的少ない場合、不要なアロケーションを避けることができ るのパフォーマンス向上しやすい Smaller Enums

Slide 10

Slide 10 text

10 Smaller Enums ● x86-64上でSubtypeだけのサイズが大きく120bytes → Box化して32bytes。 https://github.com/rust-lang/rust/pull/64394/commits/7f0637da5144c7435e88ea3805021882f077d50c

Slide 11

Slide 11 text

11 SmallVec

Slide 12

Slide 12 text

12 SmallVec: https://github.com/servo/rust-smallvec ● Vecの代わりにSmallVec<[T; N]>を使うと、N個の要素はスタックに保持され、 N+1個以降の要素はヒープに保持される ● 比較的少数の要素を持つVecがたくさんあるようなケースでアロケーションコストを削 減することが可能 ● 一方、SmallVecはアクセス時に特定の要素がアロケーションされているか、していな いかチェックする必要があるので、通常の操作はVecよりわずかにコスト増 ● 要素数(N)が多かったり、型(T)のサイズが大きかったりするとコピーコストが増 えることがあるので要ベンチマーク

Slide 13

Slide 13 text

13 SmallVec 滅多に要素数が3以上にならないので、SmallVec<[_; 4]>に変更することでベンチマーク4%改善 https://github.com/rust-lang/rust/pull/55383/commits/526dc1421b48e3ee8357d58d997e7a0f4bb26915

Slide 14

Slide 14 text

14 ArrayVec: https://github.com/bluss/arrayvec たくさんの小さいベクタとその最大長が分かるケースでは、アロケーションへのフォールバックがない 分、SmallVecよりArrayVecの方が良い https://github.com/rust-lang/rust/pull/74310/commits/c492ca40a288d8a85353ba112c4d38fe87ef453e

Slide 15

Slide 15 text

15 Cow

Slide 16

Slide 16 text

16 Cow ● 多くの場合read-onlyだが、たまに mutable、毎回Cloneするのは不要なコ スト ● 参照型の状態で所有型やmutationが必 要になったときに、はじめてcloneする ○ Clone-on-write

Slide 17

Slide 17 text

17 Cow ● 参照型と所有型のEnumであるCowを使うと不要なアロケーションを削減できることが ある ● ライフタイムなどコードの複雑性が上がってしまうこともあるので注意

Slide 18

Slide 18 text

18 Cow ● &strを引数にとって、関数内でStringに変換するのは毎回アロケーションが発生 ● 一方、実際に引数に渡すのは&’staticかStringがほとんどのケース https://github.com/rust-lang/rust/pull/56336/commits/787959c20d062d396b97a5566e0a766d963af022

Slide 19

Slide 19 text

19 ● Nicholas Nethercote ○ The Rust Performance Book ■ https://nnethercote.github.io/perf-book/ ○ Blog posts ■ https://blog.mozilla.org/nnethercote/ ● Rust Performance Pitfalls ○ https://llogiq.github.io/2017/06/01/perf-pitfalls.html References