2013-11-15 1 views
1

우리는 Nvidia GPU 및 Intel Xeon Phi를 발전시키는 프로젝트를 가지고 있습니다. 호스트 코드와 GPU 코드는 Fortran으로 작성되고 pgfortran에 의해 컴파일됩니다. 우리 직업의 일부를 Phi에서 오프로드하려면 ifort (정적 링크가 작동하지 않음)로 컴파일 된 공유 라이브러리를 만들고 코드의 pgfortran 부분에서 공유 서브 루틴을 호출해야합니다. 그렇게함으로써, 코드의 pgfortran 부분에서 Xeon Phi와 통신 할 수있는 intel fortran 공유 라이브러리로 배열을 오프로드 할 수 있습니다.다른 컴파일러 (PGI 및 Intel)간에 할당 가능한 배열을 포함하는 포트란 파생 형식 전달

이제 할당 가능한 배열을 포함하는 파생 형식을 pgfortran 코드 부분에서 ifort 공유 라이브러리로 전달하려고합니다. 어떤 문제가있는 것처럼 보입니다. 여기

간단한 예이다 (더 인텔 MIC 현재 지시자를 오프로드 없음) :

caller.f90 :

program caller                   

type cell                     
integer :: id                    
real, allocatable :: a(:)                 
real, allocatable :: b(:)                 
real, allocatable :: c(:)                 
end type cell                    

integer :: n,i,j 

type(cell) :: cl(2)                  
n=10                      
do i=1,2                     
allocate(cl(i)%a(n))                  
allocate(cl(i)%b(n))                  
allocate(cl(i)%c(n))                  
end do                     


do j=1, 2                     
do i=1, n                     
cl(j)%a(i)=10*j+i                   
cl(j)%b(i)=10*i+j                   
end do                     
end do                     


call offload(cl(1))                  
print *, cl(1)%c 
end program caller 

called.f90 :

subroutine offload(cl)                 
type cell                     
integer :: id                    
real, allocatable :: a(:)                 
real, allocatable :: b(:)                 
real, allocatable :: c(:)                 
end type cell 

type(cell) :: cl                   
integer :: n 

print *, cl%a(1:10) 
print *, cl%b(1:10) 
end subroutine offload  

메이크 :

run: caller.o libcalled.so 
      pgfortran -L. caller.o -lcalled -o [email protected] 
caller.o: caller.f90 
      pgfortran -c caller.f90 
libcalled.so: called.f90 
      ifort -shared -fPIC $^ -o [email protected] 

"cl%a(1:10) "여기에"(1:10) "이 없으면 아무 것도 인쇄되지 않습니다.

이 코드는 마침내 cl(1)%a의 요소를 인쇄 한 다음 배열 행 cl(1)%b을 인쇄하려고 시도한 다음 줄에서 세그먼트 결함을 기록합니다.

"cl%a(1:10)"을 "cl % a (1 : 100)"로 변경하고 "print *, cl%b(1:10)"을 삭제하십시오. 우리는 B 배열의 요소가 있지만 난 그냥 "cl%b(1:10)"로 그들을 가져올 수 없음을 찾을 수 있습니다

results

: 그것은 결과를 줄 것이다.

다른 컴파일러의 파생 형식 구조가 원인 일 수 있습니다. 하지만 저는 컴파일러간에 이런 종류의 파생 된 타입을 전달할 수있는 방법을 정말로 원합니다. 어떤 해결책?

감사합니다.

답변

4

컴파일러의 ABI는 다를 수 있습니다. 구조체를 직접 전달하지 말고 서브 루틴 내부에 빌드하고 포인터를 사용하십시오.이 포인터는 type(c_ptr) 또는 가정 된 크기 배열로 전달해야합니다 (단, 복사 할 수 있습니다!).

Fortran 2003의 C와의 상호 운용성은 C와 상호 작용할뿐만 아니라 C와 상호 운용되는 다른 컴파일러와도 상호 작용하기위한 것이 아닙니다. 다른 Fortran 컴파일러가 될 수 있습니다.

형식이 sequence 또는 bind(C) 인 경우를 제외하고 더 많은 곳에서 같은 유형을 선언하고 같은 유형으로 사용하는 것은 Fortran 규칙에 위배된다는 것을 알고 있어야합니다. 이것이 프로그램이 표준을 따르지 않는 또 다른 이유입니다.

