Новости
О Центре
Кластер
Обучение
Основной курс по параллельному программированию
Учебные курсы
Магистратура
Дополнительное образование
Работы студентов
Библиотека
Исследования
Конференции
Полезные ссылки
NVIDIA
Контакты
О сайте
Имя:
Пароль:
запомнить:
Забыли пароль? Регистрация

Постановка задачи

В общем, сортировку следует понимать как процесс перегруппировки заданного множества объектов в некотором определенном порядке. Цель сортировки – облегчить последующий поиск элементов в таком отсортированном множестве. Это почти универсальная, фундаментальная деятельность. Мы встречаемся с отсортированными объектами в телефонных книгах, в списках подоходных налогов, в оглавлениях книг, в библиотеках, в словарях, на складах – почти везде, где нужно искать хранимые объекты.

Вычислительная трудоемкость процедуры упорядочивания является достаточно высокой. Сортировка пузырьком имеет квадратичную зависимость от длины массива. Один из вариантов ускорения сортировки – использование параллельных вычислений при наличии нескольких процессоров. Целью лабораторной работы является реализация параллельного алгоритма сортировки пузырьком и сравнение эффективности с последовательной сортировкой.

Описание последовательного метода

Алгоритм состоит в повторяющихся проходах по сортируемому массиву. За каждый проход элементы последовательно сравниваются попарно и, если порядок в паре неверный, выполняется обмен элементов. Проходы по массиву повторяются до тех пор, пока на очередном проходе не окажется, что обмены больше не нужны, что означает — массив отсортирован. При проходе алгоритма, элемент, стоящий не на своём месте, «всплывает» до нужной позиции как пузырёк в воде, отсюда и название алгоритма.

Псевдокод алгоритма:

Вход: массив A, состоящий из элементов A[1], A[2], ..., A[n-1], A[n]

t := истина

цикл пока t:

t := ложь

цикл для j = 1, 2, ..., n − 1:

если A[j]> A[j+1]

обменять местами элементы A[j] и A[j+1]

t := истина

Описание параллельного метода

Последовательный алгоритм в прямом виде достаточно сложен для распараллеливания (сравнение пар значений упорядочиваемого набора данных происходит строго последовательно)поэтому в параллельной версии программы используется не сам этот алгоритм, а его модификация, а именно алгоритм чет-нечетной перестановки:

Алгоритм чет-нечетной перестановки:

В алгоритм сортировки вводятся два разных правила выполнения итераций метода: в зависимости от четности или нечетности номера итерации сортировки для обработки выбираются элементы с четными или нечетными индексами соответственно, сравнение выделяемых значений всегда осуществляется с их правыми соседними элементами. Таким образом, на всех нечетных итерациях сравниваются пары

(a1, a2), (a3, a4), ..., (an-1,an) (при четном n),

а на четных итерациях обрабатываются элементы (a2, a3), (a4, a5), ..., (an-2,an-1).

После n-кратного повторения итераций сортировки исходный набор данных будет упорядоченным.

Анализ эффективности

Определим теперь сложность рассмотренного параллельного алгоритма упорядочивания данных. Как отмечалось ранее, на начальной стадии работы метода каждый процессор проводит упорядочивание своих блоков данных (размер блоков при равномерном распределении данных является равным n/p). Предположим, что данная начальная сортировка может быть выполнена при помощи быстродействующих алгоритмов упорядочивания данных, тогда трудоемкость начальной стадии вычислений можно определить выражением вида:

Далее, на каждой выполняемой итерации параллельной сортировки взаимодействующие пары процессоров осуществляют передачу блоков между собой, после чего получаемые на каждом процессоре пары блоков объединяются при помощи процедуры слияния. Общее количество итераций не превышает величины p, и, как результат, общее количество операций этой части параллельных вычислений оказывается равным:

С учетом полученных соотношений показатели эффективности и ускорения параллельного метода сортировки имеют вид:

Расширим приведенные выражения – учтем длительность выполняемых вычислительных операций и оценим трудоемкость операции передачи блоков между процессорами. При использовании модели Хокни общее время всех выполняемых в ходе сортировки операций передачи блоков можно оценить при помощи соотношения вида:

где α – латентность, β – пропускная способность сети передачи данных, а w есть размер элемента упорядочиваемых данных в байтах.

