.lm 18;.rm 90;.nj;.c ;DYNAMIC ADJUSTMENT OF BASE PRIORITIES .S 1;.C ;Larry W.#Finger .c ;Carnegie Institution of Washington .s 1;.sp 1;.p ;The dynamic priority adjustment scheme employed in VMS is reasonably effective at providing quick response and balanced cpu usage. The efficiency of the algorithm diminishes, however, when one or more high priority, compute-bound users are on the system. This article describes a technique that overcomes these difficulties by modification of the ^&base\& priority of processes to enhance response. .p ;Our machine is a relatively high performance 11/780 with three megabytes memory, a floating-point accelerator and an array processor. It is mainly used for scientific calculations and for word processing of scientific manuscripts. Problems undertaken range up to computation intensive programs with cpu times of 10 hours. All interactive users have base priority of four, and there are three batch queues, each with a job limit of two. The "quick" queue with base priority 3 has a maximum cpu time of 5 minutes. The intermediate queue with priority of 2 has a time limit of 30 minutes. There is no time limit for the queue with priority equal to one. The SYSGEN parameter QUANTUM is set at 60 ticks. The system operates 24 hours per day, 7 days per week with essentially 100% cpu utilization during the prime shift. Overall cpu usage is approximately 35%. The large memory size ensures little or no swapping and the interactive response time is very good except as noted above. Even worse, several such compute-bound users can monopolize the processor, locking out batch users who are tempted to start executing their programs in interactive mode, which would make the problem worse. .p ;Various schemes were considered to break the cycle and distribute cpu time equitably. It was not possible, however, to impose strict cpu limits on interactive jobs nor to lower the base priority of the offending users. Reducing QUANTUM would have improved interactive response at the expense of overhead, but would have had no effect on batch lock-out. A scheme of dynamic base priority reduction based on cumulative cpu usage would minimize the impact of such compute-bound jobs; however, there would be reduced response to changing activity within the user process. .p ;The priority alteration scheme selected and described here uses the elapsed cpu time in execution of the current image as the critical parameter for reduction of priority. Whenever this parameter exceeds a threshold, the base priority is reduced by one level. When a second threshold is reached, a further reduction occurs, and so on until a base priority of one is achieved. The critical times for our system are 5, 300, and 1800 seconds, which were chosen to keep a given computation at essentially the priority it would have in batch mode. Whenever the user executes a new image, the original base priority and the elapsed cpu time are reset. The VMS dynamic priority algorithm is not modified in any other way. .p ;Adjustment of base priority is accomplished by a detached process started when the system is booted. This task prepares tables that include the process identification code (PID), eight characters of the file name of the image under execution, the original base priority, and the starting cpu time for the current image. No batch or system processes are included in the tables. As each process is considered in turn through the use of a "wild-card" $GETJPI system service, the PID table is searched for a match. If not found, this process has just been created and is assigned the first empty slot in the tables, which are extended if necessary. For pre-existing processes, the priority is adjusted as required. At completion of the process scan, any users that have logged-off are deleted from the tables, and the list shortened if possible. The task then hibernates for a user selected period, 15 seconds on our system. .P ;Although this priority altering process consumes system resources, its requirements are minimal - one process slot, 23 pages of memory and approximately 2 minutes of cpu time per day. The improvement in system response for text editors and batch throughput would have been worth a much larger penalty. .p ;To implement the program, the user must define several symbols to establish the characteristics of the priority alteration scheme. These symbols, with values for our system in parentheses, are NoProc (100.), the maximum number of user processes to include in the tables; LowGrpNum (65.), the smallest group number to be considered as a non-system job; LoopTime (15.), the number of seconds between rescans of the process list; and Time&n, &n=1,..,7, which are the threshold times for priority reduction 1,2,... After the above symbols are adjusted for your system requirements and the program assembled and linked, it can be initiated by the following command: .s 1;####$#RUN/NOACCOUNTING/NOAUTHORIZE/PRIORITY=6/UIC=[1,4]- .BR;####/PRIVILEGES=(WORLD,ALTPRI)/PROCESS__NAME=ADJUSTPRI ADJUSTPRI .S 1;To issue the above command, you must have DETACH, ACNT, ALTPRI, and SETPRV privileges. To initiate priority adjustment at system startup, the above command should be added to [SYSMGR]SYSTARTUP.COM. .page;.c ;^&PROGRAM LISTING\& .lm 18;.ts 18,26,34,42,50,58,66,74,82,90;.nf .s 1;.sp 1;.literal .Title AdjustPri ; ; Routine to adjust priority of running interactive processes. ; ; When such a process exceeds an execution time threshold for ; its current base priority, the base priority is lowered. ; ; Execution of a new image restores the original priority. ; ; The intent of this task is to improve response time ; for interactive jobs without forcing long computations to batch. ; ; All site-dependent parameters such of frequency of execution ; of the task, time thresholds, maximum number of processes, ; and group numbers to exclude from consideration are defined at ; the beginning of the program. ; ; Coded 11-May-1982 ; ; Larry W. Finger ; Geophysical Laboratory ; 2801 Upton St. N.W. ; Washington DC 20008 ; (202) 966-0334 ; ; ; Define symbols to set-up program ; NoProc = _^D100 ; Size of Process Tables, Maximum No. LowGrpNum = _^O101 ; Lowest Group Number to consider LoopTime = _^D15 ; Number of seconds Between Rescans Time1 = _^D5 ; Execution Time before Dropping One ; Priority Level Time2 = _^D300 ; Cpu Time before Dropping Second Level Time3 = _^D1800 ; Cpu Time before Dropping Third Level Time4 = _^D1800 ; Cpu Time before dropping Fourth Level Time5 = _^D1800 ; Cpu Time before Dropping Fifth Level Time6 = _^D1800 ; Cpu Time before Dropping Sixth Level Time7 = _^D1800 ; Cpu Time before Dropping Seventh Level ; $jpidef ;define $GETJPI item codes .page ; ; read/only data ; .psect rodata,rd,nowrt,noexe ; ; Item List for $GETJPI ; items: .word 16 ;process name buffer .word JPI$__PRCNAM ;process name code .long pcname ;pointer to buffer .long 0 ;length not needed .word 4 ;length of cputime buffer .word JPI$__CPUTIM ;cpu time code .long cputime .long 0 ;length not needed .word 4 .word JPI$__PRIB ;base priority code .long basepri .long 0 ;length not needed .word 4 .word JPI$__GRP ;group number code .long grpnum .long 0 ;length not needed .word 64 .word JPI$__IMAGNAME ;image name code .long imgnam .long 0 ;length not needed .word 4 .word JPI$__PID ;user pid code .long userpid .long 0 ;length not needed .long 0 ;end of list ; DayTime:.long -_^D10*_^D1000*_^D1000*LoopTime,-1 ;Delta Time for Rescans ; Times: .long _^D100*Time1 ; Table of Cpu Time Differences .long _^D100*Time2 ; for Priority Change .long _^D100*Time3 .long _^D100*Time4 .long _^D100*Time5 .long _^D100*Time6 .long _^D100*Time7 .page ; ; read/write data ; .psect rwdata,rd,wrt,noexe pid: .long -1 ;"wildcard" PID ; pcname: .blkb 16 ;process name buffer cputime:.blkl 1 ;cputime storage basepri:.blkl 1 ;current base priority grpnum: .blkl 1 ;group number imgnam: .blkb 64 ;image name buffer userpid:.blkl 1 ; iosb: .blkq 1 ;i/o status block ; ; Process Storage Tables ; PidTab: .blkl NoProc ; Storage Array for PID's Imgnamtab:.blkq NoProc ; Storage for Current Image OrigBas:.blkl NoProc ; Original Base Priority OrigCpu:.blkl NoProc ; Cpu time at start of this image Prcusd: .blkb NoProc ; Byte to note if this slot used ; Frstmty:.blkl 1 ; Location of First Empty Slot PidCnt: .blkl 1 ; Number of Entries in PID Tables .page ; ; executable section ; .psect code,exe,nowrt ; .entry start,0 ; clrl pidcnt ;make pid table empty restart: ;restart loop after initial pass ; ; clear process used storage area ; movl _#-1,r4 ;initialize a counter movl r4,pid ;restore wildcard PID 10$: incl r4 ;increment counter cmpl r4,pidcnt ;at end of list? beql loop ;if eql yes clrb prcusd[r4] ;set slot not used this loop brb 10$ ;go to next entry ; ; loop through all processes in system ; loop: $GETJPI__S efn=_#1,pidadr=pid,itmlst=items,iosb=iosb blbs r0,wait ;if success, continue cmpw r0,_#SS$__NOMOREPROC ;end of list? bneq loop ;if neq no brw done ;go to done wait: $WAITFR__S efn=_#1 ;wait for info ready cmpl grpnum,_#lowgrpnum ;should this group be ignored? blss loop ;if lss yes cmpb pcname,_#_^O137 ;BATCH job - Underscore first char? beql loop ;if eql yes - ignore ; ; find process in tables ; movl _#-1,r4 ;preset loop counter movl r4,frstmty ;invalidate first empty slot marker 20$: incl r4 ;update counter cmpl r4,pidcnt ;at end of list? beql 40$ ;if eql yes tstl pidtab[r4] ;slot empty? bneq 30$ ;if neq no tstl frstmty ;is this first empty this scan? bgeq 20$ ;if geq no movl r4,frstmty ;save this empty slot as first brb 20$ ;go to check next slot 30$: cmpl pidtab[r4],userpid ;slot not empty - match current PID? bneq 20$ ;if neq no brb 70$ ;found match - go to process ; ; new process found - not in current tables ; 40$: tstl frstmty ;imbedded empty slot? bgeq 50$ ;if geq yes movl pidcnt,r4 ;add new process at end - get count incl r4 ;update by one cmpl r4,_#noproc ;exceed size of tables? bgtr 45$ ;if gtr yes - ignore process movl r4,pidcnt ;update count decl r4 ;restore pointer brb 60$ 45$: brw loop ;get next process 50$: movl frstmty,r4 ;fill in empty slot - get its number ; ; add new process info to tables ; 60$: movl userpid,pidtab[r4] ;store PID in table movl cputime,origcpu[r4] ;cpu time movl basepri,origbas[r4] ;starting priority bsbw scanname ;get start of image file name movq (r0),imgnamtab[r4] ;copy first 8 characters ; ; process in tables (just added if necessary) ; compare with previous entry ; 70$: incb prcusd[r4] ;mark this entry used bsbw scanname ;scan image name for closing ] movl r0,r6 ;save r0 movaq imgnamtab[r4],r5 ;get index to old name cmpc3 _#_^D8,(r5),(r0) ;same image? bneq 80$ ;if neq no ; ; still executing previous image ; subl3 origcpu[r4],cputime,r0 ;compute ticks used subl3 basepri,origbas[r4],r1 ;get difference in priority cmpl r0,times[r1] ;time exceed threshold? bleq 90$ ;if leq no ; ; time over threshold ; subl3 _#1,basepri,r0 ;reduce base priority by 1 - to zero? bleq 90$ ;if leq yes - ignore new priority bsbw setpriority ;set new priority for this process brb 90$ ; ; new image executing ; 80$: movl cputime,origcpu[r4] ;reset cpu start movq (r6),imgnamtab[r4] ;copy first 8 char. of image name movl origbas[r4],r0 ;get original base priority cmpl r0,basepri ;any change? beql 90$ ;if eql no bsbw setpriority ;reset priority 90$: brw loop ;get next entry ; ; end of process loop ; done: ; ; leave wake-up call for 'LOOPTIME' seconds from now ; $SCHDWK__S daytim=daytime ; ; clear PID entry for anyone that logged off ; clrl r4 ;zero index register 10$: tstb prcusd[r4] ;this process still around? bneq 20$ ;if neq yes clrl pidtab[r4] ;process gone - zero pid entry 20$: incl r4 ;update counter cmpl r4,pidcnt ;at end yet? blss 10$ ;if lss no ; ; prune last entry from list if not used ; movl pidcnt,r4 ;get pidcnt - tables empty? beql 30$ ;if eql yes decl r4 ;reduce number by 1 tstl pidtab[r4] ;last entry empty? bneq 30$ ;if neq no movl r4,pidcnt ;prune empty entry from end of list 30$: $HIBER__S ;go to sleep brw restart ;do it again ; ; scanname - routine to scan for closing ] in imagename ; ; address of start of program name returned in r0 ; scanname: moval imgnam,r0 ;pointer to start of image area movl _#_^D40,r1 ;maximum number of characters before ] 10$: cmpb (r0)+,_#_^O135 ;character = ]? beql 20$ ;if eql yes sobgtr r1,10$ ;loop for next character moval imgnam,r0 ;if loop exited - no ] in name 20$: rsb ;exit with r0 set ; ; setpriority - routine to adjust priority of process ; ; new base priority in r0 at entry ; process identification in 'userpid' ; setpriority: $SETPRI__S pidadr=userpid,pri=r0 ;set new priority rsb ;exit .end start