Trailing-Edge
-
PDP-10 Archives
-
BB-AE97C-BM
-
sources/trace.mac
There are 14 other files named trace.mac in the archive. Click here to see a list.
TITLE TRACE
SEARCH MONSYM,MACSYM
TWOSEG
RELOC 0
SALL
;****************************************************************************
;* *
;* COPYRIGHT (C) 1985 *
;* BY DIGITAL EQUIPMENT CORPORATION, MAYNARD, MASS. *
;* ALL RIGHTS RESERVED. *
;* *
;* THIS SOFTWARE IS FURNISHED UNDER A LICENSE AND MAY BE USED AND COPIED *
;* ONLY IN ACCORDANCE WITH THE TERMS OF SUCH LICENSE AND WITH THE *
;* INCLUSION OF THE ABOVE COPYRIGHT NOTICE. THIS SOFTWARE OR ANY OTHER *
;* COPIES THEREOF MAY NOT BE PROVIDED OR OTHERWISE MADE AVAILABLE TO ANY *
;* OTHER PERSON. TITLE TO AND OWNERSHIP OF THE SOFTWARE IS HEREBY *
;* TRANSFERRED. *
;* *
;* THE INFORMATION IN THIS SOFTWARE IS SUBJECT TO CHANGE WITHOUT NOTICE *
;* AND SHOULD NOT BE CONSTRUED AS A COMMITMENT BY DIGITAL EQUIPMENT *
;* CORPORATION. *
;* *
;* DIGITAL ASSUMES NO RESPONSIBILITY FOR THE USE OR RELIABILITY OF ITS *
;* SOFTWARE ON EQUIPMENT WHICH IS NOT SUPPLIED BY DIGITAL. *
;* *
;****************************************************************************
;
; FUNCTIONAL SPEC:
;
; This module is part of the EDT-36 system. Its function is to record
; the total length of CPU time spent in a given routine. It accepts
; the following arguments on the stack:
;
; ARGUMENTS:
;
; .TFCN the function code. This may be one of the following:
;
; 1 - Enable tracing on all or one routine
; 2 - Disable tracing on all or one routine
; 3 - Reset the trace database
; 4 - List the current state of the database
; 5 - Open the trace file, TRACE.DAT
; 6 - Close the trace file
;
; .TPTR Byte pointer to the name of the routine to trace, or 0.
;
; .TNUM Number of stack items to record on entry to routine.
;
; .TLOC Name of a memory location to record on entry.
;
; RETURN VALUE:
;
; None - the routine prints its own error messages
;
; NOTE:
;
; This routine will correctly cope with subroutines which begin
; with any skip or non-skip instruction (including JSYS's), but
; it cannot cope with jump class instructions (JUMPx, JRST, JSR)
;
PAGE
SUBTTL DATABASE
TRCLEN=10 ;Number of slots in trace table
STKMAX=4 ;Maximum number of stack items to hold
.TFCN=-4 ;Offset to function code
.TPTR=-3 ;Offset to byte pointer
.TNUM=-2 ;Number of stack items to record
.TLOC=-1 ;Name of location to record
A==1
B==2
C==3
D==4
E==5
F==6
G==7
P==17
TRCMOD: 0 ;Mode - 0 = off, 1 = on
TRCCNT: 0 ;Number of routines being traced
TRCTIM: 0 ;Time of TRACE ON
TRCTOT: 0 ;Total CPU time of tracing
USRACS: BLOCK 17 ;Saved user AC's
TRCINS: 0 ;Instruction to XCT
TRCADR: 0 ;Address to return to
TRCJFN: 0 ;JFN of trace file
;TRCTBL is the main data area for tracing routines. It has the following
;structure. The record written to the file consists of all but the last
;word of the data area.
;
; +------------------+------------------+
; | Routine name (sixbit) |
; +------------------+------------------+
; | Routine address |
; +------------------+------------------+
; | Entry counter |
; +------------------+------------------+
; | First instruction of routine |
; +------------------+------------------+
; | CPU time on entry |
; +------------------+------------------+
; | Total CPU time for routine |
; +------------------+------------------+
; | Address of caller + 1 |
; +------------------+------------------+
; | Number of stack items recorded |
; +------------------+------------------+
; | Stack item 1 |
; +------------------+------------------+
; | Stack item 2 |
; +------------------+------------------+
; | Stack item 3 |
; +------------------+------------------+
; | Stack item 4 |
; +------------------+------------------+
; | Value of AC1 on return |
; +------------------+------------------+
; | Name of location being recorded |
; +------------------+------------------+
; | Address of location being recorded |
; +------------------+------------------+
; | Value of location being recorded |
; +------------------+------------------+
; | TRCOF$ + 3 * n (for return) |
; +------------------+------------------+
PHASE 0
.TNAME:! BLOCK 1 ;Routine name
.TADRS:! BLOCK 1 ;Address
.TCNT:! BLOCK 1 ;Entry count
.TINST:! BLOCK 1 ;First instruction
.TTIME:! BLOCK 1 ;CPU time on entry
.TTOTL:! BLOCK 1 ;Total CPU time
.TRETN:! BLOCK 1 ;Return address
.TSCNT:! BLOCK 1 ;Number of stack items
.TSTK:! BLOCK STKMAX ;First stack item
.TAC1:! BLOCK 1 ;Value of AC1
.TNAM1:! BLOCK 1 ;Name of location to record
.TADR1:! BLOCK 1 ;Address of location
.TVAL1:! BLOCK 1 ;Value of location recorded
.TRPTR:! BLOCK 1 ;Return pointer
.TLEN:! ;Length of block
DEPHASE
DEFINE X(A)<
XLIST
BLOCK .TLEN-1
EXP ^D'A*3+TRCOF$
LIST
>
%%N=0
TRCTBL: REPEAT TRCLEN,<
X \%%N
%%N=%%N+1
>
PAGE
SUBTTL MAIN ENTRY AND EXIT POINTS
ENTRY $TRACE
RELOC 400000
$TRACE:
MOVEM 16,USRACS+16 ;Save the users AC's
MOVEI 16,USRACS
BLT 16,USRACS+15
MOVE A,.TPTR(P) ;Get the byte pointer
SKIPG B,.TFCN(P) ;Get the function code
JRST T.ERR1 ;Bad
CAILE B,6
JRST T.ERR1 ;Too large
JRST @[T.ON
T.OFF
T.RES
T.LIS
T.OPN
T.CLS]-1(B) ;Dispatch
T.RET:
HRLZI 16,USRACS ;Restore user AC's
BLT 16,15
MOVE 16,USRACS+16
RET
PAGE
SUBTTL ERROR ROUTINES
DEFINE ERRMSG(STR)<
HRROI A,[ASCIZ \STR\]
JRST TERROR
>
T.ERR1:
ERRMSG <Illegal function code>
T.ERR2:
ERRMSG <No symbol table found>
T.ERR3:
ERRMSG <Routine name not found in symbol table>
T.ERR4:
ERRMSG <Trace table full>
T.ERR5:
ERRMSG <Routine not being traced>
T.ERR6:
ERRMSG <Trace file already open>
T.ERR7:
ERRMSG <Cannot open trace file>
T.ERR8:
ERRMSG <Location name not found in symbol table>
TERROR:
PUSH P,A ;Save pointer for now
TMSG <
?TRACE - >
POP P,A
PSOUT ;Do message
TMSG <
>
JRST T.RET
PAGE
SUBTTL TRACE ON ROUTINE
T.ON: ;Switch on all or one routine
SKIPN A ;All?
JRST T.ALL ;Yes
SKIPN B,.JBSYM## ;Any symbol table?
JRST T.ERR2 ;no
CALL T.SIX ;Get routine to sixbit
CALL T.R50 ;Get routine to rad50
TON.1:
CAMN D,(B) ;Match?
JRST TON.2 ;Yes
AOBJN B,.+1 ;Step past value
AOBJN B,TON.1 ;Look for another
JRST T.ERR3 ;Not found
TON.2:
MOVE B,1(B) ;Get routine address
MOVE D,[-TRCLEN,,TRCTBL] ;Point to table
TON.3:
SKIPN .TNAME(D) ;Is it in use?
JRST TON.4 ;No - found a free slot
ADDI D,.TLEN-1
AOBJN D,TON.3 ;Look for another
JRST T.ERR4 ;No free slots
TON.4:
AOS TRCCNT ;Count the number of entries
MOVEM C,.TNAME(D) ;Save the name for LIST
MOVEM B,.TADRS(D) ;Save the address
MOVE A,.TNUM(P) ;Number of stack items to record
MOVEM A,.TSCNT(D)
SETZM .TNAM1(D) ;Assume no location
SETZM .TADR1(D) ;Make sure of it
SKIPN A,.TLOC(P) ;Get pointer to name
JRST T.RET
PUSH P,D ;Save pointer to entry
CALL T.SIX ;Convert name to SIXBIT
CALL T.R50 ;Convert to RAD50
MOVE B,.JBSYM##
POP P,A ;Restore entry pointer
TON.5:
CAMN D,(B) ;Look for a symbol match
JRST TON.6 ;OK
AOBJN B,.+1
AOBJN B,TON.5 ;Loop for more
JRST T.ERR8 ;Not found
TON.6:
MOVE B,1(B) ;Get address of location
MOVEM C,.TNAM1(A) ;Save the name
MOVEM B,.TADR1(A) ;And the address
JRST T.RET
PAGE
T.ALL: ;Trace all
SKIPE TRCMOD
JRST T.RET ;Avoid setting it twice
SETOM TRCMOD ;Enable tracing
MOVE D,[-TRCLEN,,TRCTBL] ;Clear out the entries for a new run
TALL.1:
SETZM .TTOTL(D)
SETZM .TCNT(D)
SKIPN .TNAME(D) ;Anyone there?
JRST TALL.2 ;No
MOVE C,.TADRS(D) ;Get the first instruction
MOVE B,(C)
MOVEM B,.TINST(D) ;And put it in the table
MOVEI A,-TRCTBL(D) ;Get offset into table
IDIVI A,.TLEN ;Get slot number
IMULI A,3
ADD A,[CALL TRCON$] ;Get pointer to ON routine
MOVEM A,(C) ;Save the new instruction
TALL.2:
ADDI D,.TLEN-1
AOBJN D,TALL.1 ;Loop for next one
CALL T.TIM ;Get current CPU time
MOVEM B,TRCTIM ;Save it
SETZM TRCTOT ;And clear the total
JRST T.RET
PAGE
SUBTTL TRACE OFF ROUTINE
T.OFF: ;Stop tracing on one or all
SKIPN A ;All?
JRST TOFF.3 ;Yes
CALL T.SIX ;Get name to sixbit
MOVE 4,[-TRCLEN,,TRCTBL] ;Point to table
TOFF.1:
CAMN C,.TNAME(D) ;Is this the one?
JRST TOFF.2 ;Yes
ADDI D,.TLEN-1
AOBJN D,TOFF.1
JRST T.ERR5 ;Not found
TOFF.2:
SOS TRCCNT ;Decrement the counter
SETZM .TNAME(D) ;Just mark the slot as free
SKIPE B,.TINST(D) ;Get the instruction
MOVEM B,@.TADRS(D) ;And restore it if non zero
JRST T.RET
TOFF.3: ;Stop all tracing
SKIPN TRCMOD ;Avoid second calculation
JRST T.RET
SETZM TRCMOD ;Switch tracer off
CALL T.TIM ;Get CPU time
SUB B,TRCTIM ;Get total
MOVEM B,TRCTOT ;Save for LIST
MOVE D,[-TRCLEN,,TRCTBL]
TOFF.4:
SKIPN .TNAME(D) ;Is this one in use?
JRST TOFF.5 ;No
MOVE B,.TINST(D) ;Yes - restore its instruction
SETZM .TINST(D) ;And flag it
MOVEM B,@.TADRS(D)
TOFF.5:
ADDI D,.TLEN-1
AOBJN D,TOFF.4 ;Loop over all entries
JRST T.RET
PAGE
SUBTTL TRACE RESET ROUTINE
T.RES:
SETZ A,
SKIPE TRCMOD ;If trace mode was on
CALL T.OFF ;Then turn it off
MOVE D,[-TRCLEN,,TRCTBL]
TRES.1:
SETZM .TNAME(D) ;Mark the slot as free
ADDI D,.TLEN-1
AOBJN D,TRES.1 ;Loop over all the table
JRST T.RET
PAGE
SUBTTL TRACE LIST ROUTINE
T.LIS:
TMSG <
TRACE status: >
HRROI A,[ASCIZ /ON
/]
SKIPN B,TRCMOD
HRROI A,[ASCIZ /OFF
/]
PSOUT ;Display current status
SKIPN TRCCNT ;Are any routines being traced?
JRST T.RET ;No - done now
JUMPN B,TLIS.1 ;Skip time if still running
TMSG <TRACE time: >
MOVEI A,.PRIOU
MOVE B,TRCTOT
MOVEI C,^D10
NOUT ;Display total trace time
JFCL
TMSG < mS CPU time
>
TLIS.1:
MOVE D,[-TRCLEN,,TRCTBL]
TMSG <
Routine Entries CPU time (mS) Average % Total
------- ------- ------------- ------- -------
>
TLIS.2:
SKIPN .TNAME(D) ;Anything here?
JRST TLIS.5 ;no
MOVE B,[POINT 6,.TNAME(D)] ;Point to name
MOVEI C,6
TLIS.3:
ILDB A,B
ADDI A,40
PBOUT ;Output each character
SOJG C,TLIS.3
TMSG < >
MOVEI A,.PRIOU
MOVE B,.TCNT(D) ;Get number of entries
MOVX C,6B17+^D10
NOUT
JFCL
TMSG < >
MOVEI A,.PRIOU
MOVE B,.TTOTL(D) ;Get total CPU time
MOVX C,10B17+^D10
NOUT
JFCL
TMSG < >
MOVEI A,.PRIOU
MOVE B,.TTOTL(D) ;Get average CPU time
MOVE E,.TCNT(D)
JUMPE E,TLIS.4 ;Ignore it if never entered
IDIVI B,(E)
PUSH P,C ;Save remainder
MOVX C,NO%LFL+5B17+^D10
NOUT
JFCL
MOVEI A,"."
PBOUT ;Insert a dot
POP P,A
IMULI A,^D10 ;Make the first fraction digit
IDIVI A,(E)
ADDI A,"0"
PBOUT ;And output it
TMSG < >
SKIPN TRCTOT
JRST TLIS.4 ;Don't divide by zero
MOVEI A,.PRIOU
MOVE B,.TTOTL(D) ;Get %total
IMULI B,^D100
IDIV B,TRCTOT
PUSH P,C ;Save the remainder
MOVX C,NO%LFL+2B17+^D10
NOUT
JFCL
MOVEI A,"."
PBOUT ;Insert point
POP P,A
IMULI A,^D10 ;Make first fraction digit
IDIV A,TRCTOT
ADDI A,"0"
PBOUT ;And output it
TLIS.4:
TMSG <
>
TLIS.5:
ADDI D,.TLEN-1
AOBJN D,TLIS.2 ;Loop for the next
JRST T.RET
PAGE
SUBTTL OPEN AND CLOSE TRACE FILE
T.OPN:
SKIPE TRCJFN ;If already open
JRST T.ERR6 ; Then error
MOVX A,GJ%FOU+GJ%SHT
MOVE B,[POINT 7,[ASCIZ /TRACE.DAT/]]
GTJFN
ERJMP T.ERR7
HRRZM A,TRCJFN ;Save the JFN
MOVEI B,OF%WR ;36-bit write
OPENF
ERJMP T.ERR7
GTAD ;Get the current date and time
MOVE B,A
MOVE A,TRCJFN
BOUT ;And put it in the file
GETNM ;Get the program name
MOVE B,A
MOVE A,TRCJFN
BOUT ;And put it in the file
MOVE B,[STKMAX,,.TLEN-1] ;Get some flags
MOVE A,TRCJFN
BOUT ;And put it in the file
MOVNI A,5
RUNTM ;Get my runtime
MOVE B,A
MOVE A,TRCJFN
BOUT ;Base runtime
JRST T.RET
T.CLS:
SKIPE A,TRCJFN
CLOSF ;Close it if it was open
JFCL
SETZM TRCJFN ;Assume its closed now
JRST T.RET
PAGE
SUBTTL TRACE ENTRY AND EXIT ROUTINES
DEFINE X(N)<
XLIST
PUSH P,A
MOVEI A,^D'N*.TLEN+TRCTBL
JRST T.TRC
LIST>
%%N=0
TRCON$:
REPEAT TRCLEN,<
X \%%N
%%N=%%N+1>
T.TRC:
SKIPN TRCMOD ;Tracing?
JRST TTRC.1 ;No
AOS .TCNT(A) ;Count the number of entries
SKIPE .TTIME(A) ;Recursive?
JRST TTRC.1 ;Yes - ignore it - we're there already
PUSH P,B
MOVE B,.TRPTR(A) ;Point to dummy return routine
EXCH B,-3(P) ;Get callers address
MOVEM B,.TRETN(A) ;Save it
CALL T.TIM ;Get current CPU time
MOVEM B,.TTIME(A) ;And save it
POP P,B
TTRC.1:
SKIPN TRCJFN ;Recording?
JRST TTRC.3 ; No
PUSH P,A
PUSH P,B
MOVN B,.TSCNT(A) ;Get number of stack items
JUMPE B,TTRC.2
HRLS B ;Make an AOBJN pointer
HRR B,A
MOVEI A,-5(P)
HRLI A,-STKMAX ;Make a stack pointer
POP A,.TSTK(B) ;Copy a stack item
AOBJN B,.-1 ;Loop for next
TTRC.2:
MOVE A,-1(P) ;Point to entry table
MOVE B,@.TADR1(A) ;Get the value
SKIPE .TNAM1(A) ;If there is a location name
MOVEM B,.TVAL1(A) ; Then save the value
POP P,B
POP P,A
TTRC.3:
MOVE A,.TINST(A) ;Get the first instruction
MOVEM A,TRCINS
POP P,A
EXCH A,(P) ;Now move the return address off the stack
MOVEM A,TRCADR
POP P,A ;And get A back properly
XCT TRCINS
JRST @TRCADR ;Return without using the stack
CAIA ;Skip once
AOS TRCADR ;Skip twice
AOS TRCADR
JRST @TRCADR ;Return
PAGE
DEFINE X(N)<
XLIST
PUSH P,A
MOVEI A,^D'N*.TLEN+TRCTBL
JRST T.TRCF
LIST>
%%N=0
TRCOF$:
REPEAT TRCLEN,<
X \%%N
%%N=%%N+1>
T.TRCF:
PUSH P,B
CALL T.TIM ;Get current CPU time
SUB B,.TTIME(A) ;Get difference
ADDM B,.TTOTL(A) ;Save it
SKIPN TRCJFN ;If not recording
JRST TRCF.1 ; Then skip the write
PUSH P,A
PUSH P,B
MOVE B,-3(P) ;Get value in AC1
MOVEM B,.TAC1(A)
MOVEI B,(A) ;Point to entry table
HRLI B,(POINT 36,0) ;Make a byte pointer
MOVE A,TRCJFN
MOVNI C,.TLEN-1 ;Length of record
SOUT ;Write the record
POP P,C
POP P,A
TRCF.1:
SETZM .TTIME(A) ;Flag that we have finished
POP P,B
MOVE A,.TRETN(A) ;Get old stack entry
EXCH A,(P)
RET ;Return to callers caller
PAGE
SUBTTL SUPPORT ROUTINES
T.SIX: ;Get sixbit name in AC-C
MOVEI E,6
MOVE F,[POINT 6,C]
SETZ C,
PUSH P,A ;Save the pointer
TSIX.1:
ILDB G,A ;Get a byte
JUMPE G,TSIX.2 ;End on null
ANDI G,177 ;Make sure its 7-bit
CAIL G,140 ;Convert lowercase to uppercase
SUBI G,40
SUBI G,40 ;And make it 6-bit
IDPB G,F
SOJG E,TSIX.1
TSIX.2:
POP P,A
RET
T.TIM: ;Get current CPU time to AC-B
PUSH P,A
PUSH P,C ;Save these AC's
MOVNI A,5
RUNTM ;Get my runtime
MOVE B,A
POP P,C
POP P,A
RET
T.R50: ;Get name in RADIX50 to AC-D
MOVEI E,6
SETZ D,
PUSH P,A
TR50.1:
ILDB G,A ;Get a character
JUMPE G,TR50.2
ANDI G,177 ;Make if 7-bit
CAIL G,140 ;Convert lowercase to uppercase
SUBI G,40
SUBI G,40 ;And now 6-bit
ADJBP G,[POINT 6,R50TBL] ;Point into the conversion table
ILDB G,G
IMULI D,50 ;Multiply
ADD D,G ;And add in next character
SOJG E,TR50.1
TR50.2: ;Here on trailing nulls
MOVEI A,1
DPB A,[POINT 4,D,3] ;Look for code 4 (global)
POP P,A
RET
R50TBL:
BYTE (6)00,00,00,00,46,47
BYTE (6)00,00,00,00,00,00
BYTE (6)00,00,45,00,01,02
BYTE (6)03,04,05,06,07,10
BYTE (6)11,12,00,00,00,00
BYTE (6)00,00,00,13,14,15
BYTE (6)16,17,20,21,22,23
BYTE (6)24,25,26,27,30,31
BYTE (6)32,33,34,35,36,37
BYTE (6)40,41,42,43,44,00
BYTE (6)00,00,00,00,00,00
END