-- 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.