.TITLE SYSTEM STATISTICS ROUTINE .IDENT /V1.01/ .NLIST BEX .MCALL GTIM$C,EXIT$S,QIOW$,DIR$ .MCALL .INH0,.ENB0 .MCALL FDBDF$,FDAT$A,FDRC$A,FDOP$A,FDBF$A,FSRSZ$ .MCALL OPEN$A,OPEN$W,PUT$,CLOSE$,EXST$S .ENABL LC ; ; RAM DEFINITIONS ; EDMSG ARGUMENT BLOCK FOR TI: LISTING LSTARG: TIMBUF: .BLKW 6 ; GTIM BUFFER WITH RAW TIME DATA ; UHOUR: .BLKW 1 ; # OF HOURS OF UPTIME UMIN: .BLKW 1 ; # OF MINUTES OF UPTIME ; USERS: .BLKW 1 ; # OF PRESENTLY LOGGED IN TERMINALS ; CUSER: .BLKW 1 ; CURRENT USER % CBATCH: .BLKW 1 ; CURRENT BATCH % CSWAP: .BLKW 1 ; CURRENT SWAP % CNULL: .BLKW 1 ; CURRENT NULL % CREAL: .BLKW 1 ; CURRENT REAL % ; TUSER: .BLKW 1 ; TOTAL USER % TBATCH: .BLKW 1 ; TOTAL BATCH % TSWAP: .BLKW 1 ; TOTAL SWAP % TNULL: .BLKW 1 ; TOTAL NULL % TREAL: .BLKW 1 ; TOTAL REAL % ; ; END OF ARGUMENT BLOCK #1 .PAGE ; ; EDMSG ARGUMENT BLOCK FOR DATA WRITTEN TO FILE FILARG: .BLKW 6 ; COPY OF "TIMBUF" .BLKW 1 ; COPY OF LOCATION "USERS" ; TEMPORARY STORAGE FOR SINCE STARTUP TIMES TEMP: .BLKW 10. ; ; END OF ARGUMENT BLOCK #2 ; ; TEMPORARY STORAGE FOR CURRENT (DELTA TIME) VALUES CTEMP: .BLKW 10. ; ; OUTPUT STRING BUFFER OBUF: .BLKB 256. ; ; QIOW STATUS OUTPUT BLOCK QIOMO: QIOW$ IO.WVB!TF.CCO!TF.WBT,5,1,,IOSB,, QIOCTR=QIOMO+Q.IOPL+2 ; ; QIOW STATUS BLOCK IOSB: .BLKW 2 .PAGE ; ; FILE PARAMETER BLOCK DATLUN=3 ; LOGICAL UNIT NUMBER ASSOCIATED W/FILE FSRSZ$ 1 ; SET ASIDE 1 FILE STORAGE REGION DATFPB: FDBDF$ FDAT$A R.VAR,FD.CR!FD.BLK FDRC$A FD.PLC,OBUF,80. FDOP$A DATLUN,DATDSP FDBF$A ,,1 ; ; DATA SET DESCRIPTOR INFO DATDSP: .WORD DEVL,DEV .WORD UICL,UIC .WORD FILEL,FILE ; DEV: .ASCII /LB0:/ DEVL=.-DEV ; UIC: .ASCII /[1,1]/ UICL=.-UIC ; FILE: .ASCII /STAT.DAT/ FILEL=.-FILE ; .EVEN .PAGE ; ; CONSTANTS (RO) ; ; CLI MATCH WORD CLIR: .RAD50 /CLI/ ; ; FORMAT STRING FOR TI: OUTPUT LSTFMT: .ASCII /%2N%Y %3Z Uptime = %D Hr %D Min%N/ .ASCII /Terminals presently logged in = %D%N/ .ASCII /Utilization User Batch Swap Null Real%N/ .ASCII /Current %D% %D% %D% %D% %D% %N/ .ASCIZ /Since startup %D% %D% %D% %D% %D% %N/ .EVEN ; ; FORMAT STRING FOR FILE OUTPUT FILFMT: ; DATE TIME USERS SSTIM SNTIM SUTIM SPTIM SBTIM .ASCIZ /%80<%Y %3Z %D,%D,%D,%D,%D,%D,%D,%D,%D,%D,%D/ .EVEN ; TWOHUN: .FLT2 200. ; FP 200 FOR PERCENT CALCULATION .PAGE START: GTIM$C TIMBUF ; GET CURRENT DATE AND TIME ; ; GET UPTIME STATISTICS (IF > LAST TIME, OK TO DO INCR) MOV .TKPS,R0 ; TICKS/SEC MOV .SETIM,R1 ; ELAPSED UPTIME MOV .SETIM+2,R2 CALL $DDIV ; CONVERT TO SECONDS MOV #60.,R0 CALL $DDIV ; CONVERT TO MINUTES (SECS IN R0) MOV #60.,R0 CALL $DDIV ; CONVERT TO HOURS IN R2 (MINS IN R0) MOV R0,UMIN ; PUT DATA IN OUTPUT BUFFER MOV R2,UHOUR ; ; MOVE CURRENT STATISTICS INTO TEMPORARY STORAGE .INH0 ;; INHIBIT TASK SWITCHING MOV .SSTIM,TEMP ;; GET TOTAL TIMESHARING SYSTEM TIME MOV .SSTIM+2,TEMP+2 ;; MOV .SNTIM,TEMP+4 ;; GET TOTAL NULL TIME MOV .SNTIM+2,TEMP+6 ;; MOV .SUTIM,TEMP+10 ;; GET TOTAL USER TIME MOV .SUTIM+2,TEMP+12 ;; MOV .SPTIM,TEMP+14 ;; GET TOTAL SWAP TIME MOV .SPTIM+2,TEMP+16 ;; MOV .SBTIM,TEMP+20 ;; GET TOTAL BATCH TIME MOV .SBTIM+2,TEMP+22 ;; .ENB0 ; RE-ENABLE TASK SWITCHING ; ; CALCULATE SINCE STARTUP STATS AC0=%0 ; DEFINE THE FP REGISTERS AC1=%1 AC2=%2 AC3=%3 AC4=%4 SETF ; SET SP ON THE FPP SETL ; SET LONG INTEGER MODE LDCLF TEMP,AC0 ; GET TOTAL SYSTEM TIME DIVF TWOHUN,AC0 ; AND SCALE TO 200% LDCLF TEMP+4,AC1 ; GET NULL PLUS SWAP TIME LDCLF TEMP+14,AC2 ; AND GET SWAP ONLY TIME SUBF AC2,AC1 ; AC1 NOW HAS NULL ONLY TIME STCFL AC1,TEMP+4 ; PUT NULL ONLY VALUE BACK INTO TABLE DIVF AC0,AC1 ; AND CONVERT TO % SETI ; GET BACK TO INTEGER MODE STCFI AC1,R1 ; STORE IN R1 INC R1 ; ADD 1 TO ROUND UP IF REMAINDER >= .5 ASR R1 ; AND DIVIDE BY 2 TO SCALE TO 100% MOV R1,TNULL ; FINALLY STORE VALUE IN OUTPUT TABLE SETF ; AND BACK TO FP MODE SETL ; SWAP TIME IS ALREADY IN AC2 DIVF AC0,AC2 ; CONVERT SWAP TIME TO % SETI STCFI AC2,R1 ; STORE IN R1 INC R1 ; ADD 1 TO ROUND UP IF REMAINDER >= .5 ASR R1 ; AND DIVIDE BY 2 TO SCALE TO 100% MOV R1,TSWAP SETF SETL LDCLF TEMP+10,AC1 ; GET USER AND BATCH TIME LDCLF TEMP+20,AC2 ; AND GET BATCH ONLY TIME SUBF AC2,AC1 ; AC1 NOW HAS USER ONLY TIME STCFL AC1,TEMP+10 ; PUT USER ONLY VALUE BACK INTO TABLE DIVF AC0,AC1 SETI STCFI AC1,R1 ; STORE IN R1 INC R1 ; ADD 1 TO ROUND UP IF REMAINDER >= .5 ASR R1 ; AND DIVIDE BY 2 TO SCALE TO 100% MOV R1,TUSER ; STORE IN OUTPUT TABLE SETF SETL ; BATCH TIME IS ALREADY IN AC2 FROM USER CALCULATION DIVF AC0,AC2 SETI STCFI AC2,R1 ; STORE IN R1 INC R1 ; ADD 1 TO ROUND UP IF REMAINDER >= .5 ASR R1 ; AND DIVIDE BY 2 TO SCALE TO 100% MOV R1,TBATCH ; ; COMPUTE REAL TIME BY ADDING TOGETHER ABOVE QUANTITIES AND ; SUBTRACTING FROM 100% MOV #100.,R1 ; ASSUME REAL USES 100% SUB TUSER,R1 ; MINUS USER % SUB TBATCH,R1 ; MINUS BATCH % SUB TSWAP,R1 ; MINUS SWAP % SUB TNULL,R1 ; MINUS NULL % ; AT THIS POINT, R1 CONTAINS % REAL TIME ; DUE TO ROUNDING ERROR, WE MUST TEST FOR R1 < 0 BPL 10$ ; IF >= 0, EVERYTHING IS OK CLR R1 ; OTHERWISE WE MUST CLEAR R1 10$: MOV R1,TREAL ; SAVE REAL TIME % .PAGE ; ; NOW CALCULATE THE CURRENT (DELTA TIME) STATS ; WE ASSUME THAT THE SAVED DATA IN THE SGA IS VALID IF THE ; CURRENT .SSTIM IS GREATER THAN THE SAVED .SSTIM. IF THIS ; IS NOT THE CASE, CURRENT STATS ARE THE SAME AS SINCE ; STARTUP STATS, SO RE-CALCULATION NEED NOT BE DONE; THE ; VALUES IN TEMP ARE COPIED TO CTEMP FOR OUTPUT TO THE ; STAT FILE. IF .SSTIM IS LESS THAN THE SAVED .SSTIM, ; THE DIFFERENCE BETWEEN OLD AND NEW VALUES IS CALCULATED ; AND STORED IN CTEMP, AND NEW PERCENTAGES BASED ON THESE ; VALUES ARE CALCULATED. CMP TEMP,OTEMP ; IS .SSTIM MSW >= OLD .SSTIM MSW ? BMI FIRST ; NO, THIS MUST BE THE FIRST TIME THRU BNE 20$ ; NEW .SSTIM MSW > OLD, NO NEED TO TEST LSW CMP TEMP+2,OTEMP+2 ; NEW .SSTIM MSW = OLD, TEST LSW >= OLD LSW BLOS FIRST ; BRANCH IF NEW .SSTIM LSW <= OLD ; ; CALCULATE DELTA STATS 20$: SETF ; SET SP ON FPP SETL ; SET LONG INTEGER MODE LDCLF TEMP,AC0 ; GET CURRENT .SSTIM LDCLF OTEMP,AC1 ; GET OLD .SSTIM SUBF AC1,AC0 ; COMPUTE DIFFERENCE STCFL AC0,CTEMP ; AND SAVE IT DIVF TWOHUN,AC0 ; SCALE TO 200% FOR DELTA % CALCULATIONS ; CALCULATE NULL TIME LDCLF TEMP+4,AC1 ; GET CURRENT NULL TIME LDCLF OTEMP+4,AC2 ; GET OLD NULL TIME SUBF AC2,AC1 ; COMPUTE DIFFERENCE STCFL AC1,CTEMP+4 ; AND SAVE IT DIVF AC0,AC1 ; CALCULATE DELTA % NULL TIME SETI ; SET INTEGER MODE STCFI AC1,R1 ; STORE IN R1 INC R1 ; ADD 1 TO ROUND UP IF REMAINDER >= .5 ASR R1 ; AND DIVIDE BY 2 TO SCALE TO 100% MOV R1,CNULL ; STORE IN OUTPUT ARGUMENT BLOCK SETF ; GO BACK TO FLOATING POINT MODE SETL ; CALCULATE USER TIME LDCLF TEMP+10,AC1 ; GET CURRENT USER TIME LDCLF OTEMP+10,AC2 ; GET OLD USER TIME SUBF AC2,AC1 ; COMPUTE DIFFERENCE STCFL AC1,CTEMP+10 ; AND SAVE IT DIVF AC0,AC1 ; CALCULATE DELTA % USER TIME SETI ; SET INTEGER MODE STCFI AC1,R1 ; STORE IN R1 INC R1 ; ADD 1 TO ROUND UP IF REMAINDER >= .5 ASR R1 ; AND DIVIDE BY 2 TO SCALE TO 100% MOV R1,CUSER ; STORE IN OUTPUT ARGUMENT BLOCK SETF ; GO BACK TO FLOATING POINT MODE SETL ; CALCULATE SWAP TIME LDCLF TEMP+14,AC1 ; GET CURRENT SWAP TIME LDCLF OTEMP+14,AC2 ; GET OLD SWAP TIME SUBF AC2,AC1 ; COMPUTE DIFFERENCE STCFL AC1,CTEMP+14 ; AND SAVE IT DIVF AC0,AC1 ; CALCULATE DELTA % SWAP TIME SETI ; SET INTEGER MODE STCFI AC1,R1 ; STORE IN R1 INC R1 ; ADD 1 TO ROUND UP IF REMAINDER >= .5 ASR R1 ; AND DIVIDE BY 2 TO SCALE TO 100% MOV R1,CSWAP ; STORE IN OUTPUT ARGUMENT BLOCK SETF ; GO BACK TO FLOATING POINT MODE SETL ; CALCULATE BATCH TIME LDCLF TEMP+20,AC1 ; GET CURRENT BATCH TIME LDCLF OTEMP+20,AC2 ; GET OLD BATCH TIME SUBF AC2,AC1 ; COMPUTE DIFFERENCE STCFL AC1,CTEMP+20 ; AND SAVE IT DIVF AC0,AC1 ; CALCULATE DELTA % BATCH TIME SETI ; SET INTEGER MODE STCFI AC1,R1 ; STORE IN R1 INC R1 ; ADD 1 TO ROUND UP IF REMAINDER >= .5 ASR R1 ; AND DIVIDE BY 2 TO SCALE TO 100% MOV R1,CBATCH ; STORE IN OUTPUT ARGUMENT BLOCK ; ; NOW CALCULATE THE DELTA REAL TIME % BASED ON THE OTHER VALUES MOV #100.,R1 ; ASSUME REAL USES 100% SUB CUSER,R1 ; MINUS DELTA USER % SUB CBATCH,R1 ; MINUS DELTA BATCH % SUB CSWAP,R1 ; MINUS DELTA SWAP % SUB CNULL,R1 ; MINUS DELAT NULL % ; AT THIS POINT, R1 CONTAINS DELTA % REAL TIME ; DUE TO ROUNDING ERROR, WE MUST TEST FOR R1 < 0. BPL 30$ ; IF >= 0, EVERYTHING IS OK CLR R1 ; OTHERWISE WE MUST CLEAR R1 30$: MOV R1,CREAL ; SAVE DELTA REAL TIME % BR UPDATE ; UPDATE OTEMP VALUES .PAGE ; ; FIRST TIME THRU PROGRAM. MOVE SINCE STARTUP VALUES INTO BOTH ; CURRENT TEMP AND OUTPUT ARGUMENT BLOCK. FIRST: MOV #TEMP,R1 ; R1 --> SINCE STARTUP BLOCK MOV #CTEMP,R2 ; R2 --> CURRENT STATS BLOCK MOV #10.,R3 ; R3 <-- # OF WORDS TO XFER 10$: MOV (R1)+,(R2)+ SOB R3,10$ ; REPEAT LOOP UNTIL DONE ; ; NOW MOVE SINCE STARTUP PERCENTAGES INTO CURRENT STATS MOV #TUSER,R1 ; R1 --> SINCE STARTUP PERCENTAGES MOV #CUSER,R2 ; R2 --> CURRENT STATS PERCENTAGES MOV #5,R3 ; R3 <-- # OF WORDS TO XFER 20$: MOV (R1)+,(R2)+ SOB R3,20$ ; REPEAT LOOP UNTIL DONE ; ; FALL THRU TO MOVE CONTENTS OF TEMP INTO OTEMP .PAGE ; ; MOVE CONTENTS OF TEMP INTO OTEMP (SGA) UPDATE: MOV #TEMP,R1 ; R1 --> SINCE STARTUP VALUES MOV #OTEMP,R2 ; R2 --> SGA MOV #10.,R3 ; R3 <-- # OF WORDS TO XFER 5$: MOV (R1)+,(R2)+ SOB R3,5$ ; REPEAT LOOP UNTIL DONE ; ; FALL THRU TO CALCULATE NUMBER OF ACTIVE TERMINALS .PAGE ; ; CHECK THE NUMBER OF ACTIVE TERMINALS ; ; THIS SECTION OF CODE SCANS THE UTL FOR ACTIVE CLI'S. ; THE NUMBER OF ACTIVE CLI'S IS STORED IN LOCATION USERS ; IN THE OUTPUT ARGUMENT BLOCK. ; NOTE: THIS SECTION OF CODE MUST BE EXECUTED WITH ; TASK SWITCHING DISABLED!!! ; GETUJN: CLR USERS ; CLEAR THE NUMBER OF USERS .INH0 ;; INHIBIT TASK SWITCHING MOV .UTLHD,R1 ;; START ADDR OF USER JOBS MOV .UTLNO,R2 ;; NUMBER OF LEVELS 10$: MOV Z.FJ(R1),R3 ;; FIRST JOB OF THIS LEVEL MOV Z.LJ(R1),R4 ;; LAST JOB OF THIS LEVEL TSTB Z.NE(R1) ;; IS ANYTHING AT THIS LEVEL? BEQ 30$ ;; EQ -- THEN THIS LEVEL'S EMPTY 20$: MOV X.JN(R3),R0 ;; GET JOB NODE ADDRESS CMP J.JB(R0),CLIR ;; IS IT A CLI ? BNE 25$ ;; NO, SKIP USER UPDATE INC USERS ;; YES, BUMP USERS COUNT 25$: CMP R3,R4 ;; IS THIS THE LAST UJN ? BEQ 30$ ;; YES, GO TO NEXT LEVEL MOV N.FP(R3),R3 ;; POINT TO NEXT LIST ELEMENT BR 20$ ;; CHECK IT OUT 30$: DEC R2 ;; DECREASE LEVEL NUMBER BEQ 40$ ;; MOV Z.NL(R1),R1 ;; GET NEXT LEVEL BR 10$ ;; CHECK IT OUT 40$: .ENB0 ; RE-ENABLE TASK SWITCHING .PAGE ; ; OUTPUT STATS TO CONSOLE ONLY IF CUSER + CBATCH .GT. 0 MOV CUSER,R0 ; GET USER DELTA PERCENT ADD CBATCH,R0 ; ADD IN BATCH DELTA PERCENT BEQ FILOUT ; BRANCH IF NO DELTA USER OR BATCH TIME ; ; EDIT CONSOLE OUTPUT MESSAGE MOV #OBUF,R0 ; ADDRESS OF OUTPUT BUFFER MOV #LSTFMT,R1 ; ADDRESS OF INPUT STRING MOV #LSTARG,R2 ; ADDRESS OF ARGUMENT BLOCK CALL $EDMSG MOV R1,QIOCTR ; PUT NUMBER OF CHARS EDITED INTO QIO BLOCK ; ; OUTPUT MESSAGE TO THE CONSOLE DIR$ #QIOMO .PAGE ; ; NOW OUTPUT DATA TO LB0:[1,1]STAT.DAT FILOUT: ; ; MOVE TIME DATA INTO FILARG MOV #TIMBUF,R1 ; R1 --> SOURCE OF DATA MOV #FILARG,R2 ; R2 --> FILARG ARGUMENT BLOCK MOV #6,R3 ; MOVE 6 WORDS 10$: MOV (R1)+,(R2)+ SOB R3,10$ ; ; MOVE NUMBER OF USERS INTO FILARG MOV USERS,(R2) ; PUT IN FILARG JUST PAST TIMBUF DATA ; ; FORMAT OUTPUT BUFFER USING EDMSG MOV #OBUF,R0 ; ADDRESS OF OUTPUT BUFFER MOV #FILFMT,R1 ; ADDRESS OF INPUT STRING MOV #FILARG,R2 ; ADDRESS OF ARGUMENT BLOCK CALL $EDMSG ; ; OPEN OUTPUT FILE OPEN$A #DATFPB BCC OPENOK ; BRANCH IF OPEN SUCCESSFUL ; ; FILE WASN'T THERE...OPEN A NEW ONE OPEN$W #DATFPB BCS BADOPN ; BRANCH IF OPEN NOT SUCCESSFUL OPENOK: PUT$ #DATFPB,#OBUF,R1 ; OUTPUT RECORD CLOSE$ #DATFPB ; AND CLOSE FILE EXIT$S ; BYE BYE ; ; COULDN'T OPEN FILE - OUTPUT JUNK TO CONSOLE BADOPN: MOV R1,QIOCTR ; PUT NUMBER OF CHARS EDITED INTO QIO BLOCK DIR$ #QIOMO ; OUTPUT MESSAGE TO THE CONSOLE EXST$S EX$ERR ; AND EXIT WITH ERROR STATUS .END START