aboutsummaryrefslogtreecommitdiffstats
path: root/lib/kernel/doc/src/seq_trace.xml
diff options
context:
space:
mode:
Diffstat (limited to 'lib/kernel/doc/src/seq_trace.xml')
-rw-r--r--lib/kernel/doc/src/seq_trace.xml506
1 files changed, 506 insertions, 0 deletions
diff --git a/lib/kernel/doc/src/seq_trace.xml b/lib/kernel/doc/src/seq_trace.xml
new file mode 100644
index 0000000000..6c043dd767
--- /dev/null
+++ b/lib/kernel/doc/src/seq_trace.xml
@@ -0,0 +1,506 @@
+<?xml version="1.0" encoding="latin1" ?>
+<!DOCTYPE erlref SYSTEM "erlref.dtd">
+
+<erlref>
+ <header>
+ <copyright>
+ <year>1998</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>seq_trace</title>
+ <prepared>[email protected]</prepared>
+ <docno></docno>
+ <date>1998-04-16</date>
+ <rev>A</rev>
+ </header>
+ <module>seq_trace</module>
+ <modulesummary>Sequential Tracing of Messages</modulesummary>
+ <description>
+ <p>Sequential tracing makes it possible to trace all messages
+ resulting from one initial message. Sequential tracing is
+ completely independent of the ordinary tracing in Erlang, which
+ is controlled by the <c>erlang:trace/3</c> BIF. See the chapter
+ <seealso marker="#whatis">What is Sequential Tracing</seealso>
+ below for more information about what sequential tracing is and
+ how it can be used.</p>
+ <p><c>seq_trace</c> provides functions which control all aspects of
+ sequential tracing. There are functions for activation,
+ deactivation, inspection and for collection of the trace output.</p>
+ <note>
+ <p>The implementation of sequential tracing is in beta status.
+ This means that the programming interface still might undergo
+ minor adjustments (possibly incompatible) based on feedback
+ from users.</p>
+ </note>
+ </description>
+ <funcs>
+ <func>
+ <name>set_token(Token) -> PreviousToken</name>
+ <fsummary>Set the trace token</fsummary>
+ <type>
+ <v>Token = PreviousToken = term() | []</v>
+ </type>
+ <desc>
+ <p>Sets the trace token for the calling process to <c>Token</c>.
+ If <c>Token == []</c> then tracing is disabled, otherwise
+ <c>Token</c> should be an Erlang term returned from
+ <c>get_token/0</c> or <c>set_token/1</c>. <c>set_token/1</c>
+ can be used to temporarily exclude message passing from
+ the trace by setting the trace token to empty like this:</p>
+ <code type="none">
+OldToken = seq_trace:set_token([]), % set to empty and save
+ % old value
+% do something that should not be part of the trace
+io:format("Exclude the signalling caused by this~n"),
+seq_trace:set_token(OldToken), % activate the trace token again
+... </code>
+ <p>Returns the previous value of the trace token.</p>
+ </desc>
+ </func>
+ <func>
+ <name>set_token(Component, Val) -> {Component, OldVal}</name>
+ <fsummary>Set a component of the trace token</fsummary>
+ <type>
+ <v>Component = label | serial | Flag</v>
+ <v>&nbsp;Flag = send | 'receive' | print | timestamp </v>
+ <v>Val = OldVal -- see below</v>
+ </type>
+ <desc>
+ <p>Sets the individual <c>Component</c> of the trace token to
+ <c>Val</c>. Returns the previous value of the component.</p>
+ <taglist>
+ <tag><c>set_token(label, Int)</c></tag>
+ <item>
+ <p>The <c>label</c> component is an integer which
+ identifies all events belonging to the same sequential
+ trace. If several sequential traces can be active
+ simultaneously, <c>label</c> is used to identify
+ the separate traces. Default is 0.</p>
+ </item>
+ <tag><c>set_token(serial, SerialValue)</c></tag>
+ <item>
+ <p><c>SerialValue = {Previous, Current}</c>.
+ The <c>serial</c> component contains counters which
+ enables the traced messages to be sorted, should never be
+ set explicitly by the user as these counters are updated
+ automatically. Default is <c>{0, 0}</c>.</p>
+ </item>
+ <tag><c>set_token(send, Bool)</c></tag>
+ <item>
+ <p>A trace token flag (<c>true | false</c>) which
+ enables/disables tracing on message sending. Default is
+ <c>false</c>.</p>
+ </item>
+ <tag><c>set_token('receive', Bool)</c></tag>
+ <item>
+ <p>A trace token flag (<c>true | false</c>) which
+ enables/disables tracing on message reception. Default is
+ <c>false</c>.</p>
+ </item>
+ <tag><c>set_token(print, Bool)</c></tag>
+ <item>
+ <p>A trace token flag (<c>true | false</c>) which
+ enables/disables tracing on explicit calls to
+ <c>seq_trace:print/1</c>. Default is <c>false</c>.</p>
+ </item>
+ <tag><c>set_token(timestamp, Bool)</c></tag>
+ <item>
+ <p>A trace token flag (<c>true | false</c>) which
+ enables/disables a timestamp to be generated for each
+ traced event. Default is <c>false</c>.</p>
+ </item>
+ </taglist>
+ </desc>
+ </func>
+ <func>
+ <name>get_token() -> TraceToken</name>
+ <fsummary>Return the value of the trace token</fsummary>
+ <type>
+ <v>TraceToken = term() | []</v>
+ </type>
+ <desc>
+ <p>Returns the value of the trace token for the calling process.
+ If <c>[]</c> is returned, it means that tracing is not active.
+ Any other value returned is the value of an active trace
+ token. The value returned can be used as input to
+ the <c>set_token/1</c> function.</p>
+ </desc>
+ </func>
+ <func>
+ <name>get_token(Component) -> {Component, Val}</name>
+ <fsummary>Return the value of a trace token component</fsummary>
+ <type>
+ <v>Component = label | serial | Flag</v>
+ <v>&nbsp;Flag = send | 'receive' | print | timestamp </v>
+ <v>Val -- see set_token/2</v>
+ </type>
+ <desc>
+ <p>Returns the value of the trace token component
+ <c>Component</c>. See
+ <seealso marker="#set_token/2">set_token/2</seealso> for
+ possible values of <c>Component</c> and <c>Val</c>.</p>
+ </desc>
+ </func>
+ <func>
+ <name>print(TraceInfo) -> void()</name>
+ <fsummary>Put the Erlang term <c>TraceInfo</c>into the sequential trace output</fsummary>
+ <type>
+ <v>TraceInfo = term()</v>
+ </type>
+ <desc>
+ <p>Puts the Erlang term <c>TraceInfo</c> into the sequential
+ trace output if the calling process currently is executing
+ within a sequential trace and the <c>print</c> flag of
+ the trace token is set.</p>
+ </desc>
+ </func>
+ <func>
+ <name>print(Label, TraceInfo) -> void()</name>
+ <fsummary>Put the Erlang term <c>TraceInfo</c>into the sequential trace output</fsummary>
+ <type>
+ <v>Label = int()</v>
+ <v>TraceInfo = term()</v>
+ </type>
+ <desc>
+ <p>Same as <c>print/1</c> with the additional condition that
+ <c>TraceInfo</c> is output only if <c>Label</c> is equal to
+ the label component of the trace token.</p>
+ </desc>
+ </func>
+ <func>
+ <name>reset_trace() -> void()</name>
+ <fsummary>Stop all sequential tracing on the local node</fsummary>
+ <desc>
+ <p>Sets the trace token to empty for all processes on the
+ local node. The process internal counters used to create
+ the serial of the trace token is set to 0. The trace token is
+ set to empty for all messages in message queues. Together
+ this will effectively stop all ongoing sequential tracing in
+ the local node.</p>
+ </desc>
+ </func>
+ <func>
+ <name>set_system_tracer(Tracer) -> OldTracer</name>
+ <fsummary>Set the system tracer</fsummary>
+ <type>
+ <v>Tracer = OldTracer = pid() | port() | false</v>
+ </type>
+ <desc>
+ <p>Sets the system tracer. The system tracer can be either a
+ process or port denoted by <c>Tracer</c>. Returns the previous
+ value (which can be <c>false</c> if no system tracer is
+ active).</p>
+ <p>Failure: <c>{badarg, Info}}</c> if <c>Pid</c> is not an
+ existing local pid.</p>
+ </desc>
+ </func>
+ <func>
+ <name>get_system_tracer() -> Tracer</name>
+ <fsummary>Return the pid() or port() of the current system tracer.</fsummary>
+ <type>
+ <v>Tracer = pid() | port() | false</v>
+ </type>
+ <desc>
+ <p>Returns the pid or port identifier of the current system
+ tracer or <c>false</c> if no system tracer is activated.</p>
+ </desc>
+ </func>
+ </funcs>
+
+ <section>
+ <title>Trace Messages Sent To the System Tracer</title>
+ <p>The format of the messages are:</p>
+ <code type="none">
+{seq_trace, Label, SeqTraceInfo, TimeStamp}</code>
+ <p>or</p>
+ <code type="none">
+{seq_trace, Label, SeqTraceInfo}</code>
+ <p>depending on whether the <c>timestamp</c> flag of the trace
+ token is set to <c>true</c> or <c>false</c>. Where:</p>
+ <code type="none">
+Label = int()
+TimeStamp = {Seconds, Milliseconds, Microseconds}
+ Seconds = Milliseconds = Microseconds = int()</code>
+ <p>The <c>SeqTraceInfo</c> can have the following formats:</p>
+ <taglist>
+ <tag><c>{send, Serial, From, To, Message}</c></tag>
+ <item>
+ <p>Used when a process <c>From</c> with its trace token flag
+ <c>print</c> set to <c>true</c> has sent a message.</p>
+ </item>
+ <tag><c>{'receive', Serial, From, To, Message}</c></tag>
+ <item>
+ <p>Used when a process <c>To</c> receives a message with a
+ trace token that has the <c>'receive'</c> flag set to
+ <c>true</c>.</p>
+ </item>
+ <tag><c>{print, Serial, From, _, Info}</c></tag>
+ <item>
+ <p>Used when a process <c>From</c> has called
+ <c>seq_trace:print(Label, TraceInfo)</c> and has a trace
+ token with the <c>print</c> flag set to <c>true</c> and
+ <c>label</c> set to <c>Label</c>.</p>
+ </item>
+ </taglist>
+ <p><c>Serial</c> is a tuple <c>{PreviousSerial, ThisSerial}</c>,
+ where the first integer <c>PreviousSerial</c> denotes the serial
+ counter passed in the last received message which carried a trace
+ token. If the process is the first one in a new sequential trace,
+ <c>PreviousSerial</c> is set to the value of the process internal
+ "trace clock". The second integer <c>ThisSerial</c> is the serial
+ counter that a process sets on outgoing messages and it is based
+ on the process internal "trace clock" which is incremented by one
+ before it is attached to the trace token in the message.</p>
+ </section>
+
+ <section>
+ <marker id="whatis"></marker>
+ <title>What is Sequential Tracing</title>
+ <p>Sequential tracing is a way to trace a sequence of messages sent
+ between different local or remote processes, where the sequence
+ is initiated by one single message. In short it works like this:</p>
+ <p>Each process has a <em>trace token</em>, which can be empty or
+ not empty. When not empty the trace token can be seen as
+ the tuple <c>{Label, Flags, Serial, From}</c>. The trace token is
+ passed invisibly with each message.</p>
+ <p>In order to start a sequential trace the user must explicitly set
+ the trace token in the process that will send the first message
+ in a sequence.</p>
+ <p>The trace token of a process is set each time the process
+ matches a message in a receive statement, according to the trace
+ token carried by the received message, empty or not.</p>
+ <p>On each Erlang node a process can be set as the <em>system tracer</em>. This process will receive trace messages each time
+ a message with a trace token is sent or received (if the trace
+ token flag <c>send</c> or <c>'receive'</c> is set). The system
+ tracer can then print each trace event, write it to a file or
+ whatever suitable.</p>
+ <note>
+ <p>The system tracer will only receive those trace events that
+ occur locally within the Erlang node. To get the whole picture
+ of a sequential trace that involves processes on several Erlang
+ nodes, the output from the system tracer on each involved node
+ must be merged (off line).</p>
+ </note>
+ <p>In the following sections Sequential Tracing and its most
+ fundamental concepts are described.</p>
+ </section>
+
+ <section>
+ <title>Trace Token</title>
+ <p>Each process has a current trace token. Initially the token is
+ empty. When the process sends a message to another process, a
+ copy of the current token will be sent "invisibly" along with
+ the message.</p>
+ <p>The current token of a process is set in two ways, either</p>
+ <list type="ordered">
+ <item>
+ <p>explicitly by the process itself, through a call to
+ <c>seq_trace:set_token</c>, or</p>
+ </item>
+ <item>
+ <p>when a message is received.</p>
+ </item>
+ </list>
+ <p>In both cases the current token will be set. In particular, if
+ the token of a message received is empty, the current token of
+ the process is set to empty.</p>
+ <p>A trace token contains a label, and a set of flags. Both
+ the label and the flags are set in 1 and 2 above.</p>
+ </section>
+
+ <section>
+ <title>Serial</title>
+ <p>The trace token contains a component which is called
+ <c>serial</c>. It consists of two integers <c>Previous</c> and
+ <c>Current</c>. The purpose is to uniquely identify each traced
+ event within a trace sequence and to order the messages
+ chronologically and in the different branches if any.</p>
+ <p>The algorithm for updating <c>Serial</c> can be described as
+ follows:</p>
+ <p>Let each process have two counters <c>prev_cnt</c> and
+ <c>curr_cnt</c> which both are set to 0 when a process is created.
+ The counters are updated at the following occasions:</p>
+ <list type="bulleted">
+ <item>
+ <p><em>When the process is about to send a message and the trace token is not empty.</em></p>
+ <p>Let the serial of the trace token be <c>tprev</c> and
+ <c>tcurr</c>. <br></br>
+<c>curr_cnt := curr_cnt + 1</c> <br></br>
+<c>tprev := prev_cnt</c> <br></br>
+<c>tcurr := curr_cnt</c></p>
+ <p>The trace token with <c>tprev</c> and <c>tcurr</c> is then
+ passed along with the message.</p>
+ </item>
+ <item>
+ <p><em>When the process calls</em><c>seq_trace:print(Label, Info)</c>, <em>Label matches the label part of the trace token and the trace token print flag is true.</em></p>
+ <p>The same algorithm as for send above.</p>
+ </item>
+ <item>
+ <p><em>When a message is received and contains a nonempty trace token.</em></p>
+ <p>The process trace token is set to the trace token from
+ the message.</p>
+ <p>Let the serial of the trace token be <c>tprev</c> and
+ <c>tcurr</c>. <br></br>
+<c><![CDATA[if (curr_cnt < tcurr )]]></c> <br></br>
+
+ &nbsp; &nbsp; &nbsp; &nbsp;<c>curr_cnt := tcurr</c> <br></br>
+<c>prev_cnt := tcurr</c></p>
+ </item>
+ </list>
+ <p>The <c>curr_cnt</c> of a process is incremented each time
+ the process is involved in a sequential trace. The counter can
+ reach its limit (27 bits) if a process is very long-lived and is
+ involved in much sequential tracing. If the counter overflows it
+ will not be possible to use the serial for ordering of the trace
+ events. To prevent the counter from overflowing in the middle of
+ a sequential trace the function <c>seq_trace:reset_trace/0</c>
+ can be called to reset the <c>prev_cnt</c> and <c>curr_cnt</c> of
+ all processes in the Erlang node. This function will also set all
+ trace tokens in processes and their message queues to empty and
+ will thus stop all ongoing sequential tracing.</p>
+ </section>
+
+ <section>
+ <title>Performance considerations</title>
+ <p>The performance degradation for a system which is enabled for
+ Sequential Tracing is negligible as long as no tracing is
+ activated. When tracing is activated there will of course be an
+ extra cost for each traced message but all other messages will be
+ unaffected.</p>
+ </section>
+
+ <section>
+ <title>Ports</title>
+ <p>Sequential tracing is not performed across ports.</p>
+ <p>If the user for some reason wants to pass the trace token to a
+ port this has to be done manually in the code of the port
+ controlling process. The port controlling processes have to check
+ the appropriate sequential trace settings (as obtained from
+ <c>seq_trace:get_token/1</c> and include trace information in
+ the message data sent to their respective ports.</p>
+ <p>Similarly, for messages received from a port, a port controller
+ has to retrieve trace specific information, and set appropriate
+ sequential trace flags through calls to
+ <c>seq_trace:set_token/2</c>.</p>
+ </section>
+
+ <section>
+ <title>Distribution</title>
+ <p>Sequential tracing between nodes is performed transparently.
+ This applies to C-nodes built with Erl_Interface too. A C-node
+ built with Erl_Interface only maintains one trace token, which
+ means that the C-node will appear as one process from
+ the sequential tracing point of view.</p>
+ <p>In order to be able to perform sequential tracing between
+ distributed Erlang nodes, the distribution protocol has been
+ extended (in a backward compatible way). An Erlang node which
+ supports sequential tracing can communicate with an older
+ (OTP R3B) node but messages passed within that node can of course
+ not be traced.</p>
+ </section>
+
+ <section>
+ <title>Example of Usage</title>
+ <p>The example shown here will give rough idea of how the new
+ primitives can be used and what kind of output it will produce.</p>
+ <p>Assume that we have an initiating process with
+ <c><![CDATA[Pid == <0.30.0>]]></c> like this:</p>
+ <code type="none">
+-module(seqex).
+-compile(export_all).
+
+loop(Port) ->
+ receive
+ {Port,Message} ->
+ seq_trace:set_token(label,17),
+ seq_trace:set_token('receive',true),
+ seq_trace:set_token(print,true),
+ seq_trace:print(17,"**** Trace Started ****"),
+ call_server ! {self(),the_message};
+ {ack,Ack} ->
+ ok
+ end,
+ loop(Port).</code>
+ <p>And a registered process <c>call_server</c> with
+ <c><![CDATA[Pid == <0.31.0>]]></c> like this:</p>
+ <code type="none">
+loop() ->
+ receive
+ {PortController,Message} ->
+ Ack = {received, Message},
+ seq_trace:print(17,"We are here now"),
+ PortController ! {ack,Ack}
+ end,
+ loop().</code>
+ <p>A possible output from the system's sequential_tracer (inspired
+ by AXE-10 and MD-110) could look like:</p>
+ <pre>
+17:&lt;0.30.0> Info {0,1} WITH
+"**** Trace Started ****"
+17:&lt;0.31.0> Received {0,2} FROM &lt;0.30.0> WITH
+{&lt;0.30.0>,the_message}
+17:&lt;0.31.0> Info {2,3} WITH
+"We are here now"
+17:&lt;0.30.0> Received {2,4} FROM &lt;0.31.0> WITH
+{ack,{received,the_message}}</pre>
+ <p>The implementation of a system tracer process that produces
+ the printout above could look like this:</p>
+ <code type="none">
+tracer() ->
+ receive
+ {seq_trace,Label,TraceInfo} ->
+ print_trace(Label,TraceInfo,false);
+ {seq_trace,Label,TraceInfo,Ts} ->
+ print_trace(Label,TraceInfo,Ts);
+ Other -> ignore
+ end,
+ tracer().
+
+print_trace(Label,TraceInfo,false) ->
+ io:format("~p:",[Label]),
+ print_trace(TraceInfo);
+print_trace(Label,TraceInfo,Ts) ->
+ io:format("~p ~p:",[Label,Ts]),
+ print_trace(TraceInfo).
+
+print_trace({print,Serial,From,_,Info}) ->
+ io:format("~p Info ~p WITH~n~p~n", [From,Serial,Info]);
+print_trace({'receive',Serial,From,To,Message}) ->
+ io:format("~p Received ~p FROM ~p WITH~n~p~n",
+ [To,Serial,From,Message]);
+print_trace({send,Serial,From,To,Message}) ->
+ io:format("~p Sent ~p TO ~p WITH~n~p~n",
+ [From,Serial,To,Message]).</code>
+ <p>The code that creates a process that runs the tracer function
+ above and sets that process as the system tracer could look like
+ this:</p>
+ <code type="none">
+start() ->
+ Pid = spawn(?MODULE,tracer,[]),
+ seq_trace:set_system_tracer(Pid), % set Pid as the system tracer
+ ok.</code>
+ <p>With a function like <c>test/0</c> below the whole example can be
+ started.</p>
+ <code type="none">
+test() ->
+ P = spawn(?MODULE, loop, [port]),
+ register(call_server, spawn(?MODULE, loop, [])),
+ start(),
+ P ! {port,message}.</code>
+ </section>
+</erlref>
+