русс | укр

Языки программирования

ПаскальСиАссемблерJavaMatlabPhpHtmlJavaScriptCSSC#DelphiТурбо Пролог

Компьютерные сетиСистемное программное обеспечениеИнформационные технологииПрограммирование

Все о программировании


Linux Unix Алгоритмические языки Аналоговые и гибридные вычислительные устройства Архитектура микроконтроллеров Введение в разработку распределенных информационных систем Введение в численные методы Дискретная математика Информационное обслуживание пользователей Информация и моделирование в управлении производством Компьютерная графика Математическое и компьютерное моделирование Моделирование Нейрокомпьютеры Проектирование программ диагностики компьютерных систем и сетей Проектирование системных программ Системы счисления Теория статистики Теория оптимизации Уроки AutoCAD 3D Уроки базы данных Access Уроки Orcad Цифровые автоматы Шпаргалки по компьютеру Шпаргалки по программированию Экспертные системы Элементы теории информации

Разделяемая память и её использование.


Дата добавления: 2015-01-16; просмотров: 1006; Нарушение авторских прав


Каждый мультипроцессор содержит 16 Кб разделяемой памяти. Эта память поровну делится между всеми блоками сетки. Разделяемая память используется для передачи параметров при запуске ядра. Поэтому желательно избегать передачи большого объема данных. В случае большого объема можно использовать константную память. Существует два способа выделения разделяемой памяти. Простейший заключается в явном задании размеров массивов.

__global__ void inckernel (float *a)

{ __shared__ float buf [256];

buf[threadIdx.x] = a[blockIdx.x*blockDim.x+threadIdx.x];

}

В данном способе компилятор автоматически выделяет необходимое количество разделяемой памяти для каждого блока.

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

__global__ void inckernel (float *a)

{ __shared__ float buf [];

buf[threadIdx.x] = a[blockIdx.x*blockDim.x+threadIdx.x];

}

inckernel <<<dim3(n/256),dim3(256), k*sizeof(float)>>> (a);

В данном случае каждому блоку будет дополнительно выделено k*sizeof(float) разделяемой памяти, которая будет доступна через массив buf. Имеется возможность задания нескольких массивов в разделяемой памяти. При этом если их размер не указан, то в момент запуска ядра все они будут расположены в начале выделенной блоку дополнительной разделяемой памяти. Для избегания этого конфликта программист должен сам разделить память между такими массивами.

__global__ void kernel (float *a, int k)

{ __shared__ float buf1[ ];

__shared__ float buf2[ ];

buf1[threadIdx.x] = a[blockIdx.x*blockDim.x+threadIdx.x];

buf2[k+threadIdx.x] = a[blockIdx.x*blockDi.x+threadIdx.x+k];

}

Частным случаем использования разделяемой памяти является хранение постоянно используемых значений.



Оптимизация задачи о N телах.

Рассмотренный вариант задачи упирается в доступ к глобальной памяти. Для каждого тела необходимо произвести N чтений положений других тел. При этом все нити одного блока обращаются к одним и тем же данным, т.е. присутствует много избыточных чтений. Дадим каждому блоку массив в разделяемой памяти. Весь исходный массив тел разделим на группы с длиной, равной размеру блока. Для каждого тайла производится загрузка в разделяемую память. Далее ядро добавляет влияние всех тел данного тайла на тела, просчитываемые нитями блока, после чего переходит к следующему тайлу. Поскольку размер массива в разделяемой памяти равен размеру блока, то каждая нить загружает по одному элементу. Поскольку нити не выполняются физически параллельно, то необходима их синхронизация.

При работе с разделяемой памятью имеются свои способы оптимального доступа. Вся разделяемая память разбита на 16 банков. Каждый из них способен выполнить одно чтение или запись 32-битового слова. Если 16 нитей полуварпа обратятся к 16 подряд идущим 32-битовым словам, то конфликта банков не возникает.

__shared__ float buf[128];

float v = buf[baseIndex+threadIdx.x];

 

Нити могут обращаться к банкам как угодно, только не в один.

Компилятор Cuda C создает копию переменных в разделяемой памяти в каждом блоке, запускаемой на видеокарте. Все нити, работающие в одном блоке, разделяют эту переменную, но не могут ни увидеть, ни изменить её копию в других блоках. Разделяемая память играет роль внутриблочного программно-управляемого КЭШа. При этом очень важен механизм синхронизации. Без синхронизации возникла бы «гонка», и правильность результатов расчета оказалась бы зависимой от условий оборудования.

Задача: скалярное произведение.

В ядре каждый перемножает пару соответствующих элементов, а после этого переходит к следующей паре. При этом каждая нить сохраняет сумму произведений тех пар, которые обрабатывает. После обработки пары индекс нити увеличивается на величину, равную общему числу нитей. Имеется определение буфера разделяемой памяти с именем cache. В этом буфере будет храниться частичная сумма, вычисленная в данной нити. При выделении глобальной памяти принимались во внимание все нити, исполняющие данное ядро. Размер области вычислялся как произведение числа нитей на общее число блоков. В данном случае компилятор создает копию разделяемых переменных для каждого блока, поэтому требуется выделить ровно столько памяти, чтобы у каждой нити был свой номер. Дойдя до конца массива нить сохранить вычисленную сумму в cache. Далее требуется просуммировать все значения, находящиеся в cache. Процедура, в результате которой из входного массива получается меньший массив, называется редукцией. Главная идея заключается в том, что каждая нить складывает 2 значения и помещает результат обратно в тот же массив cache. Таким образом в результате одной операции число элементов массива уменьшается вдвое. При выходе из цикла в каждом блоке остается одно число. Оно находится в первом элементе массива cache и является суммой парных произведений.



<== предыдущая лекция | следующая лекция ==>
Оптимизация работы с глобальной памятью. | Реализация на cuda базовых операций над массивами.


Карта сайта Карта сайта укр


Уроки php mysql Программирование

Онлайн система счисления Калькулятор онлайн обычный Инженерный калькулятор онлайн Замена русских букв на английские для вебмастеров Замена русских букв на английские

Аппаратное и программное обеспечение Графика и компьютерная сфера Интегрированная геоинформационная система Интернет Компьютер Комплектующие компьютера Лекции Методы и средства измерений неэлектрических величин Обслуживание компьютерных и периферийных устройств Операционные системы Параллельное программирование Проектирование электронных средств Периферийные устройства Полезные ресурсы для программистов Программы для программистов Статьи для программистов Cтруктура и организация данных


 


Не нашли то, что искали? Google вам в помощь!

 
 

© life-prog.ru При использовании материалов прямая ссылка на сайт обязательна.

Генерация страницы за: 0.191 сек.