PACKET std schedule strategy DEFINES                (* Autor: J.Liedtke *)
                                                    (* Stand: 15.10.82  *)
    strategic decision :


PROC strategic decision 
              (INT CONST foreground workers, background workers,
               REAL CONST fore cpu load, back cpu load, paging load,
               INT VAR lowest activation prio, max background tasks) :
 
  IF no background permitted
    THEN lowest activation prio := 0 ;
         max background tasks := 0
    ELSE lowest activation prio := 10 ;
         select max background tasks
  FI .
 
no background permitted :
      foreground workers > 0 AND fore cpu load > 0.03 .

select max background tasks :
  IF fore cpu load > 0.01
    THEN max background tasks := 1
  ELIF paging load < 0.07
    THEN max background tasks := 3
  ELIF paging load < 0.15
    THEN max background tasks := 2
    ELSE max background tasks := 1
  FI .

ENDPROC strategic decision ;

ENDPACKET std schedule strategy ;


                                              (* Autor: J.Liedtke*)
PACKET eumelmeter DEFINES                     (* Stand: 11.10.83 *)
 
     init log ,
     log :
 
 
LET snapshot interval = 590.0 ;

REAL VAR next snapshot time ,
         time        , timex ,
         paging wait , paging wait x ,
         paging busy , paging busy x ,
         fore cpu    , fore cpu x ,
         back cpu    , back cpu x ,
         system cpu  , system cpu x ,
         delta t ;
INT VAR storage max, used ;
TEXT VAR record ;

PROC init log :

  time        := clock (1) ;
  paging wait := clock (2) ;
  paging busy := clock (3) ;
  fore cpu    := clock (4) ;
  back cpu    := clock (5) ;
  system cpu  := clock (6) ;
  next snapshot time := time + snapshot interval

ENDPROC init log ;

PROC log (INT CONST active terminals, active background) :

  new snapshot time if was clock reset ;
  IF clock (1) >= next snapshot time
    THEN save values ;
         get new values ;
         create stat record ;
         put log (record) ;
         define next snapshot time
  FI .

new snapshot time if was clock reset :
  IF clock (1) < next snapshot time - snapshot interval 
    THEN next snapshot time := clock (1)
  FI .

save values :
  time x := time ;
  paging wait x := paging wait ;
  paging busy x := paging busy ;
  fore cpu x    := fore cpu ;
  back cpu x    := back cpu ;
  system cpu x  := system cpu .

get new values :
  time := clock (1) ;
  paging wait := clock (2) ;
  paging busy := clock (3) ;
  fore cpu    := clock (4) ;
  back cpu    := clock (5) ;
  system cpu  := clock (6) ;
  storage (storage max, used) .

create stat record :
  record :=  text (used, 5) ;
  record CAT text (active terminals,3) ;
  record CAT text (active background,3) ;
  delta t := (time - time x) ;
  percent (paging wait, paging wait x) ;
  percent (paging busy, paging busy x) ;
  percent (fore cpu, fore cpu x) ;
  percent (back cpu, back cpu x) ;
  percent (system cpu, system cpu x) ;
  percent (last, 0.0) ;
  percent (nutz, 0.0) .

last :   paging wait  + paging busy  + fore cpu  + back cpu  + system cpu
       - paging waitx - paging busyx - fore cpux - back cpux - system cpux .

nutz :   time  - paging wait  - system cpu
       - timex + paging waitx + system cpux .

define next snapshot time :
  next snapshot time := time + snapshot interval .
 
ENDPROC log ;

PROC percent (REAL CONST neu, alt ) :

  record CAT text ( (neu-alt) / delta t * 100.0, 6,1) + "%"

ENDPROC percent ;

ENDPACKET eumelmeter ;



PACKET background que manager DEFINES                (* Autor: J.Liedtke *)
                                                     (* Stand: 15.10.82  *)
    into background que ,
    delete from background que ,
    get first from background que ,
    get next from background que :

LET que size = 100 ,
    ENTRY    = STRUCT (TASK task, INT class) ;

INT VAR end of que := 0 ,
        actual entry pos ;

ROW que size ENTRY VAR que ;


PROC into background que (TASK CONST task) :

  INT VAR class := prio (task) ;
  IF end of que = que size
    THEN delete all not existing tasks
  FI ;
  check whether already in que ;
  IF already in que
    THEN IF in same class
           THEN LEAVE into background que
           ELSE delete from background que (task) ;
                into background que (task)
         FI
    ELSE insert new entry
  FI .

check whether already in que :
  INT VAR entry pos := 1 ;
  WHILE entry pos <= end of que  REP
    IF que (entry pos).task = task
      THEN LEAVE check whether already in que
    FI ;
    entry pos INCR 1
  PER .

already in que :  entry pos <= end of que .

in same class :   que (entry pos).class = class .

insert new entry :
  end of que INCR 1 ;
  que (end of que) := ENTRY:( task, class ) .

delete all not existing tasks :
  INT VAR j ;
  FOR j FROM 1 UPTO end of que REP
    TASK VAR examined := que (j).task ;
    IF NOT exists (examined)
      THEN delete from background que (examined)
    FI
  PER .

ENDPROC into background que ;

PROC delete from background que (TASK CONST task) :

  search for entry ;
  IF entry found
    THEN delete entry ;
         update actual entry pos 
  FI .

