Java curious Loop Performance
У меня есть большая проблема при оценке моего java-кода. Чтобы упростить задачу, я написал следующий код, который вызывает одно и то же любопытное поведение. Важным является метод run() и заданный коэффициент двойного значения. Для моего теста времени выполнения (в основном методе) я устанавливал скорость 0,5 раза и 1,0 в другое время. При значении 1.0 if-statement будет выполняться в каждой итерации цикла и со значением 0.5, if-statement будет выполняться в два раза меньше. По этой причине я ожидал более продолжительное время выполнения в первом случае, но наоборот.
Может ли кто-нибудь объяснить мне это явление?
Результат main:
Test mit rate = 0.5
Length: 50000000, IF executions: 25000856
Execution time was 4329 ms.
Length: 50000000, IF executions: 24999141
Execution time was 4307 ms.
Length: 50000000, IF executions: 25001582
Execution time was 4223 ms.
Length: 50000000, IF executions: 25000694
Execution time was 4328 ms.
Length: 50000000, IF executions: 25004766
Execution time was 4346 ms.
=================================
Test mit rate = 1.0
Length: 50000000, IF executions: 50000000
Execution time was 3482 ms.
Length: 50000000, IF executions: 50000000
Execution time was 3572 ms.
Length: 50000000, IF executions: 50000000
Execution time was 3529 ms.
Length: 50000000, IF executions: 50000000
Execution time was 3479 ms.
Length: 50000000, IF executions: 50000000
Execution time was 3473 ms.
Код
public ArrayList<Byte> list = new ArrayList<Byte>();
public final int LENGTH = 50000000;
public PerformanceTest(){
byte[]arr = new byte[LENGTH];
Random random = new Random();
random.nextBytes(arr);
for(byte b : arr)
list.add(b);
}
public void run(double rate){
byte b = 0;
int count = 0;
for (int i = 0; i < LENGTH; i++) {
if(getRate(rate)){
list.set(i, b);
count++;
}
}
System.out.println("Length: " + LENGTH + ", IF executions: " + count);
}
public boolean getRate(double rate){
return Math.random() < rate;
}
public static void main(String[] args) throws InterruptedException {
PerformanceTest test = new PerformanceTest();
long start, end;
System.out.println("Test mit rate = 0.5");
for (int i = 0; i < 5; i++) {
start=System.currentTimeMillis();
test.run(0.5);
end = System.currentTimeMillis();
System.out.println("Execution time was "+(end-start)+" ms.");
Thread.sleep(500);
}
System.out.println("=================================");
System.out.println("Test mit rate = 1.0");
for (int i = 0; i < 5; i++) {
start=System.currentTimeMillis();
test.run(1.0);
end = System.currentTimeMillis();
System.out.println("Execution time was "+(end-start)+" ms.");
Thread.sleep(500);
}
}
Ответы
Ответ 1
Неправильное предсказание отрасли убивает производительность в первом случае. Хотя второй случай делает некоторые работы, он несколько прямолинейный, поэтому процессор может легко предсказать следующий шаг. Для получения дополнительной информации см. Эту страницу Википедии.
Попробуйте выполнить тестирование с помощью 0,7. Если я прав, производительность будет где-то между 0,5 и 1,0.
Ответ 2
Чтобы подтвердить, что вы видите эффекты неверного предсказания ветки как указано в моем комментарии, я провел несколько тестов. В таблице показана скорость (ввод в метод запуска), количество выполняемых if
и время выполнения.
0.0 0 1162
0.1 5,000,892 1204.25
0.2 10,002,410 1236.8
0.3 14,998,226 1264
0.4 19,996,983 1278
0.5 24,998,455 1305.5
0.6 29,998,879 1263.25
0.7 34,999,821 1232.25
0.8 39,999,414 1203.5
0.9 44,998,674 1202
1.0 50,000,000 1176.75
Чем ближе вы доходите до 0,5, тем больше у вас ошибочных прогнозов ветки (примерно один раз подряд). Чем ближе вы доходите до 0 или 1, тем более точными предсказаниями отрасли вы получите (без ложных предсказаний, когда ставка равна 0 или 1).
И поскольку изображение стоит тысячи слов:
![enter image description here]()
Ответ 3
Очень похоже на Почему обработка отсортированного массива выполняется быстрее, чем несортированный массив? И есть те же причины за кулисами.