Julia startup time on macOS vs. Linux

I need to replace my aging Mac but I’m concerned about macOS’ Gatekeeper checks. Currently, I’m running Monterey on an Intel MacBook. I frequently run small julia scripts so, startup times matter.

Consider running time julia --startup-file no -e "" in a terminal. The first run after waking up my Mac takes 5…10 sec and subsequent runs take about 1 sec.

Newer macOS versions check binaries on each run and I have no idea how long the checks take on current hardware.

So, could somebody share the timings of time julia --startup-file no -e "" on an Apple Silicon Mac? Cheers!

PS: I’m aware that that snippet finishes in just 200/300 msec on the same laptop when running Linux. I might even switch the OS.

Here’s a bunch of runs on my M1 Max macbook:

(base) ➜  temple git:(master) ✗ time julia --startup-file no -e ""
julia --startup-file no -e ""  0.18s user 0.08s system 132% cpu 0.196 total
(base) ➜  temple git:(master) ✗ time julia --startup-file no -e ""
julia --startup-file no -e ""  0.15s user 0.05s system 120% cpu 0.162 total
(base) ➜  temple git:(master) ✗ time julia --startup-file no -e ""
julia --startup-file no -e ""  0.16s user 0.06s system 116% cpu 0.188 total
(base) ➜  temple git:(master) ✗ time julia --startup-file no -e ""
julia --startup-file no -e ""  0.14s user 0.08s system 111% cpu 0.200 total
(base) ➜  temple git:(master) ✗ time julia --startup-file no -e ""
julia --startup-file no -e ""  0.14s user 0.09s system 125% cpu 0.185 total
(base) ➜  temple git:(master) ✗ time julia --startup-file no -e ""
julia --startup-file no -e ""  0.11s user 0.08s system 125% cpu 0.147 total
(base) ➜  temple git:(master) ✗ time julia --startup-file no -e ""
julia --startup-file no -e ""  0.13s user 0.04s system 116% cpu 0.151 total
(base) ➜  temple git:(master) ✗ time julia --startup-file no -e ""
julia --startup-file no -e ""  0.13s user 0.04s system 128% cpu 0.135 total
(base) ➜  temple git:(master) ✗ time julia --startup-file no -e ""
julia --startup-file no -e ""  0.11s user 0.08s system 125% cpu 0.146 total
(base) ➜  temple git:(master) ✗ time julia --startup-file no -e ""
julia --startup-file no -e ""  0.13s user 0.04s system 129% cpu 0.139 total
(base) ➜  temple git:(master) ✗ time julia --startup-file no -e ""
julia --startup-file no -e ""  0.12s user 0.06s system 123% cpu 0.143 total
(base) ➜  temple git:(master) ✗ time julia --startup-file no -e ""
julia --startup-file no -e ""  0.13s user 0.10s system 155% cpu 0.143 total
(base) ➜  temple git:(master) ✗ time julia --startup-file no -e ""
julia --startup-file no -e ""  0.14s user 0.05s system 118% cpu 0.156 total
(base) ➜  temple git:(master) ✗ time julia --startup-file no -e ""
julia --startup-file no -e ""  0.13s user 0.04s system 126% cpu 0.138 total
(base) ➜  temple git:(master) ✗ time julia --startup-file no -e ""
julia --startup-file no -e ""  0.14s user 0.04s system 123% cpu 0.146 total
(base) ➜  temple git:(master) ✗ time julia --startup-file no -e ""
julia --startup-file no -e ""  0.18s user 0.04s system 153% cpu 0.144 total
(base) ➜  temple git:(master) ✗ time julia --startup-file no -e ""
julia --startup-file no -e ""  0.13s user 0.04s system 128% cpu 0.136 total
1 Like

Thank you very much! I didn’t expect it to be that fast! Good news!

And on Linux:

ufechner@framework:~$ time julia --startup-file no -e ""

real	0m0,104s
user	0m0,062s
sys	0m0,050s

Framework 13 with Ryzen 7840U

2 Likes

You may want to use a tool like hyperfine, instead of doing that

1 Like

Thanks, this is helpful!

(base) ➜  temple git:(master) ✗ hyperfine --runs 200 'julia --startup-file no -e ""'
Benchmark 1: julia --startup-file no -e ""
  Time (mean ± σ):     129.1 ms ±   6.2 ms    [User: 131.0 ms, System: 62.9 ms]
  Range (min … max):   121.4 ms … 171.0 ms    200 runs 

EDIT2: This is actually not a bug, no worry, just ignore me, and is equivalent it seems, and disabled “the” startup-file. It happens either way and I only confirmed, with strace, the file opened when not trying to disable it, and actually then also a different file I didn’t know of…:

