2015/03/23

Tracing using SDA

The problem

About one or two weeks ago, I needed to find a problem in virtual memory allocation/de-allocation, since a process was running out of virtual memory. In our system we already had some tracing in a library in place, using conditional compilation. However, when building the entire system the trace just gave too much data.

The solution

I stumbled upon an article at http://labs.hoffmanlabs.com about the C-macro tr_print. That was just what I was looking for.

The definition of the macro can be found by issueing the following command

$ libr/text sys$library:sys$lib_c.tlb /extract=vms_macros /output=tt:

Note: I used output to tt:, which is effectively my terminal, so I do not extract to a file, but straight to the screen. The last part of the file shows the definition of C-macro tr_print, which was the only thing I was interested in.

Since we code in HP Pascal, at first I tried to write code like is included in the tr_print macro, but that did not quite work out. Some issues with parameter passing, I guess. Not spending too much time on getting it to work, I decided to create a small C file with a function taking only one string parameter, and to call the C function from a Pascal module.

The source code

The created C file looks like this (stripped from all mandatory style elements):

writetrc_c.c

#include <vms_macros.h>
#include <stdlib.h>

void _write_trc_c( const char *trace_string )
{

    /* NOTE: THE DOUBLE PARENTHESES ARE REQUIRED IN THIS MACRO BY DESIGN */

    tr_print(( trace_string ));

}

and the pascal module looks like this:

writetrc.pas

[
    ENVIRONMENT
    (
        'writetrc.pen'
    )
]

MODULE writetrc;

[GLOBAL,ASYNCHRONOUS]
PROCEDURE write_trc(
    p_trace_string : VARYING [$m1] OF CHAR
);

{----- External Routine Declarations ------}

[EXTERNAL]
PROCEDURE _write_trc_c(
    p_trace_str : [IMMEDIATE] C_STR_T
); EXTERNAL;

{---------- Variable Declarations ---------}
VAR
    lv_trace_string     : [VOLATILE] STRING($m1 + 1); 
                          { volatile to get rid of compiler warning }
    lv_trace_str_ptr    : C_STR_T := NIL;

BEGIN

    { Calling a C routine, so zero terminated string required }

    lv_trace_string := p_trace_string + CHR(0);
    lv_trace_str_ptr := C_STR( lv_trace_string );

    { C-function checks if the trace is activated   }
    { If not, it immediately returns                }

    _write_trc_c( lv_trace_str_ptr );

END; { of PROCEDURE write_trc }

END.

Compilation

Compilation of the C source is done as follows:

$ define DECC$TEXT_LIBRARY SYS$LIBRARY:SYS$LIB_C.TLB
$ cc writetrc_c.c /debug /noopt

Logical DECC$TEXT_LIBRARY needs to be set to let the C compiler find vms_macros.h.
Compilation of the Pascal source is done as follows:

$ pas writetrc /debug /noopt

Note: for development and test, we standard compile with /debug /noopt

Linking

When linking a program that uses the functions above, you must include /SYSEXE. The link command will then look like:

$ link example writetrc.opt/opt /sysexe

Where the file writetrc.opt contains the following 2 lines:

writetrc_c.obj
writetrc.obj

Example program

Just to demonstrate, here is a small example program, that writes "Hello, World! 2015" to screen and in the trace buffer.

[
    INHERIT
    (
        'writetrc.pen'
    )
]
PROGRAM example( INPUT, OUTPUT );

VAR
    i : INTEGER;
    s : STRING(40);
BEGIN
    i := 2015;
    s := 'Hello, World!';
    writetrc( s + DEC(i) );
    WRITELN( s, ' ', i );
END.

Compile as usual and link as described earlier.

Running the example

Open a second terminal to start SDA with the correct privileges. You need at least privilege ALTPRI to start the trace, and another privilege to increase the buffer size. Since I don't know yet which one, I use priv=all for now.

$ set proc /priv=all
$ analyze/system
SDA> TR LOAD
SDA> TR START TRACE ! optionally with /BUFFER=<nr of pages>
SDA>

Go back to the other terminal and run the example:

$ run example
Hello, World! 2015
$

Go back to the system analyzer session.

SDA> TR STOP TRACE
SDA> TR SHOW TRACE

You should get a screen with a header, and one trace line with timestamp and text "Hello, World!  00002015"  (slightly different formatted than the output of the WRITELN statement).

Finally, exit the system analyzer with:

SDA> TR UNLOAD
SDA> EXIT

That's all, folks!

1 comment:

  1. Uh oh, seems like the timestamps get messed up. I have been tracing on Apr 28, 8:45. A lot of the timestamps in TR SHOW TRACE output show Feb 25th 8:07. I hope the trace is still in order and only the timestamps are wrong. Another bug in TR$SDA.EXE?

    ReplyDelete