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