diff options
author | rwatson <rwatson@FreeBSD.org> | 2005-07-18 08:34:15 +0000 |
---|---|---|
committer | rwatson <rwatson@FreeBSD.org> | 2005-07-18 08:34:15 +0000 |
commit | 20e476a51354b521d933bdd6ba368d00fac18464 (patch) | |
tree | 7fc39b3bc366d81d8561b684f3f8c7c7a0250703 /usr.bin | |
parent | 4b8d4c3d7f5cadca197df2df31783a03872dbeab (diff) | |
download | FreeBSD-src-20e476a51354b521d933bdd6ba368d00fac18464.zip FreeBSD-src-20e476a51354b521d933bdd6ba368d00fac18464.tar.gz |
Modify "netstat -mb" to use libmemstat(3) when acting on a live system,
with a number of positive benefits:
- Start using UMA(9) statistics for mbufs and clusters, which avoids
using the mbuf allocator statistics which suffer from races under
load on SMP. This should eliminate "negative" mbuf counts in
netstat -mb.
- We are now able to track cached (free) mbufs and clusters and count
it towards memory allocated by the network stack.
- We are now also able to track memory allocated to mbuf tags since
libmemstat(3) can also query malloc(9). We don't print this except
as part of the total (for now - #if 0).
- We are now able to track mbuf/cluster/packet allocation failures,
although they are not currently printed (#if 0).
- Don't print out sfbuf statistics when running on a kernel core, as
currently that code is able only to query sysctl for statistics.
MFC after: 1 week
Diffstat (limited to 'usr.bin')
-rw-r--r-- | usr.bin/netstat/Makefile | 4 | ||||
-rw-r--r-- | usr.bin/netstat/mbuf.c | 229 |
2 files changed, 197 insertions, 36 deletions
diff --git a/usr.bin/netstat/Makefile b/usr.bin/netstat/Makefile index c039cbd..483e8ef 100644 --- a/usr.bin/netstat/Makefile +++ b/usr.bin/netstat/Makefile @@ -15,7 +15,7 @@ CFLAGS+=-DINET6 BINGRP= kmem BINMODE=2555 -DPADD= ${LIBKVM} ${LIBIPX} ${LIBNETGRAPH} ${LIBUTIL} -LDADD= -lkvm -lipx -lnetgraph -lutil +DPADD= ${LIBKVM} ${LIBIPX} ${LIBMEMSTAT} ${LIBNETGRAPH} ${LIBUTIL} +LDADD= -lkvm -lipx -lmemstat -lnetgraph -lutil .include <bsd.prog.mk> diff --git a/usr.bin/netstat/mbuf.c b/usr.bin/netstat/mbuf.c index feb4871..b7b41eb 100644 --- a/usr.bin/netstat/mbuf.c +++ b/usr.bin/netstat/mbuf.c @@ -1,6 +1,8 @@ /* * Copyright (c) 1983, 1988, 1993 - * The Regents of the University of California. All rights reserved. + * The Regents of the University of California. + * Copyright (c) 2005 Robert N. M. Watson + * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -47,6 +49,7 @@ __FBSDID("$FreeBSD$"); #include <sys/sysctl.h> #include <err.h> +#include <memstat.h> #include <stdio.h> #include <stdlib.h> #include <string.h> @@ -93,15 +96,14 @@ static struct mbtypenames { }; /* - * Print mbuf statistics. + * Print mbuf statistics extracted from kmem. */ void -mbpr(u_long mbaddr, u_long mbtaddr __unused, u_long nmbcaddr, u_long nmbufaddr, - u_long mbhiaddr, u_long clhiaddr, u_long mbloaddr, u_long clloaddr, - u_long cpusaddr __unused, u_long pgsaddr, u_long mbpaddr) +mbpr_kmem(u_long mbaddr, u_long nmbcaddr, u_long nmbufaddr, u_long mbhiaddr, + u_long clhiaddr, u_long mbloaddr, u_long clloaddr, u_long pgsaddr, + u_long mbpaddr) { int i, nmbclusters; - int nsfbufs, nsfbufspeak, nsfbufsused; short nmbtypes; size_t mlen; long *mbtypes = NULL; @@ -115,25 +117,11 @@ mbpr(u_long mbaddr, u_long mbtaddr __unused, u_long nmbcaddr, u_long nmbufaddr, goto err; } - if (mbaddr) { - if (kread(mbaddr, (char *)mbstat, sizeof mbstat)) - goto err; - if (kread(nmbcaddr, (char *)&nmbclusters, sizeof(int))) - goto err; - } else { - mlen = sizeof *mbstat; - if (sysctlbyname("kern.ipc.mbstat", mbstat, &mlen, NULL, 0) - < 0) { - warn("sysctl: retrieving mbstat"); - goto err; - } - mlen = sizeof(int); - if (sysctlbyname("kern.ipc.nmbclusters", &nmbclusters, &mlen, - NULL, 0) < 0) { - warn("sysctl: retrieving nmbclusters"); - goto err; - } - } + if (kread(mbaddr, (char *)mbstat, sizeof mbstat)) + goto err; + if (kread(nmbcaddr, (char *)&nmbclusters, sizeof(int))) + goto err; + if (mbstat->m_mbufs < 0) mbstat->m_mbufs = 0; /* XXX */ if (mbstat->m_mclusts < 0) mbstat->m_mclusts = 0; /* XXX */ @@ -170,15 +158,6 @@ mbpr(u_long mbaddr, u_long mbtaddr __unused, u_long nmbcaddr, u_long nmbufaddr, printf("%lu/%d mbuf clusters in use (current/max)\n", mbstat->m_mclusts, nmbclusters); - mlen = sizeof(nsfbufs); - if (!sysctlbyname("kern.ipc.nsfbufs", &nsfbufs, &mlen, NULL, 0) && - !sysctlbyname("kern.ipc.nsfbufsused", &nsfbufsused, &mlen, NULL, - 0) && - !sysctlbyname("kern.ipc.nsfbufspeak", &nsfbufspeak, &mlen, NULL, - 0)) { - printf("%d/%d/%d sfbufs in use (current/peak/max)\n", - nsfbufsused, nsfbufspeak, nsfbufs); - } printf("%lu KBytes allocated to network\n", (mbstat->m_mbufs * MSIZE + mbstat->m_mclusts * MCLBYTES) / 1024); printf("%lu requests for sfbufs denied\n", mbstat->sf_allocfail); @@ -195,3 +174,185 @@ err: if (mbstat != NULL) free(mbstat); } + +/* + * If running on a live kernel, directly query the zone allocator for stats + * from the four mbuf-related zones/types. + */ +static void +mbpr_sysctl(void) +{ + struct memory_type_list *mtlp; + struct memory_type *mtp; + u_int64_t mbuf_count, mbuf_bytes, mbuf_free, mbuf_failures, mbuf_size; + u_int64_t cluster_count, cluster_bytes, cluster_limit, cluster_free; + u_int64_t cluster_failures, cluster_size; + u_int64_t packet_count, packet_bytes, packet_free, packet_failures; + u_int64_t tag_count, tag_bytes; + u_int64_t bytes_inuse, bytes_incache, bytes_total; + int nsfbufs, nsfbufspeak, nsfbufsused; + struct mbstat mbstat; + size_t mlen; + + mtlp = memstat_mtl_alloc(); + if (mtlp == NULL) { + warn("memstat_mtl_alloc"); + return; + } + + /* + * Use memstat_sysctl_all() because some mbuf-related memory is in + * uma(9), and some malloc(9). + */ + if (memstat_sysctl_all(mtlp, 0) < 0) { + warn("memstat_sysctl_all"); + goto out; + } + + mtp = memstat_mtl_find(mtlp, ALLOCATOR_UMA, MBUF_MEM_NAME); + if (mtp == NULL) { + warnx("memstat_mtl_find: zone %s not found", MBUF_MEM_NAME); + goto out; + } + mbuf_count = memstat_get_count(mtp); + mbuf_bytes = memstat_get_bytes(mtp); + mbuf_free = memstat_get_free(mtp); + mbuf_failures = memstat_get_failures(mtp); + mbuf_size = memstat_get_size(mtp); + + mtp = memstat_mtl_find(mtlp, ALLOCATOR_UMA, MBUF_PACKET_MEM_NAME); + if (mtp == NULL) { + warnx("memstat_mtl_find: zone %s not found", + MBUF_PACKET_MEM_NAME); + goto out; + } + packet_count = memstat_get_count(mtp); + packet_bytes = memstat_get_bytes(mtp); + packet_free = memstat_get_free(mtp); + packet_failures = memstat_get_failures(mtp); + + mtp = memstat_mtl_find(mtlp, ALLOCATOR_UMA, MBUF_CLUSTER_MEM_NAME); + if (mtp == NULL) { + warnx("memstat_mtl_find: zone %s not found", + MBUF_CLUSTER_MEM_NAME); + goto out; + } + cluster_count = memstat_get_count(mtp); + cluster_bytes = memstat_get_bytes(mtp); + cluster_limit = memstat_get_countlimit(mtp); + cluster_free = memstat_get_free(mtp); + cluster_failures = memstat_get_failures(mtp); + cluster_size = memstat_get_size(mtp); + + mtp = memstat_mtl_find(mtlp, ALLOCATOR_MALLOC, MBUF_TAG_MEM_NAME); + if (mtp == NULL) { + warnx("memstat_mtl_find: malloc type %s not found", + MBUF_TAG_MEM_NAME); + goto out; + } + tag_count = memstat_get_count(mtp); + tag_bytes = memstat_get_bytes(mtp); + + printf("%llu/%llu/%llu mbufs in use (current/cache/total)\n", + mbuf_count + packet_count, mbuf_free + packet_free, + mbuf_count + packet_count + mbuf_free + packet_free); + + printf("%llu/%llu/%llu/%llu mbuf clusters in use " + "(current/cache/total/max)\n", + cluster_count - packet_free, cluster_free + packet_free, + cluster_count + cluster_free, cluster_limit); + +#if 0 + printf("%llu mbuf tags in use\n", tag_count); +#endif + + mlen = sizeof(nsfbufs); + if (!sysctlbyname("kern.ipc.nsfbufs", &nsfbufs, &mlen, NULL, 0) && + !sysctlbyname("kern.ipc.nsfbufsused", &nsfbufsused, &mlen, NULL, + 0) && + !sysctlbyname("kern.ipc.nsfbufspeak", &nsfbufspeak, &mlen, NULL, + 0)) { + printf("%d/%d/%d sfbufs in use (current/peak/max)\n", + nsfbufsused, nsfbufspeak, nsfbufs); + } + + /*- + * Calculate in-use bytes as: + * - straight mbuf memory + * - mbuf memory in packets + * - the clusters attached to packets + * - and the rest of the non-packet-attached clusters. + * - m_tag memory + * This avoids counting the clusters attached to packets in the cache. + * This currently excludes sf_buf space. + */ + bytes_inuse = + mbuf_bytes + /* straight mbuf memory */ + packet_bytes + /* mbufs in packets */ + (packet_count * cluster_size) + /* clusters in packets */ + /* other clusters */ + ((cluster_count - packet_count - packet_free) * cluster_size) + + tag_bytes; + + /* + * Calculate in-cache bytes as: + * - cached straught mbufs + * - cached packet mbufs + * - cached packet clusters + * - cached straight clusters + * This currently excludes sf_buf space. + */ + bytes_incache = + (mbuf_free * mbuf_size) + /* straight free mbufs */ + (packet_free * mbuf_size) + /* mbufs in free packets */ + (packet_free * cluster_size) + /* clusters in free packets */ + (cluster_free * cluster_size); /* free clusters */ + + /* + * Total is bytes in use + bytes in cache. This doesn't take into + * account various other misc data structures, overhead, etc, but + * gives the user something useful despite that. + */ + bytes_total = bytes_inuse + bytes_incache; + + printf("%lluK/%lluK/%lluK bytes allocated to network " + "(current/cache/total)\n", bytes_inuse / 1024, + bytes_incache / 1024, bytes_total / 1024); + +#if 0 + printf("%llu/%llu/%llu requests for mbufs denied (mbufs/clusters/" + "mbuf+clusters)\n", mbuf_failures, cluster_failures, + packet_failures); +#endif + + mlen = sizeof(mbstat); + if (!sysctlbyname("kern.ipc.mbstat", &mbstat, &mlen, NULL, 0)) { + printf("%lu requests for sfbufs denied\n", + mbstat.sf_allocfail); + printf("%lu requests for sfbufs delayed\n", + mbstat.sf_allocwait); + printf("%lu requests for I/O initiated by sendfile\n", + mbstat.sf_iocnt); + printf("%lu calls to protocol drain routines\n", + mbstat.m_drain); + } + +out: + memstat_mtl_free(mtlp); +} + +/* + * Print mbuf statistics. + */ +void +mbpr(u_long mbaddr, u_long mbtaddr __unused, u_long nmbcaddr, u_long nmbufaddr, + u_long mbhiaddr, u_long clhiaddr, u_long mbloaddr, u_long clloaddr, + u_long cpusaddr __unused, u_long pgsaddr, u_long mbpaddr) +{ + + if (mbaddr != 0) + mbpr_kmem(mbaddr, nmbcaddr, nmbufaddr, mbhiaddr, clhiaddr, + mbloaddr, clloaddr, pgsaddr, mbpaddr); + else + mbpr_sysctl(); +} |