
Implement BeamAsm – A JIT for Erlang/OTP - di4na
https://github.com/erlang/otp/pull/2745
======
lpgauth
This is amazing. Huge props to Lukas Larsson and the OTP team!

Some background on the journey to BeamJIT:
[https://drive.google.com/file/d/1hHCs90kDX_wJ9AbLzGNu5bZKdIV...](https://drive.google.com/file/d/1hHCs90kDX_wJ9AbLzGNu5bZKdIVWsLsg/view)

~~~
tedunangst
So this is not quite beamjit, but a sort of rewrite?

~~~
filmor
I understood it as a completely new, simplified approach that Lukas Larsson
started beginning of the year.

It's not a tracing or optimising JIT, but instead at load time translates the
BEAM opcodes to native code using asmjit.

------
ramchip
I love how much thought and polish went into this, just like so many other
Erlang features in recent years: counters, persistent_term, thread progress,
ETS scaling, process groups...

There's been talks of JIT for quite a few years, but they didn't want to merge
it in until they had something that's easy to maintain, and doesn't introduce
significant performance regressions. The end result looks really solid.

~~~
pdimitar
What do you mean by "thread progress"?

~~~
ramchip
[https://erlang.org/doc/apps/erts/ThreadProgress.html](https://erlang.org/doc/apps/erts/ThreadProgress.html)

------
andy_ppp
So this JIT supports everything but HiPE and will be included in OTP-24 and is
production ready(???) and dramatically improves performance across almost
everything? Seems too good to be true. What has been the bug finding process
so far in this PR?

~~~
hinkley
Probably a case of the low hanging fruit. With most projects you start off
with a bunch of improvements with very few side effects - at present - but
quickly start to encounter trade offs. Both in the form of new improvements
introducing more development overhead, and the fact that open ended things are
generally hard to make fast.

To make something faster may mean calcifying some part of the architecture;
this code handles every scenario that the design defines now, but it can’t
handle other scenarios we might have wanted to consider later. Those are now
harder to implement or counter to our assumptions. People don’t like it when
you take back things you previously gave them, meaning no new feature or a
huge opportunity cost for that feature (because it’s reimplementing other
features as well as adding a new one).

~~~
andy_ppp
I don’t think this is at all true... I mean the PR changes 350-odd files and
adds some crazy JIT engine. It’s hardly low hanging fruit... I don’t know
enough about how this is implemented to say it will make future features
harder, they even state in the PR maintenance is very important to the design
here so I’ll assume it won’t be a weight around their necks.

------
conradfr
Very exciting.

Also Facebook open-sourcing its static typed Erlang prototype in November.

~~~
tluyben2
Any idea how they handled static typing for messages? As I remember from
previous conversations, that was an issue.

~~~
lf-non
I may be missing some context but can't it be done similar to how we handle
data from outside world in TS ?

A runtime type guard that asserts that the shape of data conforms to a
particular type and from that point forward compiler will trust the guard and
assume that the message is of particular type.

In a dynamically typed world, I doubt one could do much better.

~~~
tluyben2
The thing is; messages for Erlang are far more part of your
programming/architecture than in other languages. You are basically writing
'nanoservices' all the time. I saw quite a lot of people mentioning it in
discussions, including here, for instance [0].

[0]
[https://news.ycombinator.com/item?id=22573535](https://news.ycombinator.com/item?id=22573535)

------
tiffanyh
I'm soooooo excited about this.

Question: how does performance compare to HiPE. I see reference to
improvements over the Interpreter but what about performance vs HiPE?

------
nickjj
Can someone break this down and explain what this means in practical runtime
performance gains?

I know it's probably "it depends", but in Elixir let's say you were doing a
lot of string parsing or mucking around with a bunch of Enum functions or
doing a bit of math. Will this put Elixir's performance on par with at least
Python and Ruby in those cases?

I know this feature is meant for Erlang but I'm assuming it applies back to
Elixir too?

~~~
strmpnk
It does apply to Elixir. It will help all around performance but more so it
does this on a per-instruction level by reducing dispatch cost in that the
interpreter pays (as well as managing to specialize things a little better
than what the fixed instruction tables can express).

To get an idea of the instruction stream of the BEAM (not the same as .beam
asm), you can use the erts_debug module:

    
    
        iex> :erts_debug.df(String)
    

This will dump a BEAM machine instruction stream to a file named
Elixir.String.dis in your current working directory. You'll see things like:

    
    
        000000001B81AFB0: i_func_info_IaaI 0 `'Elixir.String'` `at` 2 
        000000001B81AFD8: is_integer_fx f(000000001B81AFB0) x(1) 
        000000001B81AFE8: is_ge_literal_fxc f(000000001B81B008) x(1) `0` 
        000000001B81B000: i_call_only_f loc(`'Elixir.String'`:`do_at`/2) 
        000000001B81B008: allocate_tt 2 2 
        000000001B81B010: move_window2_xxy x(1) x(0) y(0) 
        000000001B81B018: i_call_f loc(`'Elixir.String'`:`length`/1) 
        000000001B81B020: i_plus_xyjd x(0) y(0) j(0) x(0) 
        000000001B81B030: is_ge_literal_fxc f(000000001B81B060) x(0) `0` 
        000000001B81B048: move_shift_yxx y(1) x(0) x(1) 
        000000001B81B050: i_call_last_fQ loc(`'Elixir.String'`:`do_at`/2) 2 
        000000001B81B060: move_deallocate_return_cQ `nil` 2
    

Each of those instructions are what the .beam file loader currently generates.
With the JIT, these will be replaced by machine code.

------
metroholografix
I wish they'd kept it C-only instead of introducing C++ (plenty of runtime
code generation libraries written in C).

There is something to be said about internal consistency and for a codebase as
established as this, C++ is more of a detriment than a gain.

~~~
mouldysammich
I imagine developers as experienced as the creators of this evaluated the C
options and decided C++ was in fact not more of a detriment than a gain.

It has its problems but blindly being anti C++ is silly.

~~~
metroholografix
Hardly blindly.

It's been a C codebase so far. Introducing C++ makes this no longer the case.
This has strong implications for both development and deployment. I'm
perplexed since there exist battle-tested code generation engines written in C
(e.g. dynasm). Correct me if I'm wrong but it doesn't look like asmjit is
anything special in that regard.

I can't imagine Joe Armstrong being happy about this.

~~~
jashmatthews
Dynasm depends on Lua for pre-processing into pure C. I guess you could write
an Erlang version? There's a Ruby meta-assembler in Safari JavaScriptCore!

~~~
metroholografix
Dynasm can be compiled with minilua.c (a single file), which can simply be
embedded into the Erlang build.

[https://corsix.github.io/dynasm-
doc/tutorial.html](https://corsix.github.io/dynasm-doc/tutorial.html)

~~~
h0l0cube
"We also considered using dynasm, but found the tooling that comes with asmjit
to be better."

[https://github.com/erlang/otp/pull/2745#issuecomment-6914821...](https://github.com/erlang/otp/pull/2745#issuecomment-691482132)

