<?xml version='1.0' standalone='no' ?>
<journal xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="JournalArticulus.xsd">
    <operCard>
        <operator>ИПМ им. М.В.Келдыша РАН|Publicator</operator>
        <date>2026-04-08 19:34:29</date>
        <cntArticle>1</cntArticle>
        <cs>0</cs>
    </operCard>
    <titleid>32018</titleid>
    <issn>2071-2901</issn>
    <codeNEB>20712901</codeNEB>
    <journalInfo lang="RUS">
        <title>Препринты ИПМ им. М.В.Келдыша</title>
    </journalInfo>
    <issue>
        <volume/>
        <number>76</number>
        <altNumber/>
        <part/>
        <dateUni>2025</dateUni>
        <issTitle/>
        <pages>1-32</pages>
        <articles>
            <article>
                <pages>1-32</pages>
                <artType>RAR</artType>
                <authors>
                    <author num="001">
                        <authorCodes>
                            <spin>9699-6471</spin>
                            <orcid>0000-0001-8385-8894</orcid>
                        </authorCodes>
                        <individInfo lang="RUS">
                            <surname>Алексахин</surname>
                            <initials>Валерий Федорович</initials>
                            <orgName>Институт прикладной математики им. М.В.Келдыша РАН</orgName>
                            <email>valex@keldysh.ru</email>
                        </individInfo>
                        <individInfo lang="ENG">
                            <surname>Aleksakhin</surname>
                            <initials>V.F.</initials>
                            <orgName>Keldysh Institute of Applied Mathematics RAS</orgName>
                        </individInfo>
                    </author>
                    <author num="002">
                        <authorCodes>
                            <spin>8464-6318</spin>
                            <orcid>0000-0003-0343-3859</orcid>
                        </authorCodes>
                        <individInfo lang="RUS">
                            <surname>Бахтин</surname>
                            <initials>Владимир Александрович</initials>
                            <orgName>Институт прикладной математики им. М.В.Келдыша РАН</orgName>
                            <email>bakhtin@keldysh.ru</email>
                        </individInfo>
                        <individInfo lang="ENG">
                            <surname>Bakhtin</surname>
                            <initials>V.A.</initials>
                            <orgName>Keldysh Institute of Applied Mathematics RAS</orgName>
                        </individInfo>
                    </author>
                    <author num="003">
                        <authorCodes>
                            <spin>6358-3927</spin>
                            <orcid>0000-0002-1033-6371</orcid>
                        </authorCodes>
                        <individInfo lang="RUS">
                            <surname>Жукова</surname>
                            <initials>Ольга Федоровна</initials>
                            <orgName>Институт прикладной математики им. М.В.Келдыша РАН</orgName>
                            <email>socol@keldysh.ru</email>
                        </individInfo>
                        <individInfo lang="ENG">
                            <surname>Zhukova</surname>
                            <initials>O.F.</initials>
                            <orgName>Keldysh Institute of Applied Mathematics RAS</orgName>
                        </individInfo>
                    </author>
                    <author num="004">
                        <authorCodes>
                            <spin>8065-7264</spin>
                            <orcid>0000-0002-6319-5090</orcid>
                        </authorCodes>
                        <individInfo lang="RUS">
                            <surname>Захаров</surname>
                            <initials>Дмитрий Александрович</initials>
                            <orgName>Институт прикладной математики им. М.В.Келдыша РАН</orgName>
                            <email>s123-93@mail.ru</email>
                        </individInfo>
                        <individInfo lang="ENG">
                            <surname>Zakharov</surname>
                            <initials>D.A.</initials>
                            <orgName>Keldysh Institute of Applied Mathematics RAS</orgName>
                        </individInfo>
                    </author>
                    <author num="005">
                        <authorCodes>
                            <spin>8151-3267</spin>
                            <orcid>0000-0002-7603-4026</orcid>
                        </authorCodes>
                        <individInfo lang="RUS">
                            <surname>Катаев</surname>
                            <initials>Никита Андреевич</initials>
                            <orgName>Институт прикладной математики им. М.В.Келдыша РАН</orgName>
                            <email>kataev@keldysh.ru</email>
                        </individInfo>
                        <individInfo lang="ENG">
                            <surname>Kataev</surname>
                            <initials>N.A.</initials>
                            <orgName>Keldysh Institute of Applied Mathematics RAS</orgName>
                        </individInfo>
                    </author>
                    <author num="006">
                        <authorCodes>
                            <spin>5485-7756</spin>
                            <orcid>0000-0002-1384-7484</orcid>
                        </authorCodes>
                        <individInfo lang="RUS">
                            <surname>Колганов</surname>
                            <initials>Александр Сергеевич</initials>
                            <orgName>Институт прикладной математики им. М.В.Келдыша РАН</orgName>
                            <email>alexander.k.s@mail.ru</email>
                        </individInfo>
                        <individInfo lang="ENG">
                            <surname>Kolganov</surname>
                            <initials>A.S.</initials>
                            <orgName>Keldysh Institute of Applied Mathematics RAS</orgName>
                        </individInfo>
                    </author>
                    <author num="007">
                        <authorCodes>
                            <spin>2704-6199</spin>
                            <orcid>0000-0001-6630-964X</orcid>
                        </authorCodes>
                        <individInfo lang="RUS">
                            <surname>Крюков</surname>
                            <initials>Виктор Алексеевич</initials>
                            <orgName>Институт прикладной математики им. М.В.Келдыша РАН</orgName>
                            <email>krukov@keldysh.ru</email>
                        </individInfo>
                        <individInfo lang="ENG">
                            <surname>Krukov</surname>
                            <initials>V.A.</initials>
                            <orgName>Keldysh Institute of Applied Mathematics RAS</orgName>
                        </individInfo>
                    </author>
                    <author num="008">
                        <authorCodes>
                            <spin>6223-9854</spin>
                            <orcid>0000-0002-0254-172X</orcid>
                        </authorCodes>
                        <individInfo lang="RUS">
                            <surname>Кузнецов</surname>
                            <initials>Михаил Юрьевич</initials>
                            <orgName>Институт прикладной математики им. М.В.Келдыша РАН</orgName>
                            <email>vmk-post@yandex.ru</email>
                        </individInfo>
                        <individInfo lang="ENG">
                            <surname>Kuznetsov</surname>
                            <initials>M.J.</initials>
                            <orgName>Keldysh Institute of Applied Mathematics RAS</orgName>
                        </individInfo>
                    </author>
                    <author num="009">
                        <authorCodes>
                            <spin>6067-6510</spin>
                            <orcid>0000-0002-9730-1381</orcid>
                        </authorCodes>
                        <individInfo lang="RUS">
                            <surname>Поддерюгина</surname>
                            <initials>Наталия Викторовна</initials>
                            <orgName>Институт прикладной математики им. М.В.Келдыша РАН</orgName>
                            <email>konov@keldysh.ru</email>
                        </individInfo>
                        <individInfo lang="ENG">
                            <surname>Podderyugina</surname>
                            <initials>N.V.</initials>
                            <orgName>Keldysh Institute of Applied Mathematics RAS</orgName>
                        </individInfo>
                    </author>
                    <author num="010">
                        <authorCodes>
                            <spin>1385-1947</spin>
                            <orcid>0000-0002-2174-3212</orcid>
                        </authorCodes>
                        <individInfo lang="RUS">
                            <surname>Савицкая</surname>
                            <initials>Ольга Антониевна</initials>
                            <orgName>Институт прикладной математики им. М.В.Келдыша РАН</orgName>
                            <email>savol@keldysh.ru</email>
                        </individInfo>
                        <individInfo lang="ENG">
                            <surname>Savitskaya</surname>
                            <initials>O.A.</initials>
                            <orgName>Keldysh Institute of Applied Mathematics RAS</orgName>
                        </individInfo>
                    </author>
                    <author num="011">
                        <authorCodes>
                            <spin>3977-3860</spin>
                            <orcid>0000-0002-2971-4248</orcid>
                        </authorCodes>
                        <individInfo lang="RUS">
                            <surname>Смирнов</surname>
                            <initials>Александр Андреевич</initials>
                            <orgName>Институт прикладной математики им. М.В.Келдыша РАН</orgName>
                            <email>smiraland@gmail.com</email>
                        </individInfo>
                        <individInfo lang="ENG">
                            <surname>Smirnov</surname>
                            <initials>A.A.</initials>
                            <orgName>Keldysh Institute of Applied Mathematics RAS</orgName>
                        </individInfo>
                    </author>
                </authors>
                <artTitles>
                    <artTitle lang="RUS">Методика распараллеливания программ на языке Fortran-DVMH</artTitle>
                    <artTitle lang="ENG">Methodics of Fortran-DVMH program parallelization</artTitle>
                </artTitles>
                <abstracts>
                    <abstract lang="RUS">Язык Fortran-DVMH предназначен для разработки мобильных и эффективных параллельных программ вычислительного характера для кластеров с ускорителями. Он представляет собой расширение языка Фортран в соответствии с моделью DVMH (DVM for Heterogeneous systems). При использовании языка Fortran-DVMH программист имеет один вариант программы и для последовательного, и для параллельного выполнения. Программа, помимо описания алгоритма обычными средствами языка Фортран, содержит правила параллельного выполнения этого алгоритма. В данной методике представлены основные возможности языка Fortran-DVMH, а также информация, необходимая для компиляции и запуска DVMH-программ на счет.</abstract>
                    <abstract lang="ENG">The Fortran-DVMH language is designed for developing portable and efficient parallel programs of computational nature for clusters with accelerators. It is an extension of the Fortran language based on the DVMH model (DVM for Heterogeneous systems). When using the Fortran-DVMH language, the programmer has a single version of the program for both sequential and parallel execution. In addition to describing the algorithm using standard Fortran tools, the program includes rules for parallel execution of this algorithm. This guide presents the main features of the Fortran-DVMH language, as well as the information necessary for compiling and running DVMH programs in practice.</abstract>
                </abstracts>
                <text lang="RUS">    
1. Введение
   
   В последнее время все большее распространение получают вычислительные кластеры, в узлах которых установлены ускорители. 
   В 2011 году в Институте прикладной математики им. М.В. Келдыша РАН была разработана модель параллельного программирования для кластеров с ускорителями. Модель является расширением модели DVM и получила название DVMH (DVM for Heterogeneous systems).
   Разработанный в рамках модели язык Fortran-DVMH (FDVMH) упрощает процесс написания параллельных программ, а также позволяет с небольшими изменениями перевести программу для кластера (DVM-программу) в программу для кластера с ускорителями (DVMH-программу).
   Язык FDVMH представляет собой язык Фортран 95, расширенный спецификациями параллелизма. Эти спецификации оформлены в виде специальных комментариев, которые называются директивами. Директивы “невидимы” для стандартных компиляторов, что позволяет иметь один вариант программы для последовательного и параллельного выполнения.
   Язык FDVMH позволяет написать программу (DVMH-программу), которая может выполняться и как последовательная, и как параллельная для кластеров с ускорителями и без ускорителей.
   
2. Развитие DVM-системы. Модель DVMH и разные архитектуры
   В модели DVM вычислительная система рассматривается как многомерный массив виртуальных процессоров. 
   В модели DVMH виртуальный процессор стал гетерогенным – он состоит из виртуального мультипроцессора и нескольких виртуальных ускорителей разной архитектуры. При этом виртуальный мультипроцессор отображается на центральное процессорное устройство (далее ЦПУ) и работает на общей оперативной памяти, а каждый виртуальный ускоритель имеет свою оперативную память и отображается на аппаратный ускоритель соответствующей архитектуры.
   При разработке модели DVMH за основу была взята модель DVM [1], в которую добавлены конструкции для организации вычислений на кластерах с ускорителями и спецификации потоков данных для управления перемещением данных между оперативной памятью центрального процессора и запоминающими устройствами ускорителей.
   Модель параллелизма базируется на специальной форме параллелизма по данным: одна программа – множество потоков данных. В этой модели одна и та же программа выполняется на каждом виртуальном процессоре, но каждый процессор выполняет свое подмножество операторов в соответствии с распределением данных.
   Вначале программист определяет массивы (распределенные данные) и витки циклов, которые могут быть распределены между процессорами.
   Распределенные массивы (DVMH-массивы) специфицируются директивами отображения данных (см. раздел 4), а параллельные  циклы (DVMH-циклы) – директивами распределения вычислений (см. раздел 5).
   Остальные переменные (распределяемые по умолчанию) отображаются по одному экземпляру на каждый процессор (размноженные данные). Размноженная переменная должна иметь одно и то же значение на каждом процессоре, за исключением редукционных переменных (см. раздел 6.5) и приватных переменных (см. раздел 5) в параллельном цикле.
   Распределение данных определяет множество локальных или собственных переменных для каждого процессора. При этом вычисления распределяются по правилу собственных вычислений: каждый процессор выполняет только вычисления собственных данных, т.е. данных, распределенных на этот процессор.
   При выполнении программы процессору могут потребоваться как значения собственных переменных, так и значения несобственных (удаленных) переменных. Все удаленные переменные должны быть указаны в директивах доступа к удаленным данным (см. раздел 6).
   Далее программист определяет фрагменты кода, которые могут быть выполнены на ускорителях или ядрах центрального процессора. Такие фрагменты называются вычислительными регионами или просто регионами.
   Фрагменты программы вне регионов всегда выполняются на центральном процессоре.
   Для каждого региона указываются данные, необходимые для его выполнения (входные, выходные, локальные).
   Для управления перемещениями данных между ускорителями и центральным процессором предусмотрены специальные директивы (см. раздел 7.3).
   Параллелизм в DVMH-программах проявляется на нескольких уровнях:
* параллелизм по данным – распределение данных и вычислений между процессорами;
* параллелизм вычислений в рамках одного гетерогенного процессора;
* параллелизм задач – независимые вычисления на секциях массива процессоров.
Замечание:
С возможностями языка FDVMH для обеспечения независимых вычислений на секциях массива процессоров можно познакомиться в описании языка FDVMH [2].
3. Распараллеливание программ на языке FDVMH
   Параллелизм программы описывается на языке FDVMH с помощью директив. Каждая директива оформляется в виде специального комментария:
!DVM$&lt;DVMH-директива&gt;
   Распараллеливание программы в модели DVMH можно разделить на следующие этапы:
1. Распределение данных (массивов) и вычислений (параллельных циклов) на массив виртуальных процессоров.
2. Определение и спецификация удаленных данных.
3. Определение регионов для выполнения на ускорителях.
4. Управление перемещением данных между памятью ЦПУ и запоминающими устройствами ускорителей.
Замечания:
* Полное описание языка FDVMH, формальный синтаксис директив, правила записи директив в свободной и фиксированной формах приведены в Приложении 1 документа «Описание языка Fortran DVMH» [2].
* Все примеры написаны в фиксированной форме.
4. Распределение массивов и параллельных циклов
   На первом этапе используются директивы DISTRIBUTE, ALIGN и PARALLEL. Если рассматривать эти директивы на абстрактном уровне, то они устанавливают соответствие между точками индексных (дискретных) пространств двух объектов. При этом используются индексные пространства следующих объектов:
P – индексное пространство массива виртуальных процессоров. Массив виртуальных процессоров определяет пользователь и задает его при запуске программы на выполнение. Размерность виртуального массива определяется размерностью массива данных. Число измерений этого массива не превышает размерность массива данных.
Ai – индексное пространство i-го массива данных.
Lj – индексное пространство j-го параллельного цикла. Параллельный цикл рассматривается как массив, элементом которого является виток цикла. Количество измерений этого массива определяется количеством заголовков цикла.
   Директивы устанавливают соответствие между точками (элементами) следующих объектов:
DISTRIBUTE: Ai==&gt; P. Каждой точке (виртуальному процессору) P ставится в соответствие подмножество точек (элементов массива) Ai.
ALIGN: Ai1==&gt;Ai2. Каждой точке (элементу массива) Ai2 ставится в соответствие подмножество точек (элементов массива) Ai1.
PARALLEL: Lj==&gt;Ai. Каждой точке (элементу массива) Ai ставится в соответствие подмножество точек (витков цикла) Lj.
   Совокупность этих директив определяет для каждого виртуального процессора подмножество собственных элементов массивов и витков параллельных циклов.
   Данные и операторы, не специфицированные этими директивами, автоматически распределяются на каждый виртуальный процессор (размноженные данные и не распараллеливаемые вычисления).
4.1. Распределение массивов. Директивы DISTRIBUTE и REDISTRIBUTE
   Язык FDVMH поддерживает распределение блоками (равными и неравными) и распределение через выравнивание.
   Распределение массива A описывается следующей директивой:
!DVM$ DISTRIBUTE A( f1…fk),
где fi – формат распределения для i-го измерения:
fi=BLOCK–распределение равными блокамиK–количество измеренийЗамечание:
Язык FDVMH позволяет задать более гибкие форматы распределения данных WGT_BLOCK, GEN_BLOCK и MULT_BLOCK. С этими форматами можно познакомиться в описании языка FDVMH [2].
   Если fi =BLOCK, то измерение массива распределяется преимущественно равными блоками. На каждый процессор распределяется блок размером 
?(N-1)/P? +1 элементов. При некоторых соотношениях N и P несколько последних процессоров могут не содержать значений элементов массива.
   Количество форматов BLOCK определяет количество измерений массива виртуальных процессоров. Если пронумеровать форматы BLOCK как fb1,…,fbn, то измерение с форматом fbi отображается на i-е измерение массива виртуальных процессоров, а количество блоков определяется размером i-го измерения массива виртуальных процессоров. В этом случае при запуске программы на выполнение можно задавать любой n-мерный массив виртуальных процессоров.
   Для многомерных массивов формат распределения указывается для каждого измерения. Между измерениями распределяемого массива и массива процессоров устанавливается следующее соответствие.
   Пусть массив процессоров имеет n измерений. Если пронумеровать измерения массива без формата * слева направо d1, ..., dk, то измерение di  будет распределяться на i-е измерение массива процессоров. При этом должно выполняться условие k?n.
   Так, для двумерного массива А, имеющего описание:
REAL A(100,100)
при задании одномерного распределения
!DVM$ DISTRIBUTE A(BLOCK,*),
распределение данных по процессорам показано на рис. 1.
Процессор 1Процессор 2A(1: 50,1:100)A(51:100,1:100)    Рис. 1. Распределение массива А при одномерном распределении
   Если для того же массива задать двумерное распределение при помощи директивы
!DVM$ DISTRIBUTE A(BLOCK,BLOCK),
то распределение данных по процессорам будет выглядеть по-другому, см.  рис. 2.
Процессор 1Процессор 2A(1: 50,1:100)A(51:100,1:100)A(51:100,1:50)A(51:100,51:100)Процессор 3   Процессор 4    Рис. 2. Распределение массива А при двумерном распределении
Массив процессоров должен быть двумерным.
   Несколько одинаково распределяемых массивов (A1, A2,…) можно распределить одной директивой вида:
!DVM$ DISTRIBUTE ( f1…fk) :: A1, A2, … ,
где fi – формат распределения для i-го измерения.
   При этом массивы должны иметь одинаковое число измерений, но необязательно одинаковые размеры измерений.
   Так, для одномерных массивов A, B, С с описанием:
   REAL A (12), B(11), C(5)
при задании распределения:
!DVM$ DISTRIBUTE (BLOCK) :: A,B,C
вариант распределения при запуске на четырех процессорах показан на рис. 3.



АПроцессор 1Процессор 2Процессор 3Процессор 4123456789101112B
С123456789101112345Рис. 3. Распределение массива А при запуске на четырех процессорах
   Директива REDISTRIBUTE может применяться только к массивам со спецификацией DYNAMIC:
!DVM$ DYNAMIC A
   Для перераспределяемого массива можно не указывать начальное распределение – это так называемое отложенное распределение. Директива DISTRIBUTE будет иметь вид
!DVM$ DISTRIBUTE :: A.
Спецификацию DYNAMIC в этом случае можно не указывать.
   Если в директиве DISTRIBUTE указан массив с атрибутом ALLOCATABLE, то распределение откладывается до выполнения оператора ALLOCATE, который размещает массив в памяти.
   Директива REDISTRIBUTE для динамически размещаемого массива может выполняться только после выполнения оператора ALLOCATE.
4.2. Локализация данных. Директивы ALIGN и REALIGN
   Выравнивание массива A на распределенный массив В ставит в соответствие каждому элементу массива А элемент или секцию массива В. При распределении массива В одновременно будет распределяться массив А. Если на данный процессор распределен элемент В, то на этот же процессор будет распределен элемент массива А, поставленный в соответствие выравниванием.
   Метод распределения через выравнивание выполняет две следующие функции:
1. Одинаковое распределение массивов одной формы на один массив процессоров не всегда гарантирует, что соответствующие элементы будут размещены на одном процессоре, см. рис. 4.
              INTEGER ::  A(N), B(2* N)
!DVM$ DISTRIBUTE (BLOCK) :: A,B
!DVM$ PARALLEL (I) ON B(2 * I)
              DO  I = 1,N
                   B(2 * I) = A(I)
              ENDDO    Рис. 4. Фрагмент программы с одинаковым распределением массивов
   Гарантию размещения на одном процессоре дает только выравнивание соответствующих элементов массивов, см. рис. 5.
              INTEGER ::  A(N), B(2* N)
!DVM$ DISTRIBUTE  B (BLOCK)  
!DVM$ ALIGN A( I)  WITH  B(2*I)
!DVM$ PARALLEL (I) ON B(2 * I)
              DO  I =1,N
                    B(2 * I) = A(I)
             ENDDO    Рис. 5. Фрагмент программы с выравниванием массивов
2. На один массив может быть выровнено несколько массивов. Изменение распределения одного массива директивой REDISTRIBUTE вызовет соответствующее изменение распределения группы массивов.
   Основным способом локализации данных (т.е. уменьшения количества удаленных данных) является совместное распределение нескольких массивов. Совместное распределение двух массивов А и В описывается директивой выравнивания массивов.
!DVM$  ALIGN  A ( a1… an) WITH  B  ( b1… bm ),
где:
ai – параметр i-го измерения выравниваемого массива А,
bj – параметр j-го измерения базового массива B,
n – количество измерений массива А,
m – количество измерений массива В.
   Эта директива ставит в соответствие каждому элементу массива В некоторое подмножество элементов массива А. Установленное подмножество элементов массива А будет распределено на тот процессор, где будет размещен соответствующий элемент массива В. Параметры выравниваемого массива А и базового массива В могут иметь следующий вид:
ai = IDi  bj = c*IDj+d 
= *      = *
где: 
IDi , IDj – идентификаторы
c, d  – целочисленные константы
   Если ai = * , то i-е измерение массива А целиком распределяется на каждый процессор, где распределен хотя бы один элемент В (размножение, локальное измерение).
Если bj = * , то выполнение директивы ALIGN не зависит от j-го измерения массива В (коллапс, т.е. измерение как бы не существует при установлении соответствия).
Если ai = IDi, то обязательно существует одно и только одно bj = c*IDj+d, где IDi=IDj. Равенство IDi=IDj означает, что i-е измерение массива А ставится в соответствие j-му измерению массива В. Соответствие элементов устанавливается функцией c*IDj+d. При этом индексы базового массива не должны выходить за пределы индексного пространства выравниваемого массива, иначе нужно осуществлять выравнивание по шаблону (см. раздел 6.1).
   При локализации данных с помощью директивы ALIGN для многомерных массивов необходимо указывать индексы выравниваемых элементов массивов по всем измерениям.
   Ниже рассмотрены возможности директивы выравнивания для совместного распределения массивов.
Пусть в программе описаны следующие массивы:
REAL A(10), B(6,10), C(5,16), D(16), E(8), F(10), G(15), H(15)
Два из них распределены:
!DVM$ DISTRIBUTE B (BLOCK,BLOCK)
!DVM$ DISTRIBUTE D (BLOCK)
   При помощи директивы
!DVM$ ALIGN G( I )  WITH  D( I+1 )
можно выровнять массивы G и D со сдвигом. Распределение по процессорам показано на рис. 6.
                        Процессор 1Процессор 2Процессор 3Процессор 4D12345678910111213141516G123456789101112131415Рис. 6. Выравнивание вектора на вектор со сдвигом 
   При помощи директивы
!DVM$ ALIGN  E( I )  WITH D( 2*I )
можно выровнять массивы E и D с раздвижкой. Распределение по процессорам показано на рис. 7.
                                    Процессор 1Процессор 2Процессор 3Процессор 4                        D12345678910111213141516E12345678Рис. 7. Выравнивание вектора на вектор с раздвижкой 
   При помощи директивы
!DVM$ ALIGN  A( I )  WITH B( 1, I )
можно осуществить выравнивание на секцию массива (вектор на первую строку матрицы А). Распределение по процессорам показано на рис. 8.
Процессор 1Процессор 2A123456789101234567891012B3456Процессор 3      Процессор 4Рис. 8. Выравнивание вектора на первую строку матрицы 
   При помощи директивы
!DVM$ ALIGN  F( I )  WITH  B( *, I )
можно осуществить размножение вектора – выравнивание на каждую строку. Распределение по процессорам приведено на рис. 9.
Процессор 1Процессор 2F123456789101234567891012B3456F12345678910Процессор 3Процессор 4Рис. 9. Выравнивание на каждую строку 
   При помощи директивы
!DVM$ ALIGN  C( *, I )  WITH D( I )
можно осуществить сжатие матрицы – столбец матрицы будет соответствовать элементу вектора. Распределение по процессорам показано на рис. 10.
Процессор 1Процессор 2Процессор 3Процессор 4D123456789101112131415161234567891011121314151612C345
Рис. 10. Выравнивание столбца матрицы на вектор
   Несколько массивов (A1, A2,…) можно выровнять одинаковым образом на один и тот же массив B одной директивой вида
!DVM$  ALIGN (a1… an) WITH  B (b1… bm)  :: A1, A2, …
   При этом массивы A1, A2… должны иметь одинаковое число измерений (n), но необязательно одинаковые размеры измерений.
   Изменить параметры выравнивания и/или базовый массив можно с помощью директивы
!DVM$  REALIGN  A ( a1… an) WITH  C (c1… ck )
При этом выравниваемый массив должен быть описан как DYNAMIC.
   Начальное выравнивание может быть не задано – это так называемое отложенное выравнивание. Директива ALIGN будет иметь вид
!DVM$  ALIGN :: A
Спецификацию DYNAMIC в этом случае можно не указывать.
   Если в директиве ALIGN в качестве выравниваемого массива указана переменная с атрибутом ALLOCATABLE, то выполнение директивы откладывается до выполнения оператора ALLOCATE. Директива REALIGN может выполняться только после выполнения оператора ALLOCATE.
   Фрагмент программы на рис. 11 иллюстрирует порядок расположения директив для динамических массивов. Операторы DEALLOCATE выполняются в обратном порядке по отношению к ALLOCATE.
   
   
   
              SUBROUTINE  SBP(N)
              REAL,ALLOCATABLE,DIMENSION(:,:)::  X, Y
!DVM$ ALIGN  Y( I, J )  WITH  X( I, J )
!DVM$ DISTRIBUTE  X ( BLOCK, BLOCK )
!DVM$ DYNAMIC  Y
  ...
              ALLOCATE(X(N,N))
              ALLOCATE(Y(N,N))
  ...
!DVM$ REALIGN  Y( I, J )  WITH  X( J, I )
  ...
              DEALLOCATE(Y)
              DEALLOCATE(X)
             ENDРис. 11. Фрагмент программы, иллюстрирующей работу с динамическими массивами
5. Распределение витков параллельного цикла. 
Директива PARALLEL
   Параллельный цикл в модели DVMH рассматривается как массив витков цикла. Количество измерений такого массива равно количеству заголовков параллельного цикла. Размер каждого измерения определяется параметрами соответствующего заголовка цикла. Чтобы такое представление было правильным, необходимо выполнение следующих условий: 
* заголовки параллельного цикла не должны разделяться другими операторами (тесно-гнездовой цикл);
* параметры заголовков параллельного цикла не должны изменяться в процессе выполнения цикла (прямоугольное индексное пространство);
* виток цикла должен быть неделимым объектом и выполняться на одном процессоре. Поэтому левые части операторов присваивания одного витка цикла должны быть распределены на один процессор (согласование с правилом собственных вычислений);
* распределенные измерения массивов индексируются только регулярными выражениями типа a*I + b , где I – индекс цикла;
* левая часть оператора присваивания является ссылкой на распределенный массив, редукционную переменную (см. раздел 6.5) или переменную, описанную в теле цикла;
* в теле цикла нет DVMН-директив.
     Распределение витков параллельного цикла осуществляется следующей директивой:
!DVM$  PARALLEL ( I1 ,… In )  ON  A ( e1,… em ),
где:
Ij – переменная (индекс) j-го заголовка параллельного цикла,
n – количество заголовков цикла,
A – идентификатор массива,
m – количество измерений массива,
ei=a* Ik+b,  a, b – целочисленные переменные, Ik – переменная (индекс) k-го заголовка цикла.
Это выражение означает следующее:
* k-е измерение (заголовок цикла) массива витков цикла ставится в соответствие i-му измерению массива данных,
* соответствие витка цикла и элемента массива устанавливается линейной функцией a* Ik+b.
   Директива PARALLEL каждый виток параллельного цикла ставит в соответствие некоторому элементу массива. Это означает, что виток цикла будет выполняться на том процессоре, на который распределен соответствующий элемент массива. По семантике директива PARALLEL аналогична директиве ALIGN. Отличием является то, что вместо выравниваемого массива данных используется массив витков параллельного цикла.
   Фрагмент программы на рис. 12 иллюстрирует использование директивы PARALLEL для распределения витков цикла.
!DVM$ PARALLEL  ( I)  ON  B( I)
              DO  I =1, N
                   B(I) =  A(I)+C(I)
             ENDDOРис. 12. Фрагмент программы, иллюстрирующей использование директивы PARALLEL
   Отсутствие директивы PARALLEL перед циклом, в котором вычисляются значения распределенных массивов, может существенно снизить эффективность работы программы. Если перед циклом есть директива PARALLEL, то каждый процессор выполняет только ту порцию итераций, которая предписана директивой. В данном случае компилятор не вставляет никаких проверок на принадлежность вычисляемого элемента данному процессору.
   Если перед циклом нет директивы PARALLEL, то данный цикл будет выполняться всеми процессорами по правилу собственных вычислений. Если массив В не является распределенным, то он размножен по все процессорам, и все процессоры выполнят весь цикл полностью от первой итерации до последней. Если массив B является распределенным, то каждый процессор выполнит только те итерации, для которых элементы B(I) распределены именно на этот процессор. Для соблюдения правила собственных вычислений перед каждым оператором компилятор автоматически вставит дополнительную проверку. За счет этого эффективность работы программы будет снижена.
   Таким образом, если в цикле есть вычисления значений элементов распределенных массивов, то для получения эффективной программы целесообразно перед циклом вставить директиву PARALLEL и обеспечить распределение левых частей операторов присваивания на одном процессоре.
   Фрагмент программы на рис. 13 иллюстрирует использование директивы PARALLEL для распределения вычислений элементов двух массивов.
!DVM$ PARALLEL  ( I, J )  ON  A( I, J)
              DO  I = 1, N
                 DO  J = 1, M-1
                       A(I,J) = …
                       B(I,J) = …
                 ENDDO
             ENDDOРис. 13. Фрагмент программы, иллюстрирующей использование директивы PARALLEL
   Для того чтобы левые части операторов присваивания одного витка цикла были распределены на одном процессоре, необходимо к описанию массива В применить следующую директиву:
!DVM$   ALIGN  B( I,J )  WITH A( I,J ).
   Если невозможно разместить левые части операторов присваивания на одном процессоре, то цикл необходимо разделить на несколько. Фрагмент программы на рис. 14 иллюстрирует такую ситуацию. Фрагмент программы на рис. 15 иллюстрирует возможность разделения цикла на два цикла, каждый из которых можно объявить параллельным. Цикл разделен на два цикла, каждый из которых удовлетворяет условию параллельного цикла.
  DO I = 1,N
         A(2*I) =...
         B(3*I) =...
     ENDDOРис. 14. Фрагмент программы с циклом, не удовлетворяющим условию параллельного цикла
!DVM$ PARALLEL (I) ON A(2*I)
              DO I =1,N
                   A(2*I) =...
             ENDDO
!DVM$ PARALLEL(I) ON B(3*I)
             DO I =1,N
                  B(3*I )=...
            ENDDOРис. 15. Фрагмент программы, иллюстрирующий разделение цикла
   Если в параллельном цикле используются приватные переменные, то в директиве PARALLEL необходимо указать дополнительную спецификацию PRIVATE, см. рис. 16.
   Если в цикле несколько приватных переменных, то они должны быть перечислены через запятую в круглых скобках после ключевого слова PRIVATE.
   Переменная называется приватной, если ее использование локализовано в пределах одного витка цикла.
   Индексы параллельного цикла, указанные в директиве PARALLEL, считаются приватными по умолчанию.
   Приватные переменные не могут быть распределенными массивами. Значение приватной переменной не определено в начале витка цикла и не используется после витка цикла, поэтому в каждом витке цикла может использоваться свой экземпляр приватной переменной.
!DVM$ PARALLEL  ( I, J )  ON  A( I, J ) , PRIVATE ( X )
              DO  I =1,N
                  DO  J =1,N
                        X = B(I,J) + C(I,J)
                        A(I,J) = X
                  ENDDO
              ENDDOРис. 16. Фрагмент программы, иллюстрирующий использование приватной переменной
6.  Удаленные данные.  Их виды и спецификация
   Данные, которые вычисляются на одном процессоре, а используются на других, называются удаленными.
   Удаленные данные определяются с помощью анализа операторов присваивания. Оператор присваивания всегда выполняется на том процессоре, где размещены данные его левой части. Если данные левой и правой частей оператора присваивания размещены на одном процессоре, то удаленных данных для этого оператора не будет. В противном случае необходимо определить вид и размер удаленных данных и описать их соответствующими директивами. Такой анализ будем называть анализом локализации данных.
   Цель распараллеливания – максимальный параллелизм при минимизации удаленных данных (максимум локализации).
   На предмет наличия удаленных данных достаточно анализировать только распределенные измерения массивов. Локальные измерения полностью распределены на каждом процессоре, и по этим измерениям не существует удаленных данных. Каждое распределенное измерение, по которому существуют удаленные данные, должно быть учтено при спецификации удаленных данных.
   Фрагмент программы на рис. 17 будет использован для демонстрации основных способов локализации данных и спецификации удаленных данных для одномерных массивов. Будет меняться состав выражения expr.
!DVM$ DISTRIBUTE A ( BLOCK)
              ...
!DVM$ PARALLEL (I) ON A(I)
              DO  I =1,N
                   A(I) = expr
              ENDDOРис. 17. Фрагмент программы для демонстрации способов локализации данных 
и спецификации удаленных данных
6.1. Локализация данных. Выравнивание по шаблону
   Пусть
     A( I ) = B( I ) + C( I ).
   Если A( I ), B( I ) и C( I ) для каждого I распределены на одном процессоре, то для этого оператора не существует удаленных данных. Локализацию данных можно выполнить директивами ALIGN (см. рис. 18).
!DVM$ ALIGN B(I,J) WITH  A(I,J)
!DVM$ ALIGN C(I,J) WITH  A(I,J)Рис. 18. Локализация данных при помощи директивы ALIGN
   Пусть
     A( I ) = B( I+d1 ) + C( I-d2 ),
где d1, d2 – положительные константы.
   Для этого оператора невозможно выполнить полную локализацию данных, используя массив A, т.к. смещения +d1 и -d2 выводят за пределы индексного пространства массива A. В этом случае необходимо определить фиктивный массив (например, TABC) – шаблон выравнивания следующей директивой:
!DVM$ TEMPLATE TABC(N+d1+d2).
   На рис. 19 перечислены директивы, необходимые для выравнивания массивов A,B,C по шаблону и распределения шаблона.
!DVM$ TEMPLATE   TABC( N+d1+d2 )
!DVM$ ALIGN B(I) WITH TABC(I)
!DVM$ ALIGN A(I) WITH TABC(I +d2)
!DVM$ ALIGN C(I) WITH TABC(I +d1+d2)
!DVM$ DISTRIBUTE TABC(BLOCK )Рис. 19. Выравнивание данных по шаблону
   В этом случае A( I ), B( I+d1 ) и C( I-d2 ) для каждого I будут распределены на один процессор. Шаблон TABC определяет некоторое индексное пространство, которое является посредником между массивом данных и массивом виртуальных процессоров. Элементы шаблона не имеют физического представления в памяти. Они указывают процессоры, на которые должны быть распределены соответствующие элементы массивов данных.
              REAL  A(10),  B(10),  C(10)
!DVM$ TEMPLATE  TABC ( 15 )
!DVM$ ALIGN B( I )  WITH  TABC( I )
!DVM$ ALIGN A( I )  WITH  TABC( I + 1 )
!DVM$ ALIGN C( I )  WITH  TABC( I + 5)
!DVM$ DISTRIBUTE TABC ( BLOCK )
              DO   I =5,9
                    A(I)= C(I-4)+ B(I+1)
             ENDDOРис. 20. Фрагмент программы, иллюстрирующий выравнивание по шаблону
   Фрагмент программы на рис. 20 иллюстрирует использование шаблона для выравнивания массивов. На рис. 21 показано распределение элементов массива при использовании шаблона.
Процессор 1Процессор 2Процессор 3Процессор 4TABC123456789101112131415B12345678910A123456789101112131415С12345678910Рис. 21. Распределение по процессорам при использовании выравнивания по шаблону
6.2. Удаленные данные вида SHADOW
   Пусть
   A( I ) = B( I-d1 ) + B( I+d2 ).
   В этом случае невозможна полная локализация данных. Тем не менее необходимо выполнить частичную локализацию данных с помощью директивы
!DVM$  ALIGN B( I )  WITH  A( I ).
   После выполнения этой директивы точно определяется местонахождение удаленных данных. Для вычисления всех A(I) на одном процессоре будут использоваться d1 элементов массива B с процессора, на котором располагаются элементы массива, с меньшими индексами и d2 – с большими индексами. Такие данные будем называть удаленными данными типа SHADOW (теневыми гранями).
   Для спецификации размера теневых граней служит директива SHADOW:
!DVM$  SHADOW  B( d1:d2 ) 
   В зависимости от выравнивания данных между массивами А и В ширина теневой грани будет разной. Если выравнивание описано директивой:
!DVM$  ALIGN B(I) WITH A(I+d2),
то директива для спецификации удаленных данных будет выглядеть так:
!DVM$  SHADOW  B( d1+d2:0).
   Для нескольких массивов (A1, A2,…) с одинаковыми размерами теневых граней можно использовать директиву вида
!DVM$  SHADOW ( d1:d2 )  ::  A1, A2, …
   По умолчанию размер теневых граней равен 1.
   В каждом параллельном цикле, где используются удаленные данные типа SHADOW массива B, в директиве PARALLEL необходимо указать дополнительную спецификацию:
!DVM$ PARALLEL  ( I )  ON  A ( I ),  SHADOW_RENEW ( B )
6.3. Удаленные данные вида ACROSS
   Пусть
   A(I) = A(I-d1) + A(I+d2).
   Как и в предыдущем разделе, необходимо описать размер удаленных данных директивой:
!DVM$ SHADOW  A( d1:d2 ).
   Но в директиве PARALLEL добавляется спецификация ACROSS:
!DVM$ PARALLEL  ( I )  ON  A ( I ),  ACROSS ( A(d1:d2) ) 
   Отличие данных типа ACROSS от данных типа SHADOW заключается в следующем: невозможно независимое выполнение витков цикла, т.к. прежде чем вычислить A(I), необходимо вычислить A(I-d1). В спецификации ACROSS перечисляются все распределенные массивы, по которым существует регулярная зависимость по данным.
6.4. Удаленные данные вида REMOTE
   Пусть
   A(I) = C(5) + C(I+N),
где C – распределенный массив.
   В этом случае в директиве PARALLEL необходимо указать следующую спецификацию REMOTE_ACCESS:
!DVM$ PARALLEL ( I )  ON  A ( I ),REMOTE_ACCESS ( C( 5 ), C( I+N ) )
   Если вне параллельного цикла встречается оператор
   A(I)=C(2)
или
   A(I)=C(N),
то перед такими операторами нужно указать директивы:
!DVM$ REMOTE_ACCESS ( C( 2) )
или
!DVM$ REMOTE_ACCESS ( C( N) ) 
соответственно.
6.5. Удаленные данные вида REDUCTION
   Пусть в цикле вычисляются:
   A(I) = B(I) + C(I)
   S = S + A(I)
   Для первого оператора необходимо локализовать данные как в разделе 4.2. Для второго оператора в директиве PARALLEL необходимо указать спецификацию REDUCTION:
!DVM$ PARALLEL  ( I )  ON  A ( I ), REDUCTION (SUM(S)),
где:
SUM – имя редукционной операции суммирования,
S        – редукционная переменная.
   К редукционным операциям относятся: SUM, PRODUCT, AND, OR, MAX, MIN, EQV, NEQV, MAXLOC, MINLOC.
7. Определение регионов для выполнения на ускорителях
   Вычислительный регион выделяет часть программы (с одним входом и одним выходом) для возможного выполнения на одном или нескольких вычислительных устройствах.
   Регион задается парой директив, отмечающих начало и конец региона, и имеет вид 
!DVM$ REGION [список_спецификаций]
&lt;содержимое региона&gt;
!DVM$ END  REGION 
   Содержимое региона – часть программы, содержащая произвольное количество параллельных циклов, возможно разделенных последовательными группами операторов (блоками операторов). Регион может быть пустым.
   В списке_спецификаций в директиве REGION при необходимости задается информация о направлении использования данных в регионе: входные, выходные, локальные и список вычислителей, на которых предполагается выполнять регион.
   Спецификации следуют за словом REGION и разделяются между собой запятыми. Данные – скалярные переменные, массивы, секции массивов –задаются после имени спецификации в круглых скобках через запятую.
   В качестве спецификаций данных может быть указано:
IN–входные данные: в регионе должны быть самые последние значения этих данных;OUT–выходные данные: значения указанных переменных в регионе изменяются и могут быть использованы далее;LOCAL–локальные данные: значения указанных переменных в регионе изменяются, но эти изменения не будут использованы далее;INOUT–сокращенная запись одновременно двух спецификаций IN и OUT;INLOCAL–сокращенная запись одновременно двух спецификаций IN и LOCAL.   Возможна запись IN(A,B) и IN(A), IN(B).
   Индексы секции массива записываются через запятую, например, IN(s(1:5,2:6)). Допускаются составные указания, например, OUT(s(1:5)), OUT (s(7:10)) или IN(s(1:5)), OUT(s(6:10)) и пересекающиеся указания, например, OUT(s(1:6)), OUT(s(3:10)) или даже OUT (s(1:6)), OUT(s(3:5)).
   Не допускаются конфликтующие указания, такие как OUT(v), LOCAL (v).
   Для используемых в регионе, но не указанных в спецификациях переменных действуют следующие правила по умолчанию:
* все используемые массивы считаются используемыми полностью (секции не выделяются);
* всякая переменная, которая используется на чтение, получает атрибут IN;
* всякая переменная, которая используется на запись, получает атрибут INOUT;
* всякая переменная, направление использования которой не поддаётся определению, получает атрибут INOUT;
* атрибуты LOCAL и OUT автоматически не проставляются.
   Если для переменной указано только направление IN (не указано OUT или LOCAL), это означает, что в такую переменную в регионе вообще нет записей и она не меняется в процессе его выполнения.
   Фрагмент программы на рис. 22 иллюстрирует описание региона со списком спецификаций.
!DVM$ REGION   IN  ( B, C ),  OUT ( A ) 
!DVM$ PARALLEL  ( I, J )  ON  A( I, J)
              DO  I =1, N
                DO  J =1, N
                     A(I,J)= B(I,J)+ C(I,J)
                ENDDO
              ENDDO
!DVM$ END REGIONРис. 22. Описание региона со списком спецификаций
   Для указания списка типов вычислителей, на которых предполагается выполнять регион, предназначена спецификация TARGETS. В текущей реализации target-name в спецификации TARGETS может принимать только два значения: 
CUDA – регион предполагается выполнять на CUDA-устройстве; 
HOST – регион предполагается выполнять на мультипроцессоре. 
   Данная спецификация ограничивает набор типов вычислительных устройств, для использования которых регион будет подготовлен компилятором. Действительное же выполнение региона может происходить только на доступных DVMH-программе ускорителях (или на ЦПУ), количество и типы которых указываются при ее запуске с помощью переменных окружения.  Фрагменты программы вне регионов выполняются на  мультипроцессоре.
   DVMH-массивы распределяются между вычислителями, нераспределенные данные размножаются. Витки параллельных DVMH-циклов внутри региона делятся между вычислителями в соответствии с правилом отображения параллельного цикла, заданного в директиве параллельного цикла.
   Каждый оператор последовательной группы операторов выполняется на всех вычислителях, кроме случая модификации в нем распределенных данных – тогда действует правило собственных вычислений.
Ограничения:
* Вложенные регионы не допускаются.
* При выполнении на CUDA-устройстве в регионе не должно быть операций ввода-вывода.
* В регионе не должно быть операторов ALLOCATE и DEALLOCATE.
* В регионе не должно быть операторов перехода за границу региона.
* Среди последовательной группы операторов не должно быть операторов перехода за границу группы.
* В регионе запрещены операторы условного и безусловного перехода для обхода выполнения параллельных циклов, все параллельные циклы региона должны выполняться.
7.1. Параллельный цикл в регионе
   Параллельный цикл – важнейшая составная часть вычислительного региона. 
   В параллельном цикле, входящем в регион, может быть задана дополнительная спецификация CUDA_BLOCK, в которой указывается размер блока нитей CUDA-устройства. Если указано целочисленное выражение, тогда блок полагается одномерным. Могут указываться два или три целочисленных выражения через запятую, соответственно, блок будет полагаться имеющим указанную размерность.
   Витки параллельного цикла внутри региона делятся между вычислителями в соответствии с правилом отображения параллельного цикла, заданного в директиве PARALLEL.
7.2. Блок операторов
   Каждый оператор блока исполняется на всех вычислителях, выбранных для выполнения региона, кроме случая модификации в нем распределенных данных – тогда действует правило собственных вычислений.
Ограничение:
Среди операторов блока не должно быть операторов перехода за его пределы.
7.3. Управление перемещением данных между памятью мультипроцессора и запоминающими устройствами ускорителей
   Вне вычислительных регионов управление перемещением данных между оперативной памятью ЦПУ и запоминающими устройствами ускорителей задается при помощи директив актуализации – GET_ACTUAL и ACTUAL.
   Директива GET_ACTUAL делает все необходимые обновления для того, чтобы в памяти ЦПУ были актуальные (т.е. самые новые) значения данных в указанных в списке переменных. В случае отсутствия параметров у директивы все данные в памяти ЦПУ становятся актуальными.
   Директива ACTUAL объявляет тот факт, что указанные в списке переменные имеют самые новые значения в памяти ЦПУ. Значения указанных переменных и элементов массивов, находящиеся в памяти ускорителей, считаются устаревшими и перед использованием будут при необходимости обновлены. В случае отсутствия параметров все данные считаются актуальными только в памяти ЦПУ.
   Использовать директивы ACTUAL и GET_ACTUAL без параметров не рекомендуется в силу повышения вероятности ошибок (ACTUAL), а также опасности излишних перемещений данных (GET_ACTUAL). Параметры директив – переменные – указываются в скобках через запятую.
   Фрагмент программы на рис. 23 иллюстрирует использование директив, управляющих перемещением данных между оперативной памятью ЦПУ и запоминающими устройствами ускорителей 
!DVM$ ACTUAL (B , C)
!DVM$ REGION IN B,C), OUT(A)
!DVM$ PARALLEL  (I,J )  ON  A(I,J)
             DO  I =1, N
               DO  J =1, N
                          A(I,J)= B(I,J)+ C(I,J)
               ENDDO
             ENDDO
!DVM$ END REGION
            . . .
!DVM$ GET_ACTUAL ( А )
              PRINT*, AРис. 23. Фрагмент программы, иллюстрирующий использование директив, управляющих    обновлением данных
8. Распределенные массивы в COMMON блоках и операторах EQUIVALENCE
   Массивы, не специфицированные директивами распределения данных, могут без ограничений использоваться в COMMON блоках и операторах EQUIVALENCE.
   Массивы, распределяемые директивами DISTRIBUTE и ALIGN, не могут использоваться в операторах EQUIVALENCE. Кроме того, эти массивы не могут ассоциироваться с другими объектами данных. Явно распределяемые массивы могут быть компонентами COMMON блока при следующих условиях:
* COMMON блок должен быть описан в главной программной единице.
* Каждое описание COMMON блока должно иметь одно и то же количество компонент, а соответствующие компоненты – последовательности памяти одинакового размера.
* Если компонентой COMMON блока является явно распределяемый массив, то объявления массива в разных программных единицах должны специфицировать один и тот же тип данных и одинаковую конфигурацию. Директивы DISTRIBUTE и ALIGN для этого массива должны иметь идентичные параметры.
  Пусть в главной программе (рис. 24) массив В распределен и используется в COMMON блоке.
              PROGRAM  MAIN
!DVM$ DISTRIBUTE  B ( *, BLOCK )
              COMMON/COM1/  X, Y(12), B(12,30)Рис. 24. Фрагмент программы, в которой распределенный массив используется 
в COMMON блоке
   Фрагмент программы на рис. 25 иллюстрирует правильное описание массива в подпрограмме.
                SUBROUTINE  SUB1
!DVM$ DISTRIBUTE  B1 ( *, BLOCK )
                COMMON/COM1/  X, Y(12), B1(12,30)Рис. 25. Фрагмент программы, иллюстрирующий правильное описание массива
   Фрагменты  программ на рис. 26, 27, 28 демонстрируют варианты ошибок в описании массивов.
              SUBROUTINE  SUB2
!DVM$ DISTRIBUTE  B2 ( *, BLOCK)
              COMMON/COM1/  X, Y(12), Z, B2(12,30)Рис. 26. Длина COMMON блока в подпрограмме отличается от длины COMMON блока в главной программе


              SUBROUTINE  SUB3
!DVM$ DISTRIBUTE  B3 ( BLOCK, BLOCK )
              COMMON/COM1/  X, Y(12), B3(12,30)Рис. 27. Распределение массива в подпрограмме отличается от распределения 
в главной программе
SUBROUTINE  SUB4
!DVM$DISTRIBUTE  B4 ( *, BLOCK )
COMMON/COM1/  X, Y(12), B4(30,12)Рис. 28. Конфигурация массива в подпрограмме отличается от конфигурации 
в главной программе
9. Процедуры в параллельной программе
9.1. Вызов процедуры из параллельного цикла
   Процедура, вызываемая из параллельного цикла, не должна иметь побочных эффектов и содержать обменов между процессорами (прозрачная процедура). Как следствие этого, прозрачная процедура не содержит:
* операторов ввода-вывода;
* директив FDVM;
* присваивания значений переменным COMMON блоков.
9.2. Вызов процедуры вне параллельного цикла
   Если фактическим аргументом является явно распределенный массив (DISTRIBUTE или ALIGN), то он должен передаваться без изменения формы. Это означает, что фактический аргумент является ссылкой на начало массива, а соответствующий формальный аргумент имеет конфигурацию, полностью совпадающую с конфигурацией фактического аргумента.
9.3. Формальные аргументы
   Если фактический аргумент является распределенным массивом, то соответствующий формальный аргумент должен иметь явное или наследуемое распределение.
   Явное распределение описывается директивами DISTRIBUTE и ALIGN со следующим ограничением: формальный аргумент может быть выровнен только на другой формальный аргумент или шаблон с атрибутом COMMON. Явное распределение формального аргумента означает, что пользователь должен перед вызовом процедуры обеспечить распределение фактического аргумента в точном соответствии с распределением формального аргумента.
   Наследуемое распределение массива С (формального аргумента) описывается директивой:
!DVM$  INHERIT C
   Наследуемое распределение означает, что формальный аргумент наследует распределение фактического аргумента при каждом вызове процедуры. Наследуемое распределение не требует от пользователя распределять фактический аргумент в соответствии с формальным аргументом.
   Директивы REDISTRIBUTE и REALIGN могут применяться к формальным аргументам, если фактический и формальный аргументы имеют атрибут DYNAMIC.
9.4. Локальные массивы
   Локальные массивы могут распределяться в процедуре директивами DISTRIBUTE и ALIGN. Локальный массив может быть выровнен на формальный аргумент. 
   Особым случаем является распределенный локальный массив с атрибутом SAVE. Для этого массива должны выполняться следующие условия:
* Директива DISTRIBUTE или ALIGN имеет идентичные параметры при каждом вызове процедуры.
* Массив не может использоваться в директивах REDISTRIBUTE и REALIGN.
   Фрагмент программы на рис. 29 иллюстрирует распределение локальных массивов и формальных аргументов.
             SUBROUTINE  DIST( A, B, C, N )
             DIMENSION  A(N,N), B(N,N), C(N,N), X(N,N), Y(N,N)
!явное распределение формального аргумента
!DVM$ DISTRIBUTE  A ( *, BLOCK )
!выравниваемый формальный аргумент
!DVM$ ALIGNB( I, J )  WITHA( I, J )
!наследуемое распределение формального аргумента
!DVM$ INHERIT  C
!выравнивание локального массива на формальный аргумент
!DVM$ ALIGN  X( I, J )  WITH  C( I, J )
! распределение локального массива
!DVM$ DISTRIBUTE  Y ( *, BLOCK )
            . . .
            ENDРис. 29. Фрагмент программы, иллюстрирующий распределение локальных массивов и формальных аргументов
10. Ввод-вывод
10.1. Последовательный ввод-вывод
   Операторы ввода-вывода, осуществляющие передачу данных, управление и другие вспомогательные операции с внешним файлом, выполняются на одном процессоре (процессоре ввода-вывода), специально выделяемом для этой цели системой поддержки выполнения DVMH-программы.
   Операция ввода-вывода размноженной переменной производится над копией переменной, размещенной на процессоре ввода-вывода. Введенное значение рассылается остальным процессорам. 
   Ввод-вывод распределенного массива реализуется с помощью буфера, размещенного на процессоре ввода-вывода. При вводе данные из внешнего файла передаются в буфер, а затем рассылаются тем процессорам, на которые распределен массив. Когда распределенный массив выводится, данные с процессоров, где локализованы элементы массива, сначала пересылаются в буфер, а из буфера передаются во внешний файл.
   Для ввода-вывода распределенных массивов разрешается использовать операторы, удовлетворяющие следующим требованиям:
* Список ввода-вывода должен состоять только из одного имени распределенного массива и не может содержать других объектов ввода-вывода.
* В операторах ввода-вывода по формату допускается только формат, задаваемый *.
* В списке управляющей информации можно использовать только размноженные переменные.
   При вводе размноженного массива неопределенного размера с помощью неявного цикла следует явно задать границы последнего измерения, т.е. использовать следующую форму: (A(i1,i2,...,I), I = n1,n2).
10.2. Параллельный ввод-вывод
   Поддерживаются два режима открытия файла: как локальный файл или как параллельный файл.
   Локальный файл открывается каждым процессором самостоятельно. Операция открытия (OPEN) локального файла приведет к открытию N файлов (где N – кол-во процессоров в текущей многопроцессорной системе). Все операции над локальными файлами обрабатываются каждым процессором независимо и никаких коммуникаций не вызывают.
   При чтении (записи) распределенного массива из локального файла, читается (записывается) только локальная часть распределенного массива. Тем самым работа с такими файлами является достаточно удобным средством параллельного ввода-вывода распределенных данных, однако требует совпадения распределений при записи файлов и при их последующем чтении.
   Параллельный файл открывается каждым процессором и привязывается к текущей многопроцессорной системе. Такой режим сохраняет содержимое файла таким же, как если бы он записывался последовательной программой, а также позволяет читать файлы, записанные программой, работавшей на любом количестве процессов (в том числе исходной последовательной).
10.3. Асинхронный режим
   Асинхронный режим открытия файла позволяет продолжать выполнять программу до завершения операции ввода-вывода.
   Такой режим может быть задан и для локального файла, и для параллельного, и для последовательного.
   Все операции над одним файлом выполняются последовательно. Операции над разными файлами могут перекрываться (выполняться разными нитями ввода-вывода). Любая не допускающая асинхронного выполнения операция приводит к ожиданию всех асинхронных операций над соответствующим файлом перед началом выполнения синхронной операции.
10.4. Директива IO_MODE
   Для задания режима выполнения ввода-вывода служит директива:
!DVM$ IO_MODE [список_спецификаций].
   В списке_спецификаций могут быть перечислены: PARALLEL, LOCAL, ASYNC.
Ограничения: 
* Допускаются только сочетания PARALLEL с ASYNC и LOCAL с ASYNC.
* Разрешен только бесформатный ввод-вывод для локального и параллельного файла.
* Возможен только потоковый метод доступа (ACCESS=’STREAM’) к данным локального и параллельного файла.
   Данную директиву следует указывать непосредственно перед оператором открытия файла (OPEN), она управляет выполнением всех операций ввода-вывода в этот файл. По умолчанию действует последовательный режим. 
   Фрагмент программы на рис. 30 иллюстрирует использование директивы IO_MODE.
!DVM$ IO_MODE  ( LOCAL )
             OPEN(3,FILE='JACOBI.DAT',FORM='UNFORMATTED',*ACCESS=’STREAM’)
             WRITE(3)   A, BРис. 30. Фрагмент программы, иллюстрирующий использование директивы
11. Компиляция и выполнение DVMH-программ на кластере с ускорителями
   Для компиляции и запуска на выполнение DVMH-программы в рабочую директорию, в которой она находится, необходимо скопировать файл запуска dvm-команд (dvm) из директории &lt;path-to-dvm&gt;/user, где &lt;path-to-dvm&gt; – путь до директории с установленной DVM системой.
   DVMH-программа – это один или несколько файлов с исходными текстами на языке FDVMH, имеющих расширение fdv, f, for, f90. Если файлы имеют расширение f90, то считается, что они в свободной форме, иначе при помощи опции компиляции (-FI) необходимо указать, что форма записи является фиксированной. При компиляции нужно указать опцию -f90, если файлы имеют расширение fdv, f, for, но записаны в свободной форме. 
   Если среди файлов есть программная единица-модуль, то файлы необходимо объединить в единую программу при помощи INCLUDE.
   Компиляция и выполнение DVMH-программ осуществляется при помощи следующих команд:
dvm f [&lt;опции компиляции&gt;]&lt;имя DVMH-программы&gt;
dvm run [N1[N2[N3[N4]]]] &lt;имя выполняемого файла DVMH-программы&gt;
где N1, N2, N3, N4 ? размеры матрицы процессоров (по умолчанию  – 1 1 1 1).
   В случае успешной компиляции будет создан выполняемый файл параллельной программы для выполнения на кластере с ускорителями. Количество CUDA-устройств для использования одним процессом и количество нитей, работающих на ЦПУ, можно задать при помощи переменных окружения DVMH_NUM_CUDAS и DVMH_NUM_THREADS. Переменные окружения могут быть заданы в файле dvm. Если переменная не задана, то ее оптимальное значение определяет система поддержки. Система поддержки обеспечивает эффективное использование всех ресурсов узла.
   При наличии ошибок компиляции исполняемый файл не формируется, и выдаются сообщения о найденных ошибках.
   При запуске DVMH-программ размерность и размеры матрицы виртуальных процессоров определяют конфигурацию и число процессов (N1*N2*N3*N4), на которых DVMH-программа будет выполняться параллельно. Количество форматов BLOCK определяет количество измерений массива виртуальных процессоров. Таким образом, если у массива одно распределенное измерение, то нужно указать N1, если два – N1,N2, если три – N1,N2,N3 и т.д. При этом значения N1, N2, N3, N4 определяют число процессоров, на которые будут распределены элементы соответствующего измерения.
   Полное описание переменных окружения для DVMH-программ и опций компиляции приведено в Приложении 1 и Приложении 2 документа [3].
Приложение 1. Пример программы Якоби 
на языке FDVMH
              PROGRAM    JAC 
              PARAMETER(L=8,  ITMAX=10)
              REAL     A(L,L), EPS, MAXEPS, B(L,L)
!DVM$ DISTRIBUTE     ( BLOCK,   BLOCK)   ::   A 
!DVM$ALIGN  B(I,J)  WITH  A(I,J) 
              PRINT*,'**********  TEST_JACOBI   **********'
              MAXEPS  =  0.5E – 7
!DVM$ REGION
!DVM$ PARALLEL    (J,I)   ON   A(I, J) 
              DO   J  =  1, L 
                  DO   I  =  1, L 
                           A(I,  J)=  0. 
                            IF (I.EQ.1 .OR. J.EQ.1 .OR. I.EQ.L .OR. J.EQ.L)THEN
                                 B(I,  J)= 0. 
                            ELSE
                                 B(I,  J)=( 1. + I + J )
                           ENDIF
                  ENDDO
              ENDDO
!DVM$ END REGION
              DO  IT  =  1,  ITMAX 
                    EPS  =  0. 
!DVM$      ACTUAL (EPS)
!DVM$      REGION
!DVM$      PARALLEL  (J,  I)   ON  A(I,  J),  REDUCTION ( MAX( EPS )) 
                    DO  J  =  2, L-1 
                        DO  I  =  2, L-1 
                               EPS =MAX( EPS,ABS( B( I, J)-  A( I, J)))
                               A(I, J)=  B(I, J)
                       ENDDO
                   ENDDO
!DVM$      PARALLEL  (J,  I)   ON  B(I,  J),  SHADOW_RENEW  (A)
                   DO  J = 2,  L-1
                         DO  I = 2,  L-1
                              B(I, J)=(A( I-1, J )+ A( I, J-1 )+ A( I+1, J)+ A( I, J+1 ))/ 4 
                         END DO
                   ENDDO
!DVM$      END REGION
!DVM$      GET_ACTUAL (EPS)
                   PRINT 200,  IT, EPS 
200             FORMAT(' IT = ',I4,'   EPS = ', E14.7)
                   IF( EPS . LT . MAXEPS ) EXIT
               ENDDO
!DVM$  GET_ACTUAL (B)
               OPEN(3,FILE='JAC.DAT',FORM='FORMATTED', STATUS='UNKNOWN')
               WRITE(3,*)  B
               CLOSE(3)
               END   


   В результате выполнения директивы
!DVM$ DISTRIBUTE (BLOCK, BLOCK) :: A
массив А будет распределен между вычислителями. Количество и тип используемых вычислителей задается при запуске программы с помощью переменных окружения и параметров командной строки.
   Директива
!DVM$ ALIGN B(I,J) WITH A(I,J)
задает совместное распределение двух массивов А и В. Элементы массива В будут распределены на тот же вычислитель, где будут размещены соответствующие элементы массива A.
   Директива
!DVM$ PARALLEL (J,I) ON A(I,J)
задает распределение вычислений. Витки цикла будут выполняться на том вычислителе, где распределены соответствующие элементы массива A.
   Спецификация REDUCTION (MAX(EPS)) организует эффективное выполнение редукционной операции – глобальной операции с расположенными на различных вычислителях данных (нахождение максимального значения).
   Спецификация SHADOW_RENEW (A) указывает на необходимость подкачки удаленных данных (теневых граней) с других вычислителей перед выполнением цикла. Поскольку никакие дополнительные спецификации в директивах REGION не заданы, компилятор определяет направления использования переменных автоматически – INOUT(A,B,EPS).
   При выполнении первого вычислительного региона (цикла инициализации) для распределенных частей массивов А и В на ускорителях будет выделена необходимая память.
   При входе во второй вычислительный регион (в итерационном цикле) осуществляется проверка, присутствуют ли актуальные представители для массивов А и В на вычислителе. Поскольку такие представители уже присутствуют, то никакие дополнительные операции копирования актуальных данных на вычислители не выполняются.
   При выходе из вычислительного региона обновление данных в памяти хоста не производится. Перед выводом массива в файл требуется скопировать последние изменения массива из памяти вычислителя при помощи директивы !DVM$  GET_ACTUAL (B). 

</text>
                <codes>
                    <udk>519.685</udk>
                    <edn>VRGQOT</edn>
                </codes>
                <keywords>
                    <kwdGroup lang="RUS">
                        <keyword>Fortran-DVMH</keyword>
                        <keyword>директивы</keyword>
                        <keyword>распределенные массивы</keyword>
                        <keyword>параллельные циклы</keyword>
                    </kwdGroup>
                    <kwdGroup lang="ENG">
                        <keyword>Fortran-DVMH</keyword>
                        <keyword>directives</keyword>
                        <keyword>distributed arrays</keyword>
                        <keyword>parallel loops</keyword>
                    </kwdGroup>
                </keywords>
                <references>
                    <reference>DVM-система [Электронный ресурс] - : [web-сайт] – DVM http://dvm-system.org/</reference>
                    <reference>Описание языка Fortran-DVMH. [Электронный ресурс] - : [web-сайт] – DVM http://dvm-system.org/static_data/docs/FDVMH-reference-ru.pdf/</reference>
                    <reference>Компиляция, выполнение и отладка DVMH-программ. [Электронный ресурс] -: [web-сайт] – DVM http://dvm-system.org/static_data/docs/FDVMH-user-guide-ru.pdf</reference>
                </references>
                <files>
                    <furl>https://keldysh.ru/papers/2025/prep2025_76.pdf</furl>
                </files>
            </article>
        </articles>
    </issue>
</journal>
