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