-- Copyright (C) 1983  by Xerox Corporation. All rights reserved. 
--File: StatsPrint.mesa,  (Last Edit: AOF  2-Jun-83 11:49:17)

DIRECTORY
  String USING [AppendChar, AppendLongNumber, AppendString],
  Stats USING [StatCounterIndex, StringProc],
  StatsMisc USING [],
  StatsOps USING [StatArray, statText];

StatsPrint: MONITOR
  IMPORTS String, StatsOps
  EXPORTS StatsOps, StatsMisc =
  BEGIN

  -- print out nonZero slots in table
  StatPrintCounters: PUBLIC PROC[
    proc: Stats.StringProc, num: StatsOps.StatArray] =
    BEGIN
    i: Stats.StatCounterIndex;
    t: LONG CARDINAL;
    FOR i IN Stats.StatCounterIndex DO
      t ← num↑[i]; IF t # 0 THEN StatPrintLine[proc, t, StatsOps.statText[i]];
      ENDLOOP;
    StatPrintGoodies[proc, num];
    END;

  -- print one line

  StatPrintLine: PUBLIC PROC[
    proc: Stats.StringProc, num: LONG CARDINAL, text: LONG STRING] =
    BEGIN
    n: STRING ← [20];
    s: STRING ← [100];
    spaces: STRING ← "          "L;
    String.AppendLongNumber[n, num, 10];
    spaces.length ← spaces.length - n.length;
    String.AppendString[s, spaces];
    String.AppendString[s, n];
    String.AppendChar[s, ' ];
    IF text # NIL THEN String.AppendString[s, text];
    proc[s];
    END;

  -- print out various things that arn't counted directly - like bits/sec
  -- watch out for overflow - 16 bits, or even 32 is just not enough


  StatPrintGoodies: PROC[proc: Stats.StringProc, num: StatsOps.StatArray] =
    BEGIN
    temp: LONG CARDINAL;
    ms: LONG CARDINAL = num[statTime];
    sec: LONG CARDINAL = num[statSeconds];

    IF ms = 0 AND sec = 0 THEN RETURN; -- divide by zero

    -- Ethernet Bandwidth
    IF (temp ← num[statEtherWordsLocal]) # 0 THEN
      StatPrintLine[proc, WordsPerSecond[temp, ms, sec], "Ether Bits/Sec Locally"L];
    IF (temp ← num[statEtherWordsReceived]) # 0 THEN
      StatPrintLine[proc, WordsPerSecond[temp, ms, sec], "Ether Bits/Sec In"L];
    IF (temp ← num[statEtherWordsSent]) # 0 THEN
      StatPrintLine[proc, WordsPerSecond[temp, ms, sec], "Ether Bits/Sec Out"L];

    -- Data Bandwidth
    IF (temp ← num[statDataBytesReceived]) # 0 THEN
      StatPrintLine[proc, BytesPerSecond[temp, ms, sec], "Data Bits/Sec In"L];
    IF (temp ← num[statDataBytesSent]) # 0 THEN
      StatPrintLine[proc, BytesPerSecond[temp, ms, sec], "Data Bits/Sec Out"L];

    -- Retransmission rate
    IF num[statDataPacketsRetransmitted] # 0 THEN
      BEGIN
      temp ← Yetch[num[statDataPacketsRetransmitted], num[statDataPacketsSent]];
      StatPrintLine[proc, temp, "Retransmissions per 1000"L];
      END;
    IF num[statDataPacketsReceivedAgain] # 0 THEN
      BEGIN
      temp ← Yetch[
	num[statDataPacketsReceivedAgain], num[statDataPacketsReceived]];
      StatPrintLine[proc, temp, "Duplicates per 1000"L];
      END;

    -- Packets/Ack
    IF num[statAcksReceived] # 0 AND num[statDataPacketsSent] # 0 THEN
      BEGIN
      temp ← Yetch[num[statDataPacketsSent], num[statAcksReceived]];
      StatPrintLine[proc, temp, "Packets sent per 1000 Acks received"L];
      END;
    IF num[statAcksSent] # 0 AND num[statDataPacketsReceived] # 0 THEN
      BEGIN
      temp ← Yetch[num[statDataPacketsReceived], num[statAcksSent]];
      StatPrintLine[proc, temp, "Packets received per 1000 Acks sent"L];
      END;

    -- Time/Packet
    temp ← num[statEtherPacketsSent] + num[statEtherPacketsReceived];
    IF FALSE THEN
      IF temp # 0 THEN
	BEGIN
	temp ← MicroSecPerPacket[ms, sec, temp];
	StatPrintLine[proc, temp, "MicroSec/EtherPacket"L];
	END;
    temp ← num[statDataPacketsSent] + num[statDataPacketsReceived];
    IF temp # 0 THEN
      BEGIN
      temp ← MicroSecPerPacket[ms, sec, temp];
      StatPrintLine[proc, temp, "MicroSec/DataPacket"L];
      END;
    temp ← num[statPupReceived] + num[statNSReceived];
    IF temp # 0 THEN
      BEGIN
      temp ← MicroSecPerPacket[ms, sec, temp];
      StatPrintLine[proc, temp, "MicroSec/(Pup+OIS) Packet Received"L];
      END;
    temp ←
      num[statPupSent] + num[statNSSent] + num[statPupBroadcast] + num[
	statNSBroadcast];
    IF temp # 0 THEN
      BEGIN
      temp ← MicroSecPerPacket[ms, sec, temp];
      StatPrintLine[proc, temp, "MicroSec/(Pup+OIS) Packet Sent"L];
      END;

    END;

  -- 32 bits of miliseconds is almost 50 (49.71) days or almost 1200 (1193) hours

  WordsPerSecond: PUBLIC PROC[words, ms, sec: LONG CARDINAL]
    RETURNS [result: LONG CARDINAL] =
    BEGIN
    IF words > bigestNum/16 THEN result ← BitsPerSecond[words, ms/16, sec/16]
    ELSE result ← BitsPerSecond[words*16, ms, sec];
    END;

  BytesPerSecond: PUBLIC PROC[bytes, ms, sec: LONG CARDINAL]
    RETURNS [result: LONG CARDINAL] =
    BEGIN
    IF bytes > bigestNum/8 THEN result ← BitsPerSecond[bytes, ms/8, sec/8]
    ELSE result ← BitsPerSecond[bytes*8, ms, sec];
    END;

  BitsPerSecond: PUBLIC PROC[bits, ms, sec: LONG CARDINAL]
    RETURNS [result: LONG CARDINAL] =
    BEGIN
    IF sec > bigestNum/1000 THEN result ← bits/sec ELSE result ← Yetch[bits, ms];
    END;

  MicroSecPerPacket: PUBLIC PROC[ms, sec, packets: LONG CARDINAL]
    RETURNS [result: LONG CARDINAL] =
    BEGIN
    IF sec > bigestNum/1000 THEN result ← Yetch[sec, packets/1000]
    ELSE result ← Yetch[ms, packets];
    END;

  -- RETURN[a*1000/b],  32 bits is not enough
  -- Do the right thing to avoid overflow and divide by 0

  Yetch: PUBLIC PROC[a, b: LONG CARDINAL] RETURNS [t: LONG CARDINAL] =
    BEGIN
    SELECT a FROM -- 2↑31 is about 2,000,000,000

      < 2048000 => BEGIN IF b = 0 THEN RETURN[0]; t ← (a*1000)/b; END;
      < 20480000 =>
	BEGIN
	temp: LONG CARDINAL = b/10;
	IF temp = 0 THEN RETURN[0];
	t ← (a*100)/temp;
	END;
      < 204800000 =>
	BEGIN
	temp: LONG CARDINAL = b/100;
	IF temp = 0 THEN RETURN[0];
	t ← (a*10)/temp;
	END;
      ENDCASE =>
	BEGIN
	temp: LONG CARDINAL = b/1000;
	IF temp = 0 THEN RETURN[0];
	t ← a/temp;
	END;
    END;

  bigestNum: LONG CARDINAL = 2000000000; -- about 31 bits

  -- initialization

  END.