/* * Copyright 2007-2010 Sun Microsystems, Inc. * * This file is part of Project Darkstar Server. * * Project Darkstar Server is free software: you can redistribute it * and/or modify it under the terms of the GNU General Public License * version 2 as published by the Free Software Foundation and * distributed hereunder to you. * * Project Darkstar Server is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. * * -- */ package com.sun.sgs.impl.profile.util; /** * A histogram that bins values according to powers of 2. */ public class PowerOfTwoHistogram implements Histogram { /** * the longest bar in the histogram */ // REMINDER: should this be a configurable option? private static final int MAX_HIST_LENGTH = 40; /** * The bins for the histogram, which contain the current count */ private final int[] bins; /** * The maximum index that contains an entry */ private int maxIndex; /** * The minimum index that contains an entry */ private int minIndex; /** * The maximum number of entries current in one bin of the * histogram. */ private int maxCount; /** * The number of samples that this histogram represents. */ private int size; /** * Creates a new power-of-2 frequency histogram. */ public PowerOfTwoHistogram() { bins = new int[64]; // buckets for (2^64)+1, plus a zero bucket maxIndex = Integer.MIN_VALUE; minIndex = Integer.MAX_VALUE; maxCount = 0; size = 0; } /** * {@inheritDoc} * * Values are binned in the largest bin that is <i>less than</i> * the element is incremented. Note that this histogram supports * only <i>non-negative</i> values; negative values will not be * counted. */ public void bin(long value) { if (value < 0) { return; } int bin = 0; // skip the special cases: bin 0 is for zero values. if (value != 0) { int i = 0; while (value > (1 << (i + 1))) { ++i; } bin = i + 1; // 0 index is for 0 values } maxIndex = Math.max(maxIndex, bin); minIndex = Math.min(minIndex, bin); int count = bins[bin]++; if (count > maxCount) { maxCount = count; } size++; } /** * {@inheritDoc} */ public void clear() { for (int i = 0; i < bins.length; ++i) { bins[i] = 0; } maxIndex = Integer.MIN_VALUE; minIndex = Integer.MAX_VALUE; maxCount = 0; size = 0; } /** * {@inheritDoc} */ public int size() { return size; } /** * Generates a text representation of this power-of-2 frequency * histogram. The histogram is presented similar to the following * example: * * <pre> * 8 |*** * 16 | * 32 |* * 64 |***** * </pre> * * Bins that have at least one sample will have a bar displayed. * All leading and trailing empty bins are truncated. The final * line will have a newline at the end. * * @return the histogram */ public String toString() { return toString(""); } /** * Generates a text representation of this power-of-2 frequency * histogram similar to {@link #toString()} but with labels on * bins. For example, a bin would appear as: * * <pre> * 16ms |*** * </pre> * * @param binLabel the label to append to each of the bins * * @return the histogram */ public String toString(String binLabel) { // get the length of the longest string version of the integer // to make the histogram line up correctly int maxLength = Integer.toString(1 << maxIndex).length(); StringBuilder b = new StringBuilder(128); for (int i = minIndex; i <= maxIndex; ++i) { // special case for the 0 index, as it represents values // of 0 and therefore can't be shifted for its real value String n = (i == 0) ? "0" : Integer.toString(1 << (i - 1)); // make the bars all line up evenly by padding with spaces for (int j = n.length(); j < maxLength; ++j) { b.append(" "); } b.append(n).append(binLabel).append(" |"); // scale the bar length relative to the max int bars = (int) ((bins[i] / (double) maxCount) * MAX_HIST_LENGTH); // bump all non-empty buckets by one, so we can tell the // difference if (bins[i] > 0) { bars++; } for (int j = 0; j < bars; ++j) { b.append("*"); } b.append("\n"); } return b.toString(); } }