-- Copyright (C) 1983  by Xerox Corporation. All rights reserved. 
-- ForwarderStats.mesa, HGM, 23-Sep-83 16:16:40

DIRECTORY
  Driver USING [GetDeviceChain, Network],
  ForwarderDefs USING [
    Counters, GetPointerToPupGateStats, ForwardStatsEntry, TransitMatrixEntry,
    statGateInfoReplies, forwardVersion, forwarderStatsReply],
  Stats USING [StatCounterIndex, StatsGetCounters],
  PupWireFormat USING [MesaToBcplLongNumber],
  PupDefs USING [PupBuffer, ReturnPup],
  PupTypes USING [maxDataWordsPerGatewayPup];

ForwarderStats: PROGRAM
  IMPORTS PupWireFormat, Stats, ForwarderDefs, PupDefs, Driver
  EXPORTS ForwarderDefs =
  BEGIN OPEN PupDefs;

  stats: LONG POINTER TO ARRAY Stats.StatCounterIndex OF LONG CARDINAL =
    Stats.StatsGetCounters[];

  -- This may be too soon (before initialization), and/or too late (page fault)
  firstNetwork: Driver.Network ← Driver.GetDeviceChain[];

  ForwarderStats: PUBLIC PROCEDURE [b: PupBuffer] =
    BEGIN OPEN ForwarderDefs;
    packets: LONG POINTER TO ForwarderDefs.Counters;
    bytes: LONG POINTER TO ForwarderDefs.Counters;
    nets: CARDINAL;
    limit: CARDINAL;
    AddStat: PROCEDURE [s, d: CARDINAL, n: LONG CARDINAL] =
      BEGIN
      IF n = 0 THEN RETURN;
      IF t = limit THEN RETURN;  -- Buffer full
      t ← t + 1;
      tme↑ ← [s, d, PupWireFormat.MesaToBcplLongNumber[n]];
      tme ← tme + SIZE[TransitMatrixEntry];
      END;
    n, t, length: CARDINAL ← 0;
    from, to: Driver.Network;
    fse: LONG POINTER TO ForwardStatsEntry;
    tme: LONG POINTER TO TransitMatrixEntry;
    [packets, bytes, nets] ← ForwarderDefs.GetPointerToPupGateStats[];
    fse ← LOOPHOLE[@b.pup.pupWords];
    length ← SIZE[ForwardStatsEntry];
    FOR from ← firstNetwork, from.next UNTIL from = NIL DO
      b.pup.pupWords[length + n] ← from.pupNetNumber; n ← n + 1; ENDLOOP;
    length ← length + n;
    limit ← (PupTypes.maxDataWordsPerGatewayPup - SIZE[ForwardStatsEntry] - n)/
      SIZE[TransitMatrixEntry];
    tme ← LOOPHOLE[@b.pup.pupWords + length];
    IF packets # NIL THEN
      BEGIN
      FOR from ← firstNetwork, from.next UNTIL from = NIL DO
        AddStat[from.pupNetNumber, 0, packets[from.index + 0*nets]];
        FOR to ← firstNetwork, to.next UNTIL to = NIL DO
          AddStat[
            from.pupNetNumber, to.pupNetNumber, packets[
            from.index + to.index*nets]];
          ENDLOOP;
        ENDLOOP;
      END;
    IF bytes # NIL THEN
      BEGIN
      FOR from ← firstNetwork, from.next UNTIL from = NIL DO
        AddStat[from.pupNetNumber, 0, bytes[from.index + 0*nets]];
        FOR to ← firstNetwork, to.next UNTIL to = NIL DO
          AddStat[
            from.pupNetNumber, to.pupNetNumber, bytes[
            from.index + to.index*nets]];
          ENDLOOP;
        ENDLOOP;
      END;
    length ← length + t*SIZE[TransitMatrixEntry];
    fse↑ ← [
      version: forwardVersion,
      routingInfoRequests: PupWireFormat.MesaToBcplLongNumber[
      stats[statGateInfoReplies]], numberOfNetworks: n, numberOfTMEs: t];
    ReturnPup[b, forwarderStatsReply, 2*length];
    END;

  END.