Show expensive mbuf operations in netstat(1) statistics.
authorbluhm <bluhm@openbsd.org>
Thu, 29 Aug 2024 10:44:40 +0000 (10:44 +0000)
committerbluhm <bluhm@openbsd.org>
Thu, 29 Aug 2024 10:44:40 +0000 (10:44 +0000)
If the memory layout is not optimal, m_defrag(), m_prepend(),
m_pullup(), and m_pulldown() will allocate mbufs or copy memory.
Count these operations to find possible optimizations.

input dhill@; OK mvs@

sys/kern/kern_sysctl.c
sys/kern/uipc_mbuf.c
sys/kern/uipc_mbuf2.c
sys/sys/mbuf.h
usr.bin/netstat/mbuf.c

index d52ff48..e015b53 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: kern_sysctl.c,v 1.445 2024/08/26 08:24:25 mvs Exp $   */
+/*     $OpenBSD: kern_sysctl.c,v 1.446 2024/08/29 10:44:40 bluhm Exp $ */
 /*     $NetBSD: kern_sysctl.c,v 1.17 1996/05/20 17:49:05 mrg Exp $     */
 
 /*-
@@ -530,7 +530,6 @@ kern_sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp, void *newp,
                return (sysctl_rdstruct(oldp, oldlenp, newp, &bt, sizeof bt));
        }
        case KERN_MBSTAT: {
-               extern struct cpumem *mbstat;
                uint64_t counters[MBSTAT_COUNT];
                struct mbstat mbs;
                unsigned int i;
@@ -543,6 +542,12 @@ kern_sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp, void *newp,
                mbs.m_drops = counters[MBSTAT_DROPS];
                mbs.m_wait = counters[MBSTAT_WAIT];
                mbs.m_drain = counters[MBSTAT_DRAIN];
+               mbs.m_defrag_alloc = counters[MBSTAT_DEFRAG_ALLOC];
+               mbs.m_prepend_alloc = counters[MBSTAT_PREPEND_ALLOC];
+               mbs.m_pullup_alloc = counters[MBSTAT_PULLUP_ALLOC];
+               mbs.m_pullup_copy = counters[MBSTAT_PULLUP_COPY];
+               mbs.m_pulldown_alloc = counters[MBSTAT_PULLDOWN_ALLOC];
+               mbs.m_pulldown_copy = counters[MBSTAT_PULLDOWN_COPY];
 
                return (sysctl_rdstruct(oldp, oldlenp, newp,
                    &mbs, sizeof(mbs)));
index fc7b515..db942bf 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: uipc_mbuf.c,v 1.290 2024/03/05 18:52:41 bluhm Exp $   */
+/*     $OpenBSD: uipc_mbuf.c,v 1.291 2024/08/29 10:44:40 bluhm Exp $   */
 /*     $NetBSD: uipc_mbuf.c,v 1.15.4.1 1996/06/13 17:11:44 cgd Exp $   */
 
 /*
@@ -234,8 +234,6 @@ struct mbuf *
 m_get(int nowait, int type)
 {
        struct mbuf *m;
-       struct counters_ref cr;
-       uint64_t *counters;
        int s;
 
        KASSERT(type >= 0 && type < MT_NTYPES);
@@ -245,9 +243,7 @@ m_get(int nowait, int type)
                return (NULL);
 
        s = splnet();
-       counters = counters_enter(&cr, mbstat);
-       counters[type]++;
-       counters_leave(&cr, mbstat);
+       counters_inc(mbstat, type);
        splx(s);
 
        m->m_type = type;
@@ -267,8 +263,6 @@ struct mbuf *
 m_gethdr(int nowait, int type)
 {
        struct mbuf *m;
-       struct counters_ref cr;
-       uint64_t *counters;
        int s;
 
        KASSERT(type >= 0 && type < MT_NTYPES);
@@ -278,9 +272,7 @@ m_gethdr(int nowait, int type)
                return (NULL);
 
        s = splnet();
-       counters = counters_enter(&cr, mbstat);
-       counters[type]++;
-       counters_leave(&cr, mbstat);
+       counters_inc(mbstat, type);
        splx(s);
 
        m->m_type = type;
@@ -417,17 +409,13 @@ struct mbuf *
 m_free(struct mbuf *m)
 {
        struct mbuf *n;
-       struct counters_ref cr;
-       uint64_t *counters;
        int s;
 
        if (m == NULL)
                return (NULL);
 
        s = splnet();
-       counters = counters_enter(&cr, mbstat);
-       counters[m->m_type]--;
-       counters_leave(&cr, mbstat);
+       counters_dec(mbstat, m->m_type);
        splx(s);
 
        n = m->m_next;
@@ -557,6 +545,7 @@ m_defrag(struct mbuf *m, int how)
 
        KASSERT(m->m_flags & M_PKTHDR);
 
+       counters_inc(mbstat, MBSTAT_DEFRAG_ALLOC);
        if ((m0 = m_gethdr(how, m->m_type)) == NULL)
                return (ENOBUFS);
        if (m->m_pkthdr.len > MHLEN) {
@@ -616,6 +605,7 @@ m_prepend(struct mbuf *m, int len, int how)
                m->m_data -= len;
                m->m_len += len;
        } else {
+               counters_inc(mbstat, MBSTAT_PREPEND_ALLOC);
                MGET(mn, how, m->m_type);
                if (mn == NULL) {
                        m_freem(m);
@@ -956,8 +946,8 @@ m_pullup(struct mbuf *m0, int len)
                        memmove(head, mtod(m0, caddr_t), m0->m_len);
                        m0->m_data = head;
                }
-
                len -= m0->m_len;
+               counters_inc(mbstat, MBSTAT_PULLUP_COPY);
        } else {
                /* the first mbuf is too small or read-only, make a new one */
                space = adj + len;
