diff options
author | Erlang/OTP <[email protected]> | 2009-11-20 14:54:40 +0000 |
---|---|---|
committer | Erlang/OTP <[email protected]> | 2009-11-20 14:54:40 +0000 |
commit | 84adefa331c4159d432d22840663c38f155cd4c1 (patch) | |
tree | bff9a9c66adda4df2106dfd0e5c053ab182a12bd /lib/kernel/doc/src/seq_trace.xml | |
download | otp-84adefa331c4159d432d22840663c38f155cd4c1.tar.gz otp-84adefa331c4159d432d22840663c38f155cd4c1.tar.bz2 otp-84adefa331c4159d432d22840663c38f155cd4c1.zip |
The R13B03 release.OTP_R13B03
Diffstat (limited to 'lib/kernel/doc/src/seq_trace.xml')
-rw-r--r-- | lib/kernel/doc/src/seq_trace.xml | 506 |
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> 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> 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> + + <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:<0.30.0> Info {0,1} WITH +"**** Trace Started ****" +17:<0.31.0> Received {0,2} FROM <0.30.0> WITH +{<0.30.0>,the_message} +17:<0.31.0> Info {2,3} WITH +"We are here now" +17:<0.30.0> Received {2,4} FROM <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> + |