Вопрос по java – Генерируют ли какие-либо JIT-компиляторы JVM код, который использует векторизованные инструкции с плавающей точкой?

88

Допустим, узким местом моей Java-программы на самом деле являются некоторые узкие циклы для вычисления набора векторных точечных продуктов. Да, я профилировал, да, это узкое место, да, это важно, да, именно таков алгоритм, да, я запускаю Proguard для оптимизации байт-кода и т. Д.

Работа, по сути, точечные продукты. Как и у меня есть дваfloat[50] и мне нужно вычислить сумму попарных произведений. Я знаю, что существуют наборы инструкций процессора для быстрого и массового выполнения таких операций, таких как SSE или MMX.

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

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

Вероятно, «нет»; стоит спросить.

Или посмотрите на источник.download.java.net/openjdk/jdk7 Bill
& quot; скоро & quot; JDK рядом с вами:mail.openjdk.java.net/pipermail/hotspot-compiler-dev/2012-July/… Jonathan S. Fisher
На самом деле, согласноthis blogJNI может быть довольно быстрым, если его использовать "правильно". ziggystar
Самый простой способ выяснить это, вероятно, получить самый современный JIT, который вы можете найти, и заставить его выводить сгенерированную сборку с-XX:+UnlockDiagnosticVMOptions -XX:+PrintAssembly -XX:+LogCompilation, Вам понадобится программа, которая запускает векторизуемый метод достаточно много раз, чтобы сделать его "горячим". Louis Wasserman
Соответствующее сообщение в блоге по этому вопросу можно найти здесь:psy-lob-saw.blogspot.com/2015/04/… с общим сообщением, что векторизация может произойти, и действительно происходит. Помимо векторизации конкретных случаев (Arrays.fill () / equals (char []) / arrayCopy), JVM автоматически векторизуется с использованием параллелизации на уровне суперслов. Соответствующий код находится в superword.cpp, а документ, на котором он основан, находится здесь:groups.csail.mit.edu/cag/slp/SLP-PLDI-2000.pdf Nitsan Wakart

Ваш Ответ

8   ответов
3

Я предполагаю, что вы написали этот вопрос до того, как узнали о netlib-java ;-), он обеспечивает именно тот нативный API, который вам необходим, с реализациями, оптимизированными для машины, и не требует каких-либо затрат на нативной границе из-за закрепления памяти.

Error: User Rate Limit Exceeded Sean Owen
25

В версиях HotSpot, начиная с Java 7u40, компилятор сервера обеспечивает поддержку автоматической векторизации. В соответствии сJDK-6340864

Однако, похоже, что это верно только для «простых циклов» - по крайней мере, на данный момент. Например, накопление массива еще не может быть векторизованоJDK-7192383

Error: User Rate Limit Exceededprestodb.rocks/code/simd
Error: User Rate Limit Exceededmail.openjdk.java.net/pipermail/hotspot-compiler-dev/2017-June/…
Error: User Rate Limit Exceededcr.openjdk.java.net/~vlivanov/talks/…
Error: User Rate Limit Exceeded
Error: User Rate Limit Exceeded
4

Вы можете написать ядро OpenCl, чтобы сделать вычисления и запустить его из Javahttp://www.jocl.org/.

Код может выполняться на процессоре и / или графическом процессоре, а язык OpenCL поддерживает также векторные типы, поэтому вы должны иметь возможность явно использовать, например, преимущество. Инструкции SSE3 / 4.

5

Вот хорошая статья об экспериментировании с инструкциями Java и SIMD, написанными моим другом: http://prestodb.rocks/code/simd/

В целом вы можете ожидать, что JIT будет использовать некоторые операции SSE в версии 1.8 (и некоторые другие в версии 1.9). Хотя вы не должны ожидать многого, и вы должны быть осторожны.

Error: User Rate Limit Exceeded
3

Посмотри наСравнение производительности между Java и JNI для оптимальной реализации вычислительных микроядер, Они показывают, что компилятор сервера Java HotSpot VM поддерживает автоматическую векторизацию с использованием параллелизма на уровне суперслов, что ограничивается простыми случаями параллелизма внутри цикла. Эта статья также даст вам некоторые рекомендации относительно того, достаточно ли велик ваш размер данных, чтобы оправдать переход на JNI-маршрут.

-3

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

Error: User Rate Limit Exceededmail.openjdk.java.net/pipermail/hotspot-compiler-dev/…
36

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

  • Create a JMH project
  • Write a small snippet of vectorizable math.
  • Run their benchmark flipping between -XX:-UseSuperWord and -XX:+UseSuperWord(default)
  • If no difference in performance is observed, your code probably didn't get vectorized
  • To make sure, run your benchmark such that it prints out the assembly. On linux you can enjoy the perfasm profiler('-prof perfasm') have a look and see if the instructions you expect get generated.

Пример:

@Benchmark
@CompilerControl(CompilerControl.Mode.DONT_INLINE) //makes looking at assembly easier
public void inc() {
    for (int i=0;i<a.length;i++)
        a[i]++;// a is an int[], I benchmarked with size 32K
}

Результат с флагом и без него (на недавнем ноутбуке Haswell, Oracle JDK 8u60): -XX: + UseSuperWord: 475.073 & # xB1; 44,579 нс / операция (наносекунд на операцию) -XX: -UseSuperWord: 3376.364 & # xB1; 233,211 нс / оп

