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 = 0; 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 zonep = LIST_FIRST(slab->ZoneAry); 162 kkread(kd, (u_long)zonep, &zone, sizeof(zone)); 163 164 for (z = 0; z < NZONES; z++) { 165 printf(" zone %2d", z); 166 first = 1; 167 save = extra; 168 if (first) 169 printf(" chunk=%-5d elms=%-4d free:", 170 zone.z_ChunkSize, zone.z_NMax); 171 172 if (first == 0) 173 printf(","); 174 printf(" %d", zone.z_NFree); 175 extra += zone.z_NFree * zone.z_ChunkSize; 176 first = 0; 177 178 chunkp = zone.z_RChunks; 179 rcount = 0; 180 while (chunkp) { 181 kkread(kd, (u_long)chunkp, &chunk, sizeof(chunk)); 182 chunkp = chunk.c_Next; 183 ++rcount; 184 } 185 if (rcount) { 186 printf(" rchunks=%d", rcount); 187 extra += rcount * zone.z_ChunkSize; 188 } 189 chunkp = zone.z_LChunks; 190 rcount = 0; 191 while (chunkp) { 192 kkread(kd, (u_long)chunkp, &chunk, sizeof(chunk)); 193 chunkp = chunk.c_Next; 194 ++rcount; 195 } 196 if (rcount) { 197 printf(" lchunks=%d", rcount); 198 extra += rcount * zone.z_ChunkSize; 199 } 200 printf(" (%jdK free)\n", (intmax_t)(extra - save) / 1024); 201 zonep = LIST_NEXT(&zone, z_Entry); 202 if (zonep) 203 kkread(kd, (u_long)zonep, &zone, sizeof(zone)); 204 } 205 printf(" TotalUnused %jdM\n", (intmax_t)extra / 1024 / 1024); 206 } 207 208 static void 209 kkread(kvm_t *kd, u_long addr, void *buf, size_t nbytes) 210 { 211 if (kvm_read(kd, addr, buf, nbytes) != nbytes) { 212 perror("kvm_read"); 213 exit(1); 214 } 215 } 216