예제 #1
0
	void updateNioCounters(HSP *sp) {
		// don't do anything if we already refreshed the numbers less than a second ago
		if(sp->nio_last_update == sp->clk) {
			return;
		}
		sp->nio_last_update = sp->clk;

		// first read all the counters into new_nio
		PPDH_RAW_COUNTER_ITEM value;
		uint32_t icount = readMultiCounter("\\Network Interface(*)\\Bytes Received/sec",&value);
		if(value) {
			for(uint32_t i = 0; i < icount; i++){
				//myLog(LOG_DEBUG, "bytes_received counter <%s> = %lu",
				//	value[i].szName,
				//	value[i].RawValue.FirstValue);
				SFLHost_nio_counters *newctrs = getNewNIO(sp, value[i].szName);
				if(newctrs) newctrs->bytes_in = value[i].RawValue.FirstValue;
			}
			my_free(value);
			value = NULL;
		}

		icount = readMultiCounter("\\Network Interface(*)\\Packets Received/sec",&value);
		if(value) {
			for(uint32_t i = 0; i < icount; i++){
				SFLHost_nio_counters *newctrs = getNewNIO(sp, value[i].szName);
				if(newctrs) newctrs->pkts_in = (uint32_t)value[i].RawValue.FirstValue;
			}
			my_free(value);
			value = NULL;
		}
		icount = readMultiCounter("\\Network Interface(*)\\Packets Received Errors",&value);
		if(value) {
			for(uint32_t i = 0; i < icount; i++){
				SFLHost_nio_counters *newctrs = getNewNIO(sp, value[i].szName);
				if(newctrs) newctrs->errs_in = (uint32_t)value[i].RawValue.FirstValue;
			}
			my_free(value);
			value = NULL;
		}
		icount = readMultiCounter("\\Network Interface(*)\\Packets Received Discarded",&value);
		if(value) {
			for(uint32_t i = 0; i < icount; i++){
				SFLHost_nio_counters *newctrs = getNewNIO(sp, value[i].szName);
				if(newctrs) newctrs->drops_in = (uint32_t)value[i].RawValue.FirstValue;
			}
			my_free(value);
			value = NULL;
		}
		icount = readMultiCounter("\\Network Interface(*)\\Bytes Sent/sec",&value);
		if(value) {
			for(uint32_t i = 0; i < icount; i++){
				SFLHost_nio_counters *newctrs = getNewNIO(sp, value[i].szName);
				if(newctrs) newctrs->bytes_out = value[i].RawValue.FirstValue;
			}
			my_free(value);
			value = NULL;
		}

		icount = readMultiCounter("\\Network Interface(*)\\Packets Sent/sec",&value);
		if(value) {
			for(uint32_t i = 0; i < icount; i++){
				SFLHost_nio_counters *newctrs = getNewNIO(sp, value[i].szName);
				if(newctrs) newctrs->pkts_out = (uint32_t)value[i].RawValue.FirstValue;
			}
			my_free(value);
			value = NULL;
		}
		icount = readMultiCounter("\\Network Interface(*)\\Packets Sent Errors",&value);
		if(value) {
			for(uint32_t i = 0; i < icount; i++){
				SFLHost_nio_counters *newctrs = getNewNIO(sp, value[i].szName);
				if(newctrs) newctrs->errs_out = (uint32_t)value[i].RawValue.FirstValue;
			}
			my_free(value);
			value = NULL;
		}
		icount = readMultiCounter("\\Network Interface(*)\\Packets Sent Discarded",&value);
		if(value) {
			for(uint32_t i = 0; i < icount; i++){
				SFLHost_nio_counters *newctrs = getNewNIO(sp, value[i].szName);
				if(newctrs) newctrs->drops_out = (uint32_t)value[i].RawValue.FirstValue;
			}
			my_free(value);
			value = NULL;
		}

		// now compute the deltas,  sanity check them, accumulate and latch
		for(uint32_t i = 0; i < sp->adaptorList->num_adaptors; i++) {
			SFLAdaptor *ad = sp->adaptorList->adaptors[i];
			if(ad) {
				HSPAdaptorNIO *nio = (HSPAdaptorNIO *)ad->userData;
				if(nio) {
					// have to detect discontinuities here, so use a full
					// set of latched counters and accumulators.
					int accumulate = nio->last_update ? YES : NO;
					nio->last_update = sp->clk;
					uint64_t maxDeltaBytes = HSP_MAX_NIO_DELTA64;

					SFLHost_nio_counters delta;
#define NIO_COMPUTE_DELTA(field) delta.field = nio->new_nio.field - nio->last_nio.field
					NIO_COMPUTE_DELTA(pkts_in);
					NIO_COMPUTE_DELTA(errs_in);
					NIO_COMPUTE_DELTA(drops_in);
					NIO_COMPUTE_DELTA(pkts_out);
					NIO_COMPUTE_DELTA(errs_out);
					NIO_COMPUTE_DELTA(drops_out);

					if(sp->nio_polling_secs == 0) {
						// 64-bit byte counters
						NIO_COMPUTE_DELTA(bytes_in);
						NIO_COMPUTE_DELTA(bytes_out);
					}
					else {
						// for case where byte counters are 32-bit,  we need
						// to use 32-bit unsigned arithmetic to avoid spikes
						delta.bytes_in = (uint32_t)nio->new_nio.bytes_in - nio->last_bytes_in32;
						delta.bytes_out = (uint32_t)nio->new_nio.bytes_out - nio->last_bytes_out32;
						nio->last_bytes_in32 = (uint32_t)nio->new_nio.bytes_in;
						nio->last_bytes_out32 = (uint32_t)nio->new_nio.bytes_out;
						maxDeltaBytes = HSP_MAX_NIO_DELTA32;
						// if we detect that the OS is using 64-bits then we can turn off the faster
						// NIO polling. This should probably be done based on the kernel version or some
						// other include-file definition, but it's not expensive to do it here like this:
						if(nio->new_nio.bytes_in > 0xFFFFFFFF || nio->new_nio.bytes_out > 0xFFFFFFFF) {
							myLog(LOG_DEBUG, "detected 64-bit network counters");
							sp->nio_polling_secs = 0;
						}
					}

					if(accumulate) {
						// sanity check in case the counters were reset under out feet.
						// normally we leave this to the upstream collector, but these
						// numbers might be getting passed through from the hardware(?)
						// so we treat them with particular distrust.
						if(delta.bytes_in > maxDeltaBytes ||
							delta.bytes_out > maxDeltaBytes ||
							delta.pkts_in > HSP_MAX_NIO_DELTA32 ||
							delta.pkts_out > HSP_MAX_NIO_DELTA32) {
								myLog(LOG_ERR, "detected NIO counter discontinuity");
								accumulate = NO;
						}
					}

					if(accumulate) {
#define NIO_ACCUMULATE(field) nio->nio.field += delta.field
						NIO_ACCUMULATE(bytes_in);
						NIO_ACCUMULATE(pkts_in);
						NIO_ACCUMULATE(errs_in);
						NIO_ACCUMULATE(drops_in);
						NIO_ACCUMULATE(bytes_out);
						NIO_ACCUMULATE(pkts_out);
						NIO_ACCUMULATE(errs_out);
						NIO_ACCUMULATE(drops_out);
						//myLog(LOG_DEBUG, "accumulated NIO counters (new=%lu old=%lu delta=%lu nio->nio.bytes_in now = %lu)",
						//                  nio->new_nio.bytes_in, nio->last_nio.bytes_in, delta.bytes_in, nio->nio.bytes_in);
					}

#define NIO_LATCH(field) nio->last_nio.field = nio->new_nio.field
					NIO_LATCH(bytes_in);
					NIO_LATCH(pkts_in);
					NIO_LATCH(errs_in);
					NIO_LATCH(drops_in);
					NIO_LATCH(bytes_out);
					NIO_LATCH(pkts_out);
					NIO_LATCH(errs_out);
					NIO_LATCH(drops_out);
				}
			}
		}
	}
