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 2007 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.util.*;
2N/Aimport java.io.*;
2N/Aimport java.beans.*;
2N/A
2N/A/**
2N/A * A linear frequency distribution aggregated by the DTrace {@code
2N/A * lquantize()} action. Aggregated values fall into consecutive ranges
2N/A * bounded by the step parameter of the {@code lquantize()} action.
2N/A * Each range, known as a bucket, begins at the {@code lquantize()}
2N/A * lower bound, or base, plus a multiple of the {@code lquantize()}
2N/A * step, unless it is the first bucket, which is the frequency of all
2N/A * aggregated values less than the base. The last bucket counts all
2N/A * aggregated values greater than or equal to the {@code lquantize()}
2N/A * upper bound. For example
2N/A * <pre> {@code @ = lquantize(n, 0, 100, 10);}</pre>
2N/A * results in a distribution with a base of 0, an upper bound of 100,
2N/A * and a step of 10. It has twelve buckets starting with {@code n < 0}
2N/A * and ending with {@code n >= 100}. The buckets in between are {@code
2N/A * 0 .. 9}, {@code 10 .. 19}, etc.
2N/A * <p>
2N/A * Immutable. Supports persistence using {@link java.beans.XMLEncoder}.
2N/A *
2N/A * @see LogDistribution
2N/A * @see Aggregation
2N/A *
2N/A * @author Tom Erickson
2N/A */
2N/Apublic final class LinearDistribution extends Distribution
2N/A implements Serializable, Comparable <LinearDistribution>
2N/A{
2N/A static final long serialVersionUID = 7100080045858770132L;
2N/A
2N/A /** @serial */
2N/A private long base;
2N/A /** @serial */
2N/A private long step;
2N/A
2N/A static {
2N/A try {
2N/A BeanInfo info = Introspector.getBeanInfo(LinearDistribution.class);
2N/A PersistenceDelegate persistenceDelegate =
2N/A new DefaultPersistenceDelegate(
2N/A new String[] {"base", "step", "buckets" });
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 /**
2N/A * Called by native C code
2N/A */
2N/A private
2N/A LinearDistribution(long lowerBound, long frequencyStep,
2N/A long[] frequencies)
2N/A {
2N/A // initializes using lowerBound and frequencyStep
2N/A super(lowerBound, frequencyStep, frequencies);
2N/A base = lowerBound;
2N/A step = frequencyStep;
2N/A }
2N/A
2N/A /**
2N/A * Creates a linear distribution with the given base, step, and
2N/A * frequencies. Supports XML persistence.
2N/A *
2N/A * @param lowerBound also known as the <i>base</i>; the minimum of
2N/A * the second bucket in this distribution (the first bucket contains
2N/A * the frequency of everything lower than the base)
2N/A * @param bucketStep the distance between the lower bound of one
2N/A * bucket and the lower bound of the next consecutive bucket
2N/A * (excluding the first bucket)
2N/A * @param frequencies list of frequencies in each bucket range
2N/A * @throws NullPointerException if {@code frequencies} is {@code
2N/A * null}
2N/A * @throws IllegalArgumentException if the given step is less than
2N/A * one, or if any bucket does not have the expected range
2N/A * (consecutive steps)
2N/A */
2N/A public
2N/A LinearDistribution(long lowerBound, long bucketStep,
2N/A List <Bucket> frequencies)
2N/A {
2N/A super(frequencies); // makes defensive copy
2N/A base = lowerBound;
2N/A step = bucketStep;
2N/A initialize(); // checks class invariants, calculates total
2N/A if (step < 1) {
2N/A throw new IllegalArgumentException("step is less than one");
2N/A }
2N/A }
2N/A
2N/A /**
2N/A * Gets a two element array: the first elelemt is the range minimum
2N/A * (inclusive), the second element is the range maximum (inclusive).
2N/A */
2N/A @Override
2N/A long[]
2N/A getBucketRange(int i, int len, long base, long step)
2N/A {
2N/A long min;
2N/A long max;
2N/A if (i == 0) {
2N/A // first bucket is everything less than the base
2N/A min = Long.MIN_VALUE;
2N/A } else {
2N/A min = (base + ((i - 1) * step));
2N/A }
2N/A
2N/A if (i == (len - 1)) {
2N/A // last bucket is everything greater than or equal to
2N/A // the upper bound
2N/A max = Long.MAX_VALUE;
2N/A } else {
2N/A max = ((base + (i * step)) - 1);
2N/A }
2N/A
2N/A long[] range = new long[] {min, max};
2N/A return range;
2N/A }
2N/A
2N/A @Override
2N/A long[]
2N/A getBucketRange(int i, int len)
2N/A {
2N/A return getBucketRange(i, len, base, step);
2N/A }
2N/A
2N/A /**
2N/A * Gets the lower bound of this distribution. In a linear
2N/A * distribution, the first bucket holds the frequency of all values
2N/A * less than the base, so the base is the minimum of the second
2N/A * bucket's range.
2N/A *
2N/A * @return the lower bound of this distribution
2N/A */
2N/A public long
2N/A getBase()
2N/A {
2N/A return base;
2N/A }
2N/A
2N/A /**
2N/A * Gets the difference between the lower bounds of consecutive
2N/A * buckets after the first.
2N/A *
2N/A * @return the step between the lower bounds of consecutive buckets
2N/A * after the first
2N/A */
2N/A public long
2N/A getStep()
2N/A {
2N/A return step;
2N/A }
2N/A
2N/A public Number
2N/A getValue()
2N/A {
2N/A double total = 0;
2N/A List <Distribution.Bucket> buckets = getBuckets();
2N/A int len = buckets.size();
2N/A Distribution.Bucket bucket;
2N/A
2N/A if (len > 0) {
2N/A bucket = buckets.get(0);
2N/A total = (double)bucket.getFrequency() * (double)(getBase() - 1);
2N/A }
2N/A for (int i = 1; i < (len - 1); ++i) {
2N/A bucket = buckets.get(i);
2N/A total += (double)bucket.getFrequency() * (double)bucket.getMin();
2N/A }
2N/A if (len > 1) {
2N/A bucket = buckets.get(len - 1);
2N/A // There doesn't seem to be any reason to add one to the
2N/A // minimum of the last bucket range, but that's how it's
2N/A // implemented in libdtrace dt_aggregate.c.
2N/A total += (double)bucket.getFrequency() *
2N/A (double)(bucket.getMin() + 1);
2N/A }
2N/A return (new Double(total));
2N/A }
2N/A
2N/A private long
2N/A getZeroBucketValue()
2N/A {
2N/A for (Distribution.Bucket b : this) {
2N/A if (b.getMin() == 0) {
2N/A return b.getFrequency();
2N/A }
2N/A }
2N/A return 0;
2N/A }
2N/A
2N/A /**
2N/A * Compares the {@code double} values of {@link #getValue()} for
2N/A * overall magnitude, and if those are equal, compares the
2N/A * frequencies at zero if the distributions include a bucket whose
2N/A * range has a minimum of zero.
2N/A */
2N/A public int
2N/A compareTo(LinearDistribution d)
2N/A {
2N/A Number v1 = getValue();
2N/A Number v2 = d.getValue();
2N/A double d1 = v1.doubleValue();
2N/A double d2 = v2.doubleValue();
2N/A int cmp = (d1 < d2 ? -1 : (d1 > d2 ? 1 : 0));
2N/A if (cmp == 0) {
2N/A long z1 = getZeroBucketValue();
2N/A long z2 = d.getZeroBucketValue();
2N/A cmp = (z1 < z2 ? -1 : (z1 > z2 ? 1 : 0));
2N/A }
2N/A return (cmp);
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 try {
2N/A initialize();
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 if (step < 1) {
2N/A throw new InvalidObjectException("step is less than one");
2N/A }
2N/A }
2N/A
2N/A /**
2N/A * Gets a string representation of this linear distribution useful
2N/A * for logging and not intended for display. The exact details of
2N/A * the representation are unspecified and subject to change, but the
2N/A * following format may be regarded as typical:
2N/A * <pre><code>
2N/A * class-name[property1 = value1, property2 = value2]
2N/A * </code></pre>
2N/A */
2N/A public String
2N/A toString()
2N/A {
2N/A StringBuilder buf = new StringBuilder();
2N/A buf.append(LinearDistribution.class.toString());
2N/A buf.append("[base = ");
2N/A buf.append(getBase());
2N/A buf.append(", step = ");
2N/A buf.append(getStep());
2N/A buf.append(", buckets = ");
2N/A List <Bucket> list = getDisplayRange();
2N/A if (list.isEmpty()) {
2N/A buf.append("<empty>");
2N/A } else {
2N/A buf.append(Arrays.toString(getDisplayRange().toArray()));
2N/A }
2N/A buf.append(", total = ");
2N/A buf.append(getTotal());
2N/A buf.append(']');
2N/A return buf.toString();
2N/A }
2N/A}