The OpenNET Project / Index page

[ новости /+++ | форум | wiki | теги | ]

Каталог документации / Раздел "Программирование в Linux" / Оглавление документа
next up previous contents
Next: Пример с ошибкой Up: PVM - параллельная виртуальная Previous: ``Раздваивание - присоединение''   Contents

Точечное произведение

В этом разделе приведена простая программа на Фортране - PSDOT - для вычисления точечного произведения. Программа вычисляет точечное произведение массивов X и Y. В первую очередь в PSDOT вызываются PVMFMYTID() и PVMFPARENT(). Вызов PVMFPARENT вернет PVMNOPARENT, если задача не была ранее порождена другой задачей PVM. Если это случай, когда PSDOT - ведущая и, следовательно, должна породить отдельные рабочие копии PSDOT, то у пользователя запрашивается число рабочих процессов и длина векторов для вычисления. Каждый порождаемый процесс будет принимать $n/nproc$ элементов X и Y, где $n$ - длина векторов, а $nproc$ - количество процессов, используемых при вычислении. Если $n$ не делится на $nproc$ нацело, то ведущий будет вычислять точечное произведение ``дополнительных элементов''. Подпрограммой SGENMAT случайным образом генерируются значения X и Y. После этого PSDOT порождает $nproc-1$ своих копий и передает каждой новой задаче часть массивов X и Y. Каждое сообщение содержит размеры подмассивов и, собственно, сами подмассивы. После того как ведущий породил рабочие процессы и передал подвекторы, он вычисляет точечное произведение своей порции X и Y. Затем ведущий процесс принимает остальные локальные точечные произведения от рабочих процессов. Обратите внимание на то, что при вызове PVMFRECV как параметр-идентификатор задачи используется специальный символ (-1). Это говорит о том, что сообщение от ``любой'' задачи будет устраивать принимающую сторону. Применение специального символа таким образом может привести к ``гибридизации''. Но в данном случае ``гибридизация'' не создаст проблему, поскольку сложение по природе коммутативно. Другими словами, совершенно не важно, в каком порядке складываются частичные суммы, полученные от рабочих. Если кто-то не уверен, что ``гибридизация'' не приведет к нежелательным программным эффектам, то ему желательно избегать ее возникновения.

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

Если программа PSDOT -это рабочий, то она принимает содержащее подмассивы X и Y сообщение от ведущего процесса. Она вычисляет точечное произведение этих подмассивов и передает результат назад ведущему процессу. В целях краткости сюда не включены подпрограммы SGENMAT и SDOT.

Программа - пример PSDOT.F:

PROGRAM PSDOT

*

* PSDOT параллельно реализует внутреннее (или точечное)

* произведение:

* векторы X и Y сначала находятся на ведущей станции,

* которая затем устанавливает виртуальную машину,

* раздает данные и задания и наконец суммирует

* локальные результаты для получения глобального

* внутреннего произведения.

*

* .. Внешние подпрограммы ..

EXTERNAL PVMFMYTID, PVMFPARENT, PVMFSPAWN, PVMFEXIT

EXTERNAL PVMFINITSEND

EXTERNAL PVMFPACK, PVMFSEND, PVMFRECV, PVMFUNPACK

EXTERNAL SGENMAT

*

* .. Внешние функции ..

INTEGER ISAMAX

REAL SDOT

EXTERNAL ISAMAX, SDOT

*

* .. Внутренние функции ..

INTRINSIC MOD

*

* .. Параметры ..

INTEGER MAXN

PARAMETER ( MAXN = 8000 )

INCLUDE 'fpvm3.h'

*

* .. Скаляры ..

INTEGER N_ LN_ MYTID_ NPROCS_ IBUF_ IERR

INTEGER I, J, K

REAL LDOT, GDOT

*

* .. Массивы ..

INTEGER TIDS(0:63)

REAL X(MAXN), Y(MAXN)

*

* Регистрация в PVM и получение идентификаторов задач

* своего и ведущего процессов.

*

CALL PVMFMYTID( MYTID )

CALL PVMFPARENT( TIDS(0) )

*

* Нужно ли порождать другие процессы 

* (Это - ведущий процесс).

*

IF ( TIDS(0) .EQ. PVMNOPARENT ) THEN

*

* Получение исходных данных.

*

WRITE(*.*)

    'Сколько процессов нужно создать (1-64)?'

