From 84adefa331c4159d432d22840663c38f155cd4c1 Mon Sep 17 00:00:00 2001 From: Erlang/OTP Date: Fri, 20 Nov 2009 14:54:40 +0000 Subject: The R13B03 release. --- system/doc/efficiency_guide/myths.xml | 203 ++++++++++++++++++++++++++++++++++ 1 file changed, 203 insertions(+) create mode 100644 system/doc/efficiency_guide/myths.xml (limited to 'system/doc/efficiency_guide/myths.xml') diff --git a/system/doc/efficiency_guide/myths.xml b/system/doc/efficiency_guide/myths.xml new file mode 100644 index 0000000000..76a72368bb --- /dev/null +++ b/system/doc/efficiency_guide/myths.xml @@ -0,0 +1,203 @@ + + + + +
+ + 2007 + 2007 + Ericsson AB, All Rights Reserved + + + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + The Initial Developer of the Original Code is Ericsson AB. + + + The Eight Myths of Erlang Performance + Bjorn Gustavsson + + 2007-11-10 + + myths.xml +
+ +

Some truths seem to live on well beyond their best-before date, + perhaps because "information" spreads more rapidly from person-to-person + faster than a single release note that notes, for instance, that funs + have become faster.

+ +

Here we try to kill the old truths (or semi-truths) that have + become myths.

+ +
+ Myth: Funs are slow +

Yes, funs used to be slow. Very slow. Slower than apply/3. + Originally, funs were implemented using nothing more than + compiler trickery, ordinary tuples, apply/3, and a great + deal of ingenuity.

+ +

But that is ancient history. Funs was given its own data type + in the R6B release and was further optimized in the R7B release. + Now the cost for a fun call falls roughly between the cost for a call to + local function and apply/3.

+
+ +
+ Myth: List comprehensions are slow + +

List comprehensions used to be implemented using funs, and in the + bad old days funs were really slow.

+ +

Nowadays the compiler rewrites list comprehensions into an ordinary + recursive function. Of course, using a tail-recursive function with + a reverse at the end would be still faster. Or would it? + That leads us to the next myth.

+
+ +
+ Myth: Tail-recursive functions are MUCH faster + than recursive functions + +

According to the myth, + recursive functions leave references + to dead terms on the stack and the garbage collector will have to + copy all those dead terms, while tail-recursive functions immediately + discard those terms.

+ +

That used to be true before R7B. In R7B, the compiler started + to generate code that overwrites references to terms that will never + be used with an empty list, so that the garbage collector would not + keep dead values any longer than necessary.

+ +

Even after that optimization, a tail-recursive function would + still most of the time be faster than a body-recursive function. Why?

+ +

It has to do with how many words of stack that are used in each + recursive call. In most cases, a recursive function would use more words + on the stack for each recursion than the number of words a tail-recursive + would allocate on the heap. Since more memory is used, the garbage + collector will be invoked more frequently, and it will have more work traversing + the stack.

+ +

In R12B and later releases, there is an optimization that will + in many cases reduces the number of words used on the stack in + body-recursive calls, so that a body-recursive list function and + tail-recursive function that calls lists:reverse/1 at the + end will use exactly the same amount of memory. + lists:map/2, lists:filter/2, list comprehensions, + and many other recursive functions now use the same amount of space + as their tail-recursive equivalents.

+ +

So which is faster?

+ +

It depends. On Solaris/Sparc, the body-recursive function seems to + be slightly faster, even for lists with very many elements. On the x86 + architecture, tail-recursion was up to about 30 percent faster.

+ +

So the choice is now mostly a matter of taste. If you really do need + the utmost speed, you must measure. You can no longer be + absolutely sure that the tail-recursive list function will be the fastest + in all circumstances.

+ +

Note: A tail-recursive function that does not need to reverse the + list at the end is, of course, faster than a body-recursive function, + as are tail-recursive functions that do not construct any terms at all + (for instance, a function that sums all integers in a list).

+
+ +
+ Myth: '++' is always bad + +

The ++ operator has, somewhat undeservedly, got a very bad reputation. + It probably has something to do with code like

+ +

DO NOT

+ +naive_reverse([H|T]) -> + naive_reverse(T)++[H]; +naive_reverse([]) -> + []. + +

which is the most inefficient way there is to reverse a list. + Since the ++ operator copies its left operand, the result + will be copied again and again and again... leading to quadratic + complexity.

+ +

On the other hand, using ++ like this

+ +

OK

+ +naive_but_ok_reverse([H|T], Acc) -> + naive_but_ok_reverse(T, [H]++Acc); +naive_but_ok_reverse([], Acc) -> + Acc. + +

is not bad. Each list element will only be copied once. + The growing result Acc is the right operand + for the ++ operator, and it will not be copied.

+ +

Of course, experienced Erlang programmers would actually write

+ +

DO

+ +vanilla_reverse([H|T], Acc) -> + vanilla_reverse(T, [H|Acc]); +vanilla_reverse([], Acc) -> + Acc. + +

which is slightly more efficient because you don't build a + list element only to directly copy it. (Or it would be more efficient + if the the compiler did not automatically rewrite [H]++Acc + to [H|Acc].)

+
+ +
+ Myth: Strings are slow + +

Actually, string handling could be slow if done improperly. + In Erlang, you'll have to think a little more about how the strings + are used and choose an appropriate representation and use + the re instead of the obsolete + regexp module if you are going to use regualr expressions.

+
+ +
+ Myth: Repairing a Dets file is very slow + +

The repair time is still proportional to the number of records + in the file, but Dets repairs used to be much, much slower in the past. + Dets has been massively rewritten and improved.

+
+ +
+ Myth: BEAM is a stack-based byte-code virtual machine (and therefore slow) + +

BEAM is a register-based virtual machine. It has 1024 virtual registers + that are used for holding temporary values and for passing arguments when + calling functions. Variables that need to survive a function call are saved + to the stack.

+ +

BEAM is a threaded-code interpreter. Each instruction is word pointing + directly to executable C-code, making instruction dispatching very fast.

+
+ +
+ Myth: Use '_' to speed up your program when a variable is not used + +

That was once true, but since R6B the BEAM compiler is quite capable of seeing itself + that a variable is not used.

+
+ +
+ -- cgit v1.2.3