Skip to content

Commit

Permalink
Auto merge of #23936 - pnkfelix:rollup, r=pnkfelix
Browse files Browse the repository at this point in the history
This is an attempt to fix #23922
  • Loading branch information
bors committed Apr 1, 2015
2 parents d754722 + 2b71aed commit 8943653
Show file tree
Hide file tree
Showing 284 changed files with 3,820 additions and 5,191 deletions.
1 change: 0 additions & 1 deletion src/compiletest/compiletest.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@
#![feature(std_misc)]
#![feature(test)]
#![feature(path_ext)]
#![feature(convert)]
#![feature(str_char)]

#![deny(warnings)]
Expand Down
4 changes: 0 additions & 4 deletions src/doc/reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -977,17 +977,13 @@ An example of `use` declarations:

```
# #![feature(core)]
use std::iter::range_step;
use std::option::Option::{Some, None};
use std::collections::hash_map::{self, HashMap};
fn foo<T>(_: T){}
fn bar(map1: HashMap<String, usize>, map2: hash_map::HashMap<String, usize>){}
fn main() {
// Equivalent to 'std::iter::range_step(0, 10, 2);'
range_step(0, 10, 2);
// Equivalent to 'foo(vec![std::option::Option::Some(1.0f64),
// std::option::Option::None]);'
foo(vec![Some(1.0f64), None]);
Expand Down
1 change: 1 addition & 0 deletions src/doc/trpl/SUMMARY.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,5 +42,6 @@
* [Intrinsics](intrinsics.md)
* [Lang items](lang-items.md)
* [Link args](link-args.md)
* [Benchmark Tests](benchmark-tests.md)
* [Conclusion](conclusion.md)
* [Glossary](glossary.md)
152 changes: 152 additions & 0 deletions src/doc/trpl/benchmark-tests.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
% Benchmark tests

Rust supports benchmark tests, which can test the performance of your
code. Let's make our `src/lib.rs` look like this (comments elided):

```{rust,ignore}
#![feature(test)]
extern crate test;
pub fn add_two(a: i32) -> i32 {
a + 2
}
#[cfg(test)]
mod tests {
use super::*;
use test::Bencher;
#[test]
fn it_works() {
assert_eq!(4, add_two(2));
}
#[bench]
fn bench_add_two(b: &mut Bencher) {
b.iter(|| add_two(2));
}
}
```

Note the `test` feature gate, which enables this unstable feature.

We've imported the `test` crate, which contains our benchmarking support.
We have a new function as well, with the `bench` attribute. Unlike regular
tests, which take no arguments, benchmark tests take a `&mut Bencher`. This
`Bencher` provides an `iter` method, which takes a closure. This closure
contains the code we'd like to benchmark.

We can run benchmark tests with `cargo bench`:

```bash
$ cargo bench
Compiling adder v0.0.1 (file:///home/steve/tmp/adder)
Running target/release/adder-91b3e234d4ed382a

running 2 tests
test tests::it_works ... ignored
test tests::bench_add_two ... bench: 1 ns/iter (+/- 0)

test result: ok. 0 passed; 0 failed; 1 ignored; 1 measured
```

Our non-benchmark test was ignored. You may have noticed that `cargo bench`
takes a bit longer than `cargo test`. This is because Rust runs our benchmark
a number of times, and then takes the average. Because we're doing so little
work in this example, we have a `1 ns/iter (+/- 0)`, but this would show
the variance if there was one.

Advice on writing benchmarks:


* Move setup code outside the `iter` loop; only put the part you want to measure inside
* Make the code do "the same thing" on each iteration; do not accumulate or change state
* Make the outer function idempotent too; the benchmark runner is likely to run
it many times
* Make the inner `iter` loop short and fast so benchmark runs are fast and the
calibrator can adjust the run-length at fine resolution
* Make the code in the `iter` loop do something simple, to assist in pinpointing
performance improvements (or regressions)

## Gotcha: optimizations

There's another tricky part to writing benchmarks: benchmarks compiled with
optimizations activated can be dramatically changed by the optimizer so that
the benchmark is no longer benchmarking what one expects. For example, the
compiler might recognize that some calculation has no external effects and
remove it entirely.

```{rust,ignore}
#![feature(test)]
extern crate test;
use test::Bencher;
#[bench]
fn bench_xor_1000_ints(b: &mut Bencher) {
b.iter(|| {
(0..1000).fold(0, |old, new| old ^ new);
});
}
```

gives the following results

```text
running 1 test
test bench_xor_1000_ints ... bench: 0 ns/iter (+/- 0)
test result: ok. 0 passed; 0 failed; 0 ignored; 1 measured
```

The benchmarking runner offers two ways to avoid this. Either, the closure that
the `iter` method receives can return an arbitrary value which forces the
optimizer to consider the result used and ensures it cannot remove the
computation entirely. This could be done for the example above by adjusting the
`b.iter` call to

```rust
# struct X;
# impl X { fn iter<T, F>(&self, _: F) where F: FnMut() -> T {} } let b = X;
b.iter(|| {
// note lack of `;` (could also use an explicit `return`).
(0..1000).fold(0, |old, new| old ^ new)
});
```

Or, the other option is to call the generic `test::black_box` function, which
is an opaque "black box" to the optimizer and so forces it to consider any
argument as used.

```rust
#![feature(test)]

extern crate test;

# fn main() {
# struct X;
# impl X { fn iter<T, F>(&self, _: F) where F: FnMut() -> T {} } let b = X;
b.iter(|| {
let n = test::black_box(1000);

(0..n).fold(0, |a, b| a ^ b)
})
# }
```

Neither of these read or modify the value, and are very cheap for small values.
Larger values can be passed indirectly to reduce overhead (e.g.
`black_box(&huge_struct)`).

Performing either of the above changes gives the following benchmarking results

```text
running 1 test
test bench_xor_1000_ints ... bench: 131 ns/iter (+/- 3)
test result: ok. 0 passed; 0 failed; 0 ignored; 1 measured
```

However, the optimizer can still modify a testcase in an undesirable manner
even when using either of the above.
16 changes: 9 additions & 7 deletions src/doc/trpl/concurrency.md
Original file line number Diff line number Diff line change
Expand Up @@ -280,13 +280,15 @@ it returns an `Result<T, E>`, and because this is just an example, we `unwrap()`
it to get a reference to the data. Real code would have more robust error handling
here. We're then free to mutate it, since we have the lock.

This timer bit is a bit awkward, however. We have picked a reasonable amount of
time to wait, but it's entirely possible that we've picked too high, and that
we could be taking less time. It's also possible that we've picked too low,
and that we aren't actually finishing this computation.

Rust's standard library provides a few more mechanisms for two threads to
synchronize with each other. Let's talk about one: channels.
Lastly, while the threads are running, we wait on a short timer. But
this is not ideal: we may have picked a reasonable amount of time to
wait but it's more likely we'll either be waiting longer than
necessary or not long enough, depending on just how much time the
threads actually take to finish computing when the program runs.

A more precise alternative to the timer would be to use one of the
mechanisms provided by the Rust standard library for synchronizing
threads with each other. Let's talk about one of them: channels.

## Channels

Expand Down
13 changes: 7 additions & 6 deletions src/doc/trpl/iterators.md
Original file line number Diff line number Diff line change
Expand Up @@ -243,11 +243,12 @@ for num in nums.iter() {
```

These two basic iterators should serve you well. There are some more
advanced iterators, including ones that are infinite. Like `count`:
advanced iterators, including ones that are infinite. Like using range syntax
and `step_by`:

```rust
# #![feature(core)]
std::iter::count(1, 5);
# #![feature(step_by)]
(1..).step_by(5);
```

This iterator counts up from one, adding five each time. It will give
Expand Down Expand Up @@ -292,11 +293,11 @@ just use `for` instead.
There are tons of interesting iterator adapters. `take(n)` will return an
iterator over the next `n` elements of the original iterator, note that this
has no side effect on the original iterator. Let's try it out with our infinite
iterator from before, `count()`:
iterator from before:

```rust
# #![feature(core)]
for i in std::iter::count(1, 5).take(5) {
# #![feature(step_by)]
for i in (1..).step_by(5).take(5) {
println!("{}", i);
}
```
Expand Down
6 changes: 3 additions & 3 deletions src/doc/trpl/macros.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ number of elements.

```rust
let x: Vec<u32> = vec![1, 2, 3];
# assert_eq!(&[1,2,3], &x);
# assert_eq!(x, [1, 2, 3]);
```

This can't be an ordinary function, because it takes any number of arguments.
Expand All @@ -51,7 +51,7 @@ let x: Vec<u32> = {
temp_vec.push(3);
temp_vec
};
# assert_eq!(&[1,2,3], &x);
# assert_eq!(x, [1, 2, 3]);
```

We can implement this shorthand, using a macro: [^actual]
Expand All @@ -73,7 +73,7 @@ macro_rules! vec {
};
}
# fn main() {
# assert_eq!([1,2,3], vec![1,2,3]);
# assert_eq!(vec![1,2,3], [1, 2, 3]);
# }
```

Expand Down
2 changes: 1 addition & 1 deletion src/doc/trpl/ownership.md
Original file line number Diff line number Diff line change
Expand Up @@ -477,7 +477,7 @@ forbidden in item signatures to allow reasoning about the types just based in
the item signature alone. However, for ergonomic reasons a very restricted
secondary inference algorithm called “lifetime elision” applies in function
signatures. It infers only based on the signature components themselves and not
based on the body of the function, only infers lifetime paramters, and does
based on the body of the function, only infers lifetime parameters, and does
this with only three easily memorizable and unambiguous rules. This makes
lifetime elision a shorthand for writing an item signature, while not hiding
away the actual types involved as full local inference would if applied to it.
Expand Down
Loading

0 comments on commit 8943653

Please sign in to comment.