;*************************** AMUS Program Label ******************************
; Filename: BENCH.M68                                       Date: 06/22/90
; Category: UTIL         Hash Code: 015-414-142-352      Version: 1.0(100)
; Initials: ESS/AM       Name: CREED A. ERICKSON
; Company:                                         Telephone #:
; Related Files: NONE
; Min. Op. Sys.:                               Expertise Level: BEG
; Special: Use LNKLIT BENCH after initial assembly
; Description: A "stopwatch" program which keeps track of various system
; resources (CPU time, disk read and writes, elapsed time) which can be
; used to benchmark programs.
;*****************************************************************************
;************************************************************************
;                                                                       *
;        BENCH.M68 - A stopwatch for benchmarking programs.             *
;                                                                       *
;************************************************************************
; Copyright (c) 1990 - Creed A. Erickson.
; All Rights Reserved.
;
; Justification:
;
;       BENCH is a utility which, when incorporated into CMD and DO files,
;       will keep track of system resources spent by a program or process.
;       Resources tracked are:
;
;               CPU time.
;               Connect time (elapsed real-time).
;               Disk reads.
;               Disk writes.
;
; Usage:
;
;       .BENCH keyword
;
;       Supported keywords are:
;
;               START   - Start/reset the stopwatch.
;               ON      - Start/reset the stopwatch.
;               YES     - Start/reset the stopwatch.
;               MARK    - Display elasped time, keep timing.
;               LAP     - Display elasped time, keep timing.
;               STOP    - Display elasped time, shut off stopwatch.
;               OFF     - Display elasped time, shut off stopwatch.
;               NO      - Display elasped time, shut off stopwatch.
;
; Example CMD file:
;
;       :R
;       LOAD SYS:BENCH          ; Load for speed.
;       BENCH ON                ; Start the clock.
;       RUN TEST1               ; Run the first test program.
;       BENCH MARK              ; Mark the elasped time (LAP).
;       RUN TEST2               ; Run the second test program.
;       BENCH OFF               ; Shut off the clock.
;
; Notes:
;
;  o    To save time and remove some variability in the timing, it is
;       highly desirable to load BENCH into user or system memory.
;
;  o    If the process being timed invokes LOGOFF, the "stopwatch" will
;       be lost.
;
; Edit History (most recent first):
;
;[100] 06/13/90 Designed and implemented by Creed A. Erickson.
;

       SEARCH  SYS                     ; Standard stuff.
       SEARCH  SYSSYM                  ;    "       "

       EXTERN  $OTCPU, $OTCON          ; External routines.

       VMAJOR  =       1.              ; Version.
       VMINOR  =       0.              ; Minor version.
       VSUB    =       0.              ; Sub-version.
       VEDIT   =       100.            ; Edit level.

       $SPACE  =       32.             ; Define a constant.

; Define impure area.
;
OFINI
OFDEF   JB.CPU, 4                       ; Saved CPU time.
OFDEF   JB.CON, 4                       ; Saved connect time.
OFDEF   JB.DSR, 4                       ; Saved disk reads.
OFDEF   JB.DSW, 4                       ; Saved disk writes.
OFDEF   LP.CPU, 4                       ; Lap CPU time.
OFDEF   LP.CON, 4                       ; Lap connect time (not used).
OFDEF   LP.DSR, 4                       ; Lap disk reads.
OFDEF   LP.DSW, 4                       ; Lap disk writes.
OFSIZ   S..IMP


BENCH:  PHDR    -1,0,PH$REE!PH$REU      ; Is reentrant & reusable.

       CALL    CMD                     ; Get command.
       BEQ     10$                     ;  Got a good command.
       TYPECR  <?Command format error.>;  Had a command error.
       BR      XSIT                    ;   All done.

; Command code is in D1:
;
;       0       =       Start
;       1       =       Lap
;       2       =       Stop
;
10$:    CALL    IMPGET                  ; Get or index impure.
       JOBIDX  A6                      ; Get job index.
       LEA     A0, JOBCPU(A6)          ;  Index stuff to save.
       LEA     A6, ACTTBL              ; Index the action table.
       LSLW    D1, #1                  ;  Multiply by 2 for word indexing.
       ADDW    D1, A6                  ;  Add offset into table.
       ADDW    @A6, A6                 ;  Add in offset from table.
       JMP     @A6                     ;   Go do it.

