Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Лекции по параллельному программированию (MPI).doc
Скачиваний:
0
Добавлен:
01.07.2025
Размер:
781.31 Кб
Скачать

Лекция 6 Определение времени выполнения программы

Практически сразу же после разработки первых параллельных программ возникает необходимость определения времени выполнения вычислений для оценки достигаемого ускорения процессов решения задач за счет использования параллелизма. Используемые обычно средства для измерения времени работы программ зависят, как правило, от аппаратной платформы, операционной системы, алгоритмического языка и т.п. Стандарт MPI включает определение специальных функций для измерения времени, использование которых позволяет устранить зависимость от среды выполнения параллельных программ.

Получение времени текущего момента выполнения программы обеспечивается при помощи функции:

double MPI_Wtime(void);

результат вызова которой есть количество секунд, прошедшее от некоторого определенного момента времени в прошлом. Этот момент времени в прошлом, от которого происходит отсчет секунд, может зависеть от среды реализации библиотеки MPI. Для ухода от такой зависимости функцию MPI_Wtime следует использовать только для определения длительности выполнения отдельных фрагментов кода параллельных программ. Возможная схема применения функции MPI_Wtime может состоять в следующем:

double t1, t2, dt;

t1 = MPI_Wtime();

t2 = MPI_Wtime();

dt = t2 – t1;

Точность измерения времени также может зависеть от среды выполнения параллельной программы. Для определения текущего значения точности может быть использована функция:

double MPI_Wtick(void);

позволяющая определить время в секундах между двумя последовательными показателями времени аппаратного таймера используемой компьютерной системы.

Рассмотрим пример программы, использующей функцию MPI_Wtime(). Программа выполняет поиск суммы элементов одномерного массива и использует следующий порядок действий:

1. Процесс с рангом 0 запрашивает с клавиатуры размер массива, после чего динамически выделяет память под массив и заполняет его случайными числами.

2. Процесс 0 передает процессу 1 размер массива.

3. Процесс 0 передает процессу 1 первую половину массива.

4. Процесс 0 вычисляет сумму оставшейся половины массива и ждет ответ от процесса 1.

5. Процесс 1 получает от процесса 0 размер массива и динамически выделяет память под половину этого размера.

6. Процесс 1 получает от процесса 0 массив данных.

7. Процесс 1 вычисляет сумму элементов массива, отсылает ее процессу 0 и завершает работу.

8. Процесс 0 принимает от процесса 1 значение суммы первой половины массива, складывает с суммой второй половины массива, выводит результат на экран и завершает работу.

Сначала приведем листинг программы без использования функции MPI_Wtime():

#include "stdafx.h"

#include <stdio.h>

#include <conio.h>

#include <mpi.h>

#include <iostream>

using namespace std;

int main(int argc, char* argv[])

{

int proc_rank, proc_count;

MPI_Status Status;

MPI_Init(&argc, &argv);

MPI_Comm_size(MPI_COMM_WORLD, &proc_count);

MPI_Comm_rank(MPI_COMM_WORLD, &proc_rank);

//===================================================================

if ((proc_rank==0) && (proc_count>1)) // Если это "главный" процесс

{ // и процессов минимум два

int n; // Размер массива (изначально неизвестен)

cout << "Input n: ";

cin >> n; // Вводим с клавиатуры размер массива

// Заводим массив на n элементов и заполняем его случайными числами:

int *mas; // Указатель на массив типа int

mas = new int [n]; // Выделяем память под массив (без проверки)

for (int i=0; i<n; i++) // и заполняем случайными числами от 0 до 10

mas[i]=rand()%11;

// Распараллелим поиск суммы ровно на два процесса.

// Даже если доступных процессорных ядер будет больше,

// они не будут использоваться. Ровно два процесса:

// текущий процесс с рангом 0 и процесс с рангом 1.

// Поскольку процесс 1 не знает о размере массива, он

// не может знать, какой объем сообщения ему принимать.

// Поэтому мы сначала передадим процессу 1 число, равное

// размеру массива. Так процесс 1 сможет подготовить

// память под принимаемый массив.

MPI_Send (&n, 1, MPI_INT, 1, 0, MPI_COMM_WORLD);

// Теперь отсылаем первую половину массива процессу 1

MPI_Send (mas, n/2, MPI_INT, 1, 0, MPI_COMM_WORLD);

// Пока процесс 1 обрабатывает первую половину массива,

// делаем пока свою часть работы: ищем сумму элементов

// оставшейся части массива

int S=0;

for (int i=n/2; i<n; i++)

S=S+mas[i];

// Готовимся получать результат работы процесса 1.

// Результатом будет одно число типа int.