1*ae94d716SRichard Lowe /*
2*ae94d716SRichard Lowe  * This file and its contents are supplied under the terms of the
3*ae94d716SRichard Lowe  * Common Development and Distribution License ("CDDL"), version 1.0.
4*ae94d716SRichard Lowe  * You may only use this file in accordance with the terms of version
5*ae94d716SRichard Lowe  * 1.0 of the CDDL.
6*ae94d716SRichard Lowe  *
7*ae94d716SRichard Lowe  * A full copy of the text of the CDDL should have accompanied this
8*ae94d716SRichard Lowe  * source.  A copy of the CDDL is also available via the Internet at
9*ae94d716SRichard Lowe  * http://www.illumos.org/license/CDDL.
10*ae94d716SRichard Lowe  */
11*ae94d716SRichard Lowe 
12*ae94d716SRichard Lowe /*
13*ae94d716SRichard Lowe  * Copyright 2011, Richard Lowe
14*ae94d716SRichard Lowe  */
15*ae94d716SRichard Lowe 
16*ae94d716SRichard Lowe package org.opensolaris.os.dtrace;
17*ae94d716SRichard Lowe 
18*ae94d716SRichard Lowe import java.beans.*;
19*ae94d716SRichard Lowe import java.io.*;
20*ae94d716SRichard Lowe import java.util.*;
21*ae94d716SRichard Lowe 
22*ae94d716SRichard Lowe /**
23*ae94d716SRichard Lowe  * A log/linear distribution aggregated by the DTrace {@code llquantize()}
24*ae94d716SRichard Lowe  * action.  Aggregated values are aggregated logarithmicly by order of
25*ae94d716SRichard Lowe  * magnitude (between the low and high magnitude arguments of the {@code
26*ae94d716SRichard Lowe  * llquantize()} action, but linearly within each order of magnitude bounded
27*ae94d716SRichard Lowe  * by the step parameter of the {@code llquantize()} action.
28*ae94d716SRichard Lowe  *
29*ae94d716SRichard Lowe  * @see LinearDistribution
30*ae94d716SRichard Lowe  * @see LogLinearDistribution
31*ae94d716SRichard Lowe  * @see Aggregation
32*ae94d716SRichard Lowe  */
33*ae94d716SRichard Lowe public final class LogLinearDistribution extends Distribution
34*ae94d716SRichard Lowe     implements Serializable, Comparable <LogLinearDistribution>
35*ae94d716SRichard Lowe {
36*ae94d716SRichard Lowe     static final long serialVersionUID = 6271156690706677711L;
37*ae94d716SRichard Lowe 
38*ae94d716SRichard Lowe     static final long UINT16_MAX = 0xffff;
39*ae94d716SRichard Lowe 
40*ae94d716SRichard Lowe     static final long FACTOR_SHIFT = 48;
41*ae94d716SRichard Lowe     static final long LOW_SHIFT = 32;
42*ae94d716SRichard Lowe     static final long HIGH_SHIFT = 16;
43*ae94d716SRichard Lowe     static final long NSTEP_SHIFT = 0;
44*ae94d716SRichard Lowe 
unpack(long x, long thing)45*ae94d716SRichard Lowe     private static long unpack(long x, long thing) {
46*ae94d716SRichard Lowe         return (x & (UINT16_MAX << thing)) >> thing;
47*ae94d716SRichard Lowe     }
48*ae94d716SRichard Lowe 
49*ae94d716SRichard Lowe     /** @serial */
50*ae94d716SRichard Lowe     private long encValue;
51*ae94d716SRichard Lowe     /** @serial */
52*ae94d716SRichard Lowe     private long base;
53*ae94d716SRichard Lowe 
54*ae94d716SRichard Lowe     static {
55*ae94d716SRichard Lowe         try {
56*ae94d716SRichard Lowe             BeanInfo info = Introspector.getBeanInfo(
57*ae94d716SRichard Lowe                 LogLinearDistribution.class);
58*ae94d716SRichard Lowe             PersistenceDelegate persistenceDelegate =
59*ae94d716SRichard Lowe               new DefaultPersistenceDelegate(
60*ae94d716SRichard Lowe                   new String[] { "encValue", "base", "buckets" });
61*ae94d716SRichard Lowe             BeanDescriptor d = info.getBeanDescriptor();
62*ae94d716SRichard Lowe             d.setValue("persistenceDelegate", persistenceDelegate);
63*ae94d716SRichard Lowe         } catch (IntrospectionException e) {
64*ae94d716SRichard Lowe             System.out.println(e);
65*ae94d716SRichard Lowe         }
66*ae94d716SRichard Lowe     }
67*ae94d716SRichard Lowe 
68*ae94d716SRichard Lowe     /**
69*ae94d716SRichard Lowe      * Called by the native C code
70*ae94d716SRichard Lowe      */
LogLinearDistribution(long constant, long[] frequencies)71*ae94d716SRichard Lowe     private LogLinearDistribution(long constant, long[] frequencies) {
72*ae94d716SRichard Lowe         super(0, constant, frequencies);
73*ae94d716SRichard Lowe         encValue = constant;
74*ae94d716SRichard Lowe     }
75*ae94d716SRichard Lowe 
76*ae94d716SRichard Lowe 
77*ae94d716SRichard Lowe     /**
78*ae94d716SRichard Lowe      * Creates a log/linear distribution with the given parameters, base value
79*ae94d716SRichard Lowe      * and frequencies.  Used by XML Persistence.
80*ae94d716SRichard Lowe      *
81*ae94d716SRichard Lowe      * @param enc The encoded representation of the high, low, step and steps
82*ae94d716SRichard Lowe      *  {@code llquantize()} paramaters.
83*ae94d716SRichard Lowe      * @param base The base value of the distirbution
84*ae94d716SRichard Lowe      * @param frequencies list of frequencies in each bucket range
85*ae94d716SRichard Lowe      */
LogLinearDistribution(long enc, long base, List<Bucket> frequencies)86*ae94d716SRichard Lowe     public LogLinearDistribution(long enc, long base,
87*ae94d716SRichard Lowe         List<Bucket> frequencies) {
88*ae94d716SRichard Lowe         super(frequencies);
89*ae94d716SRichard Lowe 
90*ae94d716SRichard Lowe         encValue = enc;
91*ae94d716SRichard Lowe         base = base;
92*ae94d716SRichard Lowe 
93*ae94d716SRichard Lowe         initialize();
94*ae94d716SRichard Lowe     }
95*ae94d716SRichard Lowe 
96*ae94d716SRichard Lowe     /**
97*ae94d716SRichard Lowe      * Creates a log/linear distribution with the given parameters, base
98*ae94d716SRichard Lowe      * values and frequencies.
99*ae94d716SRichard Lowe      *
100*ae94d716SRichard Lowe      * @param scaleFactor factor
101*ae94d716SRichard Lowe      * @param lowMagnitude the low magnitude
102*ae94d716SRichard Lowe      * @param highMagnitude the high magnitude
103*ae94d716SRichard Lowe      * @param bucketSteps number of linear steps per magnitude
104*ae94d716SRichard Lowe      * @param baseVal basue value
105*ae94d716SRichard Lowe      * @param frequencies list of frequencies in each bucket range
106*ae94d716SRichard Lowe      */
LogLinearDistribution(long scaleFactor, long lowMagnitude, long highMagnitude, long bucketSteps, long baseVal, List<Bucket> frequencies)107*ae94d716SRichard Lowe     public LogLinearDistribution(long scaleFactor, long lowMagnitude,
108*ae94d716SRichard Lowe         long highMagnitude, long bucketSteps, long baseVal,
109*ae94d716SRichard Lowe         List<Bucket> frequencies) {
110*ae94d716SRichard Lowe 
111*ae94d716SRichard Lowe         super(frequencies);
112*ae94d716SRichard Lowe 
113*ae94d716SRichard Lowe         encValue = (scaleFactor << FACTOR_SHIFT) | (lowMagnitude << LOW_SHIFT) |
114*ae94d716SRichard Lowe           (highMagnitude << HIGH_SHIFT) | (bucketSteps << NSTEP_SHIFT);
115*ae94d716SRichard Lowe         base = baseVal;
116*ae94d716SRichard Lowe 
117*ae94d716SRichard Lowe         initialize();
118*ae94d716SRichard Lowe     }
119*ae94d716SRichard Lowe 
120*ae94d716SRichard Lowe     private long[][] rangeCache = null;
121*ae94d716SRichard Lowe 
fillRangeCache(long constant, int len)122*ae94d716SRichard Lowe     private void fillRangeCache(long constant, int len) {
123*ae94d716SRichard Lowe         long value = 1;
124*ae94d716SRichard Lowe         long next, step;
125*ae94d716SRichard Lowe         long low, high, nsteps, factor;
126*ae94d716SRichard Lowe         int order, bucket = 0;
127*ae94d716SRichard Lowe 
128*ae94d716SRichard Lowe         low = unpack(constant, LOW_SHIFT);
129*ae94d716SRichard Lowe         high = unpack(constant, HIGH_SHIFT);
130*ae94d716SRichard Lowe         nsteps = unpack(constant, NSTEP_SHIFT);
131*ae94d716SRichard Lowe         factor = unpack(constant, FACTOR_SHIFT);
132*ae94d716SRichard Lowe 
133*ae94d716SRichard Lowe         if (rangeCache == null)
134*ae94d716SRichard Lowe             rangeCache = new long[len][2];
135*ae94d716SRichard Lowe 
136*ae94d716SRichard Lowe         for (order = 0; order < low; order++)
137*ae94d716SRichard Lowe             value *= factor;
138*ae94d716SRichard Lowe 
139*ae94d716SRichard Lowe         base = value;
140*ae94d716SRichard Lowe 
141*ae94d716SRichard Lowe         rangeCache[bucket][0] = Long.MIN_VALUE;
142*ae94d716SRichard Lowe         rangeCache[bucket][1] = value - 1;
143*ae94d716SRichard Lowe         bucket++;
144*ae94d716SRichard Lowe 
145*ae94d716SRichard Lowe         next = value * factor;
146*ae94d716SRichard Lowe         step = (next > nsteps) ? (next / nsteps) : 1;
147*ae94d716SRichard Lowe 
148*ae94d716SRichard Lowe         while (order <= high) {
149*ae94d716SRichard Lowe             rangeCache[bucket][0] = value;
150*ae94d716SRichard Lowe             rangeCache[bucket][1] = value + step - 1;
151*ae94d716SRichard Lowe             bucket++;
152*ae94d716SRichard Lowe 
153*ae94d716SRichard Lowe             if ((value += step) != next)
154*ae94d716SRichard Lowe                 continue;
155*ae94d716SRichard Lowe 
156*ae94d716SRichard Lowe             next = value * factor;
157*ae94d716SRichard Lowe             step = (next > nsteps) ? (next / nsteps) : 1;
158*ae94d716SRichard Lowe             order++;
159*ae94d716SRichard Lowe         }
160*ae94d716SRichard Lowe 
161*ae94d716SRichard Lowe         rangeCache[bucket][0] = value;
162*ae94d716SRichard Lowe         rangeCache[bucket][1] = Long.MAX_VALUE;
163*ae94d716SRichard Lowe     }
164*ae94d716SRichard Lowe 
165*ae94d716SRichard Lowe     /**
166*ae94d716SRichard Lowe      * Gets a two element array: the first element is the range minimum
167*ae94d716SRichard Lowe      * (inclusive), the second element is the range maximum (inclusive).
168*ae94d716SRichard Lowe      */
169*ae94d716SRichard Lowe     @Override
getBucketRange(int i, int len, long base, long constant)170*ae94d716SRichard Lowe     long[] getBucketRange(int i, int len, long base, long constant) {
171*ae94d716SRichard Lowe         if (rangeCache == null)
172*ae94d716SRichard Lowe             fillRangeCache(constant, len);
173*ae94d716SRichard Lowe 
174*ae94d716SRichard Lowe         return rangeCache[i];
175*ae94d716SRichard Lowe     }
176*ae94d716SRichard Lowe 
177*ae94d716SRichard Lowe     @Override
getBucketRange(int i, int len)178*ae94d716SRichard Lowe     long[] getBucketRange(int i, int len) {
179*ae94d716SRichard Lowe         return getBucketRange(i, len, 0, encValue);
180*ae94d716SRichard Lowe     }
181*ae94d716SRichard Lowe 
getValue()182*ae94d716SRichard Lowe     public Number getValue() {
183*ae94d716SRichard Lowe         double total = 0;
184*ae94d716SRichard Lowe 
185*ae94d716SRichard Lowe         List<Distribution.Bucket> buckets = getBuckets();
186*ae94d716SRichard Lowe         for (Distribution.Bucket bucket : buckets)
187*ae94d716SRichard Lowe             total += ((double)bucket.getFrequency() * (double)bucket.getMin());
188*ae94d716SRichard Lowe 
189*ae94d716SRichard Lowe         return (new Double(total));
190*ae94d716SRichard Lowe     }
191*ae94d716SRichard Lowe 
getZeroBucketValue()192*ae94d716SRichard Lowe     private long getZeroBucketValue() {
193*ae94d716SRichard Lowe         for (Distribution.Bucket b : this) {
194*ae94d716SRichard Lowe             if (b.getMin() == 0) {
195*ae94d716SRichard Lowe                 return b.getFrequency();
196*ae94d716SRichard Lowe             }
197*ae94d716SRichard Lowe         }
198*ae94d716SRichard Lowe         return 0;
199*ae94d716SRichard Lowe     }
200*ae94d716SRichard Lowe 
201*ae94d716SRichard Lowe     /**
202*ae94d716SRichard Lowe      * Compares the {@code double} values of {@link #getValue()} for overall
203*ae94d716SRichard Lowe      * magnitude, and if those are equal, compares frequencies at zero if the
204*ae94d716SRichard Lowe      * distrubions includea bucket whose range has a minimum of zero.
205*ae94d716SRichard Lowe      */
compareTo(LogLinearDistribution d)206*ae94d716SRichard Lowe     public int compareTo(LogLinearDistribution d) {
207*ae94d716SRichard Lowe         Number v1 = getValue();
208*ae94d716SRichard Lowe         Number v2 = getValue();
209*ae94d716SRichard Lowe         double d1 = v1.doubleValue();
210*ae94d716SRichard Lowe         double d2 = v2.doubleValue();
211*ae94d716SRichard Lowe         int cmp = (d1 < d2 ? -1 : (d1 > d2 ? 1 : 0));
212*ae94d716SRichard Lowe 
213*ae94d716SRichard Lowe         if (cmp == 0) {
214*ae94d716SRichard Lowe             long z1 = getZeroBucketValue();
215*ae94d716SRichard Lowe             long z2 = d.getZeroBucketValue();
216*ae94d716SRichard Lowe             cmp = (z1 < z2 ? -1 : (z1 > z2 ? 1 : 0));
217*ae94d716SRichard Lowe         }
218*ae94d716SRichard Lowe         return (cmp);
219*ae94d716SRichard Lowe     }
220*ae94d716SRichard Lowe 
getBase()221*ae94d716SRichard Lowe     public long getBase() {
222*ae94d716SRichard Lowe         return base;
223*ae94d716SRichard Lowe     }
224*ae94d716SRichard Lowe 
getEncValue()225*ae94d716SRichard Lowe     public long getEncValue() {
226*ae94d716SRichard Lowe         return encValue;
227*ae94d716SRichard Lowe     }
228*ae94d716SRichard Lowe 
readObject(ObjectInputStream s)229*ae94d716SRichard Lowe     private void readObject(ObjectInputStream s)
230*ae94d716SRichard Lowe         throws IOException, ClassNotFoundException {
231*ae94d716SRichard Lowe         s.defaultReadObject();
232*ae94d716SRichard Lowe         try {
233*ae94d716SRichard Lowe             initialize();
234*ae94d716SRichard Lowe         } catch (Exception e) {
235*ae94d716SRichard Lowe             InvalidObjectException x = new InvalidObjectException(
236*ae94d716SRichard Lowe                 e.getMessage());
237*ae94d716SRichard Lowe             x.initCause(e);
238*ae94d716SRichard Lowe             throw x;
239*ae94d716SRichard Lowe         }
240*ae94d716SRichard Lowe     }
241*ae94d716SRichard Lowe }
242