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 2007 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.util.*; 31 import java.io.*; 32 import java.beans.*; 33 34 /** 35 * A power-of-two logarithmic frequency distribution aggregated by the 36 * DTrace {@code quantize()} action. Aggregated values fall into 37 * consecutive ranges, each twice as large as the previous range. Each 38 * range, known as a bucket, begins at two to the power of <i>n</i> and 39 * ends at one less than the beginning of the next bucket, two to the 40 * power of <i>n + 1</i>. The zero bucket is the degenerate case and 41 * holds the frequency of the base value zero. For example, the first 42 * bucket after 0 starts at 1 (2 to the power of 0) and ends at 1 (one 43 * less than 2 to the power of 1). The next bucket starts at 2 (2 to 44 * the power of 1) and ends at 3 (one less than 2 to the power of 2). 45 * Each bucket frequency is incremented for each aggregated value that 46 * falls into its range. Buckets are typically identified by their 47 * lower bound: 1, 2, 4, 8, etc. Mirroring these are buckets with 48 * negative ranges: -1, -2, -4, -8, etc. The range of an entire {@code 49 * LogDistribution} is (<code>-2<sup>63</sup> .. 50 * 2<sup>63</sup></code>). 51 * <p> 52 * Immutable. Supports persistence using {@link java.beans.XMLEncoder}. 53 * 54 * @see LinearDistribution 55 * @see Aggregation 56 * 57 * @author Tom Erickson 58 */ 59 public final class LogDistribution extends Distribution 60 implements Serializable, Comparable <LogDistribution> 61 { 62 static final long serialVersionUID = -1279719751212721961L; 63 64 static final int ZERO_BUCKET_INDEX = 63; 65 66 static { 67 try { 68 BeanInfo info = Introspector.getBeanInfo(LogDistribution.class); 69 PersistenceDelegate persistenceDelegate = 70 new DefaultPersistenceDelegate( 71 new String[] {"buckets"}); 72 BeanDescriptor d = info.getBeanDescriptor(); 73 d.setValue("persistenceDelegate", persistenceDelegate); 74 } catch (IntrospectionException e) { 75 System.out.println(e); 76 } 77 } 78 79 /** 80 * Called by native C code 81 */ 82 private LogDistribution(long[] buckets)83 LogDistribution(long[] buckets) 84 { 85 super(0, 2, buckets); // initializes using base 0, power of 2 86 } 87 88 /** 89 * Creates a logarithmic distribution with the given frequencies. 90 * Supports XML persistence. 91 * 92 * @param frequencies list of frequencies in bucket ranges bounded 93 * by consucutive powers of two 94 * @throws NullPointerException if {@code frequencies} is {@code 95 * null} 96 * @throws IllegalArgumentException if any bucket does not have the 97 * expected range (bounded by consecutive powers of two) 98 */ 99 public LogDistribution(List <Bucket> frequencies)100 LogDistribution(List <Bucket> frequencies) 101 { 102 super(frequencies); 103 initialize(); 104 } 105 106 /** 107 * Gets a two element array: the first elelemt is the range minimum 108 * (inclusive), the second element is the range maximum (inclusive). 109 */ 110 @Override 111 long[] getBucketRange(int i, int len, long base, long constant)112 getBucketRange(int i, int len, long base, long constant) 113 { 114 long min = LocalConsumer._quantizeBucket(i); 115 long max = (LocalConsumer._quantizeBucket(i + 1) - 1); 116 117 long[] range = new long[] {min, max}; 118 return range; 119 } 120 121 @Override 122 long[] getBucketRange(int i, int len)123 getBucketRange(int i, int len) 124 { 125 return getBucketRange(i, len, 0, 2); 126 } 127 128 public Number getValue()129 getValue() 130 { 131 double total = 0; 132 List <Distribution.Bucket> buckets = getBuckets(); 133 for (Distribution.Bucket bucket : buckets) { 134 total += ((double)bucket.getFrequency() * (double)bucket.getMin()); 135 } 136 return (new Double(total)); 137 } 138 139 private long getZeroBucketValue()140 getZeroBucketValue() 141 { 142 Distribution.Bucket b = get(ZERO_BUCKET_INDEX); 143 return b.getFrequency(); 144 } 145 146 /** 147 * Compares the {@code double} values of {@link #getValue()} for 148 * overall magnitude, and if those are equal, compares the 149 * frequencies at the zero bucket (the bucket whose range has a 150 * minimum and maximum value of zero). 151 */ 152 public int compareTo(LogDistribution d)153 compareTo(LogDistribution d) 154 { 155 Number v1 = getValue(); 156 Number v2 = d.getValue(); 157 double d1 = v1.doubleValue(); 158 double d2 = v2.doubleValue(); 159 int cmp = (d1 < d2 ? -1 : (d1 > d2 ? 1 : 0)); 160 if (cmp == 0) { 161 long z1 = getZeroBucketValue(); 162 long z2 = d.getZeroBucketValue(); 163 cmp = (z1 < z2 ? -1 : (z1 > z2 ? 1 : 0)); 164 } 165 return (cmp); 166 } 167 168 private void readObject(ObjectInputStream s)169 readObject(ObjectInputStream s) 170 throws IOException, ClassNotFoundException 171 { 172 s.defaultReadObject(); 173 try { 174 initialize(); 175 } catch (Exception e) { 176 InvalidObjectException x = new InvalidObjectException( 177 e.getMessage()); 178 x.initCause(e); 179 throw x; 180 } 181 } 182 } 183