called.f90 :

subroutine offload(cl_c)                 
use iso_c_binding 

type, bind(C) :: cell_C                    
integer :: id                    
integer :: na, nb, nc 
type(c_ptr) :: a,b,c                                
end type cell_C 

type cell                    
integer :: id 
real, pointer :: a(:)                 
real, pointer :: b(:)                 
real, pointer :: c(:)                 
end type cell 

type(cell) :: cl 
type(cell_C) :: cl_C 
integer :: n 

cl%id = cl_C%id 
call c_f_pointer(cl_C%a, cl%a, [cl_c%na]) 
call c_f_pointer(cl_C%b, cl%b, [cl_c%nb]) 
call c_f_pointer(cl_C%c, cl%c, [cl_c%nc]) 

print *, cl%a(1:10) 
print *, cl%b(1:10) 
end subroutine offload 

호출.F90 : gfortran와 ifort와

program caller 
use iso_c_binding 

type, bind(C) :: cell_C                    
integer :: id                    
integer :: na, nb, nc 
type(c_ptr) :: a,b,c                                
end type cell_C 

type cell                     
integer :: id                    
real, allocatable :: a(:)                 
real, allocatable :: b(:)                 
real, allocatable :: c(:)                 
end type cell                    

integer :: n,i,j 

type(cell),target :: cl(2) 
type(cell_c) :: cl_c 
n=10                      
do i=1,2                     
allocate(cl(i)%a(n))                  
allocate(cl(i)%b(n))                  
allocate(cl(i)%c(n))                  
end do                     

do j=1, 2                     
do i=1, n                     
cl(j)%a(i)=10*j+i                   
cl(j)%b(i)=10*i+j                   
end do                     
end do                     

cl_c%a = c_loc(cl(1)%a) 
cl_c%b = c_loc(cl(1)%b) 
cl_c%c = c_loc(cl(1)%c) 
cl_c%na = size(cl(1)%a) 
cl_c%nb = size(cl(1)%b) 
cl_c%nc = size(cl(1)%c) 
cl_c%id = cl(1)%id 

call offload(cl_c)                  
print *, cl(1)%c 
end program caller 

: 여기

>gfortran called.f90 -c -o called.o 
>ifort caller.f90 -c -o caller.o 
>ifort -o a.out called.o caller.o -lgfortran 
>./a.out 
11.0000000  12.0000000  13.0000000  14.0000000  15.0000000  16.0000000  17.0000000  18.0000000  19.0000000  20.0000000  
    11.0000000  21.0000000  31.0000000  41.0000000  51.0000000  61.0000000  71.0000000  81.0000000  91.0000000  101.000000  
    0.0000000E+00 0.0000000E+00 0.0000000E+00 0.0000000E+00 0.0000000E+00 
    0.0000000E+00 0.0000000E+00 0.0000000E+00 0.0000000E+00 0.0000000E+00 

없음 동적 라이브러리 필요합니다.

이론적 인 이식성을 위해 c_int, c_float을 사용할 수 있습니다 ... 형식이 더 좋을 수는 있지만 그와 같은 점은 분명합니다.

변환을 쉽게하기 위해 cellcell_C 사이의 할당을 오버로드 할 수도 있습니다.

+0

a (:), b (:), c (:) in cell.f90은 할당 가능한 배열 일 수 있습니까? 나는 그것을 시도했다, 그것은 두 번 무료 또는 부패 오류를 줄 것이다. 나는 그들 중 하나가 patatable offload에 할당 할 수있는 배열이 될 필요가있다. – zyc

+0

아니, 될 수 없다. 할당 할 수있는 것은 특정 컴파일러에 의해 할당 된 메모리에만 있습니다. 다른 컴파일러에 의해 할당 된 경우 포인터로 가리켜 야합니다. –

+0

그러나, 나는 당신이 allocatables로 그것을 컴파일 할 수 있었다고 나는 이해하지 못한다. 나의 대답에서 제안을 사용했다면, 가능해서는 안된다. 왜 네가 그걸 필요로하는지 이해가 안돼. 정말 필요한 경우 포인터 배열에서 값을 복사하면됩니다. –

관련 문제