Данные на входе: База Данных, незаконченное 2-е внутреннее представление.
Данные на выходе: База Данных с комментариями.
Как проходит преобразование входных данных в выходные:
Из 2-го внутреннего представления комментарии переносятся в Базу Данных, соблюдая синтаксис OpenMP. Оценивается общее ускорение.
Алгоритм преобразования входных данных в выходные:
Проходим все вершины в Базе Данных. Каждую вершину пытаемся найти во 2-м внутреннем представлении, в случае успеха проставляем соответствующие комментарии следующим образом:
1) Если есть массивы с пометкой threadprivate, то в вершину с описанием переменных заносится !$OMP THREADPRIVATE (список переменных).
2) Если цикл первый в параллельном регионе и цикл выгодный для распараллеливания !$OMP PARALLEL <список необходимых к обозначению PRIVATE и SHARED переменных> < COPYIN (список переменных) >
<список необходимых к обозначению PRIVATE и SHARED переменных> - перечисление директив (клауз) вида PRIVATE (имя переменной) или SHARED (имя переменной). В одном списке может быть несколько и PRIVATE, и SHARED.
|
|
< COPYIN (список переменных) > - указывается, если в цикле используются переменныес пометкой threadprivate, причем все они должны быть перечислены через запятую в списке переменных.
3) Если цикл последний в параллельном регионе - !$OMP END PARALLEL, как директива после цикла.
4) Если цикл выгодный для распараллеливания - !$OMP DO < ORDERED > <список REDUCTION, LASTPRIVATE, FIRSTPRIVATE >
< ORDERED > - директива ORDERED. Указывается, если при распараллеливании цикла используется ORDERED.
<список REDUCTION, LASTPRIVATE, FIRSTPRIVATE > - перечисление директив (клауз) вида REDUCTION (имя переменной), или LASTPRIVATE (имя переменной), или FIRSTPRIVATE (имя переменной). В одном списке может быть несколько и REDUCTION, LASTPRIVATE, FIRSTPRIVATE.
5) Если цикл выгодный для распараллеливания - !$OMP END DO, как директива после цикла.
6) Если у цикла пометка Ordered, перед первой вершиной с пометкой "первое использование ORDERED" вносится !$OMP ORDERED.
7) Если у цикла пометка Ordered, в конец последней вершины с пометкой "последнее использование ORDERED" вносится, !$OMP END ORDERED.
8) Если у цикла пометка pipeline – вставляются следующие директивы:
В области инициализации переменных, проверяется уникальность и происходит объявление функций и переменных, необходимых для функционирования конвейера:
!$ INTEGER OMP_GET_NUM_THREADS, OMP_GET_THREAD_NUM
!$ INTEGER IAM, NUMT, ISYNC("количество процессоров")
При инициализации параллельного региона, в который входит цикл с конвейером:
!$OMP PARALLEL PRIVATE (IAM,NUMT,ILIMIT)
Перед do внешнего цикла - инициализация нитей и синхронизационного массива ISYNC:
!$ iam = omp_get_thread_num ()
!$ numt = omp_get_num_threads ()
!$ ILIMIT=MIN(NUMT-1,Число витков внешнего цикла)
|
|
!$ ISYNC (IAM) = 0
!$OMP BARRIER
До цикла с конвейерной зависимостью - инициализация конвейера, допуск к циклу для нитей только после того, как предыдущая нить сделала одну итерацию внешнего цикла и распараллеливание витков внутреннего цикла между нитями:
!$ IF (IAM.GT. 0.AND. IAM.LE. ILIMIT) THEN
!$ DO WHILE (ISYNC (IAM-1).EQ. 0)
!$OMP FLUSH (ISYNC)
!$ ENDDO
!$ ISYNC (IAM-1)=0
!$OMP FLUSH(ISYNC)
!$ ENDIF
!$OMP DO
Перед enddo внешнего цикла – дождаться, пока следующая нить запустится, и продолжать выполнение цикла:
!$OMP ENDDO NOWAIT
!$ IF (IAM.LT. ILIMIT) THEN
!$ DO WHILE (ISYNC (IAM).EQ. 1)
!$OMP FLUSH (ISYNC)
!$ ENDDO
!$ ISYNC (IAM)=1
!$OMP FLUSH(ISYNC)
!$ ENDIF
После enddo внешнего цикла – синхронизация:
!$OMP BARRIER
Таким образом, все нити входят в параллельный регион. Отрабатывает 1-я нить со своей частью витков внутреннего цикла. Вступает в работу 2-я нить, работают обе нити, причем 1-я со 2-м значением итератора, а 2-я с первым и т.д. Пример функционирования конвейера показан на Рис. 10.
Рис. 10. Вычисление цикла с конвейерной зависимостью для 2-х мерного случая. Квадраты – области элементов массива; цифра - № нити, которая вычислит эту область; цифра в скобках – шаг работы конвейера, на котором вычислится область.