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_page.h> 56 #include <vm/vm_object.h> 57 #include <vm/swap_pager.h> 58 #include <vm/vnode_pager.h> 59 60 #include <stdio.h> 61 #include <stdlib.h> 62 #include <string.h> 63 #include <stddef.h> 64 #include <fcntl.h> 65 #include <kvm.h> 66 #include <nlist.h> 67 #include <err.h> 68 #include <getopt.h> 69 70 struct nlist Nl[] = { 71 { "_CPU_prvspace" }, 72 { "_ncpus" }, 73 { NULL } 74 }; 75 76 int debugopt; 77 int verboseopt; 78 79 static void dumpslab(kvm_t *kd, int cpu, struct SLGlobalData *slab); 80 static void kkread(kvm_t *kd, u_long addr, void *buf, size_t nbytes); 81 82 int 83 main(int ac, char **av) 84 { 85 const char *corefile = NULL; 86 const char *sysfile = NULL; 87 struct SLGlobalData slab; 88 struct mdglobaldata gd; 89 u_long baseptr; 90 kvm_t *kd; 91 int offset; 92 int ncpus; 93 int ch; 94 int cpu; 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(ncpus)); 128 129 for (cpu = 0; cpu < ncpus; cpu++) { 130 /* 131 * Get the CPU_prvspace base pointer, that is the address to 132 * CPU_prvspace[i] from where other addresses can be built 133 */ 134 kkread(kd, Nl[0].n_value + cpu * sizeof(baseptr), 135 &baseptr, sizeof(baseptr)); 136 /* Now get globaldata struct for the current cpu */ 137 kkread(kd, baseptr + offsetof(struct mdglobaldata, mi.gd_slab), 138 &slab, sizeof(slab)); 139 dumpslab(kd, cpu, &slab); 140 } 141 printf("Done\n"); 142 return(0); 143 } 144 145 static void 146 dumpslab(kvm_t *kd, int cpu, struct SLGlobalData *slab) 147 { 148 struct SLZone *zonep; 149 struct SLZone zone; 150 SLChunk *chunkp; 151 SLChunk chunk; 152 int z; 153 int pass; 154 int xcount; 155 int rcount; 156 int first; 157 int64_t save; 158 int64_t extra = 0; 159 160 printf("cpu %d NFreeZones=%d JunkIndex=%d\n", cpu, slab->NFreeZones, 161 slab->JunkIndex); 162 163 for (z = 0; z < NZONES; z++) { 164 for (pass = 1; pass <= 2; ++pass) { 165 zonep = TAILQ_FIRST(&slab->ZoneAry[z]); 166 first = 1; 167 save = extra; 168 169 while (zonep) { 170 kkread(kd, (u_long)zonep, &zone, sizeof(zone)); 171 172 if (pass == 1) { 173 if (first) { 174 printf(" zone %2d", z); 175 printf(" chunk=%-5d elms=%-4d ", 176 zone.z_ChunkSize, zone.z_NMax); 177 } 178 } else if (pass == 2 && first == 0) { 179 printf(","); 180 } 181 first = 0; 182 183 if (pass == 2) 184 printf(" %d", zone.z_NFree); 185 extra += zone.z_NFree * zone.z_ChunkSize; 186 187 chunkp = zone.z_RChunks; 188 rcount = 0; 189 while (chunkp) { 190 kkread(kd, (u_long)chunkp, &chunk, sizeof(chunk)); 191 chunkp = chunk.c_Next; 192 ++rcount; 193 } 194 xcount = rcount; 195 if (xcount) { 196 if (pass == 2) 197 printf(" [rc=%d", xcount); 198 extra += xcount * zone.z_ChunkSize; 199 } 200 chunkp = zone.z_LChunks; 201 rcount = 0; 202 while (chunkp) { 203 kkread(kd, (u_long)chunkp, &chunk, sizeof(chunk)); 204 chunkp = chunk.c_Next; 205 ++rcount; 206 } 207 if (rcount) { 208 if (pass == 2) { 209 if (xcount) 210 printf(","); 211 else 212 printf(" ["); 213 printf("lc=%d", rcount); 214 } 215 extra += rcount * zone.z_ChunkSize; 216 } 217 if (rcount || xcount) { 218 if (pass == 2) 219 printf("]"); 220 } 221 zonep = TAILQ_NEXT(&zone, z_Entry); 222 } 223 if (first == 0 && pass == 1) 224 printf(" %6jdK free:", (intmax_t)(extra - save) / 1024); 225 if (first == 0 && pass == 2) 226 printf("\n"); 227 } 228 } 229 printf(" TotalUnused %jd.%03dM\n", 230 (intmax_t)extra / 1024 / 1024, 231 (int)(extra % 1024) * 999 / 1024); 232 } 233 234 static void 235 kkread(kvm_t *kd, u_long addr, void *buf, size_t nbytes) 236 { 237 if (kvm_read(kd, addr, buf, nbytes) != nbytes) { 238 perror("kvm_read"); 239 exit(1); 240 } 241 } 242