source: GenericIO.h @ 14e73bb

Revision 14e73bb, 13.0 KB checked in by Hal Finkel <hfinkel@…>, 8 years ago (diff)

Misc. improvements to splitting and error handling

  • Property mode set to 100644
Line 
1/*
2 *                    Copyright (C) 2015, UChicago Argonne, LLC
3 *                               All Rights Reserved
4 *
5 *                               Generic IO (ANL-15-066)
6 *                     Hal Finkel, Argonne National Laboratory
7 *
8 *                              OPEN SOURCE LICENSE
9 *
10 * Under the terms of Contract No. DE-AC02-06CH11357 with UChicago Argonne,
11 * LLC, the U.S. Government retains certain rights in this software.
12 *
13 * Redistribution and use in source and binary forms, with or without
14 * modification, are permitted provided that the following conditions are met:
15 *
16 *   1. Redistributions of source code must retain the above copyright notice,
17 *      this list of conditions and the following disclaimer.
18 *
19 *   2. Redistributions in binary form must reproduce the above copyright
20 *      notice, this list of conditions and the following disclaimer in the
21 *      documentation and/or other materials provided with the distribution.
22 *
23 *   3. Neither the names of UChicago Argonne, LLC or the Department of Energy
24 *      nor the names of its contributors may be used to endorse or promote
25 *      products derived from this software without specific prior written
26 *      permission.
27 *
28 * *****************************************************************************
29 *
30 *                                  DISCLAIMER
31 * THE SOFTWARE IS SUPPLIED “AS IS” WITHOUT WARRANTY OF ANY KIND.  NEITHER THE
32 * UNTED STATES GOVERNMENT, NOR THE UNITED STATES DEPARTMENT OF ENERGY, NOR
33 * UCHICAGO ARGONNE, LLC, NOR ANY OF THEIR EMPLOYEES, MAKES ANY WARRANTY,
34 * EXPRESS OR IMPLIED, OR ASSUMES ANY LEGAL LIABILITY OR RESPONSIBILITY FOR THE
35 * ACCURACY, COMPLETENESS, OR USEFULNESS OF ANY INFORMATION, DATA, APPARATUS,
36 * PRODUCT, OR PROCESS DISCLOSED, OR REPRESENTS THAT ITS USE WOULD NOT INFRINGE
37 * PRIVATELY OWNED RIGHTS.
38 *
39 * *****************************************************************************
40 */
41
42#ifndef GENERICIO_H
43#define GENERICIO_H
44
45#include <cstdlib>
46#include <vector>
47#include <string>
48#include <iostream>
49#include <limits>
50#include <stdint.h>
51
52#ifndef GENERICIO_NO_MPI
53#include <mpi.h>
54#else
55#include <fstream>
56#endif
57
58#include <unistd.h>
59
60namespace gio {
61
62class GenericFileIO {
63public:
64  virtual ~GenericFileIO() {}
65
66public:
67  virtual void open(const std::string &FN, bool ForReading = false) = 0;
68  virtual void setSize(size_t sz) = 0;
69  virtual void read(void *buf, size_t count, off_t offset,
70                    const std::string &D) = 0;
71  virtual void write(const void *buf, size_t count, off_t offset,
72                     const std::string &D) = 0;
73
74protected:
75  std::string FileName;
76};
77
78#ifndef GENERICIO_NO_MPI
79class GenericFileIO_MPI : public GenericFileIO {
80public:
81  GenericFileIO_MPI(const MPI_Comm &C) : FH(MPI_FILE_NULL), Comm(C) {}
82  virtual ~GenericFileIO_MPI();
83
84public:
85  virtual void open(const std::string &FN, bool ForReading = false);
86  virtual void setSize(size_t sz);
87  virtual void read(void *buf, size_t count, off_t offset, const std::string &D);
88  virtual void write(const void *buf, size_t count, off_t offset, const std::string &D);
89
90protected:
91  MPI_File FH;
92  MPI_Comm Comm;
93};
94
95class GenericFileIO_MPICollective : public GenericFileIO_MPI {
96public:
97  GenericFileIO_MPICollective(const MPI_Comm &C) : GenericFileIO_MPI(C) {}
98
99public:
100  void read(void *buf, size_t count, off_t offset, const std::string &D);
101  void write(const void *buf, size_t count, off_t offset, const std::string &D);
102};
103#endif
104
105class GenericFileIO_POSIX : public GenericFileIO {
106public:
107  GenericFileIO_POSIX() : FH(-1) {}
108  ~GenericFileIO_POSIX();
109
110public:
111  void open(const std::string &FN, bool ForReading = false);
112  void setSize(size_t sz);
113  void read(void *buf, size_t count, off_t offset, const std::string &D);
114  void write(const void *buf, size_t count, off_t offset, const std::string &D);
115
116protected:
117  int FH;
118};
119
120class GenericIO {
121public:
122  enum VariableFlags {
123    VarHasExtraSpace =  (1 << 0), // Note that this flag indicates that the
124                                  // extra space is available, but the GenericIO
125                                  // implementation is required to
126                                  // preserve its contents.
127    VarIsPhysCoordX  =  (1 << 1),
128    VarIsPhysCoordY  =  (1 << 2),
129    VarIsPhysCoordZ  =  (1 << 3),
130    VarMaybePhysGhost = (1 << 4)
131  };
132
133  struct VariableInfo {
134    VariableInfo(const std::string &N, std::size_t S, bool IF, bool IS,
135                 bool PCX, bool PCY, bool PCZ, bool PG)
136      : Name(N), Size(S), IsFloat(IF), IsSigned(IS),
137        IsPhysCoordX(PCX), IsPhysCoordY(PCY), IsPhysCoordZ(PCZ),
138        MaybePhysGhost(PG) {}
139
140    std::string Name;
141    std::size_t Size;
142    bool IsFloat;
143    bool IsSigned;
144    bool IsPhysCoordX, IsPhysCoordY, IsPhysCoordZ;
145    bool MaybePhysGhost;
146  };
147
148public:
149  struct Variable {
150    template <typename T>
151    Variable(const std::string &N, T* D, unsigned Flags = 0)
152      : Name(N), Size(sizeof(T)),
153        IsFloat(!std::numeric_limits<T>::is_integer),
154        IsSigned(std::numeric_limits<T>::is_signed),
155        Data((void *) D), HasExtraSpace(Flags & VarHasExtraSpace),
156        IsPhysCoordX(Flags & VarIsPhysCoordX),
157        IsPhysCoordY(Flags & VarIsPhysCoordY),
158        IsPhysCoordZ(Flags & VarIsPhysCoordZ),
159        MaybePhysGhost(Flags & VarMaybePhysGhost) {}
160
161    Variable(const VariableInfo &VI, void *D, unsigned Flags = 0)
162      : Name(VI.Name), Size(VI.Size), IsFloat(VI.IsFloat),
163        IsSigned(VI.IsSigned), Data(D),
164        HasExtraSpace(Flags & VarHasExtraSpace),
165        IsPhysCoordX((Flags & VarIsPhysCoordX) || VI.IsPhysCoordX),
166        IsPhysCoordY((Flags & VarIsPhysCoordY) || VI.IsPhysCoordY),
167        IsPhysCoordZ((Flags & VarIsPhysCoordZ) || VI.IsPhysCoordZ),
168        MaybePhysGhost((Flags & VarMaybePhysGhost) || VI.MaybePhysGhost) {}
169
170    std::string Name;
171    std::size_t Size;
172    bool IsFloat;
173    bool IsSigned;
174    void *Data;
175    bool HasExtraSpace;
176    bool IsPhysCoordX, IsPhysCoordY, IsPhysCoordZ;
177    bool MaybePhysGhost;
178  };
179
180public:
181  enum FileIO {
182    FileIOMPI,
183    FileIOPOSIX,
184    FileIOMPICollective
185  };
186
187#ifndef GENERICIO_NO_MPI
188  GenericIO(const MPI_Comm &C, const std::string &FN, unsigned FIOT = -1)
189    : NElems(0), FileIOType(FIOT == (unsigned) -1 ? DefaultFileIOType : FIOT),
190      Partition(DefaultPartition), Comm(C), FileName(FN), Redistributing(false),
191      DisableCollErrChecking(false), SplitComm(MPI_COMM_NULL) {
192    std::fill(PhysOrigin, PhysOrigin + 3, 0.0);
193    std::fill(PhysScale,  PhysScale + 3, 0.0);
194  }
195#else
196  GenericIO(const std::string &FN, unsigned FIOT = -1)
197    : NElems(0), FileIOType(FIOT == (unsigned) -1 ? DefaultFileIOType : FIOT),
198      Partition(DefaultPartition), FileName(FN), Redistributing(false),
199      DisableCollErrChecking(false) {
200    std::fill(PhysOrigin, PhysOrigin + 3, 0.0);
201    std::fill(PhysScale,  PhysScale + 3, 0.0);
202  }
203#endif
204
205  ~GenericIO() {
206    close();
207
208#ifndef GENERICIO_NO_MPI
209    if (SplitComm != MPI_COMM_NULL)
210      MPI_Comm_free(&SplitComm);
211#endif
212  }
213
214public:
215  std::size_t requestedExtraSpace() const {
216    return 8;
217  }
218
219  void setNumElems(std::size_t E) {
220    NElems = E;
221
222#ifndef GENERICIO_NO_MPI
223    int IsLarge = E >= CollectiveMPIIOThreshold;
224    int AllIsLarge;
225    MPI_Allreduce(&IsLarge, &AllIsLarge, 1, MPI_INT, MPI_SUM, Comm);
226    if (!AllIsLarge)
227      FileIOType = FileIOMPICollective;
228#endif
229  }
230
231  void setPhysOrigin(double O, int Dim = -1) {
232    if (Dim >= 0)
233      PhysOrigin[Dim] = O;
234    else
235      std::fill(PhysOrigin, PhysOrigin + 3, O);
236  }
237
238  void setPhysScale(double S, int Dim = -1) {
239    if (Dim >= 0)
240      PhysScale[Dim] = S;
241    else
242      std::fill(PhysScale,  PhysScale + 3, S);
243  }
244
245  template <typename T>
246  void addVariable(const std::string &Name, T *Data,
247                   unsigned Flags = 0) {
248    Vars.push_back(Variable(Name, Data, Flags));
249  }
250
251  template <typename T, typename A>
252  void addVariable(const std::string &Name, std::vector<T, A> &Data,
253                   unsigned Flags = 0) {
254    T *D = Data.empty() ? 0 : &Data[0];
255    addVariable(Name, D, Flags);
256  }
257
258  void addVariable(const VariableInfo &VI, void *Data,
259                   unsigned Flags = 0) {
260    Vars.push_back(Variable(VI, Data, Flags));
261  }
262
263#ifndef GENERICIO_NO_MPI
264  // Writing
265  void write();
266#endif
267
268  enum MismatchBehavior {
269    MismatchAllowed,
270    MismatchDisallowed,
271    MismatchRedistribute
272  };
273
274  // Reading
275  void openAndReadHeader(MismatchBehavior MB = MismatchDisallowed,
276                         int EffRank = -1, bool CheckPartMap = true);
277
278  int readNRanks();
279  void readDims(int Dims[3]);
280
281  // Note: For partitioned inputs, this returns -1.
282  uint64_t readTotalNumElems();
283
284  void readPhysOrigin(double Origin[3]);
285  void readPhysScale(double Scale[3]);
286
287  void clearVariables() { this->Vars.clear(); };
288
289  int getNumberOfVariables() { return this->Vars.size(); };
290
291  void getVariableInfo(std::vector<VariableInfo> &VI);
292
293  std::size_t readNumElems(int EffRank = -1);
294  void readCoords(int Coords[3], int EffRank = -1);
295  int readGlobalRankNumber(int EffRank = -1);
296
297  void readData(int EffRank = -1, bool PrintStats = true, bool CollStats = true);
298
299  void getSourceRanks(std::vector<int> &SR);
300
301  void close() {
302    FH.close();
303  }
304
305  void setPartition(int P) {
306    Partition = P;
307  }
308
309  static void setDefaultFileIOType(unsigned FIOT) {
310    DefaultFileIOType = FIOT;
311  }
312
313  static void setDefaultPartition(int P) {
314    DefaultPartition = P;
315  }
316
317  static void setNaturalDefaultPartition();
318
319  static void setDefaultShouldCompress(bool C) {
320    DefaultShouldCompress = C;
321  }
322
323#ifndef GENERICIO_NO_MPI
324  static void setCollectiveMPIIOThreshold(std::size_t T) {
325#ifndef GENERICIO_NO_NEVER_USE_COLLECTIVE_IO
326    CollectiveMPIIOThreshold = T;
327#endif
328  }
329#endif
330
331private:
332  // Implementation functions templated on the Endianness of the underlying
333  // data.
334
335#ifndef GENERICIO_NO_MPI
336  template <bool IsBigEndian>
337  void write();
338#endif
339
340  template <bool IsBigEndian>
341  void readHeaderLeader(void *GHPtr, MismatchBehavior MB, int Rank, int NRanks,
342                        int SplitNRanks, std::string &LocalFileName,
343                        uint64_t &HeaderSize, std::vector<char> &Header);
344
345  template <bool IsBigEndian>
346  int readNRanks();
347
348  template <bool IsBigEndian>
349  void readDims(int Dims[3]);
350
351  template <bool IsBigEndian>
352  uint64_t readTotalNumElems();
353
354  template <bool IsBigEndian>
355  void readPhysOrigin(double Origin[3]);
356
357  template <bool IsBigEndian>
358  void readPhysScale(double Scale[3]);
359
360  template <bool IsBigEndian>
361  int readGlobalRankNumber(int EffRank);
362
363  template <bool IsBigEndian>
364  size_t readNumElems(int EffRank);
365
366  template <bool IsBigEndian>
367  void readCoords(int Coords[3], int EffRank);
368
369  void readData(int EffRank, size_t RowOffset, int Rank,
370                uint64_t &TotalReadSize, int NErrs[3]);
371
372  template <bool IsBigEndian>
373  void readData(int EffRank, size_t RowOffset,
374                int Rank, uint64_t &TotalReadSize, int NErrs[3]);
375
376  template <bool IsBigEndian>
377  void getVariableInfo(std::vector<VariableInfo> &VI);
378
379protected:
380  std::vector<Variable> Vars;
381  std::size_t NElems;
382
383  double PhysOrigin[3], PhysScale[3];
384
385  unsigned FileIOType;
386  int Partition;
387#ifndef GENERICIO_NO_MPI
388  MPI_Comm Comm;
389#endif
390  std::string FileName;
391
392  static unsigned DefaultFileIOType;
393  static int DefaultPartition;
394  static bool DefaultShouldCompress;
395
396#ifndef GENERICIO_NO_MPI
397  static std::size_t CollectiveMPIIOThreshold;
398#endif
399
400  // When redistributing, the rank blocks which this process should read.
401  bool Redistributing, DisableCollErrChecking;
402  std::vector<int> SourceRanks;
403
404  std::vector<int> RankMap;
405#ifndef GENERICIO_NO_MPI
406  MPI_Comm SplitComm;
407#endif
408  std::string OpenFileName;
409
410  // This reference counting mechanism allows the the GenericIO class
411  // to be used in a cursor mode. To do this, make a copy of the class
412  // after reading the header but prior to adding the variables.
413  struct FHManager {
414    FHManager() : CountedFH(0) {
415      allocate();
416    }
417
418    FHManager(const FHManager& F) {
419      CountedFH = F.CountedFH;
420      CountedFH->Cnt += 1;
421    }
422
423    ~FHManager() {
424      close();
425    }
426
427    GenericFileIO *&get() {
428      if (!CountedFH)
429        allocate();
430
431      return CountedFH->GFIO;
432    }
433
434    std::vector<char> &getHeaderCache() {
435      if (!CountedFH)
436        allocate();
437
438      return CountedFH->HeaderCache;
439    }
440
441    bool isBigEndian() {
442      return CountedFH ? CountedFH->IsBigEndian : false;
443    }
444
445    void setIsBigEndian(bool isBE) {
446      CountedFH->IsBigEndian = isBE;
447    }
448
449    void allocate() {
450      close();
451      CountedFH = new FHWCnt;
452    };
453
454    void close() {
455      if (CountedFH && CountedFH->Cnt == 1)
456        delete CountedFH;
457      else if (CountedFH)
458        CountedFH->Cnt -= 1;
459
460      CountedFH = 0;
461    }
462
463    struct FHWCnt {
464      FHWCnt() : GFIO(0), Cnt(1), IsBigEndian(false) {}
465
466      ~FHWCnt() {
467        close();
468      }
469
470protected:
471      void close() {
472        delete GFIO;
473        GFIO = 0;
474      }
475
476public:
477      GenericFileIO *GFIO;
478      size_t Cnt;
479
480      // Used for reading
481      std::vector<char> HeaderCache;
482      bool IsBigEndian;
483    };
484
485    FHWCnt *CountedFH;
486  } FH;
487};
488
489} /* END namespace cosmotk */
490#endif // GENERICIO_H
491
Note: See TracBrowser for help on using the repository browser.