optimization tricks ?
Mon May 15 12:01:09 CEST 2000
On Fri, 12 May 2000, Hakan Stenholm wrote:
>* in Prolog the order of the predicate (function) clauses affect the
>speed of selecting the apropriate clause (first match is used). e.g. :
>do_something_per_element() -> ok.
>would be faster becouse the first clause is allways the right one expect
>in one case (when it is done).
>Does this apply to Erlang as well ?
Robert has already answered this.
>Are there any other non-algoritmic tricks for better perfomance ?
Francesco has already given you the Speech about how you shouldn't
worry about optimization until you have working (beautiful) code.
However, having spent the last four years on a product where we
had to constantly invent ways to improve performance, I have some
views of my own on the subject:
1. First, we've come across several cases where programmers have
optmimized themselves into bad, unsafe, and even inefficient code. One
of the better ones is using gen_server:cast/2 instead of
gen_server:call/3 "because it's faster" (I'll let you ponder that one
for yourselves.) You really need to understand your application (and
Erlang) well before you can start optimizing.
2. Don't believe rumours like "the lists module is inefficiently
implemented, so you should write your own list functions". Perhaps
this started due to an unfortunate modification of lists:map/2 back in
the old days. Indeed, some of the lists functions (e.g. member,
keysearch, reverse, append) are even BIFs, and can't be beaten by
Erlang code. This is an example of how you'd be better off pointing
out where Erlang needs to improve, and wait until the improvements are
Below is a rambling collection of optimization tricks. Not knowing
your application, it's of course hard to be specific.
3. If you really want to make an implementation-specific optimization,
break it out, make it easy to change, document it carefully, and plan
to keep up with the development of Erlang/OTP, so that you'll know
when your optimization has become obsolete.
4. All ets table reads and writes are copying operations, so strive
to keep objects small (at least give this some thought if your objects
are very large.)
5. setelement/3 becomes expensive on very large tuples. You might want
to consider switching to another representation (e.g. dynarray or
6. Try to avoid code that builds enormous amounts of live data on the
process heap. The garbage collector has a hard time with this, and you
may end up allocating tremendous amounts of memory (tricky area - it's
best to do a lot of profiling in order to understand this, before
trying to optimize.) You might want to look at the options available
for the obscure BIF spawn_opt/4 (e.g. gc_switch). If you are deeply
familiar with the characteristics of the garbage collector, you can
specify whether you want fullsweep collection or generational (or
both) for your process.
7. A more useful option for spawn_opt is perhaps 'min_heap_size',
allowing you to set a heap large enough that you completely avoid GC.
This can be used for jobs that are short but intense: you spawn a
process with a large heap, then have at it until the job is done, and
then terminate the process. This can give significantly better
8. If your application has "I/O" processes, whose job is simply to
dispatch information to the process doing the actual work, set it to
high priority. This type of process can be seen as an interrupt
handler, and keeping them on normal priority usually only increases
9. If your application uses strings a lot, perhaps to send them
through a port to the user (e.g. a web server), don't worry about
flattening lists. The Erlang ports are quite happy with deep lists,
and will normally do a better job of flattening them than you can.
Ulf Wiger, Chief Designer AXD 301 <>
Ericsson Telecom AB tfn: +46 8 719 81 95
Varuvägen 9, Älvsjö mob: +46 70 519 81 95
S-126 25 Stockholm, Sweden fax: +46 8 719 43 44
More information about the erlang-questions