Date: Sat, 19 Oct 2013 22:20:01 GMT From: Jilles Tjoelker <jilles@stack.nl> To: freebsd-bugs@FreeBSD.org Subject: Re: kern/167204: [kernel] terrible "netstat -rn" performance due to slow kvm_nlist() Message-ID: <201310192220.r9JMK1Zf088643@freefall.freebsd.org>
next in thread | raw e-mail | index | archive | help
The following reply was made to PR kern/167204; it has been noted by GNATS. From: Jilles Tjoelker <jilles@stack.nl> To: bug-followup@FreeBSD.org, eugen@grosbein.net Cc: "Eugene M. Zheganin" <emz@zhegan.in> Subject: Re: kern/167204: [kernel] terrible "netstat -rn" performance due to slow kvm_nlist() Date: Sun, 20 Oct 2013 00:15:33 +0200 In PR kern/167204, you wrote: > ['netstat -rn' is extremely slow] On a machine here with a faster CPU, 'netstat -rn' takes about 100ms which I still consider very slow. I see two main causes of the slowness here: * kldsym(2) is very slow, particularly if debug symbols are loaded or on architectures such as amd64 that use 'ELF relocatable' as their kld module format (architectures such as i386 use 'ELF shared object' which has a hash table for non-debug symbols). * netstat(1) looks up all kernel symbols it could ever need, with all possible compile options, when it needs any kernel symbol. This appears to be the usual way to use libkvm but netstat is particularly egregious in the number of kernel symbols it may need. The below ugly patch (for head only; stable/10 has a simple conflict and stable/9 is full of conflicts) ensures the '-r' and '-rs' modes only look up the symbols necessary. This speeds up those modes considerably. Index: usr.bin/netstat/main.c =================================================================== --- usr.bin/netstat/main.c (revision 256728) +++ usr.bin/netstat/main.c (working copy) @@ -69,100 +69,108 @@ #include <unistd.h> #include "netstat.h" +static struct nlist rs_nl[] = { +#define RS_N_RTSTAT 0 + { .n_name = "_rtstat" }, +#define RS_N_RTTRASH 1 + { .n_name = "_rttrash" }, + { .n_name = NULL }, +}; + +static struct nlist r_nl[] = { +#define R_N_RTREE 0 + { .n_name = "_rt_tables"}, + { .n_name = NULL }, +}; + static struct nlist nl[] = { #define N_IFNET 0 { .n_name = "_ifnet" }, /* XXXGL: can be deleted */ -#define N_RTSTAT 1 - { .n_name = "_rtstat" }, -#define N_RTREE 2 - { .n_name = "_rt_tables"}, -#define N_MRTSTAT 3 +#define N_MRTSTAT 1 { .n_name = "_mrtstat" }, -#define N_MFCHASHTBL 4 +#define N_MFCHASHTBL 2 { .n_name = "_mfchashtbl" }, -#define N_VIFTABLE 5 +#define N_VIFTABLE 3 { .n_name = "_viftable" }, -#define N_IPX 6 +#define N_IPX 3 { .n_name = "_ipxpcb_list"}, -#define N_IPXSTAT 7 +#define N_IPXSTAT 4 { .n_name = "_ipxstat"}, -#define N_SPXSTAT 8 +#define N_SPXSTAT 5 { .n_name = "_spx_istat"}, -#define N_DDPSTAT 9 +#define N_DDPSTAT 6 { .n_name = "_ddpstat"}, -#define N_DDPCB 10 +#define N_DDPCB 7 { .n_name = "_ddpcb"}, -#define N_NGSOCKS 11 +#define N_NGSOCKS 8 { .n_name = "_ngsocklist"}, -#define N_IP6STAT 12 +#define N_IP6STAT 9 { .n_name = "_ip6stat" }, -#define N_ICMP6STAT 13 +#define N_ICMP6STAT 10 { .n_name = "_icmp6stat" }, -#define N_IPSECSTAT 14 +#define N_IPSECSTAT 11 { .n_name = "_ipsec4stat" }, -#define N_IPSEC6STAT 15 +#define N_IPSEC6STAT 12 { .n_name = "_ipsec6stat" }, -#define N_PIM6STAT 16 +#define N_PIM6STAT 13 { .n_name = "_pim6stat" }, -#define N_MRT6STAT 17 +#define N_MRT6STAT 14 { .n_name = "_mrt6stat" }, -#define N_MF6CTABLE 18 +#define N_MF6CTABLE 15 { .n_name = "_mf6ctable" }, -#define N_MIF6TABLE 19 +#define N_MIF6TABLE 16 { .n_name = "_mif6table" }, -#define N_PFKEYSTAT 20 +#define N_PFKEYSTAT 17 { .n_name = "_pfkeystat" }, -#define N_RTTRASH 21 - { .n_name = "_rttrash" }, -#define N_CARPSTAT 22 +#define N_CARPSTAT 19 { .n_name = "_carpstats" }, -#define N_PFSYNCSTAT 23 +#define N_PFSYNCSTAT 20 { .n_name = "_pfsyncstats" }, -#define N_AHSTAT 24 +#define N_AHSTAT 21 { .n_name = "_ahstat" }, -#define N_ESPSTAT 25 +#define N_ESPSTAT 22 { .n_name = "_espstat" }, -#define N_IPCOMPSTAT 26 +#define N_IPCOMPSTAT 23 { .n_name = "_ipcompstat" }, -#define N_TCPSTAT 27 +#define N_TCPSTAT 24 { .n_name = "_tcpstat" }, -#define N_UDPSTAT 28 +#define N_UDPSTAT 25 { .n_name = "_udpstat" }, -#define N_IPSTAT 29 +#define N_IPSTAT 26 { .n_name = "_ipstat" }, -#define N_ICMPSTAT 30 +#define N_ICMPSTAT 27 { .n_name = "_icmpstat" }, -#define N_IGMPSTAT 31 +#define N_IGMPSTAT 28 { .n_name = "_igmpstat" }, -#define N_PIMSTAT 32 +#define N_PIMSTAT 29 { .n_name = "_pimstat" }, -#define N_TCBINFO 33 +#define N_TCBINFO 30 { .n_name = "_tcbinfo" }, -#define N_UDBINFO 34 +#define N_UDBINFO 31 { .n_name = "_udbinfo" }, -#define N_DIVCBINFO 35 +#define N_DIVCBINFO 32 { .n_name = "_divcbinfo" }, -#define N_RIPCBINFO 36 +#define N_RIPCBINFO 33 { .n_name = "_ripcbinfo" }, -#define N_UNP_COUNT 37 +#define N_UNP_COUNT 34 { .n_name = "_unp_count" }, -#define N_UNP_GENCNT 38 +#define N_UNP_GENCNT 35 { .n_name = "_unp_gencnt" }, -#define N_UNP_DHEAD 39 +#define N_UNP_DHEAD 36 { .n_name = "_unp_dhead" }, -#define N_UNP_SHEAD 40 +#define N_UNP_SHEAD 37 { .n_name = "_unp_shead" }, -#define N_RIP6STAT 41 +#define N_RIP6STAT 38 { .n_name = "_rip6stat" }, -#define N_SCTPSTAT 42 +#define N_SCTPSTAT 39 { .n_name = "_sctpstat" }, -#define N_MFCTABLESIZE 43 +#define N_MFCTABLESIZE 40 { .n_name = "_mfctablesize" }, -#define N_ARPSTAT 44 +#define N_ARPSTAT 41 { .n_name = "_arpstat" }, -#define N_UNP_SPHEAD 45 +#define N_UNP_SPHEAD 42 { .n_name = "unp_sphead" }, -#define N_SFSTAT 46 +#define N_SFSTAT 43 { .n_name = "_sfstat"}, { .n_name = NULL }, }; @@ -305,6 +313,8 @@ static struct protox *name2protox(const char *); static struct protox *knownname(const char *); +static int kvmd_init(struct nlist *); + static kvm_t *kvmd; static char *nlistf = NULL, *memf = NULL; @@ -550,18 +560,22 @@ * used for the queries, which is slower. */ #endif + if (rflag) { + if (sflag) { + kvmd_init(rs_nl); + rt_stats(rs_nl[RS_N_RTSTAT].n_value, + rs_nl[RS_N_RTTRASH].n_value); + } else { + kvmd_init(r_nl); + routepr(r_nl[R_N_RTREE].n_value, fib); + } + exit(0); + } kread(0, NULL, 0); if (iflag && !sflag) { intpr(interval, NULL); exit(0); } - if (rflag) { - if (sflag) - rt_stats(nl[N_RTSTAT].n_value, nl[N_RTTRASH].n_value); - else - routepr(nl[N_RTREE].n_value, fib); - exit(0); - } if (gflag) { if (sflag) { if (af == AF_INET || af == AF_UNSPEC) @@ -684,7 +698,7 @@ } static int -kvmd_init(void) +kvmd_init(struct nlist *nl1) { char errbuf[_POSIX2_LINE_MAX]; @@ -699,7 +713,7 @@ return (-1); } - if (kvm_nlist(kvmd, nl) < 0) { + if (kvm_nlist(kvmd, nl1) < 0) { if (nlistf) errx(1, "%s: kvm_nlist: %s", nlistf, kvm_geterr(kvmd)); @@ -707,7 +721,7 @@ errx(1, "kvm_nlist: %s", kvm_geterr(kvmd)); } - if (nl[0].n_type == 0) { + if (nl1[0].n_type == 0) { if (nlistf) errx(1, "%s: no namelist", nlistf); else @@ -724,7 +738,7 @@ kread(u_long addr, void *buf, size_t size) { - if (kvmd_init() < 0) + if (kvmd_init(nl) < 0) return (-1); if (!buf) @@ -744,7 +758,7 @@ { uint64_t *c = buf; - if (kvmd_init() < 0) + if (kvmd_init(nl) < 0) return (-1); if (kread(addr, buf, size) < 0) -- Jilles Tjoelker
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201310192220.r9JMK1Zf088643>