/* This file contains simple binary read/write routines. */ #include #include #include #include #if defined(PETSC_HAVE_UNISTD_H) #include #endif #if defined(PETSC_HAVE_IO_H) #include #endif #if !defined(PETSC_HAVE_O_BINARY) #define O_BINARY 0 #endif const char *const PetscFileModes[] = {"READ","WRITE","APPEND","UPDATE","APPEND_UPDATE","PetscFileMode","PETSC_FILE_",NULL}; /* --------------------------------------------------------- */ /* PetscByteSwapEnum - Swap bytes in a PETSc Enum */ PetscErrorCode PetscByteSwapEnum(PetscEnum *buff,PetscInt n) { PetscInt i,j; PetscEnum tmp = ENUM_DUMMY; char *ptr1,*ptr2 = (char*)&tmp; PetscFunctionBegin; for (j=0; j 0) break; /* Proxy for EOF */ if (ret < 0) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_FILE_READ,"Error reading from file, errno %d",errno); m -= ret; p += ret; n += ret; } if (m && !count) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FILE_READ,"Read past end of file"); num = (PetscInt)(n/typesize); /* Should we require `n % typesize == 0` ? */ if (count) *count = num; /* TODO: This is most likely wrong for PETSC_BIT_LOGICAL */ #if defined(PETSC_USE_REAL___FLOAT128) if ((type == PETSC_REAL || type == PETSC_COMPLEX) && readdouble) { PetscInt i, cnt = num * ((type == PETSC_REAL) ? 1 : 2); PetscReal *preal = (PetscReal*)data; if (!PetscBinaryBigEndian()) {ierr = PetscByteSwapDouble(pdouble,cnt);CHKERRQ(ierr);} for (i=0; i 1) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"Can only binary view a single function at a time"); ierr = PetscFPTFind(*(void**)p,&fnametmp);CHKERRQ(ierr); ierr = PetscStrncpy(fname,fnametmp,m);CHKERRQ(ierr); #else ierr = PetscStrncpy(fname,"",m);CHKERRQ(ierr); #endif wtype = PETSC_CHAR; pp = (char*)fname; ptmp = (void*)fname; } #if defined(PETSC_USE_REAL___FLOAT128) ierr = PetscOptionsGetBool(NULL,NULL,"-binary_write_double",&writedouble,NULL);CHKERRQ(ierr); /* If using __float128 precision we still write in doubles to file */ if ((type == PETSC_SCALAR || type == PETSC_REAL || type == PETSC_COMPLEX) && writedouble) { wtype = PETSC_DOUBLE; ierr = PetscMalloc1(n,&ppp);CHKERRQ(ierr); pv = (PetscReal*)pp; for (i=0; i 1) { ierr = PetscDataTypeToMPIDataType(type,&mtype);CHKERRQ(ierr); ierr = MPI_Bcast(data,count?ibuf[1]:num,mtype,0,comm);CHKERRMPI(ierr); } if (count) *count = ibuf[1]; if (type == PETSC_FUNCTION) { #if defined(PETSC_SERIALIZE_FUNCTIONS) ierr = PetscDLLibrarySym(PETSC_COMM_SELF,&PetscDLLibrariesLoaded,NULL,fname,(void**)fptr);CHKERRQ(ierr); #else *(void**)fptr = NULL; #endif free(fname); } PetscFunctionReturn(0); } /*@C PetscBinarySynchronizedWrite - writes to a binary file. Collective Input Parameters: + comm - the MPI communicator . fd - the file . n - the number of items to write . p - the buffer - type - the type of items to write (PETSC_INT, PETSC_DOUBLE or PETSC_SCALAR) Level: developer Notes: Process 0 does a PetscBinaryWrite() PetscBinarySynchronizedWrite() uses byte swapping to work on all machines. Integers are stored on the file as 32 long, regardless of whether they are stored in the machine as 32 or 64, this means the same binary file may be read on any machine. Notes: because byte-swapping may be done on the values in data it cannot be declared const WARNING: This is NOT like PetscSynchronizedFPrintf()! This routine ignores calls on all but process 0, while PetscSynchronizedFPrintf() has all processes print their strings in order. .seealso: PetscBinaryWrite(), PetscBinaryOpen(), PetscBinaryClose(), PetscBinaryRead(), PetscBinarySynchronizedRead(), PetscBinarySynchronizedSeek() @*/ PetscErrorCode PetscBinarySynchronizedWrite(MPI_Comm comm,int fd,const void *p,PetscInt n,PetscDataType type) { PetscErrorCode ierr; PetscMPIInt rank; PetscFunctionBegin; ierr = MPI_Comm_rank(comm,&rank);CHKERRMPI(ierr); if (rank == 0) { ierr = PetscBinaryWrite(fd,p,n,type);CHKERRQ(ierr); } PetscFunctionReturn(0); } /*@C PetscBinarySynchronizedSeek - Moves the file pointer on a PETSc binary file. Input Parameters: + fd - the file . whence - if PETSC_BINARY_SEEK_SET then size is an absolute location in the file if PETSC_BINARY_SEEK_CUR then size is offset from current location if PETSC_BINARY_SEEK_END then size is offset from end of file - off - number of bytes to move. Use PETSC_BINARY_INT_SIZE, PETSC_BINARY_SCALAR_SIZE, etc. in your calculation rather than sizeof() to compute byte lengths. Output Parameter: . offset - new offset in file Level: developer Notes: Integers are stored on the file as 32 long, regardless of whether they are stored in the machine as 32 or 64, this means the same binary file may be read on any machine. Hence you CANNOT use sizeof() to determine the offset or location. .seealso: PetscBinaryRead(), PetscBinaryWrite(), PetscBinaryOpen(), PetscBinarySynchronizedWrite(), PetscBinarySynchronizedRead(), PetscBinarySynchronizedSeek() @*/ PetscErrorCode PetscBinarySynchronizedSeek(MPI_Comm comm,int fd,off_t off,PetscBinarySeekType whence,off_t *offset) { PetscErrorCode ierr; PetscMPIInt rank; PetscFunctionBegin; ierr = MPI_Comm_rank(comm,&rank);CHKERRMPI(ierr); if (rank == 0) { ierr = PetscBinarySeek(fd,off,whence,offset);CHKERRQ(ierr); } PetscFunctionReturn(0); } #if defined(PETSC_HAVE_MPIIO) #if defined(PETSC_USE_PETSC_MPI_EXTERNAL32) /* MPICH does not provide the external32 representation for MPI_File_set_view() so we need to provide the functions. These are set into MPI in PetscInitialize() via MPI_Register_datarep() Note I use PetscMPIInt for the MPI error codes since that is what MPI uses (instead of the standard PetscErrorCode) The next three routines are not used because MPICH does not support their use */ PETSC_EXTERN PetscMPIInt PetscDataRep_extent_fn(MPI_Datatype datatype,MPI_Aint *file_extent,void *extra_state) { MPI_Aint ub; PetscMPIInt ierr; ierr = MPI_Type_get_extent(datatype,&ub,file_extent); return ierr; } PETSC_EXTERN PetscMPIInt PetscDataRep_read_conv_fn(void *userbuf, MPI_Datatype datatype,PetscMPIInt count,void *filebuf, MPI_Offset position,void *extra_state) { PetscDataType pdtype; PetscMPIInt ierr; size_t dsize; ierr = PetscMPIDataTypeToPetscDataType(datatype,&pdtype);CHKERRQ(ierr); ierr = PetscDataTypeGetSize(pdtype,&dsize);CHKERRQ(ierr); /* offset is given in units of MPI_Datatype */ userbuf = ((char*)userbuf) + dsize*position; ierr = PetscMemcpy(userbuf,filebuf,count*dsize);CHKERRQ(ierr); if (!PetscBinaryBigEndian()) {ierr = PetscByteSwap(userbuf,pdtype,count);CHKERRQ(ierr);} return ierr; } PetscMPIInt PetscDataRep_write_conv_fn(void *userbuf, MPI_Datatype datatype,PetscMPIInt count,void *filebuf, MPI_Offset position,void *extra_state) { PetscDataType pdtype; PetscMPIInt ierr; size_t dsize; ierr = PetscMPIDataTypeToPetscDataType(datatype,&pdtype);CHKERRQ(ierr); ierr = PetscDataTypeGetSize(pdtype,&dsize);CHKERRQ(ierr); /* offset is given in units of MPI_Datatype */ userbuf = ((char*)userbuf) + dsize*position; ierr = PetscMemcpy(filebuf,userbuf,count*dsize);CHKERRQ(ierr); if (!PetscBinaryBigEndian()) {ierr = PetscByteSwap(filebuf,pdtype,count);CHKERRQ(ierr);} return ierr; } #endif PetscErrorCode MPIU_File_write_all(MPI_File fd,void *data,PetscMPIInt cnt,MPI_Datatype dtype,MPI_Status *status) { PetscDataType pdtype; PetscErrorCode ierr; PetscFunctionBegin; ierr = PetscMPIDataTypeToPetscDataType(dtype,&pdtype);CHKERRQ(ierr); if (!PetscBinaryBigEndian()) {ierr = PetscByteSwap(data,pdtype,cnt);CHKERRQ(ierr);} ierr = MPI_File_write_all(fd,data,cnt,dtype,status);CHKERRMPI(ierr); if (!PetscBinaryBigEndian()) {ierr = PetscByteSwap(data,pdtype,cnt);CHKERRQ(ierr);} PetscFunctionReturn(0); } PetscErrorCode MPIU_File_read_all(MPI_File fd,void *data,PetscMPIInt cnt,MPI_Datatype dtype,MPI_Status *status) { PetscDataType pdtype; PetscErrorCode ierr; PetscFunctionBegin; ierr = PetscMPIDataTypeToPetscDataType(dtype,&pdtype);CHKERRQ(ierr); ierr = MPI_File_read_all(fd,data,cnt,dtype,status);CHKERRMPI(ierr); if (!PetscBinaryBigEndian()) {ierr = PetscByteSwap(data,pdtype,cnt);CHKERRQ(ierr);} PetscFunctionReturn(0); } PetscErrorCode MPIU_File_write_at(MPI_File fd,MPI_Offset off,void *data,PetscMPIInt cnt,MPI_Datatype dtype,MPI_Status *status) { PetscDataType pdtype; PetscErrorCode ierr; PetscFunctionBegin; ierr = PetscMPIDataTypeToPetscDataType(dtype,&pdtype);CHKERRQ(ierr); if (!PetscBinaryBigEndian()) {ierr = PetscByteSwap(data,pdtype,cnt);CHKERRQ(ierr);} ierr = MPI_File_write_at(fd,off,data,cnt,dtype,status);CHKERRMPI(ierr); if (!PetscBinaryBigEndian()) {ierr = PetscByteSwap(data,pdtype,cnt);CHKERRQ(ierr);} PetscFunctionReturn(0); } PetscErrorCode MPIU_File_read_at(MPI_File fd,MPI_Offset off,void *data,PetscMPIInt cnt,MPI_Datatype dtype,MPI_Status *status) { PetscDataType pdtype; PetscErrorCode ierr; PetscFunctionBegin; ierr = PetscMPIDataTypeToPetscDataType(dtype,&pdtype);CHKERRQ(ierr); ierr = MPI_File_read_at(fd,off,data,cnt,dtype,status);CHKERRMPI(ierr); if (!PetscBinaryBigEndian()) {ierr = PetscByteSwap(data,pdtype,cnt);CHKERRQ(ierr);} PetscFunctionReturn(0); } PetscErrorCode MPIU_File_write_at_all(MPI_File fd,MPI_Offset off,void *data,PetscMPIInt cnt,MPI_Datatype dtype,MPI_Status *status) { PetscDataType pdtype; PetscErrorCode ierr; PetscFunctionBegin; ierr = PetscMPIDataTypeToPetscDataType(dtype,&pdtype);CHKERRQ(ierr); if (!PetscBinaryBigEndian()) {ierr = PetscByteSwap(data,pdtype,cnt);CHKERRQ(ierr);} ierr = MPI_File_write_at_all(fd,off,data,cnt,dtype,status);CHKERRMPI(ierr); if (!PetscBinaryBigEndian()) {ierr = PetscByteSwap(data,pdtype,cnt);CHKERRQ(ierr);} PetscFunctionReturn(0); } PetscErrorCode MPIU_File_read_at_all(MPI_File fd,MPI_Offset off,void *data,PetscMPIInt cnt,MPI_Datatype dtype,MPI_Status *status) { PetscDataType pdtype; PetscErrorCode ierr; PetscFunctionBegin; ierr = PetscMPIDataTypeToPetscDataType(dtype,&pdtype);CHKERRQ(ierr); ierr = MPI_File_read_at_all(fd,off,data,cnt,dtype,status);CHKERRMPI(ierr); if (!PetscBinaryBigEndian()) {ierr = PetscByteSwap(data,pdtype,cnt);CHKERRQ(ierr);} PetscFunctionReturn(0); } #endif