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