statx(AT_FDCWD, "/home/pharaldsson/.julia/juliaup/julia-1.11.0-rc2+0.x64.linux.gnu/etc/julia/startup.jl", AT_STATX_SYNC_AS_STAT, STATX_ALL, {stx_mask=STATX_ALL|STATX_MNT_ID, stx_attributes=0, stx_mode=S_IFREG|0644, stx_size=162, ...}) = 0
statx(AT_FDCWD, "/home/pharaldsson/.julia/juliaup/julia-1.11.0-rc2+0.x64.linux.gnu/etc/julia/startup.jl", AT_STATX_SYNC_AS_STAT, STATX_ALL, {stx_mask=STATX_ALL|STATX_MNT_ID, stx_attributes=0, stx_mode=S_IFREG|0644, stx_size=162, ...}) = 0
openat(AT_FDCWD, "/home/pharaldsson/.julia/juliaup/julia-1.11.0-rc2+0.x64.linux.gnu/etc/julia/startup.jl", O_RDONLY|O_CLOEXEC) = 21
read(21, "# This file should contain site-"..., 32768) = 162
close(21)                               = 0
statx(AT_FDCWD, "/home/pharaldsson/.julia/config/startup.jl", AT_STATX_SYNC_AS_STAT, STATX_ALL, {stx_mask=STATX_ALL|STATX_MNT_ID, stx_attributes=0, stx_mode=S_IFREG|0664, stx_size=54, ...}) = 0
statx(AT_FDCWD, "/home/pharaldsson/.julia/config/startup.jl", AT_STATX_SYNC_AS_STAT, STATX_ALL, {stx_mask=STATX_ALL|STATX_MNT_ID, stx_attributes=0, stx_mode=S_IFREG|0664, stx_size=54, ...}) = 0
openat(AT_FDCWD, "/home/pharaldsson/.julia/config/startup.jl", O_RDONLY|O_CLOEXEC) = 21

EDIT: It’s actually not slower, my timing was bad, machine loaded, comparable with hyperfine.

strace show a lot of intriguing work happening, that I waded through, such as not opening some files, and others I didn’t know of, some for juliaup actually (for best timing, slightly faster you run julia directly, not indirectly through juliaup):

statx(AT_FDCWD, "/home/pharaldsson/.julia/juliaup/juliaup.json", AT_STATX_SYNC_AS_STAT, STATX_ALL, {stx_mask=STATX_ALL|STATX_MNT_ID, stx_attributes=0, stx_mode=S_IFREG|0664, stx_size=4424, ...}) = 0
mkdir("/home/pharaldsson/.julia/juliaup", 0777) = -1 EEXIST (File exists)
statx(AT_FDCWD, "/home/pharaldsson/.julia/juliaup", AT_STATX_SYNC_AS_STAT, STATX_ALL, {stx_mask=STATX_ALL|STATX_MNT_ID, stx_attributes=0, stx_mode=S_IFDIR|0775, stx_size=4096, ...}) = 0
openat(AT_FDCWD, "/home/pharaldsson/.julia/juliaup/.juliaup-lock", O_RDWR|O_CREAT|O_CLOEXEC, 0666) = 3
flock(3, LOCK_SH|LOCK_NB)               = 0
openat(AT_FDCWD, "/home/pharaldsson/.julia/juliaup/juliaup.json", O_RDONLY|O_CLOEXEC) = 4
read(4, "{\n  \"Default\": \"1.10\",\n  \"Instal"..., 8192) = 4424
getrandom("\x96\x2e\xc4\xd4\x78\x77\x46\x2b\xb4\xed\xeb\x96\xa7\x48\xac\x71", 16, GRND_INSECURE) = 16
read(4, "", 8192)                       = 0
close(4)                                = 0
openat(AT_FDCWD, "/home/pharaldsson/.julia/juliaup/juliaupself.json", O_RDONLY|O_CLOEXEC) = 4
..
openat(AT_FDCWD, "/home/pharaldsson/.julia/juliaup/julia-1.11.0-rc2+0.x64.linux.gnu/bin/../lib/julia/librt.so.1", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
..
openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libjulia-codegen.so.1.11", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/usr/lib/x86_64-linux-gnu/libjulia-codegen.so.1.11", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
..
prlimit64(0, RLIMIT_STACK, NULL, {rlim_cur=8192*1024, rlim_max=RLIM64_INFINITY}) = 0
getrandom("\xc9\x02\x9c\x9d\xe0\x2f\xa9\x88", 8, 0) = 8
openat(AT_FDCWD, "/sys/devices/system/cpu/online", O_RDONLY|O_CLOEXEC) = 20
..
openat(AT_FDCWD, "/proc/meminfo", O_RDONLY|O_CLOEXEC) = 20
read(20, "MemTotal:       32754160 kB\nMemF"..., 4095) = 1419
..
openat(AT_FDCWD, "/home/pharaldsson/.julia/juliaup/julia-1.11.0-rc2+0.x64.linux.gnu/bin/../lib/julia/libpcre2-8", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/home/pharaldsson/.julia/juliaup/julia-1.11.0-rc2+0.x64.linux.gnu/bin/../lib/julia/../libpcre2-8", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)

No, that’s buggy, and I’m not sure what it does without =no, but at least it’s slower:

time julia --startup-file no -e ""

real	0m0,904s
user	0m0,298s
sys	0m0,330s

compared to:

time julia --startup-file=no -e ""

real	0m0,228s
user	0m0,137s
sys	0m0,106s

and even better for RC2:

time julia +1.11 --startup-file=no -e ""

real	0m0,181s
user	0m0,133s
sys	0m0,063s
% hyperfine -w 1 'julia --startup-file no -e ""' 'julia --startup-file=no -e ""'
Benchmark 1: julia --startup-file no -e ""
  Time (mean ± σ):     108.8 ms ±   1.1 ms    [User: 84.6 ms, System: 23.8 ms]
  Range (min … max):   106.8 ms … 112.2 ms    26 runs

Benchmark 2: julia --startup-file=no -e ""
  Time (mean ± σ):     109.3 ms ±   1.0 ms    [User: 84.7 ms, System: 23.5 ms]
  Range (min … max):   107.9 ms … 112.7 ms    25 runs

Summary
  'julia --startup-file no -e ""' ran
    1.00 ± 0.01 times faster than 'julia --startup-file=no -e ""'
1 Like