3

I have a small Elixir module that takes up almost all the execution time of my program. I would like to optimize it. It seems like it takes around 15x as long time as the same implementation in C, so there should be some margin to take from. The natural step seems to write BEAM assembly for this module, but that doesn't seem too friendly. IIRC, the BEAM byte code changes between releases, and is mostly undocumented. There does seem to be quite a lot of extra instructions in the generated bytecode, though.

What are my options for optimizing this small part? Rewriting it and the module that uses it in some other language and call it externally could work, but it seems like a lot of work. Writing bytecode that won't work after the next release also seems like a bad idea.

4

I don't know much about BEAM, so take anything I say with a shovelful of salt.

You could try using HiPE, the BEAM native code compiler. From what I understand, unlike most other VMs, BEAM does not automatically compile hot code, instead you have to manually compile your code. From what I have heard, HiPE gives about a 20% performance boost.

You could try using ErLLVM, an experimental new code generation backend for HiPE using the LLVM compiler infrastructure. Reportedly, it is actually slightly slower than HiPE (but faster than interpreted BEAM) at the moment, but the information I read was rather old, so it might have improved by now. Plus, there is always the off chance, that your code happens to hit a sweet spot for ErLLVM. And both LLVM and ErLLVM continue to be improved. LLVM's optimizer should be able to remedy the non-optimal BEAM code you mentioned.

Your next option is Erjang, an implementation of BEAM on the Java platform. Erjang reportedly is about twice as fast as BEAM, however, I expect that gap to be much bigger for compute-intensive code. Erjang has a bit different performance profile than BEAM: throughput is significantly higher (2x). Message passing performance is on par with BEAM, it starts off slightly slower, but once JIT, profiling and dynamic optimizations kick in, it actually overtakes BEAM. Garbage collection pauses may be less predictable: BEAM uses one heap per process, Erjang uses a single heap for all processes. If GC starts to become a problem, you could try switching to Azul's Zing JVM with the C4 (Continuously Concurrent Compacting Collector) or the realtime variant of the IBM J9 JVM with the Metronome garbage collector.

Even if Erjang doesn't meet your performance needs, you could still run your app on Erjang and replace the offending module with one written in Scala, Kotlin, Ceylon, Clojure, Java, etc. Beats having to write BEAM assembly by hand, certainly.

Or, you could stay on BEAM and replace the slow function with a NIF, which doesn't have to be written in C, you could also write it in Haskell (which will allow you to keep the functional feel of Elixir), Go (allowing you to keep a somewhat similar concurrency model), Rust, OCaml, D, or C++.

| improve this answer | |
0

Beam assembly is probably not the way to go here. I would start by very carefully profiling the code in question to see if there are some obvious improvements that can be made. It is possible that you have a problem with something taking a non linear amount of time.

As for the rewriting it option one thing to keep in mind is how will it perform under load? Erlang/Elixir code will do quite well when you have thousands of copies of it running, code in other langauges will work differently.

I find one of the issues that people moving into Erlang face is the idea that single process speed is more important that throughput under concurrent (real world ) conditions.

| improve this answer | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.