.TITLE POOLMN POOL Monitor .IDENT /TLH858/ ; We want information .ENABL LC .NLIST BEX ; Don't list binary extensions .NLIST CND ; Don't list unsatisfied conditionals ; PPPPPPPPP OOOOOOOO OOOOOOOO LL MMM MMM NN NN ; PPPPPPPPP OOOOOOOO OOOOOOOO LL MMM MMM NN NN ; PP PP OO OO OO OO LL MMMM MMMM NNNN NN ; PP PP OO OO OO OO LL MMMM MMMM NNNN NN ; PPPPPPPPP OO OO OO OO LL MM MM MM NN NN NN ; PPPPPPPPP OO OO OO OO LL MM MM MM NN NN NN ; PP OO OO OO OO LL MM MM NN NNNN ; PP OO OO OO OO LL MM MM NN NNNN ; PP OO OO OO OO LL MM MM NN NNN ; PP OO OO OO OO LL MM MM NN NNN ; PP OOOOOOOO OOOOOOOO LLLLLLLLLL MM MM NN NN ; PP OOOOOOOO OOOOOOOO LLLLLLLLLL MM MM NN NN .SBTTL Introduction ; POOLMN - Pool Monitor Logging Task ; Authors: ; Bruce R. Mitchell ; ; From the POOL monitor task written by Dale Donchin at DEC back in '78 ; and released on the RSX SIG tapes in the "KMSKIT" in 1980. ; Source Site ; Electrocardiology Computer Systems ; Plummer Building, Mayo Clinic, Rochester, Minnesota 55902 ; Source Hardware and Operating System: ; DEC PDP-11/70 under RSX-11M-Plus V2.1 Update E ; Target Site: ; Same ; Target Hardware and Operating System: ; Same ; Revision History: ; 06-Mar-86 First version ripped out of old KMS Fusion source ; 10-Mar-86 Add support for dual format output files ; 11-Mar-86 Increase logging/averaging interval to 5 minutes ; 11-Jun-86 Add support for startup stabilization time ; 01-Oct-86 Fix problem in logging if started 5 minutes before the hour .PAGE .SBTTL Description and Philosophy 101 ; System manager: "We want - information." ; RSX-11 system: "You won't get it from me!" ; System programmer: "By hook or by crook, we will." ; ; This task is a poor man's SPM-11. It checks the amount of free POOL, ; the size of the second largest and largest POOL fragments, the number ; of POOL fragments, and the number of active tasks 4 times per minute. ; These values are averaged and written to a logging file at the end ; of each monitoring interval. ; ; Operation proceeds as follows: ; ; (1) Assign a LUN to the CO: device. Exit on error. ; (2) Check to see if running task name is POOLMN. Exit on error. ; (3) Check to see that running priority is 100 or more. Exit if not. ; (4) Ensure that the logging interval divides 60 evenly. Exit if not. ; (5) Open the logging file LB:[1,4]POOLMN.LOG. Exit on error. ; (6) Store FNB for later OFID$ use. Close file. Exit on error. ; (7) Specify abort AST. Exit on error. ; (8) Optionally sleep for 5 minutes to allow system stabilization ; (9) Sleep until next interval mark. Initialize for next pass. ; (10) Scan pool for fragmentation and task statistics. ; (11) Repeat (10) at 15 second intervals until logging interval expires. ; (12) Compute average statistics over last minute. ; (13) Reopen logging file. Exit on error. ; (14) Build log file statistics line. ; (15) Write statistics line to log file. Exit on error. ; (16) Close logging file. Exit on error. ; (17) Loop back to (9) until system crashes. .PAGE .SBTTL Log File Format ; One and only one of two formats may be chosen for the output file. ; FORMAT 1 - EXPANDED HUMAN/MACHINE READABLE ; ; This is the first format used for this task. Each record is 56 bytes ; in length, not counting Files-11 overhead. The file contains ASCII ; records of the form: ; ; 111#22-222-22#33:33##44444#55555#66666#77777#88888 ; ; where: 111 are the first 3 characters of the day of the week, ; first letter capitalized, second and third lower ; 22-222-22 is the day, month, and year since 1900 in standard ; RSX DAT$ output format (except day is zero-filled) ; 33:33 is the scan period start time hour and minute in ; standard RSX TIM$ output format ; 44444 is the average number of POOL fragments as a ; zero-filled five-place integer ; 55555 is the average size in words of the second largest ; POOL fragment as a zero-filled five-place integer ; 66666 is the average size in words of the largest POOL ; fragment as a zero-filled five-place integer ; 77777 is the average size in words of the total free POOL ; as a zero-filled five-place integer ; 88888 is the average number of tasks eligible to run as a ; zero-filled five-place integer ; # represents a single occurrence of the ASCII ; character 'space' (octal 40) ; FORMAT 2 - COMPACT MACHINE READABLE ; ; This is the second format used for this task. Each record is 24 bytes ; long, not counting Files-11 overhead. The file contains non-ASCII ; records of the form: ; ; 111#22222233334455667788 ; ; where: 111 are the first 3 characters of the day of the week, ; first letter capitalized, second and third lower ; 222222 is the day, month, and year since 1900 in standard ; RSX GTIM$ buffer format ; 3333 is the scan period start time hour and minute in ; standard RSX GTIM$ buffer format ; 44 is the average number of POOL fragments as a ; binary word ; 55 is the average size in words of the second largest ; POOL fragment as a binary word ; 66 is the average size in words of the largest POOL ; fragment as a binary word ; 77 is the average size in words of the total free POOL ; as a binary word ; 88 is the average number of tasks eligible to run as a ; binary word ; # represents an unspecified filler byte .PAGE .SBTTL Caveats and Restrictions ; There's no clean way to exit this task other than deleting its ; output file. ; This task's TCB takes up space in POOL, and it also shows up as one ; of the active tasks. This corrupts the statistics slightly. ; The logfile has to be closed during sampling so that it doesn't ; take up space in POOL. That would corrupt the statistics. .PAGE .SBTTL .SBTTL Macro Calls and Definitions ; ; System Executive macros from LB:[1,1]EXEMC.MLB ; .MCALL PCBDF$ ; Define PCB offsets .MCALL TCBDF$ ; Define TCB offsets PCBDF$ TCBDF$ ; ; Directive Macros from LB:[1,1]RSXMAC.SML ; .MCALL ALUN$ ; Assign Logical Unit Number .MCALL ASTX$S ; Exit from AST state .MCALL CLOSE$ ; Close a file .MCALL DELET$ ; Delete a file .MCALL DIR$ ; Execute directive .MCALL EXST$S ; Exit with status .MCALL FDAT$A ; Define file attributes .MCALL FDBF$A ; Define file buffer attributes .MCALL FDBDF$ ; Allocate space for an FDB .MCALL FDOP$A ; Define file open attributes .MCALL FDRC$A ; Define file record attributes .MCALL FINIT$ ; Initialize Files-11 services .MCALL FSRSZ$ ; Define FSR record area size .MCALL GTIM$ ; Get system time .MCALL GTSK$ ; Get task information .MCALL MRKT$ ; Mark time .MCALL NBOFF$ ; Define FNB offsets .MCALL OFID$A ; Open by file-ID for append .MCALL OPEN$ ; Open a file, general case .MCALL PUT$ ; Put a record to a file .MCALL QIOSY$ ; Define QIO symbols .MCALL QIOW$ ; Queue I/O and wait for completion .MCALL SREX$ ; Specify requested exit AST .MCALL STSE$ ; Stop for single event flag FSRSZ$ 1 ; Only 1 record I/O file NBOFF$ DEF$L QIOSY$ ; ; Local macro definitions ; ; Macro to send a timestamped message to the system console .MACRO COLOG STRING ; Begin COLOG macro MOV #STRING, LGMADD MOV #STRING'L, LGMLEN CALL COLOGR .ENDM ; End COLOG macro .PAGE .SBTTL .SBTTL Data .SBTTL .PSECT POLDAT, RW, D .SBTTL Symbol Definitions ; ; Conditional assembly control definitions ; H$OURL = 0 ; Uncomment for hourly logging F$ILEL = 0 ; Uncomment for output file logging ; F$MT2L = 0 ; Uncomment for compact format logging S$TABL = 0 ; Uncomment for 5 minute stabilization ; ; Logical unit numbers and event flags associated with them ; COLUN = 1 ; System console CO: I/O LUN OFILUN = 2 ; Output file I/O LUN COEFN = 1 ; System console CO: I/O EFN OFLEFN = 2 ; Output file I/O LUN MKTEFN = 3 ; Marktime activity EFN .PAGE .SBTTL Directive Parameter Blocks ; ; Directive Parameter Blocks ; ; Assign LUN to device DPBs ALUNCO: ALUN$ COLUN, CO, 0 ; Get system time DPBs GETTIM: GTIM$ TIMBUF ; Get task information DPBs GETTSK: GTSK$ TSKBUF ; Marktime DPBs MARK5M: MRKT$ MKTEFN, <5*60.>, 2 MARK15: MRKT$ MKTEFN, 15., 2 MARKTM: MRKT$ MKTEFN, , 2 ; QIO DPBs CONOUT: QIOW$ IO.WLB, COLUN, COEFN,,,, ; Specify requested exit AST DPBs NOABRT: SREX$ ABOAST ; Stop for event flag DPBs STOPFR: STSE$ MKTEFN .IF DF F$ILEL ; If file logging enabled .PAGE .SBTTL File Descriptor Blocks ; File descriptor block for the logging output file LOGFDB: FDBDF$ ; Allocate space for FDB ; File attributes FDAT$A R.VAR, FD.CR,,, ; Variable length records ; LF/CR when writing records to terminal ; Record attributes FDRC$A , OUTBUF, ; Access is sequential ; User record buffer is OUTBUF ; Open attributes FDOP$A OFILUN, OFLDDS,, FO.WRT!FA.NSP!FA.SHR, FA.DLK!FA.ENB!4 ; LUN is OFILUN ; Dataset descriptor is OFLDDS ; No default filename block ; Default open for write, no overwrite ; with shared access ; Don't lock file on improper close ; 4 retrieval pointers ; Block-buffer attributes FDBF$A OFLEFN ; FCS event flag for this file ; Output file dataset descriptor OFLDDS: .WORD OUDLEN, OUTDEV ; Device name descriptor .WORD OUULEN, OUTUFD ; UFD descriptor .WORD OUFLEN, OUTFIL ; File name OUTDEV: .ASCII \LB00:\ OUDLEN = . - OUTDEV OUTUFD: .ASCII \[1,4]\ OUULEN = . - OUTUFD OUTFIL: .ASCII \POOLMN.LOG;0\ OUFLEN = . - OUTFIL .EVEN .ENDC ; DF F$ILEL .PAGE .SBTTL Tables ; Day of the week pointer table and contiguous cumulative day table .WORD DAY6 ; Saturday .WORD DAY7 ; Sunday .WORD DAY1 ; Monday .WORD DAY2 ; Tuesday .WORD DAY3 ; Wednesday .WORD DAY4 ; Thursday .WORD DAY5 ; Friday DAYMON: .WORD -1 ; January .WORD 30. ; February .WORD 58. ; March .WORD 89. ; April .WORD 119. ; May .WORD 150. ; June .WORD 180. ; July .WORD 211. ; August .WORD 242. ; September .WORD 272. ; October .WORD 303. ; November .WORD 333. ; December .PAGE .SBTTL Messages and Strings ; ; Messages ; MS00: .ASCII \Installed task name is not POOLMN\ MS00L = . - MS00 MS01: .ASCII \Running priority is not at least 100.\ MS01L = . - MS01 MS02: .ASCII \Error opening log file, FCS code = \ MS02A: .BLKB 3 MS02L = . - MS02 MS03: .ASCII \Error closing log file, FCS code = \ MS03A: .BLKB 3 MS03L = . - MS03 MS04: .ASCII \Error writing log file, FCS code = \ MS04A: .BLKB 3 MS04L = . - MS04 MS05: .ASCII \POOLMN -- \ MS05L = . - MS05 MS06: .ASCII \POOL monitoring started\ MS06L = . - MS06 MS07: .ASCII \Error specifying abort AST, $DSW = \ MS07A: .BLKB 3 MS07L = . - MS07 MS08: .ASCII \Attempt was made to abort POOL monitor\ MS08L = . - MS08 MS09: .ASCII \Logging interval is not 1, 2, 5 or 10 minutes\ MS09L = . - MS09 MS10: .ASCII \Previous hour POOL low \ MS10A: .BLKB 5 .ASCII \. words, high \ MS10B: .BLKB 5 .ASCII \. words\ MS10L = . - MS10 ; ; Strings ; DAY1: .ASCII \Mon\ DAY2: .ASCII \Tue\ DAY3: .ASCII \Wed\ DAY4: .ASCII \Thu\ DAY5: .ASCII \Fri\ DAY6: .ASCII \Sat\ DAY7: .ASCII \Sun\ .EVEN .PAGE .SBTTL Block Variables LOGFNB: .BLKW S.FNBW ; Storage for log file FNB OUTBUF: .BLKB 80. ; Log file data line buffer TIDENT: .BLKW 2 ; Storage for task identification TIMBUF: .BLKW 8. ; Buffer for GTIM$ TSKBUF: .BLKW 16. ; Buffer for GTSK$ .PAGE .SBTTL Single Variables ACTTSK: .WORD 0 ; Number of running tasks accumulator BIGGST: .WORD 0 ; Largest available POOL in last hour INPASS: .WORD 0 ; Number of 15 sec passes per interval LGMADD: .WORD 0 ; Logging message address LGMLEN: .WORD 0 ; Logging message length LGESIZ: .WORD 0, 0 ; Largest POOL fragment accumulator MONINT: .WORD 5 ; Logging interval in minutes NFRAGS: .WORD 0 ; Number of POOL fragments accumulator PASSES: .WORD 0 ; Number of POOL scans SECINT: .WORD 0 ; Logging interval in seconds SECSIZ: .WORD 0, 0 ; 2nd largest POOL fragment accumulator SMALST: .WORD 65535. ; Smallest available POOL in last hour TOTSIZ: .WORD 0, 0 ; Free POOL available accumulator .PAGE .SBTTL .SBTTL Mainline Code .SBTTL .PSECT POLCOD, RO, I .SBTTL POLENT Entry Point ; ; Mainline code ; ; We just woke up. Assign a LUN to the system console, CO: POLENT: DIR$ #ALUNCO ; Try to assign a LUN to the console TST $DSW ; Did the assign succeed? BPL 10$ ; If so, proceed with initialization ; LUN assign failed. Such a bummer. Exit with error status. EXST$S #EX$ERR ; Exit with error status ; Get task information on ourself for verification use 10$: DIR$ #GETTSK ; Try to get task information on ourself TST $DSW ; Did the get task info succeed? BPL 20$ ; If so, proceed with initialization ; Get task info failed. Lowers my karma. Exit with error status. EXST$S #EX$ERR ; Exit with error status .PAGE .SBTTL * Runtime Validations ; Make sure that we're the only POOLMN running on the system. 20$: CMP TSKBUF+G.TSTN, #^RPOO ; First half of name Radix-50 POO? BNE 30$ ; If not, go die CMP TSKBUF+G.TSTN+2, #^RLMN ; Second half of name Radix-50 LMN? BEQ 40$ ; If so, proceed with initialization ; We're not POOLMN; maybe somebody else is. Message CO: and exit. 30$: COLOG MS00 ; Dump the error message ... EXST$S #EX$ERR ; Exit with error status ; Make sure our run priority's high enough. 100. is about right. 40$: CMP TSKBUF+G.TSPR, #100. ; Is our run priority at least 100.? BHIS 50$ ; If so, proceed with initialization ; Our run priority's too low. What a wheeze. Message CO: and exit. COLOG MS01 ; Dump the error message ... EXST$S #EX$ERR ; Exit with error status ; Make sure the logging interval is 1, 2, 5 or 10 minutes 50$: MOV #10., R1 ; Load 10 minute interval into R0/R1 CLR R0 ; doubleword register pair DIV MONINT, R0 ; Divide monitoring interval into 10 TST R1 ; Is the division remainder zero? BEQ 60$ ; If so, continue initializing ; Interval doesn't go into 10. Torques me out. Message CO: and exit. COLOG MS09 ; Dump the error message ... EXST$S #EX$ERR ; Exit with error status ; Compute and save various intervals needed repeatedly during monitoring 60$: MOV MONINT, INPASS ; Load logging interval in minutes ASL INPASS ; Multiply interval by 4 to get number ASL INPASS ; of 15 second passes per interval MOV MONINT, R1 ; Load monitoring interval in minutes MUL #60., R1 ; Multiply the interval by 60 MOV R1, SECINT ; And save the interval in seconds .IF DF F$ILEL ; If file logging enabled .PAGE .SBTTL * Build Logging File ; Initialize Files-11 services and try to open the log file FINIT$ ; Initialize Files-11 services OPEN$ #LOGFDB ; Try to open the logging file TSTB F.ERR(R0) ; Did it succeed? BPL 80$ ; If so, proceed with initialization ; Some error occurred during the file open. Log it and exit with error. MOV #MS02A, R0 ; Point at the FCS error field MOVB LOGFDB+F.ERR, R1 ; Load the error byte into R1 MOV SP, R2 ; Force no zero suppression CALL $CBTMG ; Convert binary byte to octal magnitude COLOG MS02 ; Dump the error message EXST$S #EX$ERR ; Exit to RSX with error status ; Save the FNB for later file opens by file-ID 80$: MOV #LOGFDB+F.FNB, R0 ; Load FDB FNB address in R0 MOV #LOGFNB, R1 ; Load stored FNB address in R1 MOV #S.FNBW, R2 ; Load FNB length in WORDS in R2 90$: MOV (R0)+, (R1)+ ; Copy a word from source to target SOB R2, 90$ ; Until all are copied ; Close the logging file. We'll open it during operation by file-ID. CLOSE$ #LOGFDB ; Close the file TSTB F.ERR(R0) ; Did it succeed? BPL 110$ ; If so, continue initializing ; Some error occurred during the file close. Log it and exit with error. MOV #MS03A, R0 ; Point at the FCS error field MOVB LOGFDB+F.ERR, R1 ; Load the error byte into R1 MOV SP, R2 ; Force no zero suppression CALL $CBTMG ; Convert binary byte to octal magnitude COLOG MS03 ; Dump the error message EXST$S #EX$ERR ; Exit to RSX with error status .ENDC ; DF F$ILEL .PAGE .SBTTL * Specify Abort AST ; The pool monitor task must not be aborted. Specify an abort AST. 110$: DIR$ #NOABRT ; Attempt to specify an abort AST TST $DSW ; Did it succeed? BPL 100$ ; If so, we're almost done with initting ; Some error occurred during the SREX$. Log it and exit with error. MOV #MS07A, R0 ; Point at the FCS error field MOVB $DSW, R1 ; Load the error byte into R1 MOV SP, R2 ; Force no zero suppression CALL $CBTMG ; Convert binary byte to octal magnitude COLOG MS07 ; Dump the error message DELET$ #LOGFDB ; Delete the logging file EXST$S #EX$ERR ; Exit to RSX with error status ; Log message on the system console stating that monitoring is started 100$: COLOG MS06 ; Dump console message .IF DF S$TABL ; If stabilization enabled .PAGE .SBTTL * Stabilize System ; Go to sleep for 5 minutes to allow the system time to stabilize DIR$ #MARK5M ; Take a nice little nap now DIR$ #STOPFR ; And wake up in 5 minutes .ENDC ; DF S$TABL .PAGE .SBTTL SLEEP Sleep Until Next Interval ; Do some final variable initialization before going to sleep SLEEP: CLR LGESIZ ; Clear largest fragment accumlator CLR LGESIZ+2 ; And the lower word as well CLR NFRAGS ; Clear number fragments accumulator CLR SECSIZ ; Clear 2nd largest fragmt accumulator CLR SECSIZ+2 ; And the lower word as well CLR TOTSIZ ; Clear total size accumulator CLR TOTSIZ+2 ; And the lower word as well CLR ACTTSK ; Clear the active task count MOV INPASS, PASSES ; Set up the number of 15 second scans ; We now find out the time, and sleep until the next interval mark. ; This synchronizes logging interval starts to the nearest second. DIR$ #GETTIM ; Get the system time MOV TIMBUF+G.TIMI, R1 ; Load current time in minutes in R1 MUL #60., R1 ; Multiply by 60 seconds per minute ADD TIMBUF+G.TISC, R1 ; Add seconds to get seconds-past-hour CLR R0 ; Now we'll use it as a doubleword DIV SECINT, R0 ; Divide seconds-past-hour by interval MOV SECINT, R0 ; Load monitoring interval into R0 SUB R1, R0 ; Subtracting remainder => sleep time MOV R0, MARKTM+M.KTMG ; Load nap length into marktime DPB DIR$ #MARKTM ; Take a nice little nap now DIR$ #STOPFR ; And wake up on the 0 second mark DIR$ #GETTIM ; For later reference when writing log .IF DF H$OURL ; If hourly logging enabled .PAGE .SBTTL * Hourly Logging ; See if this is the hour mark; if not, skip the hourly logging setup TST TIMBUF+G.TIMI ; Is this the 0 minute mark? BNE SCNPOL ; If not, just go scan POOL normally ; If started less than 5 minutes before the hour, don't do logging CMP SMALST, #65535. ; Is the smallest POOL mark unchanged? BEQ SCNPOL ; If so, just go scan POOL normally ; On the hour, we log high and low available POOL marks for the last hour MOV #MS10A, R0 ; Load output field address in R0 CLRB 4(R0) ; Null the output field last 2 bytes CLRB 3(R0) ; MOV SMALST, R1 ; Load low POOL mark in R1 CLR R2 ; Suppress leading zeroes CALL $CBDMG ; Convert binary to decimal magnitude MOV #MS10B, R0 ; Load output field address in R0 CLRB 4(R0) ; Null the output field last 2 bytes CLRB 3(R0) ; MOV BIGGST, R1 ; Load high POOL mark in R1 CLR R2 ; Suppress leading zeroes CALL $CBDMG ; Convert binary to decimal magnitude COLOG MS10 ; Print the message on the console MOV #65535., SMALST ; Load outrageous value into smallest CLR BIGGST ; Zero the biggest value .ENDC ; DF H$OURL .PAGE .SBTTL SCNPOL Scan POOL ; We now scan POOL looking for the relevant information. SCNPOL: SWSTK$ WAISCN ; Switch to system state to scan POOL ; Now we're in system state. Get the POOL data and then get out. ; Scan POOL for fragment and size information CLR R1 ;; Zero the free pool size CLR R2 ;; Zero the largest fragment size CLR R3 ;; Zero the number of fragments found CLR R4 ;; Zero the second largest fragmt size MOV @#$CRAVL, R0 ;; Load POOL listhead address in R0 10$: MOV 2(R0), R5 ;; Load fragment size in bytes into R5 ASR R5 ;; Change the fragment size into words ADD R5, R1 ;; Add fragment size to running total CMP R5, R2 ;; Is fragment > biggest seen so far? BLOS 20$ ;; If not, don't reset largest size MOV R5, R2 ;; Reset the largest fragment size 20$: CMP R5, R4 ;; Is fragment > 2nd biggest seen? BLOS 30$ ;; If not, don't reset 2nd largest size CMP R5, R2 ;; Is fragment = biggest seen? BEQ 30$ ;; If not, don't reset 2nd largest size MOV R5, R4 ;; Reset the 2nd largest fragment size 30$: INC R3 ;; Increment fragments examined count MOV (R0), R0 ;; Load the link to the next fragment BNE 10$ ;; And go look again if not list end ; Finished scan. Update internal variables as necessary. ADD R1, TOTSIZ+2 ;; Add total free POOL size ADC TOTSIZ ;; Add carry since it's double precision CMP R1, BIGGST ;; Available POOL > previous biggest? BLOS 35$ ;; If not, don't update biggest MOV R1, BIGGST ;; Update biggest available POOL 35$: CMP R1, SMALST ;; Available POOL < previous smallest? BHIS 36$ ;; If not, don't update smallest MOV R1, SMALST ;; Update smallest available POOL 36$: ADD R2, LGESIZ+2 ;; Add largest fragment size ADC LGESIZ ;; Add carry since it's double precision ADD R3, NFRAGS ;; Add number of fragments ADD R4, SECSIZ+2 ;; Add 2nd largest fragment size ADC SECSIZ ;; Add carry since it's double precision ; Scan POOL for active task information CLR R1 ;; Clear the active tasks counter MOV @#$ACTHD, R0 ;; Load active task listhead addr in R0 40$: TST T.STAT(R0) ;; Is the task blocked for any reason? BNE 50$ ;; If so, just forget it MOV T.PCB(R0), R2 ;; Load task PCB address in R2 CMP P.NAM(R2), #^RGEN ;; Is the task running in GEN? BNE 50$ ;; If not, just forget it INC R1 ;; Bump the tasks-active counter 50$: MOV T.ACTL(R0), R0 ;; Load the address of the next TCB BNE 40$ ;; And if nonzero go look at it ADD R1, ACTTSK ;; Add the number of active tasks RETURN ;; Return to user state .PAGE .SBTTL WAISCN Wait for Next Scan ; Back at task state. See if we're done scanning. WAISCN: DEC PASSES ; That's one more pass we've done BEQ DOSTAT ; And if we're done, exit loop NOW ; Not done yet. Wait 15 seconds and then go scan again. DIR$ #MARK15 ; Mark time for 15 seconds DIR$ #STOPFR ; And stop for the flag to set BR SCNPOL ; Go back for another scan .IF NDF F$ILEL ; If file logging disabled ; Done with this pass. Go back and sleep until the next interval. DOSTAT: JMP SLEEP ; Go back and sleep .IFF ; If file logging enabled .PAGE .SBTTL DOSTAT Compute Statistics ; We now average out the statistics collected over the last interval. ; There is a maximum time of 15 seconds to process and log this ; information before we must run again. DOSTAT: MOV ACTTSK, R1 ; Load tasks-active accumulator into CLR R0 ; R0/R1 doubleword DIV INPASS, R0 ; Divide it by # passes to get average MOV R0, ACTTSK ; Copy quotient back into accumulator MOV LGESIZ, R0 ; Load largest fragment accumulator MOV LGESIZ+2, R1 ; into R0/R1 doubleword DIV INPASS, R0 ; Divide it by # passes to get average MOV R0, LGESIZ+2 ; Copy quotient back into accumulator CLR LGESIZ ; Zero the upper word MOV NFRAGS, R1 ; Load number fragments accumulator CLR R0 ; into R0/R1 doubleword DIV INPASS, R0 ; Divide it by # passes to get average MOV R0, NFRAGS ; Copy quotient back into accumulator MOV SECSIZ, R0 ; Load second largest fragment MOV SECSIZ+2, R1 ; accumulator into R0/R1 doubleword DIV INPASS, R0 ; Divide it by # passes to get average MOV R0, SECSIZ+2 ; Copy quotient back into accumulator CLR SECSIZ ; Zero the upper word MOV TOTSIZ, R0 ; Load total free POOL accumulator MOV TOTSIZ+2, R1 ; into R0/R1 doubleword DIV INPASS, R0 ; Divide it by # passes to get average MOV R0, TOTSIZ+2 ; Copy quotient back into accumulator CLR TOTSIZ ; Zero the upper word .PAGE .SBTTL * Write Log Record ; Restore the FNB and open the file by file-ID for shared append MOV #LOGFNB, R0 ; Load stored FNB address in R0 MOV #LOGFDB+F.FNB, R1 ; Load FDB FNB address in R1 MOV #S.FNBW, R2 ; Load FNB length in WORDS in R2 10$: MOV (R0)+, (R1)+ ; Copy a word from source to target SOB R2, 10$ ; Until all are copied OFID$A #LOGFDB ; Open the output file for append TSTB F.ERR(R0) ; Did it succeed? BPL 20$ ; If so, proceed with logging ; Some error occurred during the file open. Log it and exit with error. MOV #MS02A, R0 ; Point at the FCS error field MOVB LOGFDB+F.ERR, R1 ; Load the error byte into R1 MOV SP, R2 ; Force no zero suppression CALL $CBTMG ; Convert binary byte to octal magnitude COLOG MS02 ; Dump the error message EXST$S #EX$ERR ; Exit to RSX with error status ; Log the record out to the data file 20$: CALL FILLOG ; Log the record to the data file ; Close the logging file; we're done with it for now. CLOSE$ #LOGFDB ; Close the file TSTB F.ERR(R0) ; Did it succeed? BPL 30$ ; If so, we're done for the moment ; Some error occurred during the file close. Log it and exit with error. MOV #MS03A, R0 ; Point at the FCS error field MOVB LOGFDB+F.ERR, R1 ; Load the error byte into R1 MOV SP, R2 ; Force no zero suppression CALL $CBTMG ; Convert binary byte to octal magnitude COLOG MS03 ; Dump the error message EXST$S #EX$ERR ; Exit to RSX with error status ; Done with this pass. Go back and sleep until the next minute. 30$: JMP SLEEP ; Go back and sleep .ENDC ; DF F$ILEL .PAGE .SBTTL .SBTTL AST Routines .SBTTL .SBTTL ABOAST Abort AST Handler ; AAAA BBBBBBBBB OOOOOOOO AAAA SSSSSSSSS TTTTTTTTTT ; AAAA BBBBBBBBB OOOOOOOO AAAA SSSSSSSSS TTTTTTTTTT ; AA AA BB BB OO OO AA AA SS TT ; AA AA BB BB OO OO AA AA SS TT ; AA AA BBBBBBBBB OO OO AA AA SSSSSSSS TT ; AA AA BBBBBBBBB OO OO AA AA SSSSSSSS TT ; AAAAAAAAAA BB BB OO OO AAAAAAAAAA SS TT ; AAAAAAAAAA BB BB OO OO AAAAAAAAAA SS TT ; AA AA BB BB OO OO AA AA SS TT ; AA AA BB BB OO OO AA AA SS TT ; AA AA BBBBBBBBB OOOOOOOO AA AA SSSSSSSS TT ; AA AA BBBBBBBBB OOOOOOOO AA AA SSSSSSSS TT ; ABOAST - Abort Attempt AST Service Routine ; ; This AST routine dumps a user-specified message to the system console ; and refuses the abort. ; ; Inputs: 00(SP) - Number of bytes to add to SP to clean stack ; 02(SP) - Trap dependent parameter ; 04(SP) - DSW of task prior to AST ; 06(SP) - PC of task prior to AST ; 10(SP) - PS of task prior to AST ; 12(SP) - Event flag mask word ; ; Outputs: None ; ; Register dispositions: SP modified ; ; Variable dispositions: None modified ABOAST: ADD (SP), SP ; Clean the stack off ; Dump a console message stating that an abort was tried, then exit AST COLOG MS08 ; Dump console message ASTX$S ; Exit from AST state .PAGE .SBTTL .SBTTL Subroutines .SBTTL .SBTTL COLOGR Timestamped Console Message ; CCCCCCCC OOOOOOOO LL OOOOOOOO GGGGGGGG RRRRRRRRR ; CCCCCCCC OOOOOOOO LL OOOOOOOO GGGGGGGG RRRRRRRRR ; CC CC OO OO LL OO OO GG RR RR ; CC CC OO OO LL OO OO GG RR RR ; CC OO OO LL OO OO GG RRRRRRRRR ; CC OO OO LL OO OO GG RRRRRRRRR ; CC OO OO LL OO OO GG GGGG RR RR ; CC OO OO LL OO OO GG GGGG RR RR ; CC CC OO OO LL OO OO GG GG RR RR ; CC CC OO OO LL OO OO GG GG RR RR ; CCCCCCCC OOOOOOOO LLLLLLLLLL OOOOOOOO GGGGGGGG RR RR ; CCCCCCCC OOOOOOOO LLLLLLLLLL OOOOOOOO GGGGGGGG RR RR ; COLOGR - Send Timestamped Message to System Console ; ; This subroutine dumps a user-specified message to the system console. ; The message is prepended with the current time, taskname and task ID. ; ; Inputs: LGMADD - Output string address ; LGMLEN - Output string length in bytes ; ; Outputs: None ; ; Register dispositions: All registers are saved and restored ; ; Variable dispositions: OUTBUF modified COLOGR: CALL $SAVAL ; Save R0 - R5 ; Prepend the message with date and time DIR$ #GETTIM ; Get the system time MOV #OUTBUF, R0 ; Load output buffer address in R0 MOV #TIMBUF+G.TIHR, R1 ; Load time buffer time address in R1 MOV #3, R2 ; Convert in form HH:MM:SS CALL $TIM ; Convert time to ASCII MOVB #40, (R0)+ ; Add a separating space MOVB #40, (R0)+ ; Add a separating space ; Append the task ident header to the prefix MOV #MS05, R1 ; Load task/ident string address MOV #MS05L, R2 ; Load task/ident string length 10$: MOVB (R1)+, (R0)+ ; Copy a byte from source to target SOB R2, 10$ ; And loop until all copied ; Append the message string to the prefix MOV LGMADD, R1 ; Load input string address MOV LGMLEN, R2 ; Load input string length 20$: MOVB (R1)+, (R0)+ ; Copy a byte from source to target SOB R2, 20$ ; And loop until all copied SUB #OUTBUF, R0 ; R0 is now the message length MOV R0, CONOUT+Q.IOPL+2 ; Load the message length in QIO DPB DIR$ #CONOUT ; Log message to the system console RETURN ; Return to the caller .PAGE .SBTTL DAYWEK Identify Day of Week ; DDDDDDDD AAAA YY YY WW WW EEEEEEEEEE KK KK ; DDDDDDDD AAAA YY YY WW WW EEEEEEEEEE KK KK ; DD DD AA AA YY YY WW WW EE KK KK ; DD DD AA AA YY YY WW WW EE KK KK ; DD DD AA AA YYYY WW WW EEEEEEEE KK KK ; DD DD AA AA YYYY WW WW EEEEEEEE KK KK ; DD DD AAAAAAAAAA YY WW WW WW EE KKK KK ; DD DD AAAAAAAAAA YY WW WW WW EE KKK KK ; DD DD AA AA YY WWWW WWWW EE KK KK ; DD DD AA AA YY WWWW WWWW EE KK KK ; DDDDDDDD AA AA YY WWW WWW EEEEEEEEEE KK KK ; DDDDDDDD AA AA YY WWW WWW EEEEEEEEEE KK KK ; DAYWEK - Identify Day Name of Current Date ; ; This subroutine returns a pointer to an ASCII string containing ; the current day of the week. Adapted from the RSX routine used ; in the macro assembler. ; ; Inputs: TIMBUF - GTIM$ buffer ; ; Outputs: R0 - Pointer to 3-byte ASCII string ; ; Register dispositions: R0 destroyed ; ; Variable dispositions: None modified DAYWEK: JSR R5, .SAVR1 ; Save registers 1 - 5 MOV #TIMBUF, R5 ; Move GTIM$ buffer address into R5 MOV (R5)+, R0 ; Load year into R0 SUB #110, R0 ; Subtract 72. from the year MOV (R5)+, R4 ; Load the month into R4 ASL R4 ; Multiply the month by 2 SUB #2, R4 ; And convert it to 0-based MOV (R5), R5 ; Load the day of month into R5 MOV R0, -(SP) ; Save the munged year on the stack DEC R0 ; Decrement the munged year ASR R0 ; Divide it by 2 ASR R0 ; ... by 4 ADD (SP), R0 ; Add the munged year to the year/4 INC R0 ; And increment it ADD R0, R5 ; Add that value to the day of month BIT #3, (SP)+ ; Is it a multiple of 4 (leap year)? BNE 10$ ; If not, skip around ; Leap year; special treatment for months past February CMP #2, R4 ; Is the month past February? ADC R5 ; If so, add the carry to R5 10$: ADD DAYMON(R4), R5 ; Add the number of days since 1/1 to R5 20$: SUB #7, R5 ; Subtract days per week from R5 BPL 20$ ; And continue until it goes negative ASL R5 ; Multiply remainder by 2 MOV DAYMON(R5), R0 ; Point at day of week address in table RETURN ; Return to the caller .IF DF F$ILEL ; If file logging enabled .PAGE .SBTTL FILLOG Build and Log Data Record ; FFFFFFFFFF IIIIIIII LL LL OOOOOOOO GGGGGGGG ; FFFFFFFFFF IIIIIIII LL LL OOOOOOOO GGGGGGGG ; FF II LL LL OO OO GG ; FF II LL LL OO OO GG ; FFFFFFFF II LL LL OO OO GG ; FFFFFFFF II LL LL OO OO GG ; FF II LL LL OO OO GG GGGG ; FF II LL LL OO OO GG GGGG ; FF II LL LL OO OO GG GG ; FF II LL LL OO OO GG GG ; FF IIIIIIII LLLLLLLLLL LLLLLLLLLL OOOOOOOO GGGGGGGG ; FF IIIIIIII LLLLLLLLLL LLLLLLLLLL OOOOOOOO GGGGGGGG ; FILLOG - Build and Write Logging Record to Logging File ; ; This subroutine builds and writes a logging record to the output log ; file. Note that on error, it logs the error and dies immediately. ; ; Inputs: TIMBUF - GTIM$ buffer ; ACTTSK - Active tasks ; LGESIZ - Largest fragment size ; NFRAGS - Number of fragments ; SECSIZ - 2nd largest fragment size ; TOTSIZ - Total free POOL ; ; Outputs: None ; ; Register dispositions: All registers used are saved and restored ; ; Variable dispositions: OUTBUF destroyed .IF DF F$MT2L ; If format 2 logging FILLOG: CALL DAYWEK ; Find day of the week MOV #OUTBUF, R1 ; Load logging line buffer addr in R1 MOVB (R0)+, (R1)+ ; Copy first byte of day name MOVB (R0)+, (R1)+ ; Copy second byte of day name MOVB (R0)+, (R1)+ ; Copy third byte of day name CLRB (R1)+ ; Stick in a zero separator byte MOV #TIMBUF+G.TIYR, R0 ; Load date buffer address in R0 MOV #/2, R2 ; Load WORDS date buffer length in R2 10$: MOV (R0)+, (R1)+ ; Copy another word to output buffer SOB R2, 10$ ; Until all are copied MOV NFRAGS, (R1)+ ; Load number of fragments MOV SECSIZ+2, (R1)+ ; Load 2nd largest fragment size MOV LGESIZ+2, (R1)+ ; Load largest fragment size MOV TOTSIZ+2, (R1)+ ; Load total free POOL MOV ACTTSK, (R1)+ ; Load active tasks SUB #OUTBUF, R1 ; R1 is now the line length in bytes .IFF ; If not format 2 (= format 1) logging FILLOG: CALL DAYWEK ; Find day of the week MOV #OUTBUF, R1 ; Load logging line buffer addr in R1 MOVB (R0)+, (R1)+ ; Copy first byte of day name MOVB (R0)+, (R1)+ ; Copy second byte of day name MOVB (R0)+, (R1)+ ; Copy third byte of day name MOVB #40, (R1)+ ; Add a separating space MOV R1, R0 ; Because all following routines use R0 CMP TIMBUF+G.TIDA, #10. ; Is the day 10 or more? BHIS 10$ ; If so, don't prepend a leading zero MOVB #'0, (R0)+ ; Prepend the day with a leading zero 10$: MOV #TIMBUF+G.TIYR, R1 ; Load time buffer date address CALL $DAT ; Convert date to ASCII MOVB #40, (R0)+ ; Add a separating space MOV #TIMBUF+G.TIHR, R1 ; Load time buffer time address in R1 MOV #2, R2 ; Convert in form HH:MM CALL $TIM ; Convert time to ASCII MOVB #':, (R0)+ ; Add an appended : MOVB #'0, (R0)+ ; Add an appended 0 MOVB #'0, (R0)+ ; Add an appended 0 MOVB #40, (R0)+ ; Add a separating space MOVB #40, (R0)+ ; Add a separating space MOV NFRAGS, R1 ; Load number of fragments in R1 MOV SP, R2 ; Force no leading zero suppress CALL $CBDMG ; Convert binary to decimal magnitude MOVB #40, (R0)+ ; Add a separating space MOV SECSIZ+2, R1 ; Load 2nd largest fragment size in R1 MOV SP, R2 ; Force no leading zero suppress CALL $CBDMG ; Convert binary to decimal magnitude MOVB #40, (R0)+ ; Add a separating space MOV LGESIZ+2, R1 ; Load largest fragment size in R1 MOV SP, R2 ; Force no leading zero suppress CALL $CBDMG ; Convert binary to decimal magnitude MOVB #40, (R0)+ ; Add a separating space MOV TOTSIZ+2, R1 ; Load total free POOL in R1 MOV SP, R2 ; Force no leading zero suppress CALL $CBDMG ; Convert binary to decimal magnitude MOVB #40, (R0)+ ; Add a separating space MOV ACTTSK, R1 ; Load active tasks in R1 MOV SP, R2 ; Force no leading zero suppress CALL $CBDMG ; Convert binary to decimal magnitude MOV R0, R1 ; Copy buffer pointer into R1 SUB #OUTBUF, R1 ; R1 is now the line length in bytes .ENDC ; DF F$MT2L ; Write the record to the output file PUT$ #LOGFDB,, R1 ; Write the record to the output file TSTB F.ERR(R0) ; Did it succeed? BPL 20$ ; If so, go return ; Some error occurred during the file write. Log it and exit with error. MOV #MS04A, R0 ; Point at the FCS error field MOVB LOGFDB+F.ERR, R1 ; Load the error byte into R1 MOV SP, R2 ; Force no zero suppression CALL $CBTMG ; Convert binary byte to octal magnitude COLOG MS04 ; Dump the error message EXST$S #EX$ERR ; Exit to RSX with error status ; Wrote the record just hunky-dory. Return to the caller 20$: RETURN ; Return to the caller .ENDC ; DF F$ILEL .END POLENT