Как я могу написать код для подсказки в JVM, чтобы использовать векторные операции?

Несколько связанный с этим вопрос, которому исполнился год: генерирует ли какой-нибудь JIT-компилятор JVM код, который использует векторизованные инструкции с плавающей запятой?

Предисловие: я пытаюсь сделать это на чистом Java (без JNI для C++, без работы GPGPU и т. Д.). Я профилировал, и основная часть времени обработки исходит от математических операций в этом методе (это, вероятно, математика с плавающей запятой 95% и целочисленная математика 5%). Я уже сократил все вызовы Math.xxx() до достаточно хорошего приближения, поэтому большая часть математики теперь умножается на числа с плавающей запятой с несколькими добавлениями.

У меня есть код, который занимается обработкой звука. Я делал твики и уже столкнулся с большими успехами. Теперь я смотрю на ручное развертывание цикла, чтобы увидеть, есть ли какая-то выгода (по крайней мере, при ручном развертывании 2, я вижу улучшение примерно на 25%). Пробуя свои силы при ручном развертывании 4 (которое начинает становиться очень сложным, так как я развертываю оба цикла вложенного цикла), мне интересно, можно ли что-нибудь сделать, чтобы намекнуть jvm, что во время выполнения он может использовать вектор операции (например, SSE2, AVX и т. д.). Каждый образец аудио может быть рассчитан полностью независимо от других образцов, поэтому я уже смог увидеть улучшение на 25% (уменьшив количество зависимостей от вычислений с плавающей запятой).

Например, у меня есть 4 числа с плавающей запятой, по одному на каждую из 4 разверток цикла, для хранения частично вычисленного значения. Имеет ли значение, как я объявляю и использую эти поплавки? Если я сделаю это float[4], то намекает ли это на jvm, что они не связаны друг с другом против наличия float,float, float,float или даже класса из 4 публичных float? Есть ли что-то, что я могу сделать без значения, чтобы убить мой шанс на векторизацию кода?

Я наткнулся на статьи в Интернете о написании кода "нормально", потому что компилятор /jvm знает общие шаблоны и то, как их оптимизировать и отклоняться от шаблонов, может означать меньшую оптимизацию. По крайней мере, в этом случае, однако, я не ожидал бы, что развертывание циклов на 2 приведет к улучшению производительности в той же степени, в какой это было, поэтому мне интересно, могу ли я что-нибудь еще сделать (или, по крайней мере,не сделать), чтобы помочь моему шансы. Я знаю, что компилятор /jvm будет только лучше, поэтому я также хочу быть осторожным в делах, которые могут навредить мне в будущем.

Правка для любопытных: развертывание на 4 увеличило производительность еще на ~25% по сравнению с развертыванием на 2, так что я действительно думаю, что векторные операции могли бы помочь в моем случае, если бы jvm это поддерживал (или, возможно, уже использовал их).

Спасибо!

3 ответа

Как я могу... обработка звука... чистый Java (без JNI в C++, без работы GPGPU и т. Д.)... использовать векторные операции (например, SSE2, AVX и т. Д.)

Java - это язык высокого уровня (одна инструкция в Java генерирует много аппаратных инструкций), который по своей структуре (например, управление памятью сборщика мусора) не подходит для задач, которые манипулируют большими объемами данных в режиме реального времени.

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

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

Даже C++ (считается быстрым языком) не будет автоматически использовать некоторые сверхоптимизированные аппаратные операции для вас. Он может просто встроить один из нескольких созданных вручную методов на ассемблере в определенных местах.

Поэтому я отвечаю, что "вероятно, нет способа" проинструктировать JVM использовать некоторую аппаратную оптимизацию для вашего кода (например, SSE), и даже если бы она существовала, во время выполнения языка Java все равно было бы слишком много других факторов, которые будут замедляться. ваш код.

Используйте язык низкого уровня, разработанный для этой задачи, и свяжите его с Java для логики высокого уровня.

РЕДАКТИРОВАТЬ: добавить еще немного информации на основе комментариев

Если вы убеждены, что высокоуровневая языковая среда исполнения "один раз запусти куда угодно", безусловно, также должна выполнить много низкоуровневых оптимизаций и автоматически превратить ваш высокоуровневый код в оптимизированный низкоуровневый код, то... как оптимизирует компилятор JIT зависит от реализации виртуальной машины Java. Их много.

В случае Oracle JVM (HotSpot) вы можете начать поиск ответа, загрузив исходный код, текст SSE2 появляется в следующих файлах:

  • OpenJDK / точка доступа / SRC / процессор /x86/ VM /assembler_x86.cpp
  • OpenJDK / точка доступа / SRC / процессор /x86/ VM /assembler_x86.hpp
  • OpenJDK / точка доступа / SRC / процессор /x86/ VM /c1_LIRGenerator_x86.cpp
  • OpenJDK / точка доступа / SRC / процессор /x86/ VM /c1_Runtime1_x86.cpp
  • OpenJDK / точка доступа / SRC / процессор /x86/ VM /sharedRuntime_x86_32.cpp
  • OpenJDK / точка доступа / SRC / процессор /x86/ VM /vm_version_x86.cpp
  • OpenJDK / точка доступа / SRC / процессор /x86/ VM /vm_version_x86.hpp
  • OpenJDK / точка доступа / SRC / процессор /x86/ VM /x86_32.ad
  • OpenJDK / точка доступа / SRC /os_cpu/linux_x86/ VM /os_linux_x86.cpp
  • OpenJDK / точка доступа / SRC / доля / VM /c1/c1_GraphBuilder.cpp
  • OpenJDK / точка доступа / SRC / доля / VM /c1/c1_LinearScan.cpp
  • OpenJDK / точка доступа / SRC / доля / VM / выполнения /globals.hpp

Они написаны на C++ и ассемблере, поэтому вам все равно придется выучить несколько языков низкого уровня, чтобы читать их.

Я бы не стал охотиться так глубоко даже с +500 наградами. ИМХО вопрос неверный, основанный на неправильных предположениях

Оптимизация SuperWord на Hotspot ограничена и довольно хрупка. Ограниченный, поскольку они, как правило, стоят за тем, что предлагает компилятор C/C++, и хрупкие, поскольку они зависят от конкретной формы цикла (и поддерживаются только для определенных процессоров).

Я так понимаю, ты хочешь написать, как только беги куда угодно. Похоже, у вас уже есть чистое Java-решение. Возможно, вы захотите рассмотреть опциональную реализацию для известных популярных платформ, чтобы дополнить эту реализацию "быстрым в некоторых местах", что, вероятно, уже верно.

Трудно дать вам более конкретную обратную связь с некоторым кодом. Я предлагаю вам взять рассматриваемый цикл и представить его в тесте JMH. Это позволяет легко анализировать и обсуждать.

Похоже, много оптимизаций SIMD/SSE было сделано в Java 8/9.

Другие вопросы по тегам