The following reply was made to PR kern/167204; it has been noted by GNATS.

From: Jilles Tjoelker <[email protected]>
To: [email protected], [email protected]
Cc: "Eugene M. Zheganin" <[email protected]>
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
_______________________________________________
[email protected] mailing list
http://lists.freebsd.org/mailman/listinfo/freebsd-bugs
To unsubscribe, send any mail to "[email protected]"

Reply via email to