087e1372ab71eb8a49fbb5619711cfbb79f695fctomee/*
087e1372ab71eb8a49fbb5619711cfbb79f695fctomee * CDDL HEADER START
087e1372ab71eb8a49fbb5619711cfbb79f695fctomee *
087e1372ab71eb8a49fbb5619711cfbb79f695fctomee * The contents of this file are subject to the terms of the
087e1372ab71eb8a49fbb5619711cfbb79f695fctomee * Common Development and Distribution License (the "License").
087e1372ab71eb8a49fbb5619711cfbb79f695fctomee * You may not use this file except in compliance with the License.
087e1372ab71eb8a49fbb5619711cfbb79f695fctomee *
087e1372ab71eb8a49fbb5619711cfbb79f695fctomee * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
087e1372ab71eb8a49fbb5619711cfbb79f695fctomee * or http://www.opensolaris.org/os/licensing.
087e1372ab71eb8a49fbb5619711cfbb79f695fctomee * See the License for the specific language governing permissions
087e1372ab71eb8a49fbb5619711cfbb79f695fctomee * and limitations under the License.
087e1372ab71eb8a49fbb5619711cfbb79f695fctomee *
087e1372ab71eb8a49fbb5619711cfbb79f695fctomee * When distributing Covered Code, include this CDDL HEADER in each
087e1372ab71eb8a49fbb5619711cfbb79f695fctomee * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
087e1372ab71eb8a49fbb5619711cfbb79f695fctomee * If applicable, add the following below this CDDL HEADER, with the
087e1372ab71eb8a49fbb5619711cfbb79f695fctomee * fields enclosed by brackets "[]" replaced with your own identifying
087e1372ab71eb8a49fbb5619711cfbb79f695fctomee * information: Portions Copyright [yyyy] [name of copyright owner]
087e1372ab71eb8a49fbb5619711cfbb79f695fctomee *
087e1372ab71eb8a49fbb5619711cfbb79f695fctomee * CDDL HEADER END
087e1372ab71eb8a49fbb5619711cfbb79f695fctomee */
087e1372ab71eb8a49fbb5619711cfbb79f695fctomee/*
087e1372ab71eb8a49fbb5619711cfbb79f695fctomee * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
087e1372ab71eb8a49fbb5619711cfbb79f695fctomee * Use is subject to license terms.
087e1372ab71eb8a49fbb5619711cfbb79f695fctomee */
087e1372ab71eb8a49fbb5619711cfbb79f695fctomee
087e1372ab71eb8a49fbb5619711cfbb79f695fctomee#pragma ident "%Z%%M% %I% %E% SMI"
087e1372ab71eb8a49fbb5619711cfbb79f695fctomee
087e1372ab71eb8a49fbb5619711cfbb79f695fctomee#include <mdb/mdb_modapi.h>
087e1372ab71eb8a49fbb5619711cfbb79f695fctomee#ifndef _KMDB
087e1372ab71eb8a49fbb5619711cfbb79f695fctomee#include <math.h>
087e1372ab71eb8a49fbb5619711cfbb79f695fctomee#endif
087e1372ab71eb8a49fbb5619711cfbb79f695fctomee
087e1372ab71eb8a49fbb5619711cfbb79f695fctomee#include "dist.h"
087e1372ab71eb8a49fbb5619711cfbb79f695fctomee
087e1372ab71eb8a49fbb5619711cfbb79f695fctomee/*
087e1372ab71eb8a49fbb5619711cfbb79f695fctomee * Divides the given range (inclusive at both endpoints) evenly into the given
087e1372ab71eb8a49fbb5619711cfbb79f695fctomee * number of buckets, adding one bucket at the end that is one past the end of
087e1372ab71eb8a49fbb5619711cfbb79f695fctomee * the range. The returned buckets will be automatically freed when the dcmd
087e1372ab71eb8a49fbb5619711cfbb79f695fctomee * completes or is forcibly aborted.
087e1372ab71eb8a49fbb5619711cfbb79f695fctomee */
087e1372ab71eb8a49fbb5619711cfbb79f695fctomeeconst int *
087e1372ab71eb8a49fbb5619711cfbb79f695fctomeedist_linear(int buckets, int beg, int end)
087e1372ab71eb8a49fbb5619711cfbb79f695fctomee{
087e1372ab71eb8a49fbb5619711cfbb79f695fctomee int *out = mdb_alloc((buckets + 1) * sizeof (*out), UM_SLEEP | UM_GC);
087e1372ab71eb8a49fbb5619711cfbb79f695fctomee int pos;
087e1372ab71eb8a49fbb5619711cfbb79f695fctomee int dist = end - beg + 1;
087e1372ab71eb8a49fbb5619711cfbb79f695fctomee
087e1372ab71eb8a49fbb5619711cfbb79f695fctomee for (pos = 0; pos < buckets; pos++)
087e1372ab71eb8a49fbb5619711cfbb79f695fctomee out[pos] = beg + (pos * dist)/buckets;
087e1372ab71eb8a49fbb5619711cfbb79f695fctomee out[buckets] = end + 1;
087e1372ab71eb8a49fbb5619711cfbb79f695fctomee
087e1372ab71eb8a49fbb5619711cfbb79f695fctomee return (out);
087e1372ab71eb8a49fbb5619711cfbb79f695fctomee}
087e1372ab71eb8a49fbb5619711cfbb79f695fctomee
087e1372ab71eb8a49fbb5619711cfbb79f695fctomee/*
087e1372ab71eb8a49fbb5619711cfbb79f695fctomee * We want the bins to be a constant ratio:
087e1372ab71eb8a49fbb5619711cfbb79f695fctomee *
087e1372ab71eb8a49fbb5619711cfbb79f695fctomee * b_0 = beg;
087e1372ab71eb8a49fbb5619711cfbb79f695fctomee * b_idx = b_{idx-1} * r;
087e1372ab71eb8a49fbb5619711cfbb79f695fctomee * b_buckets = end + 1;
087e1372ab71eb8a49fbb5619711cfbb79f695fctomee *
087e1372ab71eb8a49fbb5619711cfbb79f695fctomee * That is:
087e1372ab71eb8a49fbb5619711cfbb79f695fctomee *
087e1372ab71eb8a49fbb5619711cfbb79f695fctomee * buckets
087e1372ab71eb8a49fbb5619711cfbb79f695fctomee * beg * r = end
087e1372ab71eb8a49fbb5619711cfbb79f695fctomee *
087e1372ab71eb8a49fbb5619711cfbb79f695fctomee * Which reduces to:
087e1372ab71eb8a49fbb5619711cfbb79f695fctomee *
087e1372ab71eb8a49fbb5619711cfbb79f695fctomee * buckets ___________________
087e1372ab71eb8a49fbb5619711cfbb79f695fctomee * r = -------/ ((end + 1) / beg)
087e1372ab71eb8a49fbb5619711cfbb79f695fctomee *
087e1372ab71eb8a49fbb5619711cfbb79f695fctomee * log ((end + 1) / beg)
087e1372ab71eb8a49fbb5619711cfbb79f695fctomee * log r = ---------------------
087e1372ab71eb8a49fbb5619711cfbb79f695fctomee * buckets
087e1372ab71eb8a49fbb5619711cfbb79f695fctomee *
087e1372ab71eb8a49fbb5619711cfbb79f695fctomee * (log ((end + 1) / beg)) / buckets
087e1372ab71eb8a49fbb5619711cfbb79f695fctomee * r = e
087e1372ab71eb8a49fbb5619711cfbb79f695fctomee */
087e1372ab71eb8a49fbb5619711cfbb79f695fctomee/* ARGSUSED */
087e1372ab71eb8a49fbb5619711cfbb79f695fctomeeconst int *
087e1372ab71eb8a49fbb5619711cfbb79f695fctomeedist_geometric(int buckets, int beg, int end, int minbucketsize)
087e1372ab71eb8a49fbb5619711cfbb79f695fctomee{
087e1372ab71eb8a49fbb5619711cfbb79f695fctomee#ifdef _KMDB
087e1372ab71eb8a49fbb5619711cfbb79f695fctomee return (dist_linear(buckets, beg, end));
087e1372ab71eb8a49fbb5619711cfbb79f695fctomee#else
087e1372ab71eb8a49fbb5619711cfbb79f695fctomee int *out = mdb_alloc((buckets + 1) * sizeof (*out), UM_SLEEP | UM_GC);
087e1372ab71eb8a49fbb5619711cfbb79f695fctomee
087e1372ab71eb8a49fbb5619711cfbb79f695fctomee double r;
087e1372ab71eb8a49fbb5619711cfbb79f695fctomee double b;
087e1372ab71eb8a49fbb5619711cfbb79f695fctomee int idx = 0;
087e1372ab71eb8a49fbb5619711cfbb79f695fctomee int last;
087e1372ab71eb8a49fbb5619711cfbb79f695fctomee int begzero;
087e1372ab71eb8a49fbb5619711cfbb79f695fctomee
087e1372ab71eb8a49fbb5619711cfbb79f695fctomee if (minbucketsize == 0)
087e1372ab71eb8a49fbb5619711cfbb79f695fctomee minbucketsize = 1;
087e1372ab71eb8a49fbb5619711cfbb79f695fctomee
087e1372ab71eb8a49fbb5619711cfbb79f695fctomee if (buckets == 1) {
087e1372ab71eb8a49fbb5619711cfbb79f695fctomee out[0] = beg;
087e1372ab71eb8a49fbb5619711cfbb79f695fctomee out[1] = end + 1;
087e1372ab71eb8a49fbb5619711cfbb79f695fctomee return (out);
087e1372ab71eb8a49fbb5619711cfbb79f695fctomee }
087e1372ab71eb8a49fbb5619711cfbb79f695fctomee
087e1372ab71eb8a49fbb5619711cfbb79f695fctomee begzero = (beg == 0);
087e1372ab71eb8a49fbb5619711cfbb79f695fctomee if (begzero)
087e1372ab71eb8a49fbb5619711cfbb79f695fctomee beg = 1;
087e1372ab71eb8a49fbb5619711cfbb79f695fctomee
087e1372ab71eb8a49fbb5619711cfbb79f695fctomee r = exp(log((double)(end + 1) / beg) / buckets);
087e1372ab71eb8a49fbb5619711cfbb79f695fctomee
087e1372ab71eb8a49fbb5619711cfbb79f695fctomee /*
087e1372ab71eb8a49fbb5619711cfbb79f695fctomee * We've now computed r, using the previously derived formula. We
087e1372ab71eb8a49fbb5619711cfbb79f695fctomee * now need to generate the array of bucket bounds. There are
087e1372ab71eb8a49fbb5619711cfbb79f695fctomee * two major variables:
087e1372ab71eb8a49fbb5619711cfbb79f695fctomee *
087e1372ab71eb8a49fbb5619711cfbb79f695fctomee * b holds b_idx, the current index, as a double.
087e1372ab71eb8a49fbb5619711cfbb79f695fctomee * last holds the integer which goes into out[idx]
087e1372ab71eb8a49fbb5619711cfbb79f695fctomee *
087e1372ab71eb8a49fbb5619711cfbb79f695fctomee * Our job is to transform the smooth function b_idx, defined
087e1372ab71eb8a49fbb5619711cfbb79f695fctomee * above, into integer-sized buckets, with a specified minimum
087e1372ab71eb8a49fbb5619711cfbb79f695fctomee * bucket size. Since b_idx is an exponentially growing function,
087e1372ab71eb8a49fbb5619711cfbb79f695fctomee * any inadequate buckets must be at the beginning. To deal
087e1372ab71eb8a49fbb5619711cfbb79f695fctomee * with this, we make buckets of minimum size until b catches up
087e1372ab71eb8a49fbb5619711cfbb79f695fctomee * with last.
087e1372ab71eb8a49fbb5619711cfbb79f695fctomee *
087e1372ab71eb8a49fbb5619711cfbb79f695fctomee * A final wrinkle is that beg *can* be zero. We compute r and b
087e1372ab71eb8a49fbb5619711cfbb79f695fctomee * as if beg was 1, then start last as 0. This can lead to a bit
087e1372ab71eb8a49fbb5619711cfbb79f695fctomee * of oddness around the 0 bucket, but it's mostly reasonable.
087e1372ab71eb8a49fbb5619711cfbb79f695fctomee */
087e1372ab71eb8a49fbb5619711cfbb79f695fctomee
087e1372ab71eb8a49fbb5619711cfbb79f695fctomee b = last = beg;
087e1372ab71eb8a49fbb5619711cfbb79f695fctomee if (begzero)
087e1372ab71eb8a49fbb5619711cfbb79f695fctomee last = 0;
087e1372ab71eb8a49fbb5619711cfbb79f695fctomee
087e1372ab71eb8a49fbb5619711cfbb79f695fctomee for (idx = 0; idx < buckets; idx++) {
087e1372ab71eb8a49fbb5619711cfbb79f695fctomee int next;
087e1372ab71eb8a49fbb5619711cfbb79f695fctomee
087e1372ab71eb8a49fbb5619711cfbb79f695fctomee out[idx] = last;
087e1372ab71eb8a49fbb5619711cfbb79f695fctomee
087e1372ab71eb8a49fbb5619711cfbb79f695fctomee b *= r;
087e1372ab71eb8a49fbb5619711cfbb79f695fctomee next = (int)b;
087e1372ab71eb8a49fbb5619711cfbb79f695fctomee
087e1372ab71eb8a49fbb5619711cfbb79f695fctomee if (next > last + minbucketsize - 1)
087e1372ab71eb8a49fbb5619711cfbb79f695fctomee last = next;
087e1372ab71eb8a49fbb5619711cfbb79f695fctomee else
087e1372ab71eb8a49fbb5619711cfbb79f695fctomee last += minbucketsize;
087e1372ab71eb8a49fbb5619711cfbb79f695fctomee }
087e1372ab71eb8a49fbb5619711cfbb79f695fctomee out[buckets] = end + 1;
087e1372ab71eb8a49fbb5619711cfbb79f695fctomee
087e1372ab71eb8a49fbb5619711cfbb79f695fctomee return (out);
087e1372ab71eb8a49fbb5619711cfbb79f695fctomee#endif
087e1372ab71eb8a49fbb5619711cfbb79f695fctomee}
087e1372ab71eb8a49fbb5619711cfbb79f695fctomee
087e1372ab71eb8a49fbb5619711cfbb79f695fctomee#define NCHARS 50
087e1372ab71eb8a49fbb5619711cfbb79f695fctomee/*
087e1372ab71eb8a49fbb5619711cfbb79f695fctomee * Print the distribution header with the given bucket label. The header is
087e1372ab71eb8a49fbb5619711cfbb79f695fctomee * printed on a single line, and the label is assumed to fit within the given
087e1372ab71eb8a49fbb5619711cfbb79f695fctomee * width (number of characters). The default label width when unspecified (0)
087e1372ab71eb8a49fbb5619711cfbb79f695fctomee * is eleven characters. Optionally, a label other than "count" may be specified
087e1372ab71eb8a49fbb5619711cfbb79f695fctomee * for the bucket counts.
087e1372ab71eb8a49fbb5619711cfbb79f695fctomee */
087e1372ab71eb8a49fbb5619711cfbb79f695fctomeevoid
087e1372ab71eb8a49fbb5619711cfbb79f695fctomeedist_print_header(const char *label, int width, const char *count)
087e1372ab71eb8a49fbb5619711cfbb79f695fctomee{
087e1372ab71eb8a49fbb5619711cfbb79f695fctomee int n;
087e1372ab71eb8a49fbb5619711cfbb79f695fctomee const char *dist = " Distribution ";
087e1372ab71eb8a49fbb5619711cfbb79f695fctomee char dashes[NCHARS + 1];
087e1372ab71eb8a49fbb5619711cfbb79f695fctomee
087e1372ab71eb8a49fbb5619711cfbb79f695fctomee if (width == 0)
087e1372ab71eb8a49fbb5619711cfbb79f695fctomee width = 11;
087e1372ab71eb8a49fbb5619711cfbb79f695fctomee
087e1372ab71eb8a49fbb5619711cfbb79f695fctomee if (count == NULL)
087e1372ab71eb8a49fbb5619711cfbb79f695fctomee count = "count";
087e1372ab71eb8a49fbb5619711cfbb79f695fctomee
087e1372ab71eb8a49fbb5619711cfbb79f695fctomee n = (NCHARS - strlen(dist)) / 2;
087e1372ab71eb8a49fbb5619711cfbb79f695fctomee (void) memset(dashes, '-', n);
087e1372ab71eb8a49fbb5619711cfbb79f695fctomee dashes[n] = '\0';
087e1372ab71eb8a49fbb5619711cfbb79f695fctomee
087e1372ab71eb8a49fbb5619711cfbb79f695fctomee mdb_printf("%*s %s%s%s %s\n", width, label, dashes, dist, dashes,
087e1372ab71eb8a49fbb5619711cfbb79f695fctomee count);
087e1372ab71eb8a49fbb5619711cfbb79f695fctomee}
087e1372ab71eb8a49fbb5619711cfbb79f695fctomee
087e1372ab71eb8a49fbb5619711cfbb79f695fctomee/*
087e1372ab71eb8a49fbb5619711cfbb79f695fctomee * Print one distribution bucket whose range is from distarray[i] inclusive to
087e1372ab71eb8a49fbb5619711cfbb79f695fctomee * distarray[i + 1] exclusive by totalling counts in that index range. The
087e1372ab71eb8a49fbb5619711cfbb79f695fctomee * given total is assumed to be the sum of all elements in the counts array.
087e1372ab71eb8a49fbb5619711cfbb79f695fctomee * Each bucket is labeled by its range in the form "first-last" (omit "-last" if
087e1372ab71eb8a49fbb5619711cfbb79f695fctomee * the range is a single value) where first and last are integers, and last is
087e1372ab71eb8a49fbb5619711cfbb79f695fctomee * one less than the first value of the next bucket range. The bucket label is
087e1372ab71eb8a49fbb5619711cfbb79f695fctomee * assumed to fit within the given width (number of characters), which should
087e1372ab71eb8a49fbb5619711cfbb79f695fctomee * match the width value passed to dist_print_header(). The default width when
087e1372ab71eb8a49fbb5619711cfbb79f695fctomee * unspecified (0) is eleven characters.
087e1372ab71eb8a49fbb5619711cfbb79f695fctomee */
087e1372ab71eb8a49fbb5619711cfbb79f695fctomeevoid
087e1372ab71eb8a49fbb5619711cfbb79f695fctomeedist_print_bucket(const int *distarray, int i, const uint_t *counts,
087e1372ab71eb8a49fbb5619711cfbb79f695fctomee uint64_t total, int width)
087e1372ab71eb8a49fbb5619711cfbb79f695fctomee{
087e1372ab71eb8a49fbb5619711cfbb79f695fctomee int b; /* bucket range index */
087e1372ab71eb8a49fbb5619711cfbb79f695fctomee int bb = distarray[i]; /* bucket begin */
087e1372ab71eb8a49fbb5619711cfbb79f695fctomee int be = distarray[i + 1] - 1; /* bucket end */
087e1372ab71eb8a49fbb5619711cfbb79f695fctomee uint64_t count = 0; /* bucket value */
087e1372ab71eb8a49fbb5619711cfbb79f695fctomee
087e1372ab71eb8a49fbb5619711cfbb79f695fctomee int nats;
087e1372ab71eb8a49fbb5619711cfbb79f695fctomee char ats[NCHARS + 1], spaces[NCHARS + 1];
087e1372ab71eb8a49fbb5619711cfbb79f695fctomee char range[40];
087e1372ab71eb8a49fbb5619711cfbb79f695fctomee
087e1372ab71eb8a49fbb5619711cfbb79f695fctomee if (width == 0)
087e1372ab71eb8a49fbb5619711cfbb79f695fctomee width = 11;
087e1372ab71eb8a49fbb5619711cfbb79f695fctomee
087e1372ab71eb8a49fbb5619711cfbb79f695fctomee if (total == 0)
087e1372ab71eb8a49fbb5619711cfbb79f695fctomee total = 1; /* avoid divide-by-zero */
087e1372ab71eb8a49fbb5619711cfbb79f695fctomee
087e1372ab71eb8a49fbb5619711cfbb79f695fctomee for (b = bb; b <= be; b++)
087e1372ab71eb8a49fbb5619711cfbb79f695fctomee count += counts[b];
087e1372ab71eb8a49fbb5619711cfbb79f695fctomee
087e1372ab71eb8a49fbb5619711cfbb79f695fctomee nats = (NCHARS * count) / total;
087e1372ab71eb8a49fbb5619711cfbb79f695fctomee (void) memset(ats, '@', nats);
087e1372ab71eb8a49fbb5619711cfbb79f695fctomee ats[nats] = 0;
087e1372ab71eb8a49fbb5619711cfbb79f695fctomee (void) memset(spaces, ' ', NCHARS - nats);
087e1372ab71eb8a49fbb5619711cfbb79f695fctomee spaces[NCHARS - nats] = 0;
087e1372ab71eb8a49fbb5619711cfbb79f695fctomee
087e1372ab71eb8a49fbb5619711cfbb79f695fctomee if (bb == be)
087e1372ab71eb8a49fbb5619711cfbb79f695fctomee (void) mdb_snprintf(range, sizeof (range), "%d", bb);
087e1372ab71eb8a49fbb5619711cfbb79f695fctomee else
087e1372ab71eb8a49fbb5619711cfbb79f695fctomee (void) mdb_snprintf(range, sizeof (range), "%d-%d", bb, be);
087e1372ab71eb8a49fbb5619711cfbb79f695fctomee mdb_printf("%*s |%s%s %lld\n", width, range, ats, spaces, count);
087e1372ab71eb8a49fbb5619711cfbb79f695fctomee}
087e1372ab71eb8a49fbb5619711cfbb79f695fctomee#undef NCHARS