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