]>
git.saurik.com Git - apple/network_cmds.git/blob - netstat.tproj/mbuf.c
2 * Copyright (c) 2008-2010 Apple Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
29 * Copyright (c) 1983, 1988, 1993
30 * The Regents of the University of California. All rights reserved.
32 * Redistribution and use in source and binary forms, with or without
33 * modification, are permitted provided that the following conditions
35 * 1. Redistributions of source code must retain the above copyright
36 * notice, this list of conditions and the following disclaimer.
37 * 2. Redistributions in binary form must reproduce the above copyright
38 * notice, this list of conditions and the following disclaimer in the
39 * documentation and/or other materials provided with the distribution.
40 * 3. All advertising materials mentioning features or use of this software
41 * must display the following acknowledgement:
42 * This product includes software developed by the University of
43 * California, Berkeley and its contributors.
44 * 4. Neither the name of the University nor the names of its contributors
45 * may be used to endorse or promote products derived from this software
46 * without specific prior written permission.
48 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
49 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
50 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
51 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
52 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
53 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
54 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
55 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
56 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
57 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
62 #include <sys/param.h>
63 #include <sys/socket.h>
65 #include <sys/sysctl.h>
78 static struct mbtypes
{
83 { MT_OOBDATA
, "oob data" },
84 { MT_CONTROL
, "ancillary data" },
85 { MT_HEADER
, "packet headers" },
86 { MT_SOCKET
, "socket structures" }, /* XXX */
87 { MT_PCB
, "protocol control blocks" }, /* XXX */
88 { MT_RTABLE
, "routing table entries" }, /* XXX */
89 { MT_HTABLE
, "IMP host table entries" }, /* XXX */
90 { MT_ATABLE
, "address resolution tables" },
91 { MT_FTABLE
, "fragment reassembly queue headers" }, /* XXX */
92 { MT_SONAME
, "socket names and addresses" },
93 { MT_SOOPTS
, "socket options" },
94 { MT_RIGHTS
, "access rights" },
95 { MT_IFADDR
, "interface addresses" }, /* XXX */
96 { MT_TAG
, "packet tags" }, /* XXX */
100 int nmbtypes
= sizeof(mbstat
.m_mtypes
) / sizeof(short);
101 bool seen
[256]; /* "have we seen this type yet?" */
104 unsigned int njcl
, njclbytes
;
105 mleak_stat_t
*mleak_stat
;
106 struct mleak_table table
;
108 #define KERN_IPC_MB_STAT "kern.ipc.mb_stat"
109 #define KERN_IPC_NJCL "kern.ipc.njcl"
110 #define KERN_IPC_NJCL_BYTES "kern.ipc.njclbytes"
111 #define KERN_IPC_MLEAK_TABLE "kern.ipc.mleak_table"
112 #define KERN_IPC_MLEAK_TOP_TRACE "kern.ipc.mleak_top_trace"
114 #define MB_STAT_HDR1 "\
115 class buf active ctotal total cache cached uncached memory\n\
116 name size bufs bufs bufs state bufs bufs usage\n\
117 ---------- ----- -------- -------- -------- ----- -------- -------- ---------\n\
120 #define MB_STAT_HDR2 "\n\
121 class waiter notify purge wretry nwretry failure\n\
122 name count count count count count count\n\
123 ---------- -------- -------- -------- -------- -------- --------\n\
126 #define MB_LEAK_HDR "\n\
127 calltrace [1] calltrace [2] calltrace [3] calltrace [4] calltrace [5] \n\
128 ------------------ ------------------ ------------------ ------------------ ------------------ \n\
131 #define MB_LEAK_SPACING " "
132 static const char *mbpr_state(int);
133 static const char *mbpr_mem(u_int32_t
);
134 static int mbpr_getdata(void);
137 * Print mbuf statistics.
142 unsigned long totmem
= 0, totfree
= 0, totmbufs
, totused
;
144 u_int32_t m_msize
, m_mbufs
= 0, m_clfree
= 0, m_bigclfree
= 0;
145 u_int32_t m_mbufclfree
= 0, m_mbufbigclfree
= 0;
146 u_int32_t m_16kclusters
= 0, m_16kclfree
= 0, m_mbuf16kclfree
= 0;
151 if (mbpr_getdata() != 0)
154 m_msize
= mbstat
.m_msize
;
155 cp
= &mb_stat
->mbs_class
[0];
156 for (i
= 0; i
< mb_stat
->mbs_cnt
; i
++, cp
++) {
157 if (cp
->mbcl_size
== m_msize
) {
158 m_mbufs
= cp
->mbcl_active
;
159 } else if (cp
->mbcl_size
== mbstat
.m_mclbytes
) {
160 m_clfree
= cp
->mbcl_total
- cp
->mbcl_active
;
161 } else if (cp
->mbcl_size
== mbstat
.m_bigmclbytes
) {
162 m_bigclfree
= cp
->mbcl_total
- cp
->mbcl_active
;
163 } else if (njcl
> 0 && cp
->mbcl_size
== njclbytes
) {
164 m_16kclfree
= cp
->mbcl_total
- cp
->mbcl_active
;
165 m_16kclusters
= cp
->mbcl_total
;
166 } else if (cp
->mbcl_size
== (m_msize
+ mbstat
.m_mclbytes
)) {
167 m_mbufclfree
= cp
->mbcl_total
- cp
->mbcl_active
;
168 } else if (cp
->mbcl_size
== (m_msize
+ mbstat
.m_bigmclbytes
)) {
169 m_mbufbigclfree
= cp
->mbcl_total
- cp
->mbcl_active
;
170 } else if (njcl
> 0 && cp
->mbcl_size
== (m_msize
+ njclbytes
)) {
171 m_mbuf16kclfree
= cp
->mbcl_total
- cp
->mbcl_active
;
175 /* adjust free counts to include composite caches */
176 m_clfree
+= m_mbufclfree
;
177 m_bigclfree
+= m_mbufbigclfree
;
178 m_16kclfree
+= m_mbuf16kclfree
;
180 cp
= &mb_stat
->mbs_class
[0];
181 for (i
= 0; i
< mb_stat
->mbs_cnt
; i
++, cp
++) {
184 mem
= cp
->mbcl_ctotal
* cp
->mbcl_size
;
186 totfree
+= (cp
->mbcl_mc_cached
+ cp
->mbcl_infree
) *
190 printf(MB_STAT_HDR1
);
193 cp
->mbcl_size
> (m_msize
+ mbstat
.m_bigmclbytes
))
196 printf("%-10s %5u %8u %8u %8u %5s %8u %8u %9s\n",
197 cp
->mbcl_cname
, cp
->mbcl_size
, cp
->mbcl_active
,
198 cp
->mbcl_ctotal
, cp
->mbcl_total
,
199 mbpr_state(cp
->mbcl_mc_state
), cp
->mbcl_mc_cached
,
200 cp
->mbcl_infree
, mbpr_mem(mem
));
204 cp
= &mb_stat
->mbs_class
[0];
205 for (i
= 0; i
< mb_stat
->mbs_cnt
; i
++, cp
++) {
208 printf(MB_STAT_HDR2
);
211 cp
->mbcl_size
> (m_msize
+ mbstat
.m_bigmclbytes
))
214 printf("%-10s %8u %8llu %8llu %8u %8u %8llu\n",
215 cp
->mbcl_cname
, cp
->mbcl_mc_waiter_cnt
,
216 cp
->mbcl_notified
, cp
->mbcl_purge_cnt
,
217 cp
->mbcl_mc_wretry_cnt
, cp
->mbcl_mc_nwretry_cnt
,
226 for (mp
= mbtypes
; mp
->mt_name
; mp
++)
227 totmbufs
+= mbstat
.m_mtypes
[mp
->mt_type
];
229 * These stats are not updated atomically in the kernel;
230 * adjust the total as neeeded.
232 if (totmbufs
> m_mbufs
)
234 printf("%lu/%u mbufs in use:\n", totmbufs
, m_mbufs
);
235 for (mp
= mbtypes
; mp
->mt_name
; mp
++)
236 if (mbstat
.m_mtypes
[mp
->mt_type
]) {
237 seen
[mp
->mt_type
] = YES
;
238 printf("\t%u mbufs allocated to %s\n",
239 mbstat
.m_mtypes
[mp
->mt_type
], mp
->mt_name
);
242 for (i
= 0; i
< nmbtypes
; i
++)
243 if (!seen
[i
] && mbstat
.m_mtypes
[i
]) {
244 printf("\t%u mbufs allocated to <mbuf type %d>\n",
245 mbstat
.m_mtypes
[i
], i
);
247 if ((m_mbufs
- totmbufs
) > 0)
248 printf("\t%lu mbufs allocated to caches\n",
250 printf("%u/%u mbuf 2KB clusters in use\n",
251 (unsigned int)(mbstat
.m_clusters
- m_clfree
),
252 (unsigned int)mbstat
.m_clusters
);
253 printf("%u/%u mbuf 4KB clusters in use\n",
254 (unsigned int)(mbstat
.m_bigclusters
- m_bigclfree
),
255 (unsigned int)mbstat
.m_bigclusters
);
257 printf("%u/%u mbuf %uKB clusters in use\n",
258 m_16kclusters
- m_16kclfree
, m_16kclusters
,
261 totused
= totmem
- totfree
;
264 else if (totused
< (ULONG_MAX
/100))
265 totpct
= (totused
* 100)/(double)totmem
;
267 u_long totmem1
= totmem
/100;
268 u_long totused1
= totused
/100;
269 totpct
= (totused1
* 100)/(double)totmem1
;
271 printf("%lu KB allocated to network (%.1f%% in use)\n",
272 totmem
/ 1024, totpct
);
274 printf("%u requests for memory denied\n", (unsigned int)mbstat
.m_drops
);
275 printf("%u requests for memory delayed\n", (unsigned int)mbstat
.m_wait
);
276 printf("%u calls to drain routines\n", (unsigned int)mbstat
.m_drain
);
281 if (mleak_stat
!= NULL
) {
282 mleak_trace_stat_t
*mltr
;
284 printf("\nmbuf leak detection table:\n");
285 printf("\ttotal captured: %u (one per %u)\n"
286 "\ttotal allocs outstanding: %llu\n"
287 "\tnew hash recorded: %llu allocs, %llu traces\n"
288 "\thash collisions: %llu allocs, %llu traces\n"
289 "\toverwrites: %llu allocs, %llu traces\n"
290 "\tlock conflicts: %llu\n\n",
291 table
.mleak_capture
/ table
.mleak_sample_factor
,
292 table
.mleak_sample_factor
,
293 table
.outstanding_allocs
,
294 table
.alloc_recorded
, table
.trace_recorded
,
295 table
.alloc_collisions
, table
.trace_collisions
,
296 table
.alloc_overwrites
, table
.trace_overwrites
,
297 table
.total_conflicts
);
299 printf("top %d outstanding traces:\n", mleak_stat
->ml_cnt
);
300 for (i
= 0; i
< mleak_stat
->ml_cnt
; i
++) {
301 mltr
= &mleak_stat
->ml_trace
[i
];
302 printf("[%d] %llu outstanding alloc(s), "
303 "%llu hit(s), %llu collision(s)\n", (i
+ 1),
304 mltr
->mltr_allocs
, mltr
->mltr_hitcount
,
305 mltr
->mltr_collisions
);
309 for (i
= 0; i
< MLEAK_STACK_DEPTH
; i
++) {
312 printf("%2d: ", (i
+ 1));
313 for (j
= 0; j
< mleak_stat
->ml_cnt
; j
++) {
314 mltr
= &mleak_stat
->ml_trace
[j
];
315 if (i
< mltr
->mltr_depth
) {
316 if (mleak_stat
->ml_isaddr64
) {
321 (u_int32_t
)mltr
->mltr_addr
[i
]);
324 printf(MB_LEAK_SPACING
);
335 mbpr_state(int state
)
360 mbpr_mem(u_int32_t bytes
)
366 (void) snprintf(buf
, sizeof (buf
), "%d", (int)mem
);
367 } else if ((mem
/= 1024) < 1024) {
368 (void) snprintf(buf
, sizeof (buf
), "%.1f KB", mem
);
371 (void) snprintf(buf
, sizeof (buf
), "%.1f MB", mem
);
382 if (nmbtypes
!= 256) {
383 (void) fprintf(stderr
,
384 "netstat: unexpected change to mbstat; check source\n");
388 len
= sizeof(mbstat
);
389 if (sysctlbyname("kern.ipc.mbstat", &mbstat
, &len
, 0, 0) == -1)
392 if (sysctlbyname(KERN_IPC_MB_STAT
, NULL
, &len
, 0, 0) == -1) {
393 (void) fprintf(stderr
,
394 "Error retrieving length for %s\n", KERN_IPC_MB_STAT
);
398 mb_stat
= calloc(1, len
);
399 if (mb_stat
== NULL
) {
400 (void) fprintf(stderr
,
401 "Error allocating %lu bytes for sysctl data\n", len
);
405 if (sysctlbyname(KERN_IPC_MB_STAT
, mb_stat
, &len
, 0, 0) == -1) {
406 (void) fprintf(stderr
,
407 "Error %d getting %s\n", errno
, KERN_IPC_MB_STAT
);
411 if (mb_stat
->mbs_cnt
== 0) {
412 (void) fprintf(stderr
,
413 "Invalid mbuf class count (%d)\n", mb_stat
->mbs_cnt
);
417 /* mbuf leak detection! */
420 len
= sizeof (table
);
421 if (sysctlbyname(KERN_IPC_MLEAK_TABLE
, &table
, &len
, 0, 0) ==
422 -1 && errno
!= ENXIO
) {
423 (void) fprintf(stderr
, "error %d getting %s\n", errno
,
424 KERN_IPC_MLEAK_TABLE
);
426 } else if (errno
== ENXIO
) {
427 (void) fprintf(stderr
, "mbuf leak detection is not "
428 "enabled in the kernel.\n");
432 if (sysctlbyname(KERN_IPC_MLEAK_TOP_TRACE
, NULL
, &len
,
434 (void) fprintf(stderr
, "Error retrieving length for "
435 "%s: %d\n", KERN_IPC_MB_STAT
, errno
);
439 mleak_stat
= calloc(1, len
);
440 if (mleak_stat
== NULL
) {
441 (void) fprintf(stderr
, "Error allocating %lu bytes "
442 "for sysctl data\n", len
);
446 if (sysctlbyname(KERN_IPC_MLEAK_TOP_TRACE
, mleak_stat
, &len
,
448 (void) fprintf(stderr
, "error %d getting %s\n", errno
,
449 KERN_IPC_MLEAK_TOP_TRACE
);
456 (void) sysctlbyname(KERN_IPC_NJCL
, &njcl
, &len
, 0, 0);
457 len
= sizeof (njclbytes
);
458 (void) sysctlbyname(KERN_IPC_NJCL_BYTES
, &njclbytes
, &len
, 0, 0);
463 if (error
!= 0 && mb_stat
!= NULL
) {
468 if (error
!= 0 && mleak_stat
!= NULL
) {