2012-11-14 50 views
2

我有一些麻煩將一些變量從void *轉換爲MPI_Aint。下面是代碼的某些部分:(當我評論的最後一行中沒有錯誤)從無效轉換爲MPI_Aint

... 
mmap succeeded 0x7fab7b490000 
... 
*** Process received signal *** 
Signal: Segmentation fault (11) 
Signal code: Address not mapped (1) 
Failing at address: (nil) 

任何想法,以幫助

C: 
void myfunc_(MPI_Aint *out_ptr, ...) 
... 
void *ptr = mmap(...) 
... 
*out_ptr = (MPI_Aint) ptr; 

Fortran : 
#ifdef DOUBLE_PREC 
    integer, parameter, public :: mytype = KIND(0.0D0) 
    integer, parameter, public :: real_type = MPI_DOUBLE_PRECISION 
#endif 
INTEGER BSIZ, CORE_COMM, status 
real(mytype), pointer :: SND 
... 
call myfunc(SND, BSIZ, real_type, CORE_COMM, status) 

MMAP是在錯誤的工作,但在那裏?下面是完整的C函數代碼:

void myfunc_(MPI_Aint *out_ptr, MPI_Fint *nelem, MPI_Fint *type, 
      MPI_Fint *comm, MPI_Fint *ret) 
{ 
MPI_Comm world; 
int mype; 

world = MPI_Comm_f2c(*comm); 
MPI_Comm_rank(world, &mype); 

char filename[20]; 

#define POSIX_SHM 

int i,j; 

int world_rank = -1, world_size = -1; 
int mpi_result = MPI_SUCCESS; 

int color = -1; 
int ranks_per_node = -1; 
MPI_Comm IntraNodeComm; 

int node_shmem_bytes; 

mpi_result = MPI_Comm_rank(MPI_COMM_WORLD, &world_rank); 
assert(mpi_result==MPI_SUCCESS); 
mpi_result = MPI_Comm_size(MPI_COMM_WORLD, &world_size); 
assert(mpi_result==MPI_SUCCESS); 

if (world_rank==0) 
{ 
    char * env_char; 
    int units = 1; 
    int num_count = 0; 
    env_char = getenv("NODE_SHARED_MEMORY"); 
    if (env_char!=NULL) 
    { 
     if  (NULL != strstr(env_char,"G")) units = 1000000000; 
     else if (NULL != strstr(env_char,"M")) units = 1000000; 
     else if (NULL != strstr(env_char,"K")) units = 1000; 
     else          units = 1; 

     num_count = strspn(env_char, ""); 
     memset(&env_char[num_count], ' ', strlen(env_char)-num_count); 

     node_shmem_bytes = units * atoi(env_char); 
     printf("%7d: NODE_SHARED_MEMORY = %d bytes \n", world_rank, node_shmem_bytes); 
    } 
    else 
    { 
     node_shmem_bytes = getpagesize(); 
     printf("%7d: NODE_SHARED_MEMORY = %d bytes \n", world_rank, node_shmem_bytes); 
    } 
} 
mpi_result = MPI_Bcast(&node_shmem_bytes, 1, MPI_INT, 0, MPI_COMM_WORLD); 
assert(mpi_result==MPI_SUCCESS); 

int node_shmem_count = node_shmem_bytes/sizeof(double); 
node_shmem_count = (int) *nelem; 
node_shmem_bytes = node_shmem_count * sizeof(double) * 2; 

fflush(stdout); 
MPI_Barrier(MPI_COMM_WORLD); 

IntraNodeComm = world; 

int subcomm_rank = -1; 
mpi_result = MPI_Comm_rank(IntraNodeComm, &subcomm_rank); 
assert(mpi_result==MPI_SUCCESS); 

sprintf(filename,"/foo_%d_%d_%d",*nelem,*type,*comm); 

#if defined(POSIX_SHM) 
int fd; 
if (subcomm_rank==0) 
    fd = shm_open(filename, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR); 

mpi_result = MPI_Barrier(MPI_COMM_WORLD); 
assert(mpi_result==MPI_SUCCESS); 

if (subcomm_rank!=0) 
    fd = shm_open(filename, O_RDWR, S_IRUSR | S_IWUSR); 

if (fd<0) printf("%7d: shm_open failed: %d \n", world_rank, fd); 
else  printf("%7d: shm_open succeeded: %d \n", world_rank, fd); 
#elif defined(DEV_SHM) 
int fd = open("/dev/shm/foo", O_RDWR | O_CREAT, S_IRUSR | S_IWUSR); 
if (fd<0) printf("%7d: open failed: %d \n", world_rank, fd); 
else  printf("%7d: open succeeded: %d \n", world_rank, fd); 
#else 
int fd = -1; 
printf("%7d: no file backing \n", world_rank); 
#endif 
fflush(stdout); 
mpi_result = MPI_Barrier(MPI_COMM_WORLD); 
assert(mpi_result==MPI_SUCCESS); 

if (fd>=0 && subcomm_rank==0) 
{ 
    int rc = ftruncate(fd, node_shmem_bytes); 
    if (rc==0) printf("%7d: ftruncate succeeded \n", world_rank); 
    else  printf("%7d: ftruncate failed \n", world_rank); 
} 
fflush(stdout); 
mpi_result = MPI_Barrier(MPI_COMM_WORLD); 
assert(mpi_result==MPI_SUCCESS); 

#ifdef __bgp__ 
double * ptr = NULL; 
_BGP_Personality_t pers; 
Kernel_GetPersonality(&pers, sizeof(pers)); 

if(BGP_Personality_processConfig(&pers) == _BGP_PERS_PROCESSCONFIG_SMP) 
{ 
    printf("SMP mode => MAP_PRIVATE | MAP_ANONYMOUS \n"); 
    ptr = mmap(NULL, node_shmem_bytes, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, fd, 0); 
} 
else 
{ 
    if (node_shmem_bytes>pers.Kernel_Config.SharedMemMB) 
    { 
     printf("node_shmem_bytes (%d) greater than pers.Kernel_Config.SharedMemMB (%d) - allocating the latter \n", 
       node_shmem_bytes, pers.Kernel_Config.SharedMemMB); 
     node_shmem_bytes = pers.Kernel_Config.SharedMemMB; 
    } 
    ptr = mmap(NULL, node_shmem_bytes, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); 
} 
#else 
void *ptr = mmap(NULL, node_shmem_bytes, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); 
#endif 
if (ptr==NULL) printf("%7d: mmap failed \n", world_rank); 
else   printf("%7d: mmap succeeded %p\n", world_rank,ptr); 
fflush(stdout); 
mpi_result = MPI_Barrier(MPI_COMM_WORLD); 
assert(mpi_result==MPI_SUCCESS); 

mpi_result = MPI_Comm_size(IntraNodeComm, &ranks_per_node); 
assert(mpi_result==MPI_SUCCESS); 
if (0==subcomm_rank) printf("%7d: ranks_per_node = %d \n", world_rank, ranks_per_node); 
fflush(stdout); 

for (i=0; i<ranks_per_node; i++) 
{ 
    if (i==subcomm_rank) 
    { 
     printf("%7d: subcomm_rank %d setting the buffer \n", world_rank, subcomm_rank); 
     //for (j=0; j<node_shmem_count; j++) ptr[j] = (double)i; 
     printf("%7d: memset succeeded \n", world_rank); 

     int rc = msync(ptr, node_shmem_bytes, MS_INVALIDATE | MS_SYNC); 
     if (rc==0) printf("%7d: msync succeeded, %p \n", world_rank, ptr); 
     else  printf("%7d: msync failed \n", world_rank); 
    } 

    fflush(stdout); 
    mpi_result = MPI_Barrier(MPI_COMM_WORLD); 
    assert(mpi_result==MPI_SUCCESS); 

    //printf("%7d: ptr = %lf ... %lf \n", world_rank, ptr[0], ptr[node_shmem_count-1]); 
    fflush(stdout); 

    mpi_result = MPI_Barrier(MPI_COMM_WORLD); 
    assert(mpi_result==MPI_SUCCESS); 
} 
fflush(stdout); 
mpi_result = MPI_Barrier(MPI_COMM_WORLD); 
assert(mpi_result==MPI_SUCCESS); 

if (ptr!=NULL) 
{ 
    int rc = munmap(ptr, node_shmem_bytes); 
    if (rc==0) printf("%7d: munmap succeeded %p, %d\n", world_rank,ptr, (MPI_Aint) ptr); 
    else  printf("%7d: munmap failed \n", world_rank); 
} 
fflush(stdout); 
mpi_result = MPI_Barrier(MPI_COMM_WORLD); 
assert(mpi_result==MPI_SUCCESS); 

#if defined(POSIX_SHM) 
//if (fd>=0) 
if (fd>=0 && subcomm_rank==0) 
{ 
    int rc = -1; 

    rc = shm_unlink(filename); 
    if (rc==0) printf("%7d: shm_unlink succeeded %p\n", world_rank,ptr); 
    else  printf("%7d: shm_unlink failed \n", world_rank); 
} 
#elif defined(DEV_SHM) 
if (fd>=0 && subcomm_rank==0) 
{ 
    int rc = -1; 

    rc = ftruncate(fd, 0); 
    if (rc==0) printf("%7d: ftruncate succeeded \n", world_rank); 
    else  printf("%7d: ftruncate failed \n", world_rank); 

    rc = close(fd); 
    if (rc==0) printf("%7d: close succeeded \n", world_rank); 
    else  printf("%7d: close failed \n", world_rank); 
} 
#endif 
fflush(stdout); 
mpi_result = MPI_Barrier(MPI_COMM_WORLD); 
assert(mpi_result==MPI_SUCCESS); 

*out_ptr = (MPI_Aint) ptr; 

} 
+0

