2015-05-20 6 views
17

Короче говоря, я сделал несколько прототипов интерактивного программного обеспечения. Теперь я использую pygame (python sdl wrapper), и все делается на CPU. Я начинаю переносить его на C сейчас и в то же время искать существующие возможности использовать некоторые возможности графического процессора для включения процессора из избыточных операций. Однако я не могу найти хороший «ориентир», какую точную технологию/инструменты я должен выбрать в своей ситуации. Я просто прочитал множество документов, он очень быстро истощает мои умственные способности. Я не уверен, что это вообще возможно, поэтому я озадачен.
Здесь я сделал очень грубый эскиз моего типичного скелета приложения, который я разрабатываю, но учитывая, что он теперь использует GPU (заметьте, у меня почти нулевые практические знания о программировании GPU). Все еще важно то, что типы данных и функциональность должны быть точно сохранены. Вот оно:
enter image description hereОсновное приложение GPU, целочисленные вычисления

Так F (A, R, P) есть некоторая пользовательская функция, например, элемент подстановки, повторение и т.д. Функция предположительно постоянной в жизни программы, формы прямоугольника, как правило, не равны с A формы, поэтому он не выполняется на месте. Поэтому они просто генерируются с моими функциями. Примеры F: повторять строки и столбцы A; подставлять значения со значениями из таблиц замещения; составьте некоторые плитки в один массив; любая математическая функция для значений A и т. д. Как сказано, все это можно легко сделать на CPU, но приложение должно быть действительно гладким. BTW в чистом Python стал просто непригодным после добавления нескольких визуальных функций, основанных на массивах numpy. Cython помогает создавать быстрые пользовательские функции, но тогда исходный код уже является своего рода салатом.

Вопрос:

  • Отражает ли эта схема некоторые технологии (стандарт)/dev.tools?

  • Является ли CUDA тем, что я ищу? Если да, некоторые ссылки/примеры , которые совпадают с с моей структурой приложения, были бы замечательными.

Я понимаю, это большой вопрос, поэтому я дам более подробную информацию, если это поможет.


Update

Вот конкретный пример двух типичных расчетов для моего прототипа редактора растровых изображений. Поэтому редактор работает с индексами, а данные включают слои с соответствующими битовыми масками. Я могу определить размер слоев и масок того же размера, что и слои, и, скажем, все слои имеют одинаковый размер (1024^2 пикселя = 4 МБ для 32-битных значений). И моя палитра говорит: 1024 элементов (4 килобайта для формата 32 бит/с).
Рассмотрим я хочу сделать две вещи сейчас:

Шаг 1. Я хочу сгладить все слои в одном. Скажем, A1 - слой по умолчанию (фон), а слои «A2» и «A3» имеют маски «m2» и «m3». В питоне я бы написать:

from numpy import logical_not 
... 
Result = (A1 * logical_not(m2) + A2 * m2) * logical_not(m3) + A3 * m3 

Поскольку данные независим я считаю, что это должно дать proportionl для -го ускорения ряда параллельных блоков.

Этап 2. Теперь у меня есть массив и вы хотите «раскрасить» его с помощью некоторой палитры, так что это будет моя таблица поиска.Как я вижу сейчас, существует проблема с одновременным чтением элемента таблицы поиска. enter image description here

Но моя идея состоит в том, что, возможно, можно просто дублировать палитру для всех блоков, чтобы каждый блок мог читать свою собственную палитру? Пример: enter image description here

+0

