1 /*
2 * Copyright (C) by Argonne National Laboratory
3 * See COPYRIGHT in top-level directory
4 */
5
6 #include "adio.h"
7 #include "adio_extern.h"
8
ADIOI_GEN_WriteStrided_naive(ADIO_File fd,const void * buf,int count,MPI_Datatype buftype,int file_ptr_type,ADIO_Offset offset,ADIO_Status * status,int * error_code)9 void ADIOI_GEN_WriteStrided_naive(ADIO_File fd, const void *buf, int count,
10 MPI_Datatype buftype, int file_ptr_type,
11 ADIO_Offset offset, ADIO_Status * status, int
12 *error_code)
13 {
14 /* offset is in units of etype relative to the filetype. */
15
16 ADIOI_Flatlist_node *flat_buf, *flat_file;
17 /* bwr == buffer write; fwr == file write */
18 ADIO_Offset bwr_size, fwr_size = 0, sum, size_in_filetype;
19 int b_index;
20 MPI_Count bufsize;
21 ADIO_Offset n_etypes_in_filetype;
22 ADIO_Offset size, n_filetypes, etype_in_filetype;
23 ADIO_Offset abs_off_in_filetype = 0, req_len;
24 MPI_Count filetype_size, etype_size, buftype_size;
25 MPI_Aint filetype_extent, buftype_extent;
26 int buf_count, buftype_is_contig, filetype_is_contig;
27 ADIO_Offset userbuf_off;
28 ADIO_Offset off, req_off, disp, end_offset = 0, start_off;
29 ADIO_Status status1;
30
31 *error_code = MPI_SUCCESS; /* changed below if error */
32
33 ADIOI_Datatype_iscontig(buftype, &buftype_is_contig);
34 ADIOI_Datatype_iscontig(fd->filetype, &filetype_is_contig);
35
36 MPI_Type_size_x(fd->filetype, &filetype_size);
37 if (!filetype_size) {
38 #ifdef HAVE_STATUS_SET_BYTES
39 MPIR_Status_set_bytes(status, buftype, 0);
40 #endif
41 *error_code = MPI_SUCCESS;
42 return;
43 }
44
45 MPI_Type_extent(fd->filetype, &filetype_extent);
46 MPI_Type_size_x(buftype, &buftype_size);
47 MPI_Type_extent(buftype, &buftype_extent);
48 etype_size = fd->etype_size;
49
50 ADIOI_Assert((buftype_size * count) ==
51 ((ADIO_Offset) (unsigned) buftype_size * (ADIO_Offset) count));
52 bufsize = buftype_size * count;
53
54 /* contiguous in buftype and filetype is handled elsewhere */
55
56 if (!buftype_is_contig && filetype_is_contig) {
57 int b_count;
58 /* noncontiguous in memory, contiguous in file. */
59
60 flat_buf = ADIOI_Flatten_and_find(buftype);
61
62 off = (file_ptr_type == ADIO_INDIVIDUAL) ? fd->fp_ind :
63 fd->disp + (ADIO_Offset) etype_size *offset;
64
65 start_off = off;
66 end_offset = off + bufsize - 1;
67
68 /* if atomicity is true, lock (exclusive) the region to be accessed */
69 if ((fd->atomicity) && ADIO_Feature(fd, ADIO_LOCKS)) {
70 ADIOI_WRITE_LOCK(fd, start_off, SEEK_SET, end_offset - start_off + 1);
71 }
72
73 /* for each region in the buffer, grab the data and put it in
74 * place
75 */
76 for (b_count = 0; b_count < count; b_count++) {
77 for (b_index = 0; b_index < flat_buf->count; b_index++) {
78 userbuf_off = (ADIO_Offset) b_count *(ADIO_Offset) buftype_extent +
79 flat_buf->indices[b_index];
80 req_off = off;
81 req_len = flat_buf->blocklens[b_index];
82
83 ADIOI_Assert(req_len == (int) req_len);
84 ADIOI_Assert((((ADIO_Offset) (uintptr_t) buf) + userbuf_off) ==
85 (ADIO_Offset) (uintptr_t) ((uintptr_t) buf + userbuf_off));
86 ADIO_WriteContig(fd, (char *) buf + userbuf_off, (int) req_len, MPI_BYTE,
87 ADIO_EXPLICIT_OFFSET, req_off, &status1, error_code);
88 if (*error_code != MPI_SUCCESS)
89 return;
90
91 /* off is (potentially) used to save the final offset later */
92 off += flat_buf->blocklens[b_index];
93 }
94 }
95
96 if ((fd->atomicity) && ADIO_Feature(fd, ADIO_LOCKS)) {
97 ADIOI_UNLOCK(fd, start_off, SEEK_SET, end_offset - start_off + 1);
98 }
99
100 if (file_ptr_type == ADIO_INDIVIDUAL)
101 fd->fp_ind = off;
102
103 }
104
105 else { /* noncontiguous in file */
106 int f_index, st_index = 0;
107 ADIO_Offset st_fwr_size, st_n_filetypes;
108 int flag;
109
110 /* First we're going to calculate a set of values for use in all
111 * the noncontiguous in file cases:
112 * start_off - starting byte position of data in file
113 * end_offset - last byte offset to be acessed in the file
114 * st_n_filetypes - how far into the file we start in terms of
115 * whole filetypes
116 * st_index - index of block in first filetype that we will be
117 * starting in (?)
118 * st_fwr_size - size of the data in the first filetype block
119 * that we will write (accounts for being part-way
120 * into writing this block of the filetype
121 *
122 */
123
124 flat_file = ADIOI_Flatten_and_find(fd->filetype);
125 disp = fd->disp;
126
127 if (file_ptr_type == ADIO_INDIVIDUAL) {
128 start_off = fd->fp_ind; /* in bytes */
129 n_filetypes = -1;
130 flag = 0;
131 while (!flag) {
132 n_filetypes++;
133 for (f_index = 0; f_index < flat_file->count; f_index++) {
134 if (disp + flat_file->indices[f_index] +
135 n_filetypes * (ADIO_Offset) filetype_extent +
136 flat_file->blocklens[f_index] >= start_off) {
137 /* this block contains our starting position */
138
139 st_index = f_index;
140 fwr_size = disp + flat_file->indices[f_index] +
141 n_filetypes * (ADIO_Offset) filetype_extent +
142 flat_file->blocklens[f_index] - start_off;
143 flag = 1;
144 break;
145 }
146 }
147 }
148 } else {
149 n_etypes_in_filetype = filetype_size / etype_size;
150 n_filetypes = offset / n_etypes_in_filetype;
151 etype_in_filetype = offset % n_etypes_in_filetype;
152 size_in_filetype = etype_in_filetype * etype_size;
153
154 sum = 0;
155 for (f_index = 0; f_index < flat_file->count; f_index++) {
156 sum += flat_file->blocklens[f_index];
157 if (sum > size_in_filetype) {
158 st_index = f_index;
159 fwr_size = sum - size_in_filetype;
160 abs_off_in_filetype = flat_file->indices[f_index] +
161 size_in_filetype - (sum - flat_file->blocklens[f_index]);
162 break;
163 }
164 }
165
166 /* abs. offset in bytes in the file */
167 start_off = disp + n_filetypes * (ADIO_Offset) filetype_extent + abs_off_in_filetype;
168 }
169
170 st_fwr_size = fwr_size;
171 st_n_filetypes = n_filetypes;
172
173 /* start_off, st_n_filetypes, st_index, and st_fwr_size are
174 * all calculated at this point
175 */
176
177 /* Calculate end_offset, the last byte-offset that will be accessed.
178 * e.g., if start_off=0 and 100 bytes to be written, end_offset=99
179 */
180 userbuf_off = 0;
181 f_index = st_index;
182 off = start_off;
183 fwr_size = MPL_MIN(st_fwr_size, bufsize);
184 while (userbuf_off < bufsize) {
185 userbuf_off += fwr_size;
186 end_offset = off + fwr_size - 1;
187
188 if (f_index < (flat_file->count - 1))
189 f_index++;
190 else {
191 f_index = 0;
192 n_filetypes++;
193 }
194
195 off = disp + flat_file->indices[f_index] + n_filetypes * (ADIO_Offset) filetype_extent;
196 fwr_size = MPL_MIN(flat_file->blocklens[f_index], bufsize - (unsigned) userbuf_off);
197 }
198
199 /* End of calculations. At this point the following values have
200 * been calculated and are ready for use:
201 * - start_off
202 * - end_offset
203 * - st_n_filetypes
204 * - st_index
205 * - st_fwr_size
206 */
207
208 /* if atomicity is true, lock (exclusive) the region to be accessed */
209 if ((fd->atomicity) && ADIO_Feature(fd, ADIO_LOCKS)) {
210 ADIOI_WRITE_LOCK(fd, start_off, SEEK_SET, end_offset - start_off + 1);
211 }
212
213 if (buftype_is_contig && !filetype_is_contig) {
214 /* contiguous in memory, noncontiguous in file. should be the
215 * most common case.
216 */
217
218 userbuf_off = 0;
219 f_index = st_index;
220 off = start_off;
221 n_filetypes = st_n_filetypes;
222 fwr_size = MPL_MIN(st_fwr_size, bufsize);
223
224 /* while there is still space in the buffer, write more data */
225 while (userbuf_off < bufsize) {
226 if (fwr_size) {
227 /* TYPE_UB and TYPE_LB can result in
228 * fwr_size = 0. save system call in such cases */
229 req_off = off;
230 req_len = fwr_size;
231
232 ADIOI_Assert(req_len == (int) req_len);
233 ADIOI_Assert((((ADIO_Offset) (uintptr_t) buf) + userbuf_off) ==
234 (ADIO_Offset) (uintptr_t) ((uintptr_t) buf + userbuf_off));
235 ADIO_WriteContig(fd, (char *) buf + userbuf_off, (int) req_len, MPI_BYTE,
236 ADIO_EXPLICIT_OFFSET, req_off, &status1, error_code);
237 if (*error_code != MPI_SUCCESS)
238 return;
239 }
240 userbuf_off += fwr_size;
241
242 if (off + fwr_size < disp + flat_file->indices[f_index] +
243 flat_file->blocklens[f_index] + n_filetypes * (ADIO_Offset) filetype_extent) {
244 /* important that this value be correct, as it is
245 * used to set the offset in the fd near the end of
246 * this function.
247 */
248 off += fwr_size;
249 }
250 /* did not reach end of contiguous block in filetype.
251 * no more I/O needed. off is incremented by fwr_size.
252 */
253 else {
254 if (f_index < (flat_file->count - 1))
255 f_index++;
256 else {
257 f_index = 0;
258 n_filetypes++;
259 }
260 off = disp + flat_file->indices[f_index] +
261 n_filetypes * (ADIO_Offset) filetype_extent;
262 fwr_size = MPL_MIN(flat_file->blocklens[f_index],
263 bufsize - (unsigned) userbuf_off);
264 }
265 }
266 } else {
267 ADIO_Offset i_offset, tmp_bufsize = 0;
268 /* noncontiguous in memory as well as in file */
269
270 flat_buf = ADIOI_Flatten_and_find(buftype);
271
272 b_index = buf_count = 0;
273 i_offset = flat_buf->indices[0];
274 f_index = st_index;
275 off = start_off;
276 n_filetypes = st_n_filetypes;
277 fwr_size = st_fwr_size;
278 bwr_size = flat_buf->blocklens[0];
279
280 /* while we haven't read size * count bytes, keep going */
281 while (tmp_bufsize < bufsize) {
282 ADIO_Offset new_bwr_size = bwr_size, new_fwr_size = fwr_size;
283
284 size = MPL_MIN(fwr_size, bwr_size);
285 /* keep max of a single read amount <= INT_MAX */
286 size = MPL_MIN(size, INT_MAX);
287
288 if (size) {
289 req_off = off;
290 req_len = size;
291 userbuf_off = i_offset;
292
293 ADIOI_Assert(req_len == (int) req_len);
294 ADIOI_Assert((((ADIO_Offset) (uintptr_t) buf) + userbuf_off) ==
295 (ADIO_Offset) (uintptr_t) ((uintptr_t) buf + userbuf_off));
296 ADIO_WriteContig(fd, (char *) buf + userbuf_off, (int) req_len, MPI_BYTE,
297 ADIO_EXPLICIT_OFFSET, req_off, &status1, error_code);
298 if (*error_code != MPI_SUCCESS)
299 return;
300 }
301
302 if (size == fwr_size) {
303 /* reached end of contiguous block in file */
304 if (f_index < (flat_file->count - 1))
305 f_index++;
306 else {
307 f_index = 0;
308 n_filetypes++;
309 }
310
311 off = disp + flat_file->indices[f_index] +
312 n_filetypes * (ADIO_Offset) filetype_extent;
313
314 new_fwr_size = flat_file->blocklens[f_index];
315 if (size != bwr_size) {
316 i_offset += size;
317 new_bwr_size -= size;
318 }
319 }
320
321 if (size == bwr_size) {
322 /* reached end of contiguous block in memory */
323
324 b_index = (b_index + 1) % flat_buf->count;
325 buf_count++;
326 i_offset =
327 (ADIO_Offset) buftype_extent *(ADIO_Offset) (buf_count / flat_buf->count) +
328 flat_buf->indices[b_index];
329 new_bwr_size = flat_buf->blocklens[b_index];
330 if (size != fwr_size) {
331 off += size;
332 new_fwr_size -= size;
333 }
334 }
335 tmp_bufsize += size;
336 fwr_size = new_fwr_size;
337 bwr_size = new_bwr_size;
338 }
339 }
340
341 /* unlock the file region if we locked it */
342 if ((fd->atomicity) && ADIO_Feature(fd, ADIO_LOCKS)) {
343 ADIOI_UNLOCK(fd, start_off, SEEK_SET, end_offset - start_off + 1);
344 }
345
346 if (file_ptr_type == ADIO_INDIVIDUAL)
347 fd->fp_ind = off;
348 } /* end of (else noncontiguous in file) */
349
350 fd->fp_sys_posn = -1; /* mark it as invalid. */
351
352 #ifdef HAVE_STATUS_SET_BYTES
353 MPIR_Status_set_bytes(status, buftype, bufsize);
354 /* This is a temporary way of filling in status. The right way is to
355 * keep track of how much data was actually written and placed in buf
356 */
357 #endif
358
359 }
360