Benchmarking Erlang's ~application:get_env/3~
Had a bit of a discussion with a coworker this week. We were kicking around whether calling Erlang's application:get_env/3
function repeatedly – like, many times a second – would actually cause a noticeable performance hit.
My gut feeling was it should be fast. The reason being, if you look at what application:get_env/3
actually does (check the source if you like: https://github.com/erlang/otp/blob/ab9a8fee111ee1b16b6b620136379aaece6a29c3/lib/kernel/src/application.erl#L924), it boils down to a lookup in an internal ETS table via application_controller:get_env
.
The relevant code from application_controller.erl
shows this directly:
get_env(AppName, Key) -> NotFound = make_ref(), case ets:lookup_element(ac_tab, {env, AppName, Key}, 2, NotFound) of NotFound -> undefined; Val -> {ok, Val} end. get_env(AppName, Key, Default) -> ets:lookup_element(ac_tab, {env, AppName, Key}, 2, Default).
That's straight from application_controller.erl
(https://github.com/erlang/otp/blob/ab9a8fee111ee1b16b6b620136379aaece6a29c3/lib/kernel/src/application_controller.erl#L347). An ets:lookup_element
is generally a quick ride.
To get a real read on it instead of just guessing, I put together a benchmark. The code's over here if you're curious: https://git.srht/~peixian/get_env_benchmark
The numbers came back looking pretty good, backing up that expectation.
For hitting the same value over and over, it's fast:
--- Running Scenario 1 (Repeated Reads) --- Scenario 1 (Repeated Reads): Iterations: 100000 Total time: 643 microseconds Average time per read: 6.430000 nanoseconds
Averaging in the single-digit nanoseconds per read is quick enough it's unlikely to be your bottleneck in most applications.
Even when you mix in writes to the environment, it holds up. We tested reading, writing a new value, and reading again:
--- Running Scenario 2 (Interspersed Reads/Writes) --- Scenario 2 (Interspersed Reads/Writes): Cycles: 1000 Average time per read BEFORE write: 50.000000 nanoseconds Average time per read AFTER write: 1.000000 nanoseconds
There's a bit of a jump for the read right before a write in these test runs, which is interesting, but the read immediately after the write is back down to minimal nanoseconds. The impact of the write doesn't seem to linger and slow down subsequent reads much at all.
So, based on the code and the benchmark numbers, hitting application:get_env/3
a lot looks perfectly fine. It performs like the quick ETS lookup it is.