From:	CRDGW2::CRDGW2::MRGATE::"SMTP::CRVAX.SRI.COM::RELAY-INFO-VAX"  2-NOV-1989 20:02
To:	MRGATE::"ARISIA::EVERHART"
Subj:	Spinlock monitoring program, part 2 of 3

Received: From UCBVAX.BERKELEY.EDU by GIZMO.SRI.COM with TCP; Wed,  1 NOV 89 18:03:55 PDT
Received: by ucbvax.Berkeley.EDU (5.61/1.39)
	id AA23496; Wed, 1 Nov 89 17:47:57 -0800
Received: from USENET by ucbvax.Berkeley.EDU with netnews
	for info-vax@kl.sri.com (info-vax@kl.sri.com)
	(contact usenet@ucbvax.Berkeley.EDU if you have questions)
Date: 1 Nov 89 17:04:11 GMT
From: amdahl!rtech!jim@ames.arc.nasa.gov  (Jim Gessling)
Organization: Relational Technology Inc. Alameda, CA 94501
Subject: Spinlock monitoring program, part 2 of 3
Message-Id: <3955@rtech.rtech.com>
Sender: info-vax-request@kl.sri.com
To: info-vax@kl.sri.com


+-+-+-+ Beginning of part 2 +-+-+-+
XBLANK:`009`009.ASCID`009<ESC>/[!SL;1H/<ESC>/[K/
X; descriptor for general use, particularly FAO output
XFAOO:`009`009.WORD`009100
X`009`009.WORD`009`094x010E`009
X`009`009.ADDRESS STRBUF
XSTRBUF:`009`009.BLKB`009100
XSCALE:`009`009.ASCID`009<ESC>/[7;38H0/<ESC>/[7;44H!6UL/<ESC>/[7;54H!6UL/-
X                        <ESC>/[7;64H!6UL/<ESC>/[7;74H!6UL/
XEND:`009`009.ASCID`009<ESC>/[24;0H/
XBAR:`009`009.ASCID`009<ESC>/[!SL;39H!#*H/
XLABEL:`009`009.ASCID`009<ESC>/[!SL;1H/<ESC>/[K  !2UB  !AC   !12AD       !6UL/
X;
X; routine to assign to terminal channel
XINITIO::
X`009$ASSIGN_S DEVNAM=TT_DESC, CHAN=TT_CHAN
X`009BLBS`009R0, 10$
X`009PUSHL`009R0
X`009CALLS`009#1, G`094LIB$SIGNAL
X10$:`009RSB
X;
X;
X; routine to count number of spinlocks so data structures can be set-up
X; for dynmaic locks can simply count DDB's, returns count in R1
X`009.ENTRY`009COUNT_LOCKS, `094M<R5>
V`009SUBL3`009#SPL$_MIN_INDEX, #SPL$_MAX_INDEX, R1`009; static locks are easy`
X009
X`009MOVL`009#IOC$GL_DEVLIST, R5`009`009`009;`032
X10$:`009MOVL`009(R5), R5                                ; address of ddb
X`009BEQL`00920$`009`009`009`009`009; zero indicates done
X`009INCL`009R1`009`009`009`009`009; count one
X`009BRB`00910$`009
X20$:`009
X`009MOVL`009#1, R0
X`009RET`009
X;
X; routine to allocate lock block data structure
X`009.ENTRY`009GET_MEM, `094M<> `032
X`009MULL3`009NUM_LOCKS, #LBLOCK_SIZE, -(SP)`009; calculate bytes
X`009PUSHAL`009FIRST_BLOCK
X`009SUBL3`009#4, FP, -(SP)
X`009CALLS`009#2, G`094LIB$GET_VM`009`009; make memory
X`009BLBS`009R0, 10$
X`009PUSHL`009R0
X`009CALLS`009#1, G`094LIB$SIGNAL`009`009; blow off on error
X10$:`009RET
X
X;
X; routine to get command line parameters
X`009.ENTRY`009GET_PARAM, `094M<R2,R3,R4>
X`009PUSHAW`009RETURN_DESC
X`009PUSHAB`009RETURN_DESC
X`009PUSHAB`009QUALIFIER
X`009CALLS`009#3, G`094CLI$GET_VALUE`009; get interval as a string
X`009BLBS`009R0, 10$
X`009PUSHL`009#SPINLOCK_NOCLI
X`009CALLS`009#1, G`094LIB$SIGNAL
X
X10$:`009SUBL2`009#4, SP`009`009`009; move SP down one
X`009SUBL3`009#4, FP, -(SP)`009`009; convert string to floating point
X`009PUSHAB`009RETURN_DESC+8`009`009; use address of actual string
X`009MOVZWL`009RETURN_DESC, -(SP)
X`009CALLS`009#3, G`094LIB$CVT_DTB`009
X`009CVTLF`009-4(FP), WAIT_TIME
X; get range value
X`009MOVW`009#12, RETURN_DESC
X`009PUSHAW`009RETURN_DESC
X`009PUSHAB`009RETURN_DESC
X`009PUSHAB`009QUALIFIER2
X`009CALLS`009#3, G`094CLI$GET_VALUE`009; get interval as a string
X`009BLBS`009R0, 15$
X`009PUSHL`009#SPINLOCK_NOCLI
X`009CALLS`009#1, G`094LIB$SIGNAL
X
X15$:`009PUSHAL`009RANGE
X`009PUSHAB`009RETURN_DESC+8
X`009MOVZWL`009RETURN_DESC, -(SP)
X`009CALLS`009#3, G`094LIB$CVT_DTB
X
X`009MOVW`009#1, RETURN_DESC`009`009; only want first character of param
X`009PUSHAW`009RETURN_DESC
X`009PUSHAB`009RETURN_DESC
X`009PUSHAB`009PARAMETER
X`009CALLS`009#3, G`094CLI$GET_VALUE`009; get parameter as a string
X`009BLBS`009R0, 20$
X`009PUSHL`009#SPINLOCK_NOCLI
X`009CALLS`009#1, G`094LIB$SIGNAL
X; convert string into coded display_type
X20$:`009PUSHL`009#`094A/A   /
X`009PUSHL`009#`094A/SPWB/
X`009LOCC`009@RETURN_DESC+4, #5, (SP)
X`009SUBB3`009SP, R1, DISPLAY_TYPE
X
X`009CMPB`009DISPLAY_TYPE, #1`009; always use scale of 100 for O
X`009BNEQ`00930$`009
X`009MOVL`009#100, RANGE
X
X30$:`009MOVL`009#1, R0`009
X`009RET
X
X`009.ENTRY`009GET_DATA, `094M<R2,R3,R4,R5,R6,R7,R8,R9,R10>
X`009CLRL`009R6`009`009`009; lock counter
X; loop through static locks
X`009MOVL`009SMP$AR_SPNLKVEC, R7`009; base of spinlock vector
X`009MOVL`009#SPL$_MIN_INDEX, R8`009; lock index
X`009MOVL`009FIRST_BLOCK, R9         ; my block address
X`009MOVAB`009SPNAMES, R10
X; fill in data
X10$:
X`009MOVL`009(R7)[R8], SPL$L_ADDRESS(R9)`009; get address of lock block
X`009MOVC3`009#SPL$K_LENGTH, @SPL$L_ADDRESS(R9), (R9); grab VMS lock block
X`009MOVC3`009#10, (R10), SPL$L_LOCK_NAME(R9) ; get lock name
X`009ADDL2`009#10, R10`009`009`009; get next name
X
X`009CASEB`009SPL$B_SUBTYPE(R9),#1,#2`009`009; set ascii for type
X90$:`009.WORD`009100$-90$
X`009.WORD`009110$-90$
X`009.WORD`009120$-90$
X`009BRB`009130$
X100$:`009MOVB`009#`094A/S/, SPL$B_ASCII_TYPE+1(R9)`009; static lock
X`009BRB`009130$
X110$:`009MOVB`009#`094A/F/, SPL$B_ASCII_TYPE+1(R9)`009; fork lock
X`009BRB`009130$
X120$:`009MOVB`009#`094A/D/, SPL$B_ASCII_TYPE+1(R9)`009; device lock
X
X130$:`009MOVB`009#1, SPL$B_ASCII_TYPE(R9)
X`009INCL`009R8`009`009`009`009; get next lock
X`009ADDL2`009#LBLOCK_SIZE, R9`009`009; address next my block`009
X`009AOBLEQ`009#SPL$_MAX_INDEX-SPL$_MIN_INDEX-1, R6, 10$`032
X
X; dynamic locks
X`009MOVL`009IOC$GL_DEVLIST, R7`009`009`009; first ddb
X20$:`009
X`009MOVL`0094(R7), R8`009`009`009`009; address of ucb
X`009MOVL`009UCB$L_DLCK(R8), R10`009`009`009; lock address
X; strangely enough not every UCB has an entry for a device lock, so
X; skip if empty.   Readjust num_locks at end of routine to take this
X; into account.  Also IPL8 devices all use the same spinlock so don't
X; grab multiple copies.  Also NL and MB use the static mailbox lock
X; so don't grab NLA or MBA locks
X`009BEQL`00922$
X`009CMPB`009#8, SPL$B_IPL(R10)
X`009BEQL`00922$
X`009CMPW`009#`094A/NL/, DDB$T_NAME_STR(R7)
X`009BEQL`00922$
X`009CMPW`009#`094A/MB/, DDB$T_NAME_STR(R7)
X`009BEQL`00922$
X; fill in data
X`009MOVC3`009#SPL$K_LENGTH, (R10), (R9)
X`009MOVL`009R10, SPL$L_ADDRESS(R9)`009
X`009MOVZBL`009DDB$B_NAME_LEN(R7), R11`032
X`009MOVC5   R11, DDB$T_NAME_STR(R7), #32, #10, SPL$L_LOCK_NAME(R9)
X`009CASEB`009SPL$B_SUBTYPE(R9),#1,#2`009`009; set ascii for type
X190$:`009.WORD`009200$-190$
X`009.WORD`009210$-190$
X`009.WORD`009220$-190$
X`009BRB`009230$
X200$:`009MOVB`009#`094A/S/, SPL$B_ASCII_TYPE+1(R9)`009; static lock
X`009BRB`009230$
X210$:`009MOVB`009#`094A/F/, SPL$B_ASCII_TYPE+1(R9)`009; fork lock
X`009BRB`009230$
X220$:`009MOVB`009#`094A/D/, SPL$B_ASCII_TYPE+1(R9)`009; device lock
X
X230$:`009MOVB`009#1, SPL$B_ASCII_TYPE(R9)
X; set up to do it again
X`009INCL `009R6
X`009ADDL2`009#LBLOCK_SIZE, R9
X22$:`009MOVL`009(R7), R7 `032
X`009BNEQ`00920$
X; done
X`009MOVL`009R6, NUM_LOCKS`009`009`009
X`009MOVL`009#1, R0
X`009RET
X;
X; routine to paint initial screen for displays
X`009.ENTRY`009DISPLAY_SCREEN, `094M<R2,R3,R4,R5>
X`009SUBL`009#35, SP`009`009`009; make room for syi stuff
X`009MOVL`009#0, -4(FP)
X`009SUBL3`009#20,FP,-8(FP)
X`009MOVL`009SP, -12(FP)
X`009MOVW`009#SYI$_NODENAME, -14(FP)
X`009MOVW`009#15, -16(FP)
X`009CLRQ`009-(SP)
X`009PUSHL`009#0
X`009SUBL3`009#16, FP, -(SP)
X`009CLRQ`009-(SP)
X`009PUSHL`009#0
X`009CALLS`009#7, G`094SYS$GETSYI`009; all this ends up with node name
X`009BLBS`009R0, 10$`009`009`009; in ascii starting at @-12(FP) and
X`009PUSHL`009R0
X`009CALLS`009#0, G`094LIB$SIGNAL`009; counted by the word that is at
X`009`009`009`009`009; @-8(FP). Neat huh?`009
X10$:
X`009MOVZWL`009TITLE, QIO_PARAM+32`009; size of buffer
X`009MOVL`009TITLE+4, QIO_PARAM+28`009; buffer address
X`009CALLG`009QIO_PARAM, G`094SYS$QIO    ; generic title
X
X`009MOVAL`009T0, R3                  ;
X`009MOVZBL`009DISPLAY_TYPE, R4
X`009MOVL`009(R3)[R4], R5
X`009MOVZWL`009(R5), QIO_PARAM+32
X`009MOVL`0094(R5), QIO_PARAM+28
X`009CALLG`009QIO_PARAM, G`094SYS$QIO    ; specific title
X
X`009MOVZWL`009ONNODE, QIO_PARAM+32`009; size of buffer
X`009MOVL`009ONNODE+4, QIO_PARAM+28`009; buffer address
X`009CALLG`009QIO_PARAM, G`094SYS$QIO    ; generic title
X
X`009MOVZWL`009@-8(FP), QIO_PARAM+32`009; size of buffer
X`009MOVL`009-12(FP), QIO_PARAM+28`009; buffer address
X`009CALLG`009QIO_PARAM, G`094SYS$QIO    ; node name
X
X`009ADDL2`009#7, TIME+4`009`009; fake the descriptor
X`009MOVZWL`009TIME, R2`009`009; save the length
X`009MOVW`009#23, TIME
X        $ASCTIM_S TIMBUF = TIME
X`009SUBL2`009#7, TIME+4 `009`009; set it back
X`009MOVW`009R2, TIME`009
X
X`009MOVZWL`009TIME, QIO_PARAM+32`009; size of buffer
X`009MOVL`009TIME+4, QIO_PARAM+28`009; buffer address
X`009CALLG`009QIO_PARAM, G`094SYS$QIO
X`032
X`009MOVZWL`009TLINE, QIO_PARAM+32`009; size of buffer
X`009MOVL`009TLINE+4, QIO_PARAM+28`009; buffer address
X`009CALLG`009QIO_PARAM, G`094SYS$QIO
X
X
X`009MOVZWL`009BLINE, QIO_PARAM+32`009; size of buffer
X`009MOVL`009BLINE+4, QIO_PARAM+28`009; buffer address
X`009CALLG`009QIO_PARAM, G`094SYS$QIO
X
X`009MOVL`009#10, R2`009`009`009; loop to draw grid
X20$:`009PUSHL`009R2`009`009`009; set up for FAO
X`009PUSHAB`009FAOO
X`009PUSHAW`009FAOO
X`009PUSHAB`009DASH
X`009CALLS`009#4, G`094SYS$FAO`009`009; fao it
X`009MOVZWL`009FAOO, QIO_PARAM+32
X`009MOVL`009FAOO+4, QIO_PARAM+28
X`009CALLG`009QIO_PARAM, G`094SYS$QIO`009; output it
X`009MOVW`009#100, FAOO
X`009ADDL`009#2, R2
X`009CMPL`009#24, R2
X`009BNEQ`00920$  `009`009`009; back for more
X; dynamic scaling
X`009CVTLF`009RANGE, R4               ; for easier multiplication
X`009PUSHL`009RANGE
X`009MULF3`009#`094F0.75, R4, R5
X`009CVTFL`009R5, -(SP)
X`009MULF3`009#`094F0.50, R4, R5
X`009CVTFL`009R5, -(SP)
X`009MULF3`009#`094F0.25, R4, R5
X`009CVTFL`009R5, -(SP)
X`009PUSHAB`009FAOO
X`009PUSHAW`009FAOO
X`009PUSHAB`009SCALE
X`009CALLS`009#4, G`094SYS$FAO`009`009; fao it
X`009MOVZWL`009FAOO, QIO_PARAM+32
X`009MOVL`009FAOO+4, QIO_PARAM+28
X`009CALLG`009QIO_PARAM, G`094SYS$QIO`009; output it
X`009MOVW`009#100, FAOO
X
X       `009MOVL`009#1, R0
X`009RET
X;`032
X; routine to update differences in counts.  Do all no matter which
X; display we are running to  make this more general (but slower)
X`009.ENTRY`009UPDATE_DATA, `094M<R6,R7,R8,R9>
X`009CLRL`009R6`009`009`009; lock counter
X        MOVL`009FIRST_BLOCK, R7`009`009; lock block address
X
X10$:`009MOVL`009SPL$L_ADDRESS(R7), R8`009; system lock address
X`009`009`009`009`009; start grabbing stuff
X        MOVC3`009#32, SPL$L_OWN_PC_VEC(R8), SPL$L_OWN_PC_VEC(R7) ; pc's
X; spins
X`009MOVQ`009SPL$Q_SPINS(R8), R9`009; more accurate to save this
X`009SUBL3`009SPL$Q_SPINS(R7), R9, SPL$L_SPIN_DIFF(R7) ;spins
X`009MOVQ`009R9, SPL$Q_SPINS(R7) `032
X; acquisitions`009
X`009MOVQ`009SPL$Q_ACQ_COUNT(R8), R9
X`009SUBL3`009SPL$Q_ACQ_COUNT(R7), R9, SPL$L_ACQ_DIFF(R7)`032
X`009MOVQ`009R9, SPL$Q_ACQ_COUNT(R7) `032
X; busy waits
X`009MOVL`009SPL$L_BUSY_WAITS(R8), R9
X`009SUBL3`009SPL$L_BUSY_WAITS(R7), R9, SPL$L_BUSY_DIFF(R7)`032
X`009MOVL`009R9, SPL$L_BUSY_WAITS(R7)
X; again?
X`009ADDL2`009#LBLOCK_SIZE, R7
X`009AOBLSS`009NUM_LOCKS, R6, 10$ `032
X
X`009MOVL`009#1, R0
X`009RET
X;
X; routine to sort lock blocks, sets the sort field based on the type
X; of display chosen. `032
X`009.ENTRY`009SORT_DATA, `094M<R2,R3,R4,R5,R6>
X;
X; set key buffer depending on display option chosen
X`009CASEB`009DISPLAY_TYPE, #0, #4
XTABL:`009.WORD`00920$-TABL
X`009.WORD`00930$-TABL
X`009.WORD`00940$-TABL
X`009.WORD`00950$-TABL
X`009.WORD`00955$-TABL
X20$:`009MOVW`009#SPL$L_SPIN_DIFF, KEY_BUFFER+6`009; sort on spin diff
X`009BRB`00960$
X30$:`009MOVW`009#SPL$L_BUSY_PER_ACQ, KEY_BUFFER+6  ; sort on acq/busy
X`009BRB`00960$`009`009`009                           `009
X40$:`009MOVW`009#SPL$L_SPIN_PER_ACQ, KEY_BUFFER+6  ; sort on spin/acq
X`009BRB`00960$`009
X50$:`009MOVW`009#SPL$L_SPIN_PER_BUSY, KEY_BUFFER+6 ; sort on spin/busy`009
X`009BRB`00960$
X55$:`009MOVW`009#SPL$L_ACQ_DIFF, KEY_BUFFER+6 ; sort on spin/busy`009
X60$:
X`009MOVL`009NUM_LOCKS, R2`009`009`009; count blocks (DOWN)
X`009PUSHAL`009SORT_MASK
X`009PUSHAW`009LRL
X`009PUSHAW`009KEY_BUFFER
X`009CALLS`009#3, G`094SOR$BEGIN_SORT`009`009; set up sort
X`009BLBS`009R0, 70$
X`009PUSHL`009R0
X`009CALLS`009#1, G`094LIB$SIGNAL`009`009; blow off on error
X
X70$:`009MOVL`009FIRST_BLOCK, R3
X80$:`009MOVL`009R3, BLOCK_DESC+4   `009`009; first block
X;  do division for ratio displays
X`009CVTLF`009SPL$L_SPIN_DIFF(R3), R4
X`009DIVF2`009WAIT_TIME, R4
X`009CVTFL`009R4, SPL$L_SPIN_DIFF(R3)
X
X`009CVTLF`009SPL$L_ACQ_DIFF(R3), R4
X`009DIVF2`009WAIT_TIME, R4
X`009CVTFL`009R4, SPL$L_ACQ_DIFF(R3)
X
X`009CVTLF`009SPL$L_BUSY_DIFF(R3), R4
X`009DIVF2`009WAIT_TIME, R4
X`009CVTFL`009R4, SPL$L_BUSY_DIFF(R3)
X
X`009TSTL`009SPL$L_ACQ_DIFF(R3)
X`009BNEQ`00981$
X`009CLRL`009SPL$L_BUSY_PER_ACQ(R3)
X`009BRB`00982$
X81$:`009CVTLF`009SPL$L_ACQ_DIFF(R3), R4
X`009CVTLF`009SPL$L_BUSY_DIFF(R3), R5
X`009DIVF3`009R4, R5, R6
X`009MULF2`009#`094F100.0, R6`009
X`009CVTFL`009R6, SPL$L_BUSY_PER_ACQ(R3)
X
X82$:`009TSTL`009SPL$L_ACQ_DIFF(R3)
X`009BNEQ`00983$
X`009CLRL`009SPL$L_SPIN_PER_ACQ(R3)
X`009BRB`00984$
X83$:`009DIVL3   SPL$L_ACQ_DIFF(R3),SPL$L_SPIN_DIFF(R3),SPL$L_SPIN_PER_ACQ(R3)
X
X84$:`009TSTL`009SPL$L_BUSY_DIFF(R3)
X`009BNEQ`00985$
X`009CLRL`009SPL$L_SPIN_PER_BUSY(R3)
X`009BRB`00986$
V85$:`009DIVL3   SPL$L_BUSY_DIFF(R3),SPL$L_SPIN_DIFF(R3),SPL$L_SPIN_PER_BUSY(R
X3)
X
X; loop through all blocks, passing them to sort
X86$:`009PUSHAB`009BLOCK_DESC
X`009CALLS`009#1, G`094SOR$RELEASE_REC`009`009; pass the records
X`009BLBS`009R0, 90$
X`009PUSHL`009R0
X`009CALLS`009#1, G`094LIB$SIGNAL`009`009; blow off on error
X90$:`009ADDL2`009#LBLOCK_SIZE, R3
X`009DECL`009R2
X`009BLEQ `00991$
X`009BRW`00980$`009
X
X91$:`009CALLS`009#0, G`094SOR$SORT_MERGE`009`009; do the sort
X`009BLBS`009R0, 100$
X`009PUSHL`009R0
X`009CALLS`009#1, G`094LIB$SIGNAL`009`009; blow off on error
X100$:
X`009MOVL`009#1, R2`009  `009`009`009; lock counter
X`009MOVL`009FIRST_BLOCK, BLOCK_DESC+4`009; first block
X; loop through all blocks, getting them back from sort
X110$:`009PUSHAB`009BLOCK_DESC
X`009CALLS`009#1, G`094SOR$RETURN_REC`009`009; get the records back
X`009CMPL`009R0, #SS$_ENDOFFILE
X`009BEQL`009130$
X`009BLBS`009R0, 120$
X`009PUSHL`009R0
X`009CALLS`009#1, G`094LIB$SIGNAL`009`009; blow off on error
X120$:`009ADDL2`009#LBLOCK_SIZE, BLOCK_DESC+4
X`009INCL`009R2
X`009BRB`009110$
X
X130$:`009CALLS`009#0, G`094SOR$END_SORT
X; done`009`009
X`009MOVL`009#1, R0
X`009RET
X;
X; routine to update bars on display screen
X`009.ENTRY`009UPDATE_SCREEN, `094M<R2,R3,R4,R5,R6>
X`009MOVL`009#9, R2`009`009`009; first line for bar chart
X`009MOVL`009FIRST_BLOCK, R3`009`009; address of first block
X; put time on screen
X`009ADDL2`009#7, TIME+4`009`009; fake the descriptor
X`009MOVZWL`009TIME, R4`009`009; save the length
X`009MOVW`009#23, TIME
X        $ASCTIM_S TIMBUF = TIME
X`009SUBL2`009#7, TIME+4 `009`009; set it back
X`009MOVW`009R4, TIME`009
X
X`009MOVZWL`009TIME, QIO_PARAM+32`009; size of buffer
X`009MOVL`009TIME+4, QIO_PARAM+28`009; buffer address
X`009CALLG`009QIO_PARAM, G`094SYS$QIO
X;
X; put up first 8 locks (or until hit one with zero spins)
X10$:`009CASEB`009DISPLAY_TYPE, #0, #4
X11$:`009.WORD`00912$-11$
X`009.WORD`00913$-11$
X`009.WORD   14$-11$
X`009.WORD`00915$-11$
X`009.WORD`009100$-11$
X12$:`009ADDL3`009#SPL$L_SPIN_DIFF, R3, R5
X`009BRB`00916$
X13$:`009ADDL3`009#SPL$L_BUSY_PER_ACQ, R3, R5
X`009BRB`00916$
X14$:`009ADDL3`009#SPL$L_SPIN_PER_ACQ, R3, R5
X`009BRB`00916$
X15$:`009ADDL3`009#SPL$L_SPIN_PER_BUSY, R3, R5
X`009BRB`00916$
X100$:`009ADDL3`009#SPL$L_ACQ_DIFF, R3, R5
X
X16$:`009TSTL`009(R5)
X`009BNEQ`00917$
X`009BRW`00920$
X; put out text info
X17$:`009PUSHL`009(R5)
X`009ADDL3`009#SPL$L_LOCK_NAME, R3, -(SP)
X`009PUSHL`009#10
X`009ADDL3`009#SPL$B_ASCII_TYPE, R3, -(SP)
X`009MOVZBL  SPL$B_RANK(R3), -(SP)
X`009PUSHL`009R2`032
X`009PUSHAB`009FAOO
X`009PUSHAW`009FAOO
X`009PUSHAB`009LABEL
X`009CALLS`009#9, G`094SYS$FAO`009`009; fao it
X`009MOVZWL`009FAOO, QIO_PARAM+32
X`009MOVL`009FAOO+4, QIO_PARAM+28
-+-+-+-+-+ End of part 2 +-+-+-+-+-

