1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156
|
/*
* Copyright (C) by Argonne National Laboratory
* See COPYRIGHT in top-level directory
*/
#include <adio.h>
#include <limits.h>
/* utility function for creating large contiguous types: algorithim from BigMPI
* https://github.com/jeffhammond/BigMPI */
static int type_create_contiguous_x(MPI_Count count, MPI_Datatype oldtype, MPI_Datatype * newtype)
{
/* to make 'count' fit MPI-3 type processing routines (which take integer
* counts), we construct a type consisting of N INT_MAX chunks followed by
* a remainder. e.g for a count of 4000000000 bytes you would end up with
* one 2147483647-byte chunk followed immediately by a 1852516353-byte
* chunk */
MPI_Datatype chunks, remainder;
MPI_Aint lb, extent, disps[2];
int blocklens[2];
MPI_Datatype types[2];
/* truly stupendously large counts will overflow an integer with this math,
* but that is a problem for a few decades from now. Sorry, few decades
* from now! */
ADIOI_Assert(count / INT_MAX == (int) (count / INT_MAX));
int c = (int) (count / INT_MAX); /* OK to cast until 'count' is 256 bits */
int r = count % INT_MAX;
MPI_Type_vector(c, INT_MAX, INT_MAX, oldtype, &chunks);
MPI_Type_contiguous(r, oldtype, &remainder);
MPI_Type_get_extent(oldtype, &lb, &extent);
blocklens[0] = 1;
blocklens[1] = 1;
disps[0] = 0;
disps[1] = c * extent * INT_MAX;
types[0] = chunks;
types[1] = remainder;
MPI_Type_create_struct(2, blocklens, disps, types, newtype);
MPI_Type_free(&chunks);
MPI_Type_free(&remainder);
return MPI_SUCCESS;
}
/* like MPI_Type_create_hindexed, except array_of_lengths can be a larger datatype.
*
* Hindexed provides 'count' pairs of (displacement, length), but what if
* length is longer than an integer? We will create 'count' types, using
* contig if length is small enough, or something more complex if not */
int ADIOI_Type_create_hindexed_x(int count,
const MPI_Count array_of_blocklengths[],
const MPI_Aint array_of_displacements[],
MPI_Datatype oldtype, MPI_Datatype * newtype)
{
int i, ret;
MPI_Datatype *types;
int *blocklens;
int is_big = 0;
types = ADIOI_Malloc(count * sizeof(MPI_Datatype));
blocklens = ADIOI_Malloc(count * sizeof(int));
/* squashing two loops into one.
* - Look in the array_of_blocklengths for any large values
* - convert MPI_Count items (if they are not too big) into int-sized items
* after this loop we will know if we can use MPI_type_hindexed or if we
* need a more complicated BigMPI-style struct-of-chunks.
*
* Why not use the struct-of-chunks in all cases? HDF5 reported a bug,
* which I have not yet precicesly nailed down, but appears to have
* something to do with struct-of-chunks when the chunks are small */
for (i = 0; i < count; i++) {
if (array_of_blocklengths[i] > INT_MAX) {
blocklens[i] = 1;
is_big = 1;
type_create_contiguous_x(array_of_blocklengths[i], oldtype, &(types[i]));
} else {
/* OK to cast: checked for "bigness" above */
blocklens[i] = (int) array_of_blocklengths[i];
types[i] = oldtype;
}
}
if (is_big) {
ret = MPI_Type_create_struct(count, blocklens, array_of_displacements, types, newtype);
for (i = 0; i < count; i++)
if (types[i] != oldtype)
MPI_Type_free(&(types[i]));
} else {
ret = MPI_Type_create_hindexed(count, blocklens, array_of_displacements, oldtype, newtype);
}
ADIOI_Free(types);
ADIOI_Free(blocklens);
return ret;
}
/* some systems do not have pread/pwrite, or requrie XOPEN_SOURCE set higher
* than we would like. see #1973 */
#if (HAVE_DECL_PWRITE == 0)
#include <sys/types.h>
#include <unistd.h>
ssize_t pread(int fd, void *buf, size_t count, off_t offset);
ssize_t pwrite(int fd, const void *buf, size_t count, off_t offset);
ssize_t pread(int fd, void *buf, size_t count, off_t offset)
{
off_t lseek_ret;
off_t old_offset;
ssize_t read_ret;
old_offset = lseek(fd, 0, SEEK_CUR);
lseek_ret = lseek(fd, offset, SEEK_SET);
if (lseek_ret == -1)
return lseek_ret;
read_ret = read(fd, buf, count);
if (read_ret < 0)
return read_ret;
/* man page says "file offset is not changed" */
if ((lseek_ret = lseek(fd, old_offset, SEEK_SET)) < 0)
return lseek_ret;
return read_ret;
}
ssize_t pwrite(int fd, const void *buf, size_t count, off_t offset)
{
off_t lseek_ret;
off_t old_offset;
ssize_t write_ret;
old_offset = lseek(fd, 0, SEEK_CUR);
lseek_ret = lseek(fd, offset, SEEK_SET);
if (lseek_ret == -1)
return lseek_ret;
write_ret = write(fd, buf, count);
if (write_ret < 0)
return write_ret;
/* man page says "file offset is not changed" */
if ((lseek_ret = lseek(fd, old_offset, SEEK_SET)) < 0)
return lseek_ret;
return write_ret;
}
#endif
|