예제 #2
0
  void updateNioCounters(HSP *sp) {
    
    // don't do anything if we already refreshed the numbers less than a second ago
    if(sp->adaptorNIOList.last_update == sp->clk) {
      return;
    }
    sp->adaptorNIOList.last_update = sp->clk;
    
    static int mib[] = { CTL_NET,
			 PF_ROUTE,
			 0,
			 0,  /* address family */
			 NET_RT_IFLIST,
			 0 }; /* ifIndex */
    
    size_t needed = 0;
    if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) {
      myLog(LOG_ERR, "sysctl for interface list failed");
      return;
    }
    char *buf = my_calloc(needed);
    if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) {
      myLog(LOG_ERR, "sysctl for interface list failed (2nd time)");
    }
    else {
      char *lim = buf + needed;
      char *next = buf;
      
      while (next < lim) {
	struct if_msghdr *ifm = (struct if_msghdr *)next;
	
	if (ifm->ifm_type != RTM_IFINFO) {
	  myLog(LOG_ERR, "out of sync parsing NET_RT_IFLIST\n");
	  break;
	}
	
	next += ifm->ifm_msglen;
	while (next < lim) {
	  struct if_msghdr *nextifm = (struct if_msghdr *)next;
	  if (nextifm->ifm_type != RTM_NEWADDR) break;
	  next += nextifm->ifm_msglen;
	}
	
	if (!(ifm->ifm_flags & IFF_LOOPBACK) &&
	    (ifm->ifm_flags & IFF_UP)) {
	  char  deviceName[IFNAMSIZ];
	  
	  uint32_t index = ifm->ifm_index;
	  if(if_indextoname(index, deviceName)) {
	    char *str = deviceName;
	    trimWhitespace(str);
	    HSPAdaptorNIO *adaptor = getAdaptorNIO(&sp->adaptorNIOList, str);
	    if(adaptor) {
	      uint64_t bytes_in = ifm->ifm_data.ifi_ibytes;
	      uint64_t pkts_in = ifm->ifm_data.ifi_ipackets;
	      uint64_t errs_in = ifm->ifm_data.ifi_ierrors;
	      uint64_t drops_in = ifm->ifm_data.ifi_iqdrops;
	      uint64_t bytes_out = ifm->ifm_data.ifi_obytes;
	      uint64_t pkts_out = ifm->ifm_data.ifi_opackets;
	      uint64_t errs_out = ifm->ifm_data.ifi_oerrors;
	      uint64_t drops_out = (uint64_t)-1; /* unsupported */
	      
	      // have to detect discontinuities here, so use a full
	      // set of latched counters and accumulators.
	      int accumulate = adaptor->last_update ? YES : NO;
	      adaptor->last_update = sp->clk;
	      uint64_t maxDeltaBytes = HSP_MAX_NIO_DELTA64;
	      
	      SFLHost_nio_counters delta;
#define NIO_COMPUTE_DELTA(field) delta.field = field - adaptor->last_nio.field
	      NIO_COMPUTE_DELTA(pkts_in);
	      NIO_COMPUTE_DELTA(errs_in);
	      NIO_COMPUTE_DELTA(drops_in);
	      NIO_COMPUTE_DELTA(pkts_out);
	      NIO_COMPUTE_DELTA(errs_out);
	      NIO_COMPUTE_DELTA(drops_out);
	      
	      if(sp->adaptorNIOList.polling_secs == 0) {
		// 64-bit byte counters
		NIO_COMPUTE_DELTA(bytes_in);
		NIO_COMPUTE_DELTA(bytes_out);
	      }
	      else {
		// for case where byte counters are 32-bit,  we need
		// to use 32-bit unsigned arithmetic to avoid spikes
		delta.bytes_in = (uint32_t)bytes_in - adaptor->last_bytes_in32;
		delta.bytes_out = (uint32_t)bytes_out - adaptor->last_bytes_out32;
		adaptor->last_bytes_in32 = bytes_in;
		adaptor->last_bytes_out32 = bytes_out;
		maxDeltaBytes = HSP_MAX_NIO_DELTA32;
		// if we detect that the OS is using 64-bits then we can turn off the faster
		// NIO polling. This should probably be done based on the kernel version or some
		// other include-file definition, but it's not expensive to do it here like this:
		if(bytes_in > 0xFFFFFFFF || bytes_out > 0xFFFFFFFF) {
		  myLog(LOG_INFO, "detected 64-bit counters in /proc/net/dev");
		  sp->adaptorNIOList.polling_secs = 0;
		}
	      }
	      
	      if(accumulate) {
		// sanity check in case the counters were reset under out feet.
		// normally we leave this to the upstream collector, but these
		// numbers might be getting passed through from the hardware(?)
		// so we treat them with particular distrust.
		if(delta.bytes_in > maxDeltaBytes ||
		   delta.bytes_out > maxDeltaBytes ||
		   delta.pkts_in > HSP_MAX_NIO_DELTA32 ||
		   delta.pkts_out > HSP_MAX_NIO_DELTA32) {
		  myLog(LOG_ERR, "detected counter discontinuity in /proc/net/dev");
		  accumulate = NO;
		}
	      }
	      
	      if(accumulate) {
#define NIO_ACCUMULATE(field) adaptor->nio.field += delta.field
		NIO_ACCUMULATE(bytes_in);
		NIO_ACCUMULATE(pkts_in);
		NIO_ACCUMULATE(errs_in);
		NIO_ACCUMULATE(drops_in);
		NIO_ACCUMULATE(bytes_out);
		NIO_ACCUMULATE(pkts_out);
		NIO_ACCUMULATE(errs_out);
		NIO_ACCUMULATE(drops_out);
	      }
	      
#define NIO_LATCH(field) adaptor->last_nio.field = field
	      NIO_LATCH(bytes_in);
	      NIO_LATCH(pkts_in);
	      NIO_LATCH(errs_in);
	      NIO_LATCH(drops_in);
	      NIO_LATCH(bytes_out);
	      NIO_LATCH(pkts_out);
	      NIO_LATCH(errs_out);
	      NIO_LATCH(drops_out);
	    }
	  }
	}
      }
    }
    my_free(buf);
  }
