Erlang and Elixir on Apple Silicon/M1 Chip

OTP 25 is still 6+ months out, but you can use the JIT right now if you build it with kerl. Runs great!

2 Likes

Hello! I tried installing Erlang/OTP with kerl and Elixir with kiex and didn’t notice any difference. How can I tell it’s working? I just installed 24.1.4 though… should I be giving kerl a Github url and branch?

Thanks for the help!

Yes, the instruction I linked is for using a branch. Use master from the official OTP repo.

1 Like

Heh, well using master works, I can see the [jit] tag when starting up repl. Unfortunately, one of my projects compiled fine, but another crashes during compilation. So back to 24.1.4 for now.

Yeah I’m seeing similarly disappointing times on my new M1 (max) mac pro. For whatever reason I only really see the two efficiency cores doing work while compiling, there is next to 0 activity on the performance cores, and I can’t really figure out why. iex shows [smp:10:10] [ds:10:10:10] so it should have enough schedulers.

I mean, I’m getting roughly the same compile time as my previous MBP (intel) w/ 8 Intel cores so it’s still impressive, but I’d really like to get the 8 performance M1 cores in the mix.

does this help: Anyone received their new MacBook Pros today? - #8 by joseph-lozano

Unfortunately it has not helped.

Using asdf to uninstall and then reinstall Erlang with the following flags exported definitely made a big difference on my MacBook Pro M1 Max.

export KERL_CONFIGURE_OPTIONS="
      --disable-debug \
      --disable-silent-rules \
      --enable-dynamic-ssl-lib \
      --enable-hipe \
      --enable-shared-zlib \
      --enable-smp-support \
      --enable-threads \
      --enable-wx \
      --with-ssl=$(brew --prefix openssl@1.1) \
      --without-javac
      --enable-darwin-64bit \
      --enable-kernel-poll \
      --with-dynamic-trace=dtrace \
     "
1 Like

Enable hipe? Isnt that project dead?

1 Like

The args were copied from the Erlang homebrew formula.

Given this one is maintained by brew bump-formula-pr is likely keeping cruft around quite well :smiley:

1 Like

I’m running almost those exact options, I have --disable-hipe instead of enable since it’s a dead project.

So here’s something that’s interesting. I did rm -rf _build and then iex -S mix run --no-start --no-compile so that I could open :observer, and then I called the Mix.Task.run("deps.compile") to look at how it performed from Erlang’s perspective.

Here’s what I saw:

Initial:

More deps:

More deps:

This looks super strange to me. Scheduler utilization across the board is super low. I ran compile after the deps were compiled and although it did look like all 10 schedulers got involved (as we see here with some deps) none of them ever exceeded 30%.

I’m not entirely sure what to make of this. The big memory spike was Poison (yes, I know) and I think that’s likely just code gen. Anyone got any insights?

UPDATE:

Running this code trivially uses all 10 schedulers and maxes out cores from an OS level:

iex(3)> defmodule Busy do
  ...(3)>   def loop(x) do
  ...(3)>     loop(x + 1)
  ...(3)>   end
  ...(3)> end
  iex(4)> 1..20 |> Enum.map(fn _ -> spawn(fn -> Busy.loop(0) end)

So maybe the OS is right. Compilation (for some reason) is generally not generating very much scheduler activity (for some reason) and so it can run everything on the efficiency cores. When the schedulers are under load it does seem to happily move them to the performance cores.

5 Likes

IO bound then?

Very unlikely that compilation is that IO bound. He is using about 5% of the processing power. Maybe if sth is wrong with the storage.

After a chat with @dch on IRC we’re noticing that :erlang.system_info :cpu_topology returns :undefined which may be part of the issue. Will update with followup.

7 Likes

Interesting think is that on my MacBook with Intel it also returns :undefined.

The cpu_topology only affects how schedulers are bound. So you have to pass the +sbt option to Erlang in order for it to change anything. If I recall correctly it will return undefined on all MacOS devices because Apple does not provide (or we at least do not fetch) information about what the CPU topology looks like.

3 Likes

It seems that OSX (on both intel, which I have here, and M1, which I don’t) doesn’t provide any topology information, so we get undefined everywhere. For comparison, an 8 core non-SMT intel box (single socket):

 erl -noshell -eval 'io:format("~p~n",[erlang:system_info(cpu_topology)])' -s erlang halt
[{processor,[{core,{logical,0}},
             {core,{logical,1}},
             {core,{logical,2}},
             {core,{logical,3}},
             {core,{logical,4}},
             {core,{logical,5}},
             {core,{logical,6}},
             {core,{logical,7}}]}]

And an 80-core arm64 box with partitioning (single socket, but NUMA):

[{processor,[{core,{logical,0}},
             {core,{logical,1}},
             {core,{logical,2}},
              ...
             {core,{logical,39}}]},
 {processor,[{core,{logical,40}},
             {core,{logical,41}},
             {core,{logical,42}},
             ...
             {core,{logical,79}}]}]

It would be great to see if the OTP team could advise how to (ab)use the cores best here on M1, given that the efficiency cores run ~ 1/3 slower clock speed. It would be great to pin the schedulers, but I guess that requires Apple to provide information on how to access it.

The usual FreeBSD sysctls that expose that seem to be missing on OSX.

1 Like

More M1 fun: Hardware Information - by Jim Cownie - CPU fun is the best resource I found… in particular brew install hwloc and running lstopo. neat!

Setting up the Apple M1 for Code Development is also excellent.

2 Likes

[hwloc-announce] hwloc 2.6.0 released it seems the latest release is able to extract CPU info from M1


Version 2.6.0
-------------
* Backends
  + Expose two cpukinds for energy-efficient cores (icestorm) and
    high-performance cores (firestorm) on Apple M1 on Mac OS X.

Maybe that helps!

1 Like