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

Отчет

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

Сортировка является одной из типовых проблем обработки данных и обычно понимается как задача размещения элементов неупорядоченного набора значений в порядке монотонного возрастания или убывания. В данной работе необходимо реализовать алгоритм сортировки «пузырьком». Его последовательную версию для однопроцессорных систем, и параллельную – для многопроцессорных систем, используя стандарт MPI и OpenMP. А также, вычислить время его работы для обоих случаев, протестировать и сравнить ускорение параллельного и последовательного алгоритма.

Метод решения

Алгоритм пузырьковой сортировки в прямом виде достаточно сложен для распараллеливания – сравнение пар значений упорядочиваемого набора данных происходит строго последовательно. В связи с этим для параллельного применения используется не сам этот алгоритм, а его модификация, известная в литературе как метод чет-нечетной перестановки ( the odd-even transposition method). Суть модификации состоит в том, что в алгоритм сортировки вводятся два разных правила выполнения итераций метода: в зависимости от четности или нечетности номера итерации сортировки для обработки выбираются элементы с четными или нечетными индексами соответственно, сравнение выделяемых значений всегда осуществляется с их правыми соседними элементами. Таким образом, на всех нечетных итерациях сравниваются пары

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

а на четных итерациях обрабатываются элементы

(a2, a3), (a4, a5), ..., (an-2,an-1).

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

void SerialBubbleSort(int* ar, int size)
{
	for (int i = 0; i < size; i++)
	{
		if (i % 2 == 0)
		{
			for (int j = 0; j < size; j += 2)
				if (j < size - 1)
					if(ar[j] > ar[j+1])
					{
						int v = ar[j];
						ar[j] = ar[j+1];
						ar[j+1] = v;
					}
		}
		else
		{
			for (int j = 1; j < size; j += 2)
				if (j < size - 1)
					if(ar[j] > ar[j+1])
					{
						int v = ar[j];
						ar[j] = ar[j+1];
						ar[j+1] = v;
					}
		}
	}
}
        

Параллельная реализация

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

OpenMP

void ParallelBubbleSort(int* ar, int size)
{
	for (int i = 0; i < size; i++)
		{
			int v = 0;
			if (i % 2 == 0)
			{
				#pragma omp parallel for private(v)
				for (int j = 0; j < size; j += 2)
					if (j < size - 1)
						if(ar[j] > ar[j+1])
						{
							v = ar[j];
							ar[j] = ar[j+1];
							ar[j+1] = v;
						}
			}
			else
			{
				#pragma omp parallel for private(v)
				for (int j = 1; j < size; j += 2)
					if (j < size - 1)
						if(ar[j] > ar[j+1])
						{
							v = ar[j];
							ar[j] = ar[j+1];
							ar[j+1] = v;
						}
			}	
		}
}        
        
MPI

#define N кол-во элементов

int n = N;
int id, p;
int s;

MPI_Init(&argc, &argv);
MPI_Comm_rank(MPI_COMM_WORLD, &id);
MPI_Comm_size(MPI_COMM_WORLD, &p);

if (id == 0)
{
    s = n / p;

    MPI_Bcast(&s, 1, MPI_INT, 0, MPI_COMM_WORLD);
    chunk = (int *)malloc(s * sizeof(int));
    MPI_Scatter(data, s, MPI_INT, chunk, s, MPI_INT, 0, MPI_COMM_WORLD);

    sort(chunk,s);
}
else
{
    MPI_Bcast(&s, 1, MPI_INT, 0, MPI_COMM_WORLD);
    chunk = (int *)malloc(s * sizeof(int));
    MPI_Scatter(data, s, MPI_INT, chunk, s, MPI_INT, 0, MPI_COMM_WORLD);

    sort(chunk, s);
}

step = 1;
 
while (step < p)
{
    if (id % (2 * step) == 0)
    {
        if (id + step < p)
        {
            MPI_Recv(&m, 1, MPI_INT, id + step, 0, MPI_COMM_WORLD, &status);
            other = (int *)malloc(m * sizeof(int));
            MPI_Recv(other, m, MPI_INT, id+step, 0, MPI_COMM_WORLD, &status);
            chunk = merge(chunk, s, other, m);
            s = s + m;
        }
    }
    else
    {
        int near = id - step;
        MPI_Send(&s, 1, MPI_INT, near, 0, MPI_COMM_WORLD);
        MPI_Send(chunk, s, MPI_INT, near, 0, MPI_COMM_WORLD);
        break;
    }
    step = step * 2;
}
        

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

Трудоемкость последовательной версии пузырьковой сортировки O(n^2).

Параллельный алгоритм состоит из 2-х этапов. На первом каждый узел сортирует свою часть данных. Трудоемкость этой операции O((n / p)^2). На втором этапе происходят обмены между процессорами. При этом части сортируемых данных сливаются в единый массив за время O(2 * n / p). Таких итераций не более p. В итоге имеем оценку времени параллельной версии O((n / p)^2 + 2 * n)

Ускорение и эффективность:

S = (n * p^2) / (n + 2 * p^2)

E = (n * p) / (n + 2 * p^2)

Результаты экспериментов

Тестовая конфигурация (MPI):
Core 2 Duo E8300 @2.8 Ghz
4 Gb RAM DDR2 800Mhz

Кол-во элементов Кол-во процессов Время
10000 1 0.168000
10000 2 0.051000
10000 4 0.036000
20000 1 0.664000
20000 2 0.189000
20000 4 0.125000
50000 1 4.278000
50000 2 1.169000
50000 4 0.952000
100000 1 16.657000
100000 2 4.671000
100000 4 3.679000

Тестовая конфигурация (OpenMP):
Intel Core i7 Q740 @1,73GHz
8 Gb RAM DDR3 1333Mhz

Кол-во элементов Кол-во процессов Время
10000 1 0.575792
10000 2 0.320616
10000 4 0.239752
20000 1 1.907685
20000 2 1.266453
20000 4 0.759543
50000 1 12.619860
50000 2 7.828390
50000 4 4.370603
100000 1 47.312535
100000 2 29.417306
100000 4 16.072989

Об авторах

Выполнили студенты группы 83-03: Минеев Александр и Вихирев Алексей

Новости

22.10.2012
04.09.2012
05.04.2012
06.03.2012
02.03.2012