@@ -968,6 +958,7 @@ m_pullup(struct mbuf *m0, int len)
                m0->m_next = m;
                m = m0;
 
+               counters_inc(mbstat, MBSTAT_PULLUP_ALLOC);
                MGET(m0, M_DONTWAIT, m->m_type);
                if (m0 == NULL)
                        goto bad;
index 25670aa..6a4bdca 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: uipc_mbuf2.c,v 1.45 2020/12/12 11:48:54 jan Exp $     */
+/*     $OpenBSD: uipc_mbuf2.c,v 1.46 2024/08/29 10:44:40 bluhm Exp $   */
 /*     $KAME: uipc_mbuf2.c,v 1.29 2001/02/14 13:42:10 itojun Exp $     */
 /*     $NetBSD: uipc_mbuf.c,v 1.40 1999/04/01 00:23:25 thorpej Exp $   */
 
@@ -66,6 +66,7 @@
 #include <sys/systm.h>
 #include <sys/malloc.h>
 #include <sys/pool.h>
+#include <sys/percpu.h>
 #include <sys/mbuf.h>
 
 extern struct pool mtagpool;
@@ -117,6 +118,7 @@ m_pulldown(struct mbuf *m, int off, int len, int *offp)
        if (len <= n->m_len - off) {
                struct mbuf *mlast;
 
+               counters_inc(mbstat, MBSTAT_PULLDOWN_ALLOC);
                o = m_dup1(n, off, n->m_len - off, M_DONTWAIT);
                if (o == NULL) {
                        m_freem(m);
@@ -158,6 +160,7 @@ m_pulldown(struct mbuf *m, int off, int len, int *offp)
         */
        if ((off == 0 || offp) && m_trailingspace(n) >= tlen &&
            !sharedcluster) {
+               counters_inc(mbstat, MBSTAT_PULLDOWN_COPY);
                m_copydata(n->m_next, 0, tlen, mtod(n, caddr_t) + n->m_len);
                n->m_len += tlen;
                m_adj(n->m_next, tlen);
@@ -167,6 +170,7 @@ m_pulldown(struct mbuf *m, int off, int len, int *offp)
            !sharedcluster && n->m_next->m_len >= tlen) {
                n->m_next->m_data -= hlen;
                n->m_next->m_len += hlen;
+               counters_inc(mbstat, MBSTAT_PULLDOWN_COPY);
                memmove(mtod(n->m_next, caddr_t), mtod(n, caddr_t) + off, hlen);
                n->m_len -= hlen;
                n = n->m_next;
@@ -182,6 +186,7 @@ m_pulldown(struct mbuf *m, int off, int len, int *offp)
                m_freem(m);
                return (NULL);
        }
+       counters_inc(mbstat, MBSTAT_PULLDOWN_ALLOC);
        MGET(o, M_DONTWAIT, m->m_type);
        if (o && len > MLEN) {
                MCLGETL(o, M_DONTWAIT, len);
index b458e0e..b8745b9 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: mbuf.h,v 1.263 2024/04/14 20:46:27 bluhm Exp $        */
+/*     $OpenBSD: mbuf.h,v 1.264 2024/08/29 10:44:40 bluhm Exp $        */
 /*     $NetBSD: mbuf.h,v 1.19 1996/02/09 18:25:14 christos Exp $       */
 
 /*
@@ -363,11 +363,17 @@ u_int mextfree_register(void (*)(caddr_t, u_int, void *));
 /* length to m_copy to copy all */
 #define        M_COPYALL       1000000000
 
-#define MBSTAT_TYPES           MT_NTYPES
-#define MBSTAT_DROPS           (MBSTAT_TYPES + 0)
-#define MBSTAT_WAIT            (MBSTAT_TYPES + 1)
-#define MBSTAT_DRAIN           (MBSTAT_TYPES + 2)
-#define MBSTAT_COUNT           (MBSTAT_TYPES + 3)
+#define MBSTAT_TYPES           MT_NTYPES
+#define MBSTAT_DROPS           (MBSTAT_TYPES + 0)
+#define MBSTAT_WAIT            (MBSTAT_TYPES + 1)
+#define MBSTAT_DRAIN           (MBSTAT_TYPES + 2)
+#define MBSTAT_DEFRAG_ALLOC    (MBSTAT_TYPES + 3)
+#define MBSTAT_PREPEND_ALLOC   (MBSTAT_TYPES + 4)
+#define MBSTAT_PULLUP_ALLOC    (MBSTAT_TYPES + 5)
+#define MBSTAT_PULLUP_COPY     (MBSTAT_TYPES + 6)
+#define MBSTAT_PULLDOWN_ALLOC  (MBSTAT_TYPES + 7)
+#define MBSTAT_PULLDOWN_COPY   (MBSTAT_TYPES + 8)
+#define MBSTAT_COUNT           (MBSTAT_TYPES + 9)
 
 /*
  * Mbuf statistics.
@@ -378,8 +384,14 @@ struct mbstat {
        u_long  m_drops;        /* times failed to find space */
        u_long  m_wait;         /* times waited for space */
        u_long  m_drain;        /* times drained protocols for space */
-       u_long  m_mtypes[MBSTAT_COUNT];
+       u_long  m_mtypes[MBSTAT_TYPES];
                                /* type specific mbuf allocations */
+       u_long  m_defrag_alloc;
+       u_long  m_prepend_alloc;
+       u_long  m_pullup_alloc;
+       u_long  m_pullup_copy;
+       u_long  m_pulldown_alloc;
+       u_long  m_pulldown_copy;
 };
 
 #include <sys/mutex.h>
@@ -404,6 +416,7 @@ extern      long nmbclust;                  /* limit on the # of clusters */
 extern int max_linkhdr;                /* largest link-level header */
 extern int max_protohdr;               /* largest protocol header */
 extern int max_hdr;                    /* largest link+protocol header */
+extern struct cpumem *mbstat;          /* mbuf statistics counter */
 
 void   mbinit(void);
 void   mbcpuinit(void);
index 6eeeebe..7660f83 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: mbuf.c,v 1.45 2023/07/16 03:01:31 yasuoka Exp $       */
+/*     $OpenBSD: mbuf.c,v 1.46 2024/08/29 10:44:40 bluhm Exp $ */
 /*     $NetBSD: mbuf.c,v 1.9 1996/05/07 02:55:03 thorpej Exp $ */
 
 /*
@@ -79,7 +79,7 @@ static struct mbtypes {
 };
 
 int nmbtypes = sizeof(mbstat.m_mtypes) / sizeof(u_long);
-bool seen[MBSTAT_COUNT];               /* "have we seen this type yet?" */
+bool seen[MBSTAT_TYPES];               /* "have we seen this type yet?" */
 
 /*
  * Print mbuf statistics.
@@ -93,7 +93,7 @@ mbpr(void)
        struct mbtypes *mp;
        size_t size;
 
-       if (nmbtypes != MBSTAT_COUNT) {
+       if (nmbtypes != MBSTAT_TYPES) {
                fprintf(stderr,
                    "%s: unexpected change to mbstat; check source\n",
                    __progname);
@@ -205,4 +205,10 @@ mbpr(void)
        printf("%lu requests for memory denied\n", mbstat.m_drops);
        printf("%lu requests for memory delayed\n", mbstat.m_wait);
        printf("%lu calls to protocol drain routines\n", mbstat.m_drain);
+       printf("%lu defrag mbuf allocation\n", mbstat.m_defrag_alloc);
+       printf("%lu prepend mbuf allocation\n", mbstat.m_prepend_alloc);
+       printf("%lu pullup mbuf allocation\n", mbstat.m_pullup_alloc);
+       printf("%lu pullup memory copy\n", mbstat.m_pullup_copy);
+       printf("%lu pulldown mbuf allocation\n", mbstat.m_pulldown_alloc);
+       printf("%lu pulldown memory copy\n", mbstat.m_pulldown_copy);
 }