]>
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
, totreturned
= 0;
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 totreturned
+= cp
->mbcl_release_cnt
;
187 totfree
+= (cp
->mbcl_mc_cached
+ cp
->mbcl_infree
) *
191 printf(MB_STAT_HDR1
);
194 cp
->mbcl_size
> (m_msize
+ mbstat
.m_bigmclbytes
))
197 printf("%-10s %5u %8u %8u %8u %5s %8u %8u %9s\n",
198 cp
->mbcl_cname
, cp
->mbcl_size
, cp
->mbcl_active
,
199 cp
->mbcl_ctotal
, cp
->mbcl_total
,
200 mbpr_state(cp
->mbcl_mc_state
), cp
->mbcl_mc_cached
,
201 cp
->mbcl_infree
, mbpr_mem(mem
));
205 cp
= &mb_stat
->mbs_class
[0];
206 for (i
= 0; i
< mb_stat
->mbs_cnt
; i
++, cp
++) {
209 printf(MB_STAT_HDR2
);
212 cp
->mbcl_size
> (m_msize
+ mbstat
.m_bigmclbytes
))
215 printf("%-10s %8u %8llu %8llu %8u %8u %8llu\n",
216 cp
->mbcl_cname
, cp
->mbcl_mc_waiter_cnt
,
217 cp
->mbcl_notified
, cp
->mbcl_purge_cnt
,
218 cp
->mbcl_mc_wretry_cnt
, cp
->mbcl_mc_nwretry_cnt
,
227 for (mp
= mbtypes
; mp
->mt_name
; mp
++)
228 totmbufs
+= mbstat
.m_mtypes
[mp
->mt_type
];
230 * These stats are not updated atomically in the kernel;
231 * adjust the total as neeeded.
233 if (totmbufs
> m_mbufs
)
235 printf("%lu/%u mbufs in use:\n", totmbufs
, m_mbufs
);
236 for (mp
= mbtypes
; mp
->mt_name
; mp
++)
237 if (mbstat
.m_mtypes
[mp
->mt_type
]) {
238 seen
[mp
->mt_type
] = YES
;
239 printf("\t%u mbufs allocated to %s\n",
240 mbstat
.m_mtypes
[mp
->mt_type
], mp
->mt_name
);
243 for (i
= 0; i
< nmbtypes
; i
++)
244 if (!seen
[i
] && mbstat
.m_mtypes
[i
]) {
245 printf("\t%u mbufs allocated to <mbuf type %d>\n",
246 mbstat
.m_mtypes
[i
], i
);
248 if ((m_mbufs
- totmbufs
) > 0)
249 printf("\t%lu mbufs allocated to caches\n",
251 printf("%u/%u mbuf 2KB clusters in use\n",
252 (unsigned int)(mbstat
.m_clusters
- m_clfree
),
253 (unsigned int)mbstat
.m_clusters
);
254 printf("%u/%u mbuf 4KB clusters in use\n",
255 (unsigned int)(mbstat
.m_bigclusters
- m_bigclfree
),
256 (unsigned int)mbstat
.m_bigclusters
);
258 printf("%u/%u mbuf %uKB clusters in use\n",
259 m_16kclusters
- m_16kclfree
, m_16kclusters
,
262 totused
= totmem
- totfree
;
265 else if (totused
< (ULONG_MAX
/100))
266 totpct
= (totused
* 100)/(double)totmem
;
268 u_long totmem1
= totmem
/100;
269 u_long totused1
= totused
/100;
270 totpct
= (totused1
* 100)/(double)totmem1
;
272 printf("%lu KB allocated to network (%.1f%% in use)\n",
273 totmem
/ 1024, totpct
);
274 printf("%lu KB returned to the system\n", totreturned
/ 1024);
276 printf("%u requests for memory denied\n", (unsigned int)mbstat
.m_drops
);
277 printf("%u requests for memory delayed\n", (unsigned int)mbstat
.m_wait
);
278 printf("%u calls to drain routines\n", (unsigned int)mbstat
.m_drain
);
283 if (mleak_stat
!= NULL
) {
284 mleak_trace_stat_t
*mltr
;
286 printf("\nmbuf leak detection table:\n");
287 printf("\ttotal captured: %u (one per %u)\n"
288 "\ttotal allocs outstanding: %llu\n"
289 "\tnew hash recorded: %llu allocs, %llu traces\n"
290 "\thash collisions: %llu allocs, %llu traces\n"
291 "\toverwrites: %llu allocs, %llu traces\n"
292 "\tlock conflicts: %llu\n\n",
293 table
.mleak_capture
/ table
.mleak_sample_factor
,
294 table
.mleak_sample_factor
,
295 table
.outstanding_allocs
,
296 table
.alloc_recorded
, table
.trace_recorded
,
297 table
.alloc_collisions
, table
.trace_collisions
,
298 table
.alloc_overwrites
, table
.trace_overwrites
,
299 table
.total_conflicts
);
301 printf("top %d outstanding traces:\n", mleak_stat
->ml_cnt
);
302 for (i
= 0; i
< mleak_stat
->ml_cnt
; i
++) {
303 mltr
= &mleak_stat
->ml_trace
[i
];
304 printf("[%d] %llu outstanding alloc(s), "
305 "%llu hit(s), %llu collision(s)\n", (i
+ 1),
306 mltr
->mltr_allocs
, mltr
->mltr_hitcount
,
307 mltr
->mltr_collisions
);
311 for (i
= 0; i
< MLEAK_STACK_DEPTH
; i
++) {
314 printf("%2d: ", (i
+ 1));
315 for (j
= 0; j
< mleak_stat
->ml_cnt
; j
++) {
316 mltr
= &mleak_stat
->ml_trace
[j
];
317 if (i
< mltr
->mltr_depth
) {
318 if (mleak_stat
->ml_isaddr64
) {
323 (u_int32_t
)mltr
->mltr_addr
[i
]);
326 printf(MB_LEAK_SPACING
);
337 mbpr_state(int state
)
362 mbpr_mem(u_int32_t bytes
)
368 (void) snprintf(buf
, sizeof (buf
), "%d", (int)mem
);
369 } else if ((mem
/= 1024) < 1024) {
370 (void) snprintf(buf
, sizeof (buf
), "%.1f KB", mem
);
373 (void) snprintf(buf
, sizeof (buf
), "%.1f MB", mem
);
384 if (nmbtypes
!= 256) {
385 (void) fprintf(stderr
,
386 "netstat: unexpected change to mbstat; check source\n");
390 len
= sizeof(mbstat
);
391 if (sysctlbyname("kern.ipc.mbstat", &mbstat
, &len
, 0, 0) == -1)
394 if (sysctlbyname(KERN_IPC_MB_STAT
, NULL
, &len
, 0, 0) == -1) {
395 (void) fprintf(stderr
,
396 "Error retrieving length for %s\n", KERN_IPC_MB_STAT
);
400 mb_stat
= calloc(1, len
);
401 if (mb_stat
== NULL
) {
402 (void) fprintf(stderr
,
403 "Error allocating %lu bytes for sysctl data\n", len
);
407 if (sysctlbyname(KERN_IPC_MB_STAT
, mb_stat
, &len
, 0, 0) == -1) {
408 (void) fprintf(stderr
,
409 "Error %d getting %s\n", errno
, KERN_IPC_MB_STAT
);
413 if (mb_stat
->mbs_cnt
== 0) {
414 (void) fprintf(stderr
,
415 "Invalid mbuf class count (%d)\n", mb_stat
->mbs_cnt
);
419 /* mbuf leak detection! */
422 len
= sizeof (table
);
423 if (sysctlbyname(KERN_IPC_MLEAK_TABLE
, &table
, &len
, 0, 0) ==
424 -1 && errno
!= ENXIO
) {
425 (void) fprintf(stderr
, "error %d getting %s\n", errno
,
426 KERN_IPC_MLEAK_TABLE
);
428 } else if (errno
== ENXIO
) {
429 (void) fprintf(stderr
, "mbuf leak detection is not "
430 "enabled in the kernel.\n");
434 if (sysctlbyname(KERN_IPC_MLEAK_TOP_TRACE
, NULL
, &len
,
436 (void) fprintf(stderr
, "Error retrieving length for "
437 "%s: %d\n", KERN_IPC_MB_STAT
, errno
);
441 mleak_stat
= calloc(1, len
);
442 if (mleak_stat
== NULL
) {
443 (void) fprintf(stderr
, "Error allocating %lu bytes "
444 "for sysctl data\n", len
);
448 if (sysctlbyname(KERN_IPC_MLEAK_TOP_TRACE
, mleak_stat
, &len
,
450 (void) fprintf(stderr
, "error %d getting %s\n", errno
,
451 KERN_IPC_MLEAK_TOP_TRACE
);
458 (void) sysctlbyname(KERN_IPC_NJCL
, &njcl
, &len
, 0, 0);
459 len
= sizeof (njclbytes
);
460 (void) sysctlbyname(KERN_IPC_NJCL_BYTES
, &njclbytes
, &len
, 0, 0);
465 if (error
!= 0 && mb_stat
!= NULL
) {
470 if (error
!= 0 && mleak_stat
!= NULL
) {