Part 8 · 1 chapters · ~8 min
Performance
The BEAM's latency-first design, the BeamAsm JIT, finding bottleneck processes with recon and observer, message copying and reference-counted binaries, ETS and persistent_term for shared reads, Rustler NIFs and dirty schedulers, Nx for numerical work, Benchee, profiling with :eprof and :fprof, and Ecto query performance.
9
Find the hot mailbox
code
:recon.proc_count(:message_queue_len, 5) # processes with the longest mailboxes
:recon.proc_count(:reductions, 5) # who is using CPU
Benchee.run(%{"Enum" => fn -> Enum.sum(list) end, "reduce" => fn -> Enum.reduce(list, 0, &+/2) end})
# shared, rarely changing config: persistent_term reads are nearly free (writes are expensive)
:persistent_term.put({:fx, "USD-NGN"}, 1_532_00)
# a Rust NIF via Rustler for CPU-heavy work
defmodule Hash do
use Rustler, otp_app: :ledger, crate: "hash"
def blake3(_bin), do: :erlang.nif_error(:nif_not_loaded)
endELIXIR PERFORMANCE
where time goes on the BEAM
swipe the figure sideways, or tap expand for full screen
1/4
the trade-off
The BEAM trades peak single-thread speed for preemption, isolation and predictable latency: tail latency stays flat under overload when other runtimes queue up.
latency over raw speedflat tails under load