From 2ec85f72334b2b2fb8da586a9719f45c6e75596b Mon Sep 17 00:00:00 2001 From: David Gwynne Date: Tue, 7 Jul 2020 01:36:50 +0000 Subject: add kstat support for reading the "hardware" counters for each ring. the counters happen to be a series of uint64_t values in memory, so we treat them as arrays that get mapped to a series of kstat_kv structs that are set up as 64 bit counters with either packet or byte counters as appropriate. this helps keep the code size down. while we export the counters as separate kstats per rx and tx ring, you request an update from the hypervisor at the controller level. this code ratelimits these requests to 1 per second per interface to try and debounce this a bit so each kstat read doesnt cause a vmexit. here's an example of the stats. note that we get to see how many packets that rx ring moderation drops for the first time. see the "no buffers" stat. vmx0:0:rxq:5 packets: 2372483 packets bytes: 3591909057 bytes qdrops: 0 packets errors: 0 packets qlen: 0 packets ... vmx0:0:txq:5 packets: 1316856 packets bytes: 86961577 bytes qdrops: 0 packets errors: 0 packets qlen: 1 packets maxqlen: 512 packets oactive: false ... vmx0:0:vmx-rxstats:5 LRO packets: 0 packets LRO bytes: 0 bytes ucast packets: 2372483 packets ucast bytes: 3591909053 bytes mcast packets: 0 packets mcast bytes: 0 bytes bcast packets: 0 packets bcast bytes: 0 bytes no buffers: 696 packets errors: 0 packets ... vmx0:0:vmx-txstats:5 TSO packets: 0 packets TSO bytes: 0 bytes ucast packets: 1316839 packets ucast bytes: 86960455 bytes mcast packets: 0 packets mcast bytes: 0 bytes bcast packets: 0 packets bcast bytes: 0 bytes errors: 0 packets discards: 0 packets --- sys/dev/pci/if_vmx.c | 170 ++++++++++++++++++++++++++++++++++++++++++------ sys/dev/pci/if_vmxreg.h | 54 ++++++++------- 2 files changed, 179 insertions(+), 45 deletions(-) diff --git a/sys/dev/pci/if_vmx.c b/sys/dev/pci/if_vmx.c index d5a1ffc184f..bc666a8ca03 100644 --- a/sys/dev/pci/if_vmx.c +++ b/sys/dev/pci/if_vmx.c @@ -1,4 +1,4 @@ -/* $OpenBSD: if_vmx.c,v 1.61 2020/06/25 03:19:35 dlg Exp $ */ +/* $OpenBSD: if_vmx.c,v 1.62 2020/07/07 01:36:49 dlg Exp $ */ /* * Copyright (c) 2013 Tsubai Masanari @@ -17,6 +17,7 @@ */ #include "bpfilter.h" +#include "kstat.h" #include #include @@ -26,6 +27,7 @@ #include #include #include +#include #include #include @@ -98,6 +100,7 @@ struct vmxnet3_txqueue { struct vmxnet3_comp_ring comp_ring; struct vmxnet3_txq_shared *ts; struct ifqueue *ifq; + struct kstat *txkstat; } __aligned(64); struct vmxnet3_rxqueue { @@ -106,6 +109,7 @@ struct vmxnet3_rxqueue { struct vmxnet3_comp_ring comp_ring; struct vmxnet3_rxq_shared *rs; struct ifiqueue *ifiq; + struct kstat *rxkstat; } __aligned(64); struct vmxnet3_queue { @@ -136,24 +140,12 @@ struct vmxnet3_softc { struct vmxnet3_driver_shared *sc_ds; u_int8_t *sc_mcast; struct vmxnet3_upt1_rss_conf *sc_rss; -}; -#define VMXNET3_STAT - -#ifdef VMXNET3_STAT -struct { - u_int ntxdesc; - u_int nrxdesc; - u_int txhead; - u_int txdone; - u_int maxtxlen; - u_int rxdone; - u_int rxfill; - u_int intr; -} vmxstat = { - NTXDESC, NRXDESC -}; +#if NKSTAT > 0 + struct rwlock sc_kstat_lock; + struct timeval sc_kstat_updated; #endif +}; #define JUMBO_LEN (1024 * 9) #define DMAADDR(map) ((map)->dm_segs[0].ds_addr) @@ -202,6 +194,14 @@ void vmxnet3_media_status(struct ifnet *, struct ifmediareq *); int vmxnet3_media_change(struct ifnet *); void *vmxnet3_dma_allocmem(struct vmxnet3_softc *, u_int, u_int, bus_addr_t *); +#if NKSTAT > 0 +static void vmx_kstat_init(struct vmxnet3_softc *); +static void vmx_kstat_txstats(struct vmxnet3_softc *, + struct vmxnet3_txqueue *, int); +static void vmx_kstat_rxstats(struct vmxnet3_softc *, + struct vmxnet3_rxqueue *, int); +#endif /* NKSTAT > 0 */ + const struct pci_matchid vmx_devices[] = { { PCI_VENDOR_VMWARE, PCI_PRODUCT_VMWARE_NET_3 } }; @@ -388,10 +388,20 @@ vmxnet3_attach(struct device *parent, struct device *self, void *aux) if_attach_queues(ifp, sc->sc_nqueues); if_attach_iqueues(ifp, sc->sc_nqueues); + +#if NKSTAT > 0 + vmx_kstat_init(sc); +#endif + for (i = 0; i < sc->sc_nqueues; i++) { ifp->if_ifqs[i]->ifq_softc = &sc->sc_q[i].tx; sc->sc_q[i].tx.ifq = ifp->if_ifqs[i]; sc->sc_q[i].rx.ifiq = ifp->if_iqs[i]; + +#if NKSTAT > 0 + vmx_kstat_txstats(sc, &sc->sc_q[i].tx, i); + vmx_kstat_rxstats(sc, &sc->sc_q[i].rx, i); +#endif } } @@ -1023,9 +1033,6 @@ vmxnet3_rxintr(struct vmxnet3_softc *sc, struct vmxnet3_rxqueue *rq) ml_enqueue(&ml, m); skip_buffer: -#ifdef VMXNET3_STAT - vmxstat.rxdone = idx; -#endif if (rq->rs->update_rxhead) { u_int qid = letoh32((rxcd->rxc_word0 >> VMXNET3_RXC_QID_S) & VMXNET3_RXC_QID_M); @@ -1450,3 +1457,126 @@ vmxnet3_dma_allocmem(struct vmxnet3_softc *sc, u_int size, u_int align, bus_addr bus_dmamap_destroy(t, map); return va; } + +#if NKSTAT > 0 +/* + * "hardware" counters are exported as separate kstats for each tx + * and rx ring, but the request for the hypervisor to update the + * stats is done once at the controller level. we limit the number + * of updates at the controller level to a rate of one per second to + * debounce this a bit. + */ +static const struct timeval vmx_kstat_rate = { 1, 0 }; + +/* + * all the vmx stats are 64 bit counters, we just need their name and units. + */ +struct vmx_kstat_tpl { + const char *name; + enum kstat_kv_unit unit; +}; + +static const struct vmx_kstat_tpl vmx_rx_kstat_tpl[UPT1_RxStats_count] = { + { "LRO packets", KSTAT_KV_U_PACKETS }, + { "LRO bytes", KSTAT_KV_U_BYTES }, + { "ucast packets", KSTAT_KV_U_PACKETS }, + { "ucast bytes", KSTAT_KV_U_BYTES }, + { "mcast packets", KSTAT_KV_U_PACKETS }, + { "mcast bytes", KSTAT_KV_U_BYTES }, + { "bcast packets", KSTAT_KV_U_PACKETS }, + { "bcast bytes", KSTAT_KV_U_BYTES }, + { "no buffers", KSTAT_KV_U_PACKETS }, + { "errors", KSTAT_KV_U_PACKETS }, +}; + +static const struct vmx_kstat_tpl vmx_tx_kstat_tpl[UPT1_TxStats_count] = { + { "TSO packets", KSTAT_KV_U_PACKETS }, + { "TSO bytes", KSTAT_KV_U_BYTES }, + { "ucast packets", KSTAT_KV_U_PACKETS }, + { "ucast bytes", KSTAT_KV_U_BYTES }, + { "mcast packets", KSTAT_KV_U_PACKETS }, + { "mcast bytes", KSTAT_KV_U_BYTES }, + { "bcast packets", KSTAT_KV_U_PACKETS }, + { "bcast bytes", KSTAT_KV_U_BYTES }, + { "errors", KSTAT_KV_U_PACKETS }, + { "discards", KSTAT_KV_U_PACKETS }, +}; + +static void +vmx_kstat_init(struct vmxnet3_softc *sc) +{ + rw_init(&sc->sc_kstat_lock, "vmxkstat"); +} + +static int +vmx_kstat_read(struct kstat *ks) +{ + struct vmxnet3_softc *sc = ks->ks_softc; + struct kstat_kv *kvs = ks->ks_data; + uint64_t *vs = ks->ks_ptr; + unsigned int n, i; + + if (ratecheck(&sc->sc_kstat_updated, &vmx_kstat_rate)) { + WRITE_CMD(sc, VMXNET3_CMD_GET_STATS); + /* barrier? */ + } + + n = ks->ks_datalen / sizeof(*kvs); + for (i = 0; i < n; i++) + kstat_kv_u64(&kvs[i]) = lemtoh64(&vs[i]); + + TIMEVAL_TO_TIMESPEC(&sc->sc_kstat_updated, &ks->ks_updated); + + return (0); +} + +static struct kstat * +vmx_kstat_create(struct vmxnet3_softc *sc, const char *name, unsigned int unit, + const struct vmx_kstat_tpl *tpls, unsigned int n, uint64_t *vs) +{ + struct kstat *ks; + struct kstat_kv *kvs; + unsigned int i; + + ks = kstat_create(sc->sc_dev.dv_xname, 0, name, unit, + KSTAT_T_KV, 0); + if (ks == NULL) + return (NULL); + + kvs = mallocarray(n, sizeof(*kvs), M_DEVBUF, M_WAITOK|M_ZERO); + for (i = 0; i < n; i++) { + const struct vmx_kstat_tpl *tpl = &tpls[i]; + + kstat_kv_unit_init(&kvs[i], tpl->name, + KSTAT_KV_T_COUNTER64, tpl->unit); + } + + ks->ks_softc = sc; + kstat_set_wlock(ks, &sc->sc_kstat_lock); + ks->ks_ptr = vs; + ks->ks_data = kvs; + ks->ks_datalen = n * sizeof(*kvs); + ks->ks_read = vmx_kstat_read; + TIMEVAL_TO_TIMESPEC(&vmx_kstat_rate, &ks->ks_interval); + + kstat_install(ks); + + return (ks); +} + +static void +vmx_kstat_txstats(struct vmxnet3_softc *sc, struct vmxnet3_txqueue *tq, + int unit) +{ + tq->txkstat = vmx_kstat_create(sc, "vmx-txstats", unit, + vmx_tx_kstat_tpl, nitems(vmx_tx_kstat_tpl), tq->ts->stats); +} + +static void +vmx_kstat_rxstats(struct vmxnet3_softc *sc, struct vmxnet3_rxqueue *rq, + int unit) +{ + rq->rxkstat = vmx_kstat_create(sc, "vmx-rxstats", unit, + vmx_rx_kstat_tpl, nitems(vmx_rx_kstat_tpl), rq->rs->stats); +} +#endif /* NKSTAT > 0 */ diff --git a/sys/dev/pci/if_vmxreg.h b/sys/dev/pci/if_vmxreg.h index 2b29c92c915..44f5e4315e3 100644 --- a/sys/dev/pci/if_vmxreg.h +++ b/sys/dev/pci/if_vmxreg.h @@ -1,4 +1,4 @@ -/* $OpenBSD: if_vmxreg.h,v 1.8 2020/06/17 07:08:39 dlg Exp $ */ +/* $OpenBSD: if_vmxreg.h,v 1.9 2020/07/07 01:36:49 dlg Exp $ */ /* * Copyright (c) 2013 Tsubai Masanari @@ -16,30 +16,34 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -struct UPT1_TxStats { - u_int64_t TSO_packets; - u_int64_t TSO_bytes; - u_int64_t ucast_packets; - u_int64_t ucast_bytes; - u_int64_t mcast_packets; - u_int64_t mcast_bytes; - u_int64_t bcast_packets; - u_int64_t bcast_bytes; - u_int64_t error; - u_int64_t discard; +enum UPT1_TxStats { + UPT1_TxStat_TSO_packets, + UPT1_TxStat_TSO_bytes, + UPT1_TxStat_ucast_packets, + UPT1_TxStat_ucast_bytes, + UPT1_TxStat_mcast_packets, + UPT1_TxStat_mcast_bytes, + UPT1_TxStat_bcast_packets, + UPT1_TxStat_bcast_bytes, + UPT1_TxStat_error, + UPT1_TxStat_discard, + + UPT1_TxStats_count, } __packed; -struct UPT1_RxStats { - u_int64_t LRO_packets; - u_int64_t LRO_bytes; - u_int64_t ucast_packets; - u_int64_t ucast_bytes; - u_int64_t mcast_packets; - u_int64_t mcast_bytes; - u_int64_t bcast_packets; - u_int64_t bcast_bytes; - u_int64_t nobuffer; - u_int64_t error; +enum UPT1_RxStats { + UPT1_RXStat_LRO_packets, + UPT1_RXStat_LRO_bytes, + UPT1_RXStat_ucast_packets, + UPT1_RXStat_ucast_bytes, + UPT1_RXStat_mcast_packets, + UPT1_RXStat_mcast_bytes, + UPT1_RXStat_bcast_packets, + UPT1_RXStat_bcast_bytes, + UPT1_RXStat_nobuffer, + UPT1_RXStat_error, + + UPT1_RxStats_count, } __packed; /* interrupt moderation levels */ @@ -309,7 +313,7 @@ struct vmxnet3_txq_shared { u_int8_t pad2[3]; u_int32_t error; - struct UPT1_TxStats stats; + uint64_t stats[UPT1_TxStats_count]; u_int8_t pad3[88]; } __packed; @@ -333,7 +337,7 @@ struct vmxnet3_rxq_shared { u_int8_t pad3[3]; u_int32_t error; - struct UPT1_RxStats stats; + uint64_t stats[UPT1_RxStats_count]; u_int8_t pad4[88]; } __packed; -- cgit v1.2.3