aboutsummaryrefslogtreecommitdiffstats
path: root/system/doc/efficiency_guide/processes.xml
diff options
context:
space:
mode:
Diffstat (limited to 'system/doc/efficiency_guide/processes.xml')
-rw-r--r--system/doc/efficiency_guide/processes.xml264
1 files changed, 264 insertions, 0 deletions
diff --git a/system/doc/efficiency_guide/processes.xml b/system/doc/efficiency_guide/processes.xml
new file mode 100644
index 0000000000..a25ec53370
--- /dev/null
+++ b/system/doc/efficiency_guide/processes.xml
@@ -0,0 +1,264 @@
+<?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>Processes</title>
+ <prepared>Bjorn Gustavsson</prepared>
+ <docno></docno>
+ <date>2007-11-21</date>
+ <rev></rev>
+ <file>processes.xml</file>
+ </header>
+
+ <section>
+ <title>Creation of an Erlang process</title>
+
+ <p>An Erlang process is lightweight compared to operating
+ systems threads and processes.</p>
+
+ <p>A newly spawned Erlang process uses 309 words of memory
+ in the non-SMP emulator without HiPE support. (SMP support
+ and HiPE support will both add to this size.) The size can
+ be found out like this:</p>
+
+ <pre>
+Erlang (BEAM) emulator version 5.6 [async-threads:0] [kernel-poll:false]
+
+Eshell V5.6 (abort with ^G)
+1> <input>Fun = fun() -> receive after infinity -> ok end end.</input>
+#Fun&lt;...>
+2> <input>{_,Bytes} = process_info(spawn(Fun), memory).</input>
+{memory,1232}
+3> <input>Bytes div erlang:system_info(wordsize).</input>
+309</pre>
+
+ <p>The size includes 233 words for the heap area (which includes the stack).
+ The garbage collector will increase the heap as needed.</p>
+
+ <p>The main (outer) loop for a process <em>must</em> be tail-recursive.
+ If not, the stack will grow until the process terminates.</p>
+
+ <p><em>DO NOT</em></p>
+ <code type="erl">
+loop() ->
+ receive
+ {sys, Msg} ->
+ handle_sys_msg(Msg),
+ loop();
+ {From, Msg} ->
+ Reply = handle_msg(Msg),
+ From ! Reply,
+ loop()
+ end,
+ io:format("Message is processed~n", []).</code>
+
+ <p>The call to <c>io:format/2</c> will never be executed, but a
+ return address will still be pushed to the stack each time
+ <c>loop/0</c> is called recursively. The correct tail-recursive
+ version of the function looks like this:</p>
+
+ <p><em>DO</em></p>
+<code type="erl">
+ loop() ->
+ receive
+ {sys, Msg} ->
+ handle_sys_msg(Msg),
+ loop();
+ {From, Msg} ->
+ Reply = handle_msg(Msg),
+ From ! Reply,
+ loop()
+ end.</code>
+
+ <section>
+ <title>Initial heap size</title>
+
+ <p>The default initial heap size of 233 words is quite conservative
+ in order to support Erlang systems with hundreds of thousands or
+ even millions of processes. The garbage collector will grow and
+ shrink the heap as needed.</p>
+
+ <p>In a system that use comparatively few processes, performance
+ <em>might</em> be improved by increasing the minimum heap size using either
+ the <c>+h</c> option for
+ <seealso marker="erts:erl">erl</seealso> or on a process-per-process
+ basis using the <c>min_heap_size</c> option for
+ <seealso marker="erts:erlang#spawn_opt/4">spawn_opt/4</seealso>.</p>
+
+ <p>The gain is twofold: Firstly, although the garbage collector will
+ grow the heap, it will it grow it step by step, which will be more
+ costly than directly establishing a larger heap when the process
+ is spawned. Secondly, the garbage collector may also shrink the
+ heap if it is much larger than the amount of data stored on it;
+ setting the minimum heap size will prevent that.</p>
+
+ <warning><p>The emulator will probably use more memory, and because garbage
+ collections occur less frequently, huge binaries could be
+ kept much longer.</p></warning>
+
+ <p>In systems with many processes, computation tasks that run
+ for a short time could be spawned off into a new process with
+ a higher minimum heap size. When the process is done, it will
+ send the result of the computation to another process and terminate.
+ If the minimum heap size is calculated properly, the process may not
+ have to do any garbage collections at all.
+ <em>This optimization should not be attempted
+ without proper measurements.</em></p>
+ </section>
+
+ </section>
+
+ <section>
+ <title>Process messages</title>
+
+ <p>All data in messages between Erlang processes is copied, with
+ the exception of
+ <seealso marker="binaryhandling#refc_binary">refc binaries</seealso>
+ on the same Erlang node.</p>
+
+ <p>When a message is sent to a process on another Erlang node,
+ it will first be encoded to the Erlang External Format before
+ being sent via an TCP/IP socket. The receiving Erlang node decodes
+ the message and distributes it to the right process.</p>
+
+ <section>
+ <title>The constant pool</title>
+
+ <p>Constant Erlang terms (also called <em>literals</em>) are now
+ kept in constant pools; each loaded module has its own pool.
+ The following function</p>
+
+ <p><em>DO</em> (in R12B and later)</p>
+ <code type="erl">
+days_in_month(M) ->
+ element(M, {31,28,31,30,31,30,31,31,30,31,30,31}).</code>
+
+ <p>will no longer build the tuple every time it is called (only
+ to have it discarded the next time the garbage collector was run), but
+ the tuple will be located in the module's constant pool.</p>
+
+ <p>But if a constant is sent to another process (or stored in
+ an ETS table), it will be <em>copied</em>.
+ The reason is that the run-time system must be able
+ to keep track of all references to constants in order to properly
+ unload code containing constants. (When the code is unloaded,
+ the constants will be copied to the heap of the processes that refer
+ to them.) The copying of constants might be eliminated in a future
+ release.</p>
+ </section>
+
+ <section>
+ <title>Loss of sharing</title>
+
+ <p>Shared sub-terms are <em>not</em> preserved when a term is sent
+ to another process, passed as the initial process arguments in
+ the <c>spawn</c> call, or stored in an ETS table.
+ That is an optimization. Most applications do not send message
+ with shared sub-terms.</p>
+
+ <p>Here is an example of how a shared sub-term can be created:</p>
+
+ <code type="erl">
+kilo_byte() ->
+ kilo_byte(10, [42]).
+
+kilo_byte(0, Acc) ->
+ Acc;
+kilo_byte(N, Acc) ->
+ kilo_byte(N-1, [Acc|Acc]).</code>
+
+ <p><c>kilo_byte/1</c> creates a deep list. If we call
+ <c>list_to_binary/1</c>, we can convert the deep list to a binary
+ of 1024 bytes:</p>
+
+ <pre>
+1> <input>byte_size(list_to_binary(efficiency_guide:kilo_byte())).</input>
+1024</pre>
+
+ <p>Using the <c>erts_debug:size/1</c> BIF we can see that the
+ deep list only requires 22 words of heap space:</p>
+
+ <pre>
+2> <input>erts_debug:size(efficiency_guide:kilo_byte()).</input>
+22</pre>
+
+ <p>Using the <c>erts_debug:flat_size/1</c> BIF, we can calculate
+ the size of the deep list if sharing is ignored. It will be
+ the size of the list when it has been sent to another process
+ or stored in an ETS table:</p>
+
+ <pre>
+3> <input>erts_debug:flat_size(efficiency_guide:kilo_byte()).</input>
+4094</pre>
+
+ <p>We can verify that sharing will be lost if we insert the
+ data into an ETS table:</p>
+
+ <pre>
+4> <input>T = ets:new(tab, []).</input>
+17
+5> <input>ets:insert(T, {key,efficiency_guide:kilo_byte()}).</input>
+true
+6> <input>erts_debug:size(element(2, hd(ets:lookup(T, key)))).</input>
+4094
+7> <input>erts_debug:flat_size(element(2, hd(ets:lookup(T, key)))).</input>
+4094</pre>
+
+ <p>When the data has passed through an ETS table,
+ <c>erts_debug:size/1</c> and <c>erts_debug:flat_size/1</c>
+ return the same value. Sharing has been lost.</p>
+
+ <p>In a future release of Erlang/OTP, we might implement a
+ way to (optionally) preserve sharing. We have no plans to make
+ preserving of sharing the default behaviour, since that would
+ penalize the vast majority of Erlang applications.</p>
+ </section>
+ </section>
+
+ <section>
+ <title>The SMP emulator</title>
+
+ <p>The SMP emulator (introduced in R11B) will take advantage of
+ multi-core or multi-CPU computer by running several Erlang schedulers
+ threads (typically, the same as the number of cores). Each scheduler
+ thread schedules Erlang processes in the same way as the Erlang scheduler
+ in the non-SMP emulator.</p>
+
+ <p>To gain performance by using the SMP emulator, your application
+ <em>must have more than one runnable Erlang process</em> most of the time.
+ Otherwise, the Erlang emulator can still only run one Erlang process
+ at the time, but you must still pay the overhead for locking. Although
+ we try to reduce the locking overhead as much as possible, it will never
+ become exactly zero.</p>
+
+ <p>Benchmarks that may seem to be concurrent are often sequential.
+ The estone benchmark, for instance, is entirely sequential. So is also
+ the most common implementation of the "ring benchmark"; usually one process
+ is active, while the others wait in a <c>receive</c> statement.</p>
+
+ <p>The <seealso marker="percept:percept">percept</seealso> application
+ can be used to profile your application to see how much potential (or lack
+ thereof) it has for concurrency.</p>
+ </section>
+
+</chapter>
+