Лабораторная работа №1

“Обработка одномерных массивов и матриц при помощи CUDA

Цель работы: научиться использовать современную технологию параллельного программирования CUDA для обработки одномерных массивов и матриц.

Теоретическая часть

В разработке. Для выполнения данной работы можно пользоваться источником Сандерс Дж., “Технология CUDA в примерах”, гл. 1 – 4, стр. 16 – 58.

Задание и порядок выполнения лабораторной работы

Часть 1. Установка требуемого программного обеспечения

1.1 Установка MS Visual Studio

Для работы с технологией CUDA потребуется MS Visual Studio. Самую последнюю версию среды лучше не использовать, так как существует вероятность того, что последний комплект ПО CUDA ее еще не поддерживает. На момент написания этих методических указаний студентам лучше использовать Visual Studio 2005 – Visual Studio 2012.

Заметим попутно, что для учебных целей нет разницы в использовании Professional или Express версии Visual Studio. Для работы с CUDA необходимо, чтобы среда поддерживала компиляцию программ на языке С/С++. Поэтому, если Вы устанавливаете Professional версию, проблем, как правило, не бывает. При установке Express версии нужно обращать внимание на поддерживаемый язык и тип Вашей операционной системы (32 или 64 разряда). Express версию можно скачать бесплатно с сайта Microsoft по ссылке:

