Java计算平均执行时间

时间:2011-12-04 20:43:04

标签: java

我想计算x次运行的平均执行时间(即10次)...我可以使用main方法中的循环轻松执行10次,但是如何存储执行时间&计算平均值?我觉得这很简单,但我现在正在画一个空白......感谢先进!

import java.util.Arrays;
import java.util.Random;

public class OptQSort1 {

static boolean insertionSortCalled = false;
private static final Random random = new Random();
private static final int RANDOM_INT_RANGE = 9999;

private static int[] randomArray(int size) {

    // Randomize data (array)
    final int[] arr = new int[size];
    for (int i = 0; i < arr.length; i++) {
        arr[i] = random.nextInt(RANDOM_INT_RANGE);
    }
    return arr;
}

// Sort
private static void sort(int[] arr) {
    if (arr.length > 0)
        sortInPlace(arr, 0, arr.length - 1);
}

private static void sortInPlace(int[] arr, int left, int right) {



    // OptQSort1:
    int size = right - left + 1;
    if (size < 10 && !insertionSortCalled) {
        insertionSortCalled = true;
        insertionSort(arr, 0, arr.length - 1);
    }

    if (left >= right)
        return; // sorted

    final int range = right - left + 1;
    int pivot = random.nextInt(range) + left;

    int newPivot = partition(arr, left, right, pivot);

    sortInPlace(arr, left, newPivot - 1);
    sortInPlace(arr, newPivot + 1, right);

}

private static int partition(int[] arr, int left, int right, int pivot) {

    int pivotVal = arr[pivot];
    swapArrayVals(arr, pivot, right);

    int storeIndex = left;
    for (int i = left; i <= (right - 1); i++) {
        if (arr[i] < pivotVal) {
            swapArrayVals(arr, i, storeIndex);
            storeIndex++;
        }
    }

    swapArrayVals(arr, storeIndex, right);

    return storeIndex;
}

private static void swapArrayVals(int[] arr, int from, int to) {
    int fromVal = arr[from];
    int toVal = arr[to];
    arr[from] = toVal;
    arr[to] = fromVal;
}

public static void insertionSort(int[] arr, int left, int right) {
    int in, out;

    for (out = left + 1; out <= right; out++) {
        int temp = arr[out];
        in = out;

        while (in > left && arr[in - 1] >= temp) {
            arr[in] = arr[in - 1];
            --in;
        }
        arr[in] = temp;
    }

}

public static void main(String[] args) {

    long StartTime = System.nanoTime();

    int runCount = 0;

    // Array size
    int[] arr = randomArray(1000);
    int[] copy = Arrays.copyOf(arr, arr.length);

    // Print original data (array)
    System.out.println("The starting/unsorted array: \n"
            + Arrays.toString(arr));

    sort(arr);

    do {
    // check the result
    Arrays.sort(copy);
    if (Arrays.equals(arr, copy)) {
        System.out.println("The ending/sorted array: \n"
                + Arrays.toString(arr));


        // print time
        long TotalTime = System.nanoTime() - StartTime;
        System.out.println("Total elapsed time (milliseconds) " + "is: "
                + TotalTime + "\n");

        runCount++;
    } 
    }   while (runCount < 10);
}

} 

5 个答案:

答案 0 :(得分:4)

要计算平均时间,您需要时间总和。时间总和是总时间,因此您甚至不需要知道个别时间或记录它们。只需采用端到端时间并除以计数。

int count = ...
long start = System.nanoTime();
for(int i=0;i<count;i++) {
    // do something
}
long time = System.nanoTime() - start;
long averageTime = time/count;

在您完成至少10,000次迭代之前,JIT不会完全预热,因此如果可行,您可能会忽略前11,000次。

一种简单的方法是

int count = ...
long start = 0;
for(int i=-11000;i<count;i++) {
    if(i == 0) start = System.nanoTime();

    // do something
}
long time = System.nanoTime() - start;
long averageTime = time/count;

顺便说一句:只在测试时间内包含您想要的时间。例如,生成随机数可能需要比排序本身更长的时间,这可能会产生误导性的结果。

编辑:确定何时编译方法或循环的编译阈值由-XX:CompileThresholed=控制,在服务器JVM上默认为10000,在客户端JVM上默认为1500。 http://www.oracle.com/technetwork/java/javase/tech/vmoptions-jsp-140102.html

-XX:CompileThreshold=10000 Number of method invocations/branches before 
                           compiling [-client: 1,500]

答案 1 :(得分:4)

您可以通过测量代码的10次迭代的总时间来计算平均值,然后将其除以10。

e.g:

public static void main(String[] args) {
    long start = System.currentTimeMillis();
    for (int i = 0; i < 10; ++i) {
        doSort();
    }
    long elapsed = System.currentTimeMillis() - start;
    long average = elapsed / 10;
}

作为一个有用的提示,请使用命名常量而不是迭代次数的文字值:

private final static int ITERATIONS = 10;
public static void main(String[] args) {
    long start = System.currentTimeMillis();
    for (int i = 0; i < ITERATIONS; ++i) {
        doSort();
    }
    long elapsed = System.currentTimeMillis() - start;
    long average = elapsed / ITERATIONS;
}

这意味着如果您想要运行50或100次迭代,您只需在一个地方更改数字。

您还应该意识到,从这种实验中获得准确的计时结果非常困难。最好包括一个“预热”阶段,以允许JIT评估和优化代码,并获得更多的迭代次数:

private static final int WARMUP_ITERATIONS = 10000;
private static final int RUN_ITERATIONS = 100000;
public static void main(String[] args) {
    // Warmup with no timing
    for (int i = 0; i < WARMUP_ITERATIONS; ++i) {
        doSort();
    }

    // Now the real test
    long start = System.currentTimeMillis();
    for (int i = 0; i < RUN_ITERATIONS; ++i) {
        doSort();
    }
    long elapsed = System.currentTimeMillis() - start;
    long average = elapsed / RUN_ITERATIONS;
}

答案 2 :(得分:1)

您可以使用整数列表来存储每次运行的结果,但是您不需要它来计算平均值,只需将总时间除以运行次数。 顺便说一下,你的测量结果不是很好: 1)包括随机阵列的生成 2)没有进行10次运行

答案 3 :(得分:1)

执行前:

long start = System.currentTimeMillis();

执行后:

long end = System.currentTimeMillis();

每次都在这样的ArrayList中添加:

times.add(end-start);

获得平均时间:

Long total = 0;
for(Long l : times)
    total += l;

System.out.println("Average Time: "+(total/times.size()));

注意返回值的时间单位是毫秒。

答案 4 :(得分:0)

只需保留第二个long值,即Totaltime值的运行总计。当循环退出时,只需除以runCount

或者,创建一个ArrayList<Long>来存储时间。每次运行一次,将Totaltime添加到阵列。循环退出后,您可以平均值并计算其他统计数据(最小值/最大值,标准差等)。