?? RIGHT := 110 ??
?? NEWTITLE := 'NOS/VE Operator Facility : VED IS Display' ??
MODULE ofm$io_summary_display;
?? RIGHT := 110 ??

{ VED IS Display

?? NEWTITLE := 'Global Declarations Referenced by This Module', EJECT ??
?? PUSH (LISTEXT := ON) ??
*copyc oss$job_paged_literal
*copyc oss$task_shared
*copyc clt$display_control
*copyc ost$data_id
*copyc ost$status
*copyc ost$string
?? POP ??
*copyc clp$close_display
*copyc clp$convert_integer_to_rjstring
*copy  clp$new_display_line
*copy  clp$put_display
*copyc dpp$clear_window
*copyc dpp$put_next_line
*copyc ofp$build_system_line
*copyc ofp$open_display
*copyc osp$disestablish_cond_handler
*copyc osp$establish_block_exit_hndlr
*copyc osp$get_pio_pp_stats
*copyc osp$get_pio_unit_stats
*copyc osp$get_pp_unit_count
*copyc osp$get_rvsn_by_lun
*copyc pmp$binary_to_ascii_fit
*copyc cmv$logical_unit_table
*copyc osv$task_shared_heap

  VAR
    iov$reject_requests_full: [XREF] integer,
    iov$reject_unit_queue_limit: [XREF] integer,

    mmv$sq_mcount: [XREF] integer,
    mmv$sq_rcount: [XREF] integer;

?? OLDTITLE ??
?? NEWTITLE := '[xdcl] OFP$IO_SUMMARY_DISPLAY', EJECT ??

  PROCEDURE [XDCL] ofp$io_summary_display
    (    wid: dpt$window_id;
         display_name: ost$name;
         file_name: amt$local_file_name;
         initial_call: boolean;
     VAR status: ost$status);

    CONST
      c$iou_name_size = 4,
      c$channel_name_size = 6,
      c$fix_line_count = 9,
      c$non_incremental = FALSE;

    TYPE
      t$iou_name = string (c$iou_name_size), {ex. IOU0
      t$channel_name = string (c$channel_name_size), {ex. CCH01A
      t$pp_statistics = record
        time: ost$free_running_clock,
        value: array [1 .. * ] of t$pp_statistic,
      recend,
      t$pp_statistic = record
        iou_name: t$iou_name,
        channel_name: t$channel_name,
        read_requests: integer,
        write_requests: integer,
        total_response_time: integer,
        seek_and_latency_time: integer,
        computed_data_transfer_time: integer,
{ calculatated, non-incremental values:
        avg_q_size: real,
        avg_response_time: real,
        avg_wait_in_q: real,
        pp_utilization: real,
        time_per_request: real,
      recend;

    TYPE
      t$strings = array [1 .. * ] of t$string,
      t$string = string (80);

    VAR
      v$title: [READ, oss$job_paged_literal] string (18) := 'I/O Summary';

{ Static variables

    VAR
      v$previous_data_for_display: [STATIC, oss$task_shared] boolean := FALSE,
      v$previous_pp_stats_p: [STATIC, oss$task_shared] ^t$pp_statistics := NIL,
      v$previous_total_reads: [STATIC, oss$task_shared] integer := 0,
      v$previous_total_writes: [STATIC, oss$task_shared] integer := 0,
      v$previous_reject_requests_full: [STATIC, oss$task_shared] integer := 0,
      v$previous_reject_unit_q_limit: [STATIC, oss$task_shared] integer := 0,
      v$system_line_info: [STATIC, oss$task_shared] ^oft$system_line_info := NIL;

    VAR
      display_control: clt$display_control,
      found: boolean,
      i: integer,
      ln: integer,
      pio_unit_p: ^ost$disk_unit_stats,
      pio_pp_stats_p: ^ost$disk_pp_stats,
      unit_count: integer,
      pp_count: integer,
      q_count: integer,
      q_count_lines: integer,
      str_p: ^t$strings,
      total_q_count: integer,
      total_reads: integer,
      total_writes: integer,
      uit: ^iot$unit_interface_table,
      un: integer,
      units: integer,
      vsn: rmt$recorded_vsn;

?? NEWTITLE := 'P$ABORT_HANDLER', EJECT ??

{ PURPOSE:
{   This procedure provides clean-up processing when a task abort occurs.

    PROCEDURE p$abort_handler
      (    condition: pmt$condition;
           condition_information_p: ^pmt$condition_information;
           save_area_p: ^ost$stack_frame_save_area;
       VAR handler_status: ost$status);

      VAR
        ignore_status: ost$status;

      IF wid = 0 THEN
        clp$close_display (display_control, ignore_status);
      IFEND;

    PROCEND p$abort_handler;
?? OLDTITLE ??
?? NEWTITLE := 'P$INIT_PP_STATISTICS', EJECT ??

    PROCEDURE p$init_pp_statistics
      (    pp_usage: ost$disk_pp_stats;
       VAR pp_statistics: t$pp_statistics);

      VAR
        i: integer,
        local_status: ost$status;

      pp_statistics.time := 0;
      FOR i := 1 TO UPPERBOUND (pp_usage.disk_pp_stats) DO
{IOU
        IF pp_usage.disk_pp_stats [i].iou_number = 0 THEN
          pp_statistics.value [i].iou_name := 'IOU0';
        ELSE
          pp_statistics.value [i].iou_name := 'IOU1';
        IFEND;

{CHANNEL
        clp$convert_integer_to_rjstring (pp_usage.disk_pp_stats [i].channel.number, 10, FALSE, '0',
              pp_statistics.value [i].channel_name (1, 5), local_status);
        IF NOT local_status.normal THEN
          pp_statistics.value [i].channel_name := '     ';
        ELSE
          IF pp_usage.disk_pp_stats [i].channel.concurrent THEN
            pp_statistics.value [i].channel_name (1, 3) := 'CCH';
          ELSE
            pp_statistics.value [i].channel_name (1, 3) := ' CH';
          IFEND;

          CASE pp_usage.disk_pp_stats [i].channel.port OF
          = cmc$port_a =
            pp_statistics.value [i].channel_name (6) := 'A';
          = cmc$port_b =
            pp_statistics.value [i].channel_name (6) := 'B';
          ELSE
            pp_statistics.value [i].channel_name (6) := ' ';
          CASEND;
        IFEND;

        pp_statistics.value [i].read_requests := 0;
        pp_statistics.value [i].write_requests := 0;
        pp_statistics.value [i].total_response_time := 0;
        pp_statistics.value [i].seek_and_latency_time := 0;
        pp_statistics.value [i].computed_data_transfer_time := 0;

      FOREND;

    PROCEND p$init_pp_statistics;
?? OLDTITLE ??
?? NEWTITLE := 'P$PUT_PP_STATISTICS', EJECT ??

    PROCEDURE p$put_pp_statistics
      (    pio_pp_stats: ost$disk_pp_stats;
       VAR previous_pp_stats: t$pp_statistics;
       VAR str: t$strings);

      VAR
        display_pp_statistic: t$pp_statistic,
        i: integer,
        j: integer,
        str_p: ^t$string,
        temp_str: string (10),
        time_increment: ost$free_running_clock,
        time_interval: real;

      time_increment := pio_pp_stats.time - previous_pp_stats.time;
      previous_pp_stats.time := pio_pp_stats.time;
      time_interval := $REAL (time_increment);

      FOR i := 1 TO UPPERBOUND (pio_pp_stats.disk_pp_stats) DO
        p$update_pp_statistic (time_interval, pio_pp_stats.disk_pp_stats [i], previous_pp_stats.value [i],
              display_pp_statistic);

        str_p := ^str [c$fix_line_count + q_count_lines + i];
        str_p^ (1, c$iou_name_size) := display_pp_statistic.iou_name;
        str_p^ (6, c$channel_name_size) := display_pp_statistic.channel_name;
        pmp$binary_to_ascii_fit (display_pp_statistic.read_requests, 10, 8, 8, str_p^ (19, 8));
        pmp$binary_to_ascii_fit (display_pp_statistic.write_requests, 10, 8, 8, str_p^ (28, 8));
        pmp$binary_to_ascii_fit (display_pp_statistic.read_requests + display_pp_statistic.write_requests, 10,
              9, 9, str_p^ (37, 9));

        STRINGREP (temp_str, j, display_pp_statistic.pp_utilization: 6: 1);
        str_p^ (12, 6) := temp_str (1, j);
        STRINGREP (temp_str, j, display_pp_statistic.time_per_request: 8: 2);
        str_p^ (47, 8) := temp_str (1, j);
        STRINGREP (temp_str, j, display_pp_statistic.avg_q_size: 8: 2);
        str_p^ (55, 8) := temp_str (1, j);
        STRINGREP (temp_str, j, display_pp_statistic.avg_response_time: 8: 2);
        str_p^ (64, 8) := temp_str (1, j);
        STRINGREP (temp_str, j, display_pp_statistic.avg_wait_in_q: 8: 2);
        str_p^ (73, 8) := temp_str (1, j);
      FOREND;

    PROCEND p$put_pp_statistics;
?? OLDTITLE ??
?? NEWTITLE := 'P$UPDATE_PP_STATISTIC', EJECT ??

    PROCEDURE p$update_pp_statistic
      (    time_interval: real;
           current: iot$disk_pp_usage;
       VAR previous: t$pp_statistic;
       VAR display: t$pp_statistic);

      VAR
        busy_total: real,
        i: integer,
        port: 0 .. 1,
        read_requests: integer,
        total_requests: integer,
        total_response_time: integer,
        write_requests: integer;

      display.iou_name := previous.iou_name;
      display.channel_name := previous.channel_name;

      read_requests := 0;
      write_requests := 0;
      total_response_time := 0;

      FOR port := 0 TO 1 DO
        FOR i := 0 TO 7 DO
          IF current.path_usage [port] [i].path_used THEN
            read_requests := read_requests + current.path_usage [port] [i].read_requests;
            write_requests := write_requests + current.path_usage [port] [i].write_requests;
            total_response_time := total_response_time + current.path_usage [port] [i].total_request_qtime;
          IFEND;
        FOREND;
      FOREND;

      display.read_requests := read_requests - previous.read_requests;
      previous.read_requests := read_requests;

      display.write_requests := write_requests - previous.write_requests;
      previous.write_requests := write_requests;

      display.total_response_time := total_response_time - previous.total_response_time;
      previous.total_response_time := total_response_time;

      display.seek_and_latency_time := current.seek_and_latency_time - previous.seek_and_latency_time;
      previous.seek_and_latency_time := current.seek_and_latency_time;

      display.computed_data_transfer_time := current.computed_data_transfer_time -
            previous.computed_data_transfer_time;
      previous.computed_data_transfer_time := current.computed_data_transfer_time;

      busy_total := $REAL (display.seek_and_latency_time + display.computed_data_transfer_time);
      IF time_interval <> 0.0 THEN
        display.pp_utilization := 100.0 * busy_total / time_interval;
      ELSE
        display.pp_utilization := 0.0;
      IFEND;

      total_requests := display.read_requests + display.write_requests;
      IF total_requests <> 0 THEN
        display.avg_response_time := $REAL (display.total_response_time) / $REAL (total_requests) / 1000.0;
        display.time_per_request := busy_total / $REAL (total_requests) / 1000.0;
        display.avg_wait_in_q := ($REAL (display.total_response_time) - busy_total) / $REAL (total_requests) /
              1000.0;
      ELSE
        display.avg_response_time := 0.0;
        display.time_per_request := 0.0;
        display.avg_wait_in_q := 0.0;
      IFEND;

      IF busy_total <> 0.0 THEN
        display.avg_q_size := ($REAL (display.total_response_time) / busy_total);
      ELSE
        display.avg_q_size := 0.0;
      IFEND;

    PROCEND p$update_pp_statistic;
?? OLDTITLE ??
?? EJECT ??

    status.normal := TRUE;

    IF wid = 0 THEN
      osp$establish_block_exit_hndlr (^p$abort_handler);
    IFEND;
    IF initial_call THEN
      ofp$open_display (file_name, wid, dpc$wc_sharing, dpc$wk_table, v$title, display_control, status);
      IF NOT status.normal THEN
        RETURN; {----->
      IFEND;
    IFEND;

    total_reads := 0;
    total_writes := 0;
    osp$get_pp_unit_count (pp_count, unit_count, status);
    IF unit_count = 0 THEN
      RETURN; {----->
    IFEND;

    PUSH pio_unit_p: [1 .. unit_count];
    osp$get_pio_unit_stats (c$non_incremental, pio_unit_p^, status);
    IF NOT status.normal THEN
      RETURN; {----->
    IFEND;

    PUSH pio_pp_stats_p: [1 .. pp_count];
    osp$get_pio_pp_stats (c$non_incremental, pio_pp_stats_p^, status);
    IF NOT status.normal THEN
      RETURN; {----->
    IFEND;

    IF (v$previous_pp_stats_p = NIL) OR (UPPERBOUND (v$previous_pp_stats_p^.value) <> pp_count) THEN
      IF v$previous_pp_stats_p <> NIL THEN
        FREE v$previous_pp_stats_p IN osv$task_shared_heap^;
        v$previous_pp_stats_p := NIL;
      IFEND;

      ALLOCATE v$previous_pp_stats_p: [1 .. pp_count] IN osv$task_shared_heap^;
      p$init_pp_statistics (pio_pp_stats_p^, v$previous_pp_stats_p^);
    IFEND;

{ Establish base values for the general statistics display if they do not already exist.
    IF NOT v$previous_data_for_display THEN
      ALLOCATE v$system_line_info IN osv$task_shared_heap^;
      v$system_line_info^.initialized := FALSE;
      v$previous_data_for_display := TRUE;
    IFEND;

{Count Units:
    q_count_lines := 0;
    FOR i := 1 TO UPPERBOUND (cmv$logical_unit_table^) DO
      uit := cmv$logical_unit_table^ [i].unit_interface_table;
      IF (uit <> NIL)
{   } AND (uit^.unit_type >= ioc$lowest_disk_unit) AND (uit^.unit_type <= ioc$highest_disk_unit)
{   } AND (NOT uit^.unit_status.disabled) THEN
        q_count_lines := q_count_lines + 1;
      IFEND;
    FOREND;
    q_count_lines := (q_count_lines + 4) DIV 5;

{ Set up the labels.
    PUSH str_p: [1 .. c$fix_line_count + pp_count + q_count_lines];
    str_p^ [02] := '      Unit Q Full:                          Total Reads:';
    str_p^ [03] := '   Request Q Full:                         Total Writes:';
    str_p^ [04] := 'Total Queue Count:                   Total Reads/Writes:';
    str_p^ [05] := '';
    str_p^ [06] := '               QUEUE COUNT BY VSN';
    FOR i := 1 TO q_count_lines + 1 DO
      str_p^ [i + 6] := '';
    FOREND;
    str_p^ [8 + q_count_lines] :=
          'IOU  Channel  PP    Read    Write     Total   ------------- Average ------------';
    str_p^ [9 + q_count_lines] :=
          'Name Name    Util Requests Requests  Requests Time/Req   QSize  RspTime  WaitInQ';

    FOR i := 1 TO pp_count DO
      str_p^ [i + c$fix_line_count + q_count_lines] := '';
    FOREND;

{ Set up the cpu idle-statistics and the NOS percentage.
    ofp$build_system_line (v$system_line_info^, str_p^ [1]);

{ get the I/O queue counts by logical unit
    IF cmv$logical_unit_table = NIL THEN
      RETURN; {----->
    IFEND;

    units := 1;
    un := 1;
    ln := 7;
    total_q_count := 0;
    FOR i := 1 TO UPPERBOUND (cmv$logical_unit_table^) DO
      uit := cmv$logical_unit_table^ [i].unit_interface_table;
      IF (uit <> NIL)
{   } AND (uit^.unit_type >= ioc$lowest_disk_unit) AND (uit^.unit_type <= ioc$highest_disk_unit)
{   } AND (NOT uit^.unit_status.disabled) THEN
        osp$get_rvsn_by_lun (uit^.logical_unit, vsn, found);
        IF NOT found THEN
          vsn := '      ';
        IFEND;

        str_p^ [ln] (un, 6) := vsn;
        str_p^ [ln] (un + 6, 1) := ':';

        q_count := uit^.queue_count;
        total_q_count := total_q_count + q_count;
        pmp$binary_to_ascii_fit (q_count, 10, 3, 3, str_p^ [ln] (un + 8, 2));
        units := units + 1;
        IF (units = 6) THEN
          units := 1;
          un := 1;
          ln := ln + 1;
        ELSE
          un := un + 14;
        IFEND;
      IFEND;
    FOREND;

{ Set up the input/output statistics.
    FOR i := 1 TO unit_count DO
      IF pio_unit_p^.disk_unit_stats [i].unit_used THEN
        total_writes := total_writes + pio_unit_p^.disk_unit_stats [i].write_requests +
              pio_unit_p^.disk_unit_stats [i].swap_out_requests;
        total_reads := total_reads + pio_unit_p^.disk_unit_stats [i].read_requests +
              pio_unit_p^.disk_unit_stats [i].swap_in_requests;
      IFEND;
    FOREND;

{ Totals
    pmp$binary_to_ascii_fit (total_q_count, 10, 10, 10, str_p^ [4] (20, 10));
    pmp$binary_to_ascii_fit (total_reads - v$previous_total_reads, 10, 10, 10, str_p^ [2] (58, 10));
    pmp$binary_to_ascii_fit (total_writes - v$previous_total_writes, 10, 10, 10, str_p^ [3] (58, 10));
    pmp$binary_to_ascii_fit (total_reads + total_writes - v$previous_total_reads - v$previous_total_writes,
          10, 10, 10, str_p^ [4] (58, 10));

{ Display rejects
    pmp$binary_to_ascii_fit (iov$reject_unit_queue_limit - v$previous_reject_unit_q_limit, 10, 10, 10,
          str_p^ [2] (20, 10));
    pmp$binary_to_ascii_fit (iov$reject_requests_full - v$previous_reject_requests_full, 10, 10, 10,
          str_p^ [3] (20, 10));

    v$previous_total_reads := total_reads;
    v$previous_total_writes := total_writes;
    v$previous_reject_requests_full := iov$reject_requests_full;
    v$previous_reject_unit_q_limit := iov$reject_unit_queue_limit;

    p$put_pp_statistics (pio_pp_stats_p^, v$previous_pp_stats_p^, str_p^);

{ Display the results.
    IF wid <> 0 THEN
      dpp$clear_window (wid, status);
      FOR i := 1 TO UPPERBOUND (str_p^) DO
        dpp$put_next_line (wid, str_p^ [i], status);
        IF NOT status.normal THEN
          RETURN; {----->
        IFEND;
      FOREND
    ELSE
      FOR i := 1 TO UPPERBOUND (str_p^) DO
        clp$put_display (display_control, str_p^ [i], clc$trim, status);
        IF NOT status.normal THEN
          RETURN; {----->
        IFEND;
      FOREND;
      clp$close_display (display_control, status);
      osp$disestablish_cond_handler;
    IFEND;

  PROCEND ofp$io_summary_display;
?? OLDTITLE ??
MODEND ofm$io_summary_display

