В языке Java все операции над целыми числами производятся в int. Таким образом, если мы будем использовать индекс short as loop, на каждой итерации будет производиться типизация, что на самом деле тяжелее простого воздействия на int.
Я написал этот код для достижения моей цели:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
|
package com.wicht.old; public class TestShortInt { public static void main(String[] args){ long startTime = System.nanoTime(); int resultInt = 0 ; for ( int i = 0 ; i < 100000 ; i++){ for ( int j = 0 ; j < 32760 ; j++){ resultInt += i * j; } } System.out.println( "Temp pour int : " + (System.nanoTime() - startTime) / 1000000 + " ms" ); startTime = System.nanoTime(); int resultShort = 0 ; for ( int k = 0 ; k < 100000 ; k++){ for ( short f = 0 ; f < 32760 ; f++){ resultShort += k * f; } } System.out.println( "Temp pour short : " + (System.nanoTime() - startTime) / 1000000 + " ms" ); System.out.println(resultInt); System.out.println(resultShort); } } |
И в результате я обнаружил, что short был в два раза медленнее, чем int, и я был убежден в этих результатах до недели назад.
В это время читатель (Жан) раскритиковал результаты моих тестов и дал мне ссылки на несколько статей о микро-бенчмаркинге . Я прочитал эти статьи и понимаю, почему мои результаты были неверными.
Фактически, мой тест не обращает внимания на несколько вещей, которые могут изменить результаты тестов:
- Разминка JVM : из-за нескольких параметров код сначала часто медленен и становится все быстрее и быстрее, когда время выполнения увеличивается до тех пор, пока оно не перейдет в устойчивое состояние.
- Загрузка классов : при первом запуске бенчмарка все используемые классы должны быть загружены, что увеличивает время выполнения.
- Компилятор Just In Time : когда JVM идентифицирует горячую часть кода
- Сборщик мусора : Сборка мусора может происходить во время теста, и с этим время может значительно увеличиться.
Из-за всех этих факторов первые прогоны (возможно, 10 секунд пробега) медленнее других и могут сделать ваши тесты полностью ложными.
Итак, как мы можем добиться хороших результатов тестов?
Это действительно сложно, но мы можем помочь в использовании эталонной среды, представленной Брентом Бойером, разработчиком программного обеспечения из Elliptic Group. Эта структура учитывает все ранее введенные факторы и делает хорошие контрольные показатели.
Использовать этот фреймворк очень просто: вам просто нужно создать новый экземпляр класса Benchmark, передав ему Callable или Runnable, и тест будет запущен напрямую. Вот пример с тестом short и int в индексах цикла:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
|
public class ShortIndexesLoop { public static void main(String[] args) { Callable callableInt = new Callable(){ public Long call() throws Exception { long result = 0 ; for ( int f = 0 ; f < 32760 ; f++){ result += 444 ; } return result; } }; Callable callableShort = new Callable(){ public Long call() throws Exception { long result = 0 ; for ( short f = 0 ; f < 32760 ; f++){ result += 444 ; } return result; } }; try { Benchmark intBenchmark = new Benchmark(callableInt); System.out.println( "Result with int " ); System.out.println(intBenchmark.toString()); Benchmark shortBenchmark = new Benchmark(callableShort); System.out.println( "Result short " ); System.out.println(shortBenchmark.toString()); } catch (Exception e) { e.printStackTrace(); } } } |
Чтобы получить результаты, вы можете использовать Benchmark.toString () или Benchmark.toStringFull () для получения дополнительной статистики. Вы также можете напрямую получить доступ к некоторым статистическим данным, таким как стандартное отклонение, используя Benchmark.getSd () или напрямую с помощью Benchmark.getStats (), чтобы получить всю статистику.
Вот результат с предыдущим кодом:
Результат int first = 807.056 us, среднее = 46.032 us (дельты CI: -261.393 нс, +408.932 нс), sd = 230.929 us (дельты CI: -68.201 us, +105.262 us)
Результат короткий первый = 721,912 долл. США, среднее значение = 48,234 долл. США (дельта CI: -198,625 нс, +254,774 нс), сд = 160,196 долл. США (дельта CI: -32,764 долл. США, +37,882 долл. США)
Как видите, короткая версия всего на 104.78% медленнее, чем int. Это показывает, что первые результаты были полностью ложными.
Вот полные результаты версии int:
статистика действий: первая = 807,056 мкс, средняя = 46,032 мкс (дельта CI: -261,393 нс, +408,932 нс), sd = 230,929 мкс (дельта CI: -68,21 мкс, +105,262 мкс) ЗНАЧЕНИЯ МОГУТ БЫТЬ НЕ ТОЧНЫМИ ———- — статистика действий была рассчитана из статистики блоков — каждый блок измерял 32768 выполнений задач — пользователь говорит, что задача внутренне выполняет m = 1 действий — тогда число действий на измерение блока составляет = 32768 — статистика блока: среднее значение = 1,508 с (дельта CI: -8,565 мс, +13,400 мс), SD = 41,803 мс (дельта CI: -12,346 мс, +19,054 мс) — форум, используемый для преобразования статистики блока в статистику действий (средние масштабы) как 1 / a, sd масштабируется как 1 / sqrt (a)) предполагает, что времена выполнения действия iid ———– — каждый доверительный интервал (CI) сообщается либо как + — дельты от оценки точки, либо как закрытый интервал ([x, y]) — каждый доверительный интервал имеет доверительный уровень = 0,95 это было определено с использованием алгоритма коробчатого графика с медианой = 1.498 с, interquantileRange = 34.127 мс –3 являются ОЧЕНЬ экстремальными (с высокой стороны): # 57 = 1.621 с, # 58 = 1.647 с, # 59 = 1.688 с –2 мягкие ( на высокой стороне): # 55 = 1,570 с, # 56 = 1,582 с —блок-значения sd блока МОГУТ НЕ ОТРАЖАТЬ ВНУТРЕННЕЕ ИЗМЕНЕНИЕ ЗАДАЧИ — оценка: шум окружающей среды объясняет не менее 55,8941862187682222% от измеренного sd ———- — Значения sd действия ПОЧТИ МОЖНО БЕЗУМНО НАДВИЖЕНЫ выбросами — они вызывают не менее 98,95646276911543% от измеренного ВАРИАНТА согласно эквивалентной модели выбросов — количества моделей: a = 32768.0, muB = 1.5083895562166663, sigmaB = 0.041802646686166164676776771482674674164163483,1683,1683,1683,1683,1683 по номеру устройства: , sigmaA = 2.3092919283255957E-4, Tmin = 0,0, muGMin = 2.3016198062388096E-5, sigmaG = 5.754049515597024E-6, cMax1 = 1252, cMax2 = 322, Cmax = 322, cOutMin = 322, varOutMin = +0,0017292260645147487, MUG (cOutMin) = 2,3034259031465023E-5, U (cOutMin) = 0,002363416110812895
Как вы, возможно, можете видеть, когда используете эту платформу, она дает вам некоторые предупреждения, когда, например, у вас есть экстремальные выбросы, которые могут сделать стандартное отклонение полностью ложным.
Вы можете скачать эту структуру на веб-странице Elliptic Group . Я нашел его действительно мощным и простым в использовании, и буду использовать его каждый раз, когда мне нужно будет сделать тест.
В заключение я также должен сказать, что даже если вы используете такую среду, вы можете делать очень плохие тесты, если не тестируете правильную часть кода. Вот две действительно интересные статьи от Брента Бойера:
- Надежный Java-бенчмаркинг, часть 1: проблемы
- Надежный Java-бенчмаркинг, часть 2: статистика и решения
Ссылка: Как написать правильные тесты от нашего партнера JCG Баптиста Вихта в
- Беспокойство производительности — на непредсказуемости производительности, ее измерении и сравнительном анализе
- Советы по повышению производительности приложений Java
- Как получить C как производительность в Java
- Низкий GC в Java: используйте примитивы вместо оболочек
- Как сделать 100K TPS с задержкой менее 1 мс