-- File: Look.mesa, Last Edit: HGM March 5, 1981 5:38 AM DIRECTORY Ascii USING [FF], File USING [nullCapability], Format USING [], ImageDefs USING [StopMesa], Inline USING [HighHalf, LowHalf], InlineDefs USING [BcplLongNumber, BcplToMesaLongNumber], Put USING [CR, Char, Date, Decimal, Line, Number, Text], Storage USING [String], String USING [AppendString, AppendChar, AppendLongNumber], Time USING [Append, AppendCurrent, Current, Unpack], Window USING [Handle], CommUtilDefs USING [magicMemoryLocation], PupRouterDefs, AltoEthernetDefs USING [ethernetStatsReply, EtherStatsEntry], AltoSlaDefs, AltoPRDefs USING [prStatsReply, PRStatsEntry], BootServerDefs USING [ BootFile, BootFileObject, timeNotKnown, bootStatsRequest, bootStatsReply, BootStatsEntry], EchoServerDefs USING [echoStatsRequest, echoStatsReply, EchoStatsEntry], GateDefs, NameServerDefs USING [ CacheEntry, CacheEntryObject, nameStatsRequest, nameStatsReply, NameStatsEntry], TimeServerDefs USING [timeStatsRequest, timeStatsReply, TimeStatsEntry], ForwarderDefs USING [ forwarderStatsRequest, forwarderStatsReply, ForwardStatsEntry, TransitMatrixEntry], GateControlDefs USING [ GateControlStatsEntry, gateControlExamine, pupStatsSend, pupStatsNak, pupStatsAck, gateControlStatsSend, gateControlStatsNak, gateControlStatsAck], Lock, StatsDefs, PupDefs USING [ PupPackageMake, defaultNumberOfNetworks, PupBuffer, GetFreePupBuffer, ReturnFreePupBuffer, GetPupAddress, PupNameTrouble, AppendPupAddress, AppendErrorPup, GetPupContentsBytes, SetPupContentsWords, PupSocket, PupSocketMake, PupSocketDestroy, MsToTocks, SecondsToTocks], PupTypes USING [ PupAddress, fillInSocketID, echoSoc, statSoc, miscSrvSoc, gatewaySoc], DriverDefs; Look: PROGRAM IMPORTS ImageDefs, Inline, InlineDefs, Put, Storage, String, Time, PupDefs SHARES DriverDefs = BEGIN who: PupTypes.PupAddress ← [, , [0, 0]]; name: STRING = "Twinkle"; coreSoc: PupDefs.PupSocket; statSoc: PupDefs.PupSocket; Counters: TYPE = ARRAY StatsDefs.StatCounterIndex OF LONG INTEGER; Strings: TYPE = ARRAY StatsDefs.StatCounterIndex OF STRING; hisCounters: Counters; hisStrings: Strings; giantVector: DriverDefs.GiantVector; giantVectorLoc: POINTER TO DriverDefs.GiantVector; gateVector: GateDefs.GateDebugRecord; wh: Window.Handle = NIL; 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]]; Put.Char[wh, ' ]; IF hisStrings[s] # NIL THEN Put.Line[wh, hisStrings[s]] ELSE Put.CR[wh]; ENDLOOP; Put.CR[wh]; Put.CR[wh]; END; ShowBoot: PROCEDURE = BEGIN b: PupDefs.PupBuffer; b ← GetBootStats[]; IF b # NIL THEN BEGIN PrintBootStats[b]; PupDefs.ReturnFreePupBuffer[b]; END; PrintBootTable[]; END; PrintBootStats: PROCEDURE [b: PupDefs.PupBuffer] = BEGIN bse: LONG POINTER TO BootServerDefs.BootStatsEntry = LOOPHOLE[@b.pupBody]; Put.Line[wh, "Boot Server Statistics:"L]; PrintItem[ InlineDefs.BcplToMesaLongNumber[bse.directories], "Boot directories sent: "L]; PrintItem[ InlineDefs.BcplToMesaLongNumber[bse.fastSends], "Boot files sent: "L]; PrintItem[ InlineDefs.BcplToMesaLongNumber[bse.slowSends], "Slow boot file sent: "L]; PrintItem[ InlineDefs.BcplToMesaLongNumber[bse.filesRecv], "New boot files retrieved: "L]; Put.CR[wh]; END; PrintBootTable: PROCEDURE = BEGIN bf: BootServerDefs.BootFile; bfo: BootServerDefs.BootFileObject; bf ← Read[gateVector.boot]; Put.CR[wh]; Put.Line[wh, "Boot File Table:"L]; Put.Line[wh, " Code Count AvgMs Create Time FileName"L]; THROUGH [0..50) UNTIL bf = NIL DO Get[to: @bfo, from: bf, size: SIZE[BootServerDefs.BootFileObject]]; O6[bfo.code]; LD6[bfo.count]; IF bfo.count = 0 THEN Put.Text[wh, " "L] ELSE LD6[bfo.ms/bfo.count]; Put.Text[wh, " "L]; SELECT TRUE FROM (bfo.file = File.nullCapability) => Put.Text[wh, "Not on this disk "L]; (bfo.create = BootServerDefs.timeNotKnown) => Put.Text[wh, "Unknown "L]; ENDCASE => Put.Date[wh, bf.create, dateTime]; Put.Text[wh, " "L]; ShowString[bfo.fileName]; Put.CR[wh]; bf ← bfo.next; ENDLOOP; Put.CR[wh]; Put.CR[wh]; END; ShowEcho: PROCEDURE = BEGIN b: PupDefs.PupBuffer; b ← GetEchoStats[]; IF b # NIL THEN BEGIN PrintEchoStats[b]; PupDefs.ReturnFreePupBuffer[b]; END; END; PrintEchoStats: PROCEDURE [b: PupDefs.PupBuffer] = BEGIN ese: LONG POINTER TO EchoServerDefs.EchoStatsEntry = LOOPHOLE[@b.pupBody]; Put.Line[wh, "Echo Server Statistics:"L]; PrintItem[InlineDefs.BcplToMesaLongNumber[ese.pupsEchoed], "Pups Echoed: "L]; Put.CR[wh]; END; ShowTime: PROCEDURE = BEGIN b: PupDefs.PupBuffer; b ← GetTimeStats[]; IF b # NIL THEN BEGIN PrintTimeStats[b]; PupDefs.ReturnFreePupBuffer[b]; END; END; PrintTimeStats: PROCEDURE [b: PupDefs.PupBuffer] = BEGIN tse: LONG POINTER TO TimeServerDefs.TimeStatsEntry = LOOPHOLE[@b.pupBody]; Put.Line[wh, "Time Server Statistics:"L]; PrintItem[ InlineDefs.BcplToMesaLongNumber[tse.tenexRequests], "Tenex time requests: "L]; PrintItem[ InlineDefs.BcplToMesaLongNumber[tse.stringRequests], "String time requests: "L]; PrintItem[ InlineDefs.BcplToMesaLongNumber[tse.altoRequests], "Alto time requests: "L]; Put.Text[wh, " Correction factor: "L]; Put.Decimal[wh, tse.correction]; Put.CR[wh]; IF tse.resetAddress # [[0], [0], [0, 0]] THEN BEGIN reset: STRING = [20]; resetAddress: PupTypes.PupAddress ← tse.resetAddress; Put.Text[wh, " Last reset from: "L]; PupDefs.AppendPupAddress[reset, resetAddress]; Put.Line[wh, reset]; END; Put.CR[wh]; END; ShowName: PROCEDURE = BEGIN b: PupDefs.PupBuffer; b ← GetNameStats[]; IF b # NIL THEN BEGIN PrintNameStats[b]; PupDefs.ReturnFreePupBuffer[b]; END; PrintNameCache[]; END; PrintNameStats: PROCEDURE [b: PupDefs.PupBuffer] = BEGIN nse: LONG POINTER TO NameServerDefs.NameStatsEntry = LOOPHOLE[@b.pupBody]; Put.Line[wh, "Name Lookup Server Statistics:"L]; PrintItem[ InlineDefs.BcplToMesaLongNumber[nse.nameRequests], "Name lookup requests: "L]; PrintItem[ InlineDefs.BcplToMesaLongNumber[nse.directoriesSend], "NameLookup directories sent: "L]; PrintItem[InlineDefs.BcplToMesaLongNumber[nse.cacheHits], "Cache hits: "L]; PrintItem[ InlineDefs.BcplToMesaLongNumber[nse.cacheMisses], "Cache misses: "L]; Put.CR[wh]; END; PrintNameCache: PROCEDURE = BEGIN limit: CARDINAL = 10; ce: NameServerDefs.CacheEntry; ceo: NameServerDefs.CacheEntryObject; i: CARDINAL; names: ARRAY [0..limit) OF STRING; addrs: ARRAY [0..limit) OF PupTypes.PupAddress; Put.CR[wh]; Put.Line[wh, "Cache for Name Lookup Server:"L]; Put.Line[wh, " Count Seq size Name(s) <=> Address(es)"L]; ce ← Read[gateVector.cache]; THROUGH [0..50) UNTIL ce = NIL DO Get[to: @ceo, from: ce, size: SIZE[NameServerDefs.CacheEntryObject]]; Get[to: @names, from: BASE[ceo.names], size: limit*1]; Get[ to: @addrs, from: BASE[ceo.addrs], size: limit*SIZE[PupTypes.PupAddress]]; LD6[ceo.count]; D6[ceo.sequence]; D5[ceo.size]; Put.Text[wh, " "L]; IF LENGTH[ceo.names] = 0 THEN Put.Char[wh, '?] ELSE FOR i IN [0..MIN[limit, LENGTH[ceo.names]]) DO IF i # 0 THEN Put.Text[wh, ", "L]; ShowString[names[i]]; ENDLOOP; Put.Text[wh, " <=> "L]; IF LENGTH[ceo.addrs] = 0 THEN Put.Char[wh, '?] ELSE FOR i IN [0..MIN[limit, LENGTH[ceo.addrs]]) DO IF i # 0 THEN Put.Text[wh, ", "L]; WritePupAddress[addrs[i]]; ENDLOOP; Put.CR[wh]; ce ← ceo.next; ENDLOOP; Put.CR[wh]; Put.CR[wh]; END; ShowLocks: PROCEDURE = BEGIN limit: CARDINAL = 10; lock: Lock.Lock; lo: Lock.LockObject; lock ← Read[gateVector.locks]; IF lock = NIL THEN BEGIN Put.Line[wh, "Nothing is locked."L]; RETURN; END; Put.Line[wh, "Lock table:"L]; Put.Line[wh, " Read W Name"L]; THROUGH [0..30) UNTIL lock = NIL DO Get[to: @lo, from: lock, size: SIZE[Lock.LockObject]]; D5[lo.useCount]; Put.Text[wh, IF lo.write THEN " W "L ELSE " "L]; ShowString[lo.name]; Put.CR[wh]; lock ← lo.next; ENDLOOP; Put.CR[wh]; Put.CR[wh]; END; ShowSla: PROCEDURE = BEGIN OPEN AltoSlaDefs; p: LONG POINTER ← giantVector.slaThings; activeLines: CARDINAL; hisLineTable: LONG POINTER TO ARRAY Line OF LineTableEntry; hisLineInfo: LONG POINTER TO ARRAY Line OF LineInfoBlock; hisRoutingTable: LONG POINTER TO ARRAY SlaHost OF RoutingTableEntry; IF p = NIL THEN RETURN; p ← p + maxByte; -- skip CRC Table activeLines ← Read[Inline.LowHalf[p]]; hisLineTable ← p + 8; p ← 8 + p + maxLine*SIZE[LineTableEntry]; hisRoutingTable ← p; p ← p + maxSlaHost*SIZE[RoutingTableEntry]; hisLineInfo ← p; IF activeLines > maxLine THEN ERROR; ShowSlaInfo[activeLines, hisLineInfo, hisRoutingTable]; Put.CR[wh]; Put.CR[wh]; END; ShowRoutingTable: PROCEDURE = BEGIN i, k: CARDINAL; pupRoutingTableLength: CARDINAL; pupRoutingTable: ARRAY [0..PupDefs.defaultNumberOfNetworks] OF PupRouterDefs.RoutingTableObject; routing: PupRouterDefs.RoutingTableEntry; network: DriverDefs.NetworkObject; pupRoutingTableLength ← LENGTH[giantVector.pupRoutingTable]; IF pupRoutingTableLength > LENGTH[pupRoutingTable] THEN BEGIN Put.Line[wh, "pupRoutingTable is huge - truncating."L]; pupRoutingTableLength ← LENGTH[pupRoutingTable]; END; GetBig[ to: @pupRoutingTable, from: BASE[giantVector.pupRoutingTable], size: pupRoutingTableLength*SIZE[PupRouterDefs.RoutingTableObject]]; Put.Text[wh, " Pup Network Routing Table"L]; Put.Line[wh, " ix hp tm rt network num net hst"L]; FOR i IN [0..pupRoutingTableLength) DO routing ← @pupRoutingTable[i]; IF routing.network # NIL THEN BEGIN O3[i]; D4[routing.hop]; D4[routing.time]; O4[routing.route]; Put.Text[wh, " "L]; O6L[LOOPHOLE[routing.network]]; Get[ to: @network, from: routing.network, size: SIZE[DriverDefs.NetworkObject]]; O4[network.index]; O4[network.netNumber.b]; O4[network.hostNumber]; Put.Line[wh, ""L]; END; ENDLOOP; Put.CR[wh]; Put.Line[wh, "Routing Table:"L]; Put.Line[ wh, "| Net Via Hops | Net Via Hops | Net Via Hops |"L]; Put.Line[ wh, "|-------------------|-------------------|-------------------|"L]; k ← 0; FOR i IN [0..pupRoutingTableLength) DO routing ← @pupRoutingTable[i]; IF routing.network = NIL THEN LOOP; IF k = 0 THEN Put.Char[wh, '|]; O4[i]; Get[ to: @network, from: routing.network, size: SIZE[DriverDefs.NetworkObject]]; O4[network.netNumber.b]; Put.Char[wh, '#]; IF routing.hop # 0 THEN O3Z[routing.route] ELSE O3Z[network.hostNumber]; Put.Char[wh, '#]; O4[routing.hop]; Put.Text[wh, " |"L]; IF (k ← k + 1) = 3 THEN BEGIN Put.CR[wh]; k ← 0; END; ENDLOOP; IF k # 0 THEN Put.CR[wh]; END; ShowSlaInfo: PUBLIC PROCEDURE [ lines: CARDINAL, hisInfo: LONG POINTER, hisRouting: LONG POINTER] = BEGIN OPEN AltoSlaDefs; line: Line; info: ARRAY Line OF LineInfoBlock; lib: POINTER TO LineInfoBlock; routing: ARRAY SlaHost OF RoutingTableEntry; temp: LONG INTEGER; Put.CR[wh]; GetBig[to: @info, from: hisInfo, size: lines*SIZE[LineInfoBlock]]; GetBig[ to: @routing, from: hisRouting, size: maxSlaHost*SIZE[RoutingTableEntry]]; Put.Line[ wh, "More SLA Line Statistics: ----Packets---- ------Bytes----- Line Hi Sent Received Hi Sent Received"L]; FOR line IN [0..lines) DO lib ← @info[line]; O3[line]; LD10[lib.hiPacketsSent]; LD10[lib.packetsSent]; LD10[lib.packetsRecv]; LD10[lib.hiBytesSent]; LD10[lib.bytesSent]; LD10[lib.bytesRecv]; Put.CR[wh]; ENDLOOP; Put.Line[ wh, " ---Bits/Sec--- ---Bits/Pkt--- --Delay-- Err/10↑6 Line Hi Send Recv Hi Send Recv Hi Send Pkt Recv"L]; FOR line IN [0..lines) DO lib ← @info[line]; O3[line]; temp ← lib.hiBytesSent + overheadPerPacket*lib.hiPacketsSent; Mumble[temp, hisCounters[statSeconds]]; temp ← lib.bytesSent + overheadPerPacket*lib.packetsSent; Mumble[temp, hisCounters[statSeconds]]; temp ← lib.bytesRecv + overheadPerPacket*lib.packetsRecv; Mumble[temp, hisCounters[statSeconds]]; temp ← lib.hiBytesSent + overheadPerPacket*lib.hiPacketsSent; Mumble[temp, lib.hiPacketsSent]; temp ← lib.bytesSent + overheadPerPacket*lib.packetsSent; Mumble[temp, lib.packetsSent]; temp ← lib.bytesRecv + overheadPerPacket*lib.packetsRecv; Mumble[temp, lib.packetsRecv]; temp ← lib.hiQueueDelay*39; LD6[temp/lib.hiPacketsSent]; temp ← lib.queueDelay*39; LD6[temp/lib.packetsSent]; temp ← lib.syncErrors + lib.crcErrors + lib.controlErrors; LD10[temp*1000000/lib.packetsRecv]; Put.CR[wh]; ENDLOOP; Put.Line[wh, " Line Deaths Stuck Timeout Overrun"L]; FOR line IN [0..lines) DO lib ← @info[line]; O3[line]; LD10[lib.deaths]; LD10[lib.stuck]; LD10[lib.timeout]; LD10[lib.overrun]; Put.CR[wh]; ENDLOOP; END; -- Rats, 32 bits isn't enough -- Print a*8/b Mumble: PROCEDURE [a, b: LONG INTEGER] = BEGIN temp: LONG INTEGER; SELECT a FROM < 200000000 => temp ← (a*8)/b; ENDCASE => temp ← a/(b/8); LD6[temp]; END; ShowGateStats: PROCEDURE = BEGIN b: PupDefs.PupBuffer; b ← GetGateStats[]; IF b # NIL THEN BEGIN PrintGateStats[b]; PupDefs.ReturnFreePupBuffer[b]; END; b ← GetForwarderStats[]; IF b # NIL THEN BEGIN PrintForwarderStats[b]; PrintForwarderMatrix[b]; PupDefs.ReturnFreePupBuffer[b]; END; END; PrintGateStats: PROCEDURE [b: PupDefs.PupBuffer] = BEGIN text: STRING = [50]; i: CARDINAL; gse: LONG POINTER TO GateControlDefs.GateControlStatsEntry ← LOOPHOLE[@b.pupWords]; Put.CR[wh]; FOR i IN [0..gse.versionText.length) DO String.AppendChar[text, gse.versionText.char[i]]; ENDLOOP; Put.Line[wh, "Gateway status: "L]; Put.Text[wh, text]; PrintUpTime[gse.startTime]; Put.CR[wh]; PrintItem[gse.freeBuffers, "Free buffers: "L]; PrintItem[gse.freeDiskPages, "Free disk pages: "L]; Put.CR[wh]; END; PrintUpTime: PROCEDURE [startTime: InlineDefs.BcplLongNumber] = BEGIN now, then: LONG CARDINAL; sec: LONG CARDINAL; min: LONG CARDINAL; hours: LONG CARDINAL; Put.Text[wh, ", up "L]; then ← InlineDefs.BcplToMesaLongNumber[startTime]; now ← Time.Current[]; sec ← now - then; hours ← sec/3600; sec ← sec - hours*3600; min ← sec/60; sec ← sec - min*60; LD[hours]; Put.Char[wh, ':]; LD[min]; Put.Char[wh, ':]; LD[sec]; END; PrintTime: PROCEDURE = BEGIN text: STRING = [30]; Time.AppendCurrent[text]; Put.Text[wh, text]; Put.Text[wh, " "]; END; PrintForwarderStats: PROCEDURE [b: PupDefs.PupBuffer] = BEGIN fse: LONG POINTER TO ForwarderDefs.ForwardStatsEntry = LOOPHOLE[@b.pupBody]; Put.Line[wh, "Routing Server Statistics:"L]; PrintItem[ InlineDefs.BcplToMesaLongNumber[fse.routingInfoRequests], "Routing info requests: "L]; Put.CR[wh]; END; PrintForwarderMatrix: PROCEDURE [b: PupDefs.PupBuffer] = BEGIN FindIt: PROCEDURE [from, to: CARDINAL] = BEGIN i: CARDINAL; tme: LONG POINTER TO ForwarderDefs.TransitMatrixEntry; FOR i IN [0..fse.numberOfTMEs) DO tme ← @pupStatsTable[i]; IF from # tme.sourceNet OR to # tme.destNet THEN LOOP; LD10Dash[InlineDefs.BcplToMesaLongNumber[tme.count]]; EXIT; REPEAT FINISHED => LD10Dash[0]; ENDLOOP; END; nets: LONG POINTER TO ARRAY OF CARDINAL; pupStatsTable: LONG POINTER TO ARRAY OF ForwarderDefs.TransitMatrixEntry; from, to: CARDINAL; fse: LONG POINTER TO ForwarderDefs.ForwardStatsEntry = LOOPHOLE[@b.pupBody]; n: CARDINAL ← fse.numberOfNetworks; nets ← LOOPHOLE[@b.pupBody + SIZE[ForwarderDefs.ForwardStatsEntry]]; pupStatsTable ← LOOPHOLE[@b.pupBody + SIZE[ForwarderDefs.ForwardStatsEntry] + n]; Put.CR[wh]; Put.Line[wh, "Packets Forwarded:"L]; Put.CR[wh]; Put.Line[wh, "from to"L]; Put.CR[wh]; Put.Text[wh, " Discard"L]; FOR to IN [0..n) DO Put.Text[wh, " "L]; O4[nets[to]]; ENDLOOP; Put.CR[wh]; FOR from IN [0..n) DO O4[nets[from]]; FindIt[nets[from], 0]; FOR to IN [0..n) DO FindIt[nets[from], nets[to]]; ENDLOOP; Put.CR[wh]; ENDLOOP; END; ShowDriverStats: PROCEDURE = BEGIN i: CARDINAL; b: PupDefs.PupBuffer; Put.Line[wh, "Driver statistics:"]; Put.CR[wh]; FOR i IN [0..35) DO b ← GetPupStats[i]; IF b = NIL THEN LOOP; Put.Text[wh, "Network "]; O[i]; Put.CR[wh]; PrintDriverStats[b]; PupDefs.ReturnFreePupBuffer[b]; Put.CR[wh]; ENDLOOP; END; PrintDriverStats: PROCEDURE [b: PupDefs.PupBuffer] = BEGIN IF b = NIL THEN BEGIN Put.Line[wh, "Not Available."]; RETURN; END; SELECT b.pupWords[0] FROM AltoEthernetDefs.ethernetStatsReply => PrintEtherStats[LOOPHOLE[@b.pupWords[1]]]; AltoSlaDefs.slaStatsReply => PrintSlaStats[b]; AltoPRDefs.prStatsReply => PrintPrStats[LOOPHOLE[@b.pupWords[1]]]; ENDCASE => Put.Line[wh, "Unknown network type."]; END; PrintEtherStats: PROCEDURE [ p: LONG POINTER TO AltoEthernetDefs.EtherStatsEntry] = BEGIN OPEN p; i: CARDINAL; Put.Text[wh, "Rcv:"]; Put.Text[wh, " good "]; LD[InlineDefs.BcplToMesaLongNumber[packetsRecv]]; Put.Text[wh, ", bad "]; LD[InlineDefs.BcplToMesaLongNumber[badRecvStatus]]; Put.Text[wh, ", off "]; LD[InlineDefs.BcplToMesaLongNumber[inputOff]]; Put.Text[wh, "; Xmit:"]; Put.Text[wh, " good "]; LD[InlineDefs.BcplToMesaLongNumber[packetsSent]]; Put.Text[wh, ", bad "]; LD[InlineDefs.BcplToMesaLongNumber[badSendSatus]]; Put.Text[wh, "; Overrun "]; LD[InlineDefs.BcplToMesaLongNumber[overruns]]; Put.CR[wh]; Put.Text[wh, "Lds:"]; FOR i IN [0..16) DO Put.Char[wh, ' ]; LD[InlineDefs.BcplToMesaLongNumber[loadTable[i]]]; ENDLOOP; Put.Text[wh, "; Ovf: "]; LD[InlineDefs.BcplToMesaLongNumber[loadTable[16]]]; Put.CR[wh]; END; PrintSlaStats: PROCEDURE [b: PupDefs.PupBuffer] = BEGIN -- watch the order of these things maxHost: CARDINAL = b.pupWords[2]; sizeOfRoutingTable: CARDINAL = maxHost*SIZE[AltoSlaDefs.RoutingTableEntry]; activeLines: CARDINAL = b.pupWords[3 + sizeOfRoutingTable] + 1; routing: LONG SlaRoutingInfo = DESCRIPTOR[@b.pupWords[3], maxHost]; line: AltoSlaDefs.Line; sse: LONG POINTER TO AltoSlaDefs.SlaStatsEntry; IF b.pupWords[1] # AltoSlaDefs.slaVersion THEN Put.Line[wh, "**** BARF: Wrong version number."]; IF b.pupWords[2] # AltoSlaDefs.maxSlaHost THEN Put.Line[wh, "**** BARF: Wrong routing table size."]; IF activeLines > 16 THEN Put.Line[wh, "**** BARF: Too many lines."]; Put.Line[ wh, "SLA Line Statistics: ---Packets---- ------Bytes----- ------Errors----- Line To Sent Received Sent Received CRC Sync Control State"L]; sse ← LOOPHOLE[@b.pupWords[4 + sizeOfRoutingTable]]; FOR line IN [0..MIN[activeLines, 16]) DO O3[line]; PrintOtherEnd[line, routing]; LD10[InlineDefs.BcplToMesaLongNumber[sse.packetsSent]]; LD10[InlineDefs.BcplToMesaLongNumber[sse.packetsRecv]]; LD10[InlineDefs.BcplToMesaLongNumber[sse.bytesSent]]; LD10[InlineDefs.BcplToMesaLongNumber[sse.bytesRecv]]; D6[sse.badCrc]; D6[sse.syncErrors]; D6[sse.controlError]; Put.Text[wh, " "L]; SELECT LOOPHOLE[sse.state, AltoSlaDefs.LineState] FROM down => Put.Line[wh, "Down"L]; halfUp => Put.Line[wh, "Half Up"L]; up => Put.Line[wh, "Up"L]; loopedBack => Put.Line[wh, "Looped back"L]; missing => Put.Line[wh, "Missing"L]; ENDCASE => Put.Line[wh, "?"L]; sse ← sse + SIZE[AltoSlaDefs.SlaStatsEntry]; ENDLOOP; PrintSlaRoutingTable[routing]; END; SlaRoutingInfo: TYPE = DESCRIPTOR FOR ARRAY OF AltoSlaDefs.RoutingTableEntry; PrintOtherEnd: PROCEDURE [ line: AltoSlaDefs.Line, routing: LONG SlaRoutingInfo] = BEGIN host: AltoSlaDefs.SlaHost; rte: LONG POINTER TO AltoSlaDefs.RoutingTableEntry; FOR host IN AltoSlaDefs.SlaHost DO rte ← @routing[host]; IF rte.line = line AND rte.hops = 1 THEN BEGIN O4[host + 1]; EXIT; END; REPEAT FINISHED => Put.Text[wh, " ?"L]; ENDLOOP; END; PrintSlaRoutingTable: PROCEDURE [routing: LONG SlaRoutingInfo] = BEGIN host: AltoSlaDefs.SlaHost; rte: LONG POINTER TO AltoSlaDefs.RoutingTableEntry; k: CARDINAL; Put.Line[ wh, " Routing Table: Host Line Hops Host Line Hops Host Line Hops Host Line Hops"L]; k ← 0; FOR host IN [0..LENGTH[routing]) DO rte ← @routing[host]; IF rte.hops = AltoSlaDefs.longHop THEN LOOP; IF k # 0 THEN Put.Text[wh, " "L]; O4[host]; D5[rte.line]; D5[rte.hops]; IF (k ← k + 1) = 4 THEN BEGIN Put.CR[wh]; k ← 0; END; ENDLOOP; IF k # 0 THEN Put.CR[wh]; END; PrintPrStats: PROCEDURE [p: LONG POINTER TO AltoPRDefs.PRStatsEntry] = BEGIN OPEN p; i: CARDINAL; Put.Text[wh, "Rcv:"]; Put.Text[wh, " packets "]; LD[packetsReceived]; Put.Text[wh, ", pups "]; LD[oneFragPupRcvd]; Put.Text[wh, ", "]; LD[twoFragPupRcvd]; Put.Text[wh, ", "]; LD[threeFragPupRcvd]; Put.Text[wh, ", words "]; LD[wordsReceived]; Put.Text[wh, ", alive "]; LD[imAliveReceived]; Put.CR[wh]; Put.Text[wh, "Xmit:"]; Put.Text[wh, " packets "]; LD[packetsSent]; Put.Text[wh, ", pups "]; LD[oneFragPupSent]; Put.Text[wh, ", "]; LD[twoFragPupSent]; Put.Text[wh, ", "]; LD[threeFragPupSent]; Put.Text[wh, ", words "]; LD[wordsSent]; Put.Text[wh, ", TOPs "]; LD[topsSent]; Put.Text[wh, ", alive "]; LD[imAliveSent]; Put.CR[wh]; Put.Text[wh, "Assembly timeout "]; LD[assemblyTimeout]; Put.Text[wh, ", Assembly overflow "]; LD[assemblyOverflow]; Put.Text[wh, ", Input Filter: "]; LD[inputFilter]; Put.CR[wh]; Put.Text[wh, "Old Packets: "]; LD[oldPackets]; Put.Text[wh, "; Skipped Packets: "]; LD[skippedPackets]; Put.Text[wh, "; Seq Resets: "]; LD[sequencerResets]; Put.CR[wh]; Put.Text[wh, "Destination down: "]; LD[destinationDown]; Put.Text[wh, "; Output Discard: "]; LD[outputPacketsDiscarded]; Put.Text[wh, "; Xfer Timeouts: "]; LD[transferTimeout]; Put.CR[wh]; Put.Text[wh, "Hosts: "]; FOR i IN [0..maxHosts) DO IF i # 0 THEN Put.Char[wh, ',]; Put.Text[wh, IF hostsUp[i] THEN " up" ELSE " down"]; ENDLOOP; Put.CR[wh]; END; GetBootStats: PROCEDURE RETURNS [PupDefs.PupBuffer] = BEGIN b: PupDefs.PupBuffer; soc: PupDefs.PupSocket; where: PupTypes.PupAddress ← who; where.socket ← PupTypes.miscSrvSoc; soc ← PupDefs.PupSocketMake[ PupTypes.fillInSocketID, where, PupDefs.SecondsToTocks[10]]; thisID ← thisID + 1; THROUGH [0..25) DO b ← PupDefs.GetFreePupBuffer[]; b.pupID.a ← b.pupID.b ← thisID; b.pupType ← BootServerDefs.bootStatsRequest; PupDefs.SetPupContentsWords[b, 0]; soc.put[b]; UNTIL (b ← soc.get[]) = NIL DO -- Until timeout, or we find the expected one SELECT TRUE FROM (b.pupType = error) => ShowErrorPup[b]; (b.pupType = BootServerDefs.bootStatsReply) AND (b.pupID.a = thisID AND b.pupID.b = thisID) => BEGIN PupDefs.PupSocketDestroy[soc]; RETURN[b]; END; ENDCASE => BEGIN PupDefs.ReturnFreePupBuffer[b]; LOOP; END; PupDefs.ReturnFreePupBuffer[b]; ENDLOOP; IF b # NIL THEN PupDefs.ReturnFreePupBuffer[b] ENDLOOP; PupDefs.PupSocketDestroy[soc]; RETURN[NIL]; END; GetEchoStats: PROCEDURE RETURNS [PupDefs.PupBuffer] = BEGIN b: PupDefs.PupBuffer; soc: PupDefs.PupSocket; where: PupTypes.PupAddress ← who; where.socket ← PupTypes.echoSoc; soc ← PupDefs.PupSocketMake[ PupTypes.fillInSocketID, where, PupDefs.SecondsToTocks[10]]; thisID ← thisID + 1; THROUGH [0..25) DO b ← PupDefs.GetFreePupBuffer[]; b.pupID.a ← b.pupID.b ← thisID; b.pupType ← EchoServerDefs.echoStatsRequest; PupDefs.SetPupContentsWords[b, 0]; soc.put[b]; UNTIL (b ← soc.get[]) = NIL DO -- Until timeout, or we find the expected one SELECT TRUE FROM (b.pupType = error) => ShowErrorPup[b]; (b.pupType = EchoServerDefs.echoStatsReply) AND (b.pupID.a = thisID AND b.pupID.b = thisID) => BEGIN PupDefs.PupSocketDestroy[soc]; RETURN[b]; END; ENDCASE => BEGIN PupDefs.ReturnFreePupBuffer[b]; LOOP; END; PupDefs.ReturnFreePupBuffer[b]; ENDLOOP; IF b # NIL THEN PupDefs.ReturnFreePupBuffer[b] ENDLOOP; PupDefs.PupSocketDestroy[soc]; RETURN[NIL]; END; GetForwarderStats: PROCEDURE RETURNS [PupDefs.PupBuffer] = BEGIN b: PupDefs.PupBuffer; soc: PupDefs.PupSocket; where: PupTypes.PupAddress ← who; where.socket ← PupTypes.gatewaySoc; soc ← PupDefs.PupSocketMake[ PupTypes.fillInSocketID, where, PupDefs.SecondsToTocks[10]]; thisID ← thisID + 1; THROUGH [0..25) DO b ← PupDefs.GetFreePupBuffer[]; b.pupID.a ← b.pupID.b ← thisID; b.pupType ← ForwarderDefs.forwarderStatsRequest; PupDefs.SetPupContentsWords[b, 0]; soc.put[b]; UNTIL (b ← soc.get[]) = NIL DO -- Until timeout, or we find the expected one SELECT TRUE FROM (b.pupType = error) => ShowErrorPup[b]; (b.pupType = ForwarderDefs.forwarderStatsReply) AND (b.pupID.a = thisID AND b.pupID.b = thisID) => BEGIN PupDefs.PupSocketDestroy[soc]; RETURN[b]; END; ENDCASE => BEGIN PupDefs.ReturnFreePupBuffer[b]; LOOP; END; PupDefs.ReturnFreePupBuffer[b]; ENDLOOP; IF b # NIL THEN PupDefs.ReturnFreePupBuffer[b] ENDLOOP; PupDefs.PupSocketDestroy[soc]; RETURN[NIL]; END; GetNameStats: PROCEDURE RETURNS [PupDefs.PupBuffer] = BEGIN b: PupDefs.PupBuffer; soc: PupDefs.PupSocket; where: PupTypes.PupAddress ← who; where.socket ← PupTypes.miscSrvSoc; soc ← PupDefs.PupSocketMake[ PupTypes.fillInSocketID, where, PupDefs.SecondsToTocks[10]]; thisID ← thisID + 1; THROUGH [0..25) DO b ← PupDefs.GetFreePupBuffer[]; b.pupID.a ← b.pupID.b ← thisID; b.pupType ← NameServerDefs.nameStatsRequest; PupDefs.SetPupContentsWords[b, 0]; soc.put[b]; UNTIL (b ← soc.get[]) = NIL DO -- Until timeout, or we find the expected one SELECT TRUE FROM (b.pupType = error) => ShowErrorPup[b]; (b.pupType = NameServerDefs.nameStatsReply) AND (b.pupID.a = thisID AND b.pupID.b = thisID) => BEGIN PupDefs.PupSocketDestroy[soc]; RETURN[b]; END; ENDCASE => BEGIN PupDefs.ReturnFreePupBuffer[b]; LOOP; END; PupDefs.ReturnFreePupBuffer[b]; ENDLOOP; IF b # NIL THEN PupDefs.ReturnFreePupBuffer[b] ENDLOOP; PupDefs.PupSocketDestroy[soc]; RETURN[NIL]; END; GetTimeStats: PROCEDURE RETURNS [PupDefs.PupBuffer] = BEGIN b: PupDefs.PupBuffer; soc: PupDefs.PupSocket; where: PupTypes.PupAddress ← who; where.socket ← PupTypes.miscSrvSoc; soc ← PupDefs.PupSocketMake[ PupTypes.fillInSocketID, where, PupDefs.SecondsToTocks[10]]; thisID ← thisID + 1; THROUGH [0..25) DO b ← PupDefs.GetFreePupBuffer[]; b.pupID.a ← b.pupID.b ← thisID; b.pupType ← TimeServerDefs.timeStatsRequest; PupDefs.SetPupContentsWords[b, 0]; soc.put[b]; UNTIL (b ← soc.get[]) = NIL DO -- Until timeout, or we find the expected one SELECT TRUE FROM (b.pupType = error) => ShowErrorPup[b]; (b.pupType = TimeServerDefs.timeStatsReply) AND (b.pupID.a = thisID AND b.pupID.b = thisID) => BEGIN PupDefs.PupSocketDestroy[soc]; RETURN[b]; END; ENDCASE => BEGIN PupDefs.ReturnFreePupBuffer[b]; LOOP; END; PupDefs.ReturnFreePupBuffer[b]; ENDLOOP; IF b # NIL THEN PupDefs.ReturnFreePupBuffer[b] ENDLOOP; PupDefs.PupSocketDestroy[soc]; RETURN[NIL]; END; GetPupStats: PROCEDURE [driver: INTEGER] RETURNS [PupDefs.PupBuffer] = BEGIN b: PupDefs.PupBuffer ← NIL; thisID ← thisID + 1; DO -- until we get the answer IF b = NIL THEN b ← PupDefs.GetFreePupBuffer[]; b.pupID ← [27182, thisID]; b.pupWords[0] ← driver; b.pupType ← GateControlDefs.pupStatsSend; PupDefs.SetPupContentsWords[b, 1]; statSoc.put[b]; b ← statSoc.get[]; IF b = NIL THEN LOOP; IF b.pupID.b # thisID OR b.pupType = error THEN LOOP; IF b.pupType = GateControlDefs.pupStatsNak THEN BEGIN PupDefs.ReturnFreePupBuffer[b]; RETURN[NIL]; END; IF b.pupType = GateControlDefs.pupStatsAck THEN EXIT; ERROR; ENDLOOP; RETURN[b]; END; GetGateStats: PROCEDURE RETURNS [PupDefs.PupBuffer] = BEGIN b: PupDefs.PupBuffer ← NIL; thisID ← thisID + 1; DO -- until we get the answer IF b = NIL THEN b ← PupDefs.GetFreePupBuffer[]; b.pupID ← [27182, thisID]; b.pupType ← GateControlDefs.gateControlStatsSend; PupDefs.SetPupContentsWords[b, 0]; coreSoc.put[b]; b ← coreSoc.get[]; IF b = NIL THEN LOOP; IF b.pupID.b # thisID OR b.pupType = error THEN LOOP; IF b.pupType = GateControlDefs.gateControlStatsNak THEN BEGIN PupDefs.ReturnFreePupBuffer[b]; RETURN[NIL]; END; IF b.pupType = GateControlDefs.gateControlStatsAck THEN EXIT; ERROR; ENDLOOP; RETURN[b]; END; GetBig: PROCEDURE [to: POINTER, from: LONG 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; Read: PROCEDURE [p: POINTER] RETURNS [x: UNSPECIFIED] = BEGIN Get[to: @x, from: p, size: 1]; END; -- get a block of info from the "right" address space thisID: CARDINAL ← 0; Get: PROCEDURE [to: POINTER, from: LONG POINTER, size: CARDINAL] = BEGIN b: PupDefs.PupBuffer ← NIL; i: CARDINAL; IF Inline.HighHalf[from] # 0 THEN ERROR; IF size > 250 THEN ERROR; thisID ← thisID + 1; DO -- until we get the answer IF b = NIL THEN b ← PupDefs.GetFreePupBuffer[]; b.pupID ← [27182, thisID]; b.pupWords[0] ← LOOPHOLE[Inline.LowHalf[from]]; b.pupWords[1] ← size; b.pupType ← GateControlDefs.gateControlExamine; PupDefs.SetPupContentsWords[b, 2]; coreSoc.put[b]; b ← coreSoc.get[]; IF b = NIL THEN LOOP; IF b.pupID.b # thisID OR b.pupType = error THEN LOOP; IF b.pupType = GateControlDefs.gateControlStatsAck AND PupDefs.GetPupContentsBytes[b] = 2*(2 + size) THEN EXIT; ERROR; ENDLOOP; FOR i IN [0..size) DO (to + i)↑ ← b.pupWords[2 + i]; ENDLOOP; PupDefs.ReturnFreePupBuffer[b]; END; PrintItem: PROCEDURE [d: LONG CARDINAL, s: STRING] = BEGIN IF d = 0 THEN RETURN; Put.Text[wh, " "L]; Put.Text[wh, s]; LD[d]; Put.CR[wh]; END; ShowString: PROCEDURE [s: STRING] = BEGIN temp: STRING = [204]; -- maxlength gets clobbered IF s # NIL THEN BEGIN Get[to: temp, from: s, size: 100]; IF temp.length > 200 THEN temp.length ← 25; Put.Text[wh, temp]; END ELSE Put.Text[wh, "NIL"L]; END; WritePupAddress: PROCEDURE [p: PupTypes.PupAddress] = BEGIN Put.Number[wh, p.net, [8, FALSE, TRUE, 0]]; Put.Char[wh, '#]; Put.Number[wh, p.host, [8, FALSE, TRUE, 0]]; Put.Char[wh, '#]; IF p.socket.a # 0 THEN BEGIN Put.Number[wh, p.socket.a, [8, FALSE, TRUE, 0]]; Put.Char[wh, '|]; END; Put.Number[wh, p.socket.b, [8, FALSE, TRUE, 0]]; END; ShowErrorPup: PUBLIC PROCEDURE [b: PupDefs.PupBuffer] = BEGIN text: STRING = [100]; PupDefs.AppendErrorPup[text, b]; Put.Line[wh, text]; END; O: PROCEDURE [n: CARDINAL] = BEGIN Put.Number[wh, n, [8, FALSE, TRUE, 0]]; END; O3: PROCEDURE [n: CARDINAL] = BEGIN Put.Number[wh, n, [8, FALSE, TRUE, 3]]; END; O4: PROCEDURE [n: CARDINAL] = BEGIN Put.Number[wh, n, [8, FALSE, TRUE, 4]]; END; O5: PROCEDURE [n: CARDINAL] = BEGIN Put.Number[wh, n, [8, FALSE, TRUE, 5]]; END; O6L: PROCEDURE [n: LONG CARDINAL] = BEGIN Put.Number[wh, Inline.LowHalf[n], [8, FALSE, TRUE, 7]]; END; O6: PROCEDURE [n: CARDINAL] = BEGIN Put.Number[wh, n, [8, FALSE, TRUE, 7]]; END; O3Z: PROCEDURE [n: CARDINAL] = BEGIN Put.Number[wh, n, [8, TRUE, TRUE, 3]]; END; D: PROCEDURE [n: CARDINAL] = BEGIN Put.Number[wh, n, [10, FALSE, TRUE, 0]]; END; D4: PROCEDURE [n: CARDINAL] = BEGIN Put.Number[wh, n, [10, FALSE, TRUE, 4]]; END; D5: PROCEDURE [n: CARDINAL] = BEGIN Put.Number[wh, n, [10, FALSE, TRUE, 5]]; END; D6: PROCEDURE [n: CARDINAL] = BEGIN Put.Number[wh, n, [10, FALSE, TRUE, 6]]; END; LD: PROCEDURE [n: LONG INTEGER] = BEGIN s: STRING = [20]; String.AppendLongNumber[s, n, 10]; Put.Text[wh, s]; END; LD6: PROCEDURE [num: LONG INTEGER] = BEGIN s: STRING = [20]; String.AppendLongNumber[s, num, 10]; THROUGH [s.length..6) DO Put.Char[wh, ' ]; ENDLOOP; Put.Text[wh, s]; END; LD10: PROCEDURE [num: LONG INTEGER] = BEGIN s: STRING = [20]; String.AppendLongNumber[s, num, 10]; THROUGH [s.length..10) DO Put.Char[wh, ' ]; ENDLOOP; Put.Text[wh, s]; END; LD10Dash: PROCEDURE [n: LONG INTEGER] = BEGIN IF n = 0 THEN Put.Text[wh, " - "L] ELSE LD10[n]; END; MakeConnection: PROCEDURE = BEGIN OPEN PupDefs; DO Put.Text[wh, "Looking at "L]; Put.Text[wh, name]; Put.Line[wh, "."L]; GetPupAddress[ @who, name ! PupNameTrouble => BEGIN Put.Line[wh, e]; LOOP; END]; Put.CR[wh]; Put.CR[wh]; Put.CR[wh]; EXIT; ENDLOOP; who.socket ← [31415, 9265]; coreSoc ← PupSocketMake[PupTypes.fillInSocketID, who, MsToTocks[1000]]; who.socket ← PupTypes.statSoc; statSoc ← PupSocketMake[PupTypes.fillInSocketID, who, MsToTocks[1000]]; giantVectorLoc ← Read[CommUtilDefs.magicMemoryLocation]; Get[ to: @giantVector, from: giantVectorLoc, size: SIZE[DriverDefs.GiantVector]]; Get[ to: @gateVector, from: giantVector.spare, size: SIZE[GateDefs.GateDebugRecord]]; END; GetStrings: PROCEDURE = BEGIN s: StatsDefs.StatCounterIndex; temp: STRING = [204]; -- maxlength gets clobbered 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] ← Storage.String[temp.length]; String.AppendString[hisStrings[s], temp]; ENDLOOP; END; -- main program PupDefs.PupPackageMake[]; MakeConnection[]; ShowGateStats[]; Put.CR[wh]; Put.CR[wh]; ShowEcho[]; ShowTime[]; Put.Char[wh, Ascii.FF]; Put.CR[wh]; GetStrings[]; Looker[]; Put.Char[wh, Ascii.FF]; Put.CR[wh]; ShowDriverStats[]; Put.CR[wh]; Put.CR[wh]; ShowSla[]; Put.Char[wh, Ascii.FF]; Put.CR[wh]; ShowRoutingTable[]; Put.Char[wh, Ascii.FF]; Put.CR[wh]; ShowBoot[]; Put.Char[wh, Ascii.FF]; Put.CR[wh]; ShowName[]; Put.Char[wh, Ascii.FF]; Put.CR[wh]; ShowLocks[]; Put.Char[wh, Ascii.FF]; Put.CR[wh]; ImageDefs.StopMesa[]; END.