-- File: GCLook.mesa, HGM, August 1978
-- Last Edit: Ly September 21, 1978 11:18 AM

DIRECTORY
AltoSlaDefs: FROM "AltoSlaDefs",
DriverDefs: FROM "DriverDefs" USING [debugPointer, GiantVector],
GCDefs: FROM "GCDefs" USING [GCInterface, Get, GetFailure, Read],
IODefs: FROM "<Mesa>IODefs",
StatsDefs: FROM "StatsDefs" USING [StatCounterIndex],
StringDefs: FROM "StringDefs" USING [AppendString, AppendLongNumber],
SystemDefs: FROM "SystemDefs" USING [AllocateHeapString, FreeHeapString];

GCLook: PROGRAM [gc: GCDefs.GCInterface]
IMPORTS GCDefs, IODefs, StringDefs, SystemDefs
EXPORTS GCDefs =
BEGIN OPEN gc, GCDefs, IODefs;

Counters: TYPE = ARRAY StatsDefs.StatCounterIndex OF LONG INTEGER;
Strings: TYPE = ARRAY StatsDefs.StatCounterIndex OF STRING;
hisCounters: Counters;
hisStrings: Strings;
stringsAllocated: BOOLEAN ← FALSE;

giantVector: DriverDefs.GiantVector;
giantVectorLoc: POINTER TO DriverDefs.GiantVector;

Looker: PROCEDURE =
BEGIN
s: StatsDefs.StatCounterIndex;
GetBig[to:@hisCounters,from:giantVector.statCounters,size:SIZE[Counters]];
FOR s IN StatsDefs.StatCounterIndex DO
IF hisCounters[s]=0 THEN LOOP;
LD10[hisCounters[s]];
WriteChar[’ ];
IF hisStrings[s]#NIL THEN WriteLine[hisStrings[s]] ELSE WriteChar[CR];
ENDLOOP;
WriteChar[CR];
END;

ShowSla: PROCEDURE =
BEGIN OPEN AltoSlaDefs;
p: POINTER ← giantVector.slaThings;
activeLines: CARDINAL;
hisLineTable: POINTER TO ARRAY Line OF LineTableEntry;
hisLineInfo: POINTER TO ARRAY Line OF LineInfoBlock;
hisRoutingTable: POINTER TO ARRAY SlaHost OF RoutingTableEntry;
IF p=NIL THEN RETURN;
p ← p+maxByte; -- skip CRC Table
activeLines ← Read[p];
hisLineTable ← p+8; p ← 8+p+maxLine*SIZE[LineTableEntry];
hisRoutingTable ← p; p ← p+maxSlaHost*SIZE[RoutingTableEntry];
hisLineInfo ← p;
IF activeLines>maxLine THEN ERROR;
PrintSlaStats[activeLines,hisLineInfo,hisRoutingTable];
WriteChar[CR];
WriteChar[FF];
WriteChar[CR];
END;

PrintSlaStats: PUBLIC PROCEDURE [
lines: CARDINAL, hisInfo: POINTER, hisRouting: POINTER] =
BEGIN OPEN IODefs, AltoSlaDefs;
line: Line;
host: SlaHost;
info: ARRAY Line OF LineInfoBlock;
lib: POINTER TO LineInfoBlock;
routing: ARRAY SlaHost OF RoutingTableEntry;
rte: POINTER TO RoutingTableEntry;
temp: LONG INTEGER;
WriteChar[CR];
Get[to: @info, from: hisInfo, size: lines*SIZE[LineInfoBlock]];
WriteLine["SLA Line Statistics:"L];
WriteLine[" ----Packets---- ------Errors-----"L];
WriteLine["Line Sent Received CRC Sync Control State"L];
FOR line IN [0..lines) DO
lib ← @info[line];
O3[line];
LD10[lib.packetsSent];
LD10[lib.packetsRecv];
D6[lib.crcErrors];
D6[lib.syncErrors];
D6[lib.controlErrors];
WriteString[" "L];
SELECT lib.state FROM
up => WriteLine["Up"L];
down => WriteLine["Down"L];
loopedBack => WriteLine["Looped back"L];
ENDCASE => WriteLine[" ??"L];
ENDLOOP;
WriteChar[CR];
WriteLine[" ------Bytes----- ----Bits/Sec---- --Err/1000--"L];
WriteLine["Line Sent Received Sent Received Received"L];
FOR line IN [0..lines) DO
lib ← @info[line];
O3[line];
LD10[lib.bytesSent];
LD10[lib.bytesRecv];
temp ← lib.bytesSent+overheadPerPacket*lib.packetsSent;
LD10[BitsPerSecond[temp*8,hisCounters[statTime]]];
temp ← lib.bytesRecv+overheadPerPacket*lib.packetsRecv;
LD10[BitsPerSecond[temp*8,hisCounters[statTime]]];
WriteString[" "L];
temp ← lib.syncErrors+lib.crcErrors+lib.controlErrors;
LD10[temp*1000/lib.packetsRecv];
WriteChar[CR];
ENDLOOP;
WriteChar[CR];
Get[to: @routing, from: hisRouting, size: maxSlaHost*SIZE[RoutingTableEntry]];
WriteLine["Routing Table:"L];
WriteLine["Host Line Hops"L];
FOR host IN SlaHost DO
rte ← @routing[host];
IF rte.hops=longHop THEN LOOP;
O3[host];
O5[rte.line];
D5[rte.hops];
WriteChar[CR];
ENDLOOP;
WriteChar[CR];
END;

