1 /* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil ; -*- */
2 /*
3 *
4 * Copyright (C) 1997 University of Chicago.
5 * See COPYRIGHT notice in top-level directory.
6 */
7
8 #include "adio.h"
9 #include "adio_extern.h"
10
11 #define ADIOI_BUFFERED_WRITE \
12 { \
13 if (req_off >= writebuf_off + writebuf_len) { \
14 if (writebuf_len) { \
15 ADIO_WriteContig(fd, writebuf, writebuf_len, MPI_BYTE, \
16 ADIO_EXPLICIT_OFFSET, writebuf_off, &status1, error_code); \
17 if (!(fd->atomicity)) ADIOI_UNLOCK(fd, writebuf_off, SEEK_SET, writebuf_len); \
18 if (*error_code != MPI_SUCCESS) { \
19 *error_code = MPIO_Err_create_code(*error_code, \
20 MPIR_ERR_RECOVERABLE, myname, \
21 __LINE__, MPI_ERR_IO, \
22 "**iowswc", 0); \
23 goto fn_exit; \
24 } \
25 } \
26 writebuf_off = req_off; \
27 writebuf_len = (unsigned) (ADIOI_MIN(max_bufsize,end_offset-writebuf_off+1));\
28 if (!(fd->atomicity)) ADIOI_WRITE_LOCK(fd, writebuf_off, SEEK_SET, writebuf_len); \
29 ADIO_ReadContig(fd, writebuf, writebuf_len, MPI_BYTE, \
30 ADIO_EXPLICIT_OFFSET, writebuf_off, &status1, error_code); \
31 if (*error_code != MPI_SUCCESS) { \
32 *error_code = MPIO_Err_create_code(*error_code, \
33 MPIR_ERR_RECOVERABLE, myname, \
34 __LINE__, MPI_ERR_IO, \
35 "**iowsrc", 0); \
36 goto fn_exit; \
37 } \
38 } \
39 write_sz = (unsigned) (ADIOI_MIN(req_len, writebuf_off + writebuf_len - req_off)); \
40 ADIOI_Assert((ADIO_Offset)write_sz == ADIOI_MIN(req_len, writebuf_off + writebuf_len - req_off));\
41 memcpy(writebuf+req_off-writebuf_off, (char *)buf +userbuf_off, write_sz);\
42 while (write_sz != req_len) { \
43 ADIO_WriteContig(fd, writebuf, writebuf_len, MPI_BYTE, \
44 ADIO_EXPLICIT_OFFSET, writebuf_off, &status1, error_code); \
45 if (!(fd->atomicity)) ADIOI_UNLOCK(fd, writebuf_off, SEEK_SET, writebuf_len); \
46 if (*error_code != MPI_SUCCESS) { \
47 *error_code = MPIO_Err_create_code(*error_code, \
48 MPIR_ERR_RECOVERABLE, myname, \
49 __LINE__, MPI_ERR_IO, \
50 "**iowswc", 0); \
51 goto fn_exit; \
52 } \
53 req_len -= write_sz; \
54 userbuf_off += write_sz; \
55 writebuf_off += writebuf_len; \
56 writebuf_len = (unsigned) (ADIOI_MIN(max_bufsize,end_offset-writebuf_off+1));\
57 if (!(fd->atomicity)) ADIOI_WRITE_LOCK(fd, writebuf_off, SEEK_SET, writebuf_len); \
58 ADIO_ReadContig(fd, writebuf, writebuf_len, MPI_BYTE, \
59 ADIO_EXPLICIT_OFFSET, writebuf_off, &status1, error_code); \
60 if (*error_code != MPI_SUCCESS) { \
61 *error_code = MPIO_Err_create_code(*error_code, \
62 MPIR_ERR_RECOVERABLE, myname, \
63 __LINE__, MPI_ERR_IO, \
64 "**iowsrc", 0); \
65 goto fn_exit; \
66 } \
67 write_sz = ADIOI_MIN(req_len, writebuf_len); \
68 memcpy(writebuf, (char *)buf + userbuf_off, write_sz);\
69 } \
70 }
71
72
73 /* this macro is used when filetype is contig and buftype is not contig.
74 it does not do a read-modify-write and does not lock*/
75 #define ADIOI_BUFFERED_WRITE_WITHOUT_READ \
76 { \
77 if (req_off >= writebuf_off + writebuf_len) { \
78 ADIO_WriteContig(fd, writebuf, writebuf_len, MPI_BYTE, \
79 ADIO_EXPLICIT_OFFSET, writebuf_off, &status1, error_code); \
80 if (*error_code != MPI_SUCCESS) { \
81 *error_code = MPIO_Err_create_code(*error_code, \
82 MPIR_ERR_RECOVERABLE, myname, \
83 __LINE__, MPI_ERR_IO, \
84 "**iowswc", 0); \
85 goto fn_exit; \
86 } \
87 writebuf_off = req_off; \
88 writebuf_len = (unsigned) (ADIOI_MIN(max_bufsize,end_offset-writebuf_off+1));\
89 } \
90 write_sz = (unsigned) (ADIOI_MIN(req_len, writebuf_off + writebuf_len - req_off)); \
91 ADIOI_Assert((ADIO_Offset)write_sz == ADIOI_MIN(req_len, writebuf_off + writebuf_len - req_off));\
92 memcpy(writebuf+req_off-writebuf_off, (char *)buf +userbuf_off, write_sz);\
93 while (write_sz != req_len) { \
94 ADIO_WriteContig(fd, writebuf, writebuf_len, MPI_BYTE, \
95 ADIO_EXPLICIT_OFFSET, writebuf_off, &status1, error_code); \
96 if (*error_code != MPI_SUCCESS) { \
97 *error_code = MPIO_Err_create_code(*error_code, \
98 MPIR_ERR_RECOVERABLE, myname, \
99 __LINE__, MPI_ERR_IO, \
100 "**iowswc", 0); \
101 goto fn_exit; \
102 } \
103 req_len -= write_sz; \
104 userbuf_off += write_sz; \
105 writebuf_off += writebuf_len; \
106 writebuf_len = (unsigned) (ADIOI_MIN(max_bufsize,end_offset-writebuf_off+1));\
107 write_sz = ADIOI_MIN(req_len, writebuf_len); \
108 memcpy(writebuf, (char *)buf + userbuf_off, write_sz);\
109 } \
110 }
ADIOI_GEN_WriteStrided(ADIO_File fd,const void * buf,int count,MPI_Datatype datatype,int file_ptr_type,ADIO_Offset offset,ADIO_Status * status,int * error_code)111 void ADIOI_GEN_WriteStrided(ADIO_File fd, const void *buf, int count,
112 MPI_Datatype datatype, int file_ptr_type,
113 ADIO_Offset offset, ADIO_Status *status, int
114 *error_code)
115 {
116
117 /* offset is in units of etype relative to the filetype. */
118
119 ADIOI_Flatlist_node *flat_buf, *flat_file;
120 ADIO_Offset i_offset, sum, size_in_filetype;
121 int i, j, k, st_index=0;
122 ADIO_Offset num, size, n_filetypes, etype_in_filetype, st_n_filetypes;
123 ADIO_Offset n_etypes_in_filetype, abs_off_in_filetype=0;
124 MPI_Count filetype_size, etype_size, buftype_size;
125 MPI_Aint filetype_extent, buftype_extent, lb;
126 int buf_count, buftype_is_contig, filetype_is_contig;
127 ADIO_Offset userbuf_off;
128 ADIO_Offset off, req_off, disp, end_offset=0, writebuf_off, start_off;
129 char *writebuf=NULL;
130 unsigned writebuf_len, max_bufsize, write_sz;
131 MPI_Aint bufsize;
132 ADIO_Status status1;
133 ADIO_Offset new_bwr_size, new_fwr_size, st_fwr_size, fwr_size=0, bwr_size, req_len;
134 static char myname[] = "ADIOI_GEN_WriteStrided";
135
136 if (fd->hints->ds_write == ADIOI_HINT_DISABLE) {
137 /* if user has disabled data sieving on reads, use naive
138 * approach instead.
139 */
140
141 ADIOI_GEN_WriteStrided_naive(fd,
142 buf,
143 count,
144 datatype,
145 file_ptr_type,
146 offset,
147 status,
148 error_code);
149 return;
150 }
151
152
153 *error_code = MPI_SUCCESS; /* changed below if error */
154
155 ADIOI_Datatype_iscontig(datatype, &buftype_is_contig);
156 ADIOI_Datatype_iscontig(fd->filetype, &filetype_is_contig);
157
158 MPI_Type_size_x(fd->filetype, &filetype_size);
159 if ( ! filetype_size ) {
160 #ifdef HAVE_STATUS_SET_BYTES
161 MPIR_Status_set_bytes(status, datatype, 0);
162 #endif
163 *error_code = MPI_SUCCESS;
164 return;
165 }
166
167 MPI_Type_get_extent(fd->filetype, &lb, &filetype_extent);
168 MPI_Type_size_x(datatype, &buftype_size);
169 MPI_Type_get_extent(datatype, &lb, &buftype_extent);
170 etype_size = fd->etype_size;
171
172 ADIOI_Assert((buftype_size * count) == ((MPI_Count)buftype_size * (ADIO_Offset)count));
173 bufsize = buftype_size * count;
174
175 /* get max_bufsize from the info object. */
176
177 max_bufsize = fd->hints->ind_wr_buffer_size;
178
179 if (!buftype_is_contig && filetype_is_contig) {
180
181 /* noncontiguous in memory, contiguous in file. */
182
183 flat_buf = ADIOI_Flatten_and_find(datatype);
184
185 off = (file_ptr_type == ADIO_INDIVIDUAL) ? fd->fp_ind :
186 fd->disp + (ADIO_Offset)etype_size * offset;
187
188 start_off = off;
189 end_offset = off + bufsize - 1;
190 writebuf_off = off;
191 writebuf = (char *) ADIOI_Malloc(max_bufsize);
192 writebuf_len = (unsigned) (ADIOI_MIN(max_bufsize, end_offset-writebuf_off+1));
193
194 /* if atomicity is true, lock the region to be accessed */
195 if (fd->atomicity)
196 ADIOI_WRITE_LOCK(fd, start_off, SEEK_SET, end_offset-start_off+1);
197
198 for (j=0; j<count; j++)
199 {
200 for (i=0; i<flat_buf->count; i++) {
201 userbuf_off = (ADIO_Offset)j*(ADIO_Offset)buftype_extent + flat_buf->indices[i];
202 req_off = off;
203 req_len = flat_buf->blocklens[i];
204 ADIOI_BUFFERED_WRITE_WITHOUT_READ
205 off += flat_buf->blocklens[i];
206 }
207 }
208
209 /* write the buffer out finally */
210 ADIO_WriteContig(fd, writebuf, writebuf_len, MPI_BYTE, ADIO_EXPLICIT_OFFSET,
211 writebuf_off, &status1, error_code);
212
213 if (fd->atomicity)
214 ADIOI_UNLOCK(fd, start_off, SEEK_SET, end_offset-start_off+1);
215
216 if (*error_code != MPI_SUCCESS) goto fn_exit;
217
218 if (file_ptr_type == ADIO_INDIVIDUAL) fd->fp_ind = off;
219 }
220
221 else { /* noncontiguous in file */
222
223 /* filetype already flattened in ADIO_Open */
224 flat_file = ADIOI_Flatlist;
225 while (flat_file->type != fd->filetype) flat_file = flat_file->next;
226 disp = fd->disp;
227
228 if (file_ptr_type == ADIO_INDIVIDUAL) {
229 /* Wei-keng reworked type processing to be a bit more efficient */
230 offset = fd->fp_ind - disp;
231 n_filetypes = (offset - flat_file->indices[0]) / filetype_extent;
232 offset -= (ADIO_Offset)n_filetypes * filetype_extent;
233 /* now offset is local to this extent */
234
235 /* find the block where offset is located, skip blocklens[i]==0 */
236 for (i=0; i<flat_file->count; i++) {
237 ADIO_Offset dist;
238 if (flat_file->blocklens[i] == 0) continue;
239 dist = flat_file->indices[i] + flat_file->blocklens[i] - offset;
240 /* fwr_size is from offset to the end of block i */
241 if (dist == 0) {
242 i++;
243 offset = flat_file->indices[i];
244 fwr_size = flat_file->blocklens[i];
245 break;
246 }
247 if (dist > 0) {
248 fwr_size = dist;
249 break;
250 }
251 }
252 st_index = i; /* starting index in flat_file->indices[] */
253 offset += disp + (ADIO_Offset)n_filetypes*filetype_extent;
254 }
255 else {
256 n_etypes_in_filetype = filetype_size/etype_size;
257 n_filetypes = offset / n_etypes_in_filetype;
258 etype_in_filetype = offset % n_etypes_in_filetype;
259 size_in_filetype = etype_in_filetype * etype_size;
260
261 sum = 0;
262 for (i=0; i<flat_file->count; i++) {
263 sum += flat_file->blocklens[i];
264 if (sum > size_in_filetype) {
265 st_index = i;
266 fwr_size = sum - size_in_filetype;
267 abs_off_in_filetype = flat_file->indices[i] +
268 size_in_filetype - (sum - flat_file->blocklens[i]);
269 break;
270 }
271 }
272
273 /* abs. offset in bytes in the file */
274 offset = disp + (ADIO_Offset) n_filetypes*filetype_extent +
275 abs_off_in_filetype;
276 }
277
278 start_off = offset;
279
280 /* Wei-keng Liao:write request is within single flat_file contig block*/
281 /* this could happen, for example, with subarray types that are
282 * actually fairly contiguous */
283 if (buftype_is_contig && bufsize <= fwr_size) {
284 /* though MPI api has an integer 'count' parameter, derived
285 * datatypes might describe more bytes than can fit into an integer.
286 * if we've made it this far, we can pass a count of original
287 * datatypes, instead of a count of bytes (which might overflow)
288 * Other WriteContig calls in this path are operating on data
289 * sieving buffer */
290 ADIO_WriteContig(fd, buf, count, datatype, ADIO_EXPLICIT_OFFSET,
291 offset, status, error_code);
292
293 if (file_ptr_type == ADIO_INDIVIDUAL) {
294 /* update MPI-IO file pointer to point to the first byte
295 * that can be accessed in the fileview. */
296 fd->fp_ind = offset + bufsize;
297 if (bufsize == fwr_size) {
298 do {
299 st_index++;
300 if (st_index == flat_file->count) {
301 st_index = 0;
302 n_filetypes++;
303 }
304 } while (flat_file->blocklens[st_index] == 0);
305 fd->fp_ind = disp + flat_file->indices[st_index]
306 + (ADIO_Offset)n_filetypes*filetype_extent;
307 }
308 }
309 fd->fp_sys_posn = -1; /* set it to null. */
310 #ifdef HAVE_STATUS_SET_BYTES
311 MPIR_Status_set_bytes(status, datatype, bufsize);
312 #endif
313 goto fn_exit;
314 }
315
316 /* Calculate end_offset, the last byte-offset that will be accessed.
317 e.g., if start_offset=0 and 100 bytes to be write, end_offset=99*/
318
319 st_fwr_size = fwr_size;
320 st_n_filetypes = n_filetypes;
321 i_offset = 0;
322 j = st_index;
323 off = offset;
324 fwr_size = ADIOI_MIN(st_fwr_size, bufsize);
325 while (i_offset < bufsize) {
326 i_offset += fwr_size;
327 end_offset = off + fwr_size - 1;
328
329 j = (j+1) % flat_file->count;
330 n_filetypes += (j == 0) ? 1 : 0;
331 while (flat_file->blocklens[j]==0) {
332 j = (j+1) % flat_file->count;
333 n_filetypes += (j == 0) ? 1 : 0;
334 }
335
336 off = disp + flat_file->indices[j] +
337 n_filetypes*(ADIO_Offset)filetype_extent;
338 fwr_size = ADIOI_MIN(flat_file->blocklens[j], bufsize-i_offset);
339 }
340
341 /* if atomicity is true, lock the region to be accessed */
342 if (fd->atomicity)
343 ADIOI_WRITE_LOCK(fd, start_off, SEEK_SET, end_offset-start_off+1);
344
345 writebuf_off = 0;
346 writebuf_len = 0;
347 writebuf = (char *) ADIOI_Malloc(max_bufsize);
348 memset(writebuf, -1, max_bufsize);
349
350 if (buftype_is_contig && !filetype_is_contig) {
351
352 /* contiguous in memory, noncontiguous in file. should be the most
353 common case. */
354
355 i_offset = 0;
356 j = st_index;
357 off = offset;
358 n_filetypes = st_n_filetypes;
359 fwr_size = ADIOI_MIN(st_fwr_size, bufsize);
360 while (i_offset < bufsize) {
361 if (fwr_size) {
362 /* TYPE_UB and TYPE_LB can result in
363 fwr_size = 0. save system call in such cases */
364 /* lseek(fd->fd_sys, off, SEEK_SET);
365 err = write(fd->fd_sys, ((char *) buf) + i_offset, fwr_size);*/
366
367 req_off = off;
368 req_len = fwr_size;
369 userbuf_off = i_offset;
370 ADIOI_BUFFERED_WRITE
371 }
372 i_offset += fwr_size;
373
374 if (off + fwr_size < disp + flat_file->indices[j] +
375 flat_file->blocklens[j] + n_filetypes*(ADIO_Offset)filetype_extent)
376 off += fwr_size;
377 /* did not reach end of contiguous block in filetype.
378 no more I/O needed. off is incremented by fwr_size. */
379 else {
380 j = (j+1) % flat_file->count;
381 n_filetypes += (j == 0) ? 1 : 0;
382 while (flat_file->blocklens[j]==0) {
383 j = (j+1) % flat_file->count;
384 n_filetypes += (j == 0) ? 1 : 0;
385 }
386 off = disp + flat_file->indices[j] +
387 n_filetypes*(ADIO_Offset)filetype_extent;
388 fwr_size = ADIOI_MIN(flat_file->blocklens[j],
389 bufsize-i_offset);
390 }
391 }
392 }
393 else {
394 /* noncontiguous in memory as well as in file */
395
396 flat_buf = ADIOI_Flatten_and_find(datatype);
397
398 k = num = buf_count = 0;
399 i_offset = flat_buf->indices[0];
400 j = st_index;
401 off = offset;
402 n_filetypes = st_n_filetypes;
403 fwr_size = st_fwr_size;
404 bwr_size = flat_buf->blocklens[0];
405
406 while (num < bufsize) {
407 size = ADIOI_MIN(fwr_size, bwr_size);
408 if (size) {
409 /* lseek(fd->fd_sys, off, SEEK_SET);
410 err = write(fd->fd_sys, ((char *) buf) + i_offset, size); */
411
412 req_off = off;
413 req_len = size;
414 userbuf_off = i_offset;
415 ADIOI_BUFFERED_WRITE
416 }
417
418 new_fwr_size = fwr_size;
419 new_bwr_size = bwr_size;
420
421 if (size == fwr_size) {
422 /* reached end of contiguous block in file */
423 j = (j+1) % flat_file->count;
424 n_filetypes += (j == 0) ? 1 : 0;
425 while (flat_file->blocklens[j]==0) {
426 j = (j+1) % flat_file->count;
427 n_filetypes += (j == 0) ? 1 : 0;
428 }
429
430 off = disp + flat_file->indices[j] +
431 n_filetypes*(ADIO_Offset)filetype_extent;
432
433 new_fwr_size = flat_file->blocklens[j];
434 if (size != bwr_size) {
435 i_offset += size;
436 new_bwr_size -= size;
437 }
438 }
439
440 if (size == bwr_size) {
441 /* reached end of contiguous block in memory */
442
443 k = (k + 1)%flat_buf->count;
444 buf_count++;
445 i_offset = (ADIO_Offset)buftype_extent*(ADIO_Offset)(buf_count/flat_buf->count) +
446 flat_buf->indices[k];
447 new_bwr_size = flat_buf->blocklens[k];
448 if (size != fwr_size) {
449 off += size;
450 new_fwr_size -= size;
451 }
452 }
453 num += size;
454 fwr_size = new_fwr_size;
455 bwr_size = new_bwr_size;
456 }
457 }
458
459 /* write the buffer out finally */
460 if (writebuf_len) {
461 ADIO_WriteContig(fd, writebuf, writebuf_len, MPI_BYTE, ADIO_EXPLICIT_OFFSET,
462 writebuf_off, &status1, error_code);
463 if (!(fd->atomicity))
464 ADIOI_UNLOCK(fd, writebuf_off, SEEK_SET, writebuf_len);
465 if (*error_code != MPI_SUCCESS) goto fn_exit;
466 }
467 if (fd->atomicity)
468 ADIOI_UNLOCK(fd, start_off, SEEK_SET, end_offset-start_off+1);
469
470 if (file_ptr_type == ADIO_INDIVIDUAL) fd->fp_ind = off;
471 }
472
473 fd->fp_sys_posn = -1; /* set it to null. */
474
475 #ifdef HAVE_STATUS_SET_BYTES
476 /* datatypes returning negagive values, probably related to tt 1893 */
477 MPIR_Status_set_bytes(status, datatype, bufsize);
478 /* This is a temporary way of filling in status. The right way is to
479 keep track of how much data was actually written by ADIOI_BUFFERED_WRITE. */
480 #endif
481
482 if (!buftype_is_contig) ADIOI_Delete_flattened(datatype);
483 fn_exit:
484 if (writebuf != NULL) ADIOI_Free(writebuf);
485 }
486
487