Skip to content

Commit 7d3e324

Browse files
committed
Merge pull request #98 from pocket7878/benchmark-test
6.7. Benchmark tests
2 parents ccafb9c + 15c09f9 commit 7d3e324

File tree

1 file changed

+88
-51
lines changed

1 file changed

+88
-51
lines changed

1.6/ja/book/benchmark-tests.md

Lines changed: 88 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
1-
% Benchmark tests
1+
% ベンチマークテスト
2+
<!-- % Benchmark tests -->
23

3-
Rust supports benchmark tests, which can test the performance of your
4-
code. Let's make our `src/lib.rs` look like this (comments elided):
4+
<!-- Rust supports benchmark tests, which can test the performance of your -->
5+
<!-- code. Let's make our `src/lib.rs` look like this (comments elided): -->
6+
Rustはコードのパフォーマンスをテストできるベンチマークテストをサポートしています。
7+
早速、 `src/lib.rc` を以下のように作っていきましょう(コメントは省略しています):
58

69
```rust,ignore
710
#![feature(test)]
@@ -29,15 +32,21 @@ mod tests {
2932
}
3033
```
3134

32-
Note the `test` feature gate, which enables this unstable feature.
35+
<!-- Note the `test` feature gate, which enables this unstable feature. -->
36+
不安定なベンチマークのフィーチャを有効にするため、 `test` フィーチャゲートを利用していることに注意して下さい。
3337

34-
We've imported the `test` crate, which contains our benchmarking support.
35-
We have a new function as well, with the `bench` attribute. Unlike regular
36-
tests, which take no arguments, benchmark tests take a `&mut Bencher`. This
37-
`Bencher` provides an `iter` method, which takes a closure. This closure
38-
contains the code we'd like to benchmark.
38+
<!-- We've imported the `test` crate, which contains our benchmarking support. -->
39+
<!-- We have a new function as well, with the `bench` attribute. Unlike regular -->
40+
<!-- tests, which take no arguments, benchmark tests take a `&mut Bencher`. This -->
41+
<!-- `Bencher` provides an `iter` method, which takes a closure. This closure -->
42+
<!-- contains the code we'd like to benchmark. -->
43+
ベンチマークテストのサポートを含んだ `test` クレートをインポートしています。
44+
また、 `bench` アトリビュートのついた新しい関数を定義しています。
45+
引数を取らない通常のテストとは異なり、ベンチマークテストは `&mut Bencher` を引数に取ります。
46+
`Bencher` はベンチマークしたいコードを含んだクロージャを引数に取る `iter` メソッドを提供しています。
3947

40-
We can run benchmark tests with `cargo bench`:
48+
<!-- We can run benchmark tests with `cargo bench`: -->
49+
ベンチマークテストは以下のように `cargo bench` のようにして実施できます:
4150

4251
```bash
4352
$ cargo bench
@@ -51,31 +60,46 @@ test tests::bench_add_two ... bench: 1 ns/iter (+/- 0)
5160
test result: ok. 0 passed; 0 failed; 1 ignored; 1 measured
5261
```
5362

