]> git.saurik.com Git - apple/network_cmds.git/blobdiff - netstat.tproj/mbuf.c
network_cmds-596.100.2.tar.gz
[apple/network_cmds.git] / netstat.tproj / mbuf.c
index c5aacfa76d692e1249cc568e4cb3056d08da8c86..38645e92dc422e292a84c4d5d81ae5ea91975050 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008 Apple Inc. All rights reserved.
+ * Copyright (c) 2008-2010 Apple Inc. All rights reserved.
  *
  * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
  * 
@@ -65,6 +65,7 @@
 #include <sys/sysctl.h>
 
 #include <stdio.h>
+#include <string.h>
 #include <stdlib.h>
 #include <errno.h>
 #include "netstat.h"
@@ -101,10 +102,14 @@ bool seen[256];                   /* "have we seen this type yet?" */
 
 mb_stat_t *mb_stat;
 unsigned int njcl, njclbytes;
+mleak_stat_t *mleak_stat;
+struct mleak_table table;
 
 #define        KERN_IPC_MB_STAT        "kern.ipc.mb_stat"
 #define        KERN_IPC_NJCL           "kern.ipc.njcl"
 #define        KERN_IPC_NJCL_BYTES     "kern.ipc.njclbytes"
+#define        KERN_IPC_MLEAK_TABLE    "kern.ipc.mleak_table"
+#define        KERN_IPC_MLEAK_TOP_TRACE "kern.ipc.mleak_top_trace"
 
 #define        MB_STAT_HDR1 "\
 class        buf   active   ctotal    total cache   cached uncached    memory\n\
@@ -118,6 +123,12 @@ name          count    count    count    count    count    count\n\
 ---------- -------- -------- -------- -------- -------- --------\n\
 "
 
+#define MB_LEAK_HDR "\n\
+    calltrace [1]       calltrace [2]       calltrace [3]       calltrace [4]       calltrace [5]      \n\
+    ------------------  ------------------  ------------------  ------------------  ------------------ \n\
+"
+
+#define MB_LEAK_SPACING "                    "
 static const char *mbpr_state(int);
 static const char *mbpr_mem(u_int32_t);
 static int mbpr_getdata(void);
@@ -128,7 +139,7 @@ static int mbpr_getdata(void);
 void
 mbpr(void)
 {
-       unsigned long totmem = 0, totfree = 0, totmbufs, totused;
+       unsigned long totmem = 0, totfree = 0, totmbufs, totused, totreturned = 0;
        double totpct;
        u_int32_t m_msize, m_mbufs = 0, m_clfree = 0, m_bigclfree = 0;
        u_int32_t m_mbufclfree = 0, m_mbufbigclfree = 0;
@@ -172,6 +183,7 @@ mbpr(void)
 
                mem = cp->mbcl_ctotal * cp->mbcl_size;
                totmem += mem;
+               totreturned += cp->mbcl_release_cnt;
                totfree += (cp->mbcl_mc_cached + cp->mbcl_infree) *
                    cp->mbcl_size;
                if (mflag > 1) {
@@ -259,12 +271,66 @@ mbpr(void)
        }
        printf("%lu KB allocated to network (%.1f%% in use)\n",
                totmem / 1024, totpct);
+       printf("%lu KB returned to the system\n", totreturned / 1024);
 
        printf("%u requests for memory denied\n", (unsigned int)mbstat.m_drops);
        printf("%u requests for memory delayed\n", (unsigned int)mbstat.m_wait);
        printf("%u calls to drain routines\n", (unsigned int)mbstat.m_drain);
 
        free(mb_stat);
+       mb_stat = NULL;
+
+       if (mleak_stat != NULL) {
+               mleak_trace_stat_t *mltr;
+
+               printf("\nmbuf leak detection table:\n");
+               printf("\ttotal captured: %u (one per %u)\n"
+                   "\ttotal allocs outstanding: %llu\n"
+                   "\tnew hash recorded: %llu allocs, %llu traces\n"
+                   "\thash collisions: %llu allocs, %llu traces\n"
+                   "\toverwrites: %llu allocs, %llu traces\n"
+                   "\tlock conflicts: %llu\n\n",
+                   table.mleak_capture / table.mleak_sample_factor,
+                   table.mleak_sample_factor,
+                   table.outstanding_allocs,
+                   table.alloc_recorded, table.trace_recorded,
+                   table.alloc_collisions, table.trace_collisions,
+                   table.alloc_overwrites, table.trace_overwrites,
+                   table.total_conflicts);
+
+               printf("top %d outstanding traces:\n", mleak_stat->ml_cnt);
+               for (i = 0; i < mleak_stat->ml_cnt; i++) {
+                       mltr = &mleak_stat->ml_trace[i];
+                       printf("[%d] %llu outstanding alloc(s), "
+                           "%llu hit(s), %llu collision(s)\n", (i + 1),
+                           mltr->mltr_allocs, mltr->mltr_hitcount,
+                           mltr->mltr_collisions);
+               }
+
+               printf(MB_LEAK_HDR);
+               for (i = 0; i < MLEAK_STACK_DEPTH; i++) {
+                       int j;
+
+                       printf("%2d: ", (i + 1));
+                       for (j = 0; j < mleak_stat->ml_cnt; j++) {
+                               mltr = &mleak_stat->ml_trace[j];
+                               if (i < mltr->mltr_depth) {
+                                       if (mleak_stat->ml_isaddr64) {
+                                               printf("0x%0llx  ",
+                                                   mltr->mltr_addr[i]);
+                                       } else {
+                                               printf("0x%08x          ",
+                                                   (u_int32_t)mltr->mltr_addr[i]);
+                                       }
+                               } else {
+                                       printf(MB_LEAK_SPACING);
+                               }
+                       }
+                       printf("\n");
+               }
+               free(mleak_stat);
+               mleak_stat = NULL;
+       }
 }
 
 static const char *
