- •Курс лекций
- •Оглавление
- •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. Типы данных
Приложение 1 Операторы и функции языка hlsl, использованные в курсе лекций п.1.2. Типы данных
texture – двухмерный массив исходных данных (текстура), ячейки которого адресуются двумя координатами – парой чисел с плавающей точкой;
sampler – автоматическая процедура, осуществляющая выборку данных из входных текстур. Применение показано в примерах программ;
float2 – переменная, представляющая собой вектор из 2-х вещественных чисел одинарной точности; используется для адресации ячеек входных текстур и рендер-цели;
float4 – переменная, представляющая собой вектор из 4-х вещественных чисел одинарной точности, либо функция, возвращающая такой вектор в качестве значения; во втором варианте используется при декларации пиксельных шейдеров;
void – функция, не возвращающая никаких значений; используется при декларации вершинных шейдеров;
technique – декларация «техники», т.е. процедуры, которую могут запускать внешние программы, взаимодействующие с графическим процессором; внутри этой процедуры задаются значения управляющих переменных, запускаются на исполнение вершинный и пиксельный шейдеры.
П.1.2. Встроенные функции
tex2D(объект типа sampler, координаты ячейки типа float2) – функция, возвращающая расположенный в ячейке с заданными координатами 4-вектор из текстуры, к которой «привязан» sampler;
П.1.3. Другие операторы и выражения
return – оператор, возвращающий значение функции, в теле которой он расположен;
PixelShader = compile ps_3_0 sum() – строка, задающая функцию sum() в качестве исполняемого пиксельного шейдера;
VertexShader = compile vs_3_0 transform() – строка, задающая функцию transform() в качестве исполняемого вершинного шейдера;
П.1.4. Системные переменные
ZEnable – имеет значение true, если используется Z-буфер, либо false, если он не используется. При физическом моделировании Z-буфер не используется, так что ZEnable = false;
CullMode – устанавливает режим отсечения невидимых треугольников. При физическом моделировании отсечения треугольников нет, так что CullMode = none.
Приложение 2 Процедуры CUDA, исполняемые на CPU
// Файл matrixMul.cu [68]
// Copyright 1993-2007 NVIDIA Corporation. All rights reserved.
/* Умножение матриц: C = A * B. Вызывающий код на CPU.
*
* В этом примере реализовано умножение матриц как приведено в главе 7
* документации CUDA Programming Guide [68]. Эта реализация предназначена
* для изучения принципов программирования на CUDA, поэтому эффективность
* принесена в жертву ясности изложения.
*
* Высокопроизводительная версия умножения матриц реализована в библиотеке CUBLAS
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <cutil.h>
#include <matrixMul_kernel.cu>
////////////////////////////////////////////////////////////////////////////////
// предварительное объявление функций
void runTest(int argc, char** argv);
void randomInit(float*, int);
void printDiff(float*, float*, int, int);
/* Процедура, которая для сравнения перемножает матрицы на центральном процессоре: */
extern "C" void computeGold(float*, const float*, const float*, unsigned int, unsigned int, unsigned int);
int main(int argc, char** argv)
{
runTest(argc, argv);
CUT_EXIT(argc, argv);
}
void runTest(int argc, char** argv)
{
CUT_DEVICE_INIT();
// инициализация генератора псевдослучайных чисел rand()
srand(2006);
// выделение памяти для матриц A и B
unsigned int size_A = WA * HA;
unsigned int mem_size_A = sizeof(float) * size_A;
float* h_A = (float*) malloc(mem_size_A);
unsigned int size_B = WB * HB;
unsigned int mem_size_B = sizeof(float) * size_B;
float* h_B = (float*) malloc(mem_size_B);
// заполнение исходных матриц псевдослучайными числами
randomInit(h_A, size_A);
randomInit(h_B, size_B);
// выделение памяти на GPU
float* d_A;
CUDA_SAFE_CALL(cudaMalloc((void**) &d_A, mem_size_A));
float* d_B;
CUDA_SAFE_CALL(cudaMalloc((void**) &d_B, mem_size_B));
// копирование матриц на GPU
CUDA_SAFE_CALL(cudaMemcpy(d_A, h_A, mem_size_A, cudaMemcpyHostToDevice) );
CUDA_SAFE_CALL(cudaMemcpy(d_B, h_B, mem_size_B, cudaMemcpyHostToDevice) );
// выделение памяти на GPU для матрицы-результата
unsigned int size_C = WC * HC;
unsigned int mem_size_C = sizeof(float) * size_C;
float* d_C;
CUDA_SAFE_CALL(cudaMalloc((void**) &d_C, mem_size_C));
// создание и запуск таймера
unsigned int timer = 0;
CUT_SAFE_CALL(cutCreateTimer(&timer));
CUT_SAFE_CALL(cutStartTimer(timer));
// установка параметров выполнения ядра
dim3 threads(BLOCK_SIZE, BLOCK_SIZE);
dim3 grid(WC / threads.x, HC / threads.y);
// запуск ядра
matrixMul<<< grid, threads >>>(d_C, d_A, d_B, WA, WB);
// проверяем на наличие ошибок выполнения ядра
CUT_CHECK_ERROR("Ошибка выполнения ядра");
// выделяем память на CPU для матрицы-результата
float* h_C = (float*) malloc(mem_size_C);
// копируем результат на CPU
CUDA_SAFE_CALL(cudaMemcpy(h_C, d_C, mem_size_C,
cudaMemcpyDeviceToHost) );
// останавливаем таймер и освобождаем ресурсы
CUT_SAFE_CALL(cutStopTimer(timer));
printf("Processing time: %f (ms) n", cutGetTimerValue(timer));
CUT_SAFE_CALL(cutDeleteTimer(timer));
// вычисляем произведение A*B на CPU для сравнения точности
float* reference = (float*) malloc(mem_size_C);
computeGold(reference, h_A, h_B, HA, WA, WB);
// проверяем результат
CUTBoolean res = cutCompareL2fe(reference, h_C, size_C, 1e-6f);
printf("Тест %s n", (1 == res) ? "ПРОЙДЕН" : "ПРОВАЛЕН");
if (res!=1) printDiff(reference, h_C, WC, HC);
// освобождаем выделенную память
free(h_A);
free(h_B);
free(h_C);
free(reference);
CUDA_SAFE_CALL(cudaFree(d_A));
CUDA_SAFE_CALL(cudaFree(d_B));
CUDA_SAFE_CALL(cudaFree(d_C));
}
// Заполнение матрицы псевдослучайными числами.
void randomInit(float* data, int size)
{
for (int i = 0; i < size; ++i)
data[i] = rand() / (float)RAND_MAX;
}
void printDiff(float *data1, float *data2, int width, int height)
{
int i,j,k;
int error_count=0;
for (j=0; j<height; j++) {
for (i=0; i<width; i++) {
k = j*width+i;
if (data1[k] != data2[k]) {
printf("diff(%d,%d) CPU=%4.4f, GPU=%4.4f n", i,j, data1[k], data2[k]);
error_count++;
}
}
}
printf(" Количество ошибок = %d n", error_count);
}
// Файл matrixMul.h [68]
// Copyright 1993-2007 NVIDIA Corporation. All rights reserved.
#ifndef _MATRIXMUL_H_
#define _MATRIXMUL_H_
// Размер связки потоков
#define BLOCK_SIZE 16
// Размеры матрицы (для простоты кода выбраны кратными размеру связки потоков)
#define WA (3 * BLOCK_SIZE) // Matrix A width
#define HA (5 * BLOCK_SIZE) // Matrix A height
#define WB (8 * BLOCK_SIZE) // Matrix B width
#define HB WA // Matrix B height
#define WC WB // Matrix C width
#define HC HA // Matrix C height
#endif // _MATRIXMUL_H_
#ifndef _MATRIXMUL_H_
#define _MATRIXMUL_H_
// Размер связки потоков
#define BLOCK_SIZE 16
// Размеры матрицы (для простоты кода выбраны кратными размеру связки потоков)
#define WA (3 * BLOCK_SIZE) // Matrix A width
#define HA (5 * BLOCK_SIZE) // Matrix A height
#define WB (8 * BLOCK_SIZE) // Matrix B width
#define HB WA // Matrix B height
#define WC WB // Matrix C width
#define HC HA // Matrix C height
#endif // _MATRIXMUL_H_
// Файл matrixMul_gold.cpp [68]
// Copyright 1993-2007 NVIDIA Corporation. All rights reserved.
extern "C"
void computeGold( float*, const float*, const float*, unsigned int, unsigned int, unsigned int);
////////////////////////////////////////////////////////////////////////////////
// Вычисляем произведение матриц на CPU для проверки
// C = A * B
// @param C массив для хранения результата (память выделяется заранее)
// @param A матрица A
// @param B матрица B
// @param hA кол-во строк матрицы А
// @param wB кол-во столбцов матрицы B
////////////////////////////////////////////////////////////////////////////////
void
computeGold(float* C, const float* A, const float* B, unsigned int hA, unsigned int wA, unsigned int wB)
{
for (unsigned int i = 0; i < hA; ++i)
for (unsigned int j = 0; j < wB; ++j) {
double sum = 0;
for (unsigned int k = 0; k < wA; ++k) {
double a = A[i * wA + k];
double b = B[k * wB + j];
sum += a * b;
}
C[i * wB + j] = (float)sum;
}}