Performance of local function capture

146 views
Skip to first unread message

Rudolf Manusadzhian

unread,
Mar 23, 2024, 12:50:55 PMMar 23
to elixir-lang-core
Hi there! Might be a naive question.

Why don't we treat all local captures as external? Like at compile time, if it's possible, we could treat &fun/0 as &__MODULE__.fun/0 and get a free performance boost, if in the end they behave same.

I was going thought the docs for :telemetry.attach/4 and the suggestion to avoid using local captures raise that thought.

If that's not possible, does it make sense to add a note in the docs Kernel.SpecialForms.&/1 # Capture about the performance implications of local capture vs external or a recommendation?

Thanks.

Jean Klingler

unread,
Mar 24, 2024, 9:13:14 PMMar 24
to elixir-l...@googlegroups.com
This is an interesting topic.

I tried to benchmark these and sometimes local functions indeed show up as slightly slower, but it is typically in the 0~2% range even for this contrived example doing basically nothing. So I'm not sure if it is worth highlighting the difference:

Checking the S file shows that external functions are just literals while local functions are calling make_fun3:

Even though, as far as I know, recent versions of Erlang have optimizations to make sure the overhead of lambdas like this one remains very small: https://github.com/erlang/otp/pull/6963.


--
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-co...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/elixir-lang-core/c7065947-b48d-43e6-a450-387f6d4f1846n%40googlegroups.com.
Message has been deleted
Message has been deleted
Message has been deleted

Christopher Keele

unread,
Mar 25, 2024, 1:10:53 PMMar 25
to elixir-lang-core
> At compile time, if it's possible, we could treat &fun/0 as &__MODULE__.fun/0 and get a free performance boost, if in the end they behave same.

I believe local vs remote captures do not behave the same during hot code reloading. Remote calls always invoke the latest version of a module; so if __MODULE__ was being upgraded, and an old version was still completing some work, the remote call to its own function would invoke new code potentially incompatible with the running old version.

Michał Muskała

unread,
Mar 26, 2024, 2:08:06 PMMar 26
to elixir-l...@googlegroups.com
The are some subtle differences - the function needs to be exported (remote capture doesn't work with defp). Furthermore, there's a difference in case of module reloading - local capture will always dispatch into the version of the module that created it, remote capture will always dispatch to the latest version of the module. 


On 23 Mar 2024, at 16:50, 'Rudolf Manusadzhian' via elixir-lang-core <elixir-l...@googlegroups.com> wrote:

Hi there! Might be a naive question.
--

Paul Schoenfelder

unread,
Mar 26, 2024, 2:08:06 PMMar 26
to elixir-l...@googlegroups.com
They aren't exactly equivalent.

The difference comes into play with code loading. The local captures will reference the version of the module they were captured with, while remote/external captures will always reference the latest version of the module.

Depending on what the closure is doing, the latter may be perfectly fine, and is more efficient - but there are many situations where that would result in bugs/unexpected behavior. As a result, the compiler cannot make a choice that works in all situations. Obviously, in situations without hot code loading, this is irrelevant - but you can't know if that is the case at compile-time.

Hope that provides some useful context on why things work the way they do!

Paul
Reply all
Reply to author
Forward
0 new messages