Использование Java с NVIDIA GPU (cuda)
Я работаю над бизнес-проектом, который выполняется на java и требует огромной вычислительной мощности для вычисления бизнес-рынков. Простая математика, но с огромным количеством данных.
мы заказали некоторые CUDA gpu, чтобы попробовать его, и поскольку Java не поддерживается cuda, мне интересно, с чего начать. Должен ли я создать интерфейс JNI? Должен ли я использовать JCUDA или есть другие способы?
У меня нет опыта в этой области, и я хотел бы, чтобы кто-то мог направить меня к чему-то, чтобы я мог начните исследования и обучение.
2 ответов
прежде всего, вы должны знать о том, что CUDA не будет автоматически делать вычисления быстрее. С одной стороны, потому что программирование GPU-это искусство, и это может быть очень, очень сложно получить его право. С другой стороны, потому что графические процессоры хорошо подходят только для определенных видов расчетов.
Это может показаться запутанным, потому что вы можете в основном вычислить что-нибудь на GPU. Ключевой момент, конечно, в том, достигнет хорошего ускорения или нет. Наиболее важная классификация здесь заключается в том, является ли проблема параллельных задач или параллельных данных. Первый относится, грубо говоря, к проблемам, где несколько потоков работают над своими собственными задачами более или менее независимо. Второй относится к проблемам, где много темы то же - но на разных частях данных.
последнем-такая задача что графические процессоры хороши: у них есть много ядра, и все ядра делают то же самое, но работают на разных частях входных данных.
Вы упомянули, что у вас есть "простая математика, но с огромным количеством данных". Хотя это может звучать как совершенно параллельная проблема данных и, таким образом, как будто она хорошо подходит для GPU, есть еще один аспект, который следует учитывать: графические процессоры смехотворно быстры с точки зрения теоретической вычислительной мощности (флопы, операции с плавающей запятой в секунду). Но они часто ограничиваются пропускной способностью памяти.
это приведет к другой классификации проблем. А именно, есть ли проблемы привязка к памяти или вычислить скачок.
первый относится к проблемам, где количество инструкций, выполняемых для каждого элемента данных, невелико. Например, рассмотрим параллельное векторное сложение: вам придется читать два элемента данных, затем выполните одно добавление, а затем написать сумма в результирующий вектор. Вы не увидите ускорения при этом на GPU, потому что одно добавление не компенсирует усилия чтения / записи памяти.
второй член, "вычислить привязку", относится к проблемам, где количество инструкций велико по сравнению с количеством чтения/записи памяти. Например, рассмотрим умножение матрицы: количество инструкций будет O(n^3), Когда n-размер матрицы. В этом в этом случае можно ожидать, что GPU будет превосходить CPU при определенном размере матрицы. Другим примером может быть, когда многие сложные тригонометрические вычисления (синус/Косинус и т. д.) выполняются на "немногих" элементах данных.
как правило: вы можете предположить, что чтение / запись одного элемента данных из "основной" памяти GPU имеет задержку около 500 инструкций....
таким образом, еще одним ключевым моментом для производительности графических процессоров является локальность данных: если вы должны считывать или записывать данные (и в большинстве случаев, вам придется ;-)), то вы должны убедиться, что данные хранятся как можно ближе к GPU ядер. Таким образом, графические процессоры имеют определенные области памяти (называемые "локальной памятью" или "общей памятью"), размер которых обычно составляет всего несколько КБ, но особенно эффективны для данных, которые собираются участвовать в вычислении.
чтобы подчеркнуть это еще раз: Программирование GPU-это искусство, которое только отдаленно связано с параллельным программированием на CPU. Такие вещи, как потоки в Java, со всей инфраструктурой параллелизма, как ThreadPoolExecutors
, ForkJoinPools
etc. может создаться впечатление, что вам просто нужно как-то разделить свою работу и распределить ее между несколькими процессорами. На GPU вы можете столкнуться с проблемами на гораздо более низком уровне: заполняемость, давление регистра, давление общей памяти, объединение памяти ... просто назвать несколько.
однако, когда у вас есть параллельная данным, связанная с вычислениями проблема для решения, GPU-это путь.
общее замечание: ваш специально попросил CUDA. Но я настоятельно рекомендую вам также взглянуть на OpenCL. Он имеет несколько преимуществ. Прежде всего, это независимый от поставщика, открытый отраслевой стандарт, и есть реализации OpenCL от AMD, Apple, Intel и NVIDIA. Кроме того, существует гораздо более широкая поддержка OpenCL в мире Java. Единственный случай, когда я бы предпочел согласиться на CUDA, - это когда вы хотите использовать библиотеки времени выполнения CUDA, такие как CUFFT для FFT или CUBLAS для BLAS (матричные/векторные операции). Хотя существуют подходы для предоставления аналогичных библиотек для OpenCL, они не могут быть напрямую использованы со стороны Java, если вы не создадите свои собственные привязки JNI для этих библиотек.
вам также может быть интересно услышать, что в октябре 2012 года группа OpenJDK HotSpot запустила проект "Суматра":http://openjdk.java.net/projects/sumatra/ . Цель этого проекта-обеспечить поддержку GPU напрямую в JVM, при поддержке JIT. Текущее состояние и первые результаты можно увидеть в их списке рассылки по адресуhttp://mail.openjdk.java.net/mailman/listinfo/sumatra-dev
однако некоторое время назад я собрал некоторые ресурсы, связанные с "Java на GPU" в целом. Я подытожу их здесь еще раз, без особого порядка.
(отказ от ответственности: я автор http://jcuda.org/ и http://jocl.org/ )
(байт)перевод кода и генерация кода OpenCL:
https://github.com/aparapi/aparapi: библиотека с открытым исходным кодом, которая создается и активно поддерживается AMD. В специальном классе "ядро" можно переопределить определенный метод, который должен выполняться параллельно. Байтовый код этого метода загружается во время выполнения с помощью собственного считывателя байт-кода. Код переводится в код OpenCL, который затем компилируется использование компилятора OpenCL. Затем результат может быть выполнен на устройстве OpenCL, которое может быть GPU или CPU. Если компиляция в OpenCL невозможна (или OpenCL недоступен), код все равно будет выполняться параллельно, используя пул потоков.
https://github.com/pcpratts/rootbeer1: библиотека с открытым исходным кодом для преобразования частей Java в программы CUDA. Он предлагает выделенные интерфейсы, которые могут быть реализованы, чтобы указать, что определенный класс должен быть выполняется на GPU. В отличие от Aparapi, он пытается автоматически сериализовать "релевантные" данные (то есть полную релевантную часть графа объектов!) в представление, которое подходит для GPU.
https://code.google.com/archive/p/java-gpu/: библиотека для перевода аннотированного кода Java (с некоторыми ограничениями) в код CUDA, который затем компилируется в библиотеку, которая выполняет код на GPU. Библиотека была разработана в контексте Кандидатская диссертация, которая содержит глубокую информацию о процессе перевода.
https://github.com/ochafik/ScalaCL: привязки Scala для OpenCL. Позволяет обрабатывать специальные коллекции Scala параллельно с OpenCL. Функции, вызываемые для элементов коллекций, могут быть обычными функциями Scala (с некоторыми ограничениями), которые затем переводятся в ядра OpenCL.
язык расширения
http://www.ateji.com/px/index.html: расширение языка для Java, которое позволяет параллельные конструкции (например, параллельные для циклов, стиль OpenMP), которые затем выполняются на GPU с OpenCL. К сожалению, этот очень перспективный проект больше не поддерживается.
http://www.habanero.rice.edu/Publications.html (JCUDA) : библиотека, которая может перевести специальный код Java (называемый кодом JCUDA) в код Java-и CUDA-C, который затем можно скомпилировать и выполнить на GPU. Однако библиотека, как представляется, не является общедоступной.
https://www2.informatik.uni-erlangen.de/EN/research/JavaOpenMP/index.html: расширение языка Java для конструкций OpenMP с бэкэндом CUDA
библиотеки привязки Java OpenCL/CUDA
https://github.com/ochafik/JavaCL: привязки Java для OpenCL: объектно-ориентированная библиотека OpenCL, основанная на автоматически генерируемые низкоуровневые привязки
http://jogamp.org/jocl/www/: Java bindings for OpenCL: объектно-ориентированная библиотека OpenCL, основанная на автоматически генерируемых низкоуровневых привязках
http://www.lwjgl.org/: привязки Java для OpenCL: автоматически генерируемые низкоуровневые привязки и объектно-ориентированные классы удобства
http://jocl.org/: привязки Java для OpenCL: привязки низкого уровня, которые являются отображением 1:1 оригинальный API OpenCL
http://jcuda.org/: привязки Java для CUDA: привязки низкого уровня, которые являются отображением 1: 1 исходного API CUDA
разное
http://sourceforge.net/projects/jopencl/: привязки Java для OpenCL. Кажется, больше не поддерживается с 2010 года
http://www.hoopoe-cloud.com/: привязки Java для CUDA. Кажется, больше не поддерживается
Я бы начал с использования одного из проектов для Java и CUDA:http://www.jcuda.org/