search for entry :
  INT VAR entry pos := 1 ;
  WHILE entry pos <= end of que REP
    IF que (entry pos).task = task
      THEN LEAVE search for entry
    FI ;
    entry pos INCR 1
  PER .

entry found : entry pos <= end of que .

delete entry :
  INT VAR i ;
  FOR i FROM entry pos UPTO end of que - 1 REP
    que (i) := que (i+1)
  PER ;
  end of que DECR 1 .

update actual entry pos :
  IF actual entry or following one deleted
    THEN actual entry pos DECR 1
  FI .

actual entry or following one deleted :
  entry pos >= actual entry pos .

ENDPROC delete from background que ;

PROC get first from background que (TASK VAR task, INT CONST lowest class) :

  actual entry pos := 0 ;
  get next from background que (task, lowest class)

ENDPROC get first from background que ;

PROC get next from background que (TASK VAR task, INT CONST lowest class) :
 
  search next entry of permitted class ;
  IF actual entry pos <= end of que
    THEN task := que (actual entry pos).task
    ELSE task := niltask
  FI .

search next entry of permitted class :
  REP
    actual entry pos INCR 1
  UNTIL actual entry pos > end of que 
        COR que (actual entry pos).class <= lowest class PER.

ENDPROC get next from background que ;

ENDPACKET background que manager ;

 

PACKET scheduler DEFINES                         (* Autor: J.Liedtke *)
                                                 (* Stand: 09.12.82  *)
    scheduler :
 

LET std background prio     = 7 ,
    highest background prio = 5 ,
    long slice              = 6000 ,
    short slice             = 600 ,
    blocked busy            = 4 ;

INT VAR slice ,
        foreground workers ,
        background workers ;

BOOL VAR is logging ;

REAL VAR fore cpu load , back cpu load , paging load ;


access catalogue ;
TASK CONST ur task := brother (supervisor) ;

TASK VAR actual task ;


PROC scheduler :
  IF yes ("mit eumelmeter")
    THEN is logging := TRUE
    ELSE is logging := FALSE
  FI ;
  task password ("-") ;
  break ;
  set autonom ;
  command dialogue (FALSE) ;
  forget ("scheduler", quiet) ;
  disable stop; 
  REP scheduler operation; 
      clear error 
  PER; 
 
END PROC scheduler; 
 
PROC scheduler operation:
  enable stop;
  IF is logging 
    THEN init log 
  FI;
  slice := short slice ;
  init system load moniting ;
  REP
    pause (slice) ;
    monit system load ;
    look at all active user tasks and block background workers ;
    activate next background workers if possible ;
    IF is logging
      THEN log (foreground workers, background workers)
    FI
  PER .

init system load moniting :
  REAL VAR 
  time     x := clock (1) ,
  fore cpu x := clock (4) ,
  back cpu x := clock (5) ,
  paging   x := clock (2) + clock (3) .

monit system load :
  REAL VAR interval := clock (1) - time x ;
  fore cpu load := (clock (4) - fore cpu x) / interval ;
  back cpu load := (clock (5) - back cpu x) / interval ;
  paging load   := (clock (2) + clock (3) - paging x) / interval ;
  time     x := clock (1) ;
  fore cpu x := clock (4) ;
  back cpu x := clock (5) ;
  paging   x := clock (2) + clock (3) .

ENDPROC scheduler operation;

PROC look at all active user tasks and block background workers :

  foreground workers := 0 ;
  background workers := 0 ;
  actual task := myself ;
  next active (actual task) ;
  WHILE NOT (actual task = myself) REP
    IF actual task < ur task
      THEN look at this task
    FI ;
    next active (actual task)
  END REP .

look at this task :
  IF channel (actual task) >= 0
    THEN foreground workers INCR 1
    ELSE background workers INCR 1 ;
         block actual task if simple worker
  FI .

block actual task if simple worker :
  IF son (actual task) = niltask
    THEN pause (5) ;
         block (actual task) ;
         IF status (actual task) = blocked busy
           THEN set background prio ;
                into background que (actual task)
         ELIF prio (actual task) < highest background prio
           THEN unblock (actual task)
         FI
  FI .

set background prio :
  IF prio (actual task) < highest background prio
    THEN prio (actual task, std background prio)
  FI .
 
ENDPROC look at all active user tasks and block background workers ;

PROC activate next background workers if possible :

  INT VAR lowest activation prio ,
          max background workers ,
          active background workers := 0 ;

  strategic decision (foreground workers, background workers,
                      fore cpu load, back cpu load, paging load,
                      lowest activation prio, max background workers) ;

  IF background permitted
    THEN try to activate background workers
  FI ;
  IF active background workers > 0
    THEN slice := short slice
    ELSE slice := long slice
  FI .

background permitted : max background workers > 0 .

try to activate background workers :
  get first from background que (actual task, lowest activation prio) ;
  IF NOT is niltask (actual task)
    THEN delete from background que (actual task)
  FI ;

  WHILE active background workers < max background workers REP
    IF is niltask (actual task)
      THEN LEAVE try to activate background workers
    ELIF status (actual task) <> blocked busy
      THEN delete from background que (actual task)
    ELSE
           unblock (actual task) ;
           active background workers INCR 1
    FI ;
    get next from background que (actual task, lowest activation prio)
  PER .

ENDPROC activate next background workers if possible ;
 
ENDPACKET scheduler ;
 
scheduler;