    001/**
    002 * Copyright (c) 2004-2011 QOS.ch
    003 * All rights reserved.
    004 *
    005 * Permission is hereby granted, free  of charge, to any person obtaining
    006 * a  copy  of this  software  and  associated  documentation files  (the
    007 * "Software"), to  deal in  the Software without  restriction, including
    008 * without limitation  the rights to  use, copy, modify,  merge, publish,
    009 * distribute,  sublicense, and/or sell  copies of  the Software,  and to
    010 * permit persons to whom the Software  is furnished to do so, subject to
    011 * the following conditions:
    012 *
    013 * The  above  copyright  notice  and  this permission  notice  shall  be
    014 * included in all copies or substantial portions of the Software.
    015 *
    016 * THE  SOFTWARE IS  PROVIDED  "AS  IS", WITHOUT  WARRANTY  OF ANY  KIND,
    017 * EXPRESS OR  IMPLIED, INCLUDING  BUT NOT LIMITED  TO THE  WARRANTIES OF
    018 * MERCHANTABILITY,    FITNESS    FOR    A   PARTICULAR    PURPOSE    AND
    019 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
    020 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
    021 * OF CONTRACT, TORT OR OTHERWISE,  ARISING FROM, OUT OF OR IN CONNECTION
    022 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
    023 *
    024 */
    025package org.slf4j.helpers;
    026
    027import junit.framework.AssertionFailedError;
    028
    029/**
    030 * BogoPerf is used to check that the time required to perform a certain
    031 * operation does not deteriorate over time. BogoPerf adjusts to the CPU speed
    032 * and capabilities of the host.
    033 *
    034 * @author Ceki G&uuml;lc&uuml;
    035 *
    036 */
    037public class BogoPerf {
    038
    039    private static long NANOS_IN_ONE_SECOND = 1000 * 1000 * 1000;
    040    private static int INITIAL_N = 1000;
    041    private static int LAST_N = 100;
    042    private static int SLACK_FACTOR = 3;
    043
    044    static {
    045        // let the JIT warm up
    046        computeBogoIPS(INITIAL_N);
    047        double bogo_ips = computeBogoIPS(INITIAL_N);
    048        System.out.println("Host runs at " + bogo_ips + " BIPS");
    049    }
    050
    051    /**
    052     * Compute bogoInstructions per second
    053     * <p>
    054     * on a 3.2 Ghz Pentium D CPU (around 2007), we obtain about 9'000 bogoIPS.
    055     *
    056     * @param N
    057     *                number of bogoInstructions to average over in order to
    058     *                compute the result
    059     * @return bogo Instructions Per Second
    060     */
    061    private static double computeBogoIPS(int N) {
    062        long begin = System.nanoTime();
    063
    064        for (int i = 0; i < N; i++) {
    065            bogoInstruction();
    066        }
    067        long end = System.nanoTime();
    068
    069        // duration
    070        double D = end - begin;
    071        // average duration per instruction
    072        double avgDPIS = D / N;
    073        // System.out.println(D + " nanos for " + N + " instructions");
    074        // System.out.println(avgD + " nanos per instruction");
    075
    076        double bogoIPS = NANOS_IN_ONE_SECOND / avgDPIS;
    077        // System.out.println(bogoIPS + " bogoIPS");
    078
    079        return bogoIPS;
    080    }
    081
    082    private static void bogoInstruction() {
    083        // use our own random number generator, independent of the host JDK
    084        MyRandom myRandom = new MyRandom(100);
    085        int len = 150;
    086        int[] intArray = new int[len];
    087        for (int i = 0; i < len; i++) {
    088            intArray[i] = myRandom.nextInt();
    089        }
    090        // use our own sort algorithm, independent of the host JDK
    091        BubbleSort.sort(intArray);
    092    }
    093
    094    /**
    095     * Computed the BogoIPS for this host CPU.
    096     *
    097     * @return
    098     */
    099    public static double currentBIPS() {
    100        return computeBogoIPS(LAST_N);
    101    }
    102
    103    static double min(double a, double b) {
    104        return (a <= b) ? a : b;
    105    }
    106
    107    /**
    108     * Assertion used for values that <b>decrease</b> with faster CPUs, typically
    109     * the time (duration) needed to perform a task.
    110     *
    111     * @param currentDuration
    112     * @param referenceDuration
    113     * @param referenceBIPS
    114     * @throws AssertionFailedError
    115     */
    116    public static void assertDuration(double currentDuration, long referenceDuration, double referenceBIPS) throws AssertionFailedError {
    117        double ajustedDuration = adjustExpectedDuration(referenceDuration, referenceBIPS);
    118        if (currentDuration > ajustedDuration * SLACK_FACTOR) {
    119            throw new AssertionFailedError("current duration " + currentDuration + " exceeded expected " + ajustedDuration + " (adjusted reference), "
    120                            + referenceDuration + " (raw reference)");
    121        }
    122    }
    123
    124    /**
    125     * Assertion used for values that <b>increase<b> with faster CPUs, typically
    126     * the number of operations accomplished per unit of time.
    127     *
    128     * @param currentPerformance
    129     * @param referencePerformance
    130     * @param referenceBIPS
    131     * @throws AssertionFailedError
    132     */
    133    public static void assertPerformance(double currentPerformance, long referencePerformance, double referenceBIPS) throws AssertionFailedError {
    134        double ajustedPerf = adjustExpectedPerformance(referencePerformance, referenceBIPS);
    135        if (currentPerformance * SLACK_FACTOR < ajustedPerf) {
    136            throw new AssertionFailedError(currentPerformance + " below expected " + ajustedPerf + " (adjusted), " + referencePerformance + " (raw)");
    137        }
    138    }
    139
    140    private static double adjustExpectedPerformance(long referenceDuration, double referenceBIPS) {
    141        double currentBIPS = currentBIPS();
    142        return referenceDuration * (currentBIPS / referenceBIPS);
    143    }
    144
    145    private static double adjustExpectedDuration(long referenceDuration, double referenceBIPS) {
    146        double currentBIPS = currentBIPS();
    147        System.out.println("currentBIPS=" + currentBIPS + " BIPS");
    148        return referenceDuration * (referenceBIPS / currentBIPS);
    149    }
    150}