?? RIGHT := 110 ??
*copyc osd$default_pragmats
?? NEWTITLE := 'NOS/VE PERFORMANCE TOOLS : ANALYZE FILE SERVER KEYPOINTS', EJECT ??
MODULE dfm$analyze_server_keypoints;

{  PURPOSE:
{  This module contains the code necessary to analyze
{  raw keypoints generated via the commands
{    SET_SYSTEM_ATTRIBUTE FILE_SERVER_INFO_ENABLED ON
{    RESERVE_KEYPOINT_ENVIRONMENT CF=$USER.KP MM=11 JM=11 KC=100000
{    START_KEYPOINT_COLLECTION
{      - Run the benchmark, to generate keypoints
{    STOP_KEYPOINT_COLLECTION
{    RELEASE_KEYPOINT_ENVIRONMENT
{  The cf (collection_file) may be input to the keypoint_file (kp) of
{  this procedure.
{
{  ANALYZE_SERVER_KEYPOINTS
{  keypoint_file, kf          : file = $required
{     This is the keypoint collection_file to be analyzed.
{  display_options, ..
{  display_option, do         : list of key trace, t, intervals, i, ..
{                                   interval_histogram, ih, summary, s, all ..
{                             = summary
{      trace - Displays each keypoint issued and its data.
{         Usually a huge listing.
{      summary - Displays the total of the keypoints for each catagory
{         ($SYSTEM, REMOTE) of file or catalog.  At the end is a total
{          that sums the file and io activity.
{      intervals - Gives the sum of the requests for each interval of the
{          length selected by interval_microseconds.  This will display
{          for example, the number of operations per second.
{          This may be a large listing if there were alot of intervals in
{          the run.
{      interval_histogram - This summarizes the distribution of the
{           intervals in a histogram.  For example, was the distribution
{           of number of attaches per second.
{  interval_catagory, ic      : key of, total, remote_catalog, remote_file, ..
{                                   system_catalog, system_file, all = remote_file
{       Select a subset of the information.
{  interval_microseconds, im  : integer -1152921504606846974..1152921504606846975 ..
{                             = 1000000
{        Specifies the size of the interval.
{  title, t                   : string = ' Analyze Server Keypoints'
{        This strting is displayed on the listing.
{  output, o                  : file = $listing
{  status                     : var of status = $optional
{
{
{  These keypoints are emitted by various parts of the
{  operating system.  There must be an agreed upon data format for
{  each server keypoint omitted by the operating system and this
{  program.
{    REMOTE = TRUE,  local mainframe = FALSE
{    CATALOG = TRUE, permanent file = FALSE
{
{  The time processing part of this program assumes that there
{  is less than 268 seconds between arriving keypoints.
{  The clock field of the keypoint rolls over every 268 seconds.
{

?? NEWTITLE := '  GLOBAL XREFS', EJECT ??
?? PUSH (LISTEXT := ON) ??
*copyc amp$close
*copyc amp$get_segment_pointer
*copyc amp$open
*copyc clp$close_display
*copyc clp$get_value
*copyc clp$new_display_page
*copyc clp$open_display
*copyc clp$put_display
*copyc clp$scan_parameter_list
*copyc mmp$create_scratch_segment
*copyc osp$set_status_abnormal
*copyc pmp$format_compact_date
*copyc pmp$format_compact_time
*copyc pup$crack_name_list
*copyc pup$determine_if_all_selected
?? POP ??
?? OLDTITLE ??
?? NEWTITLE := '  GLOBAL TYPES', EJECT ??
*copyc gft$system_file_identifier
?? SKIP := 9 ??
*copyc iot$io_function
?? SKIP := 9 ??
*copyc osk$common_keypoint_definitions
?? SKIP := 9 ??
*copyc ost$keypoint_environment
?? TITLE := ' FILE SERVER TYPES ', EJECT ??
*copyc dfd$file_server_info
?? SKIP := 9 ??
*copyc dfk$file_server_info_keypoints
?? TITLE := ' SUMMARY TABLES ', EJECT ??

  TYPE
    request_size_ordinal = (one_page, two_pages, three_pages, four_pages, five_to_nine_pages, ten_to_19_pages,
      twenty_to_29_pages, thirty_and_up_pages);

  TYPE
    request_size_range = one_page .. thirty_and_up_pages;




  TYPE
    io_function_record = record
      total_request_count: integer,
      total_page_count: integer,
      request_size_distribution: array [request_size_range] of integer,
    recend;

  TYPE
    io_functions = ioc$read_page .. ioc$keypoint_io;

  VAR
    non_pf_io_summary: array [io_functions] of io_function_record;

  VAR
    non_pf_close_count: integer := 0,
    non_pf_open_count: integer := 0;

?? SKIP := 8 ??
  { Catalog access summary

  VAR
    total_path_accesses: integer := 0,
    remote_path_accesses: integer := 0,
    accesses_for_read: integer := 0,
    total_catalog_depth: integer := 0,
    total_remote_cat_depth: integer := 0,
    accesses_by_owner: integer := 0;

?? EJECT ??

  { file summaries

  TYPE
    file_summary = record
      number_of_attaches: integer,
      number_of_creates: integer,
      number_of_opens: integer,
      number_of_closes: integer,
      number_of_deletes: integer,
      number_of_returns: integer,

      io_summary: array [io_functions] of io_function_record,

      { This is the attach of a file      not already attached
      number_of_unique_attaches: integer,
      { unique_return refers to the last return of the file in the system
      number_of_unique_returns: integer,

      { The following field is only used in time interval data
      transfer_count: integer,
      transfer_size: integer,

      { The following fields are not      used in time interval  records of this type
      {average_time_attached := total_time_all_attaches/ number_of_returns
      total_time_all_attaches: integer,
      current_attached: integer,
      max_number_attached: integer,
    recend;

  VAR
    attach_summary_table: array [boolean {local, remote} ] of array [boolean {file, catalog} ] of
      file_summary;

  VAR
    total_summary: file_summary;

  VAR
    initialized_summary: file_summary;

?? EJECT ??
{   time event analysis figures

  VAR
    overflowed_amount: integer := 0,
    first_keypoint_clock: 0 .. 0fffffff(16) := 0,
    last_keypoint_clock: 0 .. 0fffffff(16) := 0,
    current_keypoint_time: integer := 0,
    interval_number: integer := 0,
    time_start_of_run: integer := 0,
    time_start_of_interval: integer := 0,
    time_interval: integer := 0;

  VAR
    interval_path_accesses: integer := 0,
    interval_remote_path_accesses: integer := 0,
    interval_accesses_for_read: integer := 0,
    interval_total_catalog_depth: integer := 0,
    interval_total_remote_cat_depth: integer := 0,
    interval_accesses_by_owner: integer := 0;

  VAR
    time_interval_total: file_summary;

  TYPE
    low_or_high = (low, high),

    low_to_high = low .. high;

  VAR
    interval_range: array [low_to_high] of file_summary;

  CONST
    number_of_distributions = 20;

  VAR
    interval_distribution: array [0 .. number_of_distributions] of file_summary;

  VAR
    time_interval_summary_table: array [boolean {local, remote} ] of array [boolean {file, catalog} ] of
      file_summary;

  VAR
    interval_selection: array [boolean {local, remote} ] of array [boolean {file, catalog} ] of boolean :=
      [[FALSE, FALSE], [FALSE, FALSE]],

    total_interval_selected: boolean := FALSE;

  CONST
    attach_request_transfer_size = 400,
    create_file_transfer_size = 400,
    open_request_transfer_size = 100,
    close_request_transfer_size = 100,
    delete_request_transfer_size = 400,
    return_request_transfer_size = 100,
    io_page_size = 4096;



?? EJECT ??

  TYPE
    attached_file_entry = record
      case entry_type: (valid_entry, free_entry, damaged_entry) of
      = valid_entry, damaged_entry =
        catalog: {or file} boolean,
        remote: {or local} boolean,
        time_initially_attached: integer,
        attach_count: integer,
        number_of_opens: integer,
      = free_entry =
        ,
      casend,
    recend;

  VAR
    attached_file_table: array [gft$file_descriptor_index] of attached_file_entry;

?? TITLE := '  DISPLAY_TABLES', EJECT ??

  VAR
    display_control: clt$display_control;

  VAR
    title_string: string (72) := ' Process server keypoints';

  CONST
    integer_field_length = 6;

  TYPE
    display_options = (trace, summary, intervals, interval_histogram),

    display_selections = set of display_options;

  VAR
    display_option_selection_table: [READ] array [1 .. 8] of record
      name: ost$name,
      display_option_value: display_options,
    recend := [
      {} ['TRACE                          ', trace],
      {} ['T                              ', trace],
      {} ['INTERVALS                      ', intervals],
      {} ['I                              ', intervals],
      {} ['INTERVAL_HISTOGRAM             ', interval_histogram],
      {} ['IH                             ', interval_histogram],
      {} ['SUMMARY                        ', summary],
      {} ['S                              ', summary]];

  VAR
    interval_option_table: [READ] array [1 .. 6] of record
      name: ost$name,
      selection: array [boolean {local, remote} ] of array [boolean {file, catalog} ] of boolean,
    recend := [
      {} ['ALL                            ', [[TRUE, TRUE], [TRUE, TRUE]]],
      {} ['TOTAL                          ', [[FALSE, FALSE], [FALSE, FALSE]]],
      {} ['SYSTEM_FILE                    ', [[TRUE, FALSE], [FALSE, FALSE]]],
      {} ['SYSTEM_CATALOG                 ', [[FALSE, TRUE], [FALSE, FALSE]]],
      {} ['REMOTE_FILE                    ', [[FALSE, FALSE], [TRUE, FALSE]]],
      {} ['REMOTE_CATALOG                 ', [[FALSE, FALSE], [FALSE, TRUE]]]];

  VAR
    keypoint_name_table: [READ] array [dfk$file_server_info_base .. (dfk$file_server_info_base + 8)] of
      ost$name := [
      {} 'dfk$attach_info',
      {} 'dfk$catalog_access_info',
      {} 'dfk$close_info',
      {} 'dfk$create_info',
      {} 'dfk$delete_info',
      {} 'dfk$detach_sfid',
      {} 'dfk$open_info',
      {} 'dfk$pager_io_info',
      {} 'dfk$sfid'];

  VAR
    residence_name_table: [READ] array [gft$table_residence] of ost$name := [
      {} ' gfc$tr_null_residence',
      {} ' gfc$tr_system',
      {} ' gfc$tr_job',
      {} ' gfc$tr_system_wait_recovery'];

{ DECK: IOT$IO_FUNCTION (Definitions for interface to physical IO requests)

  VAR
    io_function_names: [READ] array [io_functions] of ost$name := [
      {} ' ioc$read_page',
      {} ' ioc$write_page',
      {} ' ioc$explicit_read',
      {} ' ioc$explicit_write',
      {} ' ioc$swap_in',
      {} ' ioc$swap_out',
      {} ' ioc$compare_swap',
      {} ' ioc$write_verify',
      {} ' ioc$read_uft',
      {} ' ioc$read_mass_storage',
      {} ' ioc$write_mass_storage',
      {} ' ioc$no_io',
      {} ' ioc$write_locked_page',
      {} ' ioc$keypoint_io'];

  VAR
    remote_name: [READ] array [boolean] of string (10) := [
      {} ' $SYSTEM',
      {} ' REMOTE'];

  VAR
    catalog_name: [READ] array [boolean] of string (10) := [
      {} ' FILE ',
      {} ' CATALOG'];

  VAR
    request_size_display: [READ] array [request_size_range] of string (18) := [
      {} ' 1 page  ',
      {} ' 2 pages  ',
      {} ' 3 pages  ',
      {} ' 4 pages  ',
      {} ' 5 - 9 pages  ',
      {} ' 10 - 19 pages  ',
      {} ' 20 - 29 pages  ',
      {} ' 30 -> pages  '];

  VAR
    interval_header_table: [READ] array [1 .. 14] of record
      size: 0 .. 40,
      header: string (40),
    recend := [
      {} [10, ' INTERVAL '],
      {} [10, ' REM PATHS'],
      {} [6, '  ATTF '],
      {} [6, '  CREF '],
      {} [6, '  OPEN '],
      {} [6, '  CLOS '],
      {} [6, '  DELE '],
      {} [6, '  RETR '],
      {} [10, ' READ RC'],
      {} [10, ' READ PC'],
      {} [10, ' WRIT RC'],
      {} [10, ' WRIT PC'],
      {} [10, ' TRAN CT'],
      {} [10, ' TRAN SI']];



?? TITLE := '  [XDCL] DFP$ANALYZE_SERVER_KEYPOINTS', EJECT ??

  PROCEDURE [XDCL] dfp$analyze_server_keypoints (parameter_list: clt$parameter_list;
    VAR status: ost$status);


{ pdt analyze_server_keypoints (
{  keypoint_file, kf: file = $required
{  display_options, display_option, do: list of key trace, t, intervals, i, interval_histogram, ih, summary,..
{  s, all = summary
{  interval_catagory, ic: key of total, remote_catalog, remote_file, system_catalog, system_file, all ..
{   = remote_file
{  interval_microseconds, im: integer  = 1000000
{  title, t: string = ' Analyze Server Keypoints'
{  output, o: file = $listing
{  status)

?? PUSH (LISTEXT := ON) ??

    VAR
      analyze_server_keypoints: [STATIC, READ, cls$pdt] clt$parameter_descriptor_table :=
        [^analyze_server_keypoints_names, ^analyze_server_keypoints_params];

    VAR
      analyze_server_keypoints_names: [STATIC, READ, cls$pdt_names_and_defaults] array [1 .. 14] of
        clt$parameter_name_descriptor := [['KEYPOINT_FILE', 1], ['KF', 1], ['DISPLAY_OPTIONS', 2], [
        'DISPLAY_OPTION', 2], ['DO', 2], ['INTERVAL_CATAGORY', 3], ['IC', 3], ['INTERVAL_MICROSECONDS', 4],
        ['IM', 4], ['TITLE', 5], ['T', 5], ['OUTPUT', 6], ['O', 6], ['STATUS', 7]];

    VAR
      analyze_server_keypoints_params: [STATIC, READ, cls$pdt_parameters] array [1 .. 7] of
        clt$parameter_descriptor := [

{ KEYPOINT_FILE KF }
      [[clc$required], 1, 1, 1, 1, clc$value_range_not_allowed, [NIL, clc$file_value]],

{ DISPLAY_OPTIONS DISPLAY_OPTION DO }
      [[clc$optional_with_default, ^analyze_server_keypoints_dv2], 1, clc$max_value_sets, 1, 1,
        clc$value_range_not_allowed, [^analyze_server_keypoints_kv2, clc$keyword_value]],

{ INTERVAL_CATAGORY IC }
      [[clc$optional_with_default, ^analyze_server_keypoints_dv3], 1, 1, 1, 1, clc$value_range_not_allowed,
        [^analyze_server_keypoints_kv3, clc$keyword_value]],

{ INTERVAL_MICROSECONDS IM }
      [[clc$optional_with_default, ^analyze_server_keypoints_dv4], 1, 1, 1, 1, clc$value_range_not_allowed,
        [NIL, clc$integer_value, - 9223372036854775806, 9223372036854775807]],

{ TITLE T }
      [[clc$optional_with_default, ^analyze_server_keypoints_dv5], 1, 1, 1, 1, clc$value_range_not_allowed,
        [NIL, clc$string_value, 0, osc$max_string_size]],

{ OUTPUT O }
      [[clc$optional_with_default, ^analyze_server_keypoints_dv6], 1, 1, 1, 1, clc$value_range_not_allowed,
        [NIL, clc$file_value]],

{ STATUS }
      [[clc$optional], 1, 1, 1, 1, clc$value_range_not_allowed, [NIL, clc$variable_reference,
        clc$array_not_allowed, clc$status_value]]];

    VAR
      analyze_server_keypoints_kv2: [STATIC, READ, cls$pdt_names_and_defaults] array [1 .. 9] of ost$name :=
        ['TRACE', 'T', 'INTERVALS', 'I', 'INTERVAL_HISTOGRAM', 'IH', 'SUMMARY', 'S', 'ALL'];

    VAR
      analyze_server_keypoints_kv3: [STATIC, READ, cls$pdt_names_and_defaults] array [1 .. 7] of ost$name :=
        ['OF', 'TOTAL', 'REMOTE_CATALOG', 'REMOTE_FILE', 'SYSTEM_CATALOG', 'SYSTEM_FILE', 'ALL'];

    VAR
      analyze_server_keypoints_dv2: [STATIC, READ, cls$pdt_names_and_defaults] string (7) := 'summary';

    VAR
      analyze_server_keypoints_dv3: [STATIC, READ, cls$pdt_names_and_defaults] string (11) := 'remote_file';

    VAR
      analyze_server_keypoints_dv4: [STATIC, READ, cls$pdt_names_and_defaults] string (7) := '1000000';

    VAR
      analyze_server_keypoints_dv5: [STATIC, READ, cls$pdt_names_and_defaults] string (27) :=
        ''' Analyze Server Keypoints''';

    VAR
      analyze_server_keypoints_dv6: [STATIC, READ, cls$pdt_names_and_defaults] string (8) := '$listing';

?? POP ??

    VAR
      catalog: boolean,
      display_selection_set: display_selections,
      first_keypoint: boolean,
      keypoint_file_id: amt$file_identifier,
      keypoint_file_value: clt$value,
      number_of_keypoints: integer,
      output_value: clt$value,
      p_interval_summary: ^file_summary,
      pointer: amt$segment_pointer,
      p_intervals: ^SEQ ( * ),
      p_class_15_keypoint: ^ost$class_15_keypoint,
      p_keypoint: ^ost$keypoint,
      p_keypoint_file: ^SEQ ( * ),
      p_sfid_keypoint: ^ost$keypoint,
      p_word_alignment: ^array [1 .. * ] of cell,
      read_attribute: array [1 .. 1] of amt$file_item,
      remote: boolean,
      segment_pointer: amt$segment_pointer,
      word_alignment_length: integer;

?? EJECT ??

    number_of_keypoints := 0;
    first_keypoint := TRUE;
    initialize_summary_tables;

    { Crack the parameters, and prepare the files for access
    clp$scan_parameter_list (parameter_list, analyze_server_keypoints, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;

    clp$get_value ('KEYPOINT_FILE', 1, 1, clc$low, keypoint_file_value, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;
    read_attribute [1].key := amc$access_mode;
    read_attribute [1].access_mode := $pft$usage_selections [pfc$read];
    amp$open (keypoint_file_value.file.local_file_name, amc$segment, ^read_attribute, keypoint_file_id,
          status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;
    amp$get_segment_pointer (keypoint_file_id, amc$sequence_pointer, segment_pointer, status);

    crack_display_options ('DISPLAY_OPTIONS', display_selection_set, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;

    IF (intervals IN display_selection_set) OR (interval_histogram IN display_selection_set) THEN
      crack_interval_catagory ('INTERVAL_CATAGORY', status);
      IF NOT status.normal THEN
        RETURN;
      IFEND;
      clp$get_value ('INTERVAL_MICROSECONDS', 1, 1, clc$low, output_value, status);
      IF NOT status.normal THEN
        RETURN;
      IFEND;
      time_interval := output_value.int.value;
      display_integer (' Time interval (microseconds) : ', time_interval);
    IFEND;

    IF (interval_histogram IN display_selection_set) THEN
      mmp$create_scratch_segment (amc$sequence_pointer, mmc$as_sequential, pointer, status);
      IF NOT status.normal THEN
        RETURN;
      IFEND;
      initialize_interval_range;
      p_intervals := pointer.sequence_pointer;
      RESET p_intervals;
    IFEND;
    clp$get_value ('OUTPUT', 1, 1, clc$low, output_value, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;
    clp$open_display (output_value.file, NIL, display_control, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;

    clp$get_value ('TITLE', 1, 1, clc$low, output_value, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;
    title_string := output_value.str.value (1, output_value.str.size);
    display (' ----------------------------------------');
    display (title_string);
    IF intervals IN display_selection_set THEN
      display_time (' Time interval  : ', time_interval);
      display_time_interval_title;
    IFEND;

    word_alignment_length := 8 - (#SIZE (ost$class_15_keypoint) MOD 8);
    IF word_alignment_length = 8 THEN
      word_alignment_length := 0;
    IFEND;

    p_keypoint_file := segment_pointer.sequence_pointer;
    RESET p_keypoint_file;

    { This loop attains all the keypoints on the keypoint file.

  /files_open/
    WHILE TRUE DO
      NEXT p_keypoint IN p_keypoint_file;
      IF p_keypoint = NIL THEN
        EXIT /files_open/;
      IFEND;

      IF p_keypoint^.keypoint_class = osk$pmf_control THEN
        { Skip over the pmf keypoint, and position to the next
        {keypoint (word aligned).

        RESET p_keypoint_file TO p_keypoint;
        NEXT p_class_15_keypoint IN p_keypoint_file;
        IF p_class_15_keypoint = NIL THEN
          EXIT /files_open/
        IFEND;
        IF trace IN display_selection_set THEN
          display_pmf_keypoint (p_class_15_keypoint^);
        IFEND;
        IF word_alignment_length <> 0 THEN { skip to next keypoint }
          NEXT p_word_alignment: [1 .. word_alignment_length] IN p_keypoint_file;
        IFEND;
        CYCLE /files_open/;
      IFEND;

      IF p_keypoint^.keypoint_class = dfk$file_server_info_class THEN
        number_of_keypoints := number_of_keypoints + 1;

        { handle keypoint clock
        {current _keypoint_time is the               number of microseconds  since  the first keypoint
        IF first_keypoint THEN
          first_keypoint := FALSE;
          time_start_of_run := 0;
          time_start_of_interval := 0;
          interval_number := 1;
          overflowed_amount := 0;
          first_keypoint_clock := p_keypoint^.clock;
        ELSEIF p_keypoint^.clock < last_keypoint_clock THEN
          { overflow
          overflowed_amount := overflowed_amount + 0fffffff(16);
        IFEND;
        current_keypoint_time := p_keypoint^.clock + overflowed_amount - first_keypoint_clock;
        last_keypoint_clock := p_keypoint^.clock;
        IF current_keypoint_time >= (time_start_of_interval + time_interval) THEN
          { new time interval
          IF intervals IN display_selection_set THEN
            display_time_interval;
          IFEND;
          IF interval_histogram IN display_selection_set THEN
            NEXT p_interval_summary IN p_intervals;
            IF total_interval_selected THEN
              display_time_interval_line (time_interval_total);
              record_interval_range (time_interval_total);
              p_interval_summary^ := time_interval_total;
            ELSE
              FOR remote := FALSE TO TRUE DO
                FOR catalog := FALSE TO TRUE DO
                  IF interval_selection [remote] [catalog] THEN
                    record_interval_range (time_interval_summary_table [remote] [catalog]);
                    p_interval_summary^ := time_interval_summary_table [remote] [catalog];
                  IFEND;
                FOREND;
              FOREND;
            IFEND;
          IFEND;
          time_start_of_interval := time_start_of_interval + time_interval;
          interval_number := 1 + interval_number;

          { re-initalize the interval tables
          time_interval_total := initialized_summary;
          FOR remote := FALSE TO TRUE DO
            FOR catalog := FALSE TO TRUE DO
              time_interval_summary_table [remote] [catalog] := initialized_summary;
            FOREND;
          FOREND;
          interval_path_accesses := 0;
          interval_remote_path_accesses := 0;
          interval_accesses_for_read := 0;
          interval_total_catalog_depth := 0;
          interval_total_remote_cat_depth := 0;
          interval_accesses_by_owner := 0;
        IFEND;

        CASE p_keypoint^.keypoint_code OF
        = dfk$attach_info =
          { Imbedded locations:
          {pfp$attach_permanent_file\pfm$file_system_interfaces
          {Added remote_catalog boolean                                    on  pfp$attach_catalog
          {pfp$physically_attach_catalog, pfp$access_next_catalog
          {pfp$internal_access_object

          NEXT p_sfid_keypoint IN p_keypoint_file;
          IF p_sfid_keypoint = NIL THEN
            EXIT /files_open/;
          ELSEIF p_sfid_keypoint^.keypoint_code <> dfk$sfid THEN
            display (' unexpected keypoint found - after attach ');
            display_unknown_keypoint (p_sfid_keypoint^);
            CYCLE /files_open/;
          IFEND;
          IF trace IN display_selection_set THEN
            display_file_operation_keypoint (p_keypoint^);
            display_sfid_keypoint (p_sfid_keypoint^);
          IFEND;
          record_attach (p_keypoint^, p_sfid_keypoint^, FALSE);

        = dfk$create_info =
          { Imbedded locations:
          {modified pfp$create_permanent_file to have path
          {Modify pfp$create_catalog_object to have path
          NEXT p_sfid_keypoint IN p_keypoint_file;
          IF p_sfid_keypoint = NIL THEN
            EXIT /files_open/;
          ELSEIF p_sfid_keypoint^.keypoint_code <> dfk$sfid THEN
            display (' unexpected keypoint found  - after create');
            display_unknown_keypoint (p_sfid_keypoint^);
            CYCLE /files_open/;
          IFEND;
          IF trace IN display_selection_set THEN
            display_file_operation_keypoint (p_keypoint^);
            display_sfid_keypoint (p_sfid_keypoint^);
          IFEND;
          record_attach (p_keypoint^, p_sfid_keypoint^, TRUE);

        = dfk$catalog_access_info =
          { Imbedded locations:
          {pfp$get_catalog\pfm$catalog_access_methods
          {pfp$internal_access_object
          record_catalog_access_info (p_keypoint^);
          IF trace IN display_selection_set THEN
            display_catalog_access_keypoint (p_keypoint^);
          IFEND;

        = dfk$detach_sfid =
          { Imbedded locations:
          {pfp$detach_permanent_file\pfm$file_system_interfaces
          {physically_detach_catalog\pfm$file_system_interfaces
          record_detach (p_keypoint^);
          IF trace IN display_selection_set THEN
            display_sfid_keypoint (p_keypoint^);
          IFEND;

        = dfk$pager_io_info =
          { Imbedded locations:
          {iop$pager_io\iom$queue_request
          NEXT p_sfid_keypoint IN p_keypoint_file;
          IF p_sfid_keypoint = NIL THEN
            EXIT /files_open/;
          ELSEIF p_sfid_keypoint^.keypoint_code <> dfk$sfid THEN
            display (' unexpected keypoint found - after pager io');
            display_unknown_keypoint (p_sfid_keypoint^);
            CYCLE /files_open/;
          IFEND;
          record_pager_io (p_keypoint^, p_sfid_keypoint^);
          IF trace IN display_selection_set THEN
            display_io_keypoint (p_keypoint^);
            display_sfid_keypoint (p_sfid_keypoint^);
          IFEND;

        = dfk$open_info =
          { Imbedded locations:
          {mmp$Open_file_segment\mmm$segment_manager_job_temp
          IF trace IN display_selection_set THEN
            display_sfid_keypoint (p_keypoint^);
          IFEND;
          record_open (p_keypoint^);


        = dfk$close_info =
          { Imbedded locations:
          {mmp$close_segment\mmm$segment_manager_job_temp
          IF trace IN display_selection_set THEN
            display_sfid_keypoint (p_keypoint^);
          IFEND;
          record_close (p_keypoint^);

        = dfk$delete_info =
          { Imbedded locations:
          {purge_cycle\pfm$r2_request_processor
          {pfp$destroy_catalog
          IF trace IN display_selection_set THEN
            display_file_operation_keypoint (p_keypoint^);
          IFEND;
          convert_keypoint_to_operation (p_keypoint^, catalog, remote);
          IF catalog THEN
            { A delete for a catalog is accompanied with an sfid
            {which must be used to determine remote or local.
            NEXT p_sfid_keypoint IN p_keypoint_file;
            IF p_sfid_keypoint = NIL THEN
              EXIT /files_open/;
            ELSEIF p_sfid_keypoint^.keypoint_code <> dfk$sfid THEN
              display (' unexpected keypoint found  - delete_catalog');
              display_unknown_keypoint (p_sfid_keypoint^);
              CYCLE /files_open/;
            IFEND;
            IF trace IN display_selection_set THEN
              display_sfid_keypoint (p_sfid_keypoint^);
            IFEND;
            record_delete_catalog (remote, p_sfid_keypoint^);
          ELSE { file
            record_delete_file (remote);
          IFEND;

        ELSE
          display (' Unexpected keypoint code');
          display_unknown_keypoint (p_sfid_keypoint^);
        CASEND;
      ELSE { non server keypoint
        IF trace IN display_selection_set THEN
          display_unknown_keypoint (p_keypoint^);
        IFEND;
      IFEND;
    WHILEND /files_open/;

    display_integer (' Total number of keypoints  (or pairs) = ', number_of_keypoints);
    display_time (' Time of run  = ', current_keypoint_time);

    IF interval_histogram IN display_selection_set THEN
      display_time (' Time interval  : ', time_interval);
      display_interval_histogram ((interval_number - 1), p_intervals);
    IFEND;

    IF summary IN display_selection_set THEN
      display_summary_tables;
    IFEND;

    { close files }
    clp$close_display (display_control, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;
    amp$close (keypoint_file_id, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;
  PROCEND dfp$analyze_server_keypoints;
  ?? TITLE := ' compute_transfer_totals', EJECT ??

  PROCEDURE compute_transfer_totals (summary: file_summary;
    VAR transfer_count: integer;
    VAR transfer_size: integer);


    VAR
      io_func: io_functions;


    transfer_count := 0;
    transfer_size := 0;

    transfer_count := transfer_count + summary.number_of_attaches;
    transfer_size := transfer_size + summary.number_of_attaches * attach_request_transfer_size;

    transfer_count := transfer_count + summary.number_of_creates;
    transfer_size := transfer_size + summary.number_of_creates * create_file_transfer_size;

    transfer_count := transfer_count + summary.number_of_opens;
    transfer_size := transfer_size + summary.number_of_opens * open_request_transfer_size;

    transfer_count := transfer_count + summary.number_of_closes;
    transfer_size := transfer_size + summary.number_of_closes * close_request_transfer_size;

    transfer_count := transfer_count + summary.number_of_deletes;
    transfer_size := transfer_size + summary.number_of_deletes * delete_request_transfer_size;


    transfer_count := transfer_count + summary.number_of_returns;
    transfer_size := transfer_size + summary.number_of_returns * return_request_transfer_size;

    FOR io_func := LOWERVALUE (io_func) TO UPPERVALUE (io_func) DO
      transfer_count := transfer_count + summary.io_summary [io_func].total_request_count;
      transfer_size := transfer_size + summary.io_summary [io_func].total_page_count * io_page_size;
    FOREND;
  PROCEND compute_transfer_totals;
  ?? TITLE := 'convert_keypoint_to_cat', EJECT ??

  PROCEDURE convert_keypoint_to_cat (keypoint: ost$keypoint;
    VAR remote_catalog: boolean;
    VAR catalog_owner: boolean;
    VAR catalog_depth: integer;
    VAR read_access: boolean);

    VAR
      data_converter: dft$keypoint_catalog_summary;

    data_converter.keypoint_data := keypoint.keypoint_data;
    remote_catalog := data_converter.remote_catalog;
    catalog_owner := data_converter.catalog_owner;
    catalog_depth := data_converter.catalog_depth;
    read_access := data_converter.read_access;
  PROCEND convert_keypoint_to_cat;

?? TITLE := 'convert_keypoint_to_io_function', EJECT ??

  PROCEDURE convert_keypoint_to_io_function (keypoint: ost$keypoint;
    VAR io_function: iot$io_function;
    VAR page_count: integer);

    VAR
      data_converter: dft$keypoint_pager_io;

    data_converter.keypoint_data := keypoint.keypoint_data;
    io_function := data_converter.io_function;
    page_count := data_converter.pages;

  PROCEND convert_keypoint_to_io_function;

?? TITLE := '    convert_keypoint_to_operation ', EJECT ??

  PROCEDURE convert_keypoint_to_operation (keypoint: ost$keypoint;
    VAR catalog: boolean;
    VAR remote: boolean);

    VAR
      data_converter: dft$keypoint_file_operation;

    data_converter.keypoint_data := keypoint.keypoint_data;
    catalog := data_converter.catalog;
    remote := data_converter.remote;
  PROCEND convert_keypoint_to_operation;
?? TITLE := '    convert_keypoint_to_sfid ', EJECT ??

  PROCEDURE convert_keypoint_to_sfid (keypoint: ost$keypoint;
    VAR file_entry_index: gft$file_descriptor_index;
    VAR residence: gft$table_residence);

    VAR
      data_converter: dft$keypoint_sfid;

    data_converter.keypoint_data := keypoint.keypoint_data;
    file_entry_index := data_converter.file_entry_index;
    residence := data_converter.residence;
  PROCEND convert_keypoint_to_sfid;
?? TITLE := ' convert_page_count_to_ordinal', EJECT ??

  PROCEDURE convert_page_count_to_ordinal (page_count: integer;
    VAR request_size: request_size_ordinal);

    CASE page_count OF
    = 1 =
      request_size := one_page;
    = 2 =
      request_size := two_pages;
    = 3 =
      request_size := three_pages;
    = 4 =
      request_size := four_pages;
    = 5 .. 9 =
      request_size := five_to_nine_pages;
    = 10 .. 19 =
      request_size := ten_to_19_pages;
    = 20 .. 29 =
      request_size := twenty_to_29_pages
    ELSE
      request_size := thirty_and_up_pages;
    CASEND;
  PROCEND convert_page_count_to_ordinal;
  ?? TITLE := ' crack_display_options', EJECT ??

  PROCEDURE crack_display_options (parameter_name: string ( * );
    VAR display_selection: display_selections;
    VAR status: ost$status);

    VAR
      all_selected: boolean,
      display_option: display_options,
      i: 1 .. 20,
      name_list_container: SEQ (REP 20 of ost$name),
      p_name_list: ^array [1 .. * ] of ost$name;

    pup$crack_name_list (parameter_name, name_list_container, p_name_list, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;

    pup$determine_if_all_selected (p_name_list^, parameter_name, all_selected, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;

    IF all_selected THEN
      display_selection := - $display_selections [];
    ELSE
      display_selection := $display_selections [];
      FOR i := 1 TO UPPERBOUND (p_name_list^) DO
        convert_name_to_do (p_name_list^ [i], display_option, status);
        IF NOT status.normal THEN
          RETURN;
        IFEND;
        display_selection := display_selection + $display_selections [display_option];
      FOREND;
    IFEND;

  PROCEND crack_display_options;

?? TITLE := '  crack_interval_catagory  ', EJECT ??

  PROCEDURE crack_interval_catagory (parameter_name: string ( * );
    VAR status: ost$status);

    VAR
      value: clt$value,
      i: integer;

    clp$get_value (parameter_name, 1, 1, clc$low, value, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;
    total_interval_selected := value.name.value = 'TOTAL                          ';

    FOR i := 1 TO UPPERBOUND (interval_option_table) DO
      IF interval_option_table [i].name = value.name.value THEN
        interval_selection := interval_option_table [i].selection;
        RETURN;
      IFEND;
    FOREND;
    osp$set_status_abnormal ('DF', cle$name_not_a_keyword_value, value.name.value, status);
  PROCEND crack_interval_catagory;

?? TITLE := '    convert_name_to_do ', EJECT ??

  PROCEDURE convert_name_to_do (name: ost$name;
    VAR display_option: display_options;
    VAR status: ost$status);

    VAR
      i: integer;

    status.normal := TRUE;
    FOR i := 1 TO UPPERBOUND (display_option_selection_table) DO
      IF display_option_selection_table [i].name = name THEN
        display_option := display_option_selection_table [i].display_option_value;
        RETURN;
      IFEND;
    FOREND;
    osp$set_status_abnormal ('DF', cle$name_not_a_keyword_value, name, status);
  PROCEND convert_name_to_do;

?? TITLE := ' display ', EJECT ??

  PROCEDURE display (display_string: string ( * ));

    VAR
      status: ost$status;

    IF display_string = ' ' THEN
      clp$put_display (display_control, display_string, clc$no_trim, status);
    ELSE
      clp$put_display (display_control, display_string, clc$trim, status);
    IFEND;
  PROCEND display;
?? TITLE := ' display_catalog_access_keypoint', EJECT ??

  PROCEDURE display_catalog_access_keypoint (catalog_summary_keypoint: ost$keypoint);

    VAR
      access_string: string (8),
      catalog_depth: integer,
      catalog_owner: boolean,
      length: integer,
      owner_string: string (9),
      read_access: boolean,
      remote_catalog: boolean,
      working_string: string (200);

    convert_keypoint_to_cat (catalog_summary_keypoint, remote_catalog, catalog_owner, catalog_depth,
          read_access);

    IF catalog_owner THEN
      owner_string := 'OWNER';
    ELSE
      owner_string := 'NOT-OWNER';
    IFEND;

    IF read_access THEN
      access_string := 'READ';
    ELSE
      access_string := 'WRITE';
    IFEND;

    STRINGREP (working_string, length, ' ', catalog_summary_keypoint.clock, ' ', keypoint_name_table
          [catalog_summary_keypoint.keypoint_code], '   catalog summary  ', remote_name [remote_catalog], ' ',
          owner_string, ' depth= ', catalog_depth, ' ', access_string);
    display (working_string (1, length));
  PROCEND display_catalog_access_keypoint;
?? TITLE := ' display_distribution', EJECT ??

  PROCEDURE display_distribution (descriptor: string ( * );
        special_case_zero: boolean;
        distribution: array [ * ] OF integer;
        low_value: integer;
        high_value: integer;
        total_requests: integer);

    CONST
      bar_size = 50;

    VAR
      working_low: integer,
      bar: string (bar_size),
      distribution_point: integer,
      length: integer,
      number_of_stars: integer,
      point_low: real,
      point_high: real,
      output: string (120),
      star_bar: [STATIC, READ] string (bar_size) := '**************************************************';

    STRINGREP (output, length, descriptor, 'Total range: ', low_value, ' .. ', high_value,
      '   Total number intervals ', total_requests);
    display (output (1, length));
    IF total_requests <= 0 THEN
      display ('  No requests --- No distribution ');
      RETURN;
    IFEND;

    IF special_case_zero AND (low_value = 0) THEN
      working_low := 1;
    ELSE
      working_low := low_value;
    IFEND;
    FOR distribution_point := LOWERBOUND (distribution) TO UPPERBOUND (distribution) DO
      output := ' ';
      bar := ' ';
      number_of_stars := (distribution [distribution_point] * STRLENGTH (bar)) DIV total_requests;
      bar ((STRLENGTH (bar) + 1 - number_of_stars), * ) := star_bar;
      IF (number_of_stars = 0) AND (distribution [distribution_point] > 0) THEN
        bar (STRLENGTH (bar), 1) := '.';
      IFEND;

      { compute the low and high for   this range
      IF (distribution_point = 0) AND special_case_zero THEN
        point_low := 0.0;
        point_high := 0.0;
      ELSE
        point_low := $REAL (working_low) + ($REAL (distribution_point - 1) * range_point_size (working_low,
              high_value, number_of_distributions));
        point_high := point_low + range_point_size (working_low, high_value, number_of_distributions);
      IFEND;
      STRINGREP (output, length, ' ', bar, ' Range ', point_low: 14: 2, ' .. ', point_high: 14: 2,
        '    count: ', distribution [distribution_point]);
      display (output (1, length));
    FOREND;

  PROCEND display_distribution;
?? TITLE := ' display_file_operation_keypoint ', EJECT ??

  PROCEDURE display_file_operation_keypoint (file_operation_keypoint: ost$keypoint);

    VAR
      catalog: boolean,
      length: integer,
      remote: boolean,
      working_string: string (200);

    convert_keypoint_to_operation (file_operation_keypoint, catalog, remote);

    STRINGREP (working_string, length, ' ', file_operation_keypoint.clock, ' ', keypoint_name_table
          [file_operation_keypoint.keypoint_code], '   file operation  ', remote_name [remote], ' ',
          catalog_name [catalog]);
    display (working_string (1, length));
  PROCEND display_file_operation_keypoint;
?? TITLE := ' display_file_summary', EJECT ??

  PROCEDURE display_file_summary (summary_table: file_summary);

    VAR
      functions: io_functions,
      length: integer,
      transfer_count: integer,
      transfer_size: integer,
      working_string: string (200);

    display_integer (' Number of attaches: ', summary_table.number_of_attaches);
    display_integer (' Number of creates: ', summary_table.number_of_creates);
    display_integer (' Number of opens: ', summary_table.number_of_opens);
    display_integer (' Number of closes: ', summary_table.number_of_closes);
    display_integer (' Number of deletes: ', summary_table.number_of_deletes);
    display_integer (' Number of returns: ', summary_table.number_of_returns);
    display_integer (' Attaches of file not already attached: ', summary_table.number_of_unique_attaches);
    display_integer (' Number of final returns: ', summary_table.number_of_unique_returns);
    IF summary_table.number_of_returns > 0 THEN
      display_time (' Average attach time: ', summary_table.total_time_all_attaches DIV
           summary_table.number_of_returns);
    ELSE
      display (' Average attach time: -- No attaches ');
    IFEND;
    display_integer (' Maximum attached at any time ', summary_table.max_number_attached);

    display_io_function (summary_table.io_summary);

    compute_transfer_totals (summary_table, transfer_count, transfer_size);
    display_integer (' Total transfer count: ', transfer_count);
    display_integer (' Total transfer size: ', transfer_size);
    IF transfer_count > 0 THEN
      display_integer (' Average transfer size: ', $INTEGER ($REAL (transfer_size) /
           ($REAL (transfer_count))));
    ELSE
      display (' Average transfer size: -- No transfers ');
    IFEND;
    display_real (' Transfer count (requests per second): ', ($REAL (transfer_count) / ($REAL
          (current_keypoint_time) / 1000000.0)));
    display_real (' Transfer rate (bytes per second) ', ($REAL (transfer_size) / ($REAL
          (current_keypoint_time) / 1000000.0)));

  PROCEND display_file_summary;
?? TITLE := ' display_integer ', EJECT ??

  PROCEDURE display_integer (display_string: string ( * <= 256);
        display_int: integer);

    VAR
      length: integer,
      status: ost$status,
      working_string: string (256);

    STRINGREP (working_string, length, display_string, display_int);
    clp$put_display (display_control, working_string (1, length), clc$trim, status);
  PROCEND display_integer;
?? TITLE := ' display_interval_histogram', EJECT ??

  PROCEDURE display_interval_histogram (number_of_intervals: integer;
    VAR p_interval_file: ^SEQ ( * ));

    CONST
      special_case_zero = TRUE;

    VAR
      interval_number: integer,
      point: integer,
      single_item_array: array [0 .. number_of_distributions] of integer,
      p_current_interval: ^file_summary;

{ COMPUTE interval distributions
    RESET p_interval_file;
    FOR interval_number := 1 TO number_of_intervals DO
      NEXT p_current_interval IN p_interval_file;
      IF p_current_interval = NIL THEN
        display_integer (' NIL interval and number ', interval_number);
        RETURN;
      IFEND;

      { ATTACH
      point := interval_distribution_index (interval_range [low].number_of_attaches, interval_range [high].
            number_of_attaches, number_of_distributions, special_case_zero, p_current_interval^.
            number_of_attaches);
      interval_distribution [point].number_of_attaches := interval_distribution [point].number_of_attaches +
            1;

      { TRANSFER SIZE
      point := interval_distribution_index (interval_range [low].transfer_size, interval_range [high].
            transfer_size, number_of_distributions, special_case_zero, p_current_interval^.transfer_size);
      interval_distribution [point].transfer_size := interval_distribution [point].transfer_size + 1;

      { TRANSFER COUNT
      point := interval_distribution_index (interval_range [low].transfer_count, interval_range [high].
            transfer_count, number_of_distributions, special_case_zero, p_current_interval^.transfer_count);
      interval_distribution [point].transfer_count := interval_distribution [point].transfer_count + 1;
    FOREND;

    { DISPLAY interval distribution
    {ATTACH
    FOR point := 0 TO number_of_distributions DO
      single_item_array [point] := interval_distribution [point].number_of_attaches;
    FOREND;
    display_new_page;
    display_distribution (' ATTACH_FILE ', special_case_zero, single_item_array, interval_range [low].
          number_of_attaches, interval_range [high].number_of_attaches, number_of_intervals);

    { transfer_count
    FOR point := 0 TO number_of_distributions DO
      single_item_array [point] := interval_distribution [point].transfer_count;
    FOREND;
    display_distribution (' TRANSACTION  COUNT ', special_case_zero, single_item_array, interval_range [low].
          transfer_count, interval_range [high].transfer_count, number_of_intervals);

    { request size
    FOR point := 0 TO number_of_distributions DO
      single_item_array [point] := interval_distribution [point].transfer_size;
    FOREND;
    display_distribution (' TOTAL TRANSFER AMOUNT ', special_case_zero, single_item_array, interval_range
          [low].transfer_size, interval_range [high].transfer_size, number_of_intervals);

  PROCEND display_interval_histogram;


?? TITLE := ' display_io_function', EJECT ??

  PROCEDURE display_io_function (io_summary: array [io_functions] OF io_function_record);

    VAR
      functions: io_functions,
      length: integer,
      working_string: string (200);

    display (' ');
    display (' IO summary ');
    FOR functions := LOWERVALUE (functions) TO UPPERVALUE (functions) DO
      IF io_summary [functions].total_request_count > 0 THEN
        display (' ');
        STRINGREP (working_string, length, io_function_names [functions], ' request count = ', io_summary
              [functions].total_request_count, '      page count = ', io_summary [functions].
              total_page_count);
        display (working_string (1, length));
        display_io_distribution (io_summary [functions].total_request_count, io_summary [functions].
              request_size_distribution);
      IFEND;
    FOREND;
  PROCEND display_io_function;

?? TITLE := ' display_io_distribution ', EJECT ??

  PROCEDURE display_io_distribution (total_requests: integer;
        distribution: array [request_size_range] OF integer);

    CONST
      bar_size = 38;

    VAR
      bar: string (bar_size),
      index: request_size_ordinal,
      length: integer,
      number_of_stars: integer,
      output: string (80),
      star_bar: [STATIC, READ] string (bar_size) := '**************************************';

    IF total_requests <= 0 THEN
      display (' -- no requests --');
      RETURN;
    IFEND;

    display (' Distribution of request counts for page sizes within this io function');
    FOR index := LOWERVALUE (request_size_ordinal) TO UPPERVALUE (request_size_ordinal) DO
      output := ' ';
      bar := ' ';
      number_of_stars := (distribution [index] * STRLENGTH (bar)) DIV total_requests;
      bar ((STRLENGTH (bar) + 1 - number_of_stars), * ) := star_bar;
      IF (number_of_stars = 0) AND (distribution [index] > 0) THEN
        bar (STRLENGTH (bar), 1) := '.';
      IFEND;
      STRINGREP (output, length, ' ', bar, request_size_display [index], ' request count: ', distribution
            [index]);
      display (output (1, length));
    FOREND;

  PROCEND display_io_distribution;
?? TITLE := ' display_io_keypoint ', EJECT ??

  PROCEDURE display_io_keypoint (io_keypoint: ost$keypoint);

    VAR
      io_function: iot$io_function,
      length: integer,
      page_count: integer,
      working_string: string (256);

    convert_keypoint_to_io_function (io_keypoint, io_function, page_count);
    STRINGREP (working_string, length, ' ', io_keypoint.clock, ' ', keypoint_name_table [io_keypoint.
          keypoint_code], '   io operation  ', io_function_names [io_function], ' ', ' pages =', page_count);
    display (working_string (1, length));
  PROCEND display_io_keypoint;

?? TITLE := ' display_new_page ', EJECT ??

  PROCEDURE display_new_page;

    VAR
      status: ost$status;

    clp$new_display_page (display_control, status);
  PROCEND display_new_page;
?? TITLE := 'display_pmf_keypoint', EJECT ??

  PROCEDURE display_pmf_keypoint (pmf_keypoint: ost$class_15_keypoint);

    VAR
      ignore: ost$status,
      date: ost$date,
      time: ost$time,
      length: integer,
      working_string: string (256);

    pmp$format_compact_time (pmf_keypoint.date_time, osc$millisecond_time, time, ignore);
    pmp$format_compact_date (pmf_keypoint.date_time, osc$month_date, date, ignore);
    STRINGREP (working_string, length, ' PMF time ', time.millisecond, ' ', date.month, ' clock ',
          pmf_keypoint.microsecond_clock, ' user_data ', pmf_keypoint.user_data);
    display (working_string (1, length));
    display_unknown_keypoint (pmf_keypoint.keypoint);
    display (' end PMF ');
  PROCEND display_pmf_keypoint;

?? TITLE := ' display_real ', EJECT ??

  PROCEDURE display_real (display_string: string ( * <= 256);
        display_r: real);

    VAR
      length: integer,
      status: ost$status,
      working_string: string (256);

    STRINGREP (working_string, length, display_string, display_r: 20: 4);
    clp$put_display (display_control, working_string (1, length), clc$trim, status);
  PROCEND display_real;
?? TITLE := ' display_summary_table ', EJECT ??

  PROCEDURE display_summary_tables;

    VAR
      catalog: boolean,
      length: integer,
      remote: boolean,
      working_string: string (200);

    display_new_page;
    display (title_string);
    display (' Catalog access summary ');
    display_integer (' Total paths accessed:  ', total_path_accesses);
    display_integer (' Remote path accesses: ', remote_path_accesses);
    display (' ');
    display_integer (' Total catalog depth: ', total_catalog_depth);
    display_integer (' Remote catalog depth: ', total_remote_cat_depth);
    display (' ');
    display_integer (' Last catalog in path accessed for read: ', accesses_for_read);
    display_integer (' Accesses by owner: ', accesses_by_owner);

    FOR remote := FALSE TO TRUE DO
      FOR catalog := FALSE TO TRUE DO
        display_new_page;
        STRINGREP (working_string, length, ' ', remote_name [remote], '   ', catalog_name [catalog]);
        display (working_string (1, length));
        display_file_summary (attach_summary_table [remote] [catalog]);
      FOREND;
    FOREND;

    display_new_page;
    display (' Non permanent file or catalog summary');
    display_integer (' Number of opens: ', non_pf_open_count);
    display_integer (' Number of closes: ', non_pf_close_count);
    display_io_function (non_pf_io_summary);

    display_new_page;
    display (' TOTALS - all activity');
    display (title_string);
    display_file_summary (total_summary);

  PROCEND display_summary_tables;
?? TITLE := ' display_sfid_keypoint ', EJECT ??

  PROCEDURE display_sfid_keypoint (sfid_keypoint: ost$keypoint);

    VAR
      file_entry_index: gft$file_descriptor_index,
      length: integer,
      residence: gft$table_residence,
      working_string: string (200);

    convert_keypoint_to_sfid (sfid_keypoint, file_entry_index, residence);

    STRINGREP (working_string, length, ' ', sfid_keypoint.clock, ' ', keypoint_name_table [sfid_keypoint.
          keypoint_code], '     sfid ', residence_name_table [residence], '  ', file_entry_index);
    display (working_string (1, length));
  PROCEND display_sfid_keypoint;
?? TITLE := ' display_time ', EJECT ??

  PROCEDURE display_time (descriptor: string ( * );
        microseconds: integer);

    VAR
      length: integer,
      working_string: string (200);

    IF microseconds >= 3600000000 THEN
      STRINGREP (working_string, length, ' ', descriptor, ($REAL (microseconds) / 3600000000.0): 20: 4,
        '  hours');
    ELSEIF microseconds >= 60000000 THEN
      STRINGREP (working_string, length, ' ', descriptor, ($REAL (microseconds) / 60000000.0): 20: 4,
        ' minutes');
    ELSEIF microseconds >= 1000000 THEN
      STRINGREP (working_string, length, ' ', descriptor, ($REAL (microseconds) / 1000000.0): 20: 4,
        ' seconds ');
    ELSEIF microseconds >= 1000 THEN
      STRINGREP (working_string, length, ' ', descriptor, ($REAL (microseconds) / 1000.0): 20: 4,
        ' milliseconds');
    ELSE
      STRINGREP (working_string, length, ' ', descriptor, $REAL (microseconds): 20: 4, 'microseconds');
    IFEND;
    display (working_string (1, length));

  PROCEND display_time;
?? TITLE := ' display_time_interval', EJECT ??

  PROCEDURE display_time_interval;

    VAR
      remote: boolean,
      catalog: boolean;

    IF total_interval_selected THEN
      display_time_interval_line (time_interval_total);
    IFEND;
    FOR remote := FALSE TO TRUE DO
      FOR catalog := FALSE TO TRUE DO
        IF interval_selection [remote] [catalog] THEN
          display_time_interval_line (time_interval_summary_table [remote] [catalog]);
        IFEND;
      FOREND;
    FOREND;
  PROCEND display_time_interval;
?? TITLE := ' display_time_interval_line', EJECT ??

  PROCEDURE display_time_interval_line (summary: file_summary);

    VAR
      transfer_count: integer,
      transfer_size: integer,
      working_string: string (128),
      length: integer;

    compute_transfer_totals (summary, transfer_count, transfer_size);

    STRINGREP (working_string, length, interval_number: 9, ' ', interval_remote_path_accesses: 9, summary.
          number_of_attaches: integer_field_length, summary.number_of_creates: integer_field_length, ' ',
          summary.number_of_opens: integer_field_length, '  ', summary.number_of_closes: integer_field_length,
      '   ', summary.number_of_deletes: integer_field_length, ' ', summary.number_of_returns:
        integer_field_length, ' ', summary.io_summary [ioc$read_page].total_request_count: 8, summary.
          io_summary [ioc$read_page].total_page_count: 8, '  ', summary.io_summary [ioc$write_page].
          total_request_count: 8, '  ', summary.io_summary [ioc$write_page].total_page_count: 8, '  ',
          transfer_count: 8, transfer_size: 10);

    display (working_string (1, length));
  PROCEND display_time_interval_line;

?? TITLE := ' display_time_interval_title', EJECT ??

  PROCEDURE display_time_interval_title;

    VAR
      remote: boolean,
      catalog: boolean,
      working_string: string (128),
      length: integer;

    display_time (' time interval ', time_interval);

    IF total_interval_selected THEN
      display (' TOTALS ');
      display_time_interval_line (time_interval_total);
    IFEND;
    FOR remote := FALSE TO TRUE DO
      FOR catalog := FALSE TO TRUE DO
        IF interval_selection [remote] [catalog] THEN
          STRINGREP (working_string, length, ' ', remote_name [remote], '   ', catalog_name [catalog]);
          display (working_string (1, length));
        IFEND;
      FOREND;
    FOREND;

    STRINGREP (working_string, length, ' INTERVAL ', ' REM PATHS', ' ATTA ', ' CREA ', '  OPEN ', '  CLOSE ',
      '  DELETE', '  RETURN', ' READ RC', ' READ PC ', ' WRITE RC ', ' WRITE PC ', ' TRANS COUNT',
      ' TRANS SIZE');

    display (working_string (1, length));

  PROCEND display_time_interval_title;
?? TITLE := ' display_unknown_keypoint  ', EJECT ??

  PROCEDURE display_unknown_keypoint (keypoint: ost$keypoint);

    VAR
      class: string (5),
      length: integer,
      working_string: string (200);

    STRINGREP (working_string, length, ' ', keypoint.clock, ' UNKNOWN  class ', keypoint.keypoint_class,
      ' data ', keypoint.keypoint_data: #(16), '(16)    code ', keypoint.keypoint_code);
    display (working_string (1, length));

  PROCEND display_unknown_keypoint;

?? TITLE := ' initialize_file_summary ', EJECT ??

  PROCEDURE initialize_file_summary (VAR summary_table: file_summary);

    summary_table.number_of_attaches := 0;
    summary_table.number_of_creates := 0;
    summary_table.number_of_opens := 0;
    summary_table.number_of_closes := 0;
    summary_table.number_of_deletes := 0;
    summary_table.number_of_returns := 0;
    { This is the attach of a file                   not already attached
    summary_table.number_of_unique_attaches := 0;
    { unique_return refers to the last return of the file in the system
    summary_table.number_of_unique_returns := 0;

    summary_table.transfer_count := 0;
    summary_table.transfer_size := 0;

    { average_time_attached := total_time_all_attaches/ number_of_returns
    summary_table.total_time_all_attaches := 0;
    summary_table.max_number_attached := 0;
    initialize_io_function (summary_table.io_summary);
  PROCEND initialize_file_summary;
?? TITLE := ' initialize_interval_range', EJECT ??

  PROCEDURE initialize_interval_range;

    { initialize the low value so that the first low value will be the new lowest

    CONST
      largest_integer = 5000000000;


    VAR
      point: integer,
      io_function: io_functions;

    interval_range [low].number_of_attaches := largest_integer;
    interval_range [low].number_of_creates := largest_integer;
    interval_range [low].number_of_opens := largest_integer;
    interval_range [low].number_of_closes := largest_integer;
    interval_range [low].number_of_deletes := largest_integer;
    interval_range [low].number_of_returns := largest_integer;
    FOR io_function := LOWERVALUE (io_function) TO UPPERVALUE (io_function) DO
      interval_range [low].io_summary [io_function].total_request_count := largest_integer;
      interval_range [low].io_summary [io_function].total_page_count := largest_integer;
    FOREND;
    interval_range [low].transfer_count := largest_integer;
    interval_range [low].transfer_size := largest_integer;
{ do not use request size distribution for this

    interval_range [high].number_of_attaches := - 1;
    interval_range [high].number_of_creates := - 1;
    interval_range [high].number_of_opens := - 1;
    interval_range [high].number_of_closes := - 1;
    interval_range [high].number_of_deletes := - 1;
    interval_range [high].number_of_returns := - 1;
    FOR io_function := LOWERVALUE (io_function) TO UPPERVALUE (io_function) DO
      interval_range [high].io_summary [io_function].total_request_count := - 1;
      interval_range [high].io_summary [io_function].total_page_count := - 1;
    FOREND;
    interval_range [high].transfer_count := - 1;
    interval_range [high].transfer_size := - 1;

    { initialize distribution
    FOR point := LOWERBOUND (interval_distribution) TO UPPERBOUND (interval_distribution) DO
      interval_distribution [point] := initialized_summary;
    FOREND;
  PROCEND initialize_interval_range;

?? TITLE := '  initialize_io_function  ', EJECT ??

  PROCEDURE initialize_io_function (VAR io_summary: array [io_functions] OF io_function_record);

    VAR
      io_function: io_functions,
      request_size: request_size_ordinal;

    FOR io_function := LOWERVALUE (io_function) TO UPPERVALUE (io_function) DO
      io_summary [io_function].total_request_count := 0;
      io_summary [io_function].total_page_count := 0;
      FOR request_size := LOWERVALUE (request_size) TO UPPERVALUE (request_size) DO
        io_summary [io_function].request_size_distribution [request_size] := 0;
      FOREND;
    FOREND;
  PROCEND initialize_io_function;
?? TITLE := ' initialize_summary_tables', EJECT ??

  PROCEDURE initialize_summary_tables;

    VAR
      attach_file_table_index: gft$file_descriptor_index,
      catalog: boolean,
      file_residence_remote: boolean;

    { Do not use static initialization on this because of psr with generate_library.
    FOR attach_file_table_index := LOWERBOUND (attached_file_table) TO UPPERBOUND (attached_file_table) DO
      attached_file_table [attach_file_table_index].entry_type := free_entry;
    FOREND;

    initialize_io_function (non_pf_io_summary);

    initialize_file_summary (initialized_summary);
    FOR file_residence_remote := FALSE TO TRUE DO
      FOR catalog := FALSE TO TRUE DO
        attach_summary_table [file_residence_remote] [catalog] := initialized_summary;
        time_interval_summary_table [file_residence_remote] [catalog] := initialized_summary;
      FOREND;
    FOREND;
    total_summary := initialized_summary;
    time_interval_total := initialized_summary;
  PROCEND initialize_summary_tables;
?? TITLE := 'FUNCTION  interval_distribution_index', EJECT ??

  FUNCTION interval_distribution_index (low_value: integer;
        high_value: integer;
        number_of_distributions: integer;
        special_case_zero: boolean;
        value: integer): integer;

    VAR
      working_low: integer,
      range_point: real,
      range_point_siz: real;

    IF (value = 0) AND special_case_zero THEN
      interval_distribution_index := 0;
    ELSE
      IF special_case_zero AND (low_value = 0) THEN
        working_low := 1;
      ELSE
        working_low := low_value;
      IFEND;
      range_point_siz := range_point_size (working_low, high_value, number_of_distributions);
      IF range_point_siz = 0.0 THEN
        range_point := 0.0;
      ELSE
        range_point := $REAL (value - working_low) / range_point_siz;
      IFEND;
      IF range_point = 0.0 THEN
        interval_distribution_index := 1;
      ELSEIF range_point = $REAL ($INTEGER (range_point)) THEN
        interval_distribution_index := $INTEGER (range_point);
      ELSE
        interval_distribution_index := $INTEGER (range_point) + 1;
      IFEND;
    IFEND;
  FUNCEND interval_distribution_index;
?? TITLE := ' FUNCTION range_point_size', EJECT ??

  FUNCTION range_point_size (low_value: integer;
        high_value: integer;
        number_of_distributions: integer): real;

    IF number_of_distributions > 0 THEN
      range_point_size := ($REAL (high_value) - $REAL (low_value)) / $REAL (number_of_distributions);
    ELSE
      range_point_size := 0.0;
    IFEND;
  FUNCEND range_point_size;


?? TITLE := 'record_attach', EJECT ??

  PROCEDURE record_attach (attach_keypoint: ost$keypoint;
        sfid_keypoint: ost$keypoint;
        create: boolean);

    VAR
      catalog: boolean,
      file_entry_index: gft$file_descriptor_index,
      remote: boolean,
      residence: gft$table_residence;

    convert_keypoint_to_sfid (sfid_keypoint, file_entry_index, residence);
    convert_keypoint_to_operation (attach_keypoint, catalog, remote);
    CASE attached_file_table [file_entry_index].entry_type OF
    = valid_entry =
      IF (attached_file_table [file_entry_index].catalog = catalog) AND (attached_file_table
            [file_entry_index].remote = remote) THEN
        attached_file_table [file_entry_index].attach_count := attached_file_table [file_entry_index].
              attach_count + 1;
      ELSE
        display (' -- damaged entry: mismatch on catalog or remote on attach  of existing entry');
        display_file_operation_keypoint (attach_keypoint);
        display_sfid_keypoint (sfid_keypoint);
        attached_file_table [file_entry_index].entry_type := damaged_entry;
        RETURN;
      IFEND;
    = damaged_entry =
      display (' -- damaged entry: reaaccess on attach - data discarded ');
      display_file_operation_keypoint (attach_keypoint);
      display_sfid_keypoint (sfid_keypoint);
      RETURN;
    = free_entry =
      attach_summary_table [remote] [catalog].number_of_unique_attaches := attach_summary_table [remote]
            [catalog].number_of_unique_attaches + 1;
      time_interval_summary_table [remote] [catalog].number_of_unique_attaches := attach_summary_table
            [remote] [catalog].number_of_unique_attaches + 1;

      total_summary.number_of_unique_attaches := total_summary.number_of_unique_attaches + 1;
      time_interval_total.number_of_unique_attaches := time_interval_total.number_of_unique_attaches + 1;

      attached_file_table [file_entry_index].entry_type := valid_entry;
      attached_file_table [file_entry_index].catalog := catalog;
      attached_file_table [file_entry_index].remote := remote;
      attached_file_table [file_entry_index].time_initially_attached := current_keypoint_time;
      attached_file_table [file_entry_index].attach_count := 1;
      attached_file_table [file_entry_index].number_of_opens := 0;
    CASEND;

    attach_summary_table [remote] [catalog].current_attached := attach_summary_table [remote] [catalog].
          current_attached + 1;
    total_summary.current_attached := total_summary.current_attached + 1;

    IF create THEN
      attach_summary_table [remote] [catalog].number_of_creates := attach_summary_table [remote] [catalog].
            number_of_creates + 1;
      time_interval_summary_table [remote] [catalog].number_of_creates := time_interval_summary_table [remote]
            [catalog].number_of_creates + 1;
      total_summary.number_of_creates := total_summary.number_of_creates + 1;
      time_interval_total.number_of_creates := time_interval_total.number_of_creates + 1;
    ELSE
      attach_summary_table [remote] [catalog].number_of_attaches := attach_summary_table [remote] [catalog].
            number_of_attaches + 1;
      time_interval_summary_table [remote] [catalog].number_of_attaches := time_interval_summary_table
            [remote] [catalog].number_of_attaches + 1;
      total_summary.number_of_attaches := total_summary.number_of_attaches + 1;
      time_interval_total.number_of_attaches := time_interval_total.number_of_attaches + 1;
    IFEND;

    IF attach_summary_table [remote] [catalog].current_attached > attach_summary_table [remote] [catalog].
          max_number_attached THEN
      attach_summary_table [remote] [catalog].max_number_attached := attach_summary_table [remote] [catalog].
            current_attached;
    IFEND;
    IF total_summary.current_attached > total_summary.max_number_attached THEN
      total_summary.max_number_attached := total_summary.current_attached;
    IFEND;
  PROCEND record_attach;
?? TITLE := '  record_catalog_access_info', EJECT ??

  PROCEDURE record_catalog_access_info (keypoint: ost$keypoint);

    VAR
      data_converter: dft$keypoint_catalog_summary;

    VAR
      catalog_depth: integer,
      catalog_owner: boolean,
      read_access: boolean,
      remote_catalog: boolean;

    convert_keypoint_to_cat (keypoint, remote_catalog, catalog_owner, catalog_depth, read_access);
    total_path_accesses := total_path_accesses + 1;
    interval_path_accesses := interval_path_accesses + 1;
    IF remote_catalog THEN
      remote_path_accesses := remote_path_accesses + 1;
      interval_remote_path_accesses := interval_remote_path_accesses + 1;
    IFEND;

    IF catalog_owner THEN
      accesses_by_owner := accesses_by_owner + 1;
      interval_accesses_by_owner := interval_accesses_by_owner + 1;
    IFEND;

    total_catalog_depth := total_catalog_depth + catalog_depth;
    interval_total_catalog_depth := interval_total_catalog_depth + catalog_depth;
    IF remote_catalog THEN
      total_remote_cat_depth := total_remote_cat_depth + catalog_depth;
      interval_total_remote_cat_depth := interval_total_remote_cat_depth + catalog_depth;
    IFEND;

    IF read_access THEN
      accesses_for_read := accesses_for_read + 1;
      interval_accesses_for_read := interval_accesses_for_read + 1;
    IFEND;
  PROCEND record_catalog_access_info;
?? TITLE := ' record_close', EJECT ??

  PROCEDURE record_close (sfid_keypoint: ost$keypoint);

    VAR
      catalog: boolean,
      file_entry_index: gft$file_descriptor_index,
      remote: boolean,
      residence: gft$table_residence;

    convert_keypoint_to_sfid (sfid_keypoint, file_entry_index, residence);
    IF attached_file_table [file_entry_index].entry_type = valid_entry THEN
      catalog := attached_file_table [file_entry_index].catalog;
      remote := attached_file_table [file_entry_index].remote;
      attach_summary_table [remote] [catalog].number_of_closes := attach_summary_table [remote] [catalog].
            number_of_closes + 1;
      time_interval_summary_table [remote] [catalog].number_of_closes := time_interval_summary_table [remote]
            [catalog].number_of_closes + 1;
    ELSE
      non_pf_close_count := non_pf_close_count + 1;
    IFEND;
    total_summary.number_of_closes := total_summary.number_of_closes + 1;
    time_interval_total.number_of_closes := total_summary.number_of_closes + 1;
  PROCEND record_close;

?? TITLE := 'record_delete_catalog', EJECT ??

  PROCEDURE record_delete_catalog (remote: boolean;
        sfid_keypoint: ost$keypoint);

    VAR
      file_entry_index: gft$file_descriptor_index,
      residence: gft$table_residence;

    convert_keypoint_to_sfid (sfid_keypoint, file_entry_index, residence);
    IF (attached_file_table [file_entry_index].entry_type = valid_entry) THEN
      IF attached_file_table [file_entry_index].catalog AND (attached_file_table [file_entry_index].remote =
            remote) THEN
        attach_summary_table [remote] [ {catalog = } TRUE].number_of_deletes := attach_summary_table [remote]
              [
              {catalog = } TRUE].number_of_deletes + 1;
        time_interval_summary_table [remote] [ {catalog = } TRUE].number_of_deletes :=
              time_interval_summary_table [remote] [
              {catalog = } TRUE].number_of_deletes + 1;
        record_detach (sfid_keypoint);
      ELSE
        display (' -- damaged entry: mismatch on catalog or remote on delete_catalog');
        display_sfid_keypoint (sfid_keypoint);
        attached_file_table [file_entry_index].entry_type := damaged_entry;
      IFEND;
    ELSE
      display (' unexpected sfid on delete_catalog');
      display_sfid_keypoint (sfid_keypoint);
    IFEND;
    total_summary.number_of_deletes := total_summary.number_of_deletes + 1;
    time_interval_total.number_of_deletes := total_summary.number_of_deletes + 1;
  PROCEND record_delete_catalog;
?? TITLE := 'record_delete_file', EJECT ??

  PROCEDURE record_delete_file (remote: boolean);

    attach_summary_table [remote] [ {catalog = } FALSE].number_of_deletes := attach_summary_table [remote] [
          {catalog = } FALSE].number_of_deletes + 1;
    time_interval_summary_table [remote] [ {catalog = } FALSE].number_of_deletes :=
          time_interval_summary_table [remote] [
          {catalog = } FALSE].number_of_deletes + 1;
    total_summary.number_of_deletes := total_summary.number_of_deletes + 1;
    time_interval_total.number_of_deletes := time_interval_total.number_of_deletes + 1;
  PROCEND record_delete_file;
?? TITLE := 'record_detach', EJECT ??

  PROCEDURE record_detach (sfid_keypoint: ost$keypoint);

    VAR
      catalog: boolean,
      file_entry_index: gft$file_descriptor_index,
      remote: boolean,
      residence: gft$table_residence;

    convert_keypoint_to_sfid (sfid_keypoint, file_entry_index, residence);
    IF attached_file_table [file_entry_index].entry_type = valid_entry THEN
      catalog := attached_file_table [file_entry_index].catalog;
      remote := attached_file_table [file_entry_index].remote;
      attached_file_table [file_entry_index].attach_count := attached_file_table [file_entry_index].
            attach_count - 1;
      attach_summary_table [remote] [catalog].number_of_returns := attach_summary_table [remote] [catalog].
            number_of_returns + 1;
      time_interval_summary_table [remote] [catalog].number_of_returns := time_interval_summary_table [remote]
            [catalog].number_of_returns + 1;
      IF attached_file_table [file_entry_index].attach_count = 0 THEN
        attached_file_table [file_entry_index].entry_type := free_entry;

        attach_summary_table [remote] [catalog].number_of_unique_returns := attach_summary_table [remote]
              [catalog].number_of_unique_returns + 1;
        attach_summary_table [remote] [catalog].current_attached := attach_summary_table [remote] [catalog].
              current_attached - 1;
        attach_summary_table [remote] [catalog].total_time_all_attaches := attach_summary_table [remote]
              [catalog].total_time_all_attaches + (current_keypoint_time - attached_file_table
              [file_entry_index].time_initially_attached);

        total_summary.number_of_unique_returns := total_summary.number_of_unique_returns + 1;
        total_summary.current_attached := total_summary.current_attached - 1;
        total_summary.total_time_all_attaches := total_summary.total_time_all_attaches +
              (current_keypoint_time - attached_file_table [file_entry_index].time_initially_attached);

        time_interval_total.number_of_unique_returns := time_interval_total.number_of_unique_returns + 1;
      IFEND;
    ELSE
      display (' --  detach called with invalid sfid');
      display_sfid_keypoint (sfid_keypoint);
    IFEND;
    total_summary.number_of_returns := total_summary.number_of_returns + 1;
    time_interval_total.number_of_returns := time_interval_total.number_of_returns + 1;
  PROCEND record_detach;

?? TITLE := 'record_interval_range', EJECT ??

  PROCEDURE record_interval_range (VAR interval: file_summary);

    VAR
      transfer_count: integer,
      transfer_size: integer,
      io_function: io_functions;

    compute_transfer_totals (interval, transfer_count, transfer_size);
    interval.transfer_count := transfer_count;
    interval.transfer_size := transfer_size;


{ update new lows
    IF interval.number_of_attaches < interval_range [low].number_of_attaches THEN
      interval_range [low].number_of_attaches := interval.number_of_attaches;
    IFEND;
    IF interval.number_of_creates < interval_range [low].number_of_creates THEN
      interval_range [low].number_of_creates := interval.number_of_creates;
    IFEND;
    IF interval.number_of_opens < interval_range [low].number_of_opens THEN
      interval_range [low].number_of_opens := interval.number_of_opens;
    IFEND;
    IF interval.number_of_closes < interval_range [low].number_of_closes THEN
      interval_range [low].number_of_closes := interval.number_of_closes;
    IFEND;
    IF interval.number_of_deletes < interval_range [low].number_of_deletes THEN
      interval_range [low].number_of_deletes := interval.number_of_deletes;
    IFEND;
    IF interval.number_of_returns < interval_range [low].number_of_returns THEN
      interval_range [low].number_of_returns := interval.number_of_returns;
    IFEND;
    IF interval.transfer_count < interval_range [low].transfer_count THEN
      interval_range [low].transfer_count := interval.transfer_count;
    IFEND;
    IF interval.transfer_size < interval_range [low].transfer_size THEN
      interval_range [low].transfer_size := interval.transfer_size;
    IFEND;

    FOR io_function := LOWERVALUE (io_function) TO UPPERVALUE (io_function) DO
      IF interval.io_summary [io_function].total_request_count < interval_range [low].io_summary
            [io_function].total_request_count THEN
        interval_range [low].io_summary [io_function].total_request_count := interval.io_summary
              [io_function].total_request_count;
      IFEND;
      IF interval.io_summary [io_function].total_page_count < interval_range [low].io_summary [io_function].
            total_page_count THEN
        interval_range [low].io_summary [io_function].total_page_count := interval.io_summary [io_function].
              total_page_count;
      IFEND;
    FOREND;


{ do the same for the high
    IF interval.number_of_attaches > interval_range [high].number_of_attaches THEN
      interval_range [high].number_of_attaches := interval.number_of_attaches;
    IFEND;
    IF interval.number_of_creates > interval_range [high].number_of_creates THEN
      interval_range [high].number_of_creates := interval.number_of_creates;
    IFEND;
    IF interval.number_of_opens > interval_range [high].number_of_opens THEN
      interval_range [high].number_of_opens := interval.number_of_opens;
    IFEND;
    IF interval.number_of_closes > interval_range [high].number_of_closes THEN
      interval_range [high].number_of_closes := interval.number_of_closes;
    IFEND;
    IF interval.number_of_deletes > interval_range [high].number_of_deletes THEN
      interval_range [high].number_of_deletes := interval.number_of_deletes;
    IFEND;
    IF interval.number_of_returns > interval_range [high].number_of_returns THEN
      interval_range [high].number_of_returns := interval.number_of_returns;
    IFEND;
    IF interval.transfer_count > interval_range [high].transfer_count THEN
      interval_range [high].transfer_count := interval.transfer_count;
    IFEND;
    IF interval.transfer_size > interval_range [high].transfer_size THEN
      interval_range [high].transfer_size := interval.transfer_size;
    IFEND;

    FOR io_function := LOWERVALUE (io_function) TO UPPERVALUE (io_function) DO
      IF interval.io_summary [io_function].total_request_count > interval_range [high].io_summary
            [io_function].total_request_count THEN
        interval_range [high].io_summary [io_function].total_request_count := interval.io_summary
              [io_function].total_request_count;
      IFEND;
      IF interval.io_summary [io_function].total_page_count > interval_range [high].io_summary [io_function].
            total_page_count THEN
        interval_range [high].io_summary [io_function].total_page_count := interval.io_summary [io_function].
              total_page_count;
      IFEND;
    FOREND;

  PROCEND record_interval_range;
?? TITLE := ' record_open', EJECT ??

  PROCEDURE record_open (sfid_keypoint: ost$keypoint);

    VAR
      catalog: boolean,
      file_entry_index: gft$file_descriptor_index,
      remote: boolean,
      residence: gft$table_residence;

    convert_keypoint_to_sfid (sfid_keypoint, file_entry_index, residence);
    IF attached_file_table [file_entry_index].entry_type = valid_entry THEN
      catalog := attached_file_table [file_entry_index].catalog;
      remote := attached_file_table [file_entry_index].remote;
      attached_file_table [file_entry_index].number_of_opens := attached_file_table [file_entry_index].
            number_of_opens + 1;
      attach_summary_table [remote] [catalog].number_of_opens := attach_summary_table [remote] [catalog].
            number_of_opens + 1;
      time_interval_summary_table [remote] [catalog].number_of_opens := time_interval_summary_table [remote]
            [catalog].number_of_opens + 1;
    ELSE
      non_pf_open_count := non_pf_open_count + 1;
    IFEND;
    total_summary.number_of_opens := total_summary.number_of_opens + 1;
    time_interval_total.number_of_opens := time_interval_total.number_of_opens + 1;
  PROCEND record_open;

?? TITLE := ' record_pager_io', EJECT ??

  PROCEDURE record_pager_io (keypoint: ost$keypoint;
        sfid_keypoint: ost$keypoint);

    VAR
      catalog: boolean,
      file_entry_index: gft$file_descriptor_index,
      io_function: iot$io_function,
      page_count: integer,
      request_size: request_size_ordinal,
      remote: boolean,
      residence: gft$table_residence;

    convert_keypoint_to_sfid (sfid_keypoint, file_entry_index, residence);
    convert_keypoint_to_io_function (keypoint, io_function, page_count);
    convert_page_count_to_ordinal (page_count, request_size);
    IF (residence = gfc$tr_system) AND (attached_file_table [file_entry_index].entry_type =
          valid_entry) THEN
      catalog := attached_file_table [file_entry_index].catalog;
      remote := attached_file_table [file_entry_index].remote;
      attach_summary_table [remote] [catalog].io_summary [io_function].total_request_count :=
            attach_summary_table [remote] [catalog].io_summary [io_function].total_request_count + 1;
      attach_summary_table [remote] [catalog].io_summary [io_function].total_page_count :=
            attach_summary_table [remote] [catalog].io_summary [io_function].total_page_count + page_count;
      attach_summary_table [remote] [catalog].io_summary [io_function].request_size_distribution
            [request_size] := attach_summary_table [remote] [catalog].io_summary [io_function].
            request_size_distribution [request_size] + 1;

      time_interval_summary_table [remote] [catalog].io_summary [io_function].total_request_count :=
            time_interval_summary_table [remote] [catalog].io_summary [io_function].total_request_count + 1;
      time_interval_summary_table [remote] [catalog].io_summary [io_function].total_page_count :=
            time_interval_summary_table [remote] [catalog].io_summary [io_function].total_page_count +
            page_count;
      time_interval_summary_table [remote] [catalog].io_summary [io_function].request_size_distribution
            [request_size] := time_interval_summary_table [remote] [catalog].io_summary [io_function].
            request_size_distribution [request_size] + 1;
    ELSE
      non_pf_io_summary [io_function].total_page_count := non_pf_io_summary [io_function].total_page_count +
            page_count;
      non_pf_io_summary [io_function].total_request_count := non_pf_io_summary [io_function].
            total_request_count + 1;
      non_pf_io_summary [io_function].request_size_distribution [request_size] := non_pf_io_summary
            [io_function].request_size_distribution [request_size] + 1;
    IFEND;

    total_summary.io_summary [io_function].total_request_count := total_summary.io_summary [io_function].
          total_request_count + 1;
    total_summary.io_summary [io_function].total_page_count := total_summary.io_summary [io_function].
          total_page_count + page_count;
    total_summary.io_summary [io_function].request_size_distribution [request_size] := total_summary.
          io_summary [io_function].request_size_distribution [request_size] + 1;

    time_interval_total.io_summary [io_function].total_request_count := time_interval_total.io_summary
          [io_function].total_request_count + 1;
    time_interval_total.io_summary [io_function].total_page_count := time_interval_total.io_summary
          [io_function].total_page_count + page_count;
    time_interval_total.io_summary [io_function].request_size_distribution [request_size] :=
          time_interval_total.io_summary [io_function].request_size_distribution [request_size] + 1;

  PROCEND record_pager_io;



MODEND dfm$analyze_server_keypoints;
