--- /dev/null
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.util;
+
+import com.google.common.primitives.UnsignedLong;
+import java.util.concurrent.atomic.AtomicLongFieldUpdater;
+import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;
+
+/**
+ * Concurrent version of {@link DurationStatisticsTracker}.
+ */
+// TODO: once DurationStatsTracker is gone make this class final
+class ConcurrentDurationStatisticsTracker extends DurationStatisticsTracker {
+ private static final AtomicReferenceFieldUpdater<ConcurrentDurationStatisticsTracker, DurationWithTime> LONGEST_UPDATER =
+ AtomicReferenceFieldUpdater.newUpdater(ConcurrentDurationStatisticsTracker.class, DurationWithTime.class, "longest");
+ private static final AtomicReferenceFieldUpdater<ConcurrentDurationStatisticsTracker, DurationWithTime> SHORTEST_UPDATER =
+ AtomicReferenceFieldUpdater.newUpdater(ConcurrentDurationStatisticsTracker.class, DurationWithTime.class, "shortest");
+ private static final AtomicLongFieldUpdater<ConcurrentDurationStatisticsTracker> COUNT_UPDATER =
+ AtomicLongFieldUpdater.newUpdater(ConcurrentDurationStatisticsTracker.class, "count");
+ private static final AtomicLongFieldUpdater<ConcurrentDurationStatisticsTracker> SUM_UPDATER =
+ AtomicLongFieldUpdater.newUpdater(ConcurrentDurationStatisticsTracker.class, "sum");
+
+ private volatile long sum = 0;
+ private volatile long count = 0;
+ private volatile DurationWithTime longest = null;
+ private volatile DurationWithTime shortest = null;
+
+ ConcurrentDurationStatisticsTracker() {
+ // Hidden on purpose
+ }
+
+ @Override
+ public final void addDuration(final long duration) {
+ // First update the quick stats
+ SUM_UPDATER.addAndGet(this, duration);
+ COUNT_UPDATER.incrementAndGet(this);
+
+ /*
+ * Now the hairy 'min/max' things. The notion of "now" we cache,
+ * so the first time we use it, we do not call it twice. We populate
+ * it lazily, though.
+ *
+ * The longest/shortest stats both are encapsulated in an object,
+ * so we update them atomically and we minimize the number of volatile
+ * operations.
+ */
+ DurationWithTime current = shortest;
+ if (current == null || duration < current.getDuration()) {
+ final DurationWithTime newObj = new DurationWithTime(duration, System.currentTimeMillis());
+ while (!SHORTEST_UPDATER.weakCompareAndSet(this, current, newObj)) {
+ current = shortest;
+ if (current != null && duration >= current.getDuration()) {
+ break;
+ }
+ }
+ }
+
+ current = longest;
+ if (current == null || duration > current.getDuration()) {
+ final DurationWithTime newObj = new DurationWithTime(duration, System.currentTimeMillis());
+ while (!LONGEST_UPDATER.weakCompareAndSet(this, current, newObj)) {
+ current = longest;
+ if (current != null && duration <= current.getDuration()) {
+ break;
+ }
+ }
+ }
+ }
+
+ @Override
+ public final long getTotalDurations() {
+ return count;
+ }
+
+ @Override
+ public final double getAverageDuration() {
+ final long myCount = count;
+ return myCount == 0 ? 0 : UnsignedLong.fromLongBits(sum).doubleValue() / myCount;
+ }
+
+ @Override
+ public final synchronized void reset() {
+ // Synchronized is just to make sure we do not have concurrent resets :)
+ longest = null;
+ shortest = null;
+ count = 0;
+ sum = 0;
+ }
+
+ @Override
+ protected final DurationWithTime getLongest() {
+ return longest;
+ }
+
+ @Override
+ protected final DurationWithTime getShortest() {
+ return shortest;
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2014 Brocade Communications Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.util;
+
+import static java.util.concurrent.TimeUnit.MICROSECONDS;
+import static java.util.concurrent.TimeUnit.MILLISECONDS;
+import static java.util.concurrent.TimeUnit.NANOSECONDS;
+import static java.util.concurrent.TimeUnit.SECONDS;
+import com.google.common.annotations.Beta;
+import java.text.DecimalFormat;
+import java.text.DecimalFormatSymbols;
+import java.util.Date;
+import java.util.concurrent.TimeUnit;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Abstract class that calculates and tracks time duration statistics.
+ *
+ * @author Thomas Pantelis
+ * @author Robert Varga
+ */
+@Beta
+public abstract class DurationStatisticsTracker {
+ private static final Logger LOG = LoggerFactory.getLogger(DurationStatisticsTracker.class);
+ private static final DecimalFormat DECIMAL_FORMAT;
+
+ static {
+ final DecimalFormatSymbols symbols = DecimalFormatSymbols.getInstance();
+ symbols.setDecimalSeparator('.');
+ DECIMAL_FORMAT = new DecimalFormat("0.00", symbols);
+ }
+
+ /**
+ * Create a concurrent {@link DurationStatisticsTracker}, which performs well
+ * in very contended environments.
+ *
+ * @return A new instance.
+ */
+ public static DurationStatisticsTracker createConcurrent() {
+ return new ConcurrentDurationStatisticsTracker();
+ }
+
+ /**
+ * Create a synchronized {@link DurationStatisticsTracker}, which performs well
+ * in non-contended environments.
+ *
+ * @return A new instance.
+ */
+ public static DurationStatisticsTracker createSynchronized() {
+ return new SynchronizedDurationStatsTracker();
+ }
+
+ /**
+ * Add a duration to track.
+ *
+ * @param duration
+ * non-negative duration in nanoseconds.
+ */
+ public abstract void addDuration(long duration);
+
+ /**
+ * Returns the average duration in nanoseconds.
+ */
+ public abstract double getAverageDuration();
+
+ /**
+ * Returns the total number of tracked durations.
+ *
+ * @return Total number of measurements accumulated since last
+ * {@link #reset()}.
+ */
+ public abstract long getTotalDurations();
+
+ /**
+ * Resets all statistics back to their defaults.
+ */
+ public abstract void reset();
+
+ /**
+ * Get the shortest recorded duration and the time when it was recorded.
+ *
+ * @return Duration and timestamp.
+ */
+ protected abstract DurationWithTime getShortest();
+
+ /**
+ * Get the longest recorded duration and the time when it was recorded.
+ *
+ * @return Duration and timestamp.
+ */
+ protected abstract DurationWithTime getLongest();
+
+ /**
+ * Returns the longest duration in nanoseconds.
+ */
+ public final long getLongestDuration() {
+ return getDuration(getLongest());
+ }
+
+ /**
+ * Returns the shortest duration in nanoseconds.
+ */
+ public final long getShortestDuration() {
+ return getDuration(getShortest());
+ }
+
+ /**
+ * Returns the average duration as a displayable String with units, e.g.
+ * "12.34 ms".
+ */
+ public final String getDisplayableAverageDuration() {
+ return formatDuration(getAverageDuration(), null);
+ }
+
+ /**
+ * Returns the longest duration as a displayable String with units and the
+ * date/time at which it occurred, e.g. "12.34 ms at 08/02/2014 12:30:24".
+ */
+ public final String getDisplayableLongestDuration() {
+ return formatDuration(getLongest());
+ }
+
+ /**
+ * Returns the shortest duration as a displayable String with units and the
+ * date/time at which it occurred, e.g. "12.34 ms at 08/02/2014 12:30:24".
+ */
+ public final String getDisplayableShortestDuration() {
+ return formatDuration(getShortest());
+ }
+
+ /**
+ * Returns the time stamp of the longest duration.
+ */
+ public final long getTimeOfLongestDuration() {
+ return getTimeMillis(getLongest());
+ }
+
+ /**
+ * Returns the time stamp of the shortest duration.
+ */
+ public final long getTimeOfShortestDuration() {
+ return getTimeMillis(getShortest());
+ }
+
+ /**
+ * Returns formatted value of number, e.g. "12.34". Always is used dot as
+ * decimal separator.
+ */
+ private static synchronized String formatDecimalValue(final double value) {
+ return DECIMAL_FORMAT.format(value);
+ }
+
+ private static long getDuration(final DurationWithTime current) {
+ return current == null ? 0L : current.getDuration();
+ }
+
+ private static long getTimeMillis(final DurationWithTime current) {
+ return current == null ? 0L : current.getTimeMillis();
+ }
+
+ private static String formatDuration(final double duration, final Long timeStamp) {
+ final TimeUnit unit = chooseUnit((long) duration);
+ final double value = duration / NANOSECONDS.convert(1, unit);
+
+ final StringBuilder sb = new StringBuilder();
+ sb.append(formatDecimalValue(value));
+ sb.append(' ');
+ sb.append(abbreviate(unit));
+
+ if (timeStamp != null) {
+ sb.append(String.format(" at %1$tD %1$tT", new Date(timeStamp)));
+ }
+
+ return sb.toString();
+ }
+
+ private static String formatDuration(final DurationWithTime current) {
+ if (current != null) {
+ return formatDuration(current.getDuration(), current.getTimeMillis());
+ } else {
+ return formatDuration(0, null);
+ }
+ }
+
+ private static TimeUnit chooseUnit(final long nanos) {
+ // TODO: this could be inlined, as we are doing needless divisions
+ if (NANOSECONDS.toSeconds(nanos) > 0) {
+ return SECONDS;
+ }
+ if (NANOSECONDS.toMillis(nanos) > 0) {
+ return MILLISECONDS;
+ }
+ if (NANOSECONDS.toMicros(nanos) > 0) {
+ return MICROSECONDS;
+ }
+ return NANOSECONDS;
+ }
+
+ private static String abbreviate(final TimeUnit unit) {
+ switch (unit) {
+ case NANOSECONDS:
+ return "ns";
+ case MICROSECONDS:
+ return "\u03bcs"; // μs
+ case MILLISECONDS:
+ return "ms";
+ case SECONDS:
+ return "s";
+ case MINUTES:
+ return "m";
+ case HOURS:
+ return "h";
+ case DAYS:
+ return "d";
+ }
+
+ LOG.warn("Unhandled time unit {}", unit);
+ return "";
+ }
+}
* terms of the Eclipse Public License v1.0 which accompanies this distribution,
* and is available at http://www.eclipse.org/legal/epl-v10.html
*/
-
package org.opendaylight.yangtools.util;
-import static java.util.concurrent.TimeUnit.MICROSECONDS;
-import static java.util.concurrent.TimeUnit.MILLISECONDS;
-import static java.util.concurrent.TimeUnit.NANOSECONDS;
-import static java.util.concurrent.TimeUnit.SECONDS;
-import java.text.DecimalFormat;
-import java.text.DecimalFormatSymbols;
-import java.util.Date;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.atomic.AtomicLongFieldUpdater;
-import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
/**
* Class that calculates and tracks time duration statistics.
*
* @author Thomas Pantelis
* @author Robert Varga
+ *
+ * @deprecated Use {@link DurationStatisticsTracker} instead.
*/
-public class DurationStatsTracker {
- private static final AtomicReferenceFieldUpdater<DurationStatsTracker, DurationWithTime> LONGEST_UPDATER =
- AtomicReferenceFieldUpdater.newUpdater(DurationStatsTracker.class, DurationWithTime.class, "longest");
- private static final AtomicReferenceFieldUpdater<DurationStatsTracker, DurationWithTime> SHORTEST_UPDATER =
- AtomicReferenceFieldUpdater.newUpdater(DurationStatsTracker.class, DurationWithTime.class, "shortest");
- private static final AtomicLongFieldUpdater<DurationStatsTracker> COUNT_UPDATER =
- AtomicLongFieldUpdater.newUpdater(DurationStatsTracker.class, "count");
- private static final AtomicLongFieldUpdater<DurationStatsTracker> SUM_UPDATER =
- AtomicLongFieldUpdater.newUpdater(DurationStatsTracker.class, "sum");
-
- private static final Logger LOG = LoggerFactory.getLogger(DurationStatsTracker.class);
- private static final DecimalFormat DECIMAL_FORMAT;
-
- private volatile long sum = 0;
- private volatile long count = 0;
- private volatile DurationWithTime longest = null;
- private volatile DurationWithTime shortest = null;
-
- static {
- final DecimalFormatSymbols symbols = DecimalFormatSymbols.getInstance();
- symbols.setDecimalSeparator('.');
- DECIMAL_FORMAT = new DecimalFormat("0.00", symbols);
- }
-
- /**
- * Add a duration to track.
- *
- * @param duration
- * the duration in nanoseconds.
- */
- public void addDuration(final long duration) {
- // First update the quick stats
- SUM_UPDATER.addAndGet(this, duration);
- COUNT_UPDATER.incrementAndGet(this);
-
- /*
- * Now the hairy 'min/max' things. The notion of "now" we cache,
- * so the first time we use it, we do not call it twice. We populate
- * it lazily, though.
- *
- * The longest/shortest stats both are encapsulated in an object,
- * so we update them atomically and we minimize the number of volatile
- * operations.
- */
- DurationWithTime current = shortest;
- if (current == null || current.getDuration() > duration) {
- final DurationWithTime newObj = new DurationWithTime(duration, System.currentTimeMillis());
- while (!SHORTEST_UPDATER.compareAndSet(this, current, newObj)) {
- current = shortest;
- if (current != null && current.getDuration() <= duration) {
- break;
- }
- }
- }
-
- current = longest;
- if (current == null || current.getDuration() < duration) {
- final DurationWithTime newObj = new DurationWithTime(duration, System.currentTimeMillis());
- while (!LONGEST_UPDATER.compareAndSet(this, current, newObj)) {
- current = longest;
- if (current != null && current.getDuration() >= duration) {
- break;
- }
- }
- }
- }
-
- /**
- * Returns the total number of tracked durations.
- */
- public long getTotalDurations() {
- return count;
- }
-
- private static long getDuration(final DurationWithTime current) {
- return current == null ? 0L : current.getDuration();
- }
-
- private static long getTimeMillis(final DurationWithTime current) {
- return current == null ? 0L : current.getTimeMillis();
- }
-
- /**
- * Returns the longest duration in nanoseconds.
- */
- public long getLongestDuration() {
- return getDuration(longest);
- }
-
+@Deprecated
+public class DurationStatsTracker extends ConcurrentDurationStatisticsTracker {
/**
- * Returns the shortest duration in nanoseconds.
+ * @deprecated Use {@link DurationStatisticsTracker#createConcurrent() instead.
*/
- public long getShortestDuration() {
- return getDuration(shortest);
- }
-
- /**
- * Returns the average duration in nanoseconds.
- */
- public double getAverageDuration() {
- final long mySum = sum;
- final long myCount = count;
-
- return myCount == 0 ? 0 : ((double) mySum) / myCount;
- }
-
- /**
- * Returns the time stamp of the longest duration.
- */
- public long getTimeOfLongestDuration() {
- return getTimeMillis(longest);
- }
-
- /**
- * Returns the time stamp of the shortest duration.
- */
- public long getTimeOfShortestDuration() {
- return getTimeMillis(shortest);
- }
-
- /**
- * Resets all statistics back to their defaults.
- */
- public synchronized void reset() {
- longest = null;
- shortest = null;
- count = 0;
- sum = 0;
- }
-
- /**
- * Returns the average duration as a displayable String with units, e.g.
- * "12.34 ms".
- */
- public String getDisplayableAverageDuration() {
- return formatDuration(getAverageDuration(), null);
- }
-
- /**
- * Returns the shortest duration as a displayable String with units and the
- * date/time at which it occurred, e.g. "12.34 ms at 08/02/2014 12:30:24".
- */
- public String getDisplayableShortestDuration() {
- return formatDuration(shortest);
- }
-
- /**
- * Returns the longest duration as a displayable String with units and the
- * date/time at which it occurred, e.g. "12.34 ms at 08/02/2014 12:30:24".
- */
- public String getDisplayableLongestDuration() {
- return formatDuration(longest);
- }
-
- /**
- * Returns formatted value of number, e.g. "12.34". Always is used dot as
- * decimal separator.
- */
- private static synchronized String formatDecimalValue(final double value) {
- return DECIMAL_FORMAT.format(value);
- }
-
- private static String formatDuration(final DurationWithTime current) {
- if (current != null) {
- return formatDuration(current.getDuration(), current.getTimeMillis());
- } else {
- return formatDuration(0, null);
- }
- }
-
- private static String formatDuration(final double duration, final Long timeStamp) {
- final TimeUnit unit = chooseUnit((long) duration);
- final double value = duration / NANOSECONDS.convert(1, unit);
-
- final StringBuilder sb = new StringBuilder();
- sb.append(formatDecimalValue(value));
- sb.append(' ');
- sb.append(abbreviate(unit));
-
- if (timeStamp != null) {
- sb.append(String.format(" at %1$tD %1$tT", new Date(timeStamp)));
- }
-
- return sb.toString();
- }
+ @Deprecated
+ public DurationStatsTracker() {
- private static TimeUnit chooseUnit(final long nanos) {
- // TODO: this could be inlined, as we are doing needless divisions
- if (NANOSECONDS.toSeconds(nanos) > 0) {
- return SECONDS;
- }
- if (NANOSECONDS.toMillis(nanos) > 0) {
- return MILLISECONDS;
- }
- if (NANOSECONDS.toMicros(nanos) > 0) {
- return MICROSECONDS;
- }
- return NANOSECONDS;
}
- private static String abbreviate(final TimeUnit unit) {
- switch (unit) {
- case NANOSECONDS:
- return "ns";
- case MICROSECONDS:
- return "\u03bcs"; // μs
- case MILLISECONDS:
- return "ms";
- case SECONDS:
- return "s";
- case MINUTES:
- return "m";
- case HOURS:
- return "h";
- case DAYS:
- return "d";
- }
+ // Remove once the no-argument constructor is removed
+ DurationStatsTracker(final Void dummy) {
- LOG.warn("Unhandled time unit {}", unit);
- return "";
}
}
--- /dev/null
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.util;
+
+import com.google.common.primitives.UnsignedLong;
+
+/**
+ * Non-concurrent implementation, useful for non-contended cases.
+ */
+final class SynchronizedDurationStatsTracker extends DurationStatisticsTracker {
+ private static final long NOT_SET = -1;
+
+ // Hot fields in the order in which they are accessed
+ private long durationSum = 0;
+ private long durationCount = 0;
+ private long shortestDuration = NOT_SET;
+ private long longestDuration = NOT_SET;
+
+ // Cold fields, longest has a higher chance of being accessed
+ private long longestTimestamp;
+ private long shortestTimestamp;
+
+ SynchronizedDurationStatsTracker() {
+ // Hidden on purpose
+ }
+
+ @Override
+ public synchronized void addDuration(final long duration) {
+ durationSum += duration;
+ durationCount++;
+
+ if (duration < shortestDuration || shortestDuration == NOT_SET) {
+ shortestDuration = duration;
+ shortestTimestamp = System.currentTimeMillis();
+ }
+ if (duration > longestDuration) {
+ longestDuration = duration;
+ longestTimestamp = System.currentTimeMillis();
+ }
+ }
+
+ @Override
+ public synchronized double getAverageDuration() {
+ return durationCount == 0 ? 0 : UnsignedLong.fromLongBits(durationSum).doubleValue() / durationCount;
+ }
+
+ @Override
+ public synchronized long getTotalDurations() {
+ return durationCount;
+ }
+
+ @Override
+ public synchronized void reset() {
+ durationSum = 0;
+ durationCount = 0;
+ longestDuration = NOT_SET;
+ shortestDuration = NOT_SET;
+ }
+
+ @Override
+ protected synchronized DurationWithTime getShortest() {
+ return shortestDuration == NOT_SET ? null : new DurationWithTime(shortestDuration, shortestTimestamp);
+ }
+
+ @Override
+ protected synchronized DurationWithTime getLongest() {
+ return longestDuration == NOT_SET ? null : new DurationWithTime(longestDuration, longestTimestamp);
+ }
+}