baruh

baruh

Upgrading elixir/erlang from 1.14.3/24.3.2.8 to 1.16.2/26.2.5 resulted in 5x performance degradation

Overall, the performance in multiple places in the project I am working on has improved. However, there is one module that does a few operations that seems to - although it
doesn’t seem to - get slower between versions, actually experiencing 4-5x degradation (from 50-60 microseconds to 300 microseconds).

The example snippet of the code looks like


defmodule State do
  use Agent

  def start_link(opts \\ []) do
    state = %{
      id_availability: Keyword.get(opts, :available, true),
    }

    Agent.start_link(fn -> state end, name: Keyword.get(opts, :name, __MODULE__))
  end

  @spec available?() :: boolean()
  def available?(agent \\ __MODULE__), do: get_opts(agent)[:id_availability]

  @spec get_opts() :: map()
  def get_opts(agent \\ __MODULE__) do
    Agent.get(agent, & &1)
  end

  @spec set_opts(map()) :: :ok
  def set_opts(agent \\ __MODULE__, opts) when is_map(opts) do
    Agent.update(agent, fn _state -> opts end)
  end
end


defmodule A do
  def f1(struc, allowlist) do
    if needs_extra_elements?(struc) do
      %{
        lista: struc.lista ++ ["a"],
        listb: struc.listb ++ ["b", "c"],
        keys: Map.take(struc.keys, allowlist)
      }
    else
      struc
    end
  end

  def needs_extra_elements?(struc) do
    struc.has_lists? and String.ends_with?(struc.special_key, "aabbcc") and State.available?()
  end
end

I’m not sure how this could result in 5x performance degradation. Any help would be greatly appreciated.

Marked As Solved

baruh

baruh

@josevalim just released fix for that in plug, "1.16.1" (more info GH-issue). The newest version is 3x faster than 1.14.3/24.3.2.8 with plug, "1.16.0".

Also Liked

LostKobrakai

LostKobrakai

I cannot tell much about the performance degradation, but this isn’t a great way to use an agent. You should filter down the data within the agent callback and only return what is needed, which is then sent/copied to the caller. Currently you copy the whole agent state to the caller, to then there select a subset of the whole. In your example that likely doesn’t make a difference, but if your state is more involved in practise it might.

baruh

baruh

Not yet, I did the change that @LostKobrakai suggested, because it seems an improvement, but definitely doesn’t explain the problem.
However I notice that there is and call to

Plug.Conn.Cookies.decode(cookie)

which I am going to benchmark between the versions.

Actually after benchmark I can see
On the old elixir/erlang

Name                                      ips        average  deviation         median         99th %
Plug.Conn.Cookies.decode/1       12.54 K       79.74 μs    ±11.94%       75.71 μs      106.92 μs

Memory usage statistics:
Name                               Memory usage
Plug.Conn.Cookies.decode/1       134.95 KB

The new elixir/erlang

Name                                      ips        average  deviation         median         99th %
Plug.Conn.Cookies.decode/1        3.59 K      278.66 μs    ±10.54%      277.71 μs      360.84 μs

Memory usage statistics:
Name                               Memory usage
Plug.Conn.Cookies.decode/1       264.63 KB

It seems the problem is in Plug.Conn.Cookies.decode/1 with the same payload it gets 4x slower on the new version of elixir/erlang.

We are using :plug, "1.16.0"; :plug_cowboy, "2.6.1"; :plug_crypto, "2.1.0".

Where Next?

Popular in Questions Top

sergio
In Ruby, I can go: User.find_by(email: "foobar@email.com").update(email: "hello@email.com") How can I do something similar in Elixir? ...
New
bsollish-terakeet
Credo is smart enough to check for (something like) this: assert length(the_list) == 0 with this response: Checking if an enum is empt...
New
aalberti333
As the title describes, I’m trying to run Enum.map() over a list of key/value pairs, where the value is a map. My data looks like this: ...
New
tduccuong
Hi, is there any work on GUI with Elixir, that is similar to Electron/Javascript? My idea is to bundle Phoenix and BEAM into a single se...
New
alice
Hey, Just curious what are the main benefits of Elixir compared to Clojure? When is Elixir more useful than Clojure and vice versa? Th...
New
Fl4m3Ph03n1x
Background Let’s assume I have a typical GenServer that receives messages as requests, does some operation in a DB and returns responses....
New
johnnyicon
Hi all, I've just started learning Elixir and Phoenix Framework, so please pardon my n00bness at this stage. I'm trying to use Postg...
New
chrisalley
ExUnit now has describe blocks which is a welcome addition coming from RSpec. In the docs, it states that nested hierarchies of describe ...
New
jay1
Why is it that the mnesia database isn’t the most preferred database for use in Elixir/Phoenix?
New
joeerl
Hello again - after a longish gap I’ve decided I really must dig into Elixir and see what’s been happening here - so I have a few questio...
New

Other popular topics Top

sorentwo
Hello! tl;dr Announcing Oban, an Ecto based job processing library with a focus on reliability and historical observability. After spen...
977 41022 311
New
dotdotdotPaul
Okay, I'm having a heck of a time trying to figure out how to best handle the validation of belongs_to associations in Ecto. I'm sure I'...
New
lessless
I believe there are people here who are dealing with CSV files import on the daily basis, and since Excel is a really popular tool there ...
New
JorisKok
I have a server on AWS, and was running a load test using artillery. When looking at the Phoenix dashboard I see the Ports going to 100% ...
New
ycv005
I have followed this StackOverflow post to install the specific version of Erlang. And When I am running mix ecto.setup then getting fol...
New
grych
Hi folks, Few months ago I have announced the proof-of-concept of the library to manipulate the browsers DOM objects directly from Elixi...
639 49522 488
New
lastday4you
I wanted to check elixir version in phoenix because i found that my elixir is 1.5 but when i use Enum.chunk_by it said the function is un...
New
chrismccord
As promised, the first release candidate of Phoenix 1.3.0 is out! This release focuses on code generators with improved project structure...
New
chensan
I have a User schema with a :from_id field set to type :string: defmodule TweetBot.Repo.Migrations.CreateUsers do use Ecto.Migration ...
New
shahryarjb
Hello, I have map which I want to convert it to string like this: the map: %{last_name: "tavakkoli", name: "shahryar"} the string I ne...
New

We're in Beta

About us Mission Statement