2N/A/*
2N/A * CDDL HEADER START
2N/A *
2N/A * The contents of this file are subject to the terms of the
2N/A * Common Development and Distribution License (the "License").
2N/A * You may not use this file except in compliance with the License.
2N/A *
2N/A * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
2N/A * or http://www.opensolaris.org/os/licensing.
2N/A * See the License for the specific language governing permissions
2N/A * and limitations under the License.
2N/A *
2N/A * When distributing Covered Code, include this CDDL HEADER in each
2N/A * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
2N/A * If applicable, add the following below this CDDL HEADER, with the
2N/A * fields enclosed by brackets "[]" replaced with your own identifying
2N/A * information: Portions Copyright [yyyy] [name of copyright owner]
2N/A *
2N/A * CDDL HEADER END
2N/A */
2N/A
2N/A/*
2N/A * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
2N/A * Use is subject to license terms.
2N/A *
2N/A * ident "%Z%%M% %I% %E% SMI"
2N/A */
2N/Apackage org.opensolaris.os.dtrace;
2N/A
2N/Aimport java.io.*;
2N/Aimport java.beans.*;
2N/Aimport java.math.BigInteger;
2N/A
2N/A/**
2N/A * A {@code long} value aggregated by the DTrace {@code stddev()} action.
2N/A * <p>
2N/A * Immutable. Supports persistence using {@link java.beans.XMLEncoder}.
2N/A *
2N/A * @see Aggregation
2N/A * @author Tom Erickson
2N/A */
2N/Apublic final class StddevValue extends AbstractAggregationValue {
2N/A static final long serialVersionUID = 6409878160513885375L;
2N/A
2N/A /** @serial */
2N/A private final long total;
2N/A /** @serial */
2N/A private final long count;
2N/A /** @serial */
2N/A private final BigInteger totalSquares;
2N/A
2N/A static {
2N/A try {
2N/A BeanInfo info = Introspector.getBeanInfo(StddevValue.class);
2N/A PersistenceDelegate persistenceDelegate =
2N/A new DefaultPersistenceDelegate(
2N/A new String[] {"value", "total", "count", "totalSquares"})
2N/A {
2N/A @Override
2N/A protected Expression
2N/A instantiate(Object oldInstance, Encoder out)
2N/A {
2N/A StddevValue stddev = (StddevValue)oldInstance;
2N/A return new Expression(oldInstance, oldInstance.getClass(),
2N/A "new", new Object[] {
2N/A stddev.getValue().longValue(),
2N/A stddev.getTotal(), stddev.getCount(),
2N/A stddev.getTotalSquares().toString() });
2N/A }
2N/A };
2N/A BeanDescriptor d = info.getBeanDescriptor();
2N/A d.setValue("persistenceDelegate", persistenceDelegate);
2N/A } catch (IntrospectionException e) {
2N/A System.out.println(e);
2N/A }
2N/A }
2N/A
2N/A // ported from dt_sqrt_128 in lib/libdtrace/common/dt_consume.c
2N/A private static long
2N/A squareRoot128(BigInteger n)
2N/A {
2N/A long result = 0;
2N/A BigInteger diff = BigInteger.valueOf(0);
2N/A BigInteger nextTry = BigInteger.valueOf(0);
2N/A int bitPairs = (n.bitLength() / 2);
2N/A int bitPos = (bitPairs * 2) + 1;
2N/A int nextTwoBits;
2N/A
2N/A for (int i = 0; i <= bitPairs; i++) {
2N/A // Bring down the next pair of bits.
2N/A nextTwoBits = n.testBit(bitPos)
2N/A ? (n.testBit(bitPos - 1) ? 0x3 : 0x2)
2N/A : (n.testBit(bitPos - 1) ? 0x1 : 0x0);
2N/A
2N/A diff = diff.shiftLeft(2);
2N/A diff = diff.add(BigInteger.valueOf(nextTwoBits));
2N/A
2N/A // nextTry = R << 2 + 1
2N/A nextTry = BigInteger.valueOf(result);
2N/A nextTry = nextTry.shiftLeft(2);
2N/A nextTry = nextTry.setBit(0);
2N/A
2N/A result <<= 1;
2N/A if (nextTry.compareTo(diff) <= 0) {
2N/A diff = diff.subtract(nextTry);
2N/A result++;
2N/A }
2N/A
2N/A bitPos -= 2;
2N/A }
2N/A
2N/A return (result);
2N/A }
2N/A
2N/A // ported from dt_stddev in lib/libdtrace/common/dt_consume.c
2N/A private static long
2N/A standardDeviation(long stddevCount, long stddevTotal,
2N/A BigInteger stddevTotalSquares)
2N/A {
2N/A BigInteger averageOfSquares = stddevTotalSquares.divide(
2N/A BigInteger.valueOf(stddevCount));
2N/A long avg = (stddevTotal / stddevCount);
2N/A if (avg < 0) {
2N/A avg = -avg;
2N/A }
2N/A BigInteger squareOfAverage = BigInteger.valueOf(avg);
2N/A squareOfAverage = squareOfAverage.pow(2);
2N/A BigInteger stddev = averageOfSquares.subtract(squareOfAverage);
2N/A return squareRoot128(stddev);
2N/A }
2N/A
2N/A /*
2N/A * Called by native code.
2N/A */
2N/A private
2N/A StddevValue(long stddevCount, long stddevTotal,
2N/A BigInteger stddevTotalSquares)
2N/A {
2N/A super(stddevCount == 0 ? 0 : standardDeviation(stddevCount,
2N/A stddevTotal, stddevTotalSquares));
2N/A total = stddevTotal;
2N/A count = stddevCount;
2N/A totalSquares = stddevTotalSquares;
2N/A if (totalSquares == null) {
2N/A throw new NullPointerException("totalSquares is null");
2N/A }
2N/A if (count < 0) {
2N/A throw new IllegalArgumentException("count is negative");
2N/A }
2N/A }
2N/A
2N/A /**
2N/A * Creates a value aggregated by the DTrace {@code stddev()} action.
2N/A * Supports XML persistence.
2N/A *
2N/A * @param v standard deviation
2N/A * @param stddevTotal sum total of all values included in the standard
2N/A * deviation
2N/A * @param stddevCount number of values included in the standard
2N/A * deviation
2N/A * @param stddevTotalSquaresString decimal string representation of
2N/A * the 128-bit sum total of the squares of all values included in
2N/A * the standard deviation
2N/A * @throws IllegalArgumentException if the given count is negative
2N/A * or if the given standard deviation is not the value expected for
2N/A * the given total, total of squares, and count
2N/A * @throws NumberFormatException if the given total squares is not a
2N/A * valid integer representation
2N/A */
2N/A public
2N/A StddevValue(long v, long stddevTotal, long stddevCount,
2N/A String stddevTotalSquaresString)
2N/A {
2N/A super(v);
2N/A total = stddevTotal;
2N/A count = stddevCount;
2N/A totalSquares = new BigInteger(stddevTotalSquaresString);
2N/A validate();
2N/A }
2N/A
2N/A private final void
2N/A validate()
2N/A {
2N/A if (count < 0) {
2N/A throw new IllegalArgumentException("count is negative");
2N/A }
2N/A long stddev = super.getValue().longValue();
2N/A if (count == 0) {
2N/A if (stddev != 0) {
2N/A throw new IllegalArgumentException(
2N/A "count of values is zero, stddev is non-zero (" +
2N/A stddev + ")");
2N/A }
2N/A } else {
2N/A if (stddev != standardDeviation(count, total, totalSquares)) {
2N/A throw new IllegalArgumentException(
2N/A getValue().toString() + " is not the expected " +
2N/A "standard deviation of total " + total + ", count " +
2N/A count + ", and total squares " + totalSquares);
2N/A }
2N/A }
2N/A }
2N/A
2N/A // Needed to support XML persistence since XMLDecoder cannot find
2N/A // the public method of the non-public superclass.
2N/A
2N/A /**
2N/A * Gets the standard deviation of the aggregated values.
2N/A *
2N/A * @return standard deviation of the aggregated values
2N/A */
2N/A public Long
2N/A getValue()
2N/A {
2N/A return (Long)super.getValue();
2N/A }
2N/A
2N/A /**
2N/A * Gets the sum total of the aggregated values.
2N/A *
2N/A * @return the sum total of the aggregated values
2N/A */
2N/A public long
2N/A getTotal()
2N/A {
2N/A return total;
2N/A }
2N/A
2N/A /**
2N/A * Gets the number of aggregated values included in the standard
2N/A * deviation.
2N/A *
2N/A * @return the number of aggregated values included in the standard
2N/A * deviation
2N/A */
2N/A public long
2N/A getCount()
2N/A {
2N/A return count;
2N/A }
2N/A
2N/A /**
2N/A * Gets the sum total of the squares of the aggregated values.
2N/A *
2N/A * @return the sum total of the squares of the aggregated values
2N/A */
2N/A public BigInteger
2N/A getTotalSquares()
2N/A {
2N/A return totalSquares;
2N/A }
2N/A
2N/A private void
2N/A readObject(ObjectInputStream s)
2N/A throws IOException, ClassNotFoundException
2N/A {
2N/A s.defaultReadObject();
2N/A // check invariants
2N/A try {
2N/A validate();
2N/A } catch (Exception e) {
2N/A InvalidObjectException x = new InvalidObjectException(
2N/A e.getMessage());
2N/A x.initCause(e);
2N/A throw x;
2N/A }
2N/A }
2N/A}