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 <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 kvm_t *kd; 88 int offset; 89 int ncpus; 90 int ch; 91 int i; 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 offset = offsetof(struct privatespace, mdglobaldata.mi.gd_slab); 126 for (i = 0; i < ncpus; ++i) { 127 kkread(kd, Nl[0].n_value + sizeof(struct privatespace) * i + offset, &slab, sizeof(slab)); 128 dumpslab(kd, i, &slab); 129 } 130 printf("Done\n"); 131 return(0); 132 } 133 134 static void 135 dumpslab(kvm_t *kd, int cpu, struct SLGlobalData *slab) 136 { 137 struct SLZone *zonep; 138 struct SLZone zone; 139 SLChunk *chunkp; 140 SLChunk chunk; 141 int i; 142 int rcount; 143 int first; 144 int64_t save; 145 int64_t extra = 0; 146 147 printf("cpu %d NFreeZones=%d\n", cpu, slab->NFreeZones); 148 149 for (i = 0; i < NZONES; ++i) { 150 if ((zonep = slab->ZoneAry[i]) == NULL) 151 continue; 152 printf(" zone %2d", i); 153 first = 1; 154 save = extra; 155 while (zonep) { 156 kkread(kd, (u_long)zonep, &zone, sizeof(zone)); 157 if (first) { 158 printf(" chunk=%-5d elms=%-4d free:", 159 zone.z_ChunkSize, zone.z_NMax); 160 } 161 if (first == 0) 162 printf(","); 163 printf(" %d", zone.z_NFree); 164 extra += zone.z_NFree * zone.z_ChunkSize; 165 zonep = zone.z_Next; 166 first = 0; 167 168 chunkp = zone.z_RChunks; 169 rcount = 0; 170 while (chunkp) { 171 kkread(kd, (u_long)chunkp, &chunk, sizeof(chunk)); 172 chunkp = chunk.c_Next; 173 ++rcount; 174 } 175 if (rcount) { 176 printf(" rchunks=%d", rcount); 177 extra += rcount * zone.z_ChunkSize; 178 } 179 chunkp = zone.z_LChunks; 180 rcount = 0; 181 while (chunkp) { 182 kkread(kd, (u_long)chunkp, &chunk, sizeof(chunk)); 183 chunkp = chunk.c_Next; 184 ++rcount; 185 } 186 if (rcount) { 187 printf(" lchunks=%d", rcount); 188 extra += rcount * zone.z_ChunkSize; 189 } 190 } 191 printf(" (%jdK free)\n", (intmax_t)(extra - save) / 1024); 192 } 193 printf(" TotalUnused %jdM\n", (intmax_t)extra / 1024 / 1024); 194 } 195 196 static void 197 kkread(kvm_t *kd, u_long addr, void *buf, size_t nbytes) 198 { 199 if (kvm_read(kd, addr, buf, nbytes) != nbytes) { 200 perror("kvm_read"); 201 exit(1); 202 } 203 } 204