aboutsummaryrefslogtreecommitdiffstats
path: root/system/doc/efficiency_guide/commoncaveats.xml
diff options
context:
space:
mode:
Diffstat (limited to 'system/doc/efficiency_guide/commoncaveats.xml')
-rw-r--r--system/doc/efficiency_guide/commoncaveats.xml239
1 files changed, 239 insertions, 0 deletions
diff --git a/system/doc/efficiency_guide/commoncaveats.xml b/system/doc/efficiency_guide/commoncaveats.xml
new file mode 100644
index 0000000000..e18e5aa510
--- /dev/null
+++ b/system/doc/efficiency_guide/commoncaveats.xml
@@ -0,0 +1,239 @@
+<?xml version="1.0" encoding="latin1" ?>
+<!DOCTYPE chapter SYSTEM "chapter.dtd">
+
+<chapter>
+ <header>
+ <copyright>
+ <year>2001</year><year>2009</year>
+ <holder>Ericsson AB. All Rights Reserved.</holder>
+ </copyright>
+ <legalnotice>
+ 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.
+
+ </legalnotice>
+
+ <title>Common Caveats</title>
+ <prepared>Bjorn Gustavsson</prepared>
+ <docno></docno>
+ <date>2001-08-08</date>
+ <rev></rev>
+ <file>commoncaveats.xml</file>
+ </header>
+
+ <p>Here we list a few modules and BIFs to watch out for, and not only
+ from a performance point of view.</p>
+
+ <section>
+ <title>The regexp module</title>
+
+ <p>The regular expression functions in the
+ <seealso marker="stdlib:regexp">regexp</seealso>
+ module are written in Erlang, not in C, and were
+ meant for occasional use on small amounts of data,
+ for instance for validation of configuration files
+ when starting an application.</p>
+
+ <p>Use the <seealso marker="stdlib:re">re</seealso> module
+ (introduced in R13A) instead, especially in time-critical code.</p>
+ </section>
+
+ <section>
+ <title>The timer module</title>
+
+ <p>Creating timers using <seealso
+ marker="erts:erlang#erlang:send_after/3">erlang:send_after/3</seealso>
+ and <seealso marker="erts:erlang#erlang:start_timer/3">erlang:start_timer/3</seealso>
+ is much more efficient than using the timers provided by the
+ <seealso marker="stdlib:timer">timer</seealso> module. The
+ <c>timer</c> module uses a separate process to manage the timers,
+ and that process can easily become overloaded if many processes
+ create and cancel timers frequently (especially when using the
+ SMP emulator).</p>
+
+ <p>The functions in the <c>timer</c> module that do not manage timers (such as
+ <c>timer:tc/3</c> or <c>timer:sleep/1</c>), do not call the timer-server process
+ and are therefore harmless.</p>
+ </section>
+
+ <section>
+ <title>list_to_atom/1</title>
+
+ <p>Atoms are not garbage-collected. Once an atom is created, it will never
+ be removed. The emulator will terminate if the limit for the number
+ of atoms (1048576) is reached.</p>
+
+ <p>Therefore, converting arbitrary input strings to atoms could be
+ dangerous in a system that will run continuously.
+ If only certain well-defined atoms are allowed as input, you can use
+ <seealso marker="erts:erlang#list_to_existing_atom/1">list_to_existing_atom/1</seealso>
+ to guard against a denial-of-service attack. (All atoms that are allowed
+ must have been created earlier, for instance by simply using all of them
+ in a module and loading that module.)</p>
+
+ <p>Using <c>list_to_atom/1</c> to construct an atom that is passed to
+ <c>apply/3</c> like this</p>
+
+ <code type="erl">
+apply(list_to_atom("some_prefix"++Var), foo, Args)</code>
+
+ <p>is quite expensive and is not recommended in time-critical code.</p>
+ </section>
+
+ <section>
+ <title>length/1</title>
+
+ <p>The time for calculating the length of a list is proportional to the
+ length of the list, as opposed to <c>tuple_size/1</c>, <c>byte_size/1</c>,
+ and <c>bit_size/1</c>, which all execute in constant time.</p>
+
+ <p>Normally you don't have to worry about the speed of <c>length/1</c>,
+ because it is efficiently implemented in C. In time critical-code, though,
+ you might want to avoid it if the input list could potentially be very long.</p>
+
+ <p>Some uses of <c>length/1</c> can be replaced by matching.
+ For instance, this code</p>
+
+ <code type="erl">
+foo(L) when length(L) >= 3 ->
+ ...</code>
+
+ <p>can be rewritten to</p>
+ <code type="erl">
+foo([_,_,_|_]=L) ->
+ ...</code>
+
+ <p>(One slight difference is that <c>length(L)</c> will fail if the <c>L</c>
+ is an improper list, while the pattern in the second code fragment will
+ accept an improper list.)</p>
+ </section>
+
+ <section>
+ <title>setelement/3</title>
+
+ <p><seealso marker="erts:erlang#setelement/3">setelement/3</seealso>
+ copies the tuple it modifies. Therefore, updating a tuple in a loop
+ using <c>setelement/3</c> will create a new copy of the tuple every time.</p>
+
+ <p>There is one exception to the rule that the tuple is copied.
+ If the compiler clearly can see that destructively updating the tuple would
+ give exactly the same result as if the tuple was copied, the call to
+ <c>setelement/3</c> will be replaced with a special destructive setelement
+ instruction. In the following code sequence</p>
+
+ <code type="erl">
+multiple_setelement(T0) ->
+ T1 = setelement(9, T0, bar),
+ T2 = setelement(7, T1, foobar),
+ setelement(5, T2, new_value).</code>
+
+ <p>the first <c>setelement/3</c> call will copy the tuple and modify the
+ ninth element. The two following <c>setelement/3</c> calls will modify
+ the tuple in place.</p>
+
+ <p>For the optimization to be applied, <em>all</em> of the followings conditions
+ must be true:</p>
+
+ <list type="bulleted">
+ <item>The indices must be integer literals, not variables or expressions.</item>
+ <item>The indices must be given in descending order.</item>
+ <item>There must be no calls to other function in between the calls to
+ <c>setelement/3</c>.</item>
+ <item>The tuple returned from one <c>setelement/3</c> call must only be used
+ in the subsequent call to <c>setelement/3</c>.</item>
+ </list>
+
+ <p>If it is not possible to structure the code as in the <c>multiple_setelement/1</c>
+ example, the best way to modify multiple elements in a large tuple is to
+ convert the tuple to a list, modify the list, and convert the list back to
+ a tuple.</p>
+ </section>
+
+ <section>
+ <title>size/1</title>
+
+ <p><c>size/1</c> returns the size for both tuples and binary.</p>
+
+ <p>Using the new BIFs <c>tuple_size/1</c> and <c>byte_size/1</c> introduced
+ in R12B gives the compiler and run-time system more opportunities for
+ optimization. A further advantage is that the new BIFs could help Dialyzer
+ find more bugs in your program.</p>
+ </section>
+
+ <section>
+ <title>split_binary/2</title>
+ <p>It is usually more efficient to split a binary using matching
+ instead of calling the <c>split_binary/2</c> function.
+ Furthermore, mixing bit syntax matching and <c>split_binary/2</c>
+ may prevent some optimizations of bit syntax matching.</p>
+
+ <p><em>DO</em></p>
+ <code type="none"><![CDATA[
+ <<Bin1:Num/binary,Bin2/binary>> = Bin,]]></code>
+ <p><em>DO NOT</em></p>
+ <code type="none">
+ {Bin1,Bin2} = split_binary(Bin, Num)
+ </code>
+ </section>
+
+ <section>
+ <title>The '--' operator</title>
+ <p>Note that the '<c>--</c>' operator has a complexity
+ proportional to the product of the length of its operands,
+ meaning that it will be very slow if both of its operands
+ are long lists:</p>
+
+ <p><em>DO NOT</em></p>
+ <code type="none"><![CDATA[
+ HugeList1 -- HugeList2]]></code>
+
+ <p>Instead use the <seealso marker="stdlib:ordsets">ordsets</seealso>
+ module:</p>
+
+ <p><em>DO</em></p>
+ <code type="none">
+ HugeSet1 = ordsets:from_list(HugeList1),
+ HugeSet2 = ordsets:from_list(HugeList2),
+ ordsets:subtract(HugeSet1, HugeSet2)
+ </code>
+
+ <p>Obviously, that code will not work if the original order
+ of the list is important. If the order of the list must be
+ preserved, do like this:</p>
+
+ <p><em>DO</em></p>
+ <code type="none"><![CDATA[
+ Set = gb_sets:from_list(HugeList2),
+ [E || E <- HugeList1, not gb_sets:is_element(E, Set)]]]></code>
+
+ <p>Subtle note 1: This code behaves differently from '<c>--</c>'
+ if the lists contain duplicate elements. (One occurrence
+ of an element in HugeList2 will remove <em>all</em>
+ occurrences in HugeList1.)</p>
+
+ <p>Subtle note 2: This code compares lists elements using the
+ '<c>==</c>' operator, while '<c>--</c>' uses the '<c>=:=</c>'. If
+ that difference is important, <c>sets</c> can be used instead of
+ <c>gb_sets</c>, but note that <c>sets:from_list/1</c> is much
+ slower than <c>gb_sets:from_list/1</c> for long lists.</p>
+
+ <p>Using the '<c>--</c>' operator to delete an element
+ from a list is not a performance problem:</p>
+
+ <p><em>OK</em></p>
+ <code type="none">
+ HugeList1 -- [Element]
+ </code>
+
+ </section>
+
+</chapter>
+