1 /* 2 * This file and its contents are supplied under the terms of the 3 * Common Development and Distribution License ("CDDL"), version 1.0. 4 * You may only use this file in accordance with the terms of version 5 * 1.0 of the CDDL. 6 * 7 * A full copy of the text of the CDDL should have accompanied this 8 * source. A copy of the CDDL is also available via the Internet at 9 * http://www.illumos.org/license/CDDL. 10 */ 11 12 /* 13 * Copyright 2011, Richard Lowe 14 */ 15 16 package org.opensolaris.os.dtrace; 17 18 import java.beans.*; 19 import java.io.*; 20 import java.util.*; 21 22 /** 23 * A log/linear distribution aggregated by the DTrace {@code llquantize()} 24 * action. Aggregated values are aggregated logarithmicly by order of 25 * magnitude (between the low and high magnitude arguments of the {@code 26 * llquantize()} action, but linearly within each order of magnitude bounded 27 * by the step parameter of the {@code llquantize()} action. 28 * 29 * @see LinearDistribution 30 * @see LogLinearDistribution 31 * @see Aggregation 32 */ 33 public final class LogLinearDistribution extends Distribution 34 implements Serializable, Comparable <LogLinearDistribution> 35 { 36 static final long serialVersionUID = 6271156690706677711L; 37 38 static final long UINT16_MAX = 0xffff; 39 40 static final long FACTOR_SHIFT = 48; 41 static final long LOW_SHIFT = 32; 42 static final long HIGH_SHIFT = 16; 43 static final long NSTEP_SHIFT = 0; 44 unpack(long x, long thing)45 private static long unpack(long x, long thing) { 46 return (x & (UINT16_MAX << thing)) >> thing; 47 } 48 49 /** @serial */ 50 private long encValue; 51 /** @serial */ 52 private long base; 53 54 static { 55 try { 56 BeanInfo info = Introspector.getBeanInfo( 57 LogLinearDistribution.class); 58 PersistenceDelegate persistenceDelegate = 59 new DefaultPersistenceDelegate( 60 new String[] { "encValue", "base", "buckets" }); 61 BeanDescriptor d = info.getBeanDescriptor(); 62 d.setValue("persistenceDelegate", persistenceDelegate); 63 } catch (IntrospectionException e) { 64 System.out.println(e); 65 } 66 } 67 68 /** 69 * Called by the native C code 70 */ LogLinearDistribution(long constant, long[] frequencies)71 private LogLinearDistribution(long constant, long[] frequencies) { 72 super(0, constant, frequencies); 73 encValue = constant; 74 } 75 76 77 /** 78 * Creates a log/linear distribution with the given parameters, base value 79 * and frequencies. Used by XML Persistence. 80 * 81 * @param enc The encoded representation of the high, low, step and steps 82 * {@code llquantize()} paramaters. 83 * @param base The base value of the distirbution 84 * @param frequencies list of frequencies in each bucket range 85 */ LogLinearDistribution(long enc, long base, List<Bucket> frequencies)86 public LogLinearDistribution(long enc, long base, 87 List<Bucket> frequencies) { 88 super(frequencies); 89 90 encValue = enc; 91 base = base; 92 93 initialize(); 94 } 95 96 /** 97 * Creates a log/linear distribution with the given parameters, base 98 * values and frequencies. 99 * 100 * @param scaleFactor factor 101 * @param lowMagnitude the low magnitude 102 * @param highMagnitude the high magnitude 103 * @param bucketSteps number of linear steps per magnitude 104 * @param baseVal basue value 105 * @param frequencies list of frequencies in each bucket range 106 */ LogLinearDistribution(long scaleFactor, long lowMagnitude, long highMagnitude, long bucketSteps, long baseVal, List<Bucket> frequencies)107 public LogLinearDistribution(long scaleFactor, long lowMagnitude, 108 long highMagnitude, long bucketSteps, long baseVal, 109 List<Bucket> frequencies) { 110 111 super(frequencies); 112 113 encValue = (scaleFactor << FACTOR_SHIFT) | (lowMagnitude << LOW_SHIFT) | 114 (highMagnitude << HIGH_SHIFT) | (bucketSteps << NSTEP_SHIFT); 115 base = baseVal; 116 117 initialize(); 118 } 119 120 private long[][] rangeCache = null; 121 fillRangeCache(long constant, int len)122 private void fillRangeCache(long constant, int len) { 123 long value = 1; 124 long next, step; 125 long low, high, nsteps, factor; 126 int order, bucket = 0; 127 128 low = unpack(constant, LOW_SHIFT); 129 high = unpack(constant, HIGH_SHIFT); 130 nsteps = unpack(constant, NSTEP_SHIFT); 131 factor = unpack(constant, FACTOR_SHIFT); 132 133 if (rangeCache == null) 134 rangeCache = new long[len][2]; 135 136 for (order = 0; order < low; order++) 137 value *= factor; 138 139 base = value; 140 141 rangeCache[bucket][0] = Long.MIN_VALUE; 142 rangeCache[bucket][1] = value - 1; 143 bucket++; 144 145 next = value * factor; 146 step = (next > nsteps) ? (next / nsteps) : 1; 147 148 while (order <= high) { 149 rangeCache[bucket][0] = value; 150 rangeCache[bucket][1] = value + step - 1; 151 bucket++; 152 153 if ((value += step) != next) 154 continue; 155 156 next = value * factor; 157 step = (next > nsteps) ? (next / nsteps) : 1; 158 order++; 159 } 160 161 rangeCache[bucket][0] = value; 162 rangeCache[bucket][1] = Long.MAX_VALUE; 163 } 164 165 /** 166 * Gets a two element array: the first element is the range minimum 167 * (inclusive), the second element is the range maximum (inclusive). 168 */ 169 @Override getBucketRange(int i, int len, long base, long constant)170 long[] getBucketRange(int i, int len, long base, long constant) { 171 if (rangeCache == null) 172 fillRangeCache(constant, len); 173 174 return rangeCache[i]; 175 } 176 177 @Override getBucketRange(int i, int len)178 long[] getBucketRange(int i, int len) { 179 return getBucketRange(i, len, 0, encValue); 180 } 181 getValue()182 public Number getValue() { 183 double total = 0; 184 185 List<Distribution.Bucket> buckets = getBuckets(); 186 for (Distribution.Bucket bucket : buckets) 187 total += ((double)bucket.getFrequency() * (double)bucket.getMin()); 188 189 return (new Double(total)); 190 } 191 getZeroBucketValue()192 private long getZeroBucketValue() { 193 for (Distribution.Bucket b : this) { 194 if (b.getMin() == 0) { 195 return b.getFrequency(); 196 } 197 } 198 return 0; 199 } 200 201 /** 202 * Compares the {@code double} values of {@link #getValue()} for overall 203 * magnitude, and if those are equal, compares frequencies at zero if the 204 * distrubions includea bucket whose range has a minimum of zero. 205 */ compareTo(LogLinearDistribution d)206 public int compareTo(LogLinearDistribution d) { 207 Number v1 = getValue(); 208 Number v2 = getValue(); 209 double d1 = v1.doubleValue(); 210 double d2 = v2.doubleValue(); 211 int cmp = (d1 < d2 ? -1 : (d1 > d2 ? 1 : 0)); 212 213 if (cmp == 0) { 214 long z1 = getZeroBucketValue(); 215 long z2 = d.getZeroBucketValue(); 216 cmp = (z1 < z2 ? -1 : (z1 > z2 ? 1 : 0)); 217 } 218 return (cmp); 219 } 220 getBase()221 public long getBase() { 222 return base; 223 } 224 getEncValue()225 public long getEncValue() { 226 return encValue; 227 } 228 readObject(ObjectInputStream s)229 private void readObject(ObjectInputStream s) 230 throws IOException, ClassNotFoundException { 231 s.defaultReadObject(); 232 try { 233 initialize(); 234 } catch (Exception e) { 235 InvalidObjectException x = new InvalidObjectException( 236 e.getMessage()); 237 x.initCause(e); 238 throw x; 239 } 240 } 241 } 242