From: Matthew Dillon Date: Fri, 5 Feb 2010 08:24:04 +0000 (-0800) Subject: debug utilities - adjust vmpageinfo, add zallocinfo X-Git-Tag: v2.7.1~229^2~6 X-Git-Url: http://gitweb.dragonflybsd.org/dragonfly.git/commitdiff_plain/069cac031396ad34266cd07ffced2187830ebc56 debug utilities - adjust vmpageinfo, add zallocinfo * Adjust vmpageinfo to match recent changes. Add the symbolic names for the flags. * Add zallocinfo which dumps the state of the slab data structures. --- diff --git a/test/debug/vmpageinfo.c b/test/debug/vmpageinfo.c index f117708..cbebb0d 100644 --- a/test/debug/vmpageinfo.c +++ b/test/debug/vmpageinfo.c @@ -68,8 +68,10 @@ #include struct nlist Nl[] = { +#if 0 { "_vm_page_buckets" }, { "_vm_page_hash_mask" }, +#endif { "_vm_page_array" }, { "_vm_page_array_size" }, { NULL } @@ -77,8 +79,10 @@ struct nlist Nl[] = { int debugopt; int verboseopt; +#if 0 struct vm_page **vm_page_buckets; int vm_page_hash_mask; +#endif struct vm_page *vm_page_array; int vm_page_array_size; @@ -131,10 +135,12 @@ main(int ac, char **av) exit(1); } +#if 0 kkread(kd, Nl[0].n_value, &vm_page_buckets, sizeof(vm_page_buckets)); kkread(kd, Nl[1].n_value, &vm_page_hash_mask, sizeof(vm_page_hash_mask)); - kkread(kd, Nl[2].n_value, &vm_page_array, sizeof(vm_page_array)); - kkread(kd, Nl[3].n_value, &vm_page_array_size, sizeof(vm_page_array_size)); +#endif + kkread(kd, Nl[0].n_value, &vm_page_array, sizeof(vm_page_array)); + kkread(kd, Nl[1].n_value, &vm_page_array_size, sizeof(vm_page_array_size)); /* * Scan the vm_page_array validating all pages with associated objects @@ -163,15 +169,17 @@ main(int ac, char **av) } else { qstr = "NONE"; } - printf("page %p val=%02x dty=%02x hold=%d wired=%-2d active=%-3d busy=%d/%d %s", + printf("page %p obj %p/%-8jd val=%02x dty=%02x hold=%d " + "wire=%-2d act=%-3d busy=%d %8s", &vm_page_array[i], + m.object, + (intmax_t)m.pindex, m.valid, m.dirty, m.hold_count, m.wire_count, m.act_count, m.busy, - ((m.flags & PG_BUSY) ? 1 : 0), qstr ); switch(obj.type) { @@ -197,17 +205,44 @@ main(int ac, char **av) ostr = "unknown"; break; } - - if (m.object && verboseopt > 1) { - printf("\tobj=%p type=%s\n", m.object, ostr); - } else { - printf("\n"); - } + printf(" %-7s", ostr); + if (m.flags & PG_BUSY) + printf(" BUSY"); + if (m.flags & PG_WANTED) + printf(" WANTED"); + if (m.flags & PG_WINATCFLS) + printf(" WINATCFLS"); + if (m.flags & PG_FICTITIOUS) + printf(" FICTITIOUS"); + if (m.flags & PG_WRITEABLE) + printf(" WRITEABLE"); + if (m.flags & PG_MAPPED) + printf(" MAPPED"); + if (m.flags & PG_ZERO) + printf(" ZERO"); + if (m.flags & PG_REFERENCED) + printf(" REFERENCED"); + if (m.flags & PG_CLEANCHK) + printf(" CLEANCHK"); + if (m.flags & PG_SWAPINPROG) + printf(" SWAPINPROG"); + if (m.flags & PG_NOSYNC) + printf(" NOSYNC"); + if (m.flags & PG_UNMANAGED) + printf(" UNMANAGED"); + if (m.flags & PG_MARKER) + printf(" MARKER"); + if (m.flags & PG_RAM) + printf(" RAM"); + if (m.flags & PG_SWAPPED) + printf(" SWAPPED"); + printf("\n"); } } if (debugopt || verboseopt) printf("\n"); +#if 0 /* * Scan the vm_page_buckets array validating all pages found */ @@ -234,6 +269,7 @@ main(int ac, char **av) mptr = m.hnext; } } +#endif if (debugopt) printf("\n"); return(0); @@ -245,6 +281,7 @@ main(int ac, char **av) void checkpage(kvm_t *kd, vm_page_t mptr, vm_page_t m, struct vm_object *obj) { +#if 0 struct vm_page scan; vm_page_t scanptr; int hv; @@ -265,6 +302,7 @@ checkpage(kvm_t *kd, vm_page_t mptr, vm_page_t m, struct vm_object *obj) printf("vm_page_buckets[%d] ((struct vm_page *)%p)" " page not found in bucket list\n", hv, mptr); } +#endif } void diff --git a/test/debug/zallocinfo.c b/test/debug/zallocinfo.c new file mode 100644 index 0000000..f17f8bf --- /dev/null +++ b/test/debug/zallocinfo.c @@ -0,0 +1,177 @@ +/* + * ZALLOCINFO.C + * + * cc -I/usr/src/sys zallocinfo.c -o /usr/local/bin/zallocinfo -lkvm + * + * zallocinfo + * + * Print the slab structure and chains for all cpus. + * + * Copyright (c) 2010 The DragonFly Project. All rights reserved. + * + * This code is derived from software contributed to The DragonFly Project + * by Matthew Dillon + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name of The DragonFly Project nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific, prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#define _KERNEL_STRUCTURES_ +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +struct nlist Nl[] = { + { "_CPU_prvspace" }, + { "_ncpus" }, + { NULL } +}; + +int debugopt; +int verboseopt; + +static void dumpslab(kvm_t *kd, int cpu, struct SLGlobalData *slab); +static void kkread(kvm_t *kd, u_long addr, void *buf, size_t nbytes); + +int +main(int ac, char **av) +{ + const char *corefile = NULL; + const char *sysfile = NULL; + struct SLGlobalData slab; + kvm_t *kd; + int offset; + int ncpus; + int ch; + int i; + + while ((ch = getopt(ac, av, "M:N:dv")) != -1) { + switch(ch) { + case 'd': + ++debugopt; + break; + case 'v': + ++verboseopt; + break; + case 'M': + corefile = optarg; + break; + case 'N': + sysfile = optarg; + break; + default: + fprintf(stderr, "%s [-M core] [-N system]\n", av[0]); + exit(1); + } + } + ac -= optind; + av += optind; + + if ((kd = kvm_open(sysfile, corefile, NULL, O_RDONLY, "kvm:")) == NULL) { + perror("kvm_open"); + exit(1); + } + if (kvm_nlist(kd, Nl) != 0) { + perror("kvm_nlist"); + exit(1); + } + + kkread(kd, Nl[1].n_value, &ncpus, sizeof(ncpus)); + offset = offsetof(struct privatespace, mdglobaldata.mi.gd_slab); + for (i = 0; i < ncpus; ++i) { + kkread(kd, Nl[0].n_value + sizeof(struct privatespace) * i + offset, &slab, sizeof(slab)); + dumpslab(kd, i, &slab); + } + printf("Done\n"); + return(0); +} + +static void +dumpslab(kvm_t *kd, int cpu, struct SLGlobalData *slab) +{ + struct SLZone *zonep; + struct SLZone zone; + int i; + int first; + int64_t save; + int64_t extra = 0; + + printf("cpu %d NFreeZones=%d\n", cpu, slab->NFreeZones); + + for (i = 0; i < NZONES; ++i) { + if ((zonep = slab->ZoneAry[i]) == NULL) + continue; + printf(" zone %2d", i); + first = 1; + save = extra; + while (zonep) { + kkread(kd, (u_long)zonep, &zone, sizeof(zone)); + if (first) { + printf(" chunk=%-5d elms=%-4d free:", + zone.z_ChunkSize, zone.z_NMax); + } + if (first == 0) + printf(","); + printf(" %d", zone.z_NFree); + extra += zone.z_NFree * zone.z_ChunkSize; + zonep = zone.z_Next; + first = 0; + } + printf(" (%jdK free)\n", (intmax_t)(extra - save) / 1024); + } + printf(" TotalUnused %jdM\n", (intmax_t)extra / 1024 / 1024); +} + +static void +kkread(kvm_t *kd, u_long addr, void *buf, size_t nbytes) +{ + if (kvm_read(kd, addr, buf, nbytes) != nbytes) { + perror("kvm_read"); + exit(1); + } +}