Выравнивание данных внутри структуры в Intel Fortran

Я пытаюсь выровнять в памяти следующий тип данных:

type foo
   real, allocatable, dimension(:) :: bar1, bar2
   !dir$ attributes align:64 :: bar1
   !dir$ attributes align:64 :: bar2
end type foo

type(foo), allocatable, dimension(:) :: my_foo
allocate(my_foo(1))
allocate(my_foo(1)%bar1(100))
allocate(my_foo(1)%bar2(100))

! somewhere here I need to tell the compiler that data is aligned
!    for a simple array with name `bar` I would just do:
!dir$ assume_aligned bar1: 64
!dir$ assume_aligned bar2: 64
!    but what do I do for the data type I have, something like this?
!dir$ assume_aligned my_foo(1)%bar1: 64
!dir$ assume_aligned my_foo(1)%bar2: 64

do i = 1, 100
   my_foo(1)%bar1(i) = 10.
   my_foo(1)%bar2(i) = 10.
end do

Как видите, это массив структур типа foo, который имеет два больших массива bar1 и bar2 в качестве переменных, которые мне нужно выровнять рядом с границами кеша в памяти.

Я знаю, как это сделать для простых массивов (link), но я понятия не имею, как это сделать для такой сложной структуры данных. А что, если бы my_foo было не размера 1, а размера, скажем, 100? Я прохожу через них?


person hayk    schedule 05.11.2018    source источник


Ответы (1)


Хорошо, дело полузакрыто. Решение оказалось довольно простым. Вы просто используете указатели и делаете с ними assume_aligned. Это должно позаботиться об этом.

type foo
   real, allocatable, dimension(:) :: bar1, bar2
   !dir$ attributes align:64 :: bar1
   !dir$ attributes align:64 :: bar2
end type foo

type(foo), target, allocatable, dimension(:) :: my_foo
real, pointer, contiguous :: pt_bar1(:)
real, pointer, contiguous :: pt_bar2(:)
allocate(my_foo(1))
allocate(my_foo(1)%bar1(100))
allocate(my_foo(1)%bar2(100))

pt_bar1 = my_foo(1)%bar1
pt_bar2 = my_foo(1)%bar2
!dir$ assume_aligned pt_bar1:64, pt_bar2:64

pt_bar1 = 10.
pt_bar2 = 10.

do циклы все еще не векторизованы smh. Как будто я делаю то же самое, как это

do i = 1, 100
   pt_bar1(i) = 10.
   pt_bar2(i) = 10.
end do

он не будет векторизован.

UPD. Хорошо, это работает (также нужно добавить флаг -qopenmp-simd в компилятор):

!$omp simd
!dir$ vector aligned
do i = 1, 100
   pt_bar1(i) = 10.
   pt_bar2(i) = 10.
end do

Кроме того, если вы перебираете my_foo(j)%..., обязательно освобождайте указатели после каждой итерации с помощью pt_bar1 => null() и т. д.

PS. Спасибо BW от нашего отдела за эту помощь. :) Иногда личное общение > stackoverflow (не всегда, только иногда).

person hayk    schedule 06.11.2018
comment
Что вы хотите векторизовать в этом цикле? Это операция сохранения памяти, а не математическое вычисление. - person Vladimir F; 07.11.2018
comment
Я просто хочу векторизовать цикл do. Если я пишу такой неявный цикл pt_bar = 10, он векторизуется, но когда я делаю явный цикл do i=1,100 ..., это не так. - person hayk; 07.11.2018