void BcmPort::updateStats()

in fboss/agent/hw/bcm/BcmPort.cpp [1199:1349]


void BcmPort::updateStats() {
  auto lockedPortStatsPtr = portStats_.wlock();
  if (!lockedPortStatsPtr->has_value()) {
    return;
  }

  // TODO: It would be nicer to use a monotonic clock, but unfortunately
  // the ServiceData code currently expects everyone to use system time.
  auto now = duration_cast<seconds>(system_clock::now().time_since_epoch());
  HwPortStats curPortStats, lastPortStats;
  lastPortStats = curPortStats = (*lockedPortStatsPtr)->portStats();

  // All stats start with a unitialized (-1) value. If there are no in discards
  // we will just report that as the monotonic counter. Instead set it to
  // 0 if uninintialized
  *curPortStats.inDiscards_() = *curPortStats.inDiscards_() ==
          hardware_stats_constants::STAT_UNINITIALIZED()
      ? 0
      : *curPortStats.inDiscards_();
  curPortStats.timestamp_() = now.count();

  updateStat(now, kInBytes(), snmpIfHCInOctets, &(*curPortStats.inBytes_()));
  updateStat(
      now,
      kInUnicastPkts(),
      snmpIfHCInUcastPkts,
      &(*curPortStats.inUnicastPkts_()));
  updateStat(
      now,
      kInMulticastPkts(),
      snmpIfHCInMulticastPkts,
      &(*curPortStats.inMulticastPkts_()));
  updateStat(
      now,
      kInBroadcastPkts(),
      snmpIfHCInBroadcastPkts,
      &(*curPortStats.inBroadcastPkts_()));
  updateStat(
      now,
      kInDiscardsRaw(),
      snmpIfInDiscards,
      &(*curPortStats.inDiscardsRaw_()));
  updateStat(now, kInErrors(), snmpIfInErrors, &(*curPortStats.inErrors_()));
  updateStat(
      now,
      kInIpv4HdrErrors(),
      snmpIpInHdrErrors,
      &(*curPortStats.inIpv4HdrErrors_()));
  updateStat(
      now,
      kInIpv6HdrErrors(),
      snmpIpv6IfStatsInHdrErrors,
      &(*curPortStats.inIpv6HdrErrors_()));
  updateStat(
      now, kInPause(), snmpDot3InPauseFrames, &(*curPortStats.inPause_()));
  // Egress Stats
  updateStat(now, kOutBytes(), snmpIfHCOutOctets, &(*curPortStats.outBytes_()));
  updateStat(
      now,
      kOutUnicastPkts(),
      snmpIfHCOutUcastPkts,
      &(*curPortStats.outUnicastPkts_()));
  updateStat(
      now,
      kOutMulticastPkts(),
      snmpIfHCOutMulticastPkts,
      &(*curPortStats.outMulticastPkts_()));
  updateStat(
      now,
      kOutBroadcastPkts(),
      snmpIfHCOutBroadcastPckts,
      &(*curPortStats.outBroadcastPkts_()));
  updateStat(
      now, kOutDiscards(), snmpIfOutDiscards, &(*curPortStats.outDiscards_()));
  updateStat(now, kOutErrors(), snmpIfOutErrors, &(*curPortStats.outErrors_()));
  updateStat(
      now, kOutPause(), snmpDot3OutPauseFrames, &(*curPortStats.outPause_()));

  if (hw_->getPlatform()->getAsic()->isSupported(HwAsic::Feature::ECN)) {
    // ECN stats not supported by TD2
    updateStat(
        now,
        kOutEcnCounter(),
        snmpBcmTxEcnErrors,
        &(*curPortStats.outEcnCounter_()));
  }
  updateStat(
      now,
      kInDstNullDiscards(),
      snmpBcmCustomReceive3,
      &(*curPortStats.inDstNullDiscards_()));

  auto settings = getProgrammedSettings();
  if (settings && settings->getPfc().has_value()) {
    updatePortPfcStats(now, curPortStats, settings->getPfcPriorities());
  }
  updateFecStats(now, curPortStats);
  updateFdrStats(now);
  updateWredStats(now, &(*curPortStats.wredDroppedPackets_()));
  queueManager_->updateQueueStats(now, &curPortStats);

  std::vector<utility::CounterPrevAndCur> toSubtractFromInDiscardsRaw = {
      {*lastPortStats.inDstNullDiscards_(),
       *curPortStats.inDstNullDiscards_()}};
  if (isMmuLossy()) {
    // If MMU setup as lossy, all incoming pause frames will be
    // discarded and will count towards in discards. This makes in discards
    // counter somewhat useless. So instead calculate "in_non_pause_discards",
    // by subtracting the pause frames received from in_discards.
    // TODO: Test if this is true when rx pause is enabled
    toSubtractFromInDiscardsRaw.emplace_back(
        *lastPortStats.inPause_(), *curPortStats.inPause_());
  }
  // as with pause, remove incoming PFC frames from the discards
  // as well
  if (curPortStats.inPfcCtrl_() !=
      hardware_stats_constants::STAT_UNINITIALIZED()) {
    toSubtractFromInDiscardsRaw.emplace_back(
        *lastPortStats.inPfcCtrl_(), *curPortStats.inPfcCtrl_());
  }

  *curPortStats.inDiscards_() += utility::subtractIncrements(
      {*lastPortStats.inDiscardsRaw_(), *curPortStats.inDiscardsRaw_()},
      toSubtractFromInDiscardsRaw);

  auto inDiscards = getPortCounterIf(kInDiscards());
  inDiscards->updateValue(now, *curPortStats.inDiscards_());

  *lockedPortStatsPtr = BcmPortStats(curPortStats, now);

  // Update the queue length stat
  uint32_t qlength;
  auto ret = bcm_port_queued_count_get(unit_, port_, &qlength);
  if (BCM_FAILURE(ret)) {
    XLOG(ERR) << "Failed to get queue length for port " << port_ << " :"
              << bcm_errmsg(ret);
  } else {
    outQueueLen_.addValue(now.count(), qlength);
    // TODO: outQueueLen_ only exports the average queue length over the last
    // 60 seconds, 10 minutes, etc.
    // We should also export the current value.  We could use a simple counter
    // or a dynamic counter for this.
  }

  // Update the packet length histograms
  updatePktLenHist(now, &inPktLengths_, kInPktLengthStats);
  updatePktLenHist(now, &outPktLengths_, kOutPktLengthStats);

  // Update any platform specific port counters
  getPlatformPort()->updateStats();
};