огромная разница в производительности для пустого цикла между Java 32 и 64 бит - PullRequest
0 голосов
/ 20 февраля 2012

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

Но мне нужно было, чтобы это заняло больше времени, поэтому я вставил этот код в простое вычисление:

for (int i = 0; i < 1000000; i++)
{
    // Nothing.
}

В течение долгого времени я писал и компилировал код на 64-битной машине и тестировал его на ряде 32-битных машин.

Затем я запустил его на 64-битной машине и заметил огромную разницу в производительности.

С тем же кодом для полностью аналогичной 64 машины требуется <100 мс, что для 32 машины ~ 52000 мс (2 виртуальные машины на одном хосте). </p>

Я тестировал на Windows и Ubuntu на разных компьютерах, и, используя один и тот же файл .class, я все еще получаю эту огромную разницу между 32 и 64 битами.

Вот быстрый код, который вы можете использовать, чтобы повторить разницу в производительности.

import java.util.ArrayList;
import java.util.Collection;
public class Test {
public static void main(String[] args)
{
    long start = System.currentTimeMillis();
    int j = 2;
    ArrayList<Integer> res = new ArrayList<Integer>();
    for (int k = 0; k < 50000; k++)
    {
        Collection<Integer> partres = work(k);
        if (partres != null)
            res.addAll(work(k));
    }
    long end = System.currentTimeMillis();
    System.out.println("Done in " + (end-start) + " ms.");
}
public static Collection<Integer> work(Integer j) {
    for (int i = 0; i < 1000000; i++)
    {
        // Nothing.
    }
    if (isPrime(j))
    {
        ArrayList<Integer> res = new ArrayList<Integer>();
        res.add(j);
        return res;
    }
    else
        return null;
}
static boolean isPrime(int n) {
    if (n == 2) return true;
    if (n%2==0) return false;
    for(int i = 3; i * i <= n; i += 2) 
        if(n%i==0)
            return false;
    return true;
}
}

И вот файл .class, в который я скомпилировал его.

Теперь мой вопрос.

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

Ответы [ 2 ]

4 голосов
/ 20 февраля 2012

64-битная Java всегда использует JIT-компилятор -server, тогда как ваша 32-битная JVM, вероятно, использовала JIT-компилятор -client.

Когда С2 ака. -сервер компилятор видит что-то вроде этого:

for (int i = 0; i < 1000000; i++)
{
  // Nothing.
}

Он заметит, что цикл ничего не делает, и удаляет его! Ваш цикл, который ничего не делает, будет оптимизирован в ничто.

Чтобы помешать этой оптимизации, вам нужно будет заставить цикл делать что-то - например, он может XOR всех этих i вместе - и использовать результат . Тогда цикл будет выглядеть для компилятора как настоящая работа, и код будет сохранен.

3 голосов
/ 20 февраля 2012

В Windows будет использоваться -client JVM по умолчанию для 32-разрядной и -server для 64-разрядной JVM. Серверная JVM более агрессивна в удалении кода, который ничего не делает. например пустые петли. Вы обнаружите, что такой цикл занимает примерно одинаковое количество времени, независимо от лимита подсчета, поскольку он зависит от количества времени, которое требуется для обнаружения и устранения цикла. Попробуйте добавить второй синхронизированный цикл к тому же методу, и вы обнаружите, что это занимает почти нет времени, независимо от того, какое максимальное значение вы установили (при условии, что это не бесконечный цикл). Это потому, что метод будет скомпилирован ко времени второго цикла. начинается.

http://docs.oracle.com/javase/1.5.0/docs/guide/vm/server-class.html

Кстати: я бы использовал nanoTime и повторял бы ваши тесты по крайней мере пару секунд.

...