FYI: Существует [Theano] (http://deeplearning.net/software/theano/tutorial/using_gpu.html) (Python), который может использовать графический процессор. Он компилирует символические выражения в код CUDA, который выполняется на вашем графическом процессоре. – displayname

+0

Если есть много независимых данных, проходящих через это (hundeds of MB/s), то это может реально ускорить процесс. Единственная проблема, которую я вижу, заключается в том, что «результирующие прямоугольники могут быть произвольного размера». Я никогда не слышал/не читал о распределении через ядра. Если он известен до начала, это нормально, но массивы должны быть определены до запуска ядра GPU. Так что это в основном зависит от F (как входных, так и выходных) и размера A –

+0

@ blind.wolf Да, размеры известны, он просто не должен иметь ту же форму, что и A, например, в случае масштабирования целочисленного массива. –

ответ

1

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

Я бы сказал, эта проблема будет стоить решения на GPU только при соблюдении двух условий:

  1. Размер A[] оптимизирован, чтобы сделать время передачи значения (Посмотрите, http://blog.theincredibleholk.org/blog/2012/11/29/a-look-at-gpu-memory-transfer/).

  2. Эта таблица не слишком большая и/или значение подстановок организованы таким образом, что кэш может быть максимально использован в общих случайных поиски на GPU могут быть медленными, в идеале вы можете предварительно загрузить R[] значения в буфере общей памяти для каждого элемента буфера A[].

Если вы можете ответить на оба вопрос положительно тогда и только тогда рассмотреть возможность идти в использовании GPU для вашей проблемы, иначе эти 2 фактора одолеет вычислительное Ускорение, что GPU может предоставить вам ,

Еще одна вещь, на которую вы можете обратить внимание, - это как можно лучше совместить время передачи и вычисления, чтобы максимально скрыть медленные скорости передачи данных CPU-> GPU.

Что касается вашей F(A, R, P) функции вам нужно, чтобы убедиться, что вам не нужно знать значение F(A, R, P)[0] для того, чтобы знать, что значение F(A, R, P)[1] потому, что если вы делаете, то вам нужно переписать F(A, R, P), чтобы обойти эту проблему, используя некоторую методику распараллеливания. Если у вас ограниченное количество функций F(), это можно решить, написав параллельную версию каждой функции F() для использования графическим процессором, но если F() определяется пользователем, тогда ваша проблема становится немного сложнее.

Надеюсь, это достаточно информации, чтобы получить обоснованное предположение о том, следует ли вам использовать графический процессор или нет, чтобы решить вашу проблему.

EDIT

Прочитав вашу правку, я бы сказал, да. Палитра может вписываться в общую память (см. GPU shared memory size is very small - what can I do about it?), которая очень быстрая, если у вас несколько палитр, вы можете поместиться 16 КБ (размер разделяемой памяти на большинстве карт)/4 КБ на палитру = 4 палитры на блок потоков.

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

+0

Большое спасибо, это немного освещает мой вопрос. Я сделал обновление, иллюстрирующее точные примеры.Теоретически он отвечает критериям, но я не уверен, особенно об этом кэшировании таблицы поиска. Не могли бы вы взглянуть и сказать, будет ли это работать, как я себе представляю? Потому что эти два расчета на самом деле наиболее типичны для приложения. –

+0

спасибо, это информация, которая мне нужна на данный момент. Новый мультимедийный редактор растровых изображений находится в пути :) –

1

Разница между OpenCL и CUDA не так велика, поэтому выберите, который лучше подходит для вас. Просто помните, что CUDA ограничит вас графическими процессорами NVidia.

Если я правильно понимаю вашу проблему, ядро ​​(функция, выполняемая на графическом процессоре) должна быть простой. Он должен следовать за этим псевдокодом:

kernel main(shared A, shared outA, const struct R, const struct P, const int maxOut, const int sizeA) 
    int index := getIndex() // get offset in input array 
    if(sizeA >= index) return // GPU often works better when n of threads is 2^n 
    int outIndex := index*maxOut // to get offset in output array 
    outA[outIndex] := F(A[index], R, P) 
end 

Функции F должны быть встроены, и вы можете использовать переключатель или, если для другой функции. Поскольку неизвестный размер вывода F, вы должны использовать больше памяти. Каждый экземпляр ядра должен знать позиции для правильной записи и чтения в памяти, поэтому должен быть некоторый максимальный размер (если их нет, то это все бесполезно, и вам нужно использовать CPU!). Если разные размеры являются разреженными, то я бы использовал что-то вроде вычисления этих разных размеров после того, как массив вернулся в ОЗУ и вычислил эти несколько с процессором, заполняя А некоторыми нулями или значениями индикации.

Размеры массивов, очевидно, являются длиной (A) * maxOut = length (outA).

Я забыл упомянуть, что если выполнение F не является таким же в большинстве случаев (тот же исходный код), что и GPU, его сериализует. Многопроцессоры GPU имеют несколько ядер, подключенных к одному кэшу команд, поэтому ему придется сериализовать код, который не является одинаковым для всех ядер! OpenMP или потоки - лучший выбор для такого рода проблем!

+0

Итак, вы имеете в виду, что это вполне возможно сделать. Я постараюсь с OpenCL тогда, я очень заинтригован. Я обновлю, если выйдет что-то интересное. –

+0

Это должно быть, однако я не уверен в реальном ускорении. Если это действительно следует этой схеме, ускорение должно быть существенным. Проблема в том, что F. Если это исполнение действительно случайное, то оно будет в основном сериализовано, и лучше сделать это с помощью OpenMP или потоков, потому что GPU будет сериализовать большую часть кода. (с сериализованным кодом, CPU по крайней мере в 3 раза быстрее) –

2

Когда ваш код сильно параллелен (т.е. между этапами обработки есть небольшие или нет зависимости от данных), вы можете перейти на CUDA (более мелкомасштабный контроль над синхронизацией) или OpenCL (очень похожий и переносимый API OpenGL-интерфейса для интерфейса с графическим процессором для обработки ядра). Большая часть работы по ускорению, которую мы делаем, происходит в OpenCL, которая отлично взаимодействует как с OpenGL, так и с DirectX, но у нас также есть одна и та же настройка, работающая с CUDA. Одна большая разница между CUDA и OpenCL заключается в том, что в CUDA вы можете скомпилировать ядра один раз и задерживать (и/или связывать) их в своем приложении, тогда как в OpenCL компилятор отлично справляется с стеком драйверов OpenCL, чтобы обеспечить компиляцию ядра, когда приложение запускается.

Один из альтернатив, который часто упускается из виду, если вы используете Microsoft Visual Studio, - это C++ AMP, C++-синтаксический и интуитивно понятный api для тех, кто не хочет вникать в логические завивки и повороты OpenCL/CUDA API. Большим преимуществом здесь является то, что код также работает, если у вас нет GPU в системе, но тогда у вас не так много вариантов настройки производительности. Тем не менее, во многих случаях это быстрый и эффективный способ написать доказательство вашего концептуального кода и повторить реализацию бит и частей в CUDA или OpenCL позже.

Блоки OpenMP и Thread Building - это только хорошие альтернативы, когда у вас проблемы с синхронизацией и множество зависимостей данных. Нативная потоковая обработка с использованием рабочих потоков также является жизнеспособным решением, но только если у вас есть хорошая идея о том, как настраивать точки синхронизации между различными процессами таким образом, чтобы потоки не изгоняли друг друга во время борьбы за приоритет. Это намного сложнее добиться, и инструменты, такие как Parallel Studio, являются обязательными. Но тогда NVIDIA NSight, если вы пишете код GPU.

Приложение:

Новая платформа называется Quasar (http://quasar.ugent.be/blog/) разрабатывается, что позволяет писать свои проблемы математики в синтаксисе, который очень похож на Matlab, но с полной поддержкой C/C++/C# или java-интеграции, а также кросс-компиляции (LLVM, CLANG) вашего «ядрового» кода для любой базовой аппаратной конфигурации. Он генерирует файлы Ptx CUDA или запускается на openCL или даже на вашем CPU с использованием TBB или их смеси. Используя несколько прозвищ, вы можете украсить алгоритм так, чтобы базовый компилятор мог вывести типы (вы также можете явно использовать строгую типизацию), поэтому вы можете оставить материал тяжелого типа полностью до компилятора. Справедливости ради отметим, что на момент написания этой статьи система по-прежнему была w.i.p. и первые скомпилированные программы OpenCL просто проверяются, но наиболее важным преимуществом является быстрое прототипирование с почти одинаковой производительностью по сравнению с оптимизированным cuda.

+0

Спасибо за информацию. Главный вопрос у меня был, однако, гораздо более на первый взгляд. Я хочу всего несколько циклов, где я сканирую состояние клавиатуры и функции вызова. Теперь я пишу на Python (с VIM). До сих пор я мог делать что-то без отладки. Портирование на C/C++ (ну, я даже не нуждаюсь в C++ для таких приложений), вероятно, решит проблемы с производительностью, и это по-прежнему стандартный подход, также поддерживаемый другими инструментами. Короче говоря, как мне совместить обычную C-программу (Say SDL) с параллельным кодом? –

+0

Прежде чем я отвечу, имейте в виду, что существует различие между потоковым и параллельным программированием в том смысле, что потоковая передача связана с синхронизацией и планированием заданий, тогда как параллельное программирование с использованием графического интерфейса является идеологическим подходом к организации кода и данных в гораздо более широком смысле, он подходит для параллельного аппаратного исполнения. Чтобы быть тупым, первый тип параллелизма явно обрабатывает сложные зависимости данных, которые параллелизм GPU вообще не нравится. Из вашего описания, похоже, что pthreads - это то, что вам нужно, например: см. Http://softpixel.com/~cwright/programming/threads/threads.c.php – StarShine

+0

Нет, теперь я не хочу распараллеливать CPU или потоки на стороне процессора. Я имел в виду, что у меня есть основной цикл (извините, я писал «циклы» раньше), поэтому я просматриваю состояние клавиатуры, а затем выполняю некоторую математику, но результат, а именно массив, который является стандартизованным, хочет обрабатывать с помощью графического процессора. Поэтому я предполагаю, что мне просто нужно вызвать некоторую «специальную» функцию из моей программы. Все еще не так много, чтобы найти четкие инструкции. Это просто типичное интерактивное приложение реального времени. Также мне не нужна обратная связь с графическим процессором. –