예제 #3
0
  void updateNioCounters(HSP *sp) {

    // don't do anything if we already refreshed the numbers less than a second ago
    if(sp->nio_last_update == sp->clk) {
      return;
    }
    sp->nio_last_update = sp->clk;

    FILE *procFile;
    procFile= fopen("/proc/net/dev", "r");
    if(procFile) {
#ifdef HSP_ETHTOOL_STATS
      int fd = socket (PF_INET, SOCK_DGRAM, 0);
      struct ifreq ifr;
      memset (&ifr, 0, sizeof(ifr));
#endif
      // ASCII numbers in /proc/diskstats may be 64-bit (if not now
      // then someday), so it seems safer to read into
      // 64-bit ints with scanf first,  then copy them
      // into the host_nio structure from there.
      uint64_t bytes_in = 0;
      uint64_t pkts_in = 0;
      uint64_t errs_in = 0;
      uint64_t drops_in = 0;
      uint64_t bytes_out = 0;
      uint64_t pkts_out = 0;
      uint64_t errs_out = 0;
      uint64_t drops_out = 0;
      // limit the number of chars we will read from each line
      // (there can be more than this - fgets will chop for us)
#define MAX_PROC_LINE_CHARS 240
      char line[MAX_PROC_LINE_CHARS];
      while(fgets(line, MAX_PROC_LINE_CHARS, procFile)) {
	char deviceName[MAX_PROC_LINE_CHARS];
	// assume the format is:
	// Inter-|   Receive                                                |  Transmit
	//  face |bytes    packets errs drop fifo frame compressed multicast|bytes    packets errs drop fifo colls carrier compressed
	if(sscanf(line, "%[^:]:%"SCNu64" %"SCNu64" %"SCNu64" %"SCNu64" %*u %*u %*u %*u %"SCNu64" %"SCNu64" %"SCNu64" %"SCNu64"",
		  deviceName,
		  &bytes_in,
		  &pkts_in,
		  &errs_in,
		  &drops_in,
		  &bytes_out,
		  &pkts_out,
		  &errs_out,
		  &drops_out) == 9) {
	  SFLAdaptor *adaptor = adaptorListGet(sp->adaptorList, trimWhitespace(deviceName));
	  if(adaptor && adaptor->userData) {
	    HSPAdaptorNIO *niostate = (HSPAdaptorNIO *)adaptor->userData;
#ifdef HSP_ETHTOOL_STATS
	    HSP_ethtool_counters et_ctrs = { 0 }, et_delta = { 0 };
	    if (niostate->et_nfound) {
	      // get the latest stats block for this device via ethtool
	      // and read out the counters that we located by name.	

	      uint32_t bytes = sizeof(struct ethtool_stats);
	      bytes += niostate->et_nctrs * sizeof(uint64_t);
	      bytes += 32; // pad - just in case driver wants to write more
	      struct ethtool_stats *et_stats = (struct ethtool_stats *)my_calloc(bytes);
	      et_stats->cmd = ETHTOOL_GSTATS;
	      et_stats->n_stats = niostate->et_nctrs;

	      // now issue the ioctl
	      strncpy(ifr.ifr_name, adaptor->deviceName, sizeof(ifr.ifr_name));
	      ifr.ifr_data = (char *)et_stats;
	      if(ioctl(fd, SIOCETHTOOL, &ifr) >= 0) {
		if(debug > 2) {
		  for(int xx = 0; xx < et_stats->n_stats; xx++) {
		    myLog(LOG_INFO, "ethtool counter for %s at index %d == %"PRIu64,
			  adaptor->deviceName,
			  xx,
			  et_stats->data[xx]);
		  }
		}
		if(niostate->et_idx_mcasts_in) {
		  et_ctrs.mcasts_in = et_stats->data[niostate->et_idx_mcasts_in - 1];
		  et_delta.mcasts_in = et_ctrs.mcasts_in - niostate->et_last.mcasts_in;
		}
		if(niostate->et_idx_mcasts_out) {
		  et_ctrs.mcasts_out = et_stats->data[niostate->et_idx_mcasts_out - 1];
		  et_delta.mcasts_out = et_ctrs.mcasts_out - niostate->et_last.mcasts_out;
		}
		if(niostate->et_idx_bcasts_in) {
		  et_ctrs.bcasts_in = et_stats->data[niostate->et_idx_bcasts_in - 1];
		  et_delta.bcasts_in = et_ctrs.bcasts_in - niostate->et_last.bcasts_in;
		}
		if(niostate->et_idx_bcasts_out) {
		  et_ctrs.bcasts_out = et_stats->data[niostate->et_idx_bcasts_out - 1];
		  et_delta.bcasts_out = et_ctrs.bcasts_out - niostate->et_last.bcasts_out;
		}
	      }
	      my_free(et_stats);
	    }
#endif
	    // have to detect discontinuities here, so use a full
	    // set of latched counters and accumulators.
	    int accumulate = niostate->last_update ? YES : NO;
	    niostate->last_update = sp->clk;
	    uint64_t maxDeltaBytes = HSP_MAX_NIO_DELTA64;
	    
	    SFLHost_nio_counters delta;
#define NIO_COMPUTE_DELTA(field) delta.field = field - niostate->last_nio.field
	    NIO_COMPUTE_DELTA(pkts_in);
	    NIO_COMPUTE_DELTA(errs_in);
	    NIO_COMPUTE_DELTA(drops_in);
	    NIO_COMPUTE_DELTA(pkts_out);
	    NIO_COMPUTE_DELTA(errs_out);
	    NIO_COMPUTE_DELTA(drops_out);
	    
	    if(sp->nio_polling_secs == 0) {
	      // 64-bit byte counters
	      NIO_COMPUTE_DELTA(bytes_in);
	      NIO_COMPUTE_DELTA(bytes_out);
	    }
	    else {
	      // for case where byte counters are 32-bit,  we need
	      // to use 32-bit unsigned arithmetic to avoid spikes
	      delta.bytes_in = (uint32_t)bytes_in - niostate->last_bytes_in32;
	      delta.bytes_out = (uint32_t)bytes_out - niostate->last_bytes_out32;
	      niostate->last_bytes_in32 = bytes_in;
	      niostate->last_bytes_out32 = bytes_out;
	      maxDeltaBytes = HSP_MAX_NIO_DELTA32;
	      // if we detect that the OS is using 64-bits then we can turn off the faster
	      // NIO polling. This should probably be done based on the kernel version or some
	      // other include-file definition, but it's not expensive to do it here like this:
	      if(bytes_in > 0xFFFFFFFF || bytes_out > 0xFFFFFFFF) {
		myLog(LOG_INFO, "detected 64-bit counters in /proc/net/dev");
		sp->nio_polling_secs = 0;
	      }
	    }
	    
	    if(accumulate) {
	      // sanity check in case the counters were reset under out feet.
	      // normally we leave this to the upstream collector, but these
	      // numbers might be getting passed through from the hardware(?)
	      // so we treat them with particular distrust.
	      if(delta.bytes_in > maxDeltaBytes ||
		 delta.bytes_out > maxDeltaBytes ||
		 delta.pkts_in > HSP_MAX_NIO_DELTA32 ||
		 delta.pkts_out > HSP_MAX_NIO_DELTA32) {
		myLog(LOG_ERR, "detected counter discontinuity in /proc/net/dev for %s: deltaBytes=%"PRIu64",%"PRIu64" deltaPkts=%u,%u",
                      adaptor->deviceName,
                      delta.bytes_in,
                      delta.bytes_out,
                      delta.pkts_in,
                      delta.pkts_out);
		accumulate = NO;
	      }
#ifdef HSP_ETHTOOL_STATS
	      if(et_delta.mcasts_in > HSP_MAX_NIO_DELTA64  ||
		 et_delta.mcasts_out > HSP_MAX_NIO_DELTA64 ||
		 et_delta.bcasts_in > HSP_MAX_NIO_DELTA64  ||
		 et_delta.bcasts_out > HSP_MAX_NIO_DELTA64) {
		myLog(LOG_ERR, "detected counter discontinuity in ethtool stats");
		accumulate = NO;
	      }
#endif
	    }
	    
	    if(accumulate) {
#define NIO_ACCUMULATE(field) niostate->nio.field += delta.field
	      NIO_ACCUMULATE(bytes_in);
	      NIO_ACCUMULATE(pkts_in);
	      NIO_ACCUMULATE(errs_in);
	      NIO_ACCUMULATE(drops_in);
	      NIO_ACCUMULATE(bytes_out);
	      NIO_ACCUMULATE(pkts_out);
	      NIO_ACCUMULATE(errs_out);
	      NIO_ACCUMULATE(drops_out);
#ifdef HSP_ETHTOOL_STATS
#define ET_ACCUMULATE(field) niostate->et_total.field += et_delta.field
	      ET_ACCUMULATE(mcasts_in);
	      ET_ACCUMULATE(mcasts_out);
	      ET_ACCUMULATE(bcasts_in);
	      ET_ACCUMULATE(bcasts_out);
#endif
	    }
	    
#define NIO_LATCH(field) niostate->last_nio.field = field
	    NIO_LATCH(bytes_in);
	    NIO_LATCH(pkts_in);
	    NIO_LATCH(errs_in);
	    NIO_LATCH(drops_in);
	    NIO_LATCH(bytes_out);
	    NIO_LATCH(pkts_out);
	    NIO_LATCH(errs_out);
	    NIO_LATCH(drops_out);
#ifdef HSP_ETHTOOL_STATS
	    niostate->et_last = et_ctrs; // struct copy
#endif

	  }
	}
      }
#ifdef HSP_ETHTOOL_STATS
      if(fd >= 0) close(fd);
#endif
      fclose(procFile);
    }
  }
