В этом разделе приведена простая программа на Фортране - PSDOT - для вычисления точечного произведения. Программа вычисляет точечное произведение массивов X и Y. В первую очередь в PSDOT вызываются PVMFMYTID() и PVMFPARENT(). Вызов PVMFPARENT вернет PVMNOPARENT, если задача не была ранее порождена другой задачей PVM. Если это случай, когда PSDOT - ведущая и, следовательно, должна породить отдельные рабочие копии PSDOT, то у пользователя запрашивается число рабочих процессов и длина векторов для вычисления. Каждый порождаемый процесс будет принимать элементов X и Y, где - длина векторов, а - количество процессов, используемых при вычислении. Если не делится на нацело, то ведущий будет вычислять точечное произведение ``дополнительных элементов''. Подпрограммой SGENMAT случайным образом генерируются значения X и Y. После этого PSDOT порождает своих копий и передает каждой новой задаче часть массивов X и Y. Каждое сообщение содержит размеры подмассивов и, собственно, сами подмассивы. После того как ведущий породил рабочие процессы и передал подвекторы, он вычисляет точечное произведение своей порции X и Y. Затем ведущий процесс принимает остальные локальные точечные произведения от рабочих процессов. Обратите внимание на то, что при вызове PVMFRECV как параметр-идентификатор задачи используется специальный символ (-1). Это говорит о том, что сообщение от ``любой'' задачи будет устраивать принимающую сторону. Применение специального символа таким образом может привести к ``гибридизации''. Но в данном случае ``гибридизация'' не создаст проблему, поскольку сложение по природе коммутативно. Другими словами, совершенно не важно, в каком порядке складываются частичные суммы, полученные от рабочих. Если кто-то не уверен, что ``гибридизация'' не приведет к нежелательным программным эффектам, то ему желательно избегать ее возникновения.
Как только ведущий принял все локальные точечные произведения и глобально просуммировал их, он вычисляет полное точечное произведение уже локально. Один результат вычитается из второго, а разница между величинами выводится на экран. Несущественная разница вполне ожидаема, ибо существуют погрешности, связанные с округлениями чисел с плавающей точкой.
Если программа PSDOT -это рабочий, то она принимает содержащее подмассивы X и Y сообщение от ведущего процесса. Она вычисляет точечное произведение этих подмассивов и передает результат назад ведущему процессу. В целях краткости сюда не включены подпрограммы SGENMAT и SDOT.
Программа - пример PSDOT.F:
*
* 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