[http://www. /downloads/download-visual-studio-vs]

1.2 Установка CUDA Developer Drivers, CUDA Toolkit, GPU Computing SDK

После установки MS Visual Studio необходимо установить CUDA Developer Drivers, CUDA Toolkit, GPU Computing SDK. Технология CUDA была разработана компанией NVIDIA для ускорения вычислений при обработке графики за счет параллельной обработки данных. Принято считать, что указанная технология поддерживается во всех видеокартах NVIDIA, выпущенных после 2007 года. Поэтому если у Вас именно такая видеокарта – Вы сможете почувствовать настоящую мощь параллельных вычислений. Окончательно убедиться в том, что Ваша видеокарта поддерживает технологию CUDA можно на сайте производителя.

НЕ нашли? Не то? Что вы ищете?

Однако если у Вас нет подходящего оборудования, изучить указанную технологию и научиться писать программы для CUDA все равно можно. Правда “почувствовать мощь” уже не получится.

Этапы дальнейшей установки будут несколько отличаться для конфигурации с установленной на машине видеокартой от NVIDIA и без нее.

►Для конфигурации ПК с видеокартой от NVIDIA нужно зайти на страницу загрузки программного обеспечения для CUDA,

[https://developer. /cuda-toolkit-archive]

перейти с нее на страницу с последней версией (на момент написания это версия 6.5), скачать и установить на свой компьютер. Начиная с версии 5.0 все три пакета, которые необходимы для программирования под CUDA, – CUDA Developer Drivers, CUDA Toolkit, GPU Computing SDK – объединены в один инсталлятор, что, конечно же, очень удобно. При загрузке обращайте внимание на версию и тип Вашей операционной системы. При установке не используйте длинных путей, содержащих русские буквы, а по возможности короткие пути. Это пригодится впоследствии при интеграции этих пакетов в Visual Studio.

►Для конфигурации ПК без видеокарты от NVIDIA нужно зайти на страницу загрузки программного обеспечения для CUDA,

[https://developer. /cuda-toolkit-archive]

перейти с нее на страницу с версией 2.3, скачать и установить CUDA Toolkit, GPU Computing SDK. В отличие от первого варианта конфигурации, пакет CUDA Developer Drivers не нужен, так как у Вас нет соответствующего оборудования. Собственно, он даже не установится.

При скачивании пакетов обращайте также внимание на версию и тип Вашей операционной системы.

При установке CUDA Toolkit, GPU Computing SDK постарайтесь использовать короткие пути без русских букв. Это пригодится впоследствии при интеграции этих пакетов в Visual Studio. Наиболее оптимальный вариант – использовать следующие пути установки:

[С:\CUDA\TOOLKIT],

[С:\CUDA\SDK].

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

Не стоит также устанавливать CUDA Toolkit, GPU Computing SDK разных версий. Они могут оказаться несовместимы друг с другом.

Часть 2. Создание и настройка первого проекта для CUDA

Материал, описываемый в данной части, показывает, как создать проект, настроить интеграцию установленного ранее программного обеспечения, скомпилировать и запустить первое приложение для работы с CUDA. Обратите внимание – при создании нового проекта настройка должна выполняться каждый раз заново, поэтому, скорей всего, Вам придется возвращаться к данной части повторно.

Для начала создадим новое консольное приложение Win32 С++. В настройках создания отметим опцию “Пустой проект”. При создании проекта не используйте папку для проектов по умолчанию, а старайтесь использовать короткие пути без русских букв. Автор этих методических указаний потратил несколько дней, пытаясь понять, откуда берутся ошибки даже при компиляции пустого проекта CUDA. Как оказалось впоследствии, проект нужно было перенести в папку с короткими путями. Наиболее оптимальный вариант – создать папку

[С:\CUDA\PROJECTS]

и создавать все проекты в ней. Попутно отметим, что данное правило создания проектов актуально для версии CUDA ToolKit версии 2.3. Возможно в последующих версиях (а сейчас уже вышла 6.5) данный недостаток был исправлен.

Рис. 1. – Создание нового проекта CUDA (1 шаг)

Рис. 2. – Создание нового проекта CUDA (2 шаг)

После создания нового проекта Вам следует проверить, добавились ли правила сборки в Visual Studio. В последних версиях CUDA Toolkit это выполняется автоматически. Правила сборки могут не добавляться в старых версиях CUDA Toolkit. Кроме того, правила сборки не будут добавлены, если Вы, например, установите сначала CUDA Toolkit, а только потом Visual Studio – в этом случае их просто еще некуда добавлять.

Проверить добавились ли правила сборки можно через контекстное меню проекта.

Рис. 3. – Вызов диалога Пользовательские правила построения

Рис. 4. – Диалог “Пользовательские правила построения”

В диалоге “Пользовательские правила построения” в названиях правил ищите строку “CUDA”. Таких правил может быть несколько, а их полные названия могут отличаться в зависимости от версии CUDA Toolkit. Автору встречались варианты “CUDA C/C++”, “CUDA Driver API”, “CUDA Runtime API” и т. д.

Если подобных правил в указанном диалоге нет (как получилось, например, на рис. 4), Вам потребуется добавить их самостоятельно. Для этого в папке с установленным пакетом CUDA Toolkit поищите файл с названием [Cuda.Rules]. Если такого файла нет, попробуйте поискать его в папке с установленным пакетом GPU Computing SDK (в старых версиях файл Cuda.Rules может находиться в нем). Таких файлов Вы можете найти несколько, в разных поддиректориях. Добавьте все найденные правила вручную при помощи кнопки “Найти существующий”. В результате диалоговое окно примет вид, показанный на рис. 5.

Рис. 5. – Диалог “Пользовательские правила построения” с добавленным правилом сборки для CUDA-программ

Для того чтобы задействовать правила сборки в Вашем проекте, необходимо отметить флажок слева от названия правила и нажать кнопку “ОК”. Если же у Вас имеется несколько правил (в старших версиях CUDA Toolkit, например, есть разделение на CUDA Runtime API и CUDA Driver API), следует выбирать CUDA Runtime API. Именно CUDA Runtime API предоставляет интерфейс для более простых программ CUDA, в то время как CUDA Driver API более сложен в освоении, но вместе с тем дает доступ к низкоуровневому программированию для CUDA. Для начинающих он не нужен, и в данном цикле лабораторных работ не рассматривается.

На следующем этапе нужно создать новый файл с исходным кодом в проекте. Для этого следует воспользоваться пунктом “Создать элемент” из контекстного меню проекта (см. рис. 6). Далее нужно выбрать файл типа С++. Имя файла может быть любым, но расширение файла обязательно следует задавать вручную, как показано на рис. 7. Традиционно файлы исходного кода CUDA имеют расширение *.cu. Если Вы не зададите расширение самостоятельно, указанный файл будет обычным *.cpp файлом, и добавленные ранее правила для него станут неприменимы. Из рисунка 5 можно понять, что именно по расширению файла Visual Studio определяет, какие правила для него нужно задействовать и как его компилировать.

Рис. 6. – Создание нового файла с исходным кодом (шаг 1)

Рис. 7. – Создание нового файла с исходным кодом (шаг 2)

После создания файла следует убедиться в том, что к нему применились правила CUDA. Для этого нужно открыть свойства файла (не проекта!) и убедиться в том, что в поле “Инструмент” вкладки “Общие” задействуется именно подключенные ранее правила сборки CUDA (см. рис. 8 – рис. 9). Если по каким-либо причинам в поле инструмент окажется другой инструмент – можно переназначить инструмент вручную, выбрав его из списка.

Рис. 8. – Проверка соответствия исходного файла правилам CUDA (шаг 1)

Рис. 9. – Проверка соответствия исходного файла правилам CUDA (шаг 1)

Далее следует настроить пути для поиска средой Visual Studio компилятора CUDA программ, библиотек CUDA, заголовочных файлов и других исполняемых файлов (которые входят в состав CUDA ToolKit). Понадобится выполнить несколько настроек в свойствах проекта:

- во-первых, нужно указать месторасположение библиотек CUDA во вкладке “Компоновщик – Общие – Дополнительные каталоги библиотек”, как показано на рис. 10. Здесь следует указать путь к папке, в которой хранятся библиотеки CUDA (файлы *.lib). Эта папка входит в состав CUDA ToolKit. Если таких папок в Вашей версии CUDA ToolKit несколько, то, нужно выбрать ту из них, которая соответствует типу Вашей операционной системы и выбранной версии CUDA API. Например, если файлы *.lib находятся в папке “runtime/lib/win32/*.lib” и у Вас 32 разрядная версия Windows, то выбирать нужно именно эту папку (помня о том, что в цикле лабораторных работ используется Runtime CUDA API).

- во-вторых, следует указать библиотеку “cudart. lib” на вкладке “Компоновщик – Общие – Ввод”. Здесь можно ограничиться одним именем файла, без указания пути (см. рис. 11).

Рис. 10. – Подключение библиотек CUDA

Рис. 11. – Подключение cudart. lib

Наконец, для студентов, у которых нет реальной видеокарты от NVidia, поддерживающей CUDA, необходимо включить режим эмуляции CUDA устройства. Обратите внимание на следующий любопытный факт: если режим эмуляции не включен, то программа компилируется и даже работает, только участки кода, которые должны исполняться на устройстве CUDA, просто игнорируются, хотя по идее должна возникать ошибка компиляции. Поэтому будьте внимательны и всегда включайте режим эмуляции, иначе результат выполнения Вашей программы будет не таким, как Вы ожидаете. Для того чтобы включить режим эмуляции в свойствах проекта зайдите во вкладку “CUDA Build Rule v2.3.0 – General Emulation Mode” и выберите “Да” напротив соответствующего свойства (см. рис. 12).

Рис. 12. – Включение режима эмуляции (для CUDA ToolKit v2.3.0)

Теперь стоит проверить, как компилируется простейшее приложение CUDA. Откройте созданный ранее файл исходного кода и введите в него следующий фрагмент:

#include <stdio. h>

__global__ void add(int a, int b, int *c)

{

*c = a + b;

}

int main(void)

{

int c = 0; int *dev_c;

cudaMalloc ((void**)&dev_c, sizeof(int));

add<<<1,1>>>(2, -1, dev_c);

cudaMemcpy (&c, dev_c, sizeof(int), cudaMemcpyDeviceToHost);

printf("%d", c);

system("pause");

return 0;

}

Нетрудно догадаться (несмотря на местами незнакомый синтаксис), что делает этот фрагмент кода: складывает 2 числа, -1 и 2, и выводит результат на экран. Но происходит это уже на CUDA устройстве. Поэтому если в результате Вы увидите 1, значит, Вы все сделали правильно. Если в результате будет 0, то, скорей всего, Вы забыли включить режим эмуляции. Могут также возникнуть и ошибки компиляции. В этом случае попробуйте скомпилировать такой код:

int main(void)

{

return 0;

}

Если и в этом случае будут возникать ошибки компиляции, то можно проверить следующее:

- если возникают ошибки вида “newline в константе”, то эта ошибка, скорей всего, связана с тем, что в пути к проекту или в пути к библиотекам имеются русские буквы;

- если возникают ошибки вида “неразрешенная ссылка” – проверьте еще раз правильность указания путей ко всем библиотекам.

- наконец, при компиляции проектов Ваш антивирус может “ругаться”. Просто добавьте компилятор nvcc. exe в список разрешенных приложений. Уж в нем-то вируса точно нет, при условии, что Вы скачали его с официального сайта NVidia.

Часть 3. Изучение синтаксиса языка CUDA C

После создания первого проекта CUDA следует более глубоко познакомиться с синтаксисом языка CUDA. Данный материал выходит за рамки практической части, поэтому его лучше изучать по теоретическому материалу, прилагаемому к данной работе, конспекту лекций или по дополнительным источникам. Одним из лучших источников сегодня является работа авторов Сандерс Дж., “Технология CUDA в примерах”. Здесь отметим лишь, что язык CUDA С очень сильно похож на обычный С, поэтому многие элементы синтаксиса окажутся Вам знакомы. Исключение составят лишь дополнительные функции и конструкции языка.

Часть 4. Задание

После ознакомления с синтаксисом языка, следует разработать программу на языке CUDA С в соответствии с вариантами заданий к лабораторной работе, приведенным в таблице 1. Все задания подобраны таким образом, чтобы ощущался эффект от использования CUDA технологии, в первую очередь, это, конечно же, время выполнения программы. Но и для студентов, не имеющих реального оборудования, выполнение программы не должно превращаться в мучительное ожидание. В результате объем вычислительной работы выбирался так, чтобы достигалась “золотая середина”.

Во всех заданиях требуется создать матрицу (вектор) или несколько матриц (векторов) одинаковой размерности, указанной в таблице 1, заполнить их считанными из текстового файла значениями. Текстовые файлы следует предварительно подготовить, заполнив их случайными числами. Затем реализовать задание, используя обработку данных на CUDA. В конце вывести результаты вычислений опять в текстовый файл.

Интерфейс программы – консольное приложение. В самом начале программа спрашивает имя входного и выходного файлов. Затем, после выполнения всех вычислений, печатает общее время работы (в секундах) на экране в виде дробного числа.

Для измерения времени работы кода см. функции GetTickCount(), clock(). Общий принцип таков: засекаем время до начала вычислений, засекаем после, отнимаем от второго первое, печатаем результат.

Содержание отчета:

- титульный лист;

- задание;

- код программы;

- экранная форма разработанного приложения;

- выводы.

Варианты заданий

Таблица 1. Описание заданий

Размер­ность массива или матрицы

Тип данных

Описание задания

1

217x217

цел.

Вычислить матрицу C = ½*A+B

2

216x216

вещ.

Вычислить матрицу C = (A+B)*5+8

3

215x215

цел.

Вычислить матрицу C = (BA)* ½–8

4

217x217

вещ.

Вычислить матрицу С = A*5 – B*8 + 3

5

211x211

цел.

Вычислить произведение матриц C = A*B

6

216x216

вещ.

Вычислить транспонированную матрицу C = AT

7

215x215

цел.

Проверить, является ли матрица A диагональной

8

217x217

вещ.

Проверить, является ли матрица A единичной

9

216x216

цел.

Проверить, является ли матрица A нулевой

10

215x215

вещ.

Проверить, что все числа в матрице меньше числа k, которое задает пользователь

11

234

цел.

Вычислить одномерный массив C = (AB)*4+5

12

233

вещ.

Вычислить одномерный массив C = (A+B)*6–10

13

232

цел.

Вычислить одномерный массив C = (BA)*½–8

14

231

вещ.

Вычислить одномерный массив C = A*3–B+3

15

230

цел.

Вычислить одномерный массив C = B+3*A–8

16

234

вещ.

Вычислить отраженный относительно середины массив C

17

233

цел.

Поменять в одномерном массиве элементы, находящиеся на четных и нечетных местах

18

232

вещ.

Проверить, является ли одномерный массив единичным

19

231

цел.

Проверить, является ли одномерный массив нулевым

20

230

вещ.

Проверить, что все числа в одномерном векторе меньше числа k, которое задает пользователь

21

216x216

вещ.

Вычислить матрицу C = ½*A+B

22

215x215

цел.

Вычислить матрицу C = (A+B)*5+8

23

214x214

вещ.

Вычислить матрицу C = (BA)* ½–8

24

216x216

цел.

Вычислить матрицу С = A*5 – B*8 + 3

25

210x210

вещ.

Вычислить произведение матриц C = A*B

26

215x215

цел.

Вычислить транспонированную матрицу C = AT

27

214x214

вещ.

Проверить, является ли матрица A диагональной

28

216x216

цел.

Проверить, является ли матрица A единичной

29

215x215

вещ.

Проверить, является ли матрица A нулевой

30

214x214

цел.

Проверить, что все числа в матрице меньше числа k, которое задает пользователь

31

233

вещ.

Вычислить одномерный массив C = (AB)*4+5

32

232

цел.

Вычислить одномерный массив C = (A+B)*6–10

33

231

вещ.

Вычислить одномерный массив C = (BA)*½–8

34

230

цел.

Вычислить одномерный массив C = A*3–B+3

35

229

вещ.

Вычислить одномерный массив C = B+3*A–8

36

233

цел.

Вычислить отраженный относительно середины массив C

37

232

вещ.

Поменять в одномерном массиве элементы, находящиеся на четных и нечетных местах

38

231

цел.

Проверить, является ли одномерный массив единичным

39

230

вещ.

Проверить, является ли одномерный массив нулевым

40

229

цел.

Проверить, что все числа в одномерном векторе меньше числа k, которое задает пользователь