# Compiling Julia from source vs release binaries

**URL:** https://discourse.julialang.org/t/compiling-julia-from-source-vs-release-binaries/108180
**Category:** General Usage
**Tags:** question, juliaup
**Created:** [December 30, 2023, 10:13am UTC](https://discourse.julialang.org/t/compiling-julia-from-source-vs-release-binaries/108180 "2023-12-30T10:13:34Z")
**Posts on this page:** 7
**Page:** 1

<div class="post-metadata">

### Author: ![Tamas\_Papp](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tamas_papp/32/25949_2.png) [@Tamas\_Papp](https://discourse.julialang.org/u/Tamas_Papp)
#### Post date: [December 30, 2023, 10:13am UTC](https://discourse.julialang.org/t/compiling-julia-from-source-vs-release-binaries/108180/1 "2023-12-30T10:13:34Z")

</div>

I have always been compiling Julia from sources (checking out the relevant `release-` branch in the git repo), but since `juliaup` is so convenient, I am wondering if I should do that.

Specifically, compiling from source targets the CPU of the local machine, while AFAIK the official binaries [have only a few alternative targets](https://docs.julialang.org/en/v1/devdocs/sysimg/#Specifying-multiple-system-image-targets). I am assuming that these are the ones grabbed by `juliaup`. Am I losing any performance by using the latter, assuming a recent CPU?

(Incidentally, how can I query the targets of an existing image?)

---

<div class="post-metadata">

### Author: ![giordano](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/giordano/32/2166_2.png) [@giordano](https://discourse.julialang.org/u/giordano)
#### Post date: [December 30, 2023, 11:24am UTC](https://discourse.julialang.org/t/compiling-julia-from-source-vs-release-binaries/108180/2 "2023-12-30T11:24:58Z")

</div>

> [@Tamas\_Papp](#):
>
> Specifically, compiling from source targets the CPU of the local machine

To be clear, that only applies to the julia runtime (e.g. garbage collector, interface to LLVM, etc.) which is written in C/C++ and the packages in the sysimage, but the code generated by the julia compiler at runtime shouldn’t be affected by how the julia executable itself was compiled, as that’s always targeting the current CPU (unless you explicitly choose a different target with `julia -C`).

> [@Tamas\_Papp](#):
>
> Am I losing any performance by using the latter, assuming a recent CPU?

Based on the previous section of my reply, if you’re losing some performance it’s mainly in julia’s runtime, not really in the JIT-generated code. Playing with LTO/PGO (which is not currently easily doable in julia anyway) showed some performance gains in terms of compilation time:

> [@Building julia with \`march=native\`](https://discourse.julialang.org/t/building-julia-with-march-native/82256/13):
>
> @ImreSamu: regarding Clear Linux and the Phoronix benchmark, you have to take it with a grain of salt. For example they have amazing numbers for Zstd, but the reason is they set the default number of threads to 4, where other distro’s only use 1; the benchmark is builtin zstd -b ..., so it’s apples and oranges ([zstd benchmark misleading · Issue #633 · phoronix-test-suite/phoronix-test-suite · GitHub](https://github.com/phoronix-test-suite/phoronix-test-suite/issues/633)). Another issue is Phoronix compares Zstd 1.4 with 1.5, and there’s huge performance improvements…

---

<div class="post-metadata">

### Author: ![ImreSamu](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/imresamu/32/20677_2.png) [@ImreSamu](https://discourse.julialang.org/u/ImreSamu)
#### Post date: [December 30, 2023, 2:01pm UTC](https://discourse.julialang.org/t/compiling-julia-from-source-vs-release-binaries/108180/3 "2023-12-30T14:01:58Z")

</div>

> [@Tamas\_Papp](#):
>
> while AFAIK the official binaries [have only a few alternative targets](https://docs.julialang.org/en/v1/devdocs/sysimg/#Specifying-multiple-system-image-targets)

I tested how efficiently the official Julia 1.10.0 binary  
runs on the [AMD Ryzen 9 7940HS](https://www.amd.com/en/product/13036) with ZEN4 architecture.  
Although it recognizes the processor as ‘znver3’,  
it still generates AVX-512 (zmm) code, and this is good.

```julia
$ docker run -it --rm julia:latest 
               _
   _ _ _(_)_ | Documentation: https://docs.julialang.org
  (_) | (_) (_) |
   _ _ _| |_ __ _ | Type "?" for help, "]?" for Pkg help.
  | | | | | | |/ _` | |
  | | |_| | | | (_| | | Version 1.10.0 (2023-12-25)
 _/ |\ __'_|_|_|\__'_| | Official https://julialang.org/ release
|__/ |

julia> versioninfo()
Julia Version 1.10.0
Commit 3120989f39b (2023-12-25 18:01 UTC)
Build Info:
  Official https://julialang.org/ release
Platform Info:
  OS: Linux (x86_64-linux-gnu)
  CPU: 16 × AMD Ryzen 9 7940HS w/ Radeon 780M Graphics
  WORD_SIZE: 64
  LIBM: libopenlibm
  LLVM: libLLVM-15.0.7 (ORCJIT, znver3)
  Threads: 1 on 16 virtual cores
Environment:
  JULIA_GPG = 3673DF529D9049477F76B37566E3C7DC03D6E495
  JULIA_PATH = /usr/local/julia
  JULIA_VERSION = 1.10.0

julia> Base.Sys.CPU_NAME
"znver3"

julia> function test_avx512()
           a = rand(Float64, 1000000)
           b = rand(Float64, 1000000)
           c = a .* b
           return sum(c)
       end
       # @code_native test_avx512()
test_avx512 (generic function with 1 method)

julia> function check_avx512_in_test_avx512()
                  # Create a temporary file
                  tmp_file = tempname()
                  # Define the expression for @code_native macro
                  code_native_expr = :(@code_native test_avx512())
                  # Redirect output to the temporary file
                  open(tmp_file, "w") do file
                      redirect_stdout(file) do
                          eval(code_native_expr)
                      end
                  end
                  # Read the content of the temporary file
                  code_native_output = read(tmp_file, String)
                  # Delete the temporary file
                  rm(tmp_file)
                  # Define patterns that indicate AVX-512 usage
                  avx512_patterns = ["zmm"]
                  # Check if any of the AVX-512 patterns are in the output
                  any(occursin(pattern, code_native_output) for pattern in avx512_patterns)
              end
check_avx512_in_test_avx512 (generic function with 1 method)

julia> check_avx512_in_test_avx512()
true

```

And Julia’s support for Zen4 is pending approval for integration.

> <https://github.com/JuliaLang/julia/pull/50226>
>
> Added feature \`avxifma\` and support for Zen4 for #50178

---

<div class="post-metadata">

### Author: ![kristoffer.carlsson](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/kristoffer.carlsson/32/22_2.png) [@kristoffer.carlsson](https://discourse.julialang.org/u/kristoffer.carlsson)
#### Post date: [December 30, 2023, 2:46pm UTC](https://discourse.julialang.org/t/compiling-julia-from-source-vs-release-binaries/108180/4 "2023-12-30T14:46:50Z")

</div>

> [@giordano](#):
>
> To be clear, that only applies to the julia runtime (e.g. garbage collector, interface to LLVM, etc.) which is written in C/C++ and the packages in the sysimage, but the code generated by the julia compiler at runtime shouldn’t be affected by how the julia executable itself was compiled, as that’s always targeting the current CPU (unless you explicitly choose a different target with `julia -C`).

It also affects the (pre)compiled code that comes bundled in the sysimage.

---

<div class="post-metadata">

### Author: ![laborg](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/laborg/32/5474_2.png) [@laborg](https://discourse.julialang.org/u/laborg)
#### Post date: [December 30, 2023, 4:21pm UTC](https://discourse.julialang.org/t/compiling-julia-from-source-vs-release-binaries/108180/5 "2023-12-30T16:21:29Z")

</div>

> [@kristoffer.carlsson](#):
>
> It also affects the (pre)compiled code that comes bundled in the sysimage.

Mhm… How much performance do we lose here on a modern CPU? I would totally accept to wait for a couple of minutes while `juliaup` does its thing to know the sysimage is as fast as it can be.

---

<div class="post-metadata">

### Author: ![StefanKarpinski](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stefankarpinski/32/24_2.png) [@StefanKarpinski](https://discourse.julialang.org/u/StefanKarpinski)
#### Post date: [December 30, 2023, 4:36pm UTC](https://discourse.julialang.org/t/compiling-julia-from-source-vs-release-binaries/108180/6 "2023-12-30T16:36:01Z")

</div>

Julia is compiled with multi-versioning so it should not be much missing there.

---

<div class="post-metadata">

### Author: ![tbeason](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tbeason/32/15898_2.png) [@tbeason](https://discourse.julialang.org/u/tbeason)
#### Post date: [December 30, 2023, 5:26pm UTC](https://discourse.julialang.org/t/compiling-julia-from-source-vs-release-binaries/108180/7 "2023-12-30T17:26:42Z")

</div>

I asked this like 3-4 years ago (here? on Slack? not sure) and was told that the binaries should leave very little performance on the table. There was not much to be gained by building from source. Since then I’ve always just used the binaries and juliaup has made that even smoother.
