-- File: StatsPrint.mesa,  Last Edit: November 8, 1980  9:21 PM

DIRECTORY
  Put USING [CR, Char, Text, Line],
  String USING [AppendLongNumber],
  Window USING [Handle],
  StatsDefs USING [StatCounterIndex],
  StatsOps USING [statText];

StatsPrint: MONITOR IMPORTS Put, String, StatsOps EXPORTS StatsOps =
  BEGIN OPEN StatsDefs;

  statText: POINTER TO ARRAY StatCounterIndex OF STRING ← @StatsOps.statText;

  -- print out nonZero slots in table
  StatPrintCounters: PUBLIC PROCEDURE [
    wh: Window.Handle, num: POINTER TO ARRAY StatCounterIndex OF LONG CARDINAL] =
    BEGIN
    i: StatCounterIndex;
    t: LONG CARDINAL;
    FOR i IN StatCounterIndex DO
      t ← num↑[i]; IF t # 0 THEN StatPrintLine[wh, t, statText[i]]; ENDLOOP;
    StatPrintGoodies[wh, num];
    END;

  -- print one line

  StatPrintLine: PROCEDURE [wh: Window.Handle, num: LONG CARDINAL, text: STRING] =
    BEGIN
    s: STRING ← [20];
    String.AppendLongNumber[s, num, 10];
    THROUGH [s.length..10) DO Put.Char[wh, ' ]; ENDLOOP;
    Put.Text[wh, s];
    Put.Char[wh, ' ];
    IF text # NIL THEN Put.Line[wh, text] ELSE Put.CR[wh];
    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: PROCEDURE [
    wh: Window.Handle, num: POINTER TO ARRAY StatCounterIndex OF LONG CARDINAL] =
    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[wh, WordsPerSecond[temp, ms, sec], "Ether Bits/Sec Locally"L];
    IF (temp ← num[statEtherWordsReceived]) # 0 THEN
      StatPrintLine[wh, WordsPerSecond[temp, ms, sec], "Ether Bits/Sec In"L];
    IF (temp ← num[statEtherWordsSent]) # 0 THEN
      StatPrintLine[wh, WordsPerSecond[temp, ms, sec], "Ether Bits/Sec Out"L];

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

    -- Retransmission rate
    IF num[statDataPacketsRetransmitted] # 0 THEN
      BEGIN
      temp ← Yetch[num[statDataPacketsRetransmitted], num[statDataPacketsSent]];
      StatPrintLine[wh, temp, "Retransmissions per 1000"L];
      END;
    IF num[statDataPacketsReceivedAgain] # 0 THEN
      BEGIN
      temp ← Yetch[
	num[statDataPacketsReceivedAgain], num[statDataPacketsReceived]];
      StatPrintLine[wh, 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[wh, 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[wh, 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[wh, temp, "MicroSec/EtherPacket"L];
	END;
    temp ← num[statDataPacketsSent] + num[statDataPacketsReceived];
    IF temp # 0 THEN
      BEGIN
      temp ← MicroSecPerPacket[ms, sec, temp];
      StatPrintLine[wh, temp, "MicroSec/DataPacket"L];
      END;
    temp ← num[statPupReceived] + num[statOisReceived];
    IF temp # 0 THEN
      BEGIN
      temp ← MicroSecPerPacket[ms, sec, temp];
      StatPrintLine[wh, temp, "MicroSec/(Pup+OIS) Packet Received"L];
      END;
    temp ←
      num[statPupSent] + num[statOisSent] + num[statPupBroadcast] + num[
	statOisBroadcast];
    IF temp # 0 THEN
      BEGIN
      temp ← MicroSecPerPacket[ms, sec, temp];
      StatPrintLine[wh, 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: PROCEDURE [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: PROCEDURE [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: PROCEDURE [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: PROCEDURE [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: PROCEDURE [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.