@@ -350,6 +416,44 @@ mbpr_getdata(void)
                goto done;
        }
 
+       /* mbuf leak detection! */
+       if (mflag > 3) {
+               errno = 0;
+               len = sizeof (table);
+               if (sysctlbyname(KERN_IPC_MLEAK_TABLE, &table, &len, 0, 0) ==
+                   -1 && errno != ENXIO) {
+                       (void) fprintf(stderr, "error %d getting %s\n", errno,
+                           KERN_IPC_MLEAK_TABLE);
+                       goto done;
+               } else if (errno == ENXIO) {
+                       (void) fprintf(stderr, "mbuf leak detection is not "
+                           "enabled in the kernel.\n");
+                       goto skip;
+               }
+
+               if (sysctlbyname(KERN_IPC_MLEAK_TOP_TRACE, NULL, &len,
+                   0, 0) == -1) {
+                       (void) fprintf(stderr, "Error retrieving length for "
+                           "%s: %d\n", KERN_IPC_MB_STAT, errno);
+                       goto done;
+               }
+
+               mleak_stat = calloc(1, len);
+               if (mleak_stat == NULL) {
+                       (void) fprintf(stderr, "Error allocating %lu bytes "
+                           "for sysctl data\n", len);
+                       goto done;
+               }
+
+               if (sysctlbyname(KERN_IPC_MLEAK_TOP_TRACE, mleak_stat, &len,
+                   0, 0) == -1) {
+                       (void) fprintf(stderr, "error %d getting %s\n", errno,
+                            KERN_IPC_MLEAK_TOP_TRACE);
+                       goto done;
+               }
+       }
+
+skip:
        len = sizeof (njcl);
        (void) sysctlbyname(KERN_IPC_NJCL, &njcl, &len, 0, 0);
        len = sizeof (njclbytes);
@@ -358,8 +462,15 @@ mbpr_getdata(void)
        error = 0;
 
 done:
-       if (error != 0  && mb_stat != NULL)
+       if (error != 0  && mb_stat != NULL) {
                free(mb_stat);
+               mb_stat = NULL;
+       }
+
+       if (error != 0 && mleak_stat != NULL) {
+               free(mleak_stat);
+               mleak_stat = NULL;
+       }
 
        return (error);
 }