Сборка для горячего цикла немного сложна для форматирования и вставления, но здесь есть фрагмент (hsdis.so не может отформатировать некоторые векторные инструкции AVX2, поэтому я запустил -XX: UseAVX = 1): -XX: + UseSuperWord (с «-prof perfasm: intelSyntax = true»)

  9.15%   10.90%  │││ │↗    0x00007fc09d1ece60: vmovdqu xmm1,XMMWORD PTR [r10+r9*4+0x18]
 10.63%    9.78%  │││ ││    0x00007fc09d1ece67: vpaddd xmm1,xmm1,xmm0
 12.47%   12.67%  │││ ││    0x00007fc09d1ece6b: movsxd r11,r9d
  8.54%    7.82%  │││ ││    0x00007fc09d1ece6e: vmovdqu xmm2,XMMWORD PTR [r10+r11*4+0x28]
                  │││ ││                                                  ;*iaload
                  │││ ││                                                  ; - psy.lob.saw.VectorMath::[email protected] (line 45)
 10.68%   10.36%  │││ ││    0x00007fc09d1ece75: vmovdqu XMMWORD PTR [r10+r9*4+0x18],xmm1
 10.65%   10.44%  │││ ││    0x00007fc09d1ece7c: vpaddd xmm1,xmm2,xmm0
 10.11%   11.94%  │││ ││    0x00007fc09d1ece80: vmovdqu XMMWORD PTR [r10+r11*4+0x28],xmm1
                  │││ ││                                                  ;*iastore
                  │││ ││                                                  ; - psy.lob.saw.VectorMath::[email protected] (line 45)
 11.19%   12.65%  │││ ││    0x00007fc09d1ece87: add    r9d,0x8            ;*iinc
                  │││ ││                                                  ; - psy.lob.saw.VectorMath::[email protected] (line 44)
  8.38%    9.50%  │││ ││    0x00007fc09d1ece8b: cmp    r9d,ecx
                  │││ │╰    0x00007fc09d1ece8e: jl     0x00007fc09d1ece60  ;*if_icmpge

Весело штурмуйте замок!

Error: User Rate Limit Exceeded
Error: User Rate Limit Exceeded
Error: User Rate Limit Exceeded
Error: User Rate Limit Exceededagner.org/optimize/vectorclass.pdfError: User Rate Limit Exceeded
Error: User Rate Limit Exceeded
39

Итак, вы хотите, чтобы ваш код работал быстрее. JNI является ответом. Я знаю, что вы сказали, что это не сработало для вас, но позвольте мне показать вам, что вы не правы.

Здесь & APOS; sDot.java:

import java.nio.FloatBuffer;
import org.bytedeco.javacpp.*;
import org.bytedeco.javacpp.annotation.*;

@Platform(include="Dot.h", compiler="fastfpu")
public class Dot {
    static { Loader.load(); }

    static float[] a = new float[50], b = new float[50];
    static float dot() {
        float sum = 0;
        for (int i = 0; i < 50; i++) {
            sum += a[i]*b[i];
        }
        return sum;
    }
    static native @MemberGetter FloatPointer ac();
    static native @MemberGetter FloatPointer bc();
    static native float dotc();

    public static void main(String[] args) {
        FloatBuffer ab = ac().capacity(50).asBuffer();
        FloatBuffer bb = bc().capacity(50).asBuffer();

        for (int i = 0; i < 10000000; i++) {
            a[i%50] = b[i%50] = dot();
            float sum = dotc();
            ab.put(i%50, sum);
            bb.put(i%50, sum);
        }
        long t1 = System.nanoTime();
        for (int i = 0; i < 10000000; i++) {
            a[i%50] = b[i%50] = dot();
        }
        long t2 = System.nanoTime();
        for (int i = 0; i < 10000000; i++) {
            float sum = dotc();
            ab.put(i%50, sum);
            bb.put(i%50, sum);
        }
        long t3 = System.nanoTime();
        System.out.println("dot(): " + (t2 - t1)/10000000 + " ns");
        System.out.println("dotc(): "  + (t3 - t2)/10000000 + " ns");
    }
}

а такжеDot.h:

float ac[50], bc[50];

inline float dotc() {
    float sum = 0;
    for (int i = 0; i < 50; i++) {
        sum += ac[i]*bc[i];
    }
    return sum;
}

Мы можем скомпилировать и запустить это сJavaCPP используя командную строку эти:

$ javac -cp javacpp.jar Dot.java
$ java -jar javacpp.jar Dot
$ java -cp javacpp.jar:. Dot

С процессором Intel Core i7-3632QM на частоте 2,20 ГГц, Fedora 20, GCC 4.8.3 и OpenJDK 7 или 8 я получаю такой вывод:

dot(): 37 ns
dotc(): 23 ns

Или примерно в 1,6 раза быстрее. Нам нужно использовать прямые буферы NIO вместо массивов, ноHotSpot может обращаться к прямым буферам NIO так же быстро, как и к массивам, С другой стороны, ручное развертывание цикла не обеспечивает ощутимого прироста производительности в этом случае.

Error: User Rate Limit Exceeded
Error: User Rate Limit Exceeded Sean Owen
Error: User Rate Limit Exceeded
Error: User Rate Limit Exceeded
Error: User Rate Limit Exceeded

Похожие вопросы