From 37ab3e78f140de9cdfdc88c255015e0d72b8bcc7 Mon Sep 17 00:00:00 2001 From: Matthew Dillon Date: Thu, 7 Nov 2013 11:51:34 -0800 Subject: [PATCH] debug - Sync debug utilites, add a few more * Sync debug utilites to recent changes and add a few more. * Enhance zallocinfo --- test/debug/checkhammer.c | 169 +++++++++++++++++++++++ test/debug/crc32.c | 22 +++ test/debug/{zallocinfo.c => ksyscalls.c} | 88 +++--------- test/debug/{zallocinfo.c => slabinfo.c} | 112 ++++++++------- test/debug/{zallocinfo.c => vmobjinfo.c} | 106 +++++--------- test/debug/vmpageinfo.c | 4 + test/debug/zallocinfo.c | 26 ++++ 7 files changed, 332 insertions(+), 195 deletions(-) create mode 100644 test/debug/checkhammer.c create mode 100644 test/debug/crc32.c copy test/debug/{zallocinfo.c => ksyscalls.c} (60%) copy test/debug/{zallocinfo.c => slabinfo.c} (65%) copy test/debug/{zallocinfo.c => vmobjinfo.c} (61%) diff --git a/test/debug/checkhammer.c b/test/debug/checkhammer.c new file mode 100644 index 0000000000..a2a595cafa --- /dev/null +++ b/test/debug/checkhammer.c @@ -0,0 +1,169 @@ +/* + * checkhammer.c + * + * checkhammer blockmapdump btreedump + */ + +#include +#include +#include +#include +#include +#include + +struct rbmap_tree; +struct rbmap; + +static void parseBlockMap(FILE *fp); +static void parseBTree(FILE *fp); +static void dumpResults(void); +static int rbmap_cmp(struct rbmap *, struct rbmap *); + +typedef u_int64_t hammer_off_t; +typedef struct rbmap *rbmap_t; + +RB_HEAD(rbmap_tree, rbmap); +RB_PROTOTYPE2(rbmap_tree, rbmap, rbentry, rbmap_cmp, hammer_off_t); + +struct rbmap { + RB_ENTRY(rbmap) rbentry; + hammer_off_t base; + long app; + long free; + long bytes; + int zone; +}; + +RB_GENERATE2(rbmap_tree, rbmap, rbentry, rbmap_cmp, hammer_off_t, base); + +struct rbmap_tree rbroot; + +static +int +rbmap_cmp(struct rbmap *rb1, struct rbmap *rb2) +{ + if (rb1->base < rb2->base) + return(-1); + if (rb1->base > rb2->base) + return(1); + return(0); +} + +int +main(int ac, char **av) +{ + FILE *fp; + + if (ac != 3) { + fprintf(stderr, "checkhammer blockmapdump btreedump\n"); + exit(1); + } + if ((fp = fopen(av[1], "r")) == NULL) { + fprintf(stderr, "Unable to open %s\n", av[1]); + exit(1); + } + + RB_INIT(&rbroot); + parseBlockMap(fp); + fclose(fp); + if ((fp = fopen(av[2], "r")) == NULL) { + fprintf(stderr, "Unable to open %s\n", av[1]); + exit(1); + } + parseBTree(fp); + fclose(fp); + + dumpResults(); + return(0); +} + +static void +parseBlockMap(FILE *fp) +{ + char buf[1024]; + rbmap_t map; + int zone; + long long base; + long long app; + long long free; + + while (fgets(buf, sizeof(buf), fp) != NULL) { + if (sscanf(buf, " 4%llx zone=%d app=%lld free=%lld", + &base, &zone, &app, &free) != 4) + continue; + if (RB_LOOKUP(rbmap_tree, &rbroot, (hammer_off_t)base)) + continue; + map = malloc(sizeof(*map)); + map->base = (hammer_off_t)base; + map->app = (long)app; + map->free = (long)free; + map->zone = zone; + map->bytes = 0; + RB_INSERT(rbmap_tree, &rbroot, map); + } +} + +static void +parseBTree(FILE *fp) +{ + char buf[1024]; + rbmap_t map; + long long base; + long long bytes; + + while (fgets(buf, sizeof(buf), fp) != NULL) { + if (sscanf(buf, " NODE 8%llx", &base) == 1) { + base &= 0x0FFFFFFFFF800000LLU; + map = RB_LOOKUP(rbmap_tree, &rbroot, base); + if (map == NULL) { + printf("(not in blockmap): %s", buf); + continue; + } + map->bytes += 4096; + } + if (sscanf(buf, " dataoff=%llx/%lld", + &base, &bytes) == 2) { + base &= 0x0FFFFFFFFF800000LLU; + map = RB_LOOKUP(rbmap_tree, &rbroot, base); + if (map == NULL) { + printf("(not in blockmap): %s", buf); + continue; + } + map->bytes += (bytes + 15) & ~15; + } + } +} + +static void +dumpResults(void) +{ + rbmap_t map; + hammer_off_t bfree; + + printf("mismatches: (blockmap, actual)\n"); + RB_FOREACH(map, rbmap_tree, &rbroot) { + bfree = 8192 * 1024 - (int64_t)map->bytes; + + /* + * Ignore matches + */ + if (map->free == bfree) + continue; + + /* + * If the block is completely allocated but our calculations + * show nobody is referencing it it is probably an undo, + * blockmap, or unavailable reserved area. + */ + if (map->free == 0 && bfree == 8192 * 1024) { + if (map->zone == 3 || map->zone == 4 || + map->zone == 15) + continue; + } + + printf(" bmap %016jx %jd %jd\n", + map->base, + (intmax_t)(int64_t)map->free, + (intmax_t)(int64_t)bfree); + } +} diff --git a/test/debug/crc32.c b/test/debug/crc32.c new file mode 100644 index 0000000000..cf7b275bbd --- /dev/null +++ b/test/debug/crc32.c @@ -0,0 +1,22 @@ + +/* + * cc crc32.c /usr/src/sys/libkern/crc32.c -o /usr/local/bin/crc32 + */ + +#include +#include +#include +#include + +int +main(int ac, char **av) +{ + char buf[256]; + int n; + u_int32_t crc = crc32(NULL, 0); + + while ((n = read(0, buf, sizeof(buf))) > 0) + crc = crc32_ext(buf, n, crc); + printf("crc %08x\n", crc); + return(0); +} diff --git a/test/debug/zallocinfo.c b/test/debug/ksyscalls.c similarity index 60% copy from test/debug/zallocinfo.c copy to test/debug/ksyscalls.c index f17f8bf72d..11250d1120 100644 --- a/test/debug/zallocinfo.c +++ b/test/debug/ksyscalls.c @@ -1,13 +1,11 @@ /* - * ZALLOCINFO.C + * KSYSCALLS.C * - * cc -I/usr/src/sys zallocinfo.c -o /usr/local/bin/zallocinfo -lkvm + * cc -I/usr/src/sys ksyscalls.c -o /usr/local/bin/ksyscalls -lkvm * - * zallocinfo + * Dump syscall debugging info * - * Print the slab structure and chains for all cpus. - * - * Copyright (c) 2010 The DragonFly Project. All rights reserved. + * Copyright (c) 2011 The DragonFly Project. All rights reserved. * * This code is derived from software contributed to The DragonFly Project * by Matthew Dillon @@ -44,38 +42,33 @@ #include #include #include -#include #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" }, + { "_SysCallsWorstCase" }, { 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 @@ -83,21 +76,13 @@ 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; + uint64_t syscallsworstcase[SYS_MAXSYSCALL]; - while ((ch = getopt(ac, av, "M:N:dv")) != -1) { + while ((ch = getopt(ac, av, "M:N:")) != -1) { switch(ch) { - case 'd': - ++debugopt; - break; - case 'v': - ++verboseopt; - break; case 'M': corefile = optarg; break; @@ -120,58 +105,19 @@ main(int ac, char **av) perror("kvm_nlist"); exit(1); } + kkread(kd, Nl[0].n_value, syscallsworstcase, sizeof(syscallsworstcase)); - 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); + for (i = 0; i < SYS_MAXSYSCALL; ++i) { + if (syscallsworstcase[i]) + printf("call %3d %6jduS\n", i, (intmax_t)syscallsworstcase[i]); } - 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); + perror("kvm_read"); + exit(1); } } diff --git a/test/debug/zallocinfo.c b/test/debug/slabinfo.c similarity index 65% copy from test/debug/zallocinfo.c copy to test/debug/slabinfo.c index f17f8bf72d..47a9ca58ac 100644 --- a/test/debug/zallocinfo.c +++ b/test/debug/slabinfo.c @@ -1,13 +1,13 @@ /* - * ZALLOCINFO.C + * SLABINFO.C * - * cc -I/usr/src/sys zallocinfo.c -o /usr/local/bin/zallocinfo -lkvm + * cc -I/usr/src/sys slabinfo.c -o /usr/local/bin/slabinfo -lkvm * - * zallocinfo + * slabinfo * - * Print the slab structure and chains for all cpus. + * dump kernel slab allocator pcpu data and chains * - * Copyright (c) 2010 The DragonFly Project. All rights reserved. + * Copyright (c) 2012 The DragonFly Project. All rights reserved. * * This code is derived from software contributed to The DragonFly Project * by Matthew Dillon @@ -40,14 +40,16 @@ * SUCH DAMAGE. */ -#define _KERNEL_STRUCTURES_ +#define _KERNEL_STRUCTURES #include #include #include -#include #include +#include +#include #include #include +#include #include #include @@ -60,7 +62,6 @@ #include #include #include -#include #include #include #include @@ -75,20 +76,22 @@ struct nlist Nl[] = { 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 slzonedump(kvm_t *kd, SLZone *kslz); +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; + int j; + int ncpus; + int totalzones; + int totalfree; + struct globaldata gd; while ((ch = getopt(ac, av, "M:N:dv")) != -1) { switch(ch) { @@ -121,57 +124,60 @@ main(int ac, char **av) exit(1); } - kkread(kd, Nl[1].n_value, &ncpus, sizeof(ncpus)); - offset = offsetof(struct privatespace, mdglobaldata.mi.gd_slab); + kkread(kd, Nl[1].n_value, &ncpus, sizeof(int)); + totalzones = 0; + totalfree = 0; for (i = 0; i < ncpus; ++i) { - kkread(kd, Nl[0].n_value + sizeof(struct privatespace) * i + offset, &slab, sizeof(slab)); - dumpslab(kd, i, &slab); + kkread(kd, Nl[0].n_value + i * sizeof(struct privatespace), &gd, sizeof(gd)); + printf("CPU %02d (NFreeZones=%d) {\n", + i, gd.gd_slab.NFreeZones); + totalfree += gd.gd_slab.NFreeZones; + + for (j = 0; j < NZONES; ++j) { + printf(" Zone %02d {\n", j); + totalzones += slzonedump(kd, gd.gd_slab.ZoneAry[j]); + printf(" }\n"); + } + + printf(" FreeZone {\n"); + totalzones += slzonedump(kd, gd.gd_slab.FreeZones); + printf(" }\n"); + + printf(" FreeOVZon {\n"); + totalzones += slzonedump(kd, gd.gd_slab.FreeOvZones); + printf(" }\n"); + + printf("}\n"); } - printf("Done\n"); + printf("TotalZones %d x 131072 = %jd\n", + totalzones, (intmax_t)totalzones * 131072LL); + printf("TotalFree %d x 131072 = %jd\n", + totalfree, (intmax_t)totalfree * 131072LL); return(0); } -static void -dumpslab(kvm_t *kd, int cpu, struct SLGlobalData *slab) +int +slzonedump(kvm_t *kd, SLZone *kslz) { - 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); + SLZone slz; + int count = 0; + + while (kslz) { + kkread(kd, (u_long)kslz, &slz, sizeof(slz)); + printf("\t{ magic=%08x cpu=%d chunking=%d NFree=%d/%d RCnt=%d}\n", + slz.z_Magic, slz.z_Cpu, slz.z_ChunkSize, + slz.z_NFree, slz.z_NMax, slz.z_RCount); + kslz = slz.z_Next; + ++count; } - printf(" TotalUnused %jdM\n", (intmax_t)extra / 1024 / 1024); + return(count); } -static void +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); + perror("kvm_read"); + exit(1); } } diff --git a/test/debug/zallocinfo.c b/test/debug/vmobjinfo.c similarity index 61% copy from test/debug/zallocinfo.c copy to test/debug/vmobjinfo.c index f17f8bf72d..796aa6dcd7 100644 --- a/test/debug/zallocinfo.c +++ b/test/debug/vmobjinfo.c @@ -1,11 +1,9 @@ /* - * ZALLOCINFO.C + * VMOBJINFO.C * - * cc -I/usr/src/sys zallocinfo.c -o /usr/local/bin/zallocinfo -lkvm + * cc -I/usr/src/sys vmobjinfo.c -o /usr/local/bin/vmobjinfo -lkvm * - * zallocinfo - * - * Print the slab structure and chains for all cpus. + * Dump all vm_object's in the system * * Copyright (c) 2010 The DragonFly Project. All rights reserved. * @@ -40,64 +38,56 @@ * SUCH DAMAGE. */ -#define _KERNEL_STRUCTURES_ +#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 #include -#include #include #include #include #include +TAILQ_HEAD(object_q, vm_object); + struct nlist Nl[] = { - { "_CPU_prvspace" }, - { "_ncpus" }, + { "_vm_object_list" }, { NULL } }; -int debugopt; -int verboseopt; - -static void dumpslab(kvm_t *kd, int cpu, struct SLGlobalData *slab); +static void scan_vmobjs(kvm_t *kd, struct object_q *obj_list); 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; + struct object_q obj_list; kvm_t *kd; - int offset; - int ncpus; - int ch; int i; + int ch; + const char *corefile = NULL; + const char *sysfile = NULL; - while ((ch = getopt(ac, av, "M:N:dv")) != -1) { + while ((ch = getopt(ac, av, "M:N:")) != -1) { switch(ch) { - case 'd': - ++debugopt; - break; - case 'v': - ++verboseopt; - break; case 'M': corefile = optarg; break; @@ -109,8 +99,6 @@ main(int ac, char **av) exit(1); } } - ac -= optind; - av += optind; if ((kd = kvm_open(sysfile, corefile, NULL, O_RDONLY, "kvm:")) == NULL) { perror("kvm_open"); @@ -120,58 +108,34 @@ main(int ac, char **av) 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"); + kkread(kd, Nl[0].n_value, &obj_list, sizeof(obj_list)); + scan_vmobjs(kd, &obj_list); return(0); } static void -dumpslab(kvm_t *kd, int cpu, struct SLGlobalData *slab) +scan_vmobjs(kvm_t *kd, struct object_q *obj_list) { - struct SLZone *zonep; - struct SLZone zone; - int i; - int first; - int64_t save; - int64_t extra = 0; + struct vm_object *op; + struct vm_object obj; - printf("cpu %d NFreeZones=%d\n", cpu, slab->NFreeZones); + op = TAILQ_FIRST(obj_list); + while (op) { + kkread(kd, (long)op, &obj, sizeof(obj)); - 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("%p type=%d size=%016jx handle=%p swblocks=%d\n", + op, obj.type, (intmax_t)obj.size, obj.handle, + obj.swblock_count); + + op = TAILQ_NEXT(&obj, object_list); } - 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); + perror("kvm_read"); + exit(1); } } diff --git a/test/debug/vmpageinfo.c b/test/debug/vmpageinfo.c index 049931fc65..349ef172c6 100644 --- a/test/debug/vmpageinfo.c +++ b/test/debug/vmpageinfo.c @@ -246,11 +246,15 @@ main(int ac, char **av) printf(" RAM"); if (m.flags & PG_SWAPPED) printf(" SWAPPED"); +#if 0 if (m.flags & PG_SLAB) printf(" SLAB"); +#endif printf("\n"); +#if 0 if (m.flags & PG_SLAB) addsltrack(&m); +#endif } } if (debugopt || verboseopt) diff --git a/test/debug/zallocinfo.c b/test/debug/zallocinfo.c index f17f8bf72d..c36923008d 100644 --- a/test/debug/zallocinfo.c +++ b/test/debug/zallocinfo.c @@ -136,7 +136,10 @@ dumpslab(kvm_t *kd, int cpu, struct SLGlobalData *slab) { struct SLZone *zonep; struct SLZone zone; + SLChunk *chunkp; + SLChunk chunk; int i; + int rcount; int first; int64_t save; int64_t extra = 0; @@ -161,6 +164,29 @@ dumpslab(kvm_t *kd, int cpu, struct SLGlobalData *slab) extra += zone.z_NFree * zone.z_ChunkSize; zonep = zone.z_Next; first = 0; + + chunkp = zone.z_RChunks; + rcount = 0; + while (chunkp) { + kkread(kd, (u_long)chunkp, &chunk, sizeof(chunk)); + chunkp = chunk.c_Next; + ++rcount; + } + if (rcount) { + printf(" rchunks=%d", rcount); + extra += rcount * zone.z_ChunkSize; + } + chunkp = zone.z_LChunks; + rcount = 0; + while (chunkp) { + kkread(kd, (u_long)chunkp, &chunk, sizeof(chunk)); + chunkp = chunk.c_Next; + ++rcount; + } + if (rcount) { + printf(" lchunks=%d", rcount); + extra += rcount * zone.z_ChunkSize; + } } printf(" (%jdK free)\n", (intmax_t)(extra - save) / 1024); } -- 2.41.0