Java Пример автоматической векторизации - PullRequest
3 голосов
/ 14 января 2020

Я пытаюсь найти краткий пример, который показывает автоматическую векторизацию в java в системе x86-64.

Я реализовал приведенный ниже код, используя y[i] = y[i] + x[i] в течение l oop. Этот код может выиграть от автоматической векторизации, поэтому я думаю, что java должен скомпилировать его во время выполнения, используя инструкции SSE или AVX, чтобы ускорить его.
Однако я не смог найти векторизованные инструкции в результирующем машинном коде. * Для 1007 *

VecOpMicroBenchmark.java должна использоваться автоматическая векторизация:

    /**
     * Run with this command to show native assembly:<br/>
     * java -XX:+UnlockDiagnosticVMOptions
     * -XX:CompileCommand=print,VecOpMicroBenchmark.profile VecOpMicroBenchmark
     */
    public class VecOpMicroBenchmark {

        private static final int LENGTH = 1024;

        private static long profile(float[] x, float[] y) {
            long t = System.nanoTime();

            for (int i = 0; i < LENGTH; i++) {
                y[i] = y[i] + x[i]; // line 14
            }

            t = System.nanoTime() - t;

            return t;
        }

        public static void main(String[] args) throws Exception {
            float[] x = new float[LENGTH];
            float[] y = new float[LENGTH];

            // to let the JIT compiler do its work, repeatedly invoke
            // the method under test and then do a little nap
            long minDuration = Long.MAX_VALUE;
            for (int i = 0; i < 1000; i++) {
                long duration = profile(x, y);
                minDuration = Math.min(minDuration, duration);
            }
            Thread.sleep(10);

            System.out.println("\n\nduration: " + minDuration + "ns");
        }
    }

Чтобы выяснить, векторизована ли она, я сделал следующее:

  1. открытое затмение и создайте указанный выше файл.
  2. щелкните файл правой кнопкой мыши и в раскрывающемся меню выберите Выполнить> Java Приложение (пока игнорируйте вывод)
  3. в меню затмения нажмите Выполнить> Запустить конфигурации ...
  4. в открывшемся окне найдите VecOpMicroBenchmark , щелкните его и выберите вкладку Аргументы
  5. на вкладке Аргументы, в разделе Аргументы виртуальной машины: введите следующее: -XX:+UnlockDiagnosticVMOptions -XX:CompileCommand=print,VecOpMicroBenchmark.profile
  6. получите libhsdis и скопируйте (возможно переименуйте) ) файл hsdis-amd64.so (.dll для windows) в каталог java / lib. В моем случае это было /usr/lib/jvm/java-11-openjdk-amd64/lib.
  7. снова запустить VecOpMicroBenchmark

Теперь он должен выводить на консоль большое количество информации, частью которой является дизассемблированный машинный код, созданный компилятором JIT. Если вы видите много сообщений, но нет инструкций по сборке, таких как mov, push, add, et c, то, возможно, вы можете где-нибудь найти следующее сообщение: Could not load hsdis-amd64.so; library not loadable; PrintAssembly is disabled Это означает, что java cann ' t * найти файл hsdis-amd64.so - он не находится в правильном каталоге или не имеет правильного имени.

hsdis-amd64.so - дизассемблер, который необходим для отображения результирующего собственного машинного кода. После того, как JIT-компилятор скомпилирует байт-код java в собственный машинный код, hsdis-amd64.so используется для дизассемблирования собственного машинного кода, чтобы сделать его читаемым человеком. Вы можете найти больше информации о том, как получить / установить его в Как увидеть JIT-скомпилированный код в JVM? .

После нахождения инструкций по сборке в выводе, я пролистал его (тоже много, чтобы опубликовать все это здесь) и искал line 14. Я нашел это:

0x00007fac90ee9859: nopl    0x0(%rax)
0x00007fac90ee9860: cmp     0xc(%rdx),%esi    ; implicit exception: dispatches to 0x00007fac90ee997f
0x00007fac90ee9863: jnb     0x7fac90ee9989
0x00007fac90ee9869: movsxd  %esi,%rbx
0x00007fac90ee986c: vmovss  0x10(%rdx,%rbx,4),%xmm0  ;*faload {reexecute=0 rethrow=0 return_oop=0}
                                            ; - VecOpMicroBenchmark::profile@16 (line 14)

0x00007fac90ee9872: cmp     0xc(%rdi),%esi    ; implicit exception: dispatches to 0x00007fac90ee9997
0x00007fac90ee9875: jnb     0x7fac90ee99a1
0x00007fac90ee987b: movsxd  %esi,%rbx
0x00007fac90ee987e: vmovss  0x10(%rdi,%rbx,4),%xmm1  ;*faload {reexecute=0 rethrow=0 return_oop=0}
                                            ; - VecOpMicroBenchmark::profile@20 (line 14)

0x00007fac90ee9884: vaddss  %xmm1,%xmm0,%xmm0
0x00007fac90ee9888: movsxd  %esi,%rbx
0x00007fac90ee988b: vmovss  %xmm0,0x10(%rdx,%rbx,4)  ;*fastore {reexecute=0 rethrow=0 return_oop=0}
                                            ; - VecOpMicroBenchmark::profile@22 (line 14)

Так что он использует инструкцию AVX vaddss. Но, если я здесь прав, vaddss означает добавить скалярные значения с плавающей точкой одинарной точности , и это только добавляет одно значение с плавающей запятой к другому (здесь scalar означает только один , тогда как здесь single означает 32 бита, т.е. float, а не double).
Здесь я ожидаю vaddps, что означает add упакованные значения с плавающей точкой одинарной точности , которые являются истинной SIMD-инструкцией (SIMD = одиночная команда, множественные данные = векторизованная команда). Здесь pack означает несколько поплавков, упакованных вместе в один регистр .

О ..ss и ..ps см. http://www.songho.ca/misc/sse/sse.html :

SSE определяет два типа операций; скалярный и упакованный. Скалярная операция работает только с наименее значимым элементом данных (бит 0 ~ 31), а упакованная операция вычисляет все четыре элемента параллельно. Инструкции SSE имеют суффикс -ss для скалярных операций (Single Scalar) и -ps для упакованных операций (Parallel Scalar).

Queston:
Это мой java пример неверен или почему в выводе нет инструкции SIMD?

...