Powered by AppSignal & Oban Pro
Would you like to see your link here? Contact us
Notesclub

Elixir v1.14 + Livebook

talks/2022/10-elixirconf-us.livemd

Elixir v1.14 + Livebook

Mix.install([
  {:kino, github: "livebook-dev/kino", override: true},
  {:kino_vega_lite, "~> 0.1.3"},
  {:kino_db, "~> 0.1.2"},
  {:postgrex, "~> 0.16.3"}
])

Autocompletion

Hit tab after the dot below:

String.

Processes

self()
parent = self()

child =
  spawn(fn ->
    receive do
      :ping ->
        Process.sleep(2_000)
        send(parent, :pong)
    end
  end)

send(child, :ping)

receive do
  :pong -> :ponged!
end
Kino.Process.render_seq_trace(fn ->
  parent = self()

  child =
    spawn(fn ->
      receive do
        :ping -> send(parent, :pong)
      end
    end)

  send(child, :ping)

  receive do
    :pong -> :ponged!
  end
end)
Kino.Process.render_seq_trace(fn ->
  1..4
  |> Task.async_stream(
    fn _ -> Process.sleep(Enum.random(100..300)) end,
    max_concurrency: 4
  )
  |> Stream.run()
end)

Supervisors

{:ok, supervisor} =
  Supervisor.start_link(
    [
      {Task, fn -> Process.sleep(:infinity) end},
      {Agent, fn -> [] end}
    ],
    strategy: :one_for_one
  )
Kino.Process.render_sup_tree(supervisor)
supervisor
Kino.Process.render_app_tree(:kino)
:kino
Kino.Supervisor

dbg

"Elixir is cool!"
|> String.trim_trailing("!")
|> String.split()
|> List.first()
|> dbg()

Chart: Memory x Reductions

processes =
  for pid <- Process.list() do
    info = Process.info(pid, [:reductions, :memory, :status])

    %{
      pid: inspect(pid),
      reductions: info[:reductions],
      memory: info[:memory],
      status: info[:status]
    }
  end
alias VegaLite, as: Vl

Vl.new(width: 600, height: 400)
|> Vl.data_from_values(processes)
|> Vl.mark(:point, tooltip: true)
|> Vl.encode_field(:x, "reductions", type: :quantitative, scale: [type: "log", base: 10])
|> Vl.encode_field(:y, "memory", type: :quantitative, scale: [type: "log", base: 10])
|> Vl.encode_field(:color, "status", type: :nominal)
|> Vl.encode_field(:tooltip, "pid", type: :nominal)

Chart: memory over time

:erlang.memory()
memory_plot =
  Vl.new(width: 600, height: 400, padding: 20)
  |> Vl.repeat(
    [layer: ["total", "processes", "atom", "binary", "code", "ets"]],
    Vl.new()
    |> Vl.mark(:line)
    |> Vl.encode_field(:x, "iter", type: :quantitative, title: "Measurement")
    |> Vl.encode_repeat(:y, :layer, type: :quantitative, title: "Memory usage (MB)")
    |> Vl.encode(:color, datum: [repeat: :layer], type: :nominal)
  )
  |> Kino.VegaLite.new()
Kino.VegaLite.periodically(memory_plot, 200, 1, fn i ->
  point =
    :erlang.memory()
    |> Enum.map(fn {type, bytes} -> {type, bytes / 1_000_000} end)
    |> Map.new()
    |> Map.put(:iter, i)

  Kino.VegaLite.push(memory_plot, point, window: 1000)
  {:cont, i + 1}
end)

Binary usage

for i <- 1..10_000 do
  String.duplicate("cat", i)
end

ETS usage

tid = :ets.new(:users, [:set, :public])

for i <- 1..1_000_000 do
  :ets.insert(tid, {i, "User #{i}"})
end

Smart cells

Mouse over and press “+ Smart” and choose “Chart” to plot processes!