Background

I was recently working on a project that invoked `System.get_env/0` on 
every request it handled. Someone changed the infrastructure the 
application was deployed on and greatly increased the number of environment 
variables (3x more) in the environment the Elixir application ran in, and 
the performance of the application degraded by about that same amount (3x 
slower than before). When I profiled the application I quickly found that 
most of the request handling was spent waiting for the `System.get_env/0` 
function to return. I changed the code so `System.get_env/0` was only 
invoked on startup and the performance issue was resolved.

Problem

When I was working on the performance issue in the app the flame graphs 
revealed something interesting - Erlang was actually formatting the 
environment variables from a proplist to a list of strings in certain 
format, and then Elixir was undoing the formatting by parsing the strings 
back to a map! Because of this the performance of the `System.get_env/0` 
function call is tied to the number of variables in the environment.


   - The Erlang code that formats the variables: 
   https://github.com/erlang/otp/blob/master/lib/kernel/src/os.erl#L118
   - The Elixir code that parses them and puts them in a dictionary: 
   
https://github.com/elixir-lang/elixir/blob/v1.10.3/lib/elixir/lib/system.ex#L438


Possible Solutions

*1. Update the `System.get_env/0` function to use `os:list_env_vars/0` 
function*

This function already exists returns a proplists in the format 
`{VariableName, VariableValue}`. All we need to do is replace the existing 
code with

def get_env do
   Enum.into(:os.list_env_vars(), %{})
end

This would solve the performance issue and simplify the Elixir code! The 
downside is that `os:list_env_vars/0` is not a documented function, which I 
assume means it's not recommended for other applications to rely on it.

*2. Wait for Erlang to change*

Because I assumed `os:list_env_vars/0` is not a function that Elixir should 
be relying on (although nothing prevents it from doing so), I have created 
an enhancement ticket on the Erlang issue tracker to document 
`os:list_env_vars/0` or implement another function that returns the 
environment variables in a proplist with `{VariableName, VariableValue}` 
tuples - https://bugs.erlang.org/browse/ERL-1332. 
<https://bugs.erlang.org/browse/ERL-1332> Once Erlang implements a 
documented function that does this we could then begin updating Elixir.

Thoughts? I doubt this is something that is run into very often but it 
could be easily improved.

-- 
You received this message because you are subscribed to the Google Groups 
"elixir-lang-core" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to elixir-lang-core+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/elixir-lang-core/0aecb090-2cbb-46af-8ff4-e34337b123d4o%40googlegroups.com.

Reply via email to