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