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