Использование Java с графическими процессорами Nvidia (cuda)
Я работаю над бизнес-проектом, который выполняется на java и требует огромной вычислительной мощности для вычисления бизнес-рынков. Простая математика, но с огромным количеством данных.
мы заказали некоторые графические процессоры cuda, чтобы попробовать его, и поскольку Java не поддерживается cuda, мне интересно, с чего начать. Должен ли я построить интерфейс JNI? Должен ли я использовать JCUDA или есть другие способы?
У меня нет опыта в этой области, и я хотел бы, чтобы кто-то мог направить меня на что-то, чтобы я мог начните исследовать и учиться.
2 ответа:
прежде всего, вы должны знать о том, что CUDA не будет автоматически делать вычисления быстрее. С одной стороны, потому что программирование на GPU-это искусство, и получить его может быть очень и очень сложно право. С другой стороны, потому что графические процессоры хорошо подходят только для некоторых видов расчетов.
Это может показаться запутанным, потому что вы можете в основном вычислить что-нибудь на GPU. Ключевым моментом является, конечно же, являетесь ли вы добьется хорошего ускорения или нет. Самая важная классификация здесь заключается в том, является ли проблема параллельных задач или параллельных данных. Первый относится, грубо говоря, к задачам, где несколько потоков работают над своими собственными задачами, более или менее независимо. Второй относится к проблемам, где много темы то же - но на разных частях данных.
последний вид проблемы что графические процессоры хороши: у них есть много ядра, и все ядра делают то же самое, но работают на разных частях входных данных.
Вы упомянули, что у вас есть "простая математика, но с огромным количеством данных". Хотя это может звучать как совершенно параллельная проблема данных и, таким образом, как будто она хорошо подходит для GPU, есть еще один аспект, который следует учитывать: графические процессоры смехотворно быстры с точки зрения теоретической вычислительной мощности (флопы, операции с плавающей запятой в секунду). Но они часто задушены пропускной способностью памяти.
это приведет к другой классификации проблем. А именно есть ли проблемы привязка к памяти или вычислить скачок.
первый относится к проблемам, где количество инструкций, которые выполняются для каждого элемента данных является низким. Например, рассмотрим параллельное векторное сложение: вам придется читать два элемента данных, затем выполните одно добавление, а затем написать сумма в результирующий вектор. Вы не увидите ускорения при выполнении этого на GPU, потому что однократное добавление не компенсирует усилия чтения/записи памяти.
второй термин, "вычислительная граница", относится к задачам, в которых количество инструкций велико по сравнению с количеством операций чтения/записи в памяти. Например, рассмотрим умножение матрицы: число инструкций будет O(n^3), Когда n-размер матрицы. В этом в этом случае можно ожидать, что GPU будет превосходить процессор при определенном размере матрицы. Другой пример может быть, когда многие сложные тригонометрические вычисления (синус/Косинус и т. д.) выполняются на "немногих" элементах данных.
как правило: вы можете предположить, что чтение / запись одного элемента данных из" основной " памяти GPU имеет задержку около 500 инструкций....
поэтому еще одним ключевым моментом для производительности графических процессоров является локальность данных: если вы должны считывать или записывать данные (и в большинстве случаев, вам придется ;-)), то вы должны убедиться, что данные хранятся как можно ближе к GPU ядер. Таким образом, графические процессоры имеют определенные области памяти (называемые "локальной памятью" или "общей памятью"), размер которых обычно составляет всего несколько КБ, но особенно эффективен для данных, которые собираются участвовать в вычислении.
Итак, чтобы подчеркнуть это еще раз: Программирование GPU-это искусство, которое только отдаленно связано с параллельным программированием на CPU. Такие вещи, как потоки в Java, со всей инфраструктурой параллелизма, такой как
ThreadPoolExecutors
,ForkJoinPools
etc. может создаться впечатление, что вам просто нужно как-то разделить свою работу и распределить ее между несколькими процессорами. На графическом процессоре вы можете столкнуться с проблемами на гораздо более низком уровне: заполняемость, давление регистра, давление общей памяти, Коалесценция памяти ... просто назвать несколько.однако, когда у вас есть параллельные данные, связанные с вычислениями проблемы для решения, GPU-это путь.
общее замечание: Вы специально попросили CUDA. Но я настоятельно рекомендую вам также взглянуть на OpenCL. Он имеет несколько преимуществ. Прежде всего, это независимый от поставщика, открытый отраслевой стандарт, и есть реализации OpenCL от AMD, Apple, Intel и NVIDIA. Кроме того, существует гораздо более широкая поддержка OpenCL в мире Java. Единственный случай, когда я предпочел бы согласиться на CUDA, - это когда вы хотите использовать библиотеки времени выполнения CUDA, такие как CUFFT для БПФ или Кубла для 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
(отказ от ответственности: я автор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. Он предлагает выделенные интерфейсы, которые могут быть реализованы, чтобы указать, что определенный класс должен быть исполняется на ГПУ. В отличие от 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-привязки для OpenCL: объектно-ориентированная библиотека OpenCL, основанная на автоматически генерируемых низкоуровневых привязках
http://www.lwjgl.org/: Java-привязки для OpenCL: автоматически генерируемые низкоуровневые привязки и объектно-ориентированные классы удобства
http://jocl.org/: привязки Java для OpenCL: низкоуровневые привязки, которые являются отображением 1:1 оригинальный OpenCL API
http://jcuda.org/ : привязку Java для CUDA: низкого уровня привязки, которые являются 1:1 отображение оригинальной технологии CUDA API-интерфейс
разное
http://sourceforge.net/projects/jopencl/: привязки Java для OpenCL. Кажется, больше не поддерживается с 2010 года
http://www.hoopoe-cloud.com/: привязки Java для CUDA. Кажется, больше не поддерживается
Я бы начал с использования одного из проектов там для Java и CUDA:http://www.jcuda.org/