1 /*
2 * SLABINFO.C
3 *
4 * cc -I/usr/src/sys slabinfo.c -o ~/bin/slabinfo -lkvm
5 *
6 * slabinfo
7 *
8 * dump kernel slab allocator pcpu data and chains
9 *
10 * Copyright (c) 2012 The DragonFly Project. All rights reserved.
11 *
12 * This code is derived from software contributed to The DragonFly Project
13 * by Matthew Dillon <dillon@backplane.com>
14 *
15 * Redistribution and use in source and binary forms, with or without
16 * modification, are permitted provided that the following conditions
17 * are met:
18 *
19 * 1. Redistributions of source code must retain the above copyright
20 * notice, this list of conditions and the following disclaimer.
21 * 2. Redistributions in binary form must reproduce the above copyright
22 * notice, this list of conditions and the following disclaimer in
23 * the documentation and/or other materials provided with the
24 * distribution.
25 * 3. Neither the name of The DragonFly Project nor the names of its
26 * contributors may be used to endorse or promote products derived
27 * from this software without specific, prior written permission.
28 *
29 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
30 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
31 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
32 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
33 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
34 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
35 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
36 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
37 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
38 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
39 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
40 * SUCH DAMAGE.
41 */
42
43 #define _KERNEL_STRUCTURES
44 #include <sys/param.h>
45 #include <sys/user.h>
46 #include <sys/malloc.h>
47 #include <sys/signalvar.h>
48 #include <sys/vnode.h>
49 #include <sys/namecache.h>
50 #include <sys/globaldata.h>
51 #include <machine/globaldata.h>
52 #include <sys/slaballoc.h>
53
54 #include <vm/vm.h>
55 #include <vm/vm_page.h>
56 #include <vm/vm_kern.h>
57 #include <vm/vm_object.h>
58 #include <vm/swap_pager.h>
59 #include <vm/vnode_pager.h>
60
61 #include <stdio.h>
62 #include <stdlib.h>
63 #include <string.h>
64 #include <fcntl.h>
65 #include <kvm.h>
66 #include <nlist.h>
67 #include <getopt.h>
68
69 struct nlist Nl[] = {
70 { "_CPU_prvspace" },
71 { "_ncpus" },
72 { NULL }
73 };
74
75 int debugopt;
76 int verboseopt;
77
78 int slzonedump(kvm_t *kd, SLZoneList *list);
79 void kkread(kvm_t *kd, u_long addr, void *buf, size_t nbytes);
80
81 int
main(int ac,char ** av)82 main(int ac, char **av)
83 {
84 const char *corefile = NULL;
85 const char *sysfile = NULL;
86 kvm_t *kd;
87 int ch;
88 int i;
89 int j;
90 int ncpus;
91 int totalzones;
92 int totalfree;
93 struct globaldata gd;
94 struct privatespace **psary;
95
96 while ((ch = getopt(ac, av, "M:N:dv")) != -1) {
97 switch(ch) {
98 case 'd':
99 ++debugopt;
100 break;
101 case 'v':
102 ++verboseopt;
103 break;
104 case 'M':
105 corefile = optarg;
106 break;
107 case 'N':
108 sysfile = optarg;
109 break;
110 default:
111 fprintf(stderr, "%s [-M core] [-N system]\n", av[0]);
112 exit(1);
113 }
114 }
115 ac -= optind;
116 av += optind;
117
118 if ((kd = kvm_open(sysfile, corefile, NULL, O_RDONLY, "kvm:")) == NULL) {
119 perror("kvm_open");
120 exit(1);
121 }
122 if (kvm_nlist(kd, Nl) != 0) {
123 perror("kvm_nlist");
124 exit(1);
125 }
126
127 kkread(kd, Nl[1].n_value, &ncpus, sizeof(int));
128 totalzones = 0;
129 totalfree = 0;
130
131 psary = malloc(sizeof(void *) * ncpus);
132 kkread(kd, Nl[0].n_value, psary, sizeof(void *) * ncpus);
133
134 for (i = 0; i < ncpus; ++i) {
135 kkread(kd, (long)psary[i], &gd, sizeof(gd));
136 printf("CPU %02d (NFreeZones=%d) {\n",
137 i, gd.gd_slab.NFreeZones);
138 totalfree += gd.gd_slab.NFreeZones;
139
140 for (j = 0; j < NZONES; ++j) {
141 printf(" Zone %02d {\n", j);
142 totalzones += slzonedump(kd, &gd.gd_slab.ZoneAry[j]);
143 printf(" }\n");
144 }
145
146 printf(" FreeZone {\n");
147 totalzones += slzonedump(kd, &gd.gd_slab.FreeZones);
148 printf(" }\n");
149
150 printf(" FreeOVZon {\n");
151 totalzones += slzonedump(kd, &gd.gd_slab.FreeOvZones);
152 printf(" }\n");
153
154 printf("}\n");
155 }
156 printf("TotalZones %d x 131072 = %jd\n",
157 totalzones, (intmax_t)totalzones * 131072LL);
158 printf("TotalFree %d x 131072 = %jd\n",
159 totalfree, (intmax_t)totalfree * 131072LL);
160 return(0);
161 }
162
163 int
slzonedump(kvm_t * kd,SLZoneList * list)164 slzonedump(kvm_t *kd, SLZoneList *list)
165 {
166 SLZone slz;
167 SLZone *kslz;
168 int count = 0;
169
170 kslz = TAILQ_FIRST(list);
171
172 while (kslz) {
173 kkread(kd, (u_long)kslz, &slz, sizeof(slz));
174 printf("\t{ magic=%08x cpu=%d chunking=%d NFree=%d/%d RCnt=%d}\n",
175 slz.z_Magic, slz.z_Cpu, slz.z_ChunkSize,
176 slz.z_NFree, slz.z_NMax, slz.z_RCount);
177 kslz = TAILQ_NEXT(&slz, z_Entry);
178 ++count;
179 }
180 return(count);
181 }
182
183 void
kkread(kvm_t * kd,u_long addr,void * buf,size_t nbytes)184 kkread(kvm_t *kd, u_long addr, void *buf, size_t nbytes)
185 {
186 if (kvm_read(kd, addr, buf, nbytes) != nbytes) {
187 perror("kvm_read");
188 exit(1);
189 }
190 }
191