Скажем, узким местом моей Java-программы на самом деле являются узкие циклы для вычисления множества векторных точечных произведений. Да, я профилировал, да, это узкое место, да, это важно, да, именно такой алгоритм, да, я запустил Proguard для оптимизации байтового кода и т. Д.
По сути, работа - это точечные произведения. Например, у меня их два, float[50]
и мне нужно вычислить сумму попарных произведений. Я знаю, что существуют наборы инструкций процессора для быстрого и массового выполнения таких операций, как SSE или MMX.
Да, я, вероятно, смогу получить к ним доступ, написав собственный код в JNI. Вызов JNI оказывается довольно дорогим.
Я знаю, что вы не можете гарантировать, что JIT будет компилировать, а что нет. Кто-нибудь когда-нибудь слышал о коде, генерирующем JIT, который использует эти инструкции? и если да, то есть ли в коде Java что-нибудь, что помогает сделать его таким образом компилируемым?
Вероятно, «нет»; стоит спросить.
источник
-XX:+UnlockDiagnosticVMOptions -XX:+PrintAssembly -XX:+LogCompilation
. Вам понадобится программа, которая запускает векторизуемый метод достаточное количество раз, чтобы сделать его «горячим».Ответы:
Итак, по сути, вы хотите, чтобы ваш код работал быстрее. JNI - это ответ. Я знаю, что вы сказали, что это не сработало для вас, но позвольте мне показать вам, что вы ошибаетесь.
Вот
Dot.java
:и
Dot.h
:Мы можем скомпилировать и запустить это с помощью JavaCPP, используя эту команду:
С процессором Intel (R) Core (TM) i7-7700HQ @ 2,80 ГГц, Fedora 30, GCC 9.1.1 и OpenJDK 8 или 11, я получаю такой вывод:
Или примерно в 2,4 раза быстрее. Нам нужно использовать прямые буферы NIO вместо массивов, но HotSpot может обращаться к прямым буферам NIO так же быстро, как и к массивам . С другой стороны, ручное развертывание цикла в этом случае не дает ощутимого повышения производительности.
источник
Чтобы развеять скептицизм, выраженный другими здесь, я предлагаю всем, кто хочет доказать себе или другим, использовать следующий метод:
Пример:
Результат с флагом и без него (на недавнем ноутбуке Haswell, Oracle JDK 8u60): -XX: + UseSuperWord: 475,073 ± 44,579 нс / операцию (наносекунды на операцию) -XX: -UseSuperWord: 3376,364 ± 233,211 нс / операцию
Сборка для горячего цикла немного сложна для форматирования и вставки здесь, но вот фрагмент (hsdis.so не может форматировать некоторые векторные инструкции AVX2, поэтому я использовал -XX: UseAVX = 1): -XX: + UseSuperWord (с '-prof perfasm: intelSyntax = true')
Удачи штурму замка!
источник
В версиях HotSpot, начиная с Java 7u40, серверный компилятор обеспечивает поддержку автоматической векторизации. Согласно JDK-6340864
Однако, похоже, это верно только для «простых циклов» - по крайней мере, на данный момент. Например, накопление массива пока не может быть векторизовано JDK-7192383
источник
Вот хорошая статья об экспериментах с инструкциями Java и SIMD, написанная моим другом: http://prestodb.rocks/code/simd/
Его общий результат состоит в том, что вы можете ожидать, что JIT будет использовать некоторые операции SSE в 1.8 (и некоторые другие в 1.9). Хотя многого ожидать не стоит и нужно быть осторожным.
источник
Вы можете написать ядро OpenCl для выполнения вычислений и запустить его с java http://www.jocl.org/ .
Код может запускаться на CPU и / или GPU, а язык OpenCL поддерживает также векторные типы, поэтому вы должны иметь возможность явно воспользоваться преимуществами, например, инструкций SSE3 / 4.
источник
Взгляните на Сравнение производительности Java и JNI для оптимальной реализации вычислительных микроядер . Они показывают, что серверный компилятор Java HotSpot VM поддерживает автоматическую векторизацию с использованием параллелизма на уровне сверхслова, который ограничен простыми случаями параллелизма внутри цикла. Эта статья также подскажет, достаточно ли велик ваш размер данных, чтобы оправдать переход по маршруту JNI.
источник
Я предполагаю, что вы написали этот вопрос до того, как узнали о netlib-java ;-) он предоставляет именно тот собственный API, который вам нужен, с оптимизированными для машины реализациями и не имеет никаких затрат на родной границе благодаря закреплению памяти.
источник
Я не верю, что большинство виртуальных машин будут достаточно умными для такого рода оптимизаций. Честно говоря, большинство оптимизаций намного проще, например, сдвиг вместо умножения в степени двойки. В монопроекте были представлены собственные векторные и другие методы с нативной поддержкой для повышения производительности.
источник