diff options
Diffstat (limited to 'usr/src/cmd/mdb/common/modules')
| -rw-r--r-- | usr/src/cmd/mdb/common/modules/genunix/Makefile.files | 1 | ||||
| -rw-r--r-- | usr/src/cmd/mdb/common/modules/genunix/dist.c | 226 | ||||
| -rw-r--r-- | usr/src/cmd/mdb/common/modules/genunix/dist.h | 44 | ||||
| -rw-r--r-- | usr/src/cmd/mdb/common/modules/genunix/kmem.c | 10 | ||||
| -rw-r--r-- | usr/src/cmd/mdb/common/modules/libumem/umem.c | 10 |
5 files changed, 281 insertions, 10 deletions
diff --git a/usr/src/cmd/mdb/common/modules/genunix/Makefile.files b/usr/src/cmd/mdb/common/modules/genunix/Makefile.files index c4fa4477b6..8bf1c1b520 100644 --- a/usr/src/cmd/mdb/common/modules/genunix/Makefile.files +++ b/usr/src/cmd/mdb/common/modules/genunix/Makefile.files @@ -37,6 +37,7 @@ GENUNIX_SRCS = \ ctxop.c \ cyclic.c \ devinfo.c \ + dist.c \ findstack.c \ fm.c \ genunix.c \ diff --git a/usr/src/cmd/mdb/common/modules/genunix/dist.c b/usr/src/cmd/mdb/common/modules/genunix/dist.c new file mode 100644 index 0000000000..37b6ad553f --- /dev/null +++ b/usr/src/cmd/mdb/common/modules/genunix/dist.c @@ -0,0 +1,226 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <mdb/mdb_modapi.h> +#ifndef _KMDB +#include <math.h> +#endif + +#include "dist.h" + +/* + * Divides the given range (inclusive at both endpoints) evenly into the given + * number of buckets, adding one bucket at the end that is one past the end of + * the range. The returned buckets will be automatically freed when the dcmd + * completes or is forcibly aborted. + */ +const int * +dist_linear(int buckets, int beg, int end) +{ + int *out = mdb_alloc((buckets + 1) * sizeof (*out), UM_SLEEP | UM_GC); + int pos; + int dist = end - beg + 1; + + for (pos = 0; pos < buckets; pos++) + out[pos] = beg + (pos * dist)/buckets; + out[buckets] = end + 1; + + return (out); +} + +/* + * We want the bins to be a constant ratio: + * + * b_0 = beg; + * b_idx = b_{idx-1} * r; + * b_buckets = end + 1; + * + * That is: + * + * buckets + * beg * r = end + * + * Which reduces to: + * + * buckets ___________________ + * r = -------/ ((end + 1) / beg) + * + * log ((end + 1) / beg) + * log r = --------------------- + * buckets + * + * (log ((end + 1) / beg)) / buckets + * r = e + */ +/* ARGSUSED */ +const int * +dist_geometric(int buckets, int beg, int end, int minbucketsize) +{ +#ifdef _KMDB + return (dist_linear(buckets, beg, end)); +#else + int *out = mdb_alloc((buckets + 1) * sizeof (*out), UM_SLEEP | UM_GC); + + double r; + double b; + int idx = 0; + int last; + int begzero; + + if (minbucketsize == 0) + minbucketsize = 1; + + if (buckets == 1) { + out[0] = beg; + out[1] = end + 1; + return (out); + } + + begzero = (beg == 0); + if (begzero) + beg = 1; + + r = exp(log((double)(end + 1) / beg) / buckets); + + /* + * We've now computed r, using the previously derived formula. We + * now need to generate the array of bucket bounds. There are + * two major variables: + * + * b holds b_idx, the current index, as a double. + * last holds the integer which goes into out[idx] + * + * Our job is to transform the smooth function b_idx, defined + * above, into integer-sized buckets, with a specified minimum + * bucket size. Since b_idx is an exponentially growing function, + * any inadequate buckets must be at the beginning. To deal + * with this, we make buckets of minimum size until b catches up + * with last. + * + * A final wrinkle is that beg *can* be zero. We compute r and b + * as if beg was 1, then start last as 0. This can lead to a bit + * of oddness around the 0 bucket, but it's mostly reasonable. + */ + + b = last = beg; + if (begzero) + last = 0; + + for (idx = 0; idx < buckets; idx++) { + int next; + + out[idx] = last; + + b *= r; + next = (int)b; + + if (next > last + minbucketsize - 1) + last = next; + else + last += minbucketsize; + } + out[buckets] = end + 1; + + return (out); +#endif +} + +#define NCHARS 50 +/* + * Print the distribution header with the given bucket label. The header is + * printed on a single line, and the label is assumed to fit within the given + * width (number of characters). The default label width when unspecified (0) + * is eleven characters. Optionally, a label other than "count" may be specified + * for the bucket counts. + */ +void +dist_print_header(const char *label, int width, const char *count) +{ + int n; + const char *dist = " Distribution "; + char dashes[NCHARS + 1]; + + if (width == 0) + width = 11; + + if (count == NULL) + count = "count"; + + n = (NCHARS - strlen(dist)) / 2; + (void) memset(dashes, '-', n); + dashes[n] = '\0'; + + mdb_printf("%*s %s%s%s %s\n", width, label, dashes, dist, dashes, + count); +} + +/* + * Print one distribution bucket whose range is from distarray[i] inclusive to + * distarray[i + 1] exclusive by totalling counts in that index range. The + * given total is assumed to be the sum of all elements in the counts array. + * Each bucket is labeled by its range in the form "first-last" (omit "-last" if + * the range is a single value) where first and last are integers, and last is + * one less than the first value of the next bucket range. The bucket label is + * assumed to fit within the given width (number of characters), which should + * match the width value passed to dist_print_header(). The default width when + * unspecified (0) is eleven characters. + */ +void +dist_print_bucket(const int *distarray, int i, const uint_t *counts, + uint64_t total, int width) +{ + int b; /* bucket range index */ + int bb = distarray[i]; /* bucket begin */ + int be = distarray[i + 1] - 1; /* bucket end */ + uint64_t count = 0; /* bucket value */ + + int nats; + char ats[NCHARS + 1], spaces[NCHARS + 1]; + char range[40]; + + if (width == 0) + width = 11; + + if (total == 0) + total = 1; /* avoid divide-by-zero */ + + for (b = bb; b <= be; b++) + count += counts[b]; + + nats = (NCHARS * count) / total; + (void) memset(ats, '@', nats); + ats[nats] = 0; + (void) memset(spaces, ' ', NCHARS - nats); + spaces[NCHARS - nats] = 0; + + if (bb == be) + (void) mdb_snprintf(range, sizeof (range), "%d", bb); + else + (void) mdb_snprintf(range, sizeof (range), "%d-%d", bb, be); + mdb_printf("%*s |%s%s %lld\n", width, range, ats, spaces, count); +} +#undef NCHARS diff --git a/usr/src/cmd/mdb/common/modules/genunix/dist.h b/usr/src/cmd/mdb/common/modules/genunix/dist.h new file mode 100644 index 0000000000..f3c581fdc6 --- /dev/null +++ b/usr/src/cmd/mdb/common/modules/genunix/dist.h @@ -0,0 +1,44 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#ifndef _DIST_H +#define _DIST_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +#ifdef __cplusplus +extern "C" { +#endif + +extern const int *dist_linear(int, int, int); +extern const int *dist_geometric(int, int, int, int); +extern void dist_print_header(const char *, int, const char *); +extern void dist_print_bucket(const int *, int, const uint_t *, uint64_t, int); + +#ifdef __cplusplus +} +#endif + +#endif /* _DIST_H */ diff --git a/usr/src/cmd/mdb/common/modules/genunix/kmem.c b/usr/src/cmd/mdb/common/modules/genunix/kmem.c index 4511438b6a..47ad09126f 100644 --- a/usr/src/cmd/mdb/common/modules/genunix/kmem.c +++ b/usr/src/cmd/mdb/common/modules/genunix/kmem.c @@ -39,6 +39,7 @@ #include <sys/sysmacros.h> #include <vm/page.h> +#include "dist.h" #include "kmem.h" #include "leaky.h" @@ -353,12 +354,12 @@ kmem_slabs_print_dist(uint_t *ks_bucket, size_t buffers_per_slab, */ complete[0] = buffers_per_slab; complete[1] = buffers_per_slab + 1; - distarray = mdb_dist_linear(buckets - 1, 1, buffers_per_slab - 1); + distarray = dist_linear(buckets - 1, 1, buffers_per_slab - 1); mdb_printf("%*s\n", LABEL_WIDTH, "Allocated"); - mdb_dist_print_header("Buffers", LABEL_WIDTH, "Slabs"); + dist_print_header("Buffers", LABEL_WIDTH, "Slabs"); - mdb_dist_print_bucket(complete, 0, ks_bucket, total, LABEL_WIDTH); + dist_print_bucket(complete, 0, ks_bucket, total, LABEL_WIDTH); /* * Print bucket ranges in descending order after the first bucket for * completely allocated slabs, so a person can see immediately whether @@ -367,8 +368,7 @@ kmem_slabs_print_dist(uint_t *ks_bucket, size_t buffers_per_slab, * extra terminating bucket. */ for (i = buckets - 2; i >= 0; i--) { - mdb_dist_print_bucket(distarray, i, ks_bucket, total, - LABEL_WIDTH); + dist_print_bucket(distarray, i, ks_bucket, total, LABEL_WIDTH); } mdb_printf("\n"); } diff --git a/usr/src/cmd/mdb/common/modules/libumem/umem.c b/usr/src/cmd/mdb/common/modules/libumem/umem.c index ee0b5d5ef1..bd6c41b889 100644 --- a/usr/src/cmd/mdb/common/modules/libumem/umem.c +++ b/usr/src/cmd/mdb/common/modules/libumem/umem.c @@ -35,6 +35,7 @@ #include "misc.h" #include "leaky.h" +#include "dist.h" #include "umem_pagesize.h" @@ -3669,14 +3670,13 @@ umem_malloc_print_dist(uint_t *um_bucket, size_t minmalloc, size_t maxmalloc, } if (geometric) - distarray = mdb_dist_geometric(buckets, minb, maxb, - minbucketsize); + distarray = dist_geometric(buckets, minb, maxb, minbucketsize); else - distarray = mdb_dist_linear(buckets, minb, maxb); + distarray = dist_linear(buckets, minb, maxb); - mdb_dist_print_header("malloc size", 11, "count"); + dist_print_header("malloc size", 11, "count"); for (i = 0; i < buckets; i++) { - mdb_dist_print_bucket(distarray, i, um_bucket, um_malloc, 11); + dist_print_bucket(distarray, i, um_bucket, um_malloc, 11); } mdb_printf("\n"); } |
