!=====================================================================+ ! DYNPRI - Dynamically change interactive process base priorities | !=====================================================================+ ! Author: Harry Flowers ! ! Logicals for this program: ! ! DYNPRI_MINPRI Minimum priority that DYNPRI will use or ! Default: 1 alter; processes below this point will not ! (pri=0 ignored) be changed, and CPU-bound processes will ! be lowered to this level. Checked only ! at program start. ! ! DYNPRI_MAXPRI Maximum priority that DYNPRI will alter; ! Default: 4 processes above this point will not be ! (pri>4 ignored) changed, but this is not used as the cap ! for raising priorities; AUTHPRI is. Checked ! only at program start. ! ! DYNPRI_STOP Causes the program to stop cleanly; restores ! all interactive processes to their authorized ! base priorities before exiting. Checked every ! thirty (30) seconds. ! !====================================================================== OPTION TYPE = EXPLICIT MARGIN 80% ! ! Set up system services EXTERNAL LONG FUNCTION SYS$GETSYIW, & SYS$PROCESS_SCAN, & SYS$GETJPIW, & SYS$GETTIM, & SYS$SETPRI, & SYS$TRNLNM, & LIB$STOP, & LIB$SUB_TIMES, & LIB$CVTF_FROM_INTERNAL_TIME, & LIB$DELETE_LOGICAL ! %INCLUDE "$SSDEF" %FROM %LIBRARY "SYS$LIBRARY:BASIC$STARLET.TLB" %INCLUDE "$LNMDEF" %FROM %LIBRARY "SYS$LIBRARY:BASIC$STARLET.TLB" %INCLUDE "$JPIDEF" %FROM %LIBRARY "SYS$LIBRARY:BASIC$STARLET.TLB" %INCLUDE "$SYIDEF" %FROM %LIBRARY "SYS$LIBRARY:BASIC$STARLET.TLB" %INCLUDE "$PSCANDEF" %FROM %LIBRARY "SYS$LIBRARY:BASIC$STARLET.TLB" %INCLUDE "$LIBDTDEF" %FROM %LIBRARY "SYS$LIBRARY:BASIC$STARLET.TLB" ! ! ! Use $GETSYI to get MAXPROCESSCNT and dimension array PROC to that ! size by the number of data cells for each process. ! ! PROC_INDEX Index ! PID PID ! CPUTIM CPU time ! AUTHPRI Authorized base priority ! PRIB Current base priority ! ! Declare constants for PROC array indices DECLARE BYTE CONSTANT PID = 0% ! PID DECLARE BYTE CONSTANT CPU = 1% ! CPU time ! ! DECLARE LONG MINPRI, & MAXPRI, & MAXCPU, & MINCPU MAP(FIXED_STRINGS) & STRING MINPRIS = 2%, & MAXPRIS = 2% ! ! Use $PROCESS_SCAN to select interactive processes and $GETJPI to get ! the process information. ! DECLARE LONG JPI_PROC_INDEX, & JPI_PID, & JPI_CPUTIM, & JPI_AUTHPRI, & JPI_PRIB, & JPI_STATE DECLARE BYTE CONSTANT JPI_ITEMS = 7% ! RECORD ITMLST GROUP ITEM(JPI_ITEMS) VARIANT CASE WORD BUFFER_LEN WORD ITEM_CODE LONG BUFFER_ADDR LONG LENGTH_ADDR CASE LONG TERMINATOR END VARIANT END GROUP END RECORD ! DECLARE ITMLST ITEM_LIST DECLARE ITMLST PSCAN_ITEM_LIST DECLARE ITMLST JPI_ITEM_LIST DECLARE WORD RETLEN(JPI_ITEMS) DECLARE LONG IOSB(1%), & CURTIM(1%), & OLDTIM(1%), & DELTIM(1%), & CPUDELTA(1%) & ! DECLARE LONG CONTEXT, & STOPPING, & JPICONTROL, & OPERATION, & CHANGE_PRI, & CPU_BOUND DECLARE SINGLE CPU_SECS, & CLOCK_SECS, & PERCENT DECLARE LONG STAT, MAXIDX, NUM_CPUS, IDX ! !===================================================================== ! ITEM_LIST::ITEM(0%)::BUFFER_LEN = 4% ITEM_LIST::ITEM(0%)::ITEM_CODE = SYI$_MAXPROCESSCNT ITEM_LIST::ITEM(0%)::BUFFER_ADDR = LOC(MAXIDX) ITEM_LIST::ITEM(0%)::LENGTH_ADDR = LOC(RETLEN(0%)) ITEM_LIST::ITEM(1%)::BUFFER_LEN = 4% ITEM_LIST::ITEM(1%)::ITEM_CODE = SYI$_ACTIVECPU_CNT ITEM_LIST::ITEM(1%)::BUFFER_ADDR = LOC(NUM_CPUS) ITEM_LIST::ITEM(1%)::LENGTH_ADDR = LOC(RETLEN(1%)) ITEM_LIST::ITEM(2%)::TERMINATOR = 0% ! STAT = SYS$GETSYIW(,,,ITEM_LIST BY REF, IOSB(0%) BY REF,,) CALL LIB$STOP(STAT BY VALUE) IF (STAT AND 1%) = 0% CALL LIB$STOP(IOSB(0%) BY VALUE) IF (IOSB(0%) AND 1%) = 0% ! DIMENSION LONG PROC(MAXIDX,1%) ! ! Get the current time STAT = SYS$GETTIM(OLDTIM(0%) BY REF) CALL LIB$STOP(STAT BY VALUE) IF (STAT AND 1%) = 0% ! JPICONTROL = JPI$M_NO_TARGET_INSWAP OPERATION = LIB$K_DELTA_SECONDS_F ! MAXPRIS = " " ITEM_LIST::ITEM(0%)::BUFFER_LEN = 2% ITEM_LIST::ITEM(0%)::ITEM_CODE = LNM$_STRING ITEM_LIST::ITEM(0%)::BUFFER_ADDR = LOC(MAXPRIS) ITEM_LIST::ITEM(0%)::LENGTH_ADDR = LOC(RETLEN(0%)) ITEM_LIST::ITEM(1%)::TERMINATOR = 0% STAT = SYS$TRNLNM(,"LNM$SYSTEM_TABLE","DYNPRI_MAXPRI",,ITEM_LIST) IF STAT = SS$_NOLOGNAM THEN MAXPRI = 4% ELSE CALL LIB$STOP(STAT BY VALUE) IF (STAT AND 1%) = 0% MAXPRI = INTEGER(MAXPRIS) END IF MINPRIS = " " ITEM_LIST::ITEM(0%)::BUFFER_LEN = 2% ITEM_LIST::ITEM(0%)::ITEM_CODE = LNM$_STRING ITEM_LIST::ITEM(0%)::BUFFER_ADDR = LOC(MINPRIS) ITEM_LIST::ITEM(0%)::LENGTH_ADDR = LOC(RETLEN(0%)) ITEM_LIST::ITEM(1%)::TERMINATOR = 0% STAT = SYS$TRNLNM(,"LNM$SYSTEM_TABLE","DYNPRI_MINPRI",,ITEM_LIST) IF STAT = SS$_NOLOGNAM THEN MINPRI = 1% ELSE CALL LIB$STOP(STAT BY VALUE) IF (STAT AND 1%) = 0% MINPRI = INTEGER(MINPRIS) END IF ! ! Set up PROCESS_SCAN PSCAN_ITEM_LIST::ITEM(0%)::BUFFER_LEN = 0% PSCAN_ITEM_LIST::ITEM(0%)::ITEM_CODE = PSCAN$_MODE PSCAN_ITEM_LIST::ITEM(0%)::BUFFER_ADDR = JPI$K_INTERACTIVE PSCAN_ITEM_LIST::ITEM(0%)::LENGTH_ADDR = PSCAN$M_EQL ! PSCAN_ITEM_LIST::ITEM(1%)::BUFFER_LEN = 0% PSCAN_ITEM_LIST::ITEM(1%)::ITEM_CODE = PSCAN$_PRIB PSCAN_ITEM_LIST::ITEM(1%)::BUFFER_ADDR = MAXPRI PSCAN_ITEM_LIST::ITEM(1%)::LENGTH_ADDR = PSCAN$M_LEQ ! PSCAN_ITEM_LIST::ITEM(2%)::TERMINATOR = 0% ! ! Set up GETJPI JPI_ITEM_LIST::ITEM(0%)::BUFFER_LEN = 4% JPI_ITEM_LIST::ITEM(0%)::ITEM_CODE = JPI$_GETJPI_CONTROL_FLAGS JPI_ITEM_LIST::ITEM(0%)::BUFFER_ADDR = LOC(JPICONTROL) JPI_ITEM_LIST::ITEM(0%)::LENGTH_ADDR = LOC(RETLEN(0%)) ! JPI_ITEM_LIST::ITEM(1%)::BUFFER_LEN = 4% JPI_ITEM_LIST::ITEM(1%)::ITEM_CODE = JPI$_PROC_INDEX JPI_ITEM_LIST::ITEM(1%)::BUFFER_ADDR = LOC(JPI_PROC_INDEX) JPI_ITEM_LIST::ITEM(1%)::LENGTH_ADDR = LOC(RETLEN(1%)) ! JPI_ITEM_LIST::ITEM(2%)::BUFFER_LEN = 4% JPI_ITEM_LIST::ITEM(2%)::ITEM_CODE = JPI$_PID JPI_ITEM_LIST::ITEM(2%)::BUFFER_ADDR = LOC(JPI_PID) JPI_ITEM_LIST::ITEM(2%)::LENGTH_ADDR = LOC(RETLEN(2%)) ! JPI_ITEM_LIST::ITEM(3%)::BUFFER_LEN = 4% JPI_ITEM_LIST::ITEM(3%)::ITEM_CODE = JPI$_CPUTIM JPI_ITEM_LIST::ITEM(3%)::BUFFER_ADDR = LOC(JPI_CPUTIM) JPI_ITEM_LIST::ITEM(3%)::LENGTH_ADDR = LOC(RETLEN(3%)) ! JPI_ITEM_LIST::ITEM(4%)::BUFFER_LEN = 4% JPI_ITEM_LIST::ITEM(4%)::ITEM_CODE = JPI$_AUTHPRI JPI_ITEM_LIST::ITEM(4%)::BUFFER_ADDR = LOC(JPI_AUTHPRI) JPI_ITEM_LIST::ITEM(4%)::LENGTH_ADDR = LOC(RETLEN(4%)) ! JPI_ITEM_LIST::ITEM(5%)::BUFFER_LEN = 4% JPI_ITEM_LIST::ITEM(5%)::ITEM_CODE = JPI$_PRIB JPI_ITEM_LIST::ITEM(5%)::BUFFER_ADDR = LOC(JPI_PRIB) JPI_ITEM_LIST::ITEM(5%)::LENGTH_ADDR = LOC(RETLEN(5%)) ! JPI_ITEM_LIST::ITEM(6%)::BUFFER_LEN = 4% JPI_ITEM_LIST::ITEM(6%)::ITEM_CODE = JPI$_STATE JPI_ITEM_LIST::ITEM(6%)::BUFFER_ADDR = LOC(JPI_STATE) JPI_ITEM_LIST::ITEM(6%)::LENGTH_ADDR = LOC(RETLEN(6%)) ! JPI_ITEM_LIST::ITEM(7%)::TERMINATOR = 0% ! ! Setup DYNPRI_STOP logical translation item list ITEM_LIST::ITEM(0%)::BUFFER_LEN = 2% ITEM_LIST::ITEM(0%)::ITEM_CODE = LNM$_LENGTH ITEM_LIST::ITEM(0%)::BUFFER_ADDR = LOC(RETLEN(1%)) ITEM_LIST::ITEM(0%)::LENGTH_ADDR = LOC(RETLEN(0%)) ITEM_LIST::ITEM(1%)::TERMINATOR = 0% ! !===================================================================== ! START_LOOP: ! STAT = SYS$TRNLNM(,"LNM$SYSTEM_TABLE","DYNPRI_STOP",,ITEM_LIST) IF STAT = SS$_NOLOGNAM THEN STOPPING = 0% ELSE STOPPING = -1% END IF ! ! Calculate percentages based on CPU usage ! MAXCPU is from 5 to 99 percent (based on COM, COMO, CUR, and #CPUs) ! MINCPU is from 2 to 49 percent (half of MAXCPU) CPU_BOUND = MAX(CPU_BOUND,NUM_CPUS) ! Count at least one per CPU MAXCPU = MAX(((50%*NUM_CPUS)/CPU_BOUND),5%) MINCPU = MAXCPU/2% !PRINT TIME$(0%) !PRINT "Cpu procs:";CPU_BOUND;" MaxCPU:";MAXCPU;" MinCPU:";MINCPU ! ! Get the current time STAT = SYS$GETTIM(CURTIM(0%) BY REF) CALL LIB$STOP(STAT BY VALUE) IF (STAT AND 1%) = 0% ! ! Subtract the last time from it STAT = LIB$SUB_TIMES(CURTIM(0%) BY REF, OLDTIM(0%) BY REF, & DELTIM(0%) BY REF) CALL LIB$STOP(STAT BY VALUE) IF (STAT AND 1%) = 0% ! ! Convert it to seconds STAT = LIB$CVTF_FROM_INTERNAL_TIME(OPERATION BY REF, & CLOCK_SECS BY REF, DELTIM(0%) BY REF) CALL LIB$STOP(STAT BY VALUE) IF (STAT AND 1%) = 0% ! CONTEXT = 0% STAT = SYS$PROCESS_SCAN(CONTEXT BY REF, & PSCAN_ITEM_LIST BY REF) CALL LIB$STOP(STAT BY VALUE) IF (STAT AND 1%) = 0% ! CPU_BOUND = 0% STAT = 0% WHILE STAT <> SS$_NOMOREPROC ! STAT = SYS$GETJPIW(,CONTEXT BY REF,, & JPI_ITEM_LIST BY REF, & IOSB(0%) BY REF,,) IF STAT = SS$_NOMOREPROC THEN ITERATE \ END IF ITERATE IF (STAT AND 1%) = 0% IF IOSB(0%) = SS$_NOMOREPROC THEN ITERATE \ END IF ITERATE IF (IOSB(0%) AND 1%) = 0% ! CPU_BOUND = CPU_BOUND + 1% IF (JPI_STATE > 11%) AND (JPI_STATE < 15%) ITERATE IF JPI_PRIB < MINPRI ! JPI_PRIB > MAXPRI filtered by PSCAN IDX = JPI_PROC_INDEX IF PROC(IDX,PID) <> JPI_PID ! Brand new process THEN PROC(IDX,PID) = JPI_PID PROC(IDX,CPU) = JPI_CPUTIM ITERATE ! Go get the next one END IF CPU_SECS = JPI_CPUTIM - PROC(IDX,CPU) PERCENT = CPU_SECS/CLOCK_SECS PROC(IDX,CPU) = JPI_CPUTIM ! CHANGE_PRI = 0% IF STOPPING THEN IF JPI_PRIB <> JPI_AUTHPRI THEN JPI_PRIB = JPI_AUTHPRI CHANGE_PRI = -1% END IF ELSE IF (PERCENT < MINCPU) AND (JPI_PRIB < MIN(MAXPRI,JPI_AUTHPRI)) THEN JPI_PRIB = JPI_PRIB + 1% CHANGE_PRI = -1% ELSE IF (PERCENT > MAXCPU) AND (JPI_PRIB > MINPRI) THEN JPI_PRIB = JPI_PRIB - 1% CHANGE_PRI = -1% END IF END IF END IF ! STAT = SYS$SETPRI(JPI_PID BY REF,,JPI_PRIB BY VALUE,) IF CHANGE_PRI ! NEXT ! STAT <> SS$_NOMOREPROC ! !====================================================================== ! GOTO THE_END IF STOPPING OLDTIM(0%) = CURTIM(0%) OLDTIM(1%) = CURTIM(1%) SLEEP 30% GOTO START_LOOP ! THE_END: STAT = LIB$DELETE_LOGICAL("DYNPRI_STOP","LNM$SYSTEM_TABLE") CALL LIB$STOP(STAT BY VALUE) IF (STAT AND 1%) = 0% END