1 ! ! D Y N P R I 10 EXTEND 110 ! ! DYNPRI Dynamic priority allocation for ! RSTS/E Version 6, ! taken from RSTS SIG. newsletter. ! ! Theory of operation: ! The program sleeps SLEEP.TIME% seconds, then looks at ! the priority and CPU usage of all jobs whose ! priority is in the range PRIOR1% ... PRIOR3% ! ! Priority PRIOR1%: ! If the job has used more than LEVEL1.TICKS% system ticks, ! the level PRIOR2% residency count CYCLES%() is cleared ! and the job is dropped to PRIOR2% priority. ! ! Priority PRIOR2%: ! If the job becomes terminal or system bound, ! it is raised to priority PRIOR1%, else, the residency ! count is increased. If the job is still CPU bound ! after CYCLES% cycles. it is dropped to priority PRIOR3%. ! ! Priority PRIOR3%: ! The job remains at this level until it becomes ! terminal or system bound. Then it is raised to ! priority PRIOR1%. ! ! Configuration: ! Line 120 contains a DATA statement with the ! following configuration parameters: ! SLEEP Number of seconds between schedule cycles ! CLOCK 5 For 50 Hertz, 6 for 60 Hertz systems ! PERCENT More than 'PERCENT' and it's compute bound ! LEVEL-2 The number of seconds a job remains compute ! bound at priority PRIOR2% before being dropped ! to priority PRIOR3% ! BURST-1 The CPU run burst for jobs at level PRIOR1% ! BURST-2 The CPU run burst for jobs at level PRIOR2% ! BURST-3 The CPU run burst for jobs at level PRIOR3% ! 900 DIM TIME.USED%(63), CYCLES%(63) !TIME.USED%() TIME USED !CYCLES%() SCHEDULE CYCLES AT LEVEL PRIOR2% ! DIMENSION >= JOBMAX 910 DIM SYSVEC%(30) !SYSVEC%() USED FOR SYS FUNCTION CALL 920 DATA 20, 6, 10, 30, 10, 20, 30 930 ! SLEEP CLOCK PERCENT LEVEL-2 BURST-1 BURST-2 BURST-3 940 DATA 0 950 ! PRIOR1 960 WAIT.BITS%=32766% !WAIT.BITS% JBWAIT BITS TO TEST FOR: !"ANY" I/O WAIT CONDITION EXCEPT DISK 1100 PRINT "DYNPRI V06-01" \ READ SLEEP.TIME%, HERTZ%, LEVEL1.TICKS%, CYCLES% \ READ BURST1%, BURST2%, BURST3%, PRIOR1% !SIGN ON AND READ PARAMETERS: !SLEEP.TIME% SLEEP TIME BETWEEN RESCHEDULE CYCLES !HERTZ% 5 = 50 HERTZ, 6 = 60 HERTZ !PRIOR1% HIGHEST PRIORITY WITHIN MY RANGE 1110 LEVEL1.TICKS%=LEVEL1.TICKS%*SLEEP.TIME%/10% \ CYCLES%=CYCLES%/SLEEP.TIME% \ BURST1%=BURST1%*HERTZ% \ BURST2%=BURST2%*HERTZ% \ BURST3%=BURST3%*HERTZ% \ PRIOR2%=PRIOR1%-8% \ PRIOR3%=PRIOR2%-8% \ PRIOR4%=PRIOR3%-8% !LEVEL1.TICKS% SYSTEM TICKS AT PRIOR1% BEFORE DROPPING !CYCLES% SCHEDULE CYCLES AT PRIOR2% BEFORE DROPPING !BURST1% PRIOR1% BURST !BURST2% PRIOR2% BURST !BURST3% PRIOR3% BURST !PRIOR2% MID-LEVEL PRIORITY (SOMEWHAT COMPUTE BOUND) !PRIOR3% LOW-LEVEL PRIORITY (COMPUTE BOUND FOR A WHILE) 1120 CHANGE SYS(CHR$(6%)+CHR$(-3%)) TO SYSVEC% \ JOBTBL%=SYSVEC%(11%)+SWAP%(SYSVEC%(12%)) \ JBWAIT%=SYSVEC%(15%)+SWAP%(SYSVEC%(16%)) \ JBSTAT%=SYSVEC%(13%)+SWAP%(SYSVEC%(14%)) \ MAX.JOBS%=SYSVEC%(4%) !GET SYSTEM TABLE ADDRESSES AND: !JOBTBL% JOBTBL !JBWAIT% JBWAIT !JBSTAT% JBSTAT !MAX.JOBS% MAX JOB NUMBER 1130 SYSVEC%(K%)=0% FOR K%=1% TO 30% \ SYSVEC%(1%)=6% \ SYSVEC%(2%)=-13% \ SYSVEC%(4%), SYSVEC%(6%)=-1% \ JOB%=(PEEK(518%) AND 255%)/2% \ PRIORITY%=PRIOR1% \ BURST%=BURST1% \ GOSUB 10000 \ LSET SYSBUF$=SYS(CHR$(6%)+CHR$(-22%)) !CLEAR SYS CALL BUFFER, SETUP TO SET PRIORITY, THEN GET !MY JOB NUMBER AND RAISE TO PRIORITY PRIOR1%. FINALLY, !SET SPECIAL RUN PRIORITY SO I DON'T SCHEDULE MYSELF. 1140 PRINT "Detaching ...";CHR$(12%) \ SYSBUF$=SYS(CHR$(6%)+CHR$(7%)) !INITIALIZE JOB TIME TABLE AND DETACH 2000 SLEEP SLEEP.TIME% \ FOR JOB%=1% TO MAX.JOBS% \ JOB.INDEX%=JOB%+JOB% \ JDB%=PEEK(JOBTBL%+JOB.INDEX%) \ GOTO 2080 UNLESS JDB%<>0% \ PRIORITY%=PEEK(JDB%+28%) AND 255% \ PRIORITY%=PRIORITY%-256% IF PRIORITY% >= 128% \ GOTO 2080 IF PRIORITY% < PRIOR3% OR PRIORITY% > PRIOR1% OR (PRIORITY% AND 4%) <> 0% \ GOTO 2050 IF ((PRIORITY% AND 7%) <> 0%) AND PRIORITY% < PRIOR1% !START SCHEDULING: !EXIT IF NO JOB, PRIORITY > PRIOR1%, PRIORITY < PRIOR3%, !OR THE "SPECIAL SCHEDULING BIT" WAS SET. !GO RAISE PRIORITY IF SPECIAL BITS SET AND IT'S TOO LOW. 2010 STATE%=PEEK(JBWAIT%+JOB.INDEX%) \ STATE%=((STATE% AND PEEK(JBSTAT%+JOB.INDEX%)) = 0%) AND (STATE% AND WAIT.BITS%) <> 0% \ ON (PRIORITY% - PRIOR4%)/8% GOTO 2040, 2030, 2020 !STATE% IS NON-ZERO IF JOB CAN RUN AND WANTS TO. !GET PRIORITY AS 1,2,3, AND GO. 2020 TIME.USED%=PEEK(PEEK(JDB%+8%)+2%) \ GOTO 2070 IF (TIME.USED%-TIME.USED%(JOB%) <= LEVEL1.TICKS%) OR STATE% <> 0% \ CYCLES%(JOB%)=0% \ PRIORITY%=PRIOR2% \ BURST%=BURST2% \ GOTO 2060 !STAY AT PRIOR1% IF THE JOB DIDN'T USE !MORE THAN LEVEL1.TICKS% OR IS OTHERWISE RUNNABLE. ! (NOTE: THE TIME IS INCORRECT EVERY 3276.8 CPU SECONDS.) !CPU BOUND: CLEAR LEVEL 2 COUNTER AND DROP TO PRIOR2%. 2030 GOTO 2050 IF STATE% \ CYCLES%(JOB%) = CYCLES%(JOB%) + 1% \ GOTO 2070 IF CYCLES%(JOB%) <= CYCLES% \ PRIORITY%=PRIOR3% \ BURST%=BURST2% \ GOTO 2060 !RAISE THE JOB TO PRIOR1% IF RUNNABLE, !STAY AT PRIOR2% IF WE HAVEN'T BEEN HERE TOO LONG, !OTHERWISE, DROP THE JOB TO PRIOR3%. 2040 GOTO 2070 UNLESS STATE% !KEEP THE JOB AT PRIOR3% UNTIL IT'S SYSTEM OR USER BOUND. 2050 PRIORITY%=PRIOR1% \ BURST%=BURST1% !RAISE THIS JOB TO HIGH PRIORITY 2060 GOSUB 10000 !RESCHEDULE THIS JOB NOW 2070 TIME.USED%(JOB%)=TIME.USED% !SAVE JOB CPU TIME FOR NEXT SCHEDULE CYCLE 2080 NEXT JOB% \ GOTO 2000 !DONE WITH THIS JOB, GO GET NEXT 10000 SYSVEC%(3%)=JOB% \ SYSVEC%(5%)=PRIORITY% \ SYSVEC%(7%)=BURST% \ CHANGE SYSVEC% TO SYSBUF$ \ LSET SYSBUF$=SYS(SYSBUF$) \ RETURN !SUBROUTINE TO SET PRIORITY. GLOBALS ARE: !JOB% JOB NUMBER !P% NEW PRIORITY !B% NEW RUN BURST 32767 ON ERROR GOTO 0 \ END