GetBig: PROCEDURE [to, from: POINTER, size: CARDINAL] =
BEGIN
end: CARDINAL ← 0;
hunk: CARDINAL;
UNTIL end=size DO
hunk ← MIN[250,size-end];
Get[to+end,from+end,hunk];
end ← end+hunk;
ENDLOOP;
END;

O3: PROCEDURE [n: CARDINAL] =
BEGIN IODefs.WriteNumber[n,[8,FALSE,TRUE,3]]; END;

O4: PROCEDURE [n: CARDINAL] =
BEGIN IODefs.WriteNumber[n,[8,FALSE,TRUE,4]]; END;

O5: PROCEDURE [n: CARDINAL] =
BEGIN IODefs.WriteNumber[n,[8,FALSE,TRUE,5]]; END;

O6: PROCEDURE [n: CARDINAL] =
BEGIN IODefs.WriteNumber[n,[8,FALSE,TRUE,7]]; END;

O3Z: PROCEDURE [n: CARDINAL] =
BEGIN IODefs.WriteNumber[n,[8,TRUE,TRUE,3]]; END;

D: PROCEDURE [n: CARDINAL] =
BEGIN IODefs.WriteNumber[n,[10,FALSE,TRUE,0]]; END;

D5: PROCEDURE [n: CARDINAL] =
BEGIN IODefs.WriteNumber[n,[10,FALSE,TRUE,5]]; END;

D6: PROCEDURE [n: CARDINAL] =
BEGIN IODefs.WriteNumber[n,[10,FALSE,TRUE,6]]; END;

LD: PROCEDURE [n: LONG INTEGER] =
BEGIN
s: STRING = [20];
StringDefs.AppendLongNumber[s,n,10];
WriteString[s];
END;

LD10: PROCEDURE [num: LONG INTEGER] =
BEGIN
s: STRING = [20];
StringDefs.AppendLongNumber[s,num,10];
THROUGH [s.length..10) DO WriteChar[’ ]; ENDLOOP;
WriteString[s];
END;

-- Should get via StatsDefs
x32: LONG INTEGER = 2048000; -- 32*64000
x320: LONG INTEGER = 20480000; -- 320*64000
x3200: LONG INTEGER = 204800000; -- 3200*64000

-- do right thing to avoid overflow, 32 bits is not enough
-- RETURN[a*1000/b]
BitsPerSecond: PROCEDURE [a, b: LONG INTEGER] RETURNS [t: LONG INTEGER] =
BEGIN
SELECT a FROM -- 2↑31 is about 2,000,000,000
<x32 => t ← (a*1000)/b;
<x320 => t ← (a*100)/(b/10);
<x3200 => t ← (a*10)/(b/100);
ENDCASE => t ← a/(b/1000);
END;

GetStrings
: PROCEDURE =
BEGIN
s: StatsDefs.StatCounterIndex;
temp: STRING = [200]; -- maxlength gets clobbered
IF ~stringsAllocated THEN
BEGIN
giantVectorLoc ← Read[DriverDefs.debugPointer];
Get[to:@giantVector,from:giantVectorLoc,size:SIZE[DriverDefs.GiantVector]];
Get[to:@hisStrings,from:giantVector.statStrings,size:SIZE[Strings]];
FOR s IN StatsDefs.StatCounterIndex DO
IF hisStrings[s]=NIL THEN LOOP;
Get[to:temp,from:hisStrings[s],size:100];
hisStrings[s] ← SystemDefs.AllocateHeapString[temp.length];
StringDefs.AppendString[hisStrings[s],temp];
ENDLOOP;
stringsAllocated ← TRUE;
END;
END;

FreeStrings: PROCEDURE =
BEGIN
s: StatsDefs.StatCounterIndex;
FOR s IN StatsDefs.StatCounterIndex DO
IF hisStrings[s]=NIL THEN LOOP;
SystemDefs.FreeHeapString[hisStrings[s]];
ENDLOOP;
stringsAllocated ← FALSE;
END;

GCLookAtThings: PUBLIC PROCEDURE =
BEGIN ENABLE GetFailure =>
BEGIN
WriteLine[" GetFailure!"];
GOTO Return;
END;
WriteString["Look "L];
IF newPartner[1] THEN
BEGIN
IF stringsAllocated THEN FreeStrings[];
newPartner[1] ← FALSE;
END;
SELECT ReadChar[] FROM
’C, ’c =>
BEGIN
WriteLine["at Counters."L];
GetStrings[];
Looker[];
END;
’S, ’s =>
BEGIN
WriteLine["at Sla."L];
GetStrings[];
ShowSla[];
END;
’? => WriteLine["?
C(ounters), S(laStats)."L];
ENDCASE => WriteLine["???"L];
EXITS
Return => NULL;
END;

-- Initialization
END. -- of GCLook