如果您可以依賴MPI-3的存在,只需使用MPI_Win_allocate_shared而不是myfunc即可。這是來自寫myfunc的人:-) [https://wiki.alcf.anl.gov/parts/index.php/Shared_memory] ​​ – Jeff

回答

1

我的意思是你寫一個簡短的評論,但它在某種程度上增長超過了限制有點...

MPI標準體和實現者一直在努力與這個C到Fortran的記憶傳遞問題青睞。爲什麼不重複他們的努力,而不是重新發現一個事實,即一個圓形輪比一個圓形輪更好?

只要看看MPI標準函數MPI_ALLOC_MEM,它應該在MPI中分配特殊內存並將其返回給用戶代碼。該MPI-2.2標準定義了它的Fortran接口:

MPI_ALLOC_MEM(SIZE, INFO, BASEPTR, IERROR) 
    INTEGER INFO, IERROR 
    INTEGER(KIND=MPI_ADDRESS_KIND) SIZE, BASEPTR 

在MPI-3.0現代的Fortran 2008接口使用ISO_C_BINDING,並配備爲:

MPI_Alloc_mem(size, info, baseptr, ierror) 
    USE, INTRINSIC :: ISO_C_BINDING, ONLY : C_PTR 
    INTEGER(KIND=MPI_ADDRESS_KIND), INTENT(IN) :: size 
    TYPE(MPI_Info), INTENT(IN) :: info 
    TYPE(C_PTR), INTENT(OUT) :: baseptr 
    INTEGER, OPTIONAL, INTENT(OUT) :: ierror 

該標準給出瞭如何使用下面的示例呼叫:

USE mpi_f08 
USE, INTRINSIC :: ISO_C_BINDING 
TYPE(C_PTR) :: p 
REAL, DIMENSION(:,:), POINTER :: a 
INTEGER, DIMENSION(2) :: shape 
INTEGER(KIND=MPI_ADDRESS_KIND) :: size 
shape = (/100,100/) 
size = 4 * shape(1) * shape(2) 
CALL MPI_Alloc_mem(size,MPI_INFO_NULL,p,ierr) 
CALL C_F_POINTER(p, a, shape) 
... 
a(3,5) = 2.71 
... 
CALL MPI_Free_mem(a, ierr) 

基本上從ISO_C_BINDINGC_F_POINTER常規結合的C指針到的Fortran指針,然後將記憶,由前者指出可通過後者獲得。

這是開放MPI如何實現F08 MPI_Alloc_mem

subroutine MPI_Alloc_mem_f08(size,info,baseptr,ierror) 
    use, intrinsic :: ISO_C_BINDING, only : C_PTR 
    use :: mpi_f08_types, only : MPI_Info, MPI_ADDRESS_KIND 
    use :: mpi_f08, only : ompi_alloc_mem_f 
    implicit none 
    INTEGER(MPI_ADDRESS_KIND), INTENT(IN) :: size 
    TYPE(MPI_Info), INTENT(IN) :: info 
    TYPE(C_PTR), INTENT(OUT) :: baseptr 
    INTEGER, OPTIONAL, INTENT(OUT) :: ierror 
    integer :: c_ierror 

    call ompi_alloc_mem_f(size,info%MPI_VAL,baseptr,c_ierror) 
    if (present(ierror)) ierror = c_ierror 

end subroutine MPI_Alloc_mem_f08 

ompi_alloc_mem_f是一個C函數接口內部C實現對Fortran語言:

void ompi_alloc_mem_f(MPI_Aint *size, MPI_Fint *info, char *baseptr, MPI_Fint *ierr) 
{ 
    int ierr_c; 
    MPI_Info c_info = MPI_Info_f2c(*info); 

    ierr_c = MPI_Alloc_mem(*size, c_info, baseptr); 
    if (NULL != ierr) *ierr = OMPI_INT_2_FINT(ierr_c); 
} 

所以你可以看到,TYPE(C_PTR)baseptr Fortran的參數只是作爲一個指針出現,通過引用(像往常一樣)傳遞。這在這裏不是很明顯,因爲MPI標準定義了MPI_Alloc_mem的最後一個參數,其中返回指向分配的存儲器的指針,如void *,而實際上是指向引用傳遞的void指針(即void **)。另外,虛擬baseptr參數實際上是void **,但由於原因而簡單地聲明爲char * :)使用相同的函數來實現舊的Fortran接口,因此char *baseptr映射到實際參數INTEGER(KIND=MPI_ADDRESS_KIND)

