Closed
Description
Consider this code:
#![crate_type="lib"]
#![crate_id="test"]
extern crate test;
extern crate rand;
use test::Bencher;
use rand::{weak_rng, Rng};
use std::cell::Cell;
fn bug(a: &Vector)
{
for _ in range(0, 100)
{
let m = Multiplier::new(a, a);
for i in range(0u, 10)
{
unsafe
{
a.unsafe_set(i, m.unsafe_get(i));
}
}
}
let mut sum = 0f32;
for i in range(0u, 10)
{
unsafe
{
sum += a.unsafe_get(i);
}
}
assert!(sum != 96.0);
}
#[bench]
fn vec_speed_vec1(bh: &mut Bencher) {
let mut rng = weak_rng();
let a = &Vector::new(rng.gen_vec(10).slice(0, 10));
bh.iter(|| {
bug(a)
})
}
#[bench]
fn vec_speed_vec2(bh: &mut Bencher) {
let mut rng = weak_rng();
let a = &Vector::new(rng.gen_vec(10).slice(0, 10));
bh.iter(|| {
for _ in range(0, 100)
{
let m = Multiplier::new(a, a);
for i in range(0u, 10)
{
unsafe
{
a.unsafe_set(i, m.unsafe_get(i));
}
}
}
let mut sum = 0f32;
for i in range(0u, 10)
{
unsafe
{
sum += a.unsafe_get(i);
}
}
assert!(sum != 96.0);
})
}
pub trait VectorGet
{
unsafe fn unsafe_get(&self, idx: uint) -> f32;
}
pub trait VectorSet
{
unsafe fn unsafe_set(&self, idx: uint, val: f32);
}
pub struct Vector
{
data: Vec<Cell<f32>>
}
impl Vector
{
pub fn new(data: &[f32]) -> Vector
{
Vector{ data: data.iter().map(|&v| Cell::new(v)).collect() }
}
}
impl<'l>
VectorGet for
&'l Vector
{
unsafe fn unsafe_get(&self, idx: uint) -> f32
{
(*self.data.as_slice().unsafe_ref(idx)).get()
}
}
impl<'l>
Container for
&'l Vector
{
fn len(&self) -> uint
{
self.data.len()
}
}
impl<'l>
VectorSet for
Vector
{
unsafe fn unsafe_set(&self, idx: uint, val: f32)
{
self.data.as_slice().unsafe_ref(idx).set(val);
}
}
impl<'l>
Container for
Vector
{
fn len(&self) -> uint
{
self.data.len()
}
}
pub struct Multiplier<TA, TB>
{
a: TA,
b: TB,
}
impl<TA: Container,
TB: Container>
Multiplier<TA, TB>
{
pub fn new(a: TA, b: TB) -> Multiplier<TA, TB>
{
assert!(a.len() == b.len());
Multiplier{ a: a, b: b }
}
}
impl<'l,
TA: VectorGet + Container,
TB: VectorGet + Container>
VectorGet for
Multiplier<TA, TB>
{
unsafe fn unsafe_get(&self, idx: uint) -> f32
{
self.a.unsafe_get(idx) * self.b.unsafe_get(idx)
}
}
impl<'l,
TA: Container,
TB: Container>
Container for Multiplier<TA, TB>
{
fn len(&self) -> uint
{
self.a.len()
}
}
Compiling and running it gives the following result:
$ rustc test.rs --test --opt-level 3
$ ./test --bench
running 2 tests
test vec_speed_vec1 ... bench: 498 ns/iter (+/- 17)
test vec_speed_vec2 ... bench: 1386 ns/iter (+/- 313)
test result: ok. 0 passed; 0 failed; 0 ignored; 2 measured
Note that the only difference between the two tests is that one has the Bencher closure contents hoisted out into a separate function. This speed difference is a regression since at least January 2014.