.TITLE FRG DISK FRAGMENTATION .IDENT /D2.0/ .SBTTL DATA AREA ; ; DATE: 7/12/77 ; REVISED 2/7/78 D. M. ; BY: D. MICHAUD ; BORG INSTRUMENTS ; DELAVAN WISCONSIN ; ; THIS MCR TASK WILL PRODUCE FRAGMENTATION STATISTICS FOR THE SPECIFIED ; FILES-11 DEVICE. THE OUTPUT IS A FREQUENCY COUNT OF CONTIGUOUS FREE ; BLOCKS (HOLES) FALLING WITHIN EACH OF SEVERAL RANGES, THE TOTAL NUMBER ; OF BLOCKS FOR EACH RANGE, AND THE TOTAL NUMBER OF FREE BLOCKS FOR THE ; DEVICE. ; ; OUTPUT IS DIRECTED TO LUN 2, WHICH MAY BE ASSIGNED TO ANY TERMINAL. ; ERROR MESSAGES ARE DIRECTED TO LUN 5. ; ; MODIFIED: 19-OCT-78, D2.0, BRUCE C. WRIGHT ; CORRECTED NUMEROUS BUGS, ALLOWED NON-MCR COMMAND LINE ; EXECUTION, BETTER ERROR MESSAGES, USE 32-BIT ARITHMETIC. ; .NLIST MEB,BEX .MCALL GTIM$,QIOW$,EXIT$S,DIR$,ALUN$ .MCALL GCMLB$,GCML$ .MCALL OPEN$R,CLOSE$,FSRSZ$ .MCALL FDBDF$,FDRC$A,FDBK$A,FDOP$A .MACRO ERROR STR .NCHR $$$, JSR R0,$ERROR .WORD $$$ .ASCII "STR" .EVEN .ENDM .MACRO DIR$$ ARG MOV ARG,-(SP) JSR PC,.DIRDL .ENDM ; ; LOGICAL UNIT NUMBERS ; DSKLUN = 1 ;DISK I/O CMLLUN = 2 ;COMMAND LINE I/O ERRLUN = 5 ;ERROR MESSAGE I/O ; FSRSZ$ 1,512.+S.BFHD ; ONE FCS BUFFER FOR GET FDB: FDBDF$ FDRC$A FD.RWM FDBK$A INBUF,512.,,,IOST FDOP$A DSKLUN,DSET DSET: .WORD 0,0 .WORD UICSIZ,UIC .WORD NAMSIZ,NAME UIC: .ASCII /[0,0]/ UICSIZ=.-UIC .EVEN NAME: .ASCII /BITMAP.SYS/ NAMSIZ=.-NAME .EVEN INBUF: .BLKB 512. ;BUFFER FOR BITMAP. ENDBUF: ALUN: ALUN$ 1,DK,0 ; DUMMY ASSIGN LUN BUF: .BLKB 128. ; BUFFER FOR MESSAGES. CMLBLK: GCMLB$ 0,FRG,USRBUF,CMLLUN USRBUF: .BLKB 82. ;BUFFER FOR COMMAND LINES. TIME: GTIM$ BUF READ: QIOW$ IO.RVB,DSKLUN,32.,,IOST,, DPB: QIOW$ IO.WVB,ERRLUN,1,,,, SPSAVE: .WORD ;SAVE THE STACK POINTER FATAL: .WORD 0 ;FATAL ERROR INDICATOR. IOST: .BLKW 2 ;I/O STATUS BINS: .WORD 0,25.,0,50.,0,75.,0,100.,0,150.,0,200.,0,250. .WORD 0,300.,0,500.,0,750.,0,1000. BSIZ=11. ; NUMBER OF BINS - THE BIGGEST (< 1000. ) BIN: .BLKW *2. ;HOLDS FREQUENCY COUNT FOR EACH BIN BINSUM: .BLKW *2. ; HOLDS #BLOCKS FOR EACH BIN TOTAL: .WORD 0,0 ;TOTAL BLOCKS FOUND. TAB=11 LF=12 CR=15 FRGNAM: .ASCII /FRG/ FRGLEN = .-FRGNAM .EVEN STR1: .ASCII /DISK FRAGMENTATION STATISTICS FOR / ASCDEV: .ASCII /DK0:/ .ASCII /CONTIGUOUS FREE BLOCKS (HOLES)/ .ASCII /HOLE RANGE//FREQUENCY//NUMBER OF BLOCKS/ STR2: .ASCII / 0 - 25/ STR3: .ASCII / 26 - 50/ STR4: .ASCII / 51 - 75/ STR5: .ASCII / 76 - 100/ STR6: .ASCII /101 - 150/ STR7: .ASCII /151 - 200/ STR8: .ASCII /201 - 250/ STR9: .ASCII /251 - 300/ STRA: .ASCII /301 - 500/ STRB: .ASCII /501 - 750/ STRC: .ASCII /751 - 1000/ STRD: .ASCII / > 1000/ STRE: .ASCIZ /TOTAL FREE BLOCKS / .EVEN STRTAB: .WORD STR1 .WORD STR2 .WORD STR3 .WORD STR4 .WORD STR5 .WORD STR6 .WORD STR7 .WORD STR8 .WORD STR9 .WORD STRA .WORD STRB .WORD STRC .WORD STRD .WORD STRE .WORD STRTAB .WORD 0 .SBTTL CODE AREA ;+ ; ** FRG - DISPLAY FRAGMENTATION DATA FOR FILES-11 DEVICES ; ; SYNTAX: ; FRG DDN: ; ; WHERE: ; DD - A LEGAL FILES-11 DEVICE NAME ; N - A LEGAL UNIT NUMBER < 8 ;- CMLIOR: INC FATAL ;THIS ERROR IS FATAL. ERROR CMLOPR: ERROR CMLBIF: ERROR CMLMDE: ERROR CMLUNK: INC FATAL ;THIS ERROR IS FATAL. ERROR FRG: MOV SP,SPSAVE ; SAVE SP. RESTRT: MOV SPSAVE,SP ;RESTORE SP. GCML$ #CMLBLK ; GET A COMMAND LINE. BCC GETOK ; SKIP IF OK. CMPB CMLBLK+G.ERR,#GE.IOR ;I/O ERROR? BEQ CMLIOR ;YES CMPB CMLBLK+G.ERR,#GE.OPR ;OPEN FAILURE? BEQ CMLOPR ;YES CMPB CMLBLK+G.ERR,#GE.BIF ;SYNTAX ERROR? BEQ CMLBIF ;YES CMPB CMLBLK+G.ERR,#GE.MDE ;MAX @ FILE DEPTH? BEQ CMLMDE ;YES CMPB CMLBLK+G.ERR,#GE.EOF ;E-O-F? BNE CMLUNK ;NO EXIT$S ;YES -- EXIT. FRGSYN: ERROR GETOK:: MOV CMLBLK+G.CMLD,R1 ;GET OUR COMMAND LINE LENGTH. BEQ RESTRT ; LOOP IF 0. MOV CMLBLK+G.CMLD+2,R0 ;GET ADDR OF LINE. ; 20$: CMPB (R0)+,#' ; GET TO FIRST NON-BLANK. BNE 25$ ; FOUND IT. SOB R1,20$ ; LOOP UNTIL FIRST NON-BLANK. BR FRGSYN ; LOOP EXHAUSTED -- ERROR. 25$: MOVB -1(R0),ALUN+A.LUNA MOVB -1(R0),ASCDEV ; DEC R1 ; IS THE LINE EXHAUSTED? BLE FRGSYN ; YES -- ERROR MOVB (R0),ALUN+A.LUNA+1 MOVB (R0)+,ASCDEV+1 ; GET DEVICE NAME FOR OUTPUT MOVB #'0,ASCDEV+2 ; DEVICE NUMBER CLR ALUN+A.LUNU ; UNIT NUMBER. DEC R1 BLE 40$ ; SKIP IF END OF LINE. MOVB (R0)+,R2 ; GET THE DEVICE NUMBER. CMPB #' ,R2 ; IS IT A BLANK? BEQ 27$ ; YES -- END LINE. CMPB R2,#': ; LEGAL DEVICE? BEQ 27$ ; YES -- END LINE. CMPB R2,#'0 ; LEGAL DEVICE? BLO FRGSYN ; NO CMPB R2,#'7 ; LEGEL DEVICE? BHI FRGSYN ; NO MOVB R2,ASCDEV+2 ; DEVICE NUMBER BIC #177770,R2 ; STRIP ASCII MOV R2,ALUN+A.LUNU ; SET UNIT NUMBER. DEC R1 ; DONE? BLE 40$ ; YES CMPB #' ,(R0) ; A BLANK? BEQ 30$ ; YES -- TERMINATE LINE. CMPB (R0)+,#': ; IS IT TRAILED WITH A :? BNE FRGSYN ; NO 27$: DEC R1 ; DONE YET? BLE 40$ ; YES 30$: CMPB #' ,(R0)+ ; IS IT BLANK AFTER THE :? BNE FRGSYN ; NO SOB R1,30$ ; LOOP OVER REST OF LINE. 40$: MOV #FDB,R0 ;POINT TO FDB JUST IN CASE. CLR F.ERR(R0) ; CLEAR ERROR. DIR$ #ALUN ; ASSIGN INPUT DEVICE BCC 50$ ; CS= ILLEGAL DEVICE MOV @#$DSW,F.ERR(R0) ;RETURN ERROR CODE JMP FRGIO ; AND DO I/O ; 50$: OPEN$R R0 BCS FRGIO ;ILLEGAL DEVICE. CLR R4 ;CLEAR R4,R5 FOR COMPUTATION CLR R5 ; R4,R5 WILL HAVE BLOCK COUNT. MOV #1,READ+Q.IOPL+10 ;POINT TO BEG OF FILE. CLR R3 ;CLEAR INDEX THRU TABLES. MOV #BSIZ+1,R4 ;GET SIZE OF TABLES. 60$: CLR BIN(R3) ;CLEAR CLR BIN+2(R3) ; VARIABLES CLR BINSUM(R3) ; FOR CLR BINSUM+2(R3) ; RE-USE. ADD #4,R3 ;GO TO NEXT ADDR SOB R4,60$ ;LOOP OVER ALL DATA STRUCTURES. CLR TOTAL ;CLEAR TOTAL COUNT CLR TOTAL+2 ; AND LOW ORDER. RECORD: INC READ+Q.IOPL+10 ;INC BLOCK # MOV #FDB,R0 ; POINT TO FDB IN CASE OF ERROR. DIR$$ #READ ; DO I/O BCC 10$ ; SKIP IF OK MOV @#$DSW,F.ERR(R0) ;SET UP ERROR BYTE. BR FRGIO ; AND PRINT I/O ERROR. 10$: MOVB IOST,F.ERR(R0) ;ERROR? BLT ERR ; ERROR -- MIGHT BE END-OF-FILE. MOV #INBUF,R0 ; GET RECORD BUFFER BLOCKS: MOV (R0)+,R1 ; GET 1ST 16 BLOCKS BEQ FULL ; EQ= ALL USED CMP R1,#-1 ; ALL FREE? BNE COUNT ; NE=NOT ALL FREE ADD #16.,R5 ; COUNT 16 FREE BLOCKS ADC R4 ; INC HI ORDER. BR END ; SEE IF DONE ; COUNT: MOV #16.,R2 ; BIT SHIFT COUNTER SHIFT: ASR R1 ; CHECK A BLOCK ; NOTE: ASR RATHER THAN ROR IS CORRECT ; SO THAT THE RESULT WILL BE NON-0 ; WHEN THE SIGN BIT IS SET (THIS ; IS V E R Y IMPORTENT!) BCC FULL ; CC= A USED BLOCK ADD #1,R5 ; COUNT A BLOCK FREE ADC R4 ; INC HI ORDER. BR ENDLP ; SEE IF DONE ; FULL: TST R5 ; ANY FREE BLOCKS? BNE FULL1 ; NE=YES TST R4 ; TEST HI ORDER. BEQ ENDLP ; EQ=NOPE FULL1: MOV #BSIZ,-(SP) ; NUMBER OF BINS CLR R3 ; CLEAR BIN POINTER 5$: CMP R4,BINS(R3) ; MORE THAN THIS BIN? BLT 10$ ; LE=NO BNE 7$ ; GT=YES CMP R5,BINS+2(R3) ; MORE THAN THIS BIN? BLOS 10$ ; LOS=NOPE 7$: ADD #4,R3 ; POINT TO NEXT BIN DEC (SP) ; DEC COUNT. BGT 5$ ; AND CHECK NEXT BIN. ; 10$: ADD #2,SP ; POP STACK. ADD R4,TOTAL ; ACCUMULATE TOTAL ADD R5,TOTAL+2 ; ACCUM LOW ORDER ADC TOTAL ; GET CARRY IF ANY. ADD R4,BINSUM(R3) ; ACC TOTAL FOR EACH BIN ADD R5,BINSUM+2(R3) ; ACC LOW ORDER ADC BINSUM(R3) ; AND CARRY. ADD #1,BIN+2(R3) ; INCREMENT BIN # ADC BIN(R3) ; DITTO CLR R4 ; CLEAR COUNTERS CLR R5 ; DITTO ENDLP: TST R1 ; ANY FREE BLOCKS STILL? BNE 1$ ;; NE=YES-END THE LOOP TST R5 ;;NO-BUT ARE OLD FREE BLOCKS COUNTED? BNE FULL1 ;; NE=NO, BETTER GO COUNT THEM TST R4 ;; OLD BLOCKS TO BE COUNTED? BNE FULL1 ;; YES. BR END ;; NONE LEFT IN THIS SET-GET OUT 1$: SOB R2,SHIFT ; CHECK ANOTHER BLOCK ; END: CMP R0,#ALUN ; READ ANOTHER DISK BLOCK? BHIS RECORD ; HIS=YES BR BLOCKS ; NO,LOOK AT ANOTHER 16 BITS ; ERR: CMPB #IE.EOF,IOST ; END OF FILE? BEQ FINISH ; EQ=DONE! ; ; FRGIO: MOV #FRGNAM,R1 MOV #FRGLEN,R2 CALL .PRFCS ;PRINT I/O ERROR CLOSE$ R0 ;CLOSE THE FILE. JMP RESTRT ;AND RESTART THE PROGRAM. ; FINISH: CLR DPB+Q.IOPL+4 DIR$ #TIME ; GET TIME/DATE MOV #BSIZ+1,R3 ; # OF BINS MOV #BIN,R5 ; GET FREQUENCY BUFFER MOV #BINSUM,R4 ; GET SUBTOTALS BUFFER MOV #STRTAB,R1 ; GET STRING POINTERS. MOV (R1)+,DPB+Q.IOPL+0 ; SET BUFFER ADDRESS MOV (R1),DPB+Q.IOPL+2 ; AND BUFFER LENGTH SUB DPB+Q.IOPL,DPB+Q.IOPL+2 ; COMPUTE BUFFER LENGTH DIR$$ #DPB ; DO THE HEADER I/O 10$: MOV (R1)+,DPB+Q.IOPL MOV (R1),DPB+Q.IOPL+2 SUB DPB+Q.IOPL,DPB+Q.IOPL+2 DIR$$ #DPB MOV R1,-(SP) ; SAVE R1 MOV #BUF,R0 ; GET BUFFER ADDRESS MOV R5,R1 ;POINT TO THE NUMBER. ADD #4,R5 ; POINT TO NEXT NUMBER. CLR R2 ; SUPPRESS LEADING ZEROS. CALL $C2DMG ; CONVERT TO DECIMAL MAGNITUDE. MOVB #' ,(R0)+ ; MOVE IN A TAB. MOVB #' ,(R0)+ ; AND A SECOND TAB. MOV R4,R1 ; GET THE NUMBER ADD #4,R4 ; POINT TO NEXT NUMBER. CLR R2 CALL $C2DMG ; CONVERT IT. MOV (SP)+,R1 ; RECOVER R1 MOVB #CR,(R0)+ ; MOVB #LF,(R0)+ ; MOV #BUF,DPB+Q.IOPL ; SUB #BUF,R0 ; MOV R0,DPB+Q.IOPL+2 DIR$$ #DPB ; OUTPUT THE STRING. SOB R3,10$ ; AND LOOP. MOV (R1)+,DPB+Q.IOPL MOV (R1),DPB+Q.IOPL+2 SUB DPB+Q.IOPL,DPB+Q.IOPL+2 ; COMPUTE LENGTH DIR$$ #DPB ; DO THE I/O MOV #TOTAL,R1 ; MOV #BUF,R0 ; CLR R2 ; CALL $C2DMG ; CONVERT MOVB #CR,(R0)+ ; MOVB #LF,(R0)+ MOV #BUF,DPB+Q.IOPL SUB #BUF,R0 ; GET LENGTH MOV R0,DPB+Q.IOPL+2 DIR$$ #DPB ; DO I/O MOV #40,DPB+Q.IOPL+4 ;RESTORE DPB. CLOSE$ #FDB ; CLOSE THE FILE JMP RESTRT ; AND RESTART PGM. $ERROR: MOV (R0)+,DPB+Q.IOPL+2 ; SET UP READ DPB MOV R0,DPB+Q.IOPL ;AND THE ADDRESS OF WRITE. DIR$$ #DPB ;DO THE I/O CLOSE$ #FDB ;CLOSE FILE. TST FATAL ;IS THE ERROR FATAL? BNE 10$ ;YES JMP RESTRT ;NO -- TRY AGAIN. 10$: EXIT$S ; AND LEAVE. ; ; THE FOLLOWING PROGRAM WILL CONVERT A BINARY NUMBER ; INTO DECIMAL. THE NUMBER MUST BE DOUBLE PRECISION. ; ; R0 THE ADDRESS AT WHICH TO PLACE THE DECIMAL RESULT. ; R1 A POINTER TO A 2-WORD BLOCK OF MEMORY WITH THE NUMBER. ; R2 = 0 MEANS SUPPRESS LEADING ZERO'S. ; $C2DMG:: MOV R5,-(SP) ;SAVE REGISTERS. MOV R4,-(SP) ; MOV R3,-(SP) ; MOV R2,-(SP) ;SAVE R2 MOV R1,-(SP) ; MOV R0,R5 ;R5 WILL BE TEMP. R0. MOV 2(R1),R2 ;GET THE LOW ORDER. MOV (R1),R1 ;FIXUP LOW ORDER. CLR R4 ;CLEAR LENGTH OF STRING. 10$: MOV #10.,R0 ;GET DIVISOR. CALL $DDIV ;DIVIDE THE NUMBER. ADD #'0,R0 ;MAKE IT A NUMERIC. MOVB R0,(R5) ;MOVE INTO THE STRING. TST R1 ;IS QUOTIENT NON-0? BNE 20$ ;NO TST R2 ;CHECK LOW ORDER. BEQ 40$ ;YES -- LEAVE. 20$: INC R4 ;GET STRING LENGTH. MOV R4,R3 ;SAVE INTO A TEMP. ADD R3,R5 ;POINT TO END OF BUFFER. 30$: MOVB -1(R5),(R5) ;MOVE IN A BYTE. DEC R5 ;POINT TO PREVIOUS BYTE. SOB R3,30$ ;AND LOOP. BR 10$ ;AND CONVERT ANOTHER BYTE. 40$: ADD R4,R5 ;POINT R5 TO NEXT BYTE. MOV R5,R0 ;RETURN IN R0. INC R0 ;POINT TO ONE PAST LAST BYTE. MOV (SP)+,R1 MOV (SP)+,R2 MOV (SP)+,R3 MOV (SP)+,R4 MOV (SP)+,R5 RTS PC .END FRG