Лабораторная работа №2 "Работа с разделяемой памятью" по дисциплине "Программирование графических процессоров". Вариант общий
Состав работы
|
|
|
|
Работа представляет собой rar архив с файлами (распаковать онлайн), которые открываются в программах:
- Adobe Acrobat Reader
Описание
Выполнение лабораторной работы поможет получить навыки требующиеся для выполнения второго и третьего заданий контрольной работы.
Задание
1. Прочитайте главу из теоретического материала "Разделяемая память" и ответьте на контрольные вопросы (ответы на контрольные вопросы не нужно включать в отчёт по лабораторной работе).
2. Оптимизируйте алгоритмы, реализованные в лабораторной работе №1 при помощи разделяемой памяти.
3. Постройте графики зависимости времени выполнения алгоритма от размера матрицы и вектора (Размеры матрицы 1000x500, 1000x1000, 1500x1000, 2000x1000, 2000x1500, 2500x1500, 2500x2000).
4. Проанализируйте, реализованные алгоритмы при помощи утилиты nvprof на эффективность доступа к глобальной памяти.
Методические указания по выполнению лабораторной работы
Разделяемая память – это своего рода кэш. Ускорения от использования разделяемой памяти можно достичь только если к каким-то данным происходит многократное обращение. Тогда переместив их в разделяемую память из глобальной можно сократить время затраченное на обращение в память за счёт высокой скорости разделяемой памяти.
Рассмотрим схему параллельного умножения матрицы на вектор.
Рис. 1 – схема умножения матрицы на вектор
Каждая нить берёт по одной строке матрицы и умножает попарно элементы строки на элементы вектора. Все нити используют один и тот же вектор. Скопировав вектор в разделяемую память можно получить ускорения выполнения алгоритма. Но проблема разделяемой памяти в том, что её объём очень мал по сравнению с объёмом глобальной памяти. Поэтому нужно предусмотреть ситуацию когда вектор полностью в память не помещается.
Учитывая, что разделяемой памяти может не хватить нужно модифицировать алгоритм таким образом чтобы часть вектора копировалась в разделяемую память. Нити умножали часть строки на часть вектора, расположенного в разделяемой памяти. Затем копировали следующую часть вектора в разделяемую память и умножали элементы следующей части строки и т.д. как показано на рисунке 2.
Рис. 2 – умножение нитью строки на вектор с копированием частей вектора в разделяемую память
Копирование частей вектора можно производить параллельно, каждая нить может копировать в разделяемую память один или несколько элементов. Таким образом псевдокод алгоритма будет выглядеть следующим образом:
//Выделяем разделяемую память
//Количество элементов будет равно количеству нитей в блоке.
__shared__ shared_vector[THREAD_PER_BLOCK];
//k - номер части вектора. +1 потому что M не обязательно делится нацело
for(k = 0; k < (M / THREAD_PER_BLOCK) + 1; ++k) {
//p - реальный номер элемента вектора
//который будет скопирован нитью в разделяемую память
p = threadIdx.x + THREAD_PER_BLOCK * k;
//Проверка на выход за пределы вектора
if(p < M) {
//Копирование из глобальной памяти в разделяемую
//Т.к. размер разделяемой памяти равен размеру блока
//Каждая нить может скопировать по одному элементу
shared_vector[threadIdx.x] = V[threadIdx.x + THREAD_PER_BLOCK * k];
}
//Синхронизация. Нужно дождаться пока все нити скопируют свои элементы
//Потому что каждая нить использует скопированную часть вектора полностью
__syncthread();
//i - глобальный номер нити, N - количество строк в матрице
//Проверка не выходим ли за границы матрицы
if (i < N) {
//Умножение части вектора на часть строки
//j - порядковый номер элемента в части вектора или строки матрицы
//чтобы получить реальный номер элемента матрицы
//нужно прибавить j количеству полностью обработанных элементов
for(j = 0; j < THREAD_PER_BLOCK; ++j) {
C[i] += A[i][j + k * THREAD_PER_BLOCK] * shared_vector[j];
}
}
//Синхронизация нужна для того чтобы убедиться
//что все нити закончили работу с частью вектора
//потому что следующая операция - перезапись разделяемой памяти
__syncthread();
}
В данном коде можно сделать ещё одну оптимизацию – перенести операции над вектором C в разделяемую память. И скопировать результат в глобальную только после того как результат будет посчитан. С учётом этого алгоритм будет выглядеть следующим образом:
//Выделяем разделяемую память
//Количество элементов будет равно количеству нитей в блоке.
__shared__ shared_vector[THREAD_PER_BLOCK];
__shared__ shared_c[THREAD_PER_BLOCK];
shared_c[threadId.x] = 0;
__syncthread();
//k - номер части вектора. +1 потому что M не обязательно делится нацело
for(k = 0; k < (M / THREAD_PER_BLOCK) + 1; ++k) {
//p - реальный номер элемента вектора
//который будет скопирован нитью в разделяемую память
p = threadIdx.x + THREAD_PER_BLOCK * k;
//Проверка на выход за пределы вектора
if(p < M) {
//Копирование из глобальной памяти в разделяемую
//Т.к. размер разделяемой памяти равен размеру блока
//Каждая нить может скопировать по одному элементу
shared_vector[threadIdx.x] = V[threadIdx.x + THREAD_PER_BLOCK * k];
}
//Синхронизация. Нужно дождаться пока все нити скопируют свои элементы
//Потому что каждая нить использует скопированную часть вектора полностью
__syncthread();
//i - глобальный номер нити, N - количество строк в матрице
//Проверка не выходим ли за границы матрицы
if (i < N) {
//Умножение части вектора на часть строки
//j - порядковый номер элемента в части вектора или строки матрицы
//чтобы получить реальный номер элемента матрицы
//нужно прибавить j количеству полностью обработанных элементов
for(j = 0; j < THREAD_PER_BLOCK; ++j) {
shared_c[threadIdx.x] += A[i][j + k * THREAD_PER_BLOCK] * shared_vector[j];
}
}
//Синхронизация нужна для того чтобы убедиться
//что все нити закончили работу с частью вектора
//потому что следующая операция - перезапись разделяемой памяти
__syncthread();
}
if ( i < N ) {
С[i] = shared_c[threadId.x];
}
__syncthread();
Модификация кода хоста в этой лабораторной работе не требуется
Для анализа эффективности доступа к разделяемой памяти используйте утилиту nvprof. События для профилирования: shared_ld_bank_conflict – количество конфликтов банков памяти при считывании данных, shared_st_bank_conflict– количество конфликтов банков памяти при записи данных. И метрики: shared_efficiency – эффективность использования пропускной способности шины данных разделяемой памяти, shared_load_transactions_per_request – количество транзакций при каждом запросе к разделяемой памяти.
По аналогии оптимизируйте алгоритм умножения вектора на матрицу.
Задание
1. Прочитайте главу из теоретического материала "Разделяемая память" и ответьте на контрольные вопросы (ответы на контрольные вопросы не нужно включать в отчёт по лабораторной работе).
2. Оптимизируйте алгоритмы, реализованные в лабораторной работе №1 при помощи разделяемой памяти.
3. Постройте графики зависимости времени выполнения алгоритма от размера матрицы и вектора (Размеры матрицы 1000x500, 1000x1000, 1500x1000, 2000x1000, 2000x1500, 2500x1500, 2500x2000).
4. Проанализируйте, реализованные алгоритмы при помощи утилиты nvprof на эффективность доступа к глобальной памяти.
Методические указания по выполнению лабораторной работы
Разделяемая память – это своего рода кэш. Ускорения от использования разделяемой памяти можно достичь только если к каким-то данным происходит многократное обращение. Тогда переместив их в разделяемую память из глобальной можно сократить время затраченное на обращение в память за счёт высокой скорости разделяемой памяти.
Рассмотрим схему параллельного умножения матрицы на вектор.
Рис. 1 – схема умножения матрицы на вектор
Каждая нить берёт по одной строке матрицы и умножает попарно элементы строки на элементы вектора. Все нити используют один и тот же вектор. Скопировав вектор в разделяемую память можно получить ускорения выполнения алгоритма. Но проблема разделяемой памяти в том, что её объём очень мал по сравнению с объёмом глобальной памяти. Поэтому нужно предусмотреть ситуацию когда вектор полностью в память не помещается.
Учитывая, что разделяемой памяти может не хватить нужно модифицировать алгоритм таким образом чтобы часть вектора копировалась в разделяемую память. Нити умножали часть строки на часть вектора, расположенного в разделяемой памяти. Затем копировали следующую часть вектора в разделяемую память и умножали элементы следующей части строки и т.д. как показано на рисунке 2.
Рис. 2 – умножение нитью строки на вектор с копированием частей вектора в разделяемую память
Копирование частей вектора можно производить параллельно, каждая нить может копировать в разделяемую память один или несколько элементов. Таким образом псевдокод алгоритма будет выглядеть следующим образом:
//Выделяем разделяемую память
//Количество элементов будет равно количеству нитей в блоке.
__shared__ shared_vector[THREAD_PER_BLOCK];
//k - номер части вектора. +1 потому что M не обязательно делится нацело
for(k = 0; k < (M / THREAD_PER_BLOCK) + 1; ++k) {
//p - реальный номер элемента вектора
//который будет скопирован нитью в разделяемую память
p = threadIdx.x + THREAD_PER_BLOCK * k;
//Проверка на выход за пределы вектора
if(p < M) {
//Копирование из глобальной памяти в разделяемую
//Т.к. размер разделяемой памяти равен размеру блока
//Каждая нить может скопировать по одному элементу
shared_vector[threadIdx.x] = V[threadIdx.x + THREAD_PER_BLOCK * k];
}
//Синхронизация. Нужно дождаться пока все нити скопируют свои элементы
//Потому что каждая нить использует скопированную часть вектора полностью
__syncthread();
//i - глобальный номер нити, N - количество строк в матрице
//Проверка не выходим ли за границы матрицы
if (i < N) {
//Умножение части вектора на часть строки
//j - порядковый номер элемента в части вектора или строки матрицы
//чтобы получить реальный номер элемента матрицы
//нужно прибавить j количеству полностью обработанных элементов
for(j = 0; j < THREAD_PER_BLOCK; ++j) {
C[i] += A[i][j + k * THREAD_PER_BLOCK] * shared_vector[j];
}
}
//Синхронизация нужна для того чтобы убедиться
//что все нити закончили работу с частью вектора
//потому что следующая операция - перезапись разделяемой памяти
__syncthread();
}
В данном коде можно сделать ещё одну оптимизацию – перенести операции над вектором C в разделяемую память. И скопировать результат в глобальную только после того как результат будет посчитан. С учётом этого алгоритм будет выглядеть следующим образом:
//Выделяем разделяемую память
//Количество элементов будет равно количеству нитей в блоке.
__shared__ shared_vector[THREAD_PER_BLOCK];
__shared__ shared_c[THREAD_PER_BLOCK];
shared_c[threadId.x] = 0;
__syncthread();
//k - номер части вектора. +1 потому что M не обязательно делится нацело
for(k = 0; k < (M / THREAD_PER_BLOCK) + 1; ++k) {
//p - реальный номер элемента вектора
//который будет скопирован нитью в разделяемую память
p = threadIdx.x + THREAD_PER_BLOCK * k;
//Проверка на выход за пределы вектора
if(p < M) {
//Копирование из глобальной памяти в разделяемую
//Т.к. размер разделяемой памяти равен размеру блока
//Каждая нить может скопировать по одному элементу
shared_vector[threadIdx.x] = V[threadIdx.x + THREAD_PER_BLOCK * k];
}
//Синхронизация. Нужно дождаться пока все нити скопируют свои элементы
//Потому что каждая нить использует скопированную часть вектора полностью
__syncthread();
//i - глобальный номер нити, N - количество строк в матрице
//Проверка не выходим ли за границы матрицы
if (i < N) {
//Умножение части вектора на часть строки
//j - порядковый номер элемента в части вектора или строки матрицы
//чтобы получить реальный номер элемента матрицы
//нужно прибавить j количеству полностью обработанных элементов
for(j = 0; j < THREAD_PER_BLOCK; ++j) {
shared_c[threadIdx.x] += A[i][j + k * THREAD_PER_BLOCK] * shared_vector[j];
}
}
//Синхронизация нужна для того чтобы убедиться
//что все нити закончили работу с частью вектора
//потому что следующая операция - перезапись разделяемой памяти
__syncthread();
}
if ( i < N ) {
С[i] = shared_c[threadId.x];
}
__syncthread();
Модификация кода хоста в этой лабораторной работе не требуется
Для анализа эффективности доступа к разделяемой памяти используйте утилиту nvprof. События для профилирования: shared_ld_bank_conflict – количество конфликтов банков памяти при считывании данных, shared_st_bank_conflict– количество конфликтов банков памяти при записи данных. И метрики: shared_efficiency – эффективность использования пропускной способности шины данных разделяемой памяти, shared_load_transactions_per_request – количество транзакций при каждом запросе к разделяемой памяти.
По аналогии оптимизируйте алгоритм умножения вектора на матрицу.
Дополнительная информация
Уважаемый студент дистанционного обучения,
Оценена Ваша работа по предмету: Программирование графических процессоров
Вид работы: Лабораторная работа 2
Оценка:Зачет
Дата оценки: 27.02.2021
Рецензия:Уважаемый
Ваша работа зачтена.
Милешко Антон Владимирович
Оценена Ваша работа по предмету: Программирование графических процессоров
Вид работы: Лабораторная работа 2
Оценка:Зачет
Дата оценки: 27.02.2021
Рецензия:Уважаемый
Ваша работа зачтена.
Милешко Антон Владимирович
Похожие материалы
Лабораторная работа 2 (Вариант 3) По дисциплине: Программирование графических процессоров. Тема: «Работа с разделяемой памятью».
alexadubinina
: 21 ноября 2024
Задание
1. Прочитайте главу из теоретического материала "Разделяемая память" и ответьте на контрольные вопросы (ответы на контрольные вопросы не нужно включать в отчёт по лабораторной работе).
2. Оптимизируйте алгоритмы, реализованные в лабораторной работе №1 при помощи разделяемой памяти.
3. Постройте графики зависимости времени выполнения алгоритма от размера матрицы и вектора (Размеры матрицы 1000x500, 1000x1000, 1500x1000, 2000x1000, 2000x1500, 2500x1500, 2500x2000).
4. Проанализируйте, реал
300 руб.
Языки программирования. Вариант общий
SibGOODy
: 12 мая 2020
Контрольная работа
«Разработка динамических страниц на ЯП Python»
Цель работы: создание динамических страниц на языке высокого уровня Python при помощи CGI-скриптов.
CGI-скрипты – это исполняемые файлы, которые выполняются веб-сервером, когда в URL запрашивается соответствующий скрипт.
Методика выполнения работы включает следующие этапы:
1. Настройка локального сервера.
2. Написание и отладка CGI-скриптов.
3. Написание и отладка CGI-скриптов: получение данных.
600 руб.
Персональный менеджмент. Вариант общий
rmn77
: 19 марта 2020
Контрольная работа. Персональный менеджмент. Вариант общий
Задание 1
Цель работы – отразить результаты работы по самоанализу своей деятельности, целеполаганию и формированию плана профессиональной карьеры.
Примерная структура работы включает:
1. Мои профессиональные цели.
2. Ситуация на рынке труда. Обзор требований работодателей к соискателям. Самоанализ.
Задание 2 (УК-6.2)
ЗАДАНИЕ (тип эссе)
Руководствуясь личностным подходом к персональному менеджменту, выполните SWOT-анализ личных и пр
120 руб.
Онлайн ТЕСТ Философия Вариант общий
sibguti-help
: 5 ноября 2024
Вопрос №1
Тип культуры не подразумевает этнического единства, развиваясь как комплекс отдельных народов и государств. Экспансивные устремления способствовали подвижности её географических границ:
культура восточная
культура западная
культура национальная
Вопрос №2
Перечислите античные философские школы в порядке их возникновения?
Пифагореизм
Платоновская Академия
Ликей Аристотеля
Неоплатонизм
Вопрос №3
Компетенция человека, действующего в сфере свободного предпринимательства, основанная на з
450 руб.
Онлайн ТЕСТ Философия Вариант общий
sibguti-help
: 28 октября 2024
Вопрос №1
Интенсивное сближение цивилизаций, выражающееся во взаимопроникновении, конвергенции передовых технологий, массовой культуры, религий, идей, связанных с отношением к личности:
диалог культур
новации
традиции
Вопрос №2
Ф.Аквинский, решая вопрос об отношении веры и разума, исходил из того, что
Религия возвышается над философией
Религия и философия одним и тем же способом приходят к истине
Религия не может быть совершенно автономной по отношению к философии
Философия возвышается над ре
450 руб.
Отчет по ознакомительной практике (вариант общий)
Учеба "Под ключ"
: 9 сентября 2022
Задание на ознакомительную практику состоит из четырех мини-рефератов:
Схему из файла читать сверху-вниз. Каждому блоку схемы соответствует список тем.
мини-реферат 1: Из базовой секции выбрать одну тему
мини-реферат 2 и 3: Из секции специализации выбрать две темы (из разных разделов), которые по схеме исходят из блока 1
мини-реферат 4. Из секции углублённой специализации выбрать одну тему, которая по схеме следует из блоков 2 или 3 секции специализации
Важно: Каждый последующий блок тем до
800 руб.
"Социология и право". Вариант общий. ДО СИБГУТИ
Ivannsk97
: 14 июня 2021
Тема: "Нищенство как социальная проблема"
Темы рефератов по модулю «Социология»
1. Социологическое воображение в представлениях Ч.Миллса
2. З.Бауман: «мыслить социологически» - что это значит?
3. Социальное действие в концепциях М.Вебера и Т.Парсонса: сравнительный анализ
4. Социальное взаимодействие как обмен
5. Социальная природа юмора
6. Драматургический анализ: «самопрезентация» (И.Гофман)
7.Социальныйконтроль над девиантностью в современной России
8.Проблемабюрократии в современных
100 руб.
Общая теория связи, Лабораторная работа, Вариант общий
artinjeti
: 13 ноября 2018
Лабораторная работа №1
«Исследование помехоустойчивости дискретных видов модуляции»
Цель работы: изучение и экспериментальное исследование влияния вида модуляции (AM, ЧМ, ФМ) на помехоустойчивость системы передачи дискретных сообщений, изучение методики экспериментального измерения вероятности ошибки.
Лабораторная работа №2
«Исследование помехоустойчивости методов передачи и приема дискретных сигналов на автоматизированном рабочем месте СПИ»
Цель работы: изучение методов обработки дискретных с
20 руб.
Другие работы
Лабораторная работа №1 По дисциплине: Основы теории цепей «Законы Ома и Кирхгофа в резистивных цепях» Вариант №6
magoter
: 1 мая 2023
1. Цель работы:
Изучение и экспериментальная проверка законов Ома и Кирхгофа в разветвленной электрической цепи, содержащей источник и резистивные элементы.
2. Подготовка к выполнению работы:
При подготовке к работе необходимо изучить: законы Ома для пассивного участка цепи, участка цепи с активными (источники) и пассивными (нагрузки) элементами; первый закон Кирхгофа – для узла цепи; второй закон Кирхгофа – для замкнутого контура цепи (глава 1 электронного учебника).
3. Теоретическо
300 руб.
Теория связи, Разработка системы связи для передачи непрерывных сообщений дискретными сигналами.Вариант 02
кайлорен
: 2 декабря 2019
Исходные данные
1. Номер варианта: N = 2.
2. Вид сигнала в канале связи: ДЧМ.
3. Скорость передачи сигналов: V = 16000, Бод.
4. Амплитуда канальных сигналов: .
5. Дисперсия шума: .
6. Априорная вероятность передачи символов "1": p(1) = 0.18.
7. Способ приема сигнала: КГ.
8. Полоса пропускания реального приемника:
9. Значение отсчета принятой смеси сигнала и помехи на входе решающей схемы приёмника при однократном отсчете: .
10. Значения отсчетов принятой смеси сигнала и помехи при
300 руб.
Программирование разветвляющихся процессов
DaemonMag
: 4 февраля 2010
Лабораторная работа №1 по информатике СибГУТИ 2 семестр
Для этой лабораторной задание одно, вариант не выбирается
Программирование разветвляющихся процессов
Работа выполнена на языке Паскаль
Задание: Даны x, y, z. Найти max(x+y+z, xyz) +3
30 руб.
Лабораторные работы по теме программирование на языке Паскаль. Сибгути ДО. 1-й семестр
dezoway
: 23 октября 2021
Лабораторно-практическая работа №1
по дисциплине: Программирование
Задание:
Разработать программу для вычисления:
1) значения заданного арифметического выражения.
2) значения заданной функции;
и вывода на экран полученных результатов.
Значения исходных данных выбираются произвольно. Ввод организовывать любым известным вам способом (использовать не менее двух способов).
Лабораторно-практическая работа № 2
по дисциплине: Программирование
Задание:
Написать программу для вычисления заданного вы
120 руб.