54-
Our non-benchmark test was ignored. You may have noticed that `cargo bench`
55-
takes a bit longer than `cargo test`. This is because Rust runs our benchmark
56-
a number of times, and then takes the average. Because we're doing so little
57-
work in this example, we have a `1 ns/iter (+/- 0)`, but this would show
58-
the variance if there was one.
59-
60-
Advice on writing benchmarks:
61-
62-
63-
* Move setup code outside the `iter` loop; only put the part you want to measure inside
64-
* Make the code do "the same thing" on each iteration; do not accumulate or change state
65-
* Make the outer function idempotent too; the benchmark runner is likely to run
66-
it many times
67-
* Make the inner `iter` loop short and fast so benchmark runs are fast and the
68-
calibrator can adjust the run-length at fine resolution
69-
* Make the code in the `iter` loop do something simple, to assist in pinpointing
70-
performance improvements (or regressions)
71-
72-
## Gotcha: optimizations
73-
74-
There's another tricky part to writing benchmarks: benchmarks compiled with
75-
optimizations activated can be dramatically changed by the optimizer so that
76-
the benchmark is no longer benchmarking what one expects. For example, the
77-
compiler might recognize that some calculation has no external effects and
78-
remove it entirely.
63+
<!-- Our non-benchmark test was ignored. You may have noticed that `cargo bench` -->
64+
<!-- takes a bit longer than `cargo test`. This is because Rust runs our benchmark -->
65+
<!-- a number of times, and then takes the average. Because we're doing so little -->
66+
<!-- work in this example, we have a `1 ns/iter (+/- 0)`, but this would show -->
67+
<!-- the variance if there was one. -->
68+
ベンチマークでないテストは無視されます。
69+
`cargo bench``cargo test` よりも時間がかかることにお気づきになったかもしれません。
70+
これは、Rustがベンチマークをかなりの回数繰り返し実行し、その結果の平均を取るためです。
71+
今回のコードでは非常に小さな処理しか行っていないために、 `1 ns/iter (+/- 0)` という結果を得ました、
72+
しかし、この結果は変動することがあるでしょう。
73+
74+
<!-- Advice on writing benchmarks: -->
75+
以下は、ベンチマークを書くときのアドバイスです:
76+
77+
78+
<!-- * Move setup code outside the `iter` loop; only put the part you want to measure inside -->
79+
<!-- * Make the code do "the same thing" on each iteration; do not accumulate or change state -->
80+
<!-- * Make the outer function idempotent too; the benchmark runner is likely to run -->
81+
<!-- it many times -->
82+
<!-- * Make the inner `iter` loop short and fast so benchmark runs are fast and the -->
83+
<!-- calibrator can adjust the run-length at fine resolution -->
84+
<!-- * Make the code in the `iter` loop do something simple, to assist in pinpointing -->
85+
<!-- performance improvements (or regressions) -->
86+
* セットアップのコードを `iter` の外に移し、計測したい箇所のみを `iter` の中に書きましょう。
87+
* それぞれの繰り返しでコードが「同じこと」をするようにし、集計をしたり状態を変更したりといったことはしないで下さい。
88+
* 利用している外部の関数についても冪等にしましょう、ベンチマークはその関数をおそらく何度も実行します。
89+
* 内側の `iter` ループを短く高速にしましょう、そうすることでベンチマークの実行は高速になり、キャリブレータは実行の長さをより良い精度で補正できるようになります。
90+
* パフォーマンスの向上(または低下)をピンポイントで突き止められるように、`iter` ループ中のコードの処理を簡潔にしましょう。
91+
92+
<!-- ## Gotcha: optimizations -->
93+
## 注意点: 最適化
94+
95+
<!-- There's another tricky part to writing benchmarks: benchmarks compiled with -->
96+
<!-- optimizations activated can be dramatically changed by the optimizer so that -->
97+
<!-- the benchmark is no longer benchmarking what one expects. For example, the -->
98+
<!-- compiler might recognize that some calculation has no external effects and -->
99+
<!-- remove it entirely. -->
100+
ベンチマークを書くときに気をつけなければならないその他の点は: 最適化を有効にしてコンパイルしたベンチマークは劇的に最適化され、
101+
もはや本来ベンチマークしたかったコードとは異なるという点です。
102+
たとえば、コンパイラは幾つかの計算がなにも外部に影響を及ぼさないことを認識してそれらの計算を取り除くかもしれません。
79103

80104
```rust,ignore
81105
#![feature(test)]
@@ -91,7 +115,8 @@ fn bench_xor_1000_ints(b: &mut Bencher) {
91115
}
92116
```
93117

94-
gives the following results
118+
<!-- gives the following results -->
119+
このベンチマークは以下の様な結果となります
95120

96121
```text
97122
running 1 test
@@ -100,24 +125,32 @@ test bench_xor_1000_ints ... bench: 0 ns/iter (+/- 0)
100125
test result: ok. 0 passed; 0 failed; 0 ignored; 1 measured
101126
```
102127

