Задание к контр. раб._Параллельное программирование

advertisement
Задание к контрольной работе по дисциплине
«Параллельное программирование»
Для выполнения контрольной работы прочитайте соответствующие главы в книгах [1],
[2] или [3].
Установите необходимое программное обеспечение (компиляторы C, C++, Cilk, среду
LAM-MPI). Для выполнения заданий с процессами и нитями ознакомьтесь с примерами
программ из соответствующих разделов книги Богачева [1], для выполнения задания Б, - с
использованием MPI, рассмотрите примеры из [3] и [4], а также пример выполнения
задания, приведенный далее. В случае невозможности организовать виртуальную
параллельную машину из реальных компьютеров использовать виртуальные машины на
основе VirtualBox или VMWare с установкой на них соответствующего программного
обеспечения.
Контрольная работа выполняется по вариантам, и состоит из двух разрабатываемых
программ, A и Б. Номер вариант вычисляется как остаток от деления номера зачетной
книжки на 7 плюс один. Если полученная цифра больше 7 - делим еще раз на 7 плюс
один.
Задание A.
Вычислить двукратный интеграл , пределы интегрирования по x от a до b, по y от c до
d, число интервалов разбиения по x и по y задано числом N, N>10000; использовать метод
параллелепипедов, вычисляя объем i,j-го параллелепипеда по формуле
Построить график зависимости времени выполнения расчета от количества
параллельных задач (глубины рекурсии в варианте 6) для многоядерного процессора. Для
измерения времени вычислений использовать функцию gettimeofday, позволяющую
измерять время с точностью до микросекунд.
Варианты заданий: написать программу
1. с использованием Cilk
2. с использованием процессов и передачей данных через канал,
3. с использованием процессов и передачей данных через разделяемую память
4. с использованием процессов и передачей данных через именованный канал
5. с использованием нитей и передачей данных через глобальные переменные
6. с использованием нитей и рекурсивного способа декомпозиции
7. с использованием нитей и способа декомпозиции по данным
Задание Б.
Написать программу, моделирующую одноатомный газ, состоящий из одинаковых
молекул с массой m и радиусом r, заключенных в кубический сосуд. Центр сосуда
совпадает с началом координат. Соударениями молекул пренебречь, столкновения со
стенками сосуда считать абсолютно упругими. Каждый процесс рассчитывает отдельную
область пространства сосуда, передавая данные о молекуле соседнему процессу в случае
перехода молекулы в его область. Начальные данные — случайные значения координат
молекул и скорости задаются в головном процессе и доставляются с использованием MPI
и широковещательных способов передачи данных. Выходными данными являются:
количество соударений молекул со стенками сосуда и переданный стенкам импульс за
единицу времени.
Выполнить разработку, используя в качестве исходных данных начальные условия по
вариантам:
1. количество молекул 10000, все сосредоточены в 1/8 части объема, в первом
октанте, имеют случайные значения координат и скоростей (от 0 до 400 м/сек).
2. количество молекул 10000, распределены по всему объему, имеют случайные
значения координат и скоростей (от 0 до 400 м/сек).
3. количество молекул 10000, все сосредоточены в 1/2 части объема, с
положительными значениями координаты x, имеют случайные значения координат
и скоростей (от 0 до 400 м/сек).
4. количество молекул 10000, распределены по всему объему, имеют случайные
значения координат и одинаковые по модулю (300 м/сек), но случайные по
направлению скорости.
5. количество молекул 10000, распределены по двум диаметрально расположенным
октантам, имеют случайные значения координат и скоростей (от 0 до 400 м/сек).
6. количество молекул 10000, все распределены по объему равномерно, но в 1/8 части
объема, в первом октанте, имеют значения скоростей от 300 до 600 м/сек, в то
время как в оставшемся объеме — скорости от 0 до 400 м/сек.
7. количество молекул 10000, все сосредоточены в 1/8 части объема, в первом
октанте, имеют одинаковые по модулю значения скоростей, 400 м/сек, но
случайные по направлению.
Построить график изменения давления на отдельные стенки сосуда от времени.
Пример составления и запуска MPI-приложения.
Рассмотрим пример использования MPI для решения задачи однократного численного
интегрирования методом трапеций. Подготовим исходный файл prog.c:
#include <stdio.h>
#include <math.h>
#include "mpi.h"
main(int argc, char** argv) {
int my_rank; /* номер текущего задания */
int p; /* количество заданий */
double a; /* начало интервала интегр. */
double b; /* верний предел интегр. */
int n; /* количество подинтервалов */
double h; /* ширина интервала */
double local_a; /* нижний предел для задания */
double local_b; /* верхний предел для задания*/
int local_n; /* количество интервалов для */
/* текущего задания */
double integral; /* значение интеграла */
double total; /* итоговое значение */
int source; /* отправитель сообщения */
int dest = 0; /* получатель (корневой проц.)*/
int tag = 0;
MPI_Status status;
void Get_data(double* a_ptr, double* b_ptr,
int* n_ptr, int my_rank, int p);
double Trap(double local_a, double local_b, int local_n,
double h); /* вычисление значения на участке */
/* Входим в коммуникатор MPI */
MPI_Init(&argc, &argv);
/* Узнаем свой порядковый номер */
MPI_Comm_rank(MPI_COMM_WORLD, &my_rank);
/* Узнаем количество выполняющихся заданий */
MPI_Comm_size(MPI_COMM_WORLD, &p);
Get_data(&a, &b, &n, my_rank, p);
h = (b-a)/n; /* h вычисляем интервал разбиения */
local_n = n/p; /* и количество интервалов */
/* Подынтервал интегрирования для каждого задания
равен local_n*h. Локальные пределы интегрирования:
*/
local_a = a + my_rank*local_n*h;
local_b = local_a + local_n*h;
integral = Trap(local_a, local_b, local_n, h);
/* Добавляем вклады от каждого из заданий */
if (my_rank == 0) {
total = integral;
for (source = 1; source < p; source++) {
MPI_Recv(&integral, 1, MPI_double, source, tag,
MPI_COMM_WORLD, &status);
total = total + integral;
}
} else {
MPI_Send(&integral, 1, MPI_double, dest,
tag, MPI_COMM_WORLD);
}
/* Вывод результата */
if (my_rank == 0) {
printf("n = %d интервалов\n", n);
printf("интеграл от %lf до %lf = %lf\n",
a, b, total);
}
/* Завершаем работу MPI */
void Get_data(
double* a_ptr /* out */,
double* b_ptr /* out */,
int* n_ptr /* out */,
int my_rank /* in */,
int p /* in */) {
int source = 0; /* Переменные для функций */
int dest; /* MPI_Send и MPI_Recv */
int tag;
MPI_Status status;
if (my_rank == 0){
printf("Введите a, b, и n\n");
scanf("%f %f %d", a_ptr, b_ptr, n_ptr);
for (dest = 1; dest < p; dest++){
tag = 0;
MPI_Send(a_ptr, 1, MPI_double, dest, tag, MPI_COMM_WORLD);
tag = 1;
MPI_Send(b_ptr, 1, MPI_double, dest, tag, MPI_COMM_WORLD);
tag = 2;
MPI_Send(n_ptr, 1, MPI_INT, dest, tag, MPI_COMM_WORLD);
}
} else {
tag = 0;
MPI_Recv(a_ptr,1,MPI_double, source, tag,
MPI_COMM_WORLD,&status);
tag = 1;
MPI_Recv(b_ptr,1,MPI_double, source, tag,MPI_COMM_WORLD,
&status);
tag = 2;
MPI_Recv(n_ptr,1,MPI_INT, source, tag, MPI_COMM_WORLD, &status);
}
}
double Trap(
double local_a /* вход */,
double local_b /* вход */,
int local_n /* вход */,
double h /* вход */) {
double integral; /* Результат */
double x;
int i;
double f(double x); /* прототип подынтегральной функции */
integral = (f(local_a) + f(local_b))/2.0;
x = local_a;
for (i = 1; i <= local_n-1; i++) {
x = x + h;
integral = integral + f(x);
}
integral = integral*h;
return integral;
}
/************************************************************/
double f(double x)
{
double return_val;
/* Вычисление подынтегральной функции f(x). */
return_val = x*sin(x);
}
Для компиляции установим LAM-MPI, запустим lamboot от имени
непривилегированного пользователя и используем команду
mpicc prog.c -omyprog.
В результате успешной компиляции появится исполняемый файл myprog.
Подготовим список хостов, включаемых в виртуальную машину, сохраним его в
домашнем каталоге под именем hosts , формат списка и название могут варьироваться в
зависимости от версии LAM, посмотрите документацию.
Для выполнения программы необходимо настроить способ аутентификации на всех
компьютерах, включенных в список хостов виртуальной машины, без ввода пароля. По
умолчанию Lam-mpi использует протокол ssh. Рассмотрим настройку ssh для
безпарольной работы.
ssh (Secure Shell) — сетевой протокол, позволяющий удаленное управление
компьютером и передачу файлов. По сути, протокол является "защищённой" версией
RSH, использующей алгоритмы RSA как для идентификация пользователя, так и передачи
данных. В данной заметке описывается, каким образом "подружить" две машины, чтобы
при попытке входа по с первой из них (будем условно называть её "клиент") на вторую
("сервер" - опять-таки, условно) по протоколу ssh отпала необходмость в вводе пароля
(такая задача может возникнуть, например, во время настройки систем резервного
копирования, публикации файлов и т.п.).
Прежде всего, необходимо усвоить, что основой использования ssh без ввода пароля
служит идентификация пользователя на основе публичного ключа. Вам необходимо
создать пару ключей - публичный/частный (public/private). Покажем, как это делается на
примере ssh версии 2 (отметим, что версия 1 является устаревшей, использовать её не
рекомендуется).
Шаг 1. Создаём на "клиенте" пару ключей (публичный/частный), используя утилиту
ssh-keygen:
$ ssh-keygen -t rsa
Generating public/private rsa key pair.
Enter file in which to save the key (/home/ns/.ssh/id_rsa):
Created directory '/home/ns/.ssh'.
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /home/ns/.ssh/id_rsa.
Your public key has been saved in /home/ns/.ssh/id_rsa.pub.
The key fingerprint is:
18:f7:a3:78:ec:9e:36:b4:95:c0:5a:36:c4:b6:88:8b
Здесь мы используем опцию -t, чтобы указать на использование RSA для создания ключей.
Ввод некоторого (произвольного) выражения в качестве passphrase настоятельно
рекомендуется. После выполнения данной операции получаем два файла в поддиректории
.ssh домашней директории: id_rsa и id_rsa.pub
Шаг 2. Копируем файл id_rsa.pub в директорию .ssh/ на "сервере" (напомним, так мы
договорились называть удалённую машину, доступ по протоколу ssh к которой
необходимо осуществлять без пароля), под именем authorized_keys2:
$ scp /home/ns/.ssh/id_rsa.pub ns@vps:/home/ns/.ssh/authorized_keys2
ns@vps's password:
id_rsa.pub
100%
227
0.2KB/s
00:00
Таким образом, мы указали демону sshd (программа-демон, выполняющая роль SSHсервера) на "сервере", что для шифрования данных при соединении с нашим "клиентом"
необходимо использовать указанный публичный ключ и, кроме того, данный ключ создан
для протокола версии 2.
Шаг 3. Часть настройки, касающаяся публичного ключа, можно считать завершённой.
Теперь "сервер" не будет запрашивать пароль при попытке установления соединения по
ssh с данной конкретной машины ("клиента") от данного пользователя (конечно же, в
других случаях, пароль будет требоваться, как и должно быть).
Настройка ssh завершена, теперь можно запустить программу в параллельном режиме,
указав количество параллельно выполняющихся заданий:
mpirun -np 16 myprog
Рекомендуемая литература
1. Богачев К.Ю. Основы параллельного программирования.- М.: БИНОМ,
Лаборатория знаний, 2003. - 324 с.
2. Антонов А.С. Введение в параллельные вычисления. - М.: НИВЦ МГУ, 2002. - 69 с.
3. Грегори Р. Эндрюс. Основы многопоточного, параллельного и распределенного
программирования. -Пер. С англ. - М.: Вильямс, 2003. - 512 с.
4. Janusz Kowalik, ed. MPI: The Complete Reference. The MIT Press, Cambridge,
Massachusets, London, England. 1996 .- 336 pp.
Download