ACTTBL: OFFSET  START
       OFFSET  LAP
       OFFSET  STOP

;**********
;  START  *
;**********
; Start the stopwatch.
;
START:  LEA     A1, JB.CPU(A5)          ; Index the saved block.
       MOV     (A0)+, (A1)+            ; Move CPU time.
       MOV     (A0)+, (A1)+            ; Bypass connect time.
       MOV     (A0)+, (A1)+            ; Move disk reads.
       MOV     (A0)+, (A1)+            ; Move disk writes.
       GTIMEI  JB.CON(A5)              ; Set connect time.
       GDATEI  D1                      ; Get today.
       SUB     #2444240., D1           ; Convert to days since 1/1/80
       SWAP    D1                      ; Put in high order.
       LSL     D1                      ;  Shift up a bit.
       OR      D1, JB.CON(A5)          ;  Store.
       BR      XSIT                    ; All done.

;*********
;  STOP  *
;*********
; Stop the stopwatch.
;
STOP:   LEA     A1, LP.CPU(A5)          ; Index lap block.
       MOV     (A0)+, (A1)+            ; Move CPU time.
       MOV     (A0)+, (A1)+            ; Move connect time.
       MOV     (A0)+, (A1)+            ; Move disk reads.
       MOV     (A0)+, (A1)+            ; Move disk writes.
       CALL    REPORT                  ; Report the statistics.
       MOVW    #0, -10(A5)             ; Zap the module flags.
       BR      XSIT                    ; All done.

;********
;  LAP  *
;********
; Display elapsed time so far.
;
LAP:    LEA     A1, LP.CPU(A5)          ; Index lap block.
       MOV     (A0)+, (A1)+            ; Move CPU time.
       MOV     (A0)+, (A1)+            ; Move connect time.
       MOV     (A0)+, (A1)+            ; Move disk reads.
       MOV     (A0)+, (A1)+            ; Move disk writes.
       BCALL   REPORT                  ; Report the statistics.

XSIT:   EXIT

;***********
;  REPORT  *
;***********
; Report statistics.
;
; Passed:
;
;       A5      := The BENMRK.%%% inpure module.
;
; Returns:
;
;       Nothing.
;
; Side effects:
;
;       Destroys A2, D1
;
; Notes:
;
;       Some code shamelessly liberated from LOG.M68 and LOGOFF.M68
;
REPORT:

; Display Disk reads and writes.
;
       MOV     LP.DSR(A5), D1          ; Get count of disk reads.
       SUB     JB.DSR(A5), D1          ;  Subtract starting count.
       DCVT    0, OT$TRM               ; Output to terminal.
       TYPESP  < reads,>               ;  Say what the number is about.
       MOV     LP.DSW(A5), D1          ; Get count of disk writes.
       SUB     JB.DSW(A5), D1          ;  Less starting count.
       DCVT    0, OT$TRM               ; Output to the terminal.
       TYPE    < writes. >             ;  Say what the number is.

; Display CPU time.
;
       TYPESP  < CPU time: >
       MOV     LP.CPU(A5), D1          ; Get amount of CPU time used.
       SUB     JB.CPU(A5), D1          ;  Less starting count.
       SUB     A2, A2                  ; display on terminal
       CALL    $OTCPU                  ; display CPU time

; Display connect (or elapsed) time.
;
       TYPESP  <, Elapsed time:>
       MOV     JB.CON(A5), D1          ; Get user's connect time.
       SUB     A2,A2                   ; display on terminal
       CALL    $OTCON                  ; display connect time
       CRLF
       RTN

;***********
;  IMPGET  *
;***********
; Index or allocate the impure area.
;
; Passed:
;
;       Nothing.
;
; Returned:
;
;       A5      => Inpure area.
;
; Side effects:
;
;       Destroys A1.
;
IMPGET:
       LEA     A1, MODNAM              ; Index the module name.
       SRCH    @A1, A5, F.USR          ; Find the module.
       BEQ     99$                     ;  Found, all done.

