mruoss
Guards vs. generated functions: which is faster/more performant?
Hey there
Regarding performance, is there a difference between guards and generated functions using pattern matching? Or does the compiler generate the same byte code for both?
And if there is a difference, which one is more performant?
Using Guards
defmodule UsingGuards do
def do_work(arg) when arg in big_list do
# ...
end
end
Generated Functions
defmodule UsingFunctionGeneration do
for arg in big_list do
def do_work(unquote(arg)) do
# ...
end
end
end
Most Liked
mruoss
So I wrote the following simple Elixir script that uses benchee. I did not give it much thought to be honest. Let me know what you think.
TLDR; Performance for both approaches indeed seem to be equivalent.
Script
defmodule Test do
@numbers Range.to_list(1..1000)
def work(input, fun) do
Enum.map(input, fun)
end
for number <- @numbers do
def do_work_generated(unquote(number)), do: unquote(number)
end
def do_work_guards(number) when number in @numbers, do: number
end
Mix.install([:benchee, :benchee_markdown])
list_of_random_numbers = fn -> Enum.map(1..500_000, fn _ -> :rand.uniform(1000) end) end
inputs =
list_of_random_numbers
|> Stream.repeatedly()
|> Stream.take(5)
|> Stream.with_index()
|> Stream.map(fn {numbers, idx} -> {"Batch #{idx + 1}", numbers} end)
Benchee.run(
%{
"Generated Functions" => fn input -> Test.work(input, &Test.do_work_generated/1) end,
"Guards" => fn input -> Test.work(input, &Test.do_work_guards/1) end
},
memory_time: 60,
inputs: inputs,
formatters: [
{Benchee.Formatters.Markdown, file: "BENCHMARK.md"},
Benchee.Formatters.Console
]
)
Output
Configuration
Benchmark suite executing with the following configuration:
| :time | 5 s |
|---|---|
| :parallel | 1 |
| :warmup | 2 s |
Statistics
Input: Batch 1
Run Time
| Name | IPS | Average | Devitation | Median | 99th % |
|---|---|---|---|---|---|
| Guards | 177.07 | 5.65 ms | ±4.15% | 5.62 ms | 5.87 ms |
| Generated Functions | 175.18 | 5.71 ms | ±4.30% | 5.67 ms | 6.30 ms |
Run Time Comparison
| Name | IPS | Slower |
|---|---|---|
| Guards | 177.07 | |
| Generated Functions | 175.18 | 1.01x |
Memory Usage
| Name | Average | Factor |
|---|---|---|
| Guards | 7.63 MB | |
| Generated Functions | 7.63 MB | 1.0x |
Input: Batch 2
Run Time
| Name | IPS | Average | Devitation | Median | 99th % |
|---|---|---|---|---|---|
| Guards | 174.66 | 5.73 ms | ±4.56% | 5.69 ms | 6.14 ms |
| Generated Functions | 174.12 | 5.74 ms | ±4.46% | 5.71 ms | 6.19 ms |
Run Time Comparison
| Name | IPS | Slower |
|---|---|---|
| Guards | 174.66 | |
| Generated Functions | 174.12 | 1.0x |
Memory Usage
| Name | Average | Factor |
|---|---|---|
| Guards | 7.63 MB | |
| Generated Functions | 7.63 MB | 1.0x |
Input: Batch 3
Run Time
| Name | IPS | Average | Devitation | Median | 99th % |
|---|---|---|---|---|---|
| Guards | 174.93 | 5.72 ms | ±4.77% | 5.68 ms | 6.23 ms |
| Generated Functions | 174.21 | 5.74 ms | ±4.07% | 5.71 ms | 5.96 ms |
Run Time Comparison
| Name | IPS | Slower |
|---|---|---|
| Guards | 174.93 | |
| Generated Functions | 174.21 | 1.0x |
Memory Usage
| Name | Average | Factor |
|---|---|---|
| Guards | 7.63 MB | |
| Generated Functions | 7.63 MB | 1.0x |
Input: Batch 4
Run Time
| Name | IPS | Average | Devitation | Median | 99th % |
|---|---|---|---|---|---|
| Guards | 174.18 | 5.74 ms | ±4.48% | 5.71 ms | 6.16 ms |
| Generated Functions | 172.05 | 5.81 ms | ±4.21% | 5.79 ms | 6.14 ms |
Run Time Comparison
| Name | IPS | Slower |
|---|---|---|
| Guards | 174.18 | |
| Generated Functions | 172.05 | 1.01x |
Memory Usage
| Name | Average | Factor |
|---|---|---|
| Guards | 7.63 MB | |
| Generated Functions | 7.63 MB | 1.0x |
Input: Batch 5
Run Time
| Name | IPS | Average | Devitation | Median | 99th % |
|---|---|---|---|---|---|
| Generated Functions | 174.62 | 5.73 ms | ±4.37% | 5.69 ms | 6.19 ms |
| Guards | 174.34 | 5.74 ms | ±4.52% | 5.71 ms | 6.10 ms |
Run Time Comparison
| Name | IPS | Slower |
|---|---|---|
| Generated Functions | 174.62 | |
| Guards | 174.34 | 1.0x |
Memory Usage
| Name | Average | Factor |
|---|---|---|
| Generated Functions | 7.63 MB | |
| Guards | 7.63 MB | 1.0x |
LostKobrakai
in/2 doesn’t compile to an Enum.member?/2 call when used in a guard:
LostKobrakai
You can use GitHub - michalmuskala/decompile · GitHub to take a look how things will look at lower levels.
Popular in Questions
Other popular topics
Categories:
Sub Categories:
Forums
Popular Tags
- #ecto
- #liveview
- #troubleshooting
- #learning-elixir
- #deployment
- #library
- #erlang
- #testing
- #genserver
- #mix
- #absinthe
- #remote-other
- #otp
- #plug
- #how-to-question
- #macros
- #postgres
- #channels
- #elixirconf
- #exunit
- #discussion
- #code-sync
- #javascript
- #podcasts
- #onsite
- #dialyzer
- #docker
- #authentication
- #umbrella
- #full-time-contract
- #podcasts-by-brainlid
- #ecto-query
- #elixir-ls
- #phoenix_html
- #iex
- #blog-post
- #graphql
- #genstage
- #ai
- #websockets
- #supervisor
- #advent-of-code
- #elixirconf-us
- #distillery
- #processes
- #forms
- #api
- #metaprogramming
- #security
- #performance









