From:	CSBVAX::MRGATE!info-vax-RELAY@KL.SRI.COM@SMTP 19-JUN-1988 08:20
To:	ARISIA::EVERHART
Subj:	load average driver for VMS v4.x


Received: from VMSA.CF.UCI.EDU by KL.SRI.COM with TCP; Wed, 15 Jun 88 07:24:20 PDT
Return-path: iglesias@orion.cf.uci.edu
Received: from orion.cf.uci.edu by VMSA.CF.UCI.EDU via TCP; Wed Jun 15 07:20 PDT
Received: from localhost by orion.cf.uci.edu id a012469; 15 Jun 88 7:21 PDT
Date: Wed, 15 Jun 88 07:21:26 -0700
From: Mike Iglesias <iglesias@orion.cf.uci.edu>
Subject: load average driver for VMS v4.x
To: info-vax%kl.sri.com@orion.cf.uci.edu

Here's a load average driver for VMS v4.x.  


Mike Iglesias
University of California, Irvine



........................ Cut between dotted lines and save ......................
$!..............................................................................
$! VAX/VMS archive file created by VMS_SHAR V-4.03 05-Aug-1987
$! which was written by Michael Bednarek (U3369429@ucsvc.dn.mu.oz.au)
$! To unpack, simply save and execute (@) this file.
$!
$! This archive was created by MIGLESIAS
$!      on Friday 10-JUN-1988 10:27:14.18
$!
$! It contains the following 3 files:
$! BUILDLAV.COM LAVDRIVER.MAR LAVDRIVER.OPT
$!=============================================================================
$ Set Symbol/Scope=(NoLocal,NoGlobal)
$ Version=F$GetSYI("VERSION") ! See what VMS version we have here:
$ If Version.ges."V4.4" then goto Version_OK
$ Write SYS$Output "Sorry, you are running VMS ",Version, -
                ", but this procedure requires V4.4 or higher."
$ Exit 44
$Version_OK: CR[0,8]=13
$ Pass_or_Failed="failed!,passed."
$ Goto Start
$Convert_File:
$ Read/Time_Out=0/Error=No_Error1/Prompt="creating ''File_is'" SYS$Command ddd
$No_Error1: Define/User_Mode SYS$Output NL:
$ Edit/TPU/NoSection/NoDisplay/Command=SYS$Input/Output='File_is' -
        VMS_SHAR_DUMMY.DUMMY
f:=Get_Info(Command_Line,"File_Name");b:=Create_Buffer("",f);
o:=Get_Info(Command_Line,"Output_File");Set (Output_File,b,o);
Position (Beginning_of(b));Loop x:=Erase_Character(1); Loop ExitIf x<>"V";
Move_Vertical(1);x:=Erase_Character(1);Append_Line;Move_Horizontal
(-Current_Offset);EndLoop;Move_Vertical(1);ExitIf Mark(None)=End_of(b)
EndLoop;Exit;
$ Delete VMS_SHAR_DUMMY.DUMMY;*
$ Checksum 'File_is
$ Success=F$Element(Check_Sum_is.eq.CHECKSUM$CHECKSUM,",",Pass_or_Failed)+CR
$ Read/Time_Out=0/Error=No_Error2/Prompt=" CHECKSUM ''Success'" SYS$Command dd