的教訓是,而在Fortran語言MPI_ADDRESS_KIND整數的意思來存儲指針和指針差值,則不應使用MPI_Aint在C指針參數類型,而是普通雙指針像void **

0

我不能確定該行是否可以發表評論,以避免該問題如下與否:

*out_ptr = (MPI_Aint) ptr; 

你解引用是不相符的。

ptrdouble *,不能直接轉換爲MPI_Aint

也許你想

*out_ptr = *(MPI_Aint *)ptr; 

如果呼叫者在一個指針傳遞(如out_ptr)到要存儲在*ptr發現單MPI_Aint的位置。但是,這種沒有意義在分配node_shmem_bytes所以也許光:

out_ptr = (MPI_Aint *)ptr 

這將設置(地方到MYFUNC副本)out_ptr到MPI_Aint對象的塊,但主叫方不會看到。我不知道正在使用Fortran - > C調用約定,但是可能您想傳遞一個指向C程序可以放置ptr的指針:MPI_Aint *

+0

感謝您的幫助。你是對的,評論行「* out_ptr =(MPI_Aint)ptr;」導致沒有錯誤。主要思想是在C函數中分配一些共享內存,並在out_ptr中返回基本分配的內存地址內存。做這個接口有點棘手。不能真正使用iso_c_binding,因爲「變量可以通過使用C綁定屬性從C訪問,也可以指定一個綁定名稱,這些變量必須在MODULE的聲明部分聲明,具有可互操作的類型,指針或可分配屬性。「 – user1824346

相關問題