
- •Курс лекций
- •Оглавление
- •1. Архитектура и принципы работы обычных эвм с центральным процессором (cpu) 9
- •2. Методы повышения производительности традиционных эвм 27
- •3. Типы архитектур высокопроизводительных вычислительных систем 45
- •4. Потоковые параллельные вычисления для физического моделирования 62
- •5. Применение графических процессоров на примерах сложения матриц и решения дифференциальных уравнений 82
- •6. Молекулярная динамика на графическом процессоре 100
- •7. Высокоскоростное моделирование систем с дальнодействием 125
- •8. Восстановление потенциалов межчастичных взаимодействий по температурной зависимости периода решетки методами высокоскоростного мдм на графических процессорах 145
- •9. Базовые особенности программирования графических процессоров шейдерной модели 4.0 160
- •Введение
- •1.Архитектура и принципы работы обычных эвм с центральным процессором (cpu)
- •1.1.Структура традиционной эвм
- •1.2.Организация работы эвм
- •1.3.Иерархия памяти компьютера
- •1.4. Выполнение команд
- •1.5.Требования к коммуникационным линиям
- •1.6.Устройства ввода-вывода
- •2.Методы повышения производительности традиционных эвм
- •2.1. Распараллеливание расчетов
- •2.2.Конвейерная обработка данных и команд
- •2.3.Высокопроизводительные процессоры
- •2.3.1.Суперскалярные процессоры
- •2.3.2.Процессоры risc с сокращенным набором команд
- •2.3.3.Процессоры со сверхдлинным командным словом
- •2.3.4.Векторные процессоры
- •2.3.5.Процессоры для параллельных компьютеров
- •2.3.6.Процессоры с многопоточной архитектурой
- •2.3.7.Технология Hyper-Threading
- •2.4.Требования к памяти высокопроизводительных эвм
- •2.5.Коммуникационная сеть высокопроизводительных эвм
- •2.5.1.Статические и динамические топологии и маршрутизация коммуникационных систем
- •2.5.2.Многокаскадные сети и методы коммутации
- •2.6.Классификация архитектур параллельных компьютеров
- •3.Типы архитектур высокопроизводительных вычислительных систем
- •3.1.Simd архитектура (с разделяемой и распределенной памятью)
- •3.2. Mimd архитектура с разделяемой и распределенной памятью
- •3.3. Комбинированные системы
- •3.4. Мультипроцессорные и мультикомпьютерные системы
- •3.5.Кластеры пэвм и рабочих станций
- •3.6.Особенности параллельного программирования
- •4.Потоковые параллельные вычисления для физического моделирования
- •4.1.Общие принципы распараллеливания расчётов
- •4.2.Обмен данными между процессором и памятью
- •4.3.Графические процессоры как вычислительные системы для поточно-параллельных расчётов
- •4.3.1.Вычислительные возможности центральных процессоров общего назначения и графических процессоров
- •4.3.2.Графический конвейер
- •4.3.3.История программируемости графических процессоров
- •4.3.4.Требования к алгоритмам для gpu, поддерживающих шейдерную модель 3.0
- •4.3.5.Возможности gpu в рамках шейдерной модели 3.0 и взаимодействие gpu с памятью
- •4.3.6.Проблема одинарной точности
- •4.4.Средства программирования графических процессоров
- •4.4.1.Общая структура программы для физического моделирования на графическом процессоре
- •4.4.2.Необходимое программное обеспечение
- •4.5.Области использования графических процессоров
- •5.Применение графических процессоров на примерах сложения матриц и решения дифференциальных уравнений
- •5.1.Распараллеливание независимых вычислений
- •5.2.Используемый графический процессор
- •5.3.Представление данных для графического процессора
- •5.4.Программирование вычислительного ядра
- •5.5.Взаимодействие центрального и графического процессоров
- •5.5.1.Функции центрального процессора
- •5.5.2.Пример программы
- •6.Молекулярная динамика на графическом процессоре
- •6.1.Принципы моделирования ионных кристаллов методом молекулярной динамики
- •6.2.Программирование графического процессора для расчёта действующих на ионы результирующих сил
- •6.2.1.Исходные данные
- •6.2.2.Представление исходных данных для gpu
- •6.2.3.Алгоритм расчёта результирующих сил с использованием графического процессора
- •6.2.4.Шейдер для расчёта результирующей силы
- •6.3.Исполнение шейдера из программы мд-моделирования на c#
- •6.3.1.Этапы алгоритма моделирования, исполняемые на cpu
- •6.3.2.Процедуры на c#, обеспечивающие работу с графическим процессором
- •6.4.Постановка граничных условий и стабилизация макросостояния молекулярно-динамической системы
- •6.4.1.Компенсация импульса и момента импульса
- •6.4.2.Стабилизация температуры
- •7.Высокоскоростное моделирование систем с дальнодействием
- •7.1.Актуальность моделирования
- •7.2.Высокоскоростные алгоритмы моделирования систем с дальнодействующими силами
- •7.3.Методика высокоскоростного молекулярно-динамического моделирования диоксида урана
- •7.4.Экспериментальные результаты и их обсуждение
- •7.5.Анализ зависимостей среднего квадрата смещений ионов кислорода от времени
- •8.Восстановление потенциалов межчастичных взаимодействий по температурной зависимости периода решетки методами высокоскоростного мдм на графических процессорах
- •8.1.Задача восстановления потенциалов межчастичных взаимодействий в кристаллах
- •8.2.Исходные данные и метод восстановления потенциалов
- •8.3.Модель и детали реализации
- •9.Базовые особенности программирования графических процессоров шейдерной модели 4.0
- •9.1.Предпосылки появления новой шейдерной модели
- •9.2.Архитектура gpu шейдерной модели 4.0. Преимущества этой модели
- •9.2.1.Иерархия вычислительных блоков и памяти в шейдерной модели 4.0
- •9.2.2.Конвейерная обработка данных на gpu sm4
- •9.2.3.Логическая структура вычислений на gpu sm4
- •9.2.4.Преимущества gpu шейдерной модели 4.0
- •9.3.Средства высокоуровневого программирования gpu шейдерной модели 4.0
- •9.3.1.Совместимость с шейдерной моделью 3.0
- •9.3.2.Специальные средства программирования gpu sm4. Cuda
- •9.3.3.Средства для написания и компиляции программ на cuda
- •9.3.4.Структура программы на cuda
- •9.4.Перемножение матриц на cuda
- •9.4.1.Алгоритм перемножения матриц
- •9.4.2.Процедура перемножения матриц на gpu sm4
- •9.4.3.Вызов процедуры перемножения матриц из программы на c
- •9.5.Молекулярная динамика на cuda
- •9.5.1.Алгоритм с использованием разделяемой памяти
- •9.5.2.Расчёт сил на gpu с использованием 3-го закона Ньютона
- •Библиографический список
- •Приложение 1 Операторы и функции языка hlsl, использованные в курсе лекций п.1.2. Типы данных
9.4.3.Вызов процедуры перемножения матриц из программы на c
В принципе, использование CUDA позволяет писать процедуры для графического и центрального процессоров в одном и том же текстовом файле. В настоящем примере коды для GPU и для CPU разнесены в разные файлы, для того чтобы лучше структурировать проект. В Приложении 2 мы приводим код, исполняемый на СPU, с краткими комментариями. Подробности даны, например, в руководстве пользователя CUDA от NVIDIA [67].
В проект также должны входить заголовочный файл matrixMul.h и файл, содержащий непараллельную процедуру перемножения матриц на CPU matrixMul_gold.cpp. Тексты этих файлов [68] также приведены в Приложении 2.
9.5.Молекулярная динамика на cuda
9.5.1.Алгоритм с использованием разделяемой памяти
Самые последние графические процессоры уже поддерживают вычисления с двойной точностью, что в принципе позволяет полностью реализовывать на GPU шаги молекулярной динамики, не обращаясь к центральному процессору. Всё же, здесь мы ограничимся только рассмотрением алгоритма расчёта межчастичных сил, который вполне демонстрирует новые возможности 4-й шейдерной модели и CUDA [69].
Этот алгоритм, приведённый на рис. 9.7, отличается от рассмотренных в главе 6 тем, что включает в себя «ручную» оптимизацию использования «быстрой» разделяемой параллельной памяти, которой не существовало у GPU шейдерной модели 3.0.
Кодирование алгоритма молекулярной динамики на CUDA не имеет принципиальных особенностей по сравнению с перемножением матриц, так что мы не будем приводить весь код. Остановимся только на одной из простых реализаций «треугольного» цикла расчёта сил, использующего 3-й закон Ньютона для двукратного уменьшения объёма вычислений.
9.5.2.Расчёт сил на gpu с использованием 3-го закона Ньютона
На рис. 9.8a (без учёта распараллеливания) показан самый простой цикл расчёта действующих между частицами сил. На GPU SM3 можно (с распараллеливанием) реализовать только этот цикл, поскольку каждая сила Fi рассчитывается независимо от сил Fj, действующих на другие частицы. Распараллеливание этого же цикла на GPU SM4 показано на рис. 9.7.
Вместе с тем, согласно 3-му закону Ньютона, Fij = Fji, то есть Uij(Rij) = Uji(Rji). Таким образом, алгоритм расчёта сил можно модифицировать согласно рис. 9.8б. В новом цикле суммирование по j начинается с j = i+1, а не с нуля, так что весь двойной цикл по i, j, становящийся «треугольным», содержит в 2 раза меньше операций вычисления сил. На рис. 9.9, иллюстрирующем «треугольный» цикл, тёмные прямоугольники соответствуют парам (i, j), для которых силы Fij реально считаются, а белые – обратным комбинациям (i, j), для которых Fji = Fij.
Рис. 9.7. Молекулярная динамика на графическом процессоре шейдерной модели 4.0
Ниже с комментариями приведена реализация «треугольного» цикла с 3-м законом Ньютона на CUDA. Для наглядности используется только один мультипроцессор. Каждый i-й поток суммирует парные взаимодействия i-й частицы и записывает их в разделяемую память, а в конце сохраняет одну из накопленных сумм в линейный массив force (каждой частице соответствует только один элемент), расположенный в глобальной памяти. Это позволяет минимизировать количество обращений к медленной общей памяти.
|
|
a) |
б) |
Рис. 9.8. Расчёт сил с учётом и без учёта 3-го закона Ньютона
Рис. 9.9. «Треугольный» цикл расчёта сил
Процедура вычисления сил в «треугольном» цикле на CUDA
/* Спецификатор __global__ означает, что вся процедура будет исполняться на GPU как вычислительное ядро */
__global__ void kernel_NxN(float4 force[], float4 pos[], int type[], float4 coefs[]) {
/* Переменные, описываемые без спецификаторов, будут хранится в том кэше GPU, который называют «памятью для констант». Они не будут меняться по ходу алгоритма: */
int j;
/* Вычислительные потоки в данном случае упорядочены в линейный массив. Каждый поток рассчитывает силу Fi, действующую на одну из частиц: */
int i = threadIdx.x;
/* Тип частицы type[i] и 4-вектор с координатами частицы pos[i] копируются в кэш, для того чтобы потом не обращаться за ними внутри цикла по j к медленной видеопамяти: */
int type_i = type[i];
float4 pos_i = pos[i];
/* Создаётся переменная (4-вектор) force_i, в которой будет суммироваться результирующая сила, действующая на частицу i со стороны остальных частиц; в начале расчёта она зануляется */
float4 force_i = { 0, 0, 0, 0 };
/* В разделяемой памяти (на что указывает модификатор __shared__ ) создаются массивы, содержащие координаты и типы всех частиц, параметры всех потенциалов взаимодействия (coefs_ij[4], где coefs_ij – сам по себе 4-вектор), а также все результирующие силы (force_j[N]), действующие на каждую из частиц: */
__shared__ float4 pos_j[N];
__shared__ int type_j[N];
__shared__ float4 coefs_ij[4];
__shared__ float4 force_j[N];
/* Следующий блок операторов копирует данные из медленной «глобальной» памяти GPU, куда их перед обращением к GPU записывает центральный процессор, в быструю разделяемую память. Каждый из потоков копирует элементы массивов, относящиеся к «своей» частице i, а первые 4 потока – ещё и параметры потенциалов взаимодействия */
if (threadIdx.x < 4) coefs_ij[i] = coefs[i];
pos_j[i] = pos[i]; type_j[i] = type[i];
force_j[j] = make_float4(0, 0, 0, 0);
/* Синхронизация потоков. Выполнение программы за функцией __syncthreads() продолжится только после того, как все потоки завершат копирование данных в разделяемую память */
__syncthreads();
/* Цикл, в котором суммируется сила, действующая на i-ю частицу со стороны остальных. Индекс j изменяется до N + i для того, чтобы во всех потоках, независимо от значения i, в этом цикле было одинаковое количество итераций. Фактически, при j N внутри цикла ничего не делается */
for (j = i+1; j < N + i; j++)
{
if (j < N)
{
/* Функция force_ij возвращает силу, действующую между частицами i и j. Аргументами функции являются координаты частиц и параметры потенциала взаимодействия */
float4 Fij = force_ij(pos_i, pos_j[j], coefs_ij[type_i + type_j[j]]);
/* Применение 3-го закона Ньютона
force_i += Fij; force_j[j] -= Fij;
}
/* Синхронизация потоков, необходимая для устранения возможных конфликтов доступа к элементам массива force_j[j]: */
__syncthreads();
}
/* Получение окончательных результирующих сил
force[i] = force_i + force_j[i];
}
/* Функция расчёта парной силы force_ij. Возвращает 4-вектор с компонентами силы (четвёртый элемент – пустой). Спецификатор __device__ означает, что функция и вызывается, и исполняется графическим процессором */
__device__ float4 force_ij(float4 pos_i, float4 pos_j, float4 c)
{
float4 R = pos_i - pos_j; R.w = rsqrt(max(R * R, 1e-4));
return R * (c.x * R.w * R.w * R.w + pow(c.y * R.w, c.z));
}