READ(*.*) NPROCS

WRITE(*,2000) MAXN

READ(*.*) N

TIDS(0) = MYTID

IF ( N .GT. MAXN ) THEN

WRITE(*.*) 'N слишком велико.

  Увеличьте параметр MAXN'//$ 'для этого случая.'

STOP

END IF

*

* LN - количество элементов точечного произведения

* для локальной обработки. Все имеют одинаковое

* количество, а ``лишние'' элементы достаются ведущему.

* ``Общее'' количество элементов хранится в J.

*

J = N / NPROCS

LN = J + MOD(N, NPROCS)

I = LN + 1

*

* Генерирование случайных X и Y.

*

CALL SGENMAT( N, 1, X, N, MYTID, NPROCS, MAXN, J )

CALL SGENMAT( N, 1, Y, N, I, N, LN, NPROCS )

*

* Обход всех рабочих процессов.

*

DO 10 K = 1, NPROCS-1

*

* Порождение процесса и проверка на ошибки.

*

CALL PVMFSPAWN( 'psdot', 0, 'anywhere', 1, TIDS(K),

     IERR )

IF (IERR .NE. 1) THEN

WRITE(*.*) 'ERROR, невозможно создать процесс #',K,

$ '. Dying . . .'

CALL PVMFEXIT( IERR )

STOP

END IF

*

* Рассылка исходных данных.

*

CALL PVMFINITSEND( PVMDEFAULT, IBUF )

CALL PVMFPACK( INTEGER4, J, 1, 1, IERR )

CALL PVMFPACK( REAL4, X(I), J, 1, IERR )

CALL PVMFPACK( REAL4, Y(I), J, 1, IERR )

CALL PVMFSEND( TIDS(K), 0, IERR )

I = I + J

10 CONTINUE

*

* Вычисление ведущим своей части точечного произведения.

*

GDOT = SDOT( LN, X, 1, Y, 1 )

*

* Получение локальных точечных произведений и их

* сложение с целью формирования глобального.

*

DO 20 K = 1, NPROCS-1)

CALL PVMFRECV( -1, 1, IBUF )

CALL PVMFUNPACK( REAL4, LDOT, 1, 1, IERR )

GDOT = GDOT + LDOT

20 CONTINUE

*

* Вывод на экран результатов.

*

WRITE(*,*) ' '

WRITE(*,*) '<x,y> = ',GDOT

*

* ``Последовательное'' вычисление точечного произведения

* и его вычитание из ``распределенного'' точечного

* произведения - с целью проверки

* на допустимость уровня ошибок.

*

LDOT = SDOT( N, X, 1, Y, 1 )

WRITE(*,*) '<x,y> : последовательное произведение.

    <x,y>^ : ' $ 'распределенное произведение.'

WRITE(*,*) '| <x,y> - <x,y>^ | = ',ABS(GDOT = LDOT)

WRITE(*,*) 'Завершено.'

*

* Является ли этот процесс рабочим?

*

ELSE

*

* Прием исходных данных.

*

CALL PVMFRECV( TIDS(0), 0, IBUF )

CALL PVMFUNPACK( INTEGER4, LN, 1, 1, IERR )

CALL PVMFUNPACK( REAL, X, LN, 1, IERR )

CALL PVMFUNPACK( REAL, Y, LN, 1, IERR )

*

* Вычисление локального точечного произведения

* и передача его ведущему.

*

LDOT = SDOT( LN, X, 1, Y, 1 )

CALL PVMFINITSEND( PVMDEFAULT, IBUF )

CALL PVMFPACK( REAL4, LDOT, 1, 1, IERR )

CALL PVMFSEND( TIDS(0), 1, IERR )

END IF

*

CALL PVMFEXIT( 0 )

*

1000 FORMAT(I10, 'Успешно порожден процесс #',I2,',

    TID =',I10)

2000 FORMAT('Введите длину перемножаемых векторов

   (1 -',I7,'):')

STOP

*

* End program PSDOT

*

END


next up previous contents
Next: Пример с ошибкой Up: PVM - параллельная виртуальная Previous: ``Раздваивание - присоединение''   Contents
2004-06-22



Партнёры:
PostgresPro
Inferno Solutions
Hosting by Hoster.ru
Хостинг:

Закладки на сайте
Проследить за страницей
Created 1996-2024 by Maxim Chirkov
Добавить, Поддержать, Вебмастеру