xref: /titanic_50/usr/src/cmd/mdb/common/modules/genunix/dist.c (revision 087e1372ab71eb8a49fbb5619711cfbb79f695fc)
1*087e1372Stomee /*
2*087e1372Stomee  * CDDL HEADER START
3*087e1372Stomee  *
4*087e1372Stomee  * The contents of this file are subject to the terms of the
5*087e1372Stomee  * Common Development and Distribution License (the "License").
6*087e1372Stomee  * You may not use this file except in compliance with the License.
7*087e1372Stomee  *
8*087e1372Stomee  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*087e1372Stomee  * or http://www.opensolaris.org/os/licensing.
10*087e1372Stomee  * See the License for the specific language governing permissions
11*087e1372Stomee  * and limitations under the License.
12*087e1372Stomee  *
13*087e1372Stomee  * When distributing Covered Code, include this CDDL HEADER in each
14*087e1372Stomee  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*087e1372Stomee  * If applicable, add the following below this CDDL HEADER, with the
16*087e1372Stomee  * fields enclosed by brackets "[]" replaced with your own identifying
17*087e1372Stomee  * information: Portions Copyright [yyyy] [name of copyright owner]
18*087e1372Stomee  *
19*087e1372Stomee  * CDDL HEADER END
20*087e1372Stomee  */
21*087e1372Stomee /*
22*087e1372Stomee  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
23*087e1372Stomee  * Use is subject to license terms.
24*087e1372Stomee  */
25*087e1372Stomee 
26*087e1372Stomee #pragma ident	"%Z%%M%	%I%	%E% SMI"
27*087e1372Stomee 
28*087e1372Stomee #include <mdb/mdb_modapi.h>
29*087e1372Stomee #ifndef	_KMDB
30*087e1372Stomee #include <math.h>
31*087e1372Stomee #endif
32*087e1372Stomee 
33*087e1372Stomee #include "dist.h"
34*087e1372Stomee 
35*087e1372Stomee /*
36*087e1372Stomee  * Divides the given range (inclusive at both endpoints) evenly into the given
37*087e1372Stomee  * number of buckets, adding one bucket at the end that is one past the end of
38*087e1372Stomee  * the range. The returned buckets will be automatically freed when the dcmd
39*087e1372Stomee  * completes or is forcibly aborted.
40*087e1372Stomee  */
41*087e1372Stomee const int *
dist_linear(int buckets,int beg,int end)42*087e1372Stomee dist_linear(int buckets, int beg, int end)
43*087e1372Stomee {
44*087e1372Stomee 	int *out = mdb_alloc((buckets + 1) * sizeof (*out), UM_SLEEP | UM_GC);
45*087e1372Stomee 	int pos;
46*087e1372Stomee 	int dist = end - beg + 1;
47*087e1372Stomee 
48*087e1372Stomee 	for (pos = 0; pos < buckets; pos++)
49*087e1372Stomee 		out[pos] = beg + (pos * dist)/buckets;
50*087e1372Stomee 	out[buckets] = end + 1;
51*087e1372Stomee 
52*087e1372Stomee 	return (out);
53*087e1372Stomee }
54*087e1372Stomee 
55*087e1372Stomee /*
56*087e1372Stomee  * We want the bins to be a constant ratio:
57*087e1372Stomee  *
58*087e1372Stomee  *	b_0	  = beg;
59*087e1372Stomee  *	b_idx	  = b_{idx-1} * r;
60*087e1372Stomee  *	b_buckets = end + 1;
61*087e1372Stomee  *
62*087e1372Stomee  * That is:
63*087e1372Stomee  *
64*087e1372Stomee  *	       buckets
65*087e1372Stomee  *	beg * r        = end
66*087e1372Stomee  *
67*087e1372Stomee  * Which reduces to:
68*087e1372Stomee  *
69*087e1372Stomee  *		  buckets ___________________
70*087e1372Stomee  *	      r = -------/ ((end + 1) / beg)
71*087e1372Stomee  *
72*087e1372Stomee  *		  log ((end + 1) / beg)
73*087e1372Stomee  *	  log r = ---------------------
74*087e1372Stomee  *		         buckets
75*087e1372Stomee  *
76*087e1372Stomee  *		   (log ((end + 1) / beg)) / buckets
77*087e1372Stomee  *	      r = e
78*087e1372Stomee  */
79*087e1372Stomee /* ARGSUSED */
80*087e1372Stomee const int *
dist_geometric(int buckets,int beg,int end,int minbucketsize)81*087e1372Stomee dist_geometric(int buckets, int beg, int end, int minbucketsize)
82*087e1372Stomee {
83*087e1372Stomee #ifdef	_KMDB
84*087e1372Stomee 	return (dist_linear(buckets, beg, end));
85*087e1372Stomee #else
86*087e1372Stomee 	int *out = mdb_alloc((buckets + 1) * sizeof (*out), UM_SLEEP | UM_GC);
87*087e1372Stomee 
88*087e1372Stomee 	double r;
89*087e1372Stomee 	double b;
90*087e1372Stomee 	int idx = 0;
91*087e1372Stomee 	int last;
92*087e1372Stomee 	int begzero;
93*087e1372Stomee 
94*087e1372Stomee 	if (minbucketsize == 0)
95*087e1372Stomee 		minbucketsize = 1;
96*087e1372Stomee 
97*087e1372Stomee 	if (buckets == 1) {
98*087e1372Stomee 		out[0] = beg;
99*087e1372Stomee 		out[1] = end + 1;
100*087e1372Stomee 		return (out);
101*087e1372Stomee 	}
102*087e1372Stomee 
103*087e1372Stomee 	begzero = (beg == 0);
104*087e1372Stomee 	if (begzero)
105*087e1372Stomee 		beg = 1;
106*087e1372Stomee 
107*087e1372Stomee 	r = exp(log((double)(end + 1) / beg) / buckets);
108*087e1372Stomee 
109*087e1372Stomee 	/*
110*087e1372Stomee 	 * We've now computed r, using the previously derived formula.  We
111*087e1372Stomee 	 * now need to generate the array of bucket bounds.  There are
112*087e1372Stomee 	 * two major variables:
113*087e1372Stomee 	 *
114*087e1372Stomee 	 *	b	holds b_idx, the current index, as a double.
115*087e1372Stomee 	 *	last	holds the integer which goes into out[idx]
116*087e1372Stomee 	 *
117*087e1372Stomee 	 * Our job is to transform the smooth function b_idx, defined
118*087e1372Stomee 	 * above, into integer-sized buckets, with a specified minimum
119*087e1372Stomee 	 * bucket size.  Since b_idx is an exponentially growing function,
120*087e1372Stomee 	 * any inadequate buckets must be at the beginning.  To deal
121*087e1372Stomee 	 * with this, we make buckets of minimum size until b catches up
122*087e1372Stomee 	 * with last.
123*087e1372Stomee 	 *
124*087e1372Stomee 	 * A final wrinkle is that beg *can* be zero.  We compute r and b
125*087e1372Stomee 	 * as if beg was 1, then start last as 0.  This can lead to a bit
126*087e1372Stomee 	 * of oddness around the 0 bucket, but it's mostly reasonable.
127*087e1372Stomee 	 */
128*087e1372Stomee 
129*087e1372Stomee 	b = last = beg;
130*087e1372Stomee 	if (begzero)
131*087e1372Stomee 		last = 0;
132*087e1372Stomee 
133*087e1372Stomee 	for (idx = 0; idx < buckets; idx++) {
134*087e1372Stomee 		int next;
135*087e1372Stomee 
136*087e1372Stomee 		out[idx] = last;
137*087e1372Stomee 
138*087e1372Stomee 		b *= r;
139*087e1372Stomee 		next = (int)b;
140*087e1372Stomee 
141*087e1372Stomee 		if (next > last + minbucketsize - 1)
142*087e1372Stomee 			last = next;
143*087e1372Stomee 		else
144*087e1372Stomee 			last += minbucketsize;
145*087e1372Stomee 	}
146*087e1372Stomee 	out[buckets] = end + 1;
147*087e1372Stomee 
148*087e1372Stomee 	return (out);
149*087e1372Stomee #endif
150*087e1372Stomee }
151*087e1372Stomee 
152*087e1372Stomee #define	NCHARS	50
153*087e1372Stomee /*
154*087e1372Stomee  * Print the distribution header with the given bucket label. The header is
155*087e1372Stomee  * printed on a single line, and the label is assumed to fit within the given
156*087e1372Stomee  * width (number of characters). The default label width when unspecified (0)
157*087e1372Stomee  * is eleven characters. Optionally, a label other than "count" may be specified
158*087e1372Stomee  * for the bucket counts.
159*087e1372Stomee  */
160*087e1372Stomee void
dist_print_header(const char * label,int width,const char * count)161*087e1372Stomee dist_print_header(const char *label, int width, const char *count)
162*087e1372Stomee {
163*087e1372Stomee 	int n;
164*087e1372Stomee 	const char *dist = " Distribution ";
165*087e1372Stomee 	char dashes[NCHARS + 1];
166*087e1372Stomee 
167*087e1372Stomee 	if (width == 0)
168*087e1372Stomee 		width = 11;
169*087e1372Stomee 
170*087e1372Stomee 	if (count == NULL)
171*087e1372Stomee 		count = "count";
172*087e1372Stomee 
173*087e1372Stomee 	n = (NCHARS - strlen(dist)) / 2;
174*087e1372Stomee 	(void) memset(dashes, '-', n);
175*087e1372Stomee 	dashes[n] = '\0';
176*087e1372Stomee 
177*087e1372Stomee 	mdb_printf("%*s  %s%s%s %s\n", width, label, dashes, dist, dashes,
178*087e1372Stomee 	    count);
179*087e1372Stomee }
180*087e1372Stomee 
181*087e1372Stomee /*
182*087e1372Stomee  * Print one distribution bucket whose range is from distarray[i] inclusive to
183*087e1372Stomee  * distarray[i + 1] exclusive by totalling counts in that index range.  The
184*087e1372Stomee  * given total is assumed to be the sum of all elements in the counts array.
185*087e1372Stomee  * Each bucket is labeled by its range in the form "first-last" (omit "-last" if
186*087e1372Stomee  * the range is a single value) where first and last are integers, and last is
187*087e1372Stomee  * one less than the first value of the next bucket range. The bucket label is
188*087e1372Stomee  * assumed to fit within the given width (number of characters), which should
189*087e1372Stomee  * match the width value passed to dist_print_header(). The default width when
190*087e1372Stomee  * unspecified (0) is eleven characters.
191*087e1372Stomee  */
192*087e1372Stomee void
dist_print_bucket(const int * distarray,int i,const uint_t * counts,uint64_t total,int width)193*087e1372Stomee dist_print_bucket(const int *distarray, int i, const uint_t *counts,
194*087e1372Stomee     uint64_t total, int width)
195*087e1372Stomee {
196*087e1372Stomee 	int b;				/* bucket range index */
197*087e1372Stomee 	int bb = distarray[i];		/* bucket begin */
198*087e1372Stomee 	int be = distarray[i + 1] - 1;	/* bucket end */
199*087e1372Stomee 	uint64_t count = 0;		/* bucket value */
200*087e1372Stomee 
201*087e1372Stomee 	int nats;
202*087e1372Stomee 	char ats[NCHARS + 1], spaces[NCHARS + 1];
203*087e1372Stomee 	char range[40];
204*087e1372Stomee 
205*087e1372Stomee 	if (width == 0)
206*087e1372Stomee 		width = 11;
207*087e1372Stomee 
208*087e1372Stomee 	if (total == 0)
209*087e1372Stomee 		total = 1;		/* avoid divide-by-zero */
210*087e1372Stomee 
211*087e1372Stomee 	for (b = bb; b <= be; b++)
212*087e1372Stomee 		count += counts[b];
213*087e1372Stomee 
214*087e1372Stomee 	nats = (NCHARS * count) / total;
215*087e1372Stomee 	(void) memset(ats, '@', nats);
216*087e1372Stomee 	ats[nats] = 0;
217*087e1372Stomee 	(void) memset(spaces, ' ', NCHARS - nats);
218*087e1372Stomee 	spaces[NCHARS - nats] = 0;
219*087e1372Stomee 
220*087e1372Stomee 	if (bb == be)
221*087e1372Stomee 		(void) mdb_snprintf(range, sizeof (range), "%d", bb);
222*087e1372Stomee 	else
223*087e1372Stomee 		(void) mdb_snprintf(range, sizeof (range), "%d-%d", bb, be);
224*087e1372Stomee 	mdb_printf("%*s |%s%s %lld\n", width, range, ats, spaces, count);
225*087e1372Stomee }
226*087e1372Stomee #undef NCHARS
227