%
% x-kernel v3.3
%
% Copyright (c) 1996,1993,1991,1990  Arizona Board of Regents
%

\section{Trace Library}\label{trace_lib}

The {\xk} provides two different facilities for tracing protocol
execution. The first, which is described in this section, supports the
conditional printing, in {\var printf} format, of statements taking
from zero to six variables. Every protocol should make use of the
trace facililty described in this section. The second, which is
described in the next section, supports the collection of fine-grain
trace data, and the storage of this data to files, where it can later
be analyzed. Protocols use this more advanced facility only when they
are being instrumented for detailed performance analysis.

\subsection{Type Definitions}\label{trace_type_defs}

The current value of the trace variable {\var tracevar} is used to
control whether or not a particular trace operation takes place.  The
trace variable values can be set at system build time (see
Section~\ref{config}).  The following defined constants are suggestive
of how to use trace levels.

\begin{tabbing}
xxxx \= xxxxxxxxxxxxxxxxxxxxxxxxxxx \= \kill
\>{\var TR\_NEVER}             \>for debugging statements that are unused (noop)\\
\>{\var TR\_FULL\_TRACE}       \>every subroutine entry and exit\\
\>{\var TR\_DETAILED}          \>all functions plus dumps of data structures at strategic points\\
\>{\var TR\_FUNCTIONAL\_TRACE} \>all the functions of the module and their parameters\\
\>{\var TR\_MORE\_EVENTS}      \>even more detail on events\\
\>{\var TR\_EVENTS}            \>more detail than major events\\
\>{\var TR\_SOFT\_ERRORS}      \>mild warnings\\
\>{\var TR\_MAJOR\_EVENTS}     \>open, close, etc.\\
\>{\var TR\_GROSS\_EVENTS}     \>the coarsest tracing level\\
\>{\var TR\_ERRORS}            \>serious non-fatal errors; some residual event traces\\
\>{\var TR\_ALWAYS}            \>normally only used during protocol development
\end{tabbing}

\subsection{Operations}\label{trace_ops}

\subsubsection{xTrace}\label{xTrace}
\index{xTrace}

The {\var xTrace}$n$ macros take $n$ arguments (where 0 $<$= $n$ $<$= 6)
in addition to the variables {\var tracevar}, {\var tracelevel}, and
{\var formatstring}.  {\var tracevar} is a name associated with the
protocol or subsystem being traced.  {\var tracelevel} is compared to
the value of the trace variable to determine at runtime if the trace
statement should be printed.  {\var formatstring} is a {\var
printf}-style formatting statement.

Each protocol has a trace variable based on the protocol name with
``trace'' prepended and ``p'' appended; e.g., udp has trace variable
{\var traceudpp}.  In addition to protocol tracing, there are {\xk}
trace variables for subsystems: e.g., init, processswitch, protocol,
processcreation, event, msg and ptbl.  These are defined in the file
{\var xkernel/include/xk\_debug.h}.

Note that the trace facility automatically supplies a newline at the
end of the trace message, therefore the supplied format string need
not.  Also, the trace facility prepends ``trace'' to the 
{\var tracevar} argument passed in.  Thus, the first argument must be the
protocol name with only ``p'' appended; e.g., {\var udpp} for udp.
Because of this prepending, there should be no whitespace preceding a
trace variable name in any tracing statement.  Whitespace will cause
errors in the macro expansion and result in compilation errors.
\medskip

{\var xTrace$n$(int tracevar, int tracelevel, char *formatstring, args, ...)}
\medskip

\noindent
For example:

\begin{verbatim}
    int traceudpp;

    xTrace2(udpp, TR_ERRORS, "input port %d output port %d", inp, outp);
\end{verbatim}

\noindent
will print the trace message if the {\xk} was built in DEBUG mode (see
Section~\ref{config} and if {\var TR\_ERRORS} $<$= {\var traceudpp}.

\subsubsection{xTraceP, xTraceS}\label{xTraceP}\label{xTraceS}
\index{xTraceP}
\index{xTraceS}

The {\var xTraceP}$n$ and {\var xTraceS}$n$ macros function much the
same way as the {\var xTrace}$n$ macros, except that they take a 
{\var Protl} or {\var Sessn} as their first parameter (instead of a
trace variable) and they print the protocol instance name before the
rest of the trace statement.  This turns out to be very useful when
reading an {\xk} trace where several protocols were interleaving trace
statements.  We recommend using the {\var xTraceP}$n$ and {\var xTraceS}$n$
macros whenever you have an appropriate {\var Protl} {\var Sessn} in
scope, using the {\var xTrace}$n$ macros only when there is no such
{\var Protl} or {\var Sessn} available.
\medskip

{\var xTraceP$n$(Protl protocol, int tracelevel, char *formatstring, args, ...)}
{\var xTraceS$n$(Sessn session, int tracelevel, char *formatstring, args, ...)}
\medskip

\subsubsection{xIfTrace, xIfTraceP, xIfTraceS}\label{xIfTrace}
\index{xIfTrace}
\index{xIfTraceP}
\index{xIfTraceS}

If the {\var tracelevel} is less than or equal to the value of the
{\var tracevar}, then execute the statement directly following.
\smallskip

{\var xIfTrace(int tracevar, int tracelevel)}
\medskip

\noindent
For example:

\begin{verbatim}
        int traceudpp;

        xIfTrace(udpp, TR_ERRORS)
            dump_header();
\end{verbatim}

\noindent
{\var xIfTraceP} and {\var xIfTraceS} are the analogous operations,
taking a {\var Protl} or {\var Sessn} instead of a trace variable.
\medskip

{\var xIfTraceP(Protl protocol, int tracelevel)}
{\var xIfTraceS(Sessn session, int tracelevel)}

\subsection{Usage Rules}\label{trace_usage}

Trace statements are macros which are only active in DEBUG mode
(see Section~\ref{config}).  If you are writing a new protocol,
you should insert trace statements.  Even though there will be no
bugs left after you release your protocol, it may help others in
debugging their protocols.  Don't delete these very helpful
debugging statements when you are done.

The trace levels listed in Section~\ref{trace_type_defs} are in
increasing order of severity.  When an {\xk} runs with tracing
enabled, trace statements associated with a trace variable will print
if their trace level is at least as severe as the value of the trace
variable.  For example, if the TCP trace variable is set to 
{\var TR\_GROSS\_EVENTS}, this will cause TCP trace statements with trace
levels of {\var TR\_GROSS\_EVENTS}, {\var TR\_ERRORS} and 
{\var TR\_ALWAYS} to be displayed.  To display all TCP trace statements, you
would set the TCP trace variable to have the value 
{\var TR\_FULL\_TRACE}.
