1 /* 2 * ZALLOCINFO.C 3 * 4 * cc -I/usr/src/sys zallocinfo.c -o /usr/local/bin/zallocinfo -lkvm 5 * 6 * zallocinfo 7 * 8 * Print the slab structure and chains for all cpus. 9 * 10 * Copyright (c) 2010 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/slaballoc.h> 48 #include <sys/signalvar.h> 49 #include <sys/globaldata.h> 50 #include <machine/globaldata.h> 51 52 #include <vm/vm.h> 53 #include <vm/vm_page.h> 54 #include <vm/vm_kern.h> 55 #include <vm/vm_object.h> 56 #include <vm/swap_pager.h> 57 #include <vm/vnode_pager.h> 58 59 #include <stdio.h> 60 #include <stdlib.h> 61 #include <string.h> 62 #include <stddef.h> 63 #include <fcntl.h> 64 #include <kvm.h> 65 #include <nlist.h> 66 #include <err.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 static void dumpslab(kvm_t *kd, int cpu, struct SLGlobalData *slab); 79 static void kkread(kvm_t *kd, u_long addr, void *buf, size_t nbytes); 80 81 int 82 main(int ac, char **av) 83 { 84 const char *corefile = NULL; 85 const char *sysfile = NULL; 86 struct SLGlobalData slab; 87 u_long baseptr; 88 kvm_t *kd; 89 int ncpus; 90 int ch; 91 int cpu; 92 93 while ((ch = getopt(ac, av, "M:N:dv")) != -1) { 94 switch(ch) { 95 case 'd': 96 ++debugopt; 97 break; 98 case 'v': 99 ++verboseopt; 100 break; 101 case 'M': 102 corefile = optarg; 103 break; 104 case 'N': 105 sysfile = optarg; 106 break; 107 default: 108 fprintf(stderr, "%s [-M core] [-N system]\n", av[0]); 109 exit(1); 110 } 111 } 112 ac -= optind; 113 av += optind; 114 115 if ((kd = kvm_open(sysfile, corefile, NULL, O_RDONLY, "kvm:")) == NULL) { 116 perror("kvm_open"); 117 exit(1); 118 } 119 if (kvm_nlist(kd, Nl) != 0) { 120 perror("kvm_nlist"); 121 exit(1); 122 } 123 124 kkread(kd, Nl[1].n_value, &ncpus, sizeof(ncpus)); 125 126 for (cpu = 0; cpu < ncpus; cpu++) { 127 /* 128 * Get the CPU_prvspace base pointer, that is the address to 129 * CPU_prvspace[i] from where other addresses can be built 130 */ 131 kkread(kd, Nl[0].n_value + cpu * sizeof(baseptr), 132 &baseptr, sizeof(baseptr)); 133 /* Now get globaldata struct for the current cpu */ 134 kkread(kd, baseptr + offsetof(struct mdglobaldata, mi.gd_slab), 135 &slab, sizeof(slab)); 136 dumpslab(kd, cpu, &slab); 137 } 138 printf("Done\n"); 139 return(0); 140 } 141 142 static void 143 dumpslab(kvm_t *kd, int cpu, struct SLGlobalData *slab) 144 { 145 struct SLZone *zonep; 146 struct SLZone zone; 147 SLChunk *chunkp; 148 SLChunk chunk; 149 int z; 150 int pass; 151 int xcount; 152 int rcount; 153 int first; 154 int64_t save; 155 int64_t extra = 0; 156 157 printf("cpu %d NFreeZones=%d JunkIndex=%d\n", cpu, slab->NFreeZones, 158 slab->JunkIndex); 159 160 for (z = 0; z < NZONES; z++) { 161 for (pass = 1; pass <= 2; ++pass) { 162 zonep = TAILQ_FIRST(&slab->ZoneAry[z]); 163 first = 1; 164 save = extra; 165 166 while (zonep) { 167 kkread(kd, (u_long)zonep, &zone, sizeof(zone)); 168 169 if (pass == 1) { 170 if (first) { 171 printf(" zone %2d", z); 172 printf(" chunk=%-5d elms=%-4d ", 173 zone.z_ChunkSize, zone.z_NMax); 174 } 175 } else if (pass == 2 && first == 0) { 176 printf(","); 177 } 178 first = 0; 179 180 if (pass == 2) 181 printf(" %d", zone.z_NFree); 182 extra += zone.z_NFree * zone.z_ChunkSize; 183 184 chunkp = zone.z_RChunks; 185 rcount = 0; 186 while (chunkp) { 187 kkread(kd, (u_long)chunkp, &chunk, sizeof(chunk)); 188 chunkp = chunk.c_Next; 189 ++rcount; 190 } 191 xcount = rcount; 192 if (xcount) { 193 if (pass == 2) 194 printf(" [rc=%d", xcount); 195 extra += xcount * zone.z_ChunkSize; 196 } 197 chunkp = zone.z_LChunks; 198 rcount = 0; 199 while (chunkp) { 200 kkread(kd, (u_long)chunkp, &chunk, sizeof(chunk)); 201 chunkp = chunk.c_Next; 202 ++rcount; 203 } 204 if (rcount) { 205 if (pass == 2) { 206 if (xcount) 207 printf(","); 208 else 209 printf(" ["); 210 printf("lc=%d", rcount); 211 } 212 extra += rcount * zone.z_ChunkSize; 213 } 214 if (rcount || xcount) { 215 if (pass == 2) 216 printf("]"); 217 } 218 zonep = TAILQ_NEXT(&zone, z_Entry); 219 } 220 if (first == 0 && pass == 1) 221 printf(" %6jdK free:", (intmax_t)(extra - save) / 1024); 222 if (first == 0 && pass == 2) 223 printf("\n"); 224 } 225 } 226 printf(" TotalUnused %jd.%03dM\n", 227 (intmax_t)extra / 1024 / 1024, 228 (int)(extra % 1024) * 999 / 1024); 229 } 230 231 static void 232 kkread(kvm_t *kd, u_long addr, void *buf, size_t nbytes) 233 { 234 if (kvm_read(kd, addr, buf, nbytes) != nbytes) { 235 perror("kvm_read"); 236 exit(1); 237 } 238 } 239