<HTML>
<HEAD>
<!-- refpage -->
<TITLE>gen_trace</TITLE>
</HEAD>
<BODY BGCOLOR="#FFFFFF">
<CENTER>
<A HREF="http://www.erlang.se"><IMG BORDER=0 ALT="[Erlang Systems]" SRC="min_head.gif"></A>
<H1>gen_trace</H1>
</CENTER>
<H3>MODULE</H3>
<UL>
gen_trace</UL>
<H3>MODULE SUMMARY</H3>
<UL>
Visualization of traces from gen_server instances</UL>
<H3>DESCRIPTION</H3>
<UL>
<P>A behaviour module for implementing visualizations of
traces of a generic server instance.
By writing abstractions on the state and events of a
certain generic server, one can visualize the traces of that
server in different graphs. The aim of the <code>gen_trace</code>
module is to extract the pictures in the design document from
the running code, therefore depicting the actual behaviour more accurat.
<p>
The key idea is to identify equivalent states, which will be
visualized as one node in a graph. For example, consider a server
call back for which
the <CODE>init</CODE> function
returns the initial state <code>{true,0}</code> and
the only <code>handle_call</code> function updates the state
<code>{Bool,Num}</code> to <code>{not Bool, Num+1}</code>.
Any trace of the state of the program would look like
<code>{true,N}</code>,
<code>{false,N+1}</code>,
<code>{true,N+2}</code>,
<code>{false,N+3}</code>,
<code>{true,N+4}</code>,...
With <code>gen_trace</code> you could define an abstraction function
over the state of the server, instructing to only look at the first
argument of the state, viz.
<pre>
abstract_state({Bool,Num},Store) ->
{Bool,Store}.
</pre>
As a consequence, the trace output will only show to states and the events
between them.
</UL>
<H3>EXPORTS</H3>
In order to use the gen_trace software, one needs a trace to work on and
a function to transform the trace to a graph.
<P><A NAME="dump"><STRONG><CODE>dump(
[process() | {node(),process()}], filename(), [option()]) -> <BR>
<UL>
trace_process :: pid().<BR>
<br>
where option() is </BR>
{len,int()} | {timeout, seconds :: int() | infinity} |
process_dictionary </BR>
</CODE></STRONG></A><BR>
<P>
The function <code>dump</code> is used to collect the trace of a running
program. The trace is stored as a log file (see disk_log). The typical
events that are traced are the callback functions of the behaviours
(handle_call, handle_cast, etc.) together with sending messages.
There is an option available where the content of the process
dictionary is saved as well.
<P>Processes can be specified by their pid or an atom when they are registered.
If a node name is not specified, it is assumed to run on the local node.
Named processes need not be started before one calls this dump function.
The function will wait for them to start and starts tracing them as soon as
they show up. Note that one might, though, loose a few initial actions, since
starting tracing takes a little time.
<p>The function is not complaining about non-existing processes, thus better
check later that you did not mistype a pid or process name by the function
<a href="#proc_info">gen_trace:proc_info/1</a>.
<p>
The filename specifies the log file one writes the trace in. Note that
the trace is appended if the file already exists.
<p>
Options one can specify are the maximum length of the trace, the maximum
time the trace is running and whether one wants to trace changes in the
process dictionary as well.
<p><I>WARNING</I>: tracing is affected by this function. If other processes are tracing
at the same time, unexpected results may happen. For example, all local
function tracing is disabled by gen_trace:dump/3.
</UL>
<p><a name="show"><STRONG><CODE>show(filename()) -> ok. <BR>
<UL>
</CODE></STRONG></A><BR>
<P>
The function show/1 can be used to inspect the content of the
trace file as generated by <a href="#dump">gen_trace:dump/3</a>.
The content of the specified file is written to the screen.
</UL>
<p><a name="proc_info"><STRONG><CODE>proc_info(filename()) -> <BR>
<UL>
{[process() | {node(),process()}],length :: int()}.
</CODE></STRONG></A><BR>
<P>
The function proc_info/1 is used to extract information from
a trace file as generated by <a href="#dump">gen_trace:dump/3</a>.
<P>
Given the name of the trace file, this function traverses the file and
collects all processes that it finds traced. If possible, the name of the
process is provided instead of the pid. It returns the processes and the
length of the trace.
</UL>
<p><a name="proc_select"><STRONG><CODE>proc_select(filename(),[process() | {node(),process()}]) -> ok. <BR>
<UL>
</CODE></STRONG></A><BR>
<p>Given the filename of the trace file, say mytrace.dump, this function
will write a new file, adding "-sel" to the rootname of the file, thus
mytrace-sel.dump, in which only the trace information of the specified
processes is present.
</UL>
<p><a name="abstract"><STRONG><CODE>abstract(callback :: module(), filename(),
[option()]) -> ok.<br>
abstract([{process()|{node(),processid()},callback :: module()}], filename(),
[option()]) -> ok.<br>
<UL>
<br>
where option() = {tool, toolname(), file :: atom()} |
{connect, trace | changetrace | singletrace |
graph | changegraph}
</CODE></STRONG></A><BR>
<P>
After having obtained a trace file with <a href="#dump">gen_trace:dump/3</a>,
the function
abstract/3 is used to get a graphical output of the trace
according to a set of predefined abstraction functions, i.e., the callbacks.
<p>The function can be called in two ways, either with one callback module
or one specifies exactly which callback
is used for which process (the default is taken for unspecified processes).
<p>
The filename is the name of the trace file. The options determine the
operations performed on the data.
<UL>
<LI>One specifies a format in which the data should be written with the
<strong><code>tool</code></strong> option.
Presently implementations for
<UL>
<LI> <strong><code>davinci</code></strong>,
<LI> <strong><code>svg</code></strong>,
<LI> <strong><code>postscript</code></strong>, and
<LI> <strong><code>cadp</code></strong>,
</UL> are provided.
<I>Note</I> that a filename should be provided as an atom in order to
store the graph. The graph data is written into files that
start with that name as prefix and have different extensions (e.g.\
in case of <code>davinci</code>, a file with extension
<code>.daVinci</code> is written, in case of
<code>cadp</code> two files are written with extensions
<code>.aut</code> and <code>.map</code>).
<LI>The option <strong><code>connect</code></strong> is used to select a
way of connecting the data in the graph structure that one is building.
<UL>
<li> with <code>trace</code> <i>(the default)</i> data is presented as
sequence of events
<li> with <code>changetrace</code> data is presented as sequence of events,
only changes in the state data are presented
<li> with <code>singletrace</code> data is presented as sequence of
events and the process identifier is not visable in the state component.
<li> with <code>graph</code> states that are equal under the abstraction
are mapped to the same node.
<li> with <code>changegraph</code> states that are equal under the
abstraction are mapped to the same node and only difference in
data is shown.
</UL>
</UL>
</UL>
<H3>CALLBACK FUNCTIONS</H3>
<P>
From the following callback functions, the functions
<strong><code>init/1</code></strong>,
<strong><code>abstract_state/2</code></strong>, and
<strong><code>abstract_event/2</code></strong> have to be provided.
The other functions are optional and defaults will be substituted
if you omit them.
<P>The abstraction functions compute an abstract state and abstract event
for every state and event as it appears in the trace of the process
that follow the gen_server behaviour.
<p>In order to give extra power to the abstractor, an internal state is
provided for the abstraction functions. We refer to this internal state
as "the store". The datatype <code>store()</code> is equivalent to
<code>term()</code>.
<p><a name="init"><strong><code>init() -> store().<br>
<UL>
</CODE></STRONG></A><BR>
The <code>init</code> function returns the initial value of the store
you want to appoint to the trace of a process.
</UL>
<p><a name="abstract_state"><strong><code>abstract_state(state :: term(),store()) ->
{abstract_state :: term(),store()}.<br>
<UL>
</CODE></STRONG></A><BR>
Every state change of the <code>gen_server</code> that is traced causes
the new state to be passed to the function <code>abstract_state</code> in the
callback module.
The first argument is the state of the gen_server, the second argument the
store of the abstractor. The function should
return an abstract state and new store as result.
The store is passed from state to state and can be used to compute
the new abstract state. For example, one can store the fields of the record
that one wants to extract from the state of the gen_server in the store.
Another possibility is to save information on the states that one has visited
in the store. This is completely left up to the user.
</UL>
<p><a name="abstract_event"><strong><code>abstract_event(event :: term(),store()) ->
{abstract_event :: term(),store()}.<br>
<UL>
</CODE></STRONG></A><BR>
Events connected to the process one is tracing, such as handle_call,
handle_cast, sending a message, are passed on to the abstract_event/2
function.
The function should return an abstract event and a new store.
The abstract state can be any Erlang term; the function
<a href="#abstract_eventseq"><code>abstract_eventseq/2</code></a>
can be used to get a modified list of abstract events.
</UL>
<p><a name="abstract_eventseq"><strong><code>abstract_eventseq([event :: term()],store()) ->
{[abstract_event :: term()],store()}.<br>
<UL>
</CODE></STRONG></A><BR>
This function is called after collecting all abstract events between
a state change. Thus, every event is first abstracted by
<a href="#abstract_event"><code>abstract_event/2</code></a>,
resulting in a list of abstract events. These events are passed on to
<code>abstract_eventseq/2</code>, which returns a new list of abstract events.
This function is typically used to filter the events.
If the function <code>abstract_eventseq/2</code>
is not available in the callback module,
the list of abstract events is not modified.
</UL>
<p><a name="typeset_state">
<strong><code>typeset_state(term()) -> string().<br>
<a name="typeset_event">typeset_event(term()) -> string().<br>
<a name="typeset_eventseq">typeset_eventseq([string()]) -> string().<br>
<UL>
</CODE></STRONG></A><BR>
The list of events between states and the states themself are typesetted
by <a href="#abstract"><code>abstract/3</code></a> before they are passed
on to the tool that is
specified. By default, <code>io_lib:format/2</code> is used to typeset a term.
If one is not content with the output in the graph, one may specify own typeset
functions in the callback module: typeset_state/1, typeset_event/1 and
typeset_eventseq/1.
<p><i>Note</i> that the function <code>typeset_eventseq</code> takes a
list of strings as input. The strings are obtained by typesetting the
events, either by the default typesetting or by the function
<code>typeset_event</code>.
</UL>
<p><a name="terminate"><strong><code>terminate(store()) ->
ok.<br>
<UL>
</CODE></STRONG></A><BR>
After that a trace has been fully abstracted and after that the abstracted,
typesetted information is passed on to the
tool specified, in the <a href="#abstract"><code>abstract</code></a> function,
the function <code>terminate</code> in the callback module is called.
<p>This termination function is typically used in case one wants to archive
the information in the store.
</UL>
<H3>SEE ALSO</H3>
<UL>
<P></UL>
<H3>AUTHORS</H3>
<UL>
Thomas Arts - thomas@cslab.ericsson.se<BR>
</UL>
</BODY>
</HTML>