xref: /dflybsd-src/test/debug/zallocinfo.c (revision bd3216114e47bc709310ae289acc727624cb901e)
1069cac03SMatthew Dillon /*
2069cac03SMatthew Dillon  * ZALLOCINFO.C
3069cac03SMatthew Dillon  *
4069cac03SMatthew Dillon  * cc -I/usr/src/sys zallocinfo.c -o /usr/local/bin/zallocinfo -lkvm
5069cac03SMatthew Dillon  *
6069cac03SMatthew Dillon  * zallocinfo
7069cac03SMatthew Dillon  *
8069cac03SMatthew Dillon  * Print the slab structure and chains for all cpus.
9069cac03SMatthew Dillon  *
10069cac03SMatthew Dillon  * Copyright (c) 2010 The DragonFly Project.  All rights reserved.
11069cac03SMatthew Dillon  *
12069cac03SMatthew Dillon  * This code is derived from software contributed to The DragonFly Project
13069cac03SMatthew Dillon  * by Matthew Dillon <dillon@backplane.com>
14069cac03SMatthew Dillon  *
15069cac03SMatthew Dillon  * Redistribution and use in source and binary forms, with or without
16069cac03SMatthew Dillon  * modification, are permitted provided that the following conditions
17069cac03SMatthew Dillon  * are met:
18069cac03SMatthew Dillon  *
19069cac03SMatthew Dillon  * 1. Redistributions of source code must retain the above copyright
20069cac03SMatthew Dillon  *    notice, this list of conditions and the following disclaimer.
21069cac03SMatthew Dillon  * 2. Redistributions in binary form must reproduce the above copyright
22069cac03SMatthew Dillon  *    notice, this list of conditions and the following disclaimer in
23069cac03SMatthew Dillon  *    the documentation and/or other materials provided with the
24069cac03SMatthew Dillon  *    distribution.
25069cac03SMatthew Dillon  * 3. Neither the name of The DragonFly Project nor the names of its
26069cac03SMatthew Dillon  *    contributors may be used to endorse or promote products derived
27069cac03SMatthew Dillon  *    from this software without specific, prior written permission.
28069cac03SMatthew Dillon  *
29069cac03SMatthew Dillon  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
30069cac03SMatthew Dillon  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
31069cac03SMatthew Dillon  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
32069cac03SMatthew Dillon  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
33069cac03SMatthew Dillon  * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
34069cac03SMatthew Dillon  * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
35069cac03SMatthew Dillon  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
36069cac03SMatthew Dillon  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
37069cac03SMatthew Dillon  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
38069cac03SMatthew Dillon  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
39069cac03SMatthew Dillon  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
40069cac03SMatthew Dillon  * SUCH DAMAGE.
41069cac03SMatthew Dillon  */
42069cac03SMatthew Dillon 
43069cac03SMatthew Dillon #define _KERNEL_STRUCTURES_
44069cac03SMatthew Dillon #include <sys/param.h>
45069cac03SMatthew Dillon #include <sys/user.h>
46069cac03SMatthew Dillon #include <sys/malloc.h>
47069cac03SMatthew Dillon #include <sys/slaballoc.h>
48069cac03SMatthew Dillon #include <sys/signalvar.h>
49069cac03SMatthew Dillon #include <sys/globaldata.h>
50069cac03SMatthew Dillon #include <machine/globaldata.h>
51069cac03SMatthew Dillon 
52069cac03SMatthew Dillon #include <vm/vm.h>
53069cac03SMatthew Dillon #include <vm/vm_page.h>
54069cac03SMatthew Dillon #include <vm/vm_kern.h>
55069cac03SMatthew Dillon #include <vm/vm_object.h>
56069cac03SMatthew Dillon #include <vm/swap_pager.h>
57069cac03SMatthew Dillon #include <vm/vnode_pager.h>
58069cac03SMatthew Dillon 
59069cac03SMatthew Dillon #include <stdio.h>
60069cac03SMatthew Dillon #include <stdlib.h>
61069cac03SMatthew Dillon #include <string.h>
62069cac03SMatthew Dillon #include <stddef.h>
63069cac03SMatthew Dillon #include <fcntl.h>
64069cac03SMatthew Dillon #include <kvm.h>
65069cac03SMatthew Dillon #include <nlist.h>
66be312ea8SAntonio Huete Jimenez #include <err.h>
67069cac03SMatthew Dillon #include <getopt.h>
68069cac03SMatthew Dillon 
69069cac03SMatthew Dillon struct nlist Nl[] = {
70069cac03SMatthew Dillon     { "_CPU_prvspace" },
71069cac03SMatthew Dillon     { "_ncpus" },
72069cac03SMatthew Dillon     { NULL }
73069cac03SMatthew Dillon };
74069cac03SMatthew Dillon 
75069cac03SMatthew Dillon int debugopt;
76069cac03SMatthew Dillon int verboseopt;
77069cac03SMatthew Dillon 
78069cac03SMatthew Dillon static void dumpslab(kvm_t *kd, int cpu, struct SLGlobalData *slab);
79069cac03SMatthew Dillon static void kkread(kvm_t *kd, u_long addr, void *buf, size_t nbytes);
80069cac03SMatthew Dillon 
81069cac03SMatthew Dillon int
main(int ac,char ** av)82069cac03SMatthew Dillon main(int ac, char **av)
83069cac03SMatthew Dillon {
84069cac03SMatthew Dillon     const char *corefile = NULL;
85069cac03SMatthew Dillon     const char *sysfile = NULL;
86069cac03SMatthew Dillon     struct SLGlobalData slab;
87be312ea8SAntonio Huete Jimenez     u_long baseptr;
88069cac03SMatthew Dillon     kvm_t *kd;
89069cac03SMatthew Dillon     int ncpus;
90069cac03SMatthew Dillon     int ch;
91be312ea8SAntonio Huete Jimenez     int cpu;
92069cac03SMatthew Dillon 
93069cac03SMatthew Dillon     while ((ch = getopt(ac, av, "M:N:dv")) != -1) {
94069cac03SMatthew Dillon 	switch(ch) {
95069cac03SMatthew Dillon 	case 'd':
96069cac03SMatthew Dillon 	    ++debugopt;
97069cac03SMatthew Dillon 	    break;
98069cac03SMatthew Dillon 	case 'v':
99069cac03SMatthew Dillon 	    ++verboseopt;
100069cac03SMatthew Dillon 	    break;
101069cac03SMatthew Dillon 	case 'M':
102069cac03SMatthew Dillon 	    corefile = optarg;
103069cac03SMatthew Dillon 	    break;
104069cac03SMatthew Dillon 	case 'N':
105069cac03SMatthew Dillon 	    sysfile = optarg;
106069cac03SMatthew Dillon 	    break;
107069cac03SMatthew Dillon 	default:
108069cac03SMatthew Dillon 	    fprintf(stderr, "%s [-M core] [-N system]\n", av[0]);
109069cac03SMatthew Dillon 	    exit(1);
110069cac03SMatthew Dillon 	}
111069cac03SMatthew Dillon     }
112069cac03SMatthew Dillon     ac -= optind;
113069cac03SMatthew Dillon     av += optind;
114069cac03SMatthew Dillon 
115069cac03SMatthew Dillon     if ((kd = kvm_open(sysfile, corefile, NULL, O_RDONLY, "kvm:")) == NULL) {
116069cac03SMatthew Dillon 	perror("kvm_open");
117069cac03SMatthew Dillon 	exit(1);
118069cac03SMatthew Dillon     }
119069cac03SMatthew Dillon     if (kvm_nlist(kd, Nl) != 0) {
120069cac03SMatthew Dillon 	perror("kvm_nlist");
121069cac03SMatthew Dillon 	exit(1);
122069cac03SMatthew Dillon     }
123069cac03SMatthew Dillon 
124069cac03SMatthew Dillon     kkread(kd, Nl[1].n_value, &ncpus, sizeof(ncpus));
125be312ea8SAntonio Huete Jimenez 
126be312ea8SAntonio Huete Jimenez     for (cpu = 0; cpu < ncpus; cpu++) {
127be312ea8SAntonio Huete Jimenez 	    /*
128be312ea8SAntonio Huete Jimenez 	     * Get the CPU_prvspace base pointer, that is the address to
129be312ea8SAntonio Huete Jimenez 	     * CPU_prvspace[i] from where other addresses can be built
130be312ea8SAntonio Huete Jimenez 	     */
131be312ea8SAntonio Huete Jimenez 	    kkread(kd, Nl[0].n_value + cpu * sizeof(baseptr),
132be312ea8SAntonio Huete Jimenez 		    &baseptr, sizeof(baseptr));
133be312ea8SAntonio Huete Jimenez 	    /* Now get globaldata struct for the current cpu */
134be312ea8SAntonio Huete Jimenez 	    kkread(kd, baseptr + offsetof(struct mdglobaldata, mi.gd_slab),
135be312ea8SAntonio Huete Jimenez 		&slab, sizeof(slab));
136be312ea8SAntonio Huete Jimenez 	    dumpslab(kd, cpu, &slab);
137069cac03SMatthew Dillon     }
138069cac03SMatthew Dillon     printf("Done\n");
139069cac03SMatthew Dillon     return(0);
140069cac03SMatthew Dillon }
141069cac03SMatthew Dillon 
142069cac03SMatthew Dillon static void
dumpslab(kvm_t * kd,int cpu,struct SLGlobalData * slab)143069cac03SMatthew Dillon dumpslab(kvm_t *kd, int cpu, struct SLGlobalData *slab)
144069cac03SMatthew Dillon {
145069cac03SMatthew Dillon     struct SLZone *zonep;
146069cac03SMatthew Dillon     struct SLZone zone;
14737ab3e78SMatthew Dillon     SLChunk *chunkp;
14837ab3e78SMatthew Dillon     SLChunk chunk;
149c06ca5eeSMatthew Dillon     int z;
150c06ca5eeSMatthew Dillon     int pass;
151c06ca5eeSMatthew Dillon     int xcount;
15237ab3e78SMatthew Dillon     int rcount;
153069cac03SMatthew Dillon     int first;
154069cac03SMatthew Dillon     int64_t save;
155069cac03SMatthew Dillon     int64_t extra = 0;
156069cac03SMatthew Dillon 
157be312ea8SAntonio Huete Jimenez     printf("cpu %d NFreeZones=%d JunkIndex=%d\n", cpu, slab->NFreeZones,
158be312ea8SAntonio Huete Jimenez 	slab->JunkIndex);
159069cac03SMatthew Dillon 
160be312ea8SAntonio Huete Jimenez     for (z = 0; z < NZONES; z++) {
161c06ca5eeSMatthew Dillon     for (pass = 1; pass <= 2; ++pass) {
162*c1b91053SMatthew Dillon 	zonep = TAILQ_FIRST(&slab->ZoneAry[z]);
163069cac03SMatthew Dillon 	first = 1;
164069cac03SMatthew Dillon 	save = extra;
165c06ca5eeSMatthew Dillon 
166c06ca5eeSMatthew Dillon 	while (zonep) {
167c06ca5eeSMatthew Dillon 		kkread(kd, (u_long)zonep, &zone, sizeof(zone));
168c06ca5eeSMatthew Dillon 
169c06ca5eeSMatthew Dillon 		if (pass == 1) {
170c06ca5eeSMatthew Dillon 			if (first) {
171c06ca5eeSMatthew Dillon 				printf("    zone %2d", z);
172*c1b91053SMatthew Dillon 				printf(" chunk=%-5d elms=%-4d ",
173069cac03SMatthew Dillon 				       zone.z_ChunkSize, zone.z_NMax);
174c06ca5eeSMatthew Dillon 			}
175c06ca5eeSMatthew Dillon 		} else if (pass == 2 && first == 0) {
176069cac03SMatthew Dillon 			printf(",");
177c06ca5eeSMatthew Dillon 		}
178c06ca5eeSMatthew Dillon 		first = 0;
179c06ca5eeSMatthew Dillon 
180c06ca5eeSMatthew Dillon 		if (pass == 2)
181069cac03SMatthew Dillon 			printf(" %d", zone.z_NFree);
182069cac03SMatthew Dillon 		extra += zone.z_NFree * zone.z_ChunkSize;
18337ab3e78SMatthew Dillon 
18437ab3e78SMatthew Dillon 		chunkp = zone.z_RChunks;
18537ab3e78SMatthew Dillon 		rcount = 0;
18637ab3e78SMatthew Dillon 		while (chunkp) {
18737ab3e78SMatthew Dillon 			kkread(kd, (u_long)chunkp, &chunk, sizeof(chunk));
18837ab3e78SMatthew Dillon 			chunkp = chunk.c_Next;
18937ab3e78SMatthew Dillon 			++rcount;
19037ab3e78SMatthew Dillon 		}
191c06ca5eeSMatthew Dillon 		xcount = rcount;
192c06ca5eeSMatthew Dillon 		if (xcount) {
193c06ca5eeSMatthew Dillon 			if (pass == 2)
194c06ca5eeSMatthew Dillon 				printf(" [rc=%d", xcount);
195c06ca5eeSMatthew Dillon 			extra += xcount * zone.z_ChunkSize;
19637ab3e78SMatthew Dillon 		}
19737ab3e78SMatthew Dillon 		chunkp = zone.z_LChunks;
19837ab3e78SMatthew Dillon 		rcount = 0;
19937ab3e78SMatthew Dillon 		while (chunkp) {
20037ab3e78SMatthew Dillon 			kkread(kd, (u_long)chunkp, &chunk, sizeof(chunk));
20137ab3e78SMatthew Dillon 			chunkp = chunk.c_Next;
20237ab3e78SMatthew Dillon 			++rcount;
20337ab3e78SMatthew Dillon 		}
20437ab3e78SMatthew Dillon 		if (rcount) {
205c06ca5eeSMatthew Dillon 			if (pass == 2) {
206c06ca5eeSMatthew Dillon 				if (xcount)
207c06ca5eeSMatthew Dillon 					printf(",");
208c06ca5eeSMatthew Dillon 				else
209c06ca5eeSMatthew Dillon 					printf(" [");
210c06ca5eeSMatthew Dillon 				printf("lc=%d", rcount);
211c06ca5eeSMatthew Dillon 			}
21237ab3e78SMatthew Dillon 			extra += rcount * zone.z_ChunkSize;
21337ab3e78SMatthew Dillon 		}
214c06ca5eeSMatthew Dillon 		if (rcount || xcount) {
215c06ca5eeSMatthew Dillon 			if (pass == 2)
216c06ca5eeSMatthew Dillon 				printf("]");
217069cac03SMatthew Dillon 		}
218*c1b91053SMatthew Dillon 		zonep = TAILQ_NEXT(&zone, z_Entry);
219c06ca5eeSMatthew Dillon 	}
220c06ca5eeSMatthew Dillon 	if (first == 0 && pass == 1)
221*c1b91053SMatthew Dillon 		printf(" %6jdK free:", (intmax_t)(extra - save) / 1024);
222c06ca5eeSMatthew Dillon 	if (first == 0 && pass == 2)
223c06ca5eeSMatthew Dillon 		printf("\n");
224c06ca5eeSMatthew Dillon     }
225c06ca5eeSMatthew Dillon     }
226c06ca5eeSMatthew Dillon     printf("    TotalUnused %jd.%03dM\n",
227c06ca5eeSMatthew Dillon 	   (intmax_t)extra / 1024 / 1024,
228c06ca5eeSMatthew Dillon 	   (int)(extra % 1024) * 999 / 1024);
229069cac03SMatthew Dillon }
230069cac03SMatthew Dillon 
231069cac03SMatthew Dillon static void
kkread(kvm_t * kd,u_long addr,void * buf,size_t nbytes)232069cac03SMatthew Dillon kkread(kvm_t *kd, u_long addr, void *buf, size_t nbytes)
233069cac03SMatthew Dillon {
234069cac03SMatthew Dillon     if (kvm_read(kd, addr, buf, nbytes) != nbytes) {
235069cac03SMatthew Dillon 	    perror("kvm_read");
236069cac03SMatthew Dillon 	    exit(1);
237069cac03SMatthew Dillon     }
238069cac03SMatthew Dillon }
239