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