?? RIGHT := 110 ??
?? NEWTITLE := 'NOS/VE Job Management : job scheduler monitor or r1' ??
MODULE jmm$job_scheduler_monitor_or_r1;

{ Purpose:
{   This module contains scheduler procedures which can be called from either monitor or
{   ring 1.
{
{ Index of procedures:
{   jmp$calculate_service
{   jmp$find_jsn
{
{ Externals referenced by this module:

?? NEWTITLE := 'Global Declarations Referenced by This Module', EJECT ??
*copyc jmp$compute_total_memory_used
*copyc jmv$ijl_p
*copyc jmv$last_service_calc_time
*copyc jmv$service_classes
*copyc jmv$ssn_previous_sequence
*copyc jmv$system_supplied_name

?? PUSH (LISTEXT := ON) ??
*copyc jmt$ijl_ordinal
*copyc jmt$initiated_job_list_entry
*copyc jmt$service_factors
*copyc jmt$system_supplied_name
*copyc jmt$system_supplied_name_mask
?? POP ??

?? TITLE := '[XDCL] jmp$calculate_service', EJECT ??

{ PURPOSE:
{   This procedure calculates the amount of service a job has used.
{ DESIGN:
{   This procedure is called periodically (based on the job scheduler table attribute,
{   service_adjustment_interval) to calculate the service all active jobs have used.  It
{   is also called to calculate service for jobs that swap out for long wait.
{   The value for each service component is determined and multiplied by the service
{   factor.  Some components (io and cptime) must be determined even if the service factor
{   for that component is zero; otherwise there is no "history" for the component.  If the
{   service factor is changed to a non-zero value, the first service calculation would
{   be skewed.

  PROCEDURE [XDCL] jmp$calculate_service
    (    ijl_p: ^jmt$initiated_job_list_entry;
     VAR service_used: integer);

    VAR
      cptime_used: integer,
      current_cptime: integer,
      current_page_fault_count: integer,
      memory_used: 0 .. osc$max_page_frames,
      service_class_list_p: ^jmt$service_class_attributes,
      time_swapped_in: integer;

{ Compute the service the job has received.

    service_used := 0;
    service_class_list_p := ^jmv$service_classes [ijl_p^.job_scheduler_data.service_class]^.attributes;

    current_cptime := ijl_p^.statistics.cp_time.time_spent_in_job_mode;
    cptime_used := (current_cptime - ijl_p^.job_scheduler_data.last_cptime) DIV 1000;
    IF cptime_used < 1 THEN
      cptime_used := 1;
    IFEND;
    service_used := service_used + (service_class_list_p^.service_factors [jmc$sf_cpu] * cptime_used);
    ijl_p^.job_scheduler_data.last_cptime := current_cptime;

    IF service_class_list_p^.service_factors [jmc$sf_memory] <> 0 THEN
      jmp$compute_total_memory_used (ijl_p, memory_used);
      service_used := service_used + (service_class_list_p^.service_factors [jmc$sf_memory] * memory_used);
    IFEND;

    IF service_class_list_p^.service_factors [jmc$sf_residence] <> 0 THEN
      IF jmv$last_service_calc_time < ijl_p^.swap_data.timestamp THEN
        time_swapped_in := (#FREE_RUNNING_CLOCK (0) - ijl_p^.swap_data.timestamp) DIV 1000000;
      ELSE
        time_swapped_in := (#FREE_RUNNING_CLOCK (0) - jmv$last_service_calc_time) DIV 1000000;
      IFEND;
      service_used := service_used + (service_class_list_p^.service_factors [jmc$sf_residence] *
            time_swapped_in);
    IFEND;

    current_page_fault_count := ijl_p^.statistics.paging_statistics.page_fault_count;
    service_used := service_used + (service_class_list_p^.service_factors [jmc$sf_io] *
          (current_page_fault_count - ijl_p^.job_scheduler_data.last_page_fault_count));
    ijl_p^.job_scheduler_data.last_page_fault_count := current_page_fault_count;

{ Increment the job's service accumulators by the amount of service the job has used.

    ijl_p^.job_scheduler_data.service_accumulator := ijl_p^.job_scheduler_data.service_accumulator +
          service_used;
    ijl_p^.job_scheduler_data.service_accumulator_since_swap :=
          ijl_p^.job_scheduler_data.service_accumulator_since_swap + service_used;

  PROCEND jmp$calculate_service;

?? TITLE := '[XDCL] jmp$find_jsn', EJECT ??

  PROCEDURE [XDCL] jmp$find_jsn
    (    jsn: string ( * <= jmc$system_supplied_name_size);
     VAR ijle_p: ^jmt$initiated_job_list_entry;
     VAR ijlo: jmt$ijl_ordinal);

    VAR
      ijl_bn: jmt$ijl_block_number,
      ijl_bi: jmt$ijl_block_index,
      ijl_p: ^jmt$initiated_job_list_entry,
      jsn_length: 0 .. jmc$system_supplied_name_size,
      system_supplied_name: jmt$system_supplied_name_mask;

    ijle_p := NIL;

{ Expand jsn to full system supplied name.

    jsn_length := STRLENGTH (jsn);
    IF jsn_length = jmc$system_supplied_name_size THEN
      system_supplied_name.system_supplied_name := jsn;
    ELSEIF jsn_length = jmc$long_ssn_size THEN
      system_supplied_name := jmv$system_supplied_name;
      system_supplied_name.sequence := jsn (2, jmc$ssn_sequence_number_size);
      system_supplied_name.counter := jsn (6, jmc$ssn_counter_size);
    ELSEIF jsn_length = jmc$short_ssn_size THEN
      system_supplied_name := jmv$system_supplied_name;
      IF system_supplied_name.counter < jsn (2, jmc$ssn_counter_size) THEN
        system_supplied_name.sequence := jmv$ssn_previous_sequence;
      IFEND;
      system_supplied_name.counter := jsn (2, jmc$ssn_counter_size);
    ELSE
      RETURN;
    IFEND;

  /scan_ijl_for_jsn/

    FOR ijl_bn := LOWERBOUND (jmv$ijl_p.block_p^) TO jmv$ijl_p.max_block_in_use DO
      IF (jmv$ijl_p.block_p^ [ijl_bn].index_p <> NIL) THEN
        FOR ijl_bi := LOWERVALUE (jmt$ijl_block_index) TO UPPERVALUE (jmt$ijl_block_index) DO
          ijl_p := ^jmv$ijl_p.block_p^ [ijl_bn].index_p^ [ijl_bi];
          IF ijl_p^.system_supplied_name = system_supplied_name.system_supplied_name THEN
            ijle_p := ijl_p;
            ijlo.block_number := ijl_bn;
            ijlo.block_index := ijl_bi;
            RETURN;
          IFEND;

        FOREND;
      IFEND;
    FOREND /scan_ijl_for_jsn/;
  PROCEND jmp$find_jsn;

MODEND jmm$job_scheduler_monitor_or_r1;