$No_Error2: Return
$Start:
$ File_is="BUILDLAV.COM"
$ Check_Sum_is=1214797239
$ Copy SYS$Input VMS_SHAR_DUMMY.DUMMY
X$ MACRO  LAVDRIVER
X$ link/map/full/notrace lavdriver+lavdriver/option+sys$system:sys.stb/select
$ GoSub Convert_File
$ File_is="LAVDRIVER.MAR"
$ Check_Sum_is=1160355418
$ Copy SYS$Input VMS_SHAR_DUMMY.DUMMY
X    .TITLE    LAVDRIVER    VAX/VMS Load Average Pseudo Device
X    .IDENT    /Version 1.00/
X    .SBTTL    DOCUMENTATION
X;---------------S-R-I-International-Artificial-Intelligence-Center-----------
X;
X;
X; MODULE NAME:
X;
X;    LAVDRIVER
X;
X; PURPOSE:
X;
X;    This is a pseudo device which supplies load average information to
X;    programs wishing to display some indication of system load.
X;
X; MEDIA:
X;
X;    USR:[KASHTAN.DRIVERS]LAVDRIVER.MAR
X;
X; KEYWORDS:
X;
X;    Drivers
X;
X; USAGE:
X;
X;    Standard system QIO calls.
X;
X;    The driver is installed via sysgen.  The following is the correct
X;        sysgen command sequence.
X;
X;        SYSGEN>  LOAD LAVDRIVER
X;        SYSGEN>  CONNECT LAV0 /NOADA/DRIVER=LAVDRIVER
X;
X;        Note: LAVDRIVER.EXE should reside in [SYSEXE]
X;
X;
X; SPECIAL REQUIREMENTS:
X;
X;    none
X;
X; LANGUAGE:
X;
X;       VAX-11 MACRO
X;
X; PARAMETERS:
X;
X;    none
X;
X; SPECIAL TECHNIQUES:
X;
X;    none
X;
X; AUTHOR:
X;
X;    David Kashtan
X;
X; DATE CREATED:
X;
X;    Wed Jul 21 11:25:19 1982
X;
X; MAINTAINED BY:
X;
X;    David Kashtan
X;
X; UPDATES:
X;
X;    none
X;
X;---------------S-R-I-International-Artificial-Intelligence-Center-----------
X
X    .SBTTL    DEFINITIONS
X    .LIBRARY    /SYS$LIBRARY:LIB.MLB/
X;+ ---
X;
X; DEFINE CONTROL BLOCK OFFSETS & OTHER SYSTEM STUFF BY CALLING 'DEF' MACROS
X;
X;- ---
X    $CRBDEF            ;DEFINE CHANNEL REQUEST BLOCK
X    $DDBDEF            ;DEFINE DEVICE DATA BLOCK
X    $DEVDEF            ;DEFINE DEVICE CONSTANTS
X    $DPTDEF            ;DEFINE DRIVER PROLOGUE TABLE
X    $DYNDEF            ;DEFINE DYNAMIC STRUCTURE CODES
X    $IODEF            ;DEFINE I/O FUNCTION CODES
X    $IRPDEF            ;DEFINE I/O REQUEST PACKET
X    $TQEDEF            ;DEFINE TIMER QUEUE ENTRY
X    $UCBDEF            ;DEFINE UNIT CONTROL BLOCK
X    $VECDEF            ;DEFINE VECTOR OFFSETS
X;
X
X    .SBTTL    DRIVER PROLOGUE TABLE
X;+ ---
X;
X; DRIVER CHARACTERISTICS
X;
X;- ---
X    DPTAB           -
X            END=LAV_END,           -;END OF DRIVER (SIZE)
X            ADAPTER=NULL,           -;UNIBUS DEVICE
X            UCBSIZE=UCB$C_Length,  -;UNIT CONTROL BLOCK LENGTH
X            FLAGS = DPT$M_NOUNLOAD,-;DO NOT UNLOAD THE DRIVER,EVER
X            NAME=LAVDRIVER        ;DRIVER NAME
X;+ ---
X;
X; INITIALIZATION INFORMATION
X;
X;- ---
X    DPT_STORE    INIT
X    DPT_STORE    UCB,UCB$B_FIPL,B,8    ;FORK IPL LEVEL (UBA #1 = 8)
X    DPT_STORE    UCB,UCB$B_DIPL,B,21    ;DEVICE IPL LEVEL (BR5 = 21)
X    DPT_STORE    UCB,UCB$L_DEVCHAR,L,   -;DEVICE CHARACTERISTICS:
X               <-
X            DEV$M_AVL!           -;   DEVICE AVAILABLE
X            DEV$M_REC!           -;   RECORD ORIENTED
X            DEV$M_IDV!           -;   INPUT DEVICE
X            DEV$M_SHR           -;   SHARED
X               >
X    DPT_STORE    UCB,UCB$W_DEVBUFSIZ,   -;DEVICE BUFFER SIZE
X                W,12        ;    (12 bytes)
X;+ ---
X;
X; RE-INITIALIZATION INFORMATION
X;
X;- ---
X    DPT_STORE    REINIT
X    DPT_STORE    DDB,DDB$L_DDT,D,LAV$DDT    ;DRIVER DISPATCH TABLE
X    DPT_STORE    CRB,               -;UNIT INITIALIZATION ROUTINE
X             CRB$L_INTD+VEC$L_UNITINIT,D,-
X                LAV_INIT
X    DPT_STORE    END
X;
X
X    .SBTTL    DRIVER DISPATCH TABLE
X;+ ---
X;
X; ADDRESSES OF VARIOUS DRIVER ENTRY POINTS
X;
X;- ---
X    DDTAB    -
X         DEVNAM=LAV,           -;DEVICE NAME
X         START=0,           -;ADDRESS OF START I/O ENTRY POINT
X         UNSOLIC=0,           -;ADDRESS OF UNSOLICITED INT. ROUTINE
X         FUNCTB=LAV_FUNCTABLE, -;ADDRESS OF FUNCTION DECISION TABLE
X         CANCEL=0,           -;ADDRESS OF CANCEL I/O ENTRY POINT
X         REGDMP=0,           -;ADDRESS OF REGISTER DUMP ROUTINE
X         DIAGBF=0,           -;SIZE OF DIAGNOSTIC BUFFER
X         ERLGBF=0        ;SIZE OF ERROR LOG BUFFER
X;
X
X    .SBTTL    FUNCTION DECISION TABLE
XLAV_FUNCTABLE:
X;+ ---
X;
X; SPECIFY LEGAL FUNCTION CODES
X;
X;- ---
X    FUNCTAB    ,           -;LEGAL FUNCTION CODE ENTRY
X        <           -;
X         READVBLK,     -;READ VIRTUAL BLOCK
X         READLBLK,     -;READ LOGICAL BLOCK
X         READPBLK,     -;READ PHYSICAL BLOCK
X        >
X;+ ---
X;
X; SPECIFY BUFFERED I/O FUNCTION CODES
X;
X;- ---
X    FUNCTAB    ,           -;BUFFERED FUNCTION CODE ENTRY
X        <>        ;NONE
X;+ ---
X;
X; SPECIFY 1ST AND ONLY FDT ROUTINE
X;
X;- ---
X    FUNCTAB    GET_LOAD_AVE,  -;GET THE CURRENT LOAD AVERAGES
X        <           -;USED BY:
X         READVBLK,     -;READ VIRTUAL BLOCK
X         READLBLK,     -;READ LOGICAL BLOCK
X         READPBLK      -;READ PHYSICAL BLOCK
X        >        ;
X;
X
X    .SBTTL    READ FDT ROUTINE
X;+ ---
X;
X; GET_LOAD_AVE        READ FDT ROUTINE
X;
X; FUNCTIONAL DESCRIPTION:
X;
X;    All this routine does is verify the read arguments and return M1->M15
X;
X; INPUTS:
X;
X;    R3 = I/O Packet address
X;    R4 = Current Process Control Block address
X;    R5 = Unit Control Block Address
X;    R6 = Channel Control Block Address
X;    R7 = Function Code
X;    R8 = Scratch
X;    R9 = Scratch
X;
X;    0(AP) --> Read Size
X;    4(AP) --> Read Buffer
X;
X; OUTPUTS:
X;
X;    none
X;
X;- ---
XGET_LOAD_AVE:
X     
X;+ ---
X; Get Read Size (limited to 12 bytes)
X;- ---
X    MOVZWL    4(AP),R0                ;Get Read Size
X    CMPL    R0,#12                ;Bigger than 12??
X    BLEQU    10$                ;No:
X    MOVL    #12,R0                ;Yes: Truncate to 12 bytes
X10$:
X;+ ---
X; Make sure that the buffer is writeable
X;- ---
X    IFNOWRT    R0,@(AP),ACCVIO            ;Return SS$_ACCVIO if no write
X;+ ---
X; Move the data
X;- ---
X    PUSHR    #^M<R0,R1,R2,R3,R4,R5>        ;Be conservative!!!
X    MOVC3    R0,M1,@(AP)            ;Move the Data
X    POPR    #^M<R0,R1,R2,R3,R4,R5>        ;Restore registers
X;+ ---
X; Complete the I/O request
X;- ---
X    ASHL    #16,R0,R0            ;Set transfer size
X    BISW2    #SS$_NORMAL,R0            ;Set Completion code
X    JMP    G^EXE$FINISHIOC            ;Complete the request
X     
X     
X;+ ---
X; Return and access violation
X;- ---
XACCVIO:
X    MOVZWL    #SS$_ACCVIO,R0            ;Set return code
X    CLRL    R1
X    JMP    G^EXE$ABORTIO            ;Abort the I/O request
X     
X
X    .SBTTL    UNIT INITIALIZATION ROUTINE
X;+ ---
X;
X; ROUTINE CALLED WHEN THE LOADING PROCEDURE SETS UP THE UNIT.
X;  THE DEVICE ONLINE BIT IS SET IN THE UCB.
X;
X; INPUT REGISTERS:
X;    R0 = SCRATCH
X;    R5 = ADDRESS OF UNIT CONTROL BLOCK
X;
X; REGISTERS MODIFIED:
X;    R0 = SCRATCH
X;
X; SIDE EFFECTS:
X;    UNIT ONLINE BIT IS SET IN UCB
X;    LOAD AVERAGE WATCHER IS SET UP
X;
X;- ---
XLAV_INIT:
X    BISW    #UCB$M_ONLINE,UCB$W_STS(R5)    ;SET STATUS = ONLINE
X     
X; SET LOAD AVES TO ZERO
X     
X    CLRF    M1
X    CLRF    M5
X    CLRF    M15
X     
X; SET UP THE LOAD AVERAGE WATCHING CODE (INSERT THE TIMER QUEUE ENTRY)
X     
X    MOVAB    UPDATE_LOAD_AVERAGE,TQE_PC
X    MOVQ    @#EXE$GQ_SYSTIME,TQE_DUE
X    INSQUE    TQE,@#EXE$GL_TQFL
X     
X    RSB                    ;AND RETURN
X;
X
X    .SBTTL    LOCAL DATA
X;+ ---
X; Local Data for the Load Average Watcher
X;- ---
XM1:    .FLOAT    0.0                ;1  Min. Load Ave.
XM5:    .FLOAT    0.0                ;5  Min. Load Ave.
XM15:    .FLOAT    0.0                ;15 Min. Load Ave.
X     
XF1:    .FLOAT    0.9200444146293232        ;1 min. load ave. constants
XF11:    .FLOAT    0.0799555853706768
X     
XF2:    .FLOAT    0.9834714538216175        ;5 min. load ave. constants
XF12:    .FLOAT    0.0165285461783825
X     
XF3:    .FLOAT    0.9944598480048968        ;15 min. load ave. constants
XF13:    .FLOAT    0.0055401519951032
X     
X     
XTQE:    .LONG    0                ;TIMER QUEUE ELEMENT (FLINK)
X    .LONG    0                ;(BLINK)
X    .WORD    0                ;SIZE
X    .BYTE    DYN$C_TQE            ;TYPE
X    .BYTE    TQE$C_SSREPT            ;REQUEST == REPEAT
XTQE_PC:    .LONG    0                ;PC TO CALL
X    .LONG    0                ;N/A
X    .LONG    0                ;N/A
XTQE_DUE:.LONG    0                ;DUE TIME
X    .LONG    0
X    .LONG    100000*100*5            ;Repeat time (5 Sec.)
X    .LONG    0
X     
X
X    .SBTTL    Load Average Watching Code
X     
XUPDATE_LOAD_AVERAGE:                ;We link into the
X                        ;VMS kernel via the timer q
X                        ;and is entered by JSB when
X                        ;each 5 sec. interval ends.
X                        ;R0-R4 are available
X     
X    CLRL    R2                ;Initialize the run count=0
X;+ ---
X; Check the run queues for the number of processes in 'COM' state
X;- ---
X    CLRL    R1                ;Initialize summary word pos=0
X     
XFind_Comq:                    ;Find a run queue with entries
X    SUBL3    R1,#32,R0            ;Calculate #bits left (32-R1)
X    FFS    R1,R0,@#SCH$GL_Comqs,R1        ;Look for an active queue
X    BEQL    Ncomo                ;None: look for procs waiting
X                        ;    for inswap
X    MOVAQ    @#SCH$AQ_Comh[R1],R0        ;Got one: get its queue header
X    MOVL    R0,R3                ;Save terminating address
X     
X10$:    MOVL    (R0),R0                ;Get the next process in the q
X    CMPL    R0,R3                ;End of queue?
X    BEQL    20$                ;Yes: look for next queue
X    INCL    R2                ;No: count this process
X    BRB    10$                ;and try the next one
X     
X20$:    INCL    R1                ;Queue done, look for next one
X    BRB    Find_Comq
X     
X;+ ---
X; Check the COMO queues for the number of processes in 'COM' state (outswap)
X;- ---
XNcomo:    CLRL    R1                ;Initialize summary word pos=0
X     
XFind_Comoq:                    ;Find a run queue with entries
X    SUBL3    R1,#32,R0            ;Calculate #bits left (32-R1)
X    FFS    R1,R0,@#SCH$GL_Comoqs,R1    ;Look for an active queue
X    BEQL    Nwait                ;None: look for procs waiting
X                        ;    for resources
X    MOVAQ    @#SCH$AQ_Comoh[R1],R0        ;Got one: get its queue header
X    MOVL    R0,R3                ;Save terminating address
X     
X10$:    MOVL    (R0),R0                ;Get the next process in the q
X    CMPL    R0,R3                ;End of queue?
X    BEQL    20$                ;Yes: look for next queue
X    INCL    R2                ;No: count this process
X    BRB    10$                ;and try the next one
X     
X20$:    INCL    R1                ;Queue done, look for next one
X    BRB    Find_Comoq
X     
X;+ ---
X; Count processes in collided page wait
X;- ---
XNwait:
X    MOVAQ    @#SCH$GQ_Colpgwq,R0        ;Get the collided page wait q
X     
X10$:    MOVL    (R0),R0                ;Get the next process in the q
X    CMPL    R0,#SCH$GQ_Colpgwq        ;End of queue?
X    BEQL    Npfw                ;Yes: look at page fault waits
X    INCL    R2                ;No: count this process
X    BRB    10$                ;and try the next one
X     
X;+ ---
X; Count processes in page fault wait
X;- ---
XNpfw:
X    MOVAQ    @#SCH$GQ_PfwQ,R0        ;Get the page fault wait q
X     
X10$:    MOVL    (R0),R0                ;Get the next process in the q
X    CMPL    R0,#SCH$GQ_Pfwq            ;End of queue?
X    BEQL    Nfpw                ;Yes: look at free page waits
X    INCL    R2                ;No: count this process
X    BRB    10$                ;and try the next one
X     
X;+ ---
X; Count processes in free page wait
X;- ---
XNfpw:
X    MOVAQ    @#SCH$GQ_FpgwQ,R0        ;Get the free page wait q
X     
X10$:    MOVL    (R0),R0                ;Get the next process in the q
X    CMPL    R0,#SCH$GQ_Fpgwq        ;End of queue?
X    BEQL    Count_Done            ;Yes: all done
X    INCL    R2                ;No: count this process
X    BRB    10$                ;and try the next one
X     
X;+ ---
X; Count done, calculate the load ave.
X;- ---
XCount_Done:
X    CVTLF    R2,R2                ;Float the count
X; 1 min. load ave.
X    MULF3    R2,F11,R0            ;La=OldLa*F+NewLa*(1-F)
X    MULF3    M1,F1,R1
X    ADDF3    R0,R1,M1
X; 5 min. load ave.
X    MULF3    R2,F12,R0
X    MULF3    M5,F2,R1
X    ADDF3    R0,R1,M5
X; 15 min. load ave.
X    MULF3    R2,F13,R0
X    MULF3    M15,F3,R1
X    ADDF3    R0,R1,M15
X    RSB                    ;Return to clock dispatcher
X     
X     
X
X    .SBTTL    END OF DRIVER
X;+ ---
X;
X; END OF DRIVER
X;
X;- ---
XLAV_END:                    ;LET DPTAB KNOW THE DRIVER SIZE
X;
X    .END
$ GoSub Convert_File
$ File_is="LAVDRIVER.OPT"
$ Check_Sum_is=1163084207
$ Copy SYS$Input VMS_SHAR_DUMMY.DUMMY
XBASE=0
$ GoSub Convert_File
$ Exit
