2012-11-14 49 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

相关问题