예제 #4
0
/**
 * Updates the cached NIO counters using PDH if the counters were updated 
 * more than a second ago.
 * Computes the delta between current and last counters, checks for
 * discontinuities (including determining whether 32 bit counters are being
 * use - eg for bytes - and have wrapped), accumulates totals, and stores
 * the latest counter values for delta computation on next invokation. 
 * If 64 bit counters are detected, indicates this by setting 
 * sp->nio->polling_seconds = 0 so that more
 * frequent polling of counters can be turned off.
 */
void updateNioCounters(HSP *sp) {
	// don't do anything if we refreshed the numbers less than a second ago
	if (sp->nio_last_update == sp->clk) {
		return;
	}
	

	sp->nio_last_update = sp->clk;
	// first read all the counters into new_nio
	if (query == NULL) {
		PDH_STATUS status = createCounterQuery();
		if (status != ERROR_SUCCESS) {
			query = NULL;
			myLog(LOG_ERR, "updateNioCounters: creating query failed: 0x%x", status);
			return;
		}
	}
	PdhCollectQueryData(query);

	PPDH_RAW_COUNTER_ITEM_W values;
	uint32_t icount = 0;
	icount = getRawCounterValues(&bytesIn, &values);

	if (icount > 0) {
		for (uint32_t i = 0; i < icount; i++) {
			SFLHost_nio_counters *newctrs = getNewNIO(sp, values[i].szName);
			if (newctrs != NULL) {
				newctrs->bytes_in = values[i].RawValue.FirstValue;
				//myLog(LOG_INFO, "updateNioCounters: adapter=%S bytesIn=%lu",
				//	  values[i].szName, newctrs->bytes_in);
			}
		}
		my_free(values);
		icount = 0;
	}
	icount = getRawCounterValues(&pktsIn, &values);
	if (icount > 0) {
		for (uint32_t i = 0; i < icount; i++) {
			SFLHost_nio_counters *newctrs = getNewNIO(sp, values[i].szName);
			if(newctrs != NULL) {
				newctrs->pkts_in = (uint32_t)values[i].RawValue.FirstValue;
			}
		}
		my_free(values);
		icount = 0;
	}
	icount = getRawCounterValues(&errorsIn, &values);
	if (icount > 0) {
		for (uint32_t i = 0; i < icount; i++) {
			SFLHost_nio_counters *newctrs = getNewNIO(sp, values[i].szName);
			if(newctrs != NULL) {
				newctrs->errs_in = (uint32_t)values[i].RawValue.FirstValue;
			}
		}
		my_free(values);
		icount = 0;
	}
	icount = getRawCounterValues(&discardsIn, &values);
	if (icount > 0) {
		for (uint32_t i = 0; i < icount; i++) {
			SFLHost_nio_counters *newctrs = getNewNIO(sp, values[i].szName);
			if (newctrs != NULL) {
				newctrs->drops_in = (uint32_t)values[i].RawValue.FirstValue;
			}
		}
		my_free(values);
		icount = 0;
	}
	icount = getRawCounterValues(&bytesOut, &values);
	if (icount > 0) {
		for (uint32_t i = 0; i < icount; i++) {
			SFLHost_nio_counters *newctrs = getNewNIO(sp, values[i].szName);
			if (newctrs != NULL) {
				newctrs->bytes_out = values[i].RawValue.FirstValue;
			}
		}
		my_free(values);
		icount = 0;
	}
	icount = getRawCounterValues(&pktsOut, &values);
	if (icount > 0) {
		for (uint32_t i = 0; i < icount; i++) {
			SFLHost_nio_counters *newctrs = getNewNIO(sp, values[i].szName);
			if (newctrs != NULL) {
				newctrs->pkts_out = (uint32_t)values[i].RawValue.FirstValue;
			}
		}
		my_free(values);
		icount = 0;
	}
	icount = getRawCounterValues(&errorsOut, &values);
	if (icount > 0) {
		for (uint32_t i = 0; i < icount; i++) {
			SFLHost_nio_counters *newctrs = getNewNIO(sp, values[i].szName);
			if (newctrs != NULL) {
				newctrs->errs_out = (uint32_t)values[i].RawValue.FirstValue;
			}
		}
		my_free(values);
		icount = 0;
	}
	icount = getRawCounterValues(&discardsOut, &values);
	if (icount > 0) {
		for (uint32_t i = 0; i < icount; i++) {
			SFLHost_nio_counters *newctrs = getNewNIO(sp, values[i].szName);
			if (newctrs != NULL) {
				newctrs->drops_out = (uint32_t)values[i].RawValue.FirstValue;
			}
		}
		my_free(values);
		icount = 0;
	}
	// now compute the deltas,  sanity check them, accumulate and latch
	for (uint32_t i = 0; i < sp->adaptorList->num_adaptors; i++) {
		SFLAdaptor *ad = sp->adaptorList->adaptors[i];
		if (ad != NULL) {
			HSPAdaptorNIO *nio = (HSPAdaptorNIO *)ad->userData;
			if (nio != NULL) {
				// have to detect discontinuities here, so use a full
				// set of latched counters and accumulators.
				BOOL accumulate = nio->last_update ? TRUE : FALSE;
				nio->last_update = sp->clk;
				uint64_t maxDeltaBytes = HSP_MAX_NIO_DELTA64;

				SFLHost_nio_counters delta;
#define NIO_COMPUTE_DELTA(field) delta.field = nio->new_nio.field - nio->last_nio.field
				NIO_COMPUTE_DELTA(pkts_in);
				NIO_COMPUTE_DELTA(errs_in);
				NIO_COMPUTE_DELTA(drops_in);
				NIO_COMPUTE_DELTA(pkts_out);
				NIO_COMPUTE_DELTA(errs_out);
				NIO_COMPUTE_DELTA(drops_out);

				if (sp->nio_polling_secs == 0) {
					// 64-bit byte counters
					NIO_COMPUTE_DELTA(bytes_in);
					NIO_COMPUTE_DELTA(bytes_out);
				} else {
					// for case where byte counters are 32-bit,  we need
					// to use 32-bit unsigned arithmetic to avoid spikes
					delta.bytes_in = (uint32_t)nio->new_nio.bytes_in - nio->last_bytes_in32;
					delta.bytes_out = (uint32_t)nio->new_nio.bytes_out - nio->last_bytes_out32;
					nio->last_bytes_in32 = (uint32_t)nio->new_nio.bytes_in;
					nio->last_bytes_out32 = (uint32_t)nio->new_nio.bytes_out;
					maxDeltaBytes = HSP_MAX_NIO_DELTA32;
					// if we detect that the OS is using 64-bits then we can turn off the faster
					// NIO polling. This should probably be done based on the kernel version or some
					// other include-file definition, but it's not expensive to do it here like this:
					if (nio->new_nio.bytes_in > 0xFFFFFFFF || nio->new_nio.bytes_out > 0xFFFFFFFF) {
						myLog(LOG_INFO, "detected 64-bit network counters");
						sp->nio_polling_secs = 0;
					}
				}

				if (accumulate) {
					// sanity check in case the counters were reset under out feet.
					// normally we leave this to the upstream collector, but these
					// numbers might be getting passed through from the hardware(?)
					// so we treat them with particular distrust.
					if (delta.bytes_in > maxDeltaBytes ||
						delta.bytes_out > maxDeltaBytes ||
						delta.pkts_in > HSP_MAX_NIO_DELTA32 ||
						delta.pkts_out > HSP_MAX_NIO_DELTA32) {
						myLog(LOG_INFO, "detected NIO counter discontinuity");
						accumulate = FALSE;
					}
				}

				if (accumulate) {
#define NIO_ACCUMULATE(field) nio->nio.field += delta.field
					NIO_ACCUMULATE(bytes_in);
					NIO_ACCUMULATE(pkts_in);
					NIO_ACCUMULATE(errs_in);
					NIO_ACCUMULATE(drops_in);
					NIO_ACCUMULATE(bytes_out);
					NIO_ACCUMULATE(pkts_out);
					NIO_ACCUMULATE(errs_out);
					NIO_ACCUMULATE(drops_out);
					//myLog(LOG_INFO, "accumulated NIO counters (new=%lu old=%lu delta=%lu nio->nio.bytes_in now = %lu)",
					//                  nio->new_nio.bytes_in, nio->last_nio.bytes_in, delta.bytes_in, nio->nio.bytes_in);
				}

#define NIO_LATCH(field) nio->last_nio.field = nio->new_nio.field
				NIO_LATCH(bytes_in);
				NIO_LATCH(pkts_in);
				NIO_LATCH(errs_in);
				NIO_LATCH(drops_in);
				NIO_LATCH(bytes_out);
				NIO_LATCH(pkts_out);
				NIO_LATCH(errs_out);
				NIO_LATCH(drops_out);
			}
		}
	}
}