]> git.lizzy.rs Git - rust.git/commit
auto merge of #14174 : stepancheg/rust/once, r=alexcrichton
authorbors <bors@rust-lang.org>
Thu, 15 May 2014 11:16:47 +0000 (04:16 -0700)
committerbors <bors@rust-lang.org>
Thu, 15 May 2014 11:16:47 +0000 (04:16 -0700)
commitf2c4c88ff1236e381ec20f5444abe098b7873180
treeb99c9651748ee458a929e2e7a0b9d21230a1d9c7
parentfedffa785eb1def61d012e8e614d562afaf19a6e
parentf853cf79b568fdffe83729aad4a43cb3c9ff3c92
auto merge of #14174 : stepancheg/rust/once, r=alexcrichton

Submitting PR again, because I cannot reopen #13349, and github does not attach new patch to that PR.

=======

Optimize `Once::doit`: perform optimistic check that initializtion is
already completed.  `load` is much cheaper than `fetch_add` at least
on x86_64.

Verified with this test:

```
static mut o: one::Once = one::ONCE_INIT;
unsafe {
    loop {
        let start = time::precise_time_ns();
        let iters = 50000000u64;
        for _ in range(0, iters) {
            o.doit(|| { println!("once!"); });
        }
        let end = time::precise_time_ns();
        let ps_per_iter = 1000 * (end - start) / iters;
        println!("{} ps per iter", ps_per_iter);

        // confuse the optimizer
        o.doit(|| { println!("once!"); });
    }
}
```

Test executed on Mac, Intel Core i7 2GHz. Result is:
* 20ns per iteration without patch
*  4ns per iteration with this patch applied

Once.doit could be even faster (800ps per iteration), if `doit` function
was split into a pair of `doit`/`doit_slow`, and `doit` marked as
`#[inline]` like this:

```
#[inline(always)]
pub fn doit(&self, f: ||) {
    if self.cnt.load(atomics::SeqCst) < 0 {
        return
    }

    self.doit_slow(f);
}

fn doit_slow(&self, f: ||) { ... }
```