Skip to content

It makes startup time significantly longer on Mac #733

Closed

Description

@ShikChen

Testing environment:

  • macOS 10.14.3
  • Rust 1.32.0
  • rand 0.6.5

Reproduce steps:

  1. cargo new hello
  2. Add rand = "0.6" into dependencies.
  3. Modify main.rs
extern crate rand;

fn main() {
}
  1. cargo build --release

The extern crate rand line makes the running time ~5x slower (measured by hyperfine):

❯ hyperfine --warmup 32 './no-rand' './with-rand'
Benchmark #1: ./no-rand
  Time (mean ± σ):       1.6 ms ±   0.5 ms    [User: 0.8 ms, System: 0.4 ms]
  Range (min … max):     0.9 ms …   5.1 ms    670 runs

  Warning: Command took less than 5 ms to complete. Results might be inaccurate.

Benchmark #2: ./with-rand
  Time (mean ± σ):       7.6 ms ±   0.8 ms    [User: 4.6 ms, System: 2.3 ms]
  Range (min … max):     6.4 ms …  11.3 ms    267 runs

Summary
  './no-rand' ran
    4.87 ± 1.55 times faster than './with-rand'

It looks like most of the time is spent on pre-main stuff:

❯ DYLD_PRINT_STATISTICS=1 ./no-rand
Total pre-main time:   1.19 milliseconds (100.0%)
         dylib loading time:   0.51 milliseconds (42.7%)
        rebase/binding time:   0.05 milliseconds (4.6%)
            ObjC setup time:   0.24 milliseconds (20.1%)
           initializer time:   0.33 milliseconds (28.1%)
           slowest intializers :
             libSystem.B.dylib :   0.27 milliseconds (23.3%)
                libc++.1.dylib :   0.02 milliseconds (2.0%)

❯ DYLD_PRINT_STATISTICS=1 ./with-rand
Total pre-main time:   9.33 milliseconds (100.0%)
         dylib loading time:   2.61 milliseconds (28.0%)
        rebase/binding time:   0.66 milliseconds (7.0%)
            ObjC setup time:   2.46 milliseconds (26.3%)
           initializer time:   3.50 milliseconds (37.5%)
           slowest intializers :
             libSystem.B.dylib :   0.46 milliseconds (5.0%)
                CoreFoundation :   2.34 milliseconds (25.1%)
                    Foundation :   0.24 milliseconds (2.6%)

I tried the same steps on a Linux machine, and there is no issue (always ~1ms). Judged by the above information, I guess the culprit is

#[link(name = "Security", kind = "framework")]
extern {
fn SecRandomCopyBytes(rnd: *const SecRandom,
count: size_t, bytes: *mut u8) -> c_int;
}

It currently blocks me to use rand and some crates that depends on it in a time sensitive application. How can we fix this? Is it ok to use /dev/urandom as the platform source on Mac just like what we did for Linux, instead of linking Security.framework?

Activity

  1. dhardy commented on Feb 18, 2019

    @dhardy
    Member

    Rust doesn't have life-before-main. Is this dynamic linking perhaps?

    Is using /dev/random on OSX a a good idea?

    May I question why 7.6ms start-up is not good enough? That's still good enough for an interactive application, and if you are continually starting your app within a loop, then you know where to start optimising...

  2. nagisa commented on Feb 18, 2019

    @nagisa
    Contributor

    Rust doesn't have life-before-main.

    While Rust itself does not, the shared libraries may bring in their own.

    Either way this seems like an issue that should be reported to Apple, not here.

  3. burdges commented on Feb 18, 2019

    @burdges
    Contributor

    Just running otool is slow on OSX, so maybe this comes from dynamic linker overhead, which afaik OSX does rather differently form Linux. Avoid the spawns or play with your build options?

  4. newpavlov commented on Jun 25, 2019

    @newpavlov
    Member

    This issue may be fixed in rust-random/getrandom#38.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions