Программирование больших вычислительных задач на современном Фортране с использованием компиляторов Intel

Создание параллельных программ

Разбить на страницы
Показывать лекцию целиком

Презентацию к лекции Вы можете скачать здесь.

Возможности

  • Автопараллелизация.
  • Использование директив.
  • Языковые средства.
  • CoArray для систем с распределенной памятью.
  • Библиотеки MPI для систем с распределенной памятью.
  • OpenMP для систем с общей памятью.
  • Использование библиотек Intel-MKL.
  • Сервис Intel Advisor, Intel Inspector.
  • Автопараллелизация

    Auto-parallelization функция компилятора Intel® автоматически переводящая последовательные части программы в эквивалентный многопоточный код.

    Последовательный код

    subroutine serial(a, b, c)
      integer, dimension(100) :: a, b, c
      do i = 1,100
        a(i) = a(i) + b(i) * c(i)
      enddo
    end subroutine serial
        

    Параллельный код

    subroutine sub_par(a, b, c)
      integer, dimension(100) :: a, b, c
    
      do i = 1,50 ! поток 1
        a(i) = a(i) + b(i) * c(i)
      end do
    
      do i = 51,100 ! поток 2
        a(i) = a(i) + b(i) * c(i)
      end do
    end subroutine par
        

    Критерии параллелизации цикла

  • Вычисляемость количества итераций цикла во время компиляции.
    do 
       ! вычисления
       if (условие) exit
    end do
          
  • Отсутствие зависимостей по данным:
  • потоковой (FLOW, READ after WRITE)
  • антизависимости (ANTI, WRITE after READ)
  • выходной (OUTPUT, WRITE after WRITE)
  • Директивы

    Директива !DEC$ PARALLEL приводит к параллельному выполнению цикла.

    Следим за зависимостью данных, ответственность на разработчике!
    !DEC$ PARALLEL [ALWAYS]
        

    выполнять параллельно, даже если это противоречит "решению" компилятора.

    !DEC$ PARALLEL [ALWAYS [ASSERT]]
        

    выдавать сообщение о невозможности распараллеливания цикла

    !DEC$ NOPARALLEL
        

    отмена автопараллелизации

    Пример использование директив !DEC$ PARALLEL, !DEC$ NOPARALLEL

    program prog
      integer, parameter :: n = 100
      integer x(n),a(n) 
    
      !DEC$ NOPARALLEL
      do i = 1,n
        x(i) = i
      end do 
    
      !DEC$ PARALLEL
      do i = 1,n
        a( x(i) ) = i
      end do
    end
        

    DO CONCURRENT

    Организация параллельного выполнения цикла. Не должно быть зависимости по данным.

    real  Q
       do concurrent (k = 1:N)
          Q = B(k) + C(k)
          D(k) = Q + sin(Q) + 2
       end do
        

    COARRAY

    CAF (CoArray Fortran) середина 90-х годов

    Поддержка компанией Cray. Центр развития – Rice University

    Модель PGAS (Partitioned Global Address Space) разделённое глобальное адресное пространство.

    Глобальная адресуемая память представлена логическими разделами. У каждого процессора свой раздел.

    Цели

  • Простое расширение Fortran и чувствовать, как Fortran, а не как что-то другое.
  • Небольшие требования к разработчикам.
  • Очевидность локальности или удаленности ссылки.
  • Обеспечение возможности для оптимизации связей.
  • Легкая читаемость кода.
  • Модель программирования

    Архитектура SPMD "Single program multiple data" ("Одна программа - много данных")

    Создаётся один экземпляр программы, который затем копируется несколько раз. Каждая копия выполняется параллельно, обрабатывает свои локальные данные.

    Данные распределенные между копиями программы объявляются как coarray переменные.

    Подключение

    В свойствах проекта указать использование Coarrays, при необходимости Coarray Images.

    Images

    Image - копия CAF - программы.

    Функция num_images() возвращает количество созданных копий программы.

    Количество копий программы как правило соответствует количеству имеющихся процессоров. В общем случае устанавливается в настройках проекта.

    Каждая копия имеет свой уникальный номер, возвращаемый функцией this_image().

    COARRAY - переменные

    Данные распределенные между images объявляются как coarray переменные.

    тип имя [*]

    integer A[*] ! A[1] – переменная A 
                 !        в копии № 1
                 ! A[2] – переменная A 
                          в копии № 2
            
    real С(N)[-1:*] ! С(N)[-1] – массив С
                    !         в копии № 1
                    ! С(N)[0]  – массив С
                    !         в копии № 2
            
    complex     Y(50)[1:10,1:*]
    type (matrix)   MS[*] 
    real, allocatable :: W(:)[:]
            

    Пересылка данных – обращение к элементам coarrays.

    complex C(100,100)[*]
            

    Объявление копии массива для всех images.

    C(1:10,30:50)[2] = C(21:30,90:100)[3]
            

    Пересылка сечения массива из 3-й копии во 2-ю.

    Если без скобок то обращение к локальному, т.е. в первой копии программы пересылка массива А в k-ю копию A[k] = A равносильно A[k] = A[1]

    Для определения номера копии программы по индексам coarray используется функция image_index().

    program CAF
      complex Y(50)[1,1:*]
    
      if (this_image() == 1) then ! == 2
        write(*,*) "This is ", this_image(),  
                   " copy of program "
    
        write(*,*) "Image index = ",  
                   image_index(Y, [1,this_image()])
    
        write(*,*) "Coordinates = ", this_image(Y)
        write(*,*)
      end if
            
     This is            1  copy of program
     Image index =            1
     Coordinates =            1           1
            

    Функция lcobound возвращает нижнюю границу coarray - переменной. Функция ucobound возвращает верхнюю границу coarray - переменной.

    type point
      integer x
      integer y
    end type point
    type (point) PS(10)[1,-2:*]
      ! num_images() = 4   ! 1   -2
      write(*,*) "LCOBOUND = ", LCOBOUND (PS)   
      write(*,*) "UCOBOUND = ", UCOBOUND (PS)    
                           ! 1    1
            

    Пример (1)

    Всем images установить значения переменных.

    Пример (2)

    Две копии программы рисующие разные случайные геометрические фигуры. Первая – прямоугольники, Вторая – окружности.

    Вариант программы

    program  prog2
      use ifqwin
      integer, parameter :: dx = 10, dy = 10
      do
        call random_number(x);  call random_number(y)
        call random_number(r);  call random_number(g)
        call random_number(b)
    
       ires2 = setcolorrgb(rgbtointeger(int(r*255),   
                                        int(g*255), 
                                        int(b*255)))
    
        if (this_image() == 1) ires2 = rectangle(3,int2(x*800), 
                    int2(y*600),int2(x*800)+dx, int2(y*600)+dy)
    
        if (this_image() == 2) ires2 = ellipse(3,int2(x*800),   
                    int2(y*600),int2(x*800)+dx, int2(y*600)+dy)
      end do  
    end
            

    SYNC ALL

    Барьерная синхронизация. Копии программы приостанавливаются на барьере до тех пор, пока на барьере не окажутся все копии программы.

    program CAF
      integer, parameter :: M = 100
      real A(M,M)[*]
    
      if (this_image() == 1) then
        call random_number(A)
        A = real(int(A*10))
        do k = 2,num_images()  ! каждый узнал об изменении
          A[k] = A
        end  do
      end if
      sync all
    ...
        

    Пример SYNC ALL

     integer :: i, k1, k2
      integer(8) sum = 0, k[*]    ! k - coarray-переменная
    
      if (this_image() == 1) then ! --- план для вычислений
        k1 = 1; k2 = 100
      end if
    
      if (this_image() == 2) then
        k1 = 101; k2 = 100000
      end if
    
      do i = k1,k2 ! --- расчет каждой копией программы
        k[this_image()] = k[this_image()] + i
      end do
      SYNC ALL  ! дожидаемся всех, сколько каждая копия насчитала
        
      if (this_image() == 1) then ! --- сбор результатов 
        do i = 1,num_images() 
          sum = sum + k[i]
        end do
        write(*,*) sum    ! 5000050000
      end if 
    
    end
            

    SYNC IMAGES

    SYNC IMAGES(image_set)
        

    Синхронизация избранных копий программы,

    image_set – массив номеров копий программы или просто номер копии
    image_set(*) - означает все копии
    if (this_image() == 5) then
       ! image 5 ожидает других images, 
       ! чтобы завершить использование данных.
       sync images(*)
    else
       sync images(5) 
       ! Другие images ожидают image 5, 
       ! чтобы установить данные, 
       ! но не ожидают никакого другого image.
    end if
        

    CRITICAL

    critical
      ! операторы, выполняемые в любой момент
      ! времени только одной копией программы
    end critical
        
    program CAF
    implicit none
    
    complex Y(50)[1,1:*]
    
      write(*,*) "This is ", this_image(), " copy of program "
      write(*,*) "Image index = ", image_index(Y,[1,this_image()])
      write(*,*) "Coordinates = ", this_image(Y)
      write(*,*)
    
    end program CAF
        
    Результаты печати на экране "перепутаны"!
     This is            1  copy of program
     This is            2  copy of program
     Index =            2
     Coordinates =            1           2
    
     Index =            1
     Coordinates =            1           1
        
     This is            2  copy of program
     This is            1  copy of program
     Index =            2
     Coordinates =            1           2
    
     Index =            1
     Coordinates =            1           1
        
     This is            2  copy of program
     This is            1  copy of program
     Index =            1
     Coordinates =            1           1
    
     Index =            2
     Coordinates =            1           2
        

    Экран – критическая секция.

    program CAF
    implicit none
    
    complex Y(50)[1,1:*]
    critical
      write(*,*) "This is ", this_image(), " copy of program "
      write(*,*) "Image index = ", image_index(Y,[1,this_image()])
      write(*,*) "Coordinates = ", this_image(Y)
      write(*,*)
    end critical
    end program CAF
        
     This is            1  copy of program
     Image index =            1
     Coordinates =            1           1
    
     This is            2  copy of program
     Image index =            2
     Coordinates =            1           2
        

    Задания

    Написать программу нахождения максимума в одномерном массиве.

    Страницы:

    Презентацию к лекции Вы можете скачать здесь.

    Возможности

  • Автопараллелизация.
  • Использование директив.
  • Языковые средства.
  • CoArray для систем с распределенной памятью.
  • Библиотеки MPI для систем с распределенной памятью.
  • OpenMP для систем с общей памятью.
  • Использование библиотек Intel-MKL.
  • Сервис Intel Advisor, Intel Inspector.
  • Автопараллелизация

    Auto-parallelization функция компилятора Intel® автоматически переводящая последовательные части программы в эквивалентный многопоточный код.

    Последовательный код

    subroutine serial(a, b, c)
      integer, dimension(100) :: a, b, c
      do i = 1,100
        a(i) = a(i) + b(i) * c(i)
      enddo
    end subroutine serial
        

    Параллельный код

    subroutine sub_par(a, b, c)
      integer, dimension(100) :: a, b, c
    
      do i = 1,50 ! поток 1
        a(i) = a(i) + b(i) * c(i)
      end do
    
      do i = 51,100 ! поток 2
        a(i) = a(i) + b(i) * c(i)
      end do
    end subroutine par
        

    Критерии параллелизации цикла

  • Вычисляемость количества итераций цикла во время компиляции.
    do 
       ! вычисления
       if (условие) exit
    end do
          
  • Отсутствие зависимостей по данным:
  • потоковой (FLOW, READ after WRITE)
  • антизависимости (ANTI, WRITE after READ)
  • выходной (OUTPUT, WRITE after WRITE)
  • Директивы

    Директива !DEC$ PARALLEL приводит к параллельному выполнению цикла.

    Следим за зависимостью данных, ответственность на разработчике!
    !DEC$ PARALLEL [ALWAYS]
        

    выполнять параллельно, даже если это противоречит "решению" компилятора.

    !DEC$ PARALLEL [ALWAYS [ASSERT]]
        

    выдавать сообщение о невозможности распараллеливания цикла

    !DEC$ NOPARALLEL
        

    отмена автопараллелизации

    Пример использование директив !DEC$ PARALLEL, !DEC$ NOPARALLEL

    program prog
      integer, parameter :: n = 100
      integer x(n),a(n) 
    
      !DEC$ NOPARALLEL
      do i = 1,n
        x(i) = i
      end do 
    
      !DEC$ PARALLEL
      do i = 1,n
        a( x(i) ) = i
      end do
    end
        

    DO CONCURRENT

    Организация параллельного выполнения цикла. Не должно быть зависимости по данным.

    real  Q
       do concurrent (k = 1:N)
          Q = B(k) + C(k)
          D(k) = Q + sin(Q) + 2
       end do
        

    COARRAY

    CAF (CoArray Fortran) середина 90-х годов

    Поддержка компанией Cray. Центр развития – Rice University

    Модель PGAS (Partitioned Global Address Space) разделённое глобальное адресное пространство.

    Глобальная адресуемая память представлена логическими разделами. У каждого процессора свой раздел.

    Цели

  • Простое расширение Fortran и чувствовать, как Fortran, а не как что-то другое.
  • Небольшие требования к разработчикам.
  • Очевидность локальности или удаленности ссылки.
  • Обеспечение возможности для оптимизации связей.
  • Легкая читаемость кода.
  • Модель программирования

    Архитектура SPMD "Single program multiple data" ("Одна программа - много данных")

    Создаётся один экземпляр программы, который затем копируется несколько раз. Каждая копия выполняется параллельно, обрабатывает свои локальные данные.

    Данные распределенные между копиями программы объявляются как coarray переменные.

    Подключение

    В свойствах проекта указать использование Coarrays, при необходимости Coarray Images.

    Images

    Image - копия CAF - программы.

    Функция num_images() возвращает количество созданных копий программы.

    Количество копий программы как правило соответствует количеству имеющихся процессоров. В общем случае устанавливается в настройках проекта.

    Каждая копия имеет свой уникальный номер, возвращаемый функцией this_image().

    COARRAY - переменные

    Данные распределенные между images объявляются как coarray переменные.

    тип имя [*]

    integer A[*] ! A[1] – переменная A 
                 !        в копии № 1
                 ! A[2] – переменная A 
                          в копии № 2
            
    real С(N)[-1:*] ! С(N)[-1] – массив С
                    !         в копии № 1
                    ! С(N)[0]  – массив С
                    !         в копии № 2
            
    complex     Y(50)[1:10,1:*]
    type (matrix)   MS[*] 
    real, allocatable :: W(:)[:]
            

    Пересылка данных – обращение к элементам coarrays.

    complex C(100,100)[*]
            

    Объявление копии массива для всех images.

    C(1:10,30:50)[2] = C(21:30,90:100)[3]
            

    Пересылка сечения массива из 3-й копии во 2-ю.

    Если без скобок то обращение к локальному, т.е. в первой копии программы пересылка массива А в k-ю копию A[k] = A равносильно A[k] = A[1]

    Для определения номера копии программы по индексам coarray используется функция image_index().

    program CAF
      complex Y(50)[1,1:*]
    
      if (this_image() == 1) then ! == 2
        write(*,*) "This is ", this_image(),  
                   " copy of program "
    
        write(*,*) "Image index = ",  
                   image_index(Y, [1,this_image()])
    
        write(*,*) "Coordinates = ", this_image(Y)
        write(*,*)
      end if
            
     This is            1  copy of program
     Image index =            1
     Coordinates =            1           1
            

    Функция lcobound возвращает нижнюю границу coarray - переменной. Функция ucobound возвращает верхнюю границу coarray - переменной.

    type point
      integer x
      integer y
    end type point
    type (point) PS(10)[1,-2:*]
      ! num_images() = 4   ! 1   -2
      write(*,*) "LCOBOUND = ", LCOBOUND (PS)   
      write(*,*) "UCOBOUND = ", UCOBOUND (PS)    
                           ! 1    1
            

    Пример (1)

    Всем images установить значения переменных.

    Пример (2)

    Две копии программы рисующие разные случайные геометрические фигуры. Первая – прямоугольники, Вторая – окружности.

    Вариант программы

    program  prog2
      use ifqwin
      integer, parameter :: dx = 10, dy = 10
      do
        call random_number(x);  call random_number(y)
        call random_number(r);  call random_number(g)
        call random_number(b)
    
       ires2 = setcolorrgb(rgbtointeger(int(r*255),   
                                        int(g*255), 
                                        int(b*255)))
    
        if (this_image() == 1) ires2 = rectangle(3,int2(x*800), 
                    int2(y*600),int2(x*800)+dx, int2(y*600)+dy)
    
        if (this_image() == 2) ires2 = ellipse(3,int2(x*800),   
                    int2(y*600),int2(x*800)+dx, int2(y*600)+dy)
      end do  
    end
            

    SYNC ALL

    Барьерная синхронизация. Копии программы приостанавливаются на барьере до тех пор, пока на барьере не окажутся все копии программы.

    program CAF
      integer, parameter :: M = 100
      real A(M,M)[*]
    
      if (this_image() == 1) then
        call random_number(A)
        A = real(int(A*10))
        do k = 2,num_images()  ! каждый узнал об изменении
          A[k] = A
        end  do
      end if
      sync all
    ...
        

    Пример SYNC ALL

     integer :: i, k1, k2
      integer(8) sum = 0, k[*]    ! k - coarray-переменная
    
      if (this_image() == 1) then ! --- план для вычислений
        k1 = 1; k2 = 100
      end if
    
      if (this_image() == 2) then
        k1 = 101; k2 = 100000
      end if
    
      do i = k1,k2 ! --- расчет каждой копией программы
        k[this_image()] = k[this_image()] + i
      end do
      SYNC ALL  ! дожидаемся всех, сколько каждая копия насчитала
        
      if (this_image() == 1) then ! --- сбор результатов 
        do i = 1,num_images() 
          sum = sum + k[i]
        end do
        write(*,*) sum    ! 5000050000
      end if 
    
    end
            

    SYNC IMAGES

    SYNC IMAGES(image_set)
        

    Синхронизация избранных копий программы,

    image_set – массив номеров копий программы или просто номер копии
    image_set(*) - означает все копии
    if (this_image() == 5) then
       ! image 5 ожидает других images, 
       ! чтобы завершить использование данных.
       sync images(*)
    else
       sync images(5) 
       ! Другие images ожидают image 5, 
       ! чтобы установить данные, 
       ! но не ожидают никакого другого image.
    end if
        

    CRITICAL

    critical
      ! операторы, выполняемые в любой момент
      ! времени только одной копией программы
    end critical
        
    program CAF
    implicit none
    
    complex Y(50)[1,1:*]
    
      write(*,*) "This is ", this_image(), " copy of program "
      write(*,*) "Image index = ", image_index(Y,[1,this_image()])
      write(*,*) "Coordinates = ", this_image(Y)
      write(*,*)
    
    end program CAF
        
    Результаты печати на экране "перепутаны"!
     This is            1  copy of program
     This is            2  copy of program
     Index =            2
     Coordinates =            1           2
    
     Index =            1
     Coordinates =            1           1
        
     This is            2  copy of program
     This is            1  copy of program
     Index =            2
     Coordinates =            1           2
    
     Index =            1
     Coordinates =            1           1
        
     This is            2  copy of program
     This is            1  copy of program
     Index =            1
     Coordinates =            1           1
    
     Index =            2
     Coordinates =            1           2
        

    Экран – критическая секция.

    program CAF
    implicit none
    
    complex Y(50)[1,1:*]
    critical
      write(*,*) "This is ", this_image(), " copy of program "
      write(*,*) "Image index = ", image_index(Y,[1,this_image()])
      write(*,*) "Coordinates = ", this_image(Y)
      write(*,*)
    end critical
    end program CAF
        
     This is            1  copy of program
     Image index =            1
     Coordinates =            1           1
    
     This is            2  copy of program
     Image index =            2
     Coordinates =            1           2
        

    Задания

    Написать программу нахождения максимума в одномерном массиве.

    Вернуться к учебному плану