103-
The benchmarking runner offers two ways to avoid this. Either, the closure that
104-
the `iter` method receives can return an arbitrary value which forces the
105-
optimizer to consider the result used and ensures it cannot remove the
106-
computation entirely. This could be done for the example above by adjusting the
107-
`b.iter` call to
128+
<!-- The benchmarking runner offers two ways to avoid this. Either, the closure that -->
129+
<!-- the `iter` method receives can return an arbitrary value which forces the -->
130+
<!-- optimizer to consider the result used and ensures it cannot remove the -->
131+
<!-- computation entirely. This could be done for the example above by adjusting the -->
132+
<!-- `b.iter` call to -->
133+
ベンチマークランナーはこの問題を避ける2つの手段を提供します。
134+
`iter` メソッドが受け取るクロージャは任意の値を返すことができ、
135+
オプティマイザに計算の結果が利用されていると考えさせ、その計算を取り除くことができないと保証することができます。
136+
これは、上のコードにおいて `b.iter` の呼出を以下のようにすることで可能です:
108137

109138
```rust
110139
# struct X;
111140
# impl X { fn iter<T, F>(&self, _: F) where F: FnMut() -> T {} } let b = X;
112141
b.iter(|| {
113-
// note lack of `;` (could also use an explicit `return`).
142+
# // note lack of `;` (could also use an explicit `return`).
143+
// `;` が無いことに注意して下さい (明示的な `return` を使うこともできます)。
114144
(0..1000).fold(0, |old, new| old ^ new)
115145
});
116146
```
117147

118-
Or, the other option is to call the generic `test::black_box` function, which
119-
is an opaque "black box" to the optimizer and so forces it to consider any
120-
argument as used.
148+
<!-- Or, the other option is to call the generic `test::black_box` function, which -->
149+
<!-- is an opaque "black box" to the optimizer and so forces it to consider any -->
150+
<!-- argument as used. -->
151+
もう一つの方法としては、ジェネリックな `test::black_box` 関数を呼び出すという手段が有ります、
152+
`test::black_box` 関数はオプティマイザにとって不透明な「ブラックボックス」であり、
153+
オプティマイザに引数のどれもが利用されていると考えさせることができます。
121154

122155
```rust
123156
#![feature(test)]
@@ -135,11 +168,14 @@ b.iter(|| {
135168
# }
136169
```
137170

138-
Neither of these read or modify the value, and are very cheap for small values.
139-
Larger values can be passed indirectly to reduce overhead (e.g.
140-
`black_box(&huge_struct)`).
171+
<!-- Neither of these read or modify the value, and are very cheap for small values. -->
172+
<!-- Larger values can be passed indirectly to reduce overhead (e.g. -->
173+
<!-- `black_box(&huge_struct)`). -->
174+
2つの手段のどちらも値を読んだり変更したりせず、小さな値に対して非常に低コストです。
175+
大きな値は、オーバーヘッドを減らすために間接的に渡すことができます(例: `black_box(&huge_struct)`)。
141176

142-
Performing either of the above changes gives the following benchmarking results
177+
<!-- Performing either of the above changes gives the following benchmarking results -->
178+
上記のどちらかの変更を施すことでベンチマークの結果は以下のようになります
143179

144180
```text
145181
running 1 test
@@ -148,5 +184,6 @@ test bench_xor_1000_ints ... bench: 131 ns/iter (+/- 3)
148184
test result: ok. 0 passed; 0 failed; 0 ignored; 1 measured
149185
```
150186

151-
However, the optimizer can still modify a testcase in an undesirable manner
152-
even when using either of the above.
187+
<!-- However, the optimizer can still modify a testcase in an undesirable manner -->
188+
<!-- even when using either of the above. -->
189+
しかしながら、上のどちらかの方法をとったとしても依然オプティマイザはテストケースを望まない形で変更する場合があります。

0 commit comments

Comments
 (0)