Skip to content

Commit

Permalink
Show that #[cold] attribute is not propagated to child crates
Browse files Browse the repository at this point in the history
Adding `#[cold]` attribute inside lazy_static makes a measurable difference:

  λ cargo +nightly run --release --example bench
      Finished release [optimized] target(s) in 0.00s
       Running `target/release/examples/bench`
  706.647812ms

  λ cargo +nightly run --release --example bench --features cold
      Finished release [optimized] target(s) in 0.00s
       Running `target/release/examples/bench`
  475.424509ms

However, because Once has #[cold] internally, this shouldn't have any
effect?
  • Loading branch information
matklad committed Sep 1, 2019
1 parent 4216696 commit 7863cc0
Show file tree
Hide file tree
Showing 4 changed files with 52 additions and 6 deletions.
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ optional = true

[features]
spin_no_std = ["spin"]
cold = []

[dev-dependencies]
doc-comment = "0.3.1"
Expand Down
31 changes: 31 additions & 0 deletions examples/bench.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
#[macro_use]
extern crate lazy_static;

use std::thread;
use std::time;

const N_THREADS: usize = 32;
const N_ROUNDS: usize = 100_000_000;

lazy_static! {
static ref XS: Vec<String> = vec!["Spica".to_string(), "Hoyten".to_string()];
}

fn main() {
let start = time::Instant::now();
let threads = (0..N_THREADS)
.map(|_| thread::spawn(move || thread_main()))
.collect::<Vec<_>>();
for thread in threads {
thread.join().unwrap();
}
let elapsed = start.elapsed();
println!("{:?}", elapsed)
}

fn thread_main() {
for _ in 0..N_ROUNDS {
let len = XS.len();
assert_eq!(len, 2)
}
}
25 changes: 19 additions & 6 deletions src/inline_lazy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@
extern crate core;
extern crate std;

use self::std::prelude::v1::*;
use self::std::cell::Cell;
use self::std::hint::unreachable_unchecked;
use self::std::prelude::v1::*;
use self::std::sync::Once;
#[allow(deprecated)]
pub use self::std::sync::ONCE_INIT;
Expand All @@ -27,23 +27,36 @@ impl<T: Sync> Lazy<T> {
where
F: FnOnce() -> T,
{
self.1.call_once(|| {
self.0.set(Some(f()));
});
if !self.1.is_completed() {
self.init(f)
}

// `self.0` is guaranteed to be `Some` by this point
// The `Once` will catch and propagate panics
unsafe {
match *self.0.as_ptr() {
Some(ref x) => x,
None => {
debug_assert!(false, "attempted to derefence an uninitialized lazy static. This is a bug");
debug_assert!(
false,
"attempted to derefence an uninitialized lazy static. This is a bug"
);

unreachable_unchecked()
},
}
}
}
}

#[cfg_attr(feature = "cold", cold)]
fn init<F>(&self, f: F)
where
F: FnOnce() -> T,
{
self.1.call_once(|| {
self.0.set(Some(f()));
});
}
}

unsafe impl<T: Sync> Sync for Lazy<T> {}
Expand Down
1 change: 1 addition & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
#![feature(once_is_completed)]
// Copyright 2016 lazy-static.rs Developers
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
Expand Down

0 comments on commit 7863cc0

Please sign in to comment.