- •Курс лекций
- •Оглавление
- •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. Типы данных
6.3.Исполнение шейдера из программы мд-моделирования на c#
6.3.1.Этапы алгоритма моделирования, исполняемые на cpu
Программа для графического процессора должна запускаться внутри полного алгоритма молекулярной динамики, остальные части которого исполняются на центральном процессоре. Ниже мы рассмотрим реализацию этого общего алгоритма на языке C# с использованием библиотеки процедур XNA2.
Для проведения расчёта на графическом процессоре во внешней, вызывающей этот расчёт, программе, необходимо выполнить ряд операций:
Создать объект (в DirectX – объект типа GraphicsDeviceManager), реализующий доступ к графическому процессору;
Рис. 6.6. Операции, исполняемые центральным процессором
Выделить память (т.е., описать переменные) для массивов, в которых будут храниться входные данные, – координаты частиц и параметры потенциалов взаимодействия, – а также выходные данные – компоненты векторов сил, действующих на ионы;
Представить входные данные в форме, требуемой для их передачи графическому процессору;
Выделить память для хранения координат вершин квада (описание понятия «квад» приведено выше) и задать значения этих координат;
Обратиться к текстовому файлу, содержащему код шейдера (программы для графического процессора). Откомпилировать этот код и записать полученную программу в память, доступную графическому процессору (перечисленные задачи программируются несложно, поскольку в библиотеке XNA2 для этого есть стандартные процедуры);
Передать графическому процессору исходные данные;
Исполнить необходимые расчёты;
Скопировать результат из рендер-цели для дальнейшего использования в программе на центральном процессоре;
Операции, которые необходимо выполнить для организации расчёта, обобщены в блок-схеме на рис. 6.6.
6.3.2.Процедуры на c#, обеспечивающие работу с графическим процессором
Ниже приведён текст программы на C#, в котором выделены и прокомментированы все перечисленные этапы. В этом тексте присутствуют и все необходимые вспомогательные операции, также с комментариями.
private void InitGPU() /* Подготовительные операции для расчёта на графическом процессоре */
{
//Локальная переменная, представляющая графический процессор
gpu = graphics.GraphicsDevice;
//Создаем текстуру размером w * h, в которой будут храниться координаты и типы частиц. Количество ячеек в этой текстуре (w*h) должно совпадать с количеством частиц в кристалле, либо превышать это количество (в последнем случае «лишние» ячейки не используются). Расчёт на GPU будет наиболее быстрым, если w и h кратны 32.
in_pos = new Texture2D(gpu, w, h, 1, TextureUsage.None, SurfaceFormat.Vector4);
//Создаём рендер-цель – текстуру размером w * h, в которую попадет результат расчета сил – в её ячейках будут храниться силы, действующие на каждый из ионов.
out_force = new RenderTarget2D(gpu, w, h, 1, SurfaceFormat.Vector4, RenderTargetUsage.PreserveContents);
// Задаем текстуру размером 2 * 2, с параметрами парного межчастичного потенциала
in_coefs = new Texture2D(gpu, 2, 2, 1, TextureUsage.None, SurfaceFormat.Vector4);
float[] data = new float[2 * 2 * 4];
for (int u = 0; u < 2; u++)
for (int v = 0; v < 2; v++) //здесь 2 цикла могли быть заменены одним по i от 0
//до <количества пар> - 1
{
int i = (u * 2 + v) * 4;
data[i] = (float)coefs[i++];
data[i] = (float)coefs[i++];
data[i] = (float)coefs[i++];
data[i] = (float)coefs[i++];
}
in_coefs.SetData<float>(data); //in_coefs - переменная типа Texture2D
//Задаем квад (вершинные и текстурные координаты, соответственно).
//Y-координата текстуры инвертирована по отношению к Y-координате вершины,
//т.к. ось Y направлена снизу вверх в пространстве вершин и сверху вниз в пространстве экрана.
float du = 0.5f / w, dv = 0.5f / h;
// смещения для адресации текселей по центрам
//(в случае текстур с размерами не равными степени числа 2
quad = new VertexBuffer(gpu, typeof(VertexPositionTexture), 4, BufferUsage.None); //переменная типа VertexBuffer
quad.SetData<VertexPositionTexture>(new VertexPositionTexture[] {
new VertexPositionTexture(new Vector3(-1, 1, 0), new Vector2(0 + du, 0 + dv)),
new VertexPositionTexture(new Vector3( 1, 1, 0), new Vector2(1 + du, 0 + dv)),
new VertexPositionTexture(new Vector3(-1, -1, 0), new Vector2(0 + du, 1 + dv)),
new VertexPositionTexture(new Vector3( 1, -1, 0), new Vector2(1 + du, 1 + dv))
}); // кубу в пространстве сопоставлены смещенные углы плоскости
gpu.Vertices[0].SetSource(quad, 0, VertexPositionTexture.SizeInBytes); //размер квада
gpu.VertexDeclaration = new VertexDeclaration(gpu, VertexPositionTexture.VertexElements); //неясно, что
//Задаем шейдер и его входные параметры.
//Компиляция текстового файла с шейдером
CompiledEffect e = Effect.CompileEffectFromFile("force.fx", null, null, CompilerOptions.None, TargetPlatform.Windows);
//Проверка успешности компиляции
if (!e.Success) throw new Exception(e.ErrorsAndWarnings);
//Записывает программу эффекта в память видеокарты
fx = new Effect(gpu, e.GetEffectCode(), CompilerOptions.None, null); //переменная типа Effect
//Выбирает роцедуру из кода эффекта, которую надо будет выполнять
fx.CurrentTechnique = fx.Techniques["Force"];
//Передача на видеокарту координат частиц
fx.Parameters["in_pos"].SetValue(in_pos); //видимо, in_pos и in_coefs описаны в шейдере как входные текстуры
//Передача на видеокарту параметров потенциалов взаимодействия
fx.Parameters["in_coefs"].SetValue(in_coefs);
}
private void ForceGPU()
{
int i, u, v;
//Задаем текстуру с координатами и типами частиц
float[] data = new float[w * h * 4];
/* Текстура представляет собой таблицу с размером w по горизонтали и h по вертикали.
* В каждой ячейке таблицы находится 4-х-вектор, хранящий координаты и тип ионов.
* Номер частицы в линейном массиве i вычисляется по формуле i = v * w + u
*/
for (v = 0; v < h; v++)
for (u = 0; u < w; u++)
{
i = v * w + u;
data[i * 4 + 0] = (float)pos[i * 3 + 0];
data[i * 4 + 1] = (float)pos[i * 3 + 1];
data[i * 4 + 2] = (float)pos[i * 3 + 2];
data[i * 4 + 3] = type[i] / 2f;
}
in_pos.SetData<float>(data); //in_pos - переменная типа Texture2D
//Задаем новую рендер-цель, сохраняя старую.
RenderTarget2D old_render_target = (RenderTarget2D)gpu.GetRenderTarget(0); //Зачем нужно преобразование типа?
gpu.SetRenderTarget(0, out_force); //out_force - переменная типа RenderTarget2D
gpu.Clear(new Color(0, 0, 0, 0)); //Обнуление сил в рендер-цели
fx.Begin(); //спросить, что делает Begin. Загружает в память?
for (i = 0; i < ions; i++)
{
//Обновляем ссылку на рендер-цель (необходимо для корректного выполнения операции += в шейдере)
gpu.SetRenderTarget(0, null); fx.Parameters["out_force"].SetValue(out_force.GetTexture());
gpu.SetRenderTarget(0, out_force);
//Передаем в шейдер текстурные координаты i-й частицы.
u = i % w; v = i / w; //очевидно, % - остаток от деления
fx.Parameters["u_i"].SetValue((u + 0.5f) / w); //передаётся центр ячейки
fx.Parameters["v_i"].SetValue((v + 0.5f) / h); //передаётся центр ячейки
//Вычисляем взаимодействие i-й частицы со всеми остальными.
fx.CurrentTechnique.Passes["force_i"].Begin();
gpu.DrawPrimitives(PrimitiveType.TriangleStrip, 0, 2);
fx.CurrentTechnique.Passes["force_i"].End();
}
fx.End(); //В цикле по всем частицам заполняется одна и та же рендер-цель
//Восстанавливаем старую рендер-цель.
gpu.SetRenderTarget(0, old_render_target);
//Получаем результат из новой рендер-цели
data = new float[w * h * 4];
for (i = 0; i < 3; i++) gpu.Textures[i] = null;
out_force.GetTexture().GetData<float>(data); //out_force - массив с рендер-целью
for (v = 0; v < h; v++)
for (u = 0; u < w; u++)
{
i = v * w + u;
force[i * 3 + 0] = data[i * 4 + 0];
force[i * 3 + 1] = data[i * 4 + 1];
force[i * 3 + 2] = data[i * 4 + 2];
}
}