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!