; Module not found, make a new one.
; Use stack for temporary MCB.
;
       PUSH    #S..IMP                 ; Size to allocate.
       PUSH                            ; Room for index.
       GETMEM  @SP                     ; Allocate the module.
       BEQ     10$                     ;  OK, proceed.
       TYPECR  <?Insufficient memory.> ;  Failed, report error.
       JMP     XSIT                    ;   And bomb out.

10$:    POP     A5                      ; Get the index.
       POP                             ; Clean up stack.

; Name the module.  Remember, A1 is still pointed at the name block.
;
       MOV     (A1)+, -6(A5)           ; Move in a module name.
       MOVW    @A1, -2(A5)             ; Move in a module extension.

; Flag the module as permanent.
;
       MOVW    #<FIL!LOK>, -10(A5)     ; Lock as memory file.

99$:    RTN                             ; Return to caller.

MODNAM: WORD    [BEN], [MRK], [%%%]     ; Name is BENMRK.%%%

;********
;  CMD  *
;********
; Parse command line for proper command word.
;
; Passed:
;
;       A2      => Standard AMOS command line pointer.
;
; Returned:
;
;       D1      := Command value:
;
;                       0 = Start
;                       1 = Lap
;                       2 = Stop
;       Z-bit   Set if valid command word encountered, reset otherwise.
;
; Side effects:
;
;       Destroys A2, A1, D1.
;
; Credits:
;
;       This routine was inspired by a similar, bu more extensive
;       routine by Brett R. Halle.
;
CMD:    BYP                             ; Bypass white space.
       LIN                             ; End of line?
       BNE     05$                     ;  No, scan the line.
       LCC     #0                      ;  Yes, flag bad line.
       BR      99$                     ;   All done.
05$:    LEA     A1, KEYWORD             ; Index the keyword table.
       MOV     A2, A0                  ; Save A2 command line index.
       BR      20$

; Come to here to skip over a keyword entry.
;
10$:    TSTB    (A1)+                   ; End of string?
       BNE     10$                     ;  No, loop for more.
       TSTB    (A1)+                   ;  Yes, skip value.
       MOV     A0, A2                  ; Restore command line index.
       TSTB    @A1                     ; End of table?
       BNE     20$                     ;  No.
       LCC     #0                      ;  Yes, flag failure.
       BR      99$                     ;    And exit this routine.

20$:    LIN                             ; End of line?
       BEQ     30$                     ;  Yes.
       CMPB    @A2, #$SPACE            ; End of word?
       BLE     30$                     ;  Yes.
       MOVB    (A1)+, D1               ;  No, get next keyword byte.
       BEQ     10$                     ;   End of keyword, didn't match.
       CMPB    D1, (A2)+               ;   Compare to command line.
       BEQ     20$                     ;    Matched, compare next.
       BR      10$                     ;    Didn't match, next keyword.

; Come to here if command line terminated.  Test for end of keyword also.
;
30$:    TSTB    (A1)+                   ; End of keyword?
       BNE     10$                     ;  Nope, try the next keyword.
       CLR     D1                      ;  Yep, preclear D1.
       MOVB    @A1, D1                 ;   Get the keyword value.
       LCC     #PS.Z                   ;   Flag success.

99$:    MOV     A0, A2                  ; Restore command line pointer.
       RTN                             ; Return to caller.

;*********************
;  Keyword table...  *
;*********************
; Table of valid keywords and their values.
;
DEFINE  KWD     WRD, VAL
       ASCIZ   "WRD"
       BYTE    VAL
ENDM
KEYWORD:
       KWD     <ON>, 0                 ; Start the clock.
       KWD     <START>, 0              ; Start the clock.
       KWD     <YES>, 0                ; Start the clock.
       KWD     <LAP>, 1                ; Report a "Lap" time.
       KWD     <MARK>, 1               ; Report a "Lap" time.
       KWD     <OFF>, 2                ; Stop the clock.
       KWD     <STOP>, 2               ; Stop the clock.
       KWD     <NO>, 2                 ; Stop the clock.
       BYTE    0                       ; End of table.
       EVEN                            ; Force to even address.

       END