1*e77b06d2Stomee /*
2*e77b06d2Stomee  * CDDL HEADER START
3*e77b06d2Stomee  *
4*e77b06d2Stomee  * The contents of this file are subject to the terms of the
5*e77b06d2Stomee  * Common Development and Distribution License (the "License").
6*e77b06d2Stomee  * You may not use this file except in compliance with the License.
7*e77b06d2Stomee  *
8*e77b06d2Stomee  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*e77b06d2Stomee  * or http://www.opensolaris.org/os/licensing.
10*e77b06d2Stomee  * See the License for the specific language governing permissions
11*e77b06d2Stomee  * and limitations under the License.
12*e77b06d2Stomee  *
13*e77b06d2Stomee  * When distributing Covered Code, include this CDDL HEADER in each
14*e77b06d2Stomee  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*e77b06d2Stomee  * If applicable, add the following below this CDDL HEADER, with the
16*e77b06d2Stomee  * fields enclosed by brackets "[]" replaced with your own identifying
17*e77b06d2Stomee  * information: Portions Copyright [yyyy] [name of copyright owner]
18*e77b06d2Stomee  *
19*e77b06d2Stomee  * CDDL HEADER END
20*e77b06d2Stomee  */
21*e77b06d2Stomee 
22*e77b06d2Stomee /*
23*e77b06d2Stomee  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
24*e77b06d2Stomee  * Use is subject to license terms.
25*e77b06d2Stomee  *
26*e77b06d2Stomee  * ident	"%Z%%M%	%I%	%E% SMI"
27*e77b06d2Stomee  */
28*e77b06d2Stomee package org.opensolaris.os.dtrace;
29*e77b06d2Stomee 
30*e77b06d2Stomee import java.io.*;
31*e77b06d2Stomee import java.beans.*;
32*e77b06d2Stomee import java.math.BigInteger;
33*e77b06d2Stomee 
34*e77b06d2Stomee /**
35*e77b06d2Stomee  * A {@code long} value aggregated by the DTrace {@code stddev()} action.
36*e77b06d2Stomee  * <p>
37*e77b06d2Stomee  * Immutable.  Supports persistence using {@link java.beans.XMLEncoder}.
38*e77b06d2Stomee  *
39*e77b06d2Stomee  * @see Aggregation
40*e77b06d2Stomee  * @author Tom Erickson
41*e77b06d2Stomee  */
42*e77b06d2Stomee public final class StddevValue extends AbstractAggregationValue {
43*e77b06d2Stomee     static final long serialVersionUID = 6409878160513885375L;
44*e77b06d2Stomee 
45*e77b06d2Stomee     /** @serial */
46*e77b06d2Stomee     private final long total;
47*e77b06d2Stomee     /** @serial */
48*e77b06d2Stomee     private final long count;
49*e77b06d2Stomee     /** @serial */
50*e77b06d2Stomee     private final BigInteger totalSquares;
51*e77b06d2Stomee 
52*e77b06d2Stomee     static {
53*e77b06d2Stomee 	try {
54*e77b06d2Stomee 	    BeanInfo info = Introspector.getBeanInfo(StddevValue.class);
55*e77b06d2Stomee 	    PersistenceDelegate persistenceDelegate =
56*e77b06d2Stomee 		    new DefaultPersistenceDelegate(
57*e77b06d2Stomee 		    new String[] {"value", "total", "count", "totalSquares"})
58*e77b06d2Stomee 	    {
59*e77b06d2Stomee 		@Override
60*e77b06d2Stomee 		protected Expression
61*e77b06d2Stomee 		instantiate(Object oldInstance, Encoder out)
62*e77b06d2Stomee 		{
63*e77b06d2Stomee 		    StddevValue stddev = (StddevValue)oldInstance;
64*e77b06d2Stomee 		    return new Expression(oldInstance, oldInstance.getClass(),
65*e77b06d2Stomee 			    "new", new Object[] {
66*e77b06d2Stomee 			    stddev.getValue().longValue(),
67*e77b06d2Stomee 			    stddev.getTotal(), stddev.getCount(),
68*e77b06d2Stomee 			    stddev.getTotalSquares().toString() });
69*e77b06d2Stomee 		}
70*e77b06d2Stomee 	    };
71*e77b06d2Stomee 	    BeanDescriptor d = info.getBeanDescriptor();
72*e77b06d2Stomee 	    d.setValue("persistenceDelegate", persistenceDelegate);
73*e77b06d2Stomee 	} catch (IntrospectionException e) {
74*e77b06d2Stomee 	    System.out.println(e);
75*e77b06d2Stomee 	}
76*e77b06d2Stomee     }
77*e77b06d2Stomee 
78*e77b06d2Stomee     // ported from dt_sqrt_128 in lib/libdtrace/common/dt_consume.c
79*e77b06d2Stomee     private static long
squareRoot128(BigInteger n)80*e77b06d2Stomee     squareRoot128(BigInteger n)
81*e77b06d2Stomee     {
82*e77b06d2Stomee 	long result = 0;
83*e77b06d2Stomee 	BigInteger diff = BigInteger.valueOf(0);
84*e77b06d2Stomee 	BigInteger nextTry = BigInteger.valueOf(0);
85*e77b06d2Stomee 	int bitPairs = (n.bitLength() / 2);
86*e77b06d2Stomee 	int bitPos = (bitPairs * 2) + 1;
87*e77b06d2Stomee 	int nextTwoBits;
88*e77b06d2Stomee 
89*e77b06d2Stomee 	for (int i = 0; i <= bitPairs; i++) {
90*e77b06d2Stomee 	    // Bring down the next pair of bits.
91*e77b06d2Stomee 	    nextTwoBits = n.testBit(bitPos)
92*e77b06d2Stomee 		    ? (n.testBit(bitPos - 1) ? 0x3 : 0x2)
93*e77b06d2Stomee 		    : (n.testBit(bitPos - 1) ? 0x1 : 0x0);
94*e77b06d2Stomee 
95*e77b06d2Stomee 	    diff = diff.shiftLeft(2);
96*e77b06d2Stomee 	    diff = diff.add(BigInteger.valueOf(nextTwoBits));
97*e77b06d2Stomee 
98*e77b06d2Stomee 	    // nextTry = R << 2 + 1
99*e77b06d2Stomee 	    nextTry = BigInteger.valueOf(result);
100*e77b06d2Stomee 	    nextTry = nextTry.shiftLeft(2);
101*e77b06d2Stomee 	    nextTry = nextTry.setBit(0);
102*e77b06d2Stomee 
103*e77b06d2Stomee 	    result <<= 1;
104*e77b06d2Stomee 	    if (nextTry.compareTo(diff) <= 0) {
105*e77b06d2Stomee 		diff = diff.subtract(nextTry);
106*e77b06d2Stomee 		result++;
107*e77b06d2Stomee 	    }
108*e77b06d2Stomee 
109*e77b06d2Stomee 	    bitPos -= 2;
110*e77b06d2Stomee 	}
111*e77b06d2Stomee 
112*e77b06d2Stomee 	return (result);
113*e77b06d2Stomee     }
114*e77b06d2Stomee 
115*e77b06d2Stomee     // ported from dt_stddev in lib/libdtrace/common/dt_consume.c
116*e77b06d2Stomee     private static long
standardDeviation(long stddevCount, long stddevTotal, BigInteger stddevTotalSquares)117*e77b06d2Stomee     standardDeviation(long stddevCount, long stddevTotal,
118*e77b06d2Stomee 	    BigInteger stddevTotalSquares)
119*e77b06d2Stomee     {
120*e77b06d2Stomee 	BigInteger averageOfSquares = stddevTotalSquares.divide(
121*e77b06d2Stomee 		BigInteger.valueOf(stddevCount));
122*e77b06d2Stomee 	long avg = (stddevTotal / stddevCount);
123*e77b06d2Stomee 	if (avg < 0) {
124*e77b06d2Stomee 	    avg = -avg;
125*e77b06d2Stomee 	}
126*e77b06d2Stomee 	BigInteger squareOfAverage = BigInteger.valueOf(avg);
127*e77b06d2Stomee 	squareOfAverage = squareOfAverage.pow(2);
128*e77b06d2Stomee 	BigInteger stddev = averageOfSquares.subtract(squareOfAverage);
129*e77b06d2Stomee 	return squareRoot128(stddev);
130*e77b06d2Stomee     }
131*e77b06d2Stomee 
132*e77b06d2Stomee     /*
133*e77b06d2Stomee      * Called by native code.
134*e77b06d2Stomee      */
135*e77b06d2Stomee     private
StddevValue(long stddevCount, long stddevTotal, BigInteger stddevTotalSquares)136*e77b06d2Stomee     StddevValue(long stddevCount, long stddevTotal,
137*e77b06d2Stomee 	    BigInteger stddevTotalSquares)
138*e77b06d2Stomee     {
139*e77b06d2Stomee 	super(stddevCount == 0 ? 0 : standardDeviation(stddevCount,
140*e77b06d2Stomee 		stddevTotal, stddevTotalSquares));
141*e77b06d2Stomee 	total = stddevTotal;
142*e77b06d2Stomee 	count = stddevCount;
143*e77b06d2Stomee 	totalSquares = stddevTotalSquares;
144*e77b06d2Stomee 	if (totalSquares == null) {
145*e77b06d2Stomee 	    throw new NullPointerException("totalSquares is null");
146*e77b06d2Stomee 	}
147*e77b06d2Stomee 	if (count < 0) {
148*e77b06d2Stomee 	    throw new IllegalArgumentException("count is negative");
149*e77b06d2Stomee 	}
150*e77b06d2Stomee     }
151*e77b06d2Stomee 
152*e77b06d2Stomee     /**
153*e77b06d2Stomee      * Creates a value aggregated by the DTrace {@code stddev()} action.
154*e77b06d2Stomee      * Supports XML persistence.
155*e77b06d2Stomee      *
156*e77b06d2Stomee      * @param v standard deviation
157*e77b06d2Stomee      * @param stddevTotal sum total of all values included in the standard
158*e77b06d2Stomee      * deviation
159*e77b06d2Stomee      * @param stddevCount number of values included in the standard
160*e77b06d2Stomee      * deviation
161*e77b06d2Stomee      * @param stddevTotalSquaresString decimal string representation of
162*e77b06d2Stomee      * the 128-bit sum total of the squares of all values included in
163*e77b06d2Stomee      * the standard deviation
164*e77b06d2Stomee      * @throws IllegalArgumentException if the given count is negative
165*e77b06d2Stomee      * or if the given standard deviation is not the value expected for
166*e77b06d2Stomee      * the given total, total of squares, and count
167*e77b06d2Stomee      * @throws NumberFormatException if the given total squares is not a
168*e77b06d2Stomee      * valid integer representation
169*e77b06d2Stomee      */
170*e77b06d2Stomee     public
StddevValue(long v, long stddevTotal, long stddevCount, String stddevTotalSquaresString)171*e77b06d2Stomee     StddevValue(long v, long stddevTotal, long stddevCount,
172*e77b06d2Stomee 	    String stddevTotalSquaresString)
173*e77b06d2Stomee     {
174*e77b06d2Stomee 	super(v);
175*e77b06d2Stomee 	total = stddevTotal;
176*e77b06d2Stomee 	count = stddevCount;
177*e77b06d2Stomee 	totalSquares = new BigInteger(stddevTotalSquaresString);
178*e77b06d2Stomee 	validate();
179*e77b06d2Stomee     }
180*e77b06d2Stomee 
181*e77b06d2Stomee     private final void
validate()182*e77b06d2Stomee     validate()
183*e77b06d2Stomee     {
184*e77b06d2Stomee 	if (count < 0) {
185*e77b06d2Stomee 	    throw new IllegalArgumentException("count is negative");
186*e77b06d2Stomee 	}
187*e77b06d2Stomee 	long stddev = super.getValue().longValue();
188*e77b06d2Stomee 	if (count == 0) {
189*e77b06d2Stomee 	    if (stddev != 0) {
190*e77b06d2Stomee 		throw new IllegalArgumentException(
191*e77b06d2Stomee 			"count of values is zero, stddev is non-zero (" +
192*e77b06d2Stomee 			stddev + ")");
193*e77b06d2Stomee 	    }
194*e77b06d2Stomee 	} else {
195*e77b06d2Stomee 	    if (stddev != standardDeviation(count, total, totalSquares)) {
196*e77b06d2Stomee 		throw new IllegalArgumentException(
197*e77b06d2Stomee 			getValue().toString() + " is not the expected " +
198*e77b06d2Stomee 			"standard deviation of total " + total + ", count " +
199*e77b06d2Stomee 			count + ", and total squares " + totalSquares);
200*e77b06d2Stomee 	    }
201*e77b06d2Stomee 	}
202*e77b06d2Stomee     }
203*e77b06d2Stomee 
204*e77b06d2Stomee     // Needed to support XML persistence since XMLDecoder cannot find
205*e77b06d2Stomee     // the public method of the non-public superclass.
206*e77b06d2Stomee 
207*e77b06d2Stomee     /**
208*e77b06d2Stomee      * Gets the standard deviation of the aggregated values.
209*e77b06d2Stomee      *
210*e77b06d2Stomee      * @return standard deviation of the aggregated values
211*e77b06d2Stomee      */
212*e77b06d2Stomee     public Long
getValue()213*e77b06d2Stomee     getValue()
214*e77b06d2Stomee     {
215*e77b06d2Stomee 	return (Long)super.getValue();
216*e77b06d2Stomee     }
217*e77b06d2Stomee 
218*e77b06d2Stomee     /**
219*e77b06d2Stomee      * Gets the sum total of the aggregated values.
220*e77b06d2Stomee      *
221*e77b06d2Stomee      * @return the sum total of the aggregated values
222*e77b06d2Stomee      */
223*e77b06d2Stomee     public long
getTotal()224*e77b06d2Stomee     getTotal()
225*e77b06d2Stomee     {
226*e77b06d2Stomee 	return total;
227*e77b06d2Stomee     }
228*e77b06d2Stomee 
229*e77b06d2Stomee     /**
230*e77b06d2Stomee      * Gets the number of aggregated values included in the standard
231*e77b06d2Stomee      * deviation.
232*e77b06d2Stomee      *
233*e77b06d2Stomee      * @return the number of aggregated values included in the standard
234*e77b06d2Stomee      * deviation
235*e77b06d2Stomee      */
236*e77b06d2Stomee     public long
getCount()237*e77b06d2Stomee     getCount()
238*e77b06d2Stomee     {
239*e77b06d2Stomee 	return count;
240*e77b06d2Stomee     }
241*e77b06d2Stomee 
242*e77b06d2Stomee     /**
243*e77b06d2Stomee      * Gets the sum total of the squares of the aggregated values.
244*e77b06d2Stomee      *
245*e77b06d2Stomee      * @return the sum total of the squares of the aggregated values
246*e77b06d2Stomee      */
247*e77b06d2Stomee     public BigInteger
getTotalSquares()248*e77b06d2Stomee     getTotalSquares()
249*e77b06d2Stomee     {
250*e77b06d2Stomee 	return totalSquares;
251*e77b06d2Stomee     }
252*e77b06d2Stomee 
253*e77b06d2Stomee     private void
readObject(ObjectInputStream s)254*e77b06d2Stomee     readObject(ObjectInputStream s)
255*e77b06d2Stomee             throws IOException, ClassNotFoundException
256*e77b06d2Stomee     {
257*e77b06d2Stomee 	s.defaultReadObject();
258*e77b06d2Stomee 	// check invariants
259*e77b06d2Stomee 	try {
260*e77b06d2Stomee 	    validate();
261*e77b06d2Stomee 	} catch (Exception e) {
262*e77b06d2Stomee 	    InvalidObjectException x = new InvalidObjectException(
263*e77b06d2Stomee 		    e.getMessage());
264*e77b06d2Stomee 	    x.initCause(e);
265*e77b06d2Stomee 	    throw x;
266*e77b06d2Stomee 	}
267*e77b06d2Stomee     }
268*e77b06d2Stomee }
269