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