С учетом трудоемкости коммуникационных действий общее время выполнения параллельного алгоритма сортировки определяется следующим выражением:

где τ есть время выполнения базовой операции сортировки.

Демонстрация

Результаты

Код программы

#define SIZE_OF_ARRAY 10000

void sort (int *pMas, int size)

{

for (int i = size - 2; i >= 0; i--)

for (int j = 0; j <= i; j++)

if (pMas[j] > pMas[j + 1])

pMas[j] ^= pMas[j+1] ^= pMas[j] ^= pMas[j+1];

}

void mergeArrays (int *pMas1, int size1, int *pMas2, int size2, int *result)

{

int i = 0, j = 0, k = 0;

while (i < size1 && j < size2)

if (pMas1[i] < pMas2[j])

result[k++] = pMas1[i++];

else

result[k++] = pMas2[j++];

if (i == size1)

while (j < size2)

result[k++] = pMas2[j++];

if(j == size2)

while (i < size1)

result[k++] = pMas1[i++];

}

void initArray (int *pMas, int size)

{

for (int i = 0; i < size; i++)

pMas[i] = rand() % 1000;

}

void outputArray (const char *pFileName, int *pMas, int size)

{

FILE *file = fopen(pFileName, "wt");

for (int i = 0; i < size; i++)

fprintf(file, "%d: %d\n", i, pMas[i]);

fclose(file);

}

int main (int argc, char **argv)

{

double startTime, stopTime;

int *data;

int *resultant_array;

int *sub;

int m;

int r;

int s;

int move;

MPI_Status status;

MPI_Init (&argc, &argv);

int rank, count;

MPI_Comm_rank (MPI_COMM_WORLD, &rank);

MPI_Comm_size (MPI_COMM_WORLD, &count);

if (rank == 0)

{

s = SIZE_OF_ARRAY / count;

r = SIZE_OF_ARRAY % count;

data = new int[SIZE_OF_ARRAY + s - r];

initArray (data, SIZE_OF_ARRAY);

outputArray ("input.txt", data, SIZE_OF_ARRAY);

if (r != 0)

{

for (int i = SIZE_OF_ARRAY; i < SIZE_OF_ARRAY + s - r; i++)

data[i] = 0;

s = s + 1;

}

startTime = MPI_Wtime();

MPI_Bcast (&s, 1, MPI_INT, 0, MPI_COMM_WORLD);

resultant_array = new int[s];

MPI_Scatter (data, s, MPI_INT, resultant_array, s, MPI_INT, 0, MPI_COMM_WORLD);

sort (resultant_array, s);

}

else

{

MPI_Bcast (&s, 1, MPI_INT, 0, MPI_COMM_WORLD);

resultant_array = new int[s];

MPI_Scatter (data, s, MPI_INT, resultant_array, s, MPI_INT, 0, MPI_COMM_WORLD);

sort (resultant_array, s);

}

move = 1;

while (move < count)

{

if (rank % (2 * move) == 0)

{

if (rank + move < count)

{

MPI_Recv (&m, 1, MPI_INT, rank + move, 0, MPI_COMM_WORLD, &status);

sub = new int [m];

MPI_Recv (sub, m, MPI_INT, rank + move, 0, MPI_COMM_WORLD, &status);

int *tmp = new int[s + m];

mergeArrays (resultant_array, s, sub, m, tmp);

resultant_array = tmp;

s = s + m;

}

}

else

{

int near = rank - move;

MPI_Send (&s, 1, MPI_INT, near, 0, MPI_COMM_WORLD);

MPI_Send (resultant_array, s, MPI_INT, near, 0, MPI_COMM_WORLD);

break;

}

move = move * 2;

}

if (rank == 0)

{

stopTime = MPI_Wtime();

double t1 = stopTime- startTime;

printf("Time on %d: %lf\n", count, t1);

startTime = MPI_Wtime();

sort(data,SIZE_OF_ARRAY);

stopTime = MPI_Wtime();

double t2 = stopTime - startTime;

printf("Time on 1: %lf\n", t2);

printf("A: %f\n", t2/t1);

outputArray ("output.txt", resultant_array, SIZE_OF_ARRAY);

}

MPI_Finalize ();

return 0;

}

Об авторах

Работу выполнили студенты группы 8409 Федоров А.В. и Секачев Е.

Новости

22.10.2012
04.09.2012
05.04.2012
06.03.2012
02.03.2012