Создать быстрый / надежный тест с помощью Java? - PullRequest
5 голосов
/ 16 июня 2011

Я пытаюсь создать тест с помощью Java.В настоящее время у меня есть следующий простой метод:

public static long runTest(int times){
    long start = System.nanoTime();     
    String str = "str";
    for(int i=0; i<times; i++){
        str = "str"+i;
    }       
    return System.nanoTime()-start;     
}

В настоящее время у меня есть этот цикл несколько раз в другом цикле, который происходит несколько раз, и получаю минимальное / максимальное / среднее время, необходимое для запуска этого метода,Затем я начинаю некоторые действия в другом потоке и снова тестирую.По сути, я просто хочу получить последовательные результаты ... Кажется, довольно последовательным, если у меня есть цикл runTest 10 миллионов раз:

Number of times ran: 5
The max time was: 1231419504 (102.85% of the average)
The min time was: 1177508466 (98.35% of the average)
The average time was: 1197291937
The difference between the max and min is: 4.58%

Activated thread activity.

Number of times ran: 5
The max time was: 3872724739 (100.82% of the average)
The min time was: 3804827995 (99.05% of the average)
The average time was: 3841216849
The difference between the max and min is: 1.78%

Running with thread activity took 320.83% as much time as running without.

Но это кажется немного большим, и занимает некоторое время ... еслиЯ пробую меньшее число (100000) в цикле runTest ... оно начинает становиться очень непоследовательным:

    Number of times ran: 5
    The max time was: 34726168 (143.01% of the average)
    The min time was: 20889055 (86.02% of the average)
    The average time was: 24283026
    The difference between the max and min is: 66.24%

    Activated thread activity.

    Number of times ran: 5
    The max time was: 143950627 (148.83% of the average)
    The min time was: 64780554 (66.98% of the average)
    The average time was: 96719589
    The difference between the max and min is: 122.21%

    Running with thread activity took 398.3% as much time as running without.

Есть ли способ, которым я могу сделать такой тест, который будет последовательным и эффективным /быстро?

Кстати, я не тестирую код, который находится между временем начала и окончания.Я тестирую загрузку процессора некоторым способом (посмотрите, как я запускаю некоторую активность потока и повторное тестирование).Поэтому я думаю, что то, что я ищу, может заменить код, который у меня есть в «runTest», что даст более быстрые и согласованные результаты.

Спасибо

Ответы [ 3 ]

5 голосов
/ 19 августа 2011

Короче говоря:

(Микро) бенчмаркинг очень сложен, поэтому используйте такой инструмент, как инфраструктура бенчмаркинга http://www.ellipticgroup.com/misc/projectLibrary.zip - и все же скептически относитесь к результатам («Поместите микро-доверие в микро-бенчмарк», доктор Клифф Нажмите).

Подробно:

Существует множество факторов, которые могут сильно повлиять на результаты:

  • Точность и точность System.nanoTime: в худшем случае он так же плох, как и System.currentTimeMillis.
  • код разогрева и загрузки классов
  • смешанный режим: JIT-компиляция JVM (см. Ответ Эдвина Бака) только после того, как блок кода вызывается достаточно часто (1500 или 1000 раз)
  • динамическая оптимизация: деоптимизация, замена в стеке, удаление мертвого кода (вы должны использовать результат, который вы вычислили в цикле, например, распечатать его)
  • восстановление ресурса: коллекция предметов (см. Ответ Михаила Боргвардта) и завершение объекта
  • кеширование: ввод / вывод и процессор
  • ваша операционная система в целом: заставка, управление питанием, другие процессы (индексатор, сканирование на вирусы, ...)

Статья Брента Бойера «Надежный бенчмаркинг Java, часть 1: проблемы» (http://www.ibm.com/developerworks/java/library/j-benchmark1/index.html) - хорошее описание всех этих проблем и того, можно ли / что вы можете с ними сделать (например, используйте параметры JVM или предварительно вызовите ProcessIdleTask) .

Вы не сможете устранить все эти факторы, поэтому хорошая статистика - хорошая идея. Но:

  • вместо того, чтобы вычислять разницу между максимальным и минимальным, вы должны приложить усилия для вычисления стандартного отклонения (результаты {1, 1000 × 2, 3} отличаются от {501 × 1, 501 × 3}) ,
  • Надежность учитывается путем создания доверительных интервалов (например, с помощью начальной загрузки).

Упомянутая выше платформа Benchmark (http://www.ellipticgroup.com/misc/projectLibrary.zip) использует эти методы. Вы можете прочитать о них в статье Брента Бойера "Надежный тест Java, Часть 2: Статистика и решения" (https://www.ibm.com/developerworks/java/library/j-benchmark2/).

1 голос
/ 16 июня 2011

Ваш код заканчивается тестированием в основном производительности сборки мусора, потому что добавление строки в цикл приводит к созданию и немедленному отбрасыванию большого количества все более крупных объектов String.

Это то, что по своей сути приводит к дико меняющимся измерениям и сильно зависит от многопоточной активности.

Я предлагаю вам сделать что-то еще в вашем цикле с более предсказуемой производительностью, например, математические вычисления.

0 голосов
/ 16 июня 2011

При 10-миллионном прогоне шансы хороши: компилятор HotSpot обнаружил «интенсивно используемый» фрагмент кода и скомпилировал его в машинный собственный код.

Байт-код JVM интерпретируется, что приводит к его восприимчивости к большему количествупрерывания от других фоновых процессов, происходящих в JVM (например, сборщик мусора).

Вообще говоря, эти виды тестов изобилуют предположениями, которые не выполняются.Вы не можете поверить, что микропроцессор действительно доказывает то, что он намеревался доказать, без большого количества доказательств того, что первоначальное измерение (время) на самом деле не измеряет вашу задачу и, возможно, некоторые другие фоновые задачи.Если вы не пытаетесь контролировать фоновые задачи, то измерение гораздо менее полезно.

...