source: GenericIO.h @ eeacdad

Revision eeacdad, 17.7 KB checked in by Hal Finkel <hfinkel@…>, 6 years ago (diff)

initial SZ integration - it compiles

  • 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
120namespace detail {
121// A standard enable_if idiom (we include our own here for pre-C++11 support).
122template <bool B, typename T = void>
123struct enable_if {};
124
125template <typename T>
126struct enable_if<true, T> { typedef T type; };
127
128// A SFINAE-based trait to detect whether a type has a member named x. This is
129// designed to work both with structs/classes and also with OpenCL-style vector
130// types.
131template <typename T>
132class has_x {
133  typedef char yes[1];
134  typedef char no[2];
135
136  template <typename C>
137  static yes &test(char(*)[sizeof((*((C *) 0)).x)]);
138
139  template <typename C>
140  static no &test(...);
141
142public:
143  enum { value = sizeof(test<T>(0)) == sizeof(yes) };
144};
145
146// A SFINAE-based trait to detect whether a type is array-like (i.e. supports
147// the [] operator).
148template <typename T>
149class is_array {
150  typedef char yes[1];
151  typedef char no[2];
152
153  template <typename C>
154  static yes &test(char(*)[sizeof((*((C *) 0))[0])]);
155
156  template <typename C>
157  static no &test(...);
158
159public:
160  enum { value = sizeof(test<T>(0)) == sizeof(yes) };
161};
162} // namespace detail
163
164class GenericIO {
165public:
166  enum VariableFlags {
167    VarHasExtraSpace =  (1 << 0), // Note that this flag indicates that the
168                                  // extra space is available, but the GenericIO
169                                  // implementation is required to
170                                  // preserve its contents.
171    VarIsPhysCoordX  =  (1 << 1),
172    VarIsPhysCoordY  =  (1 << 2),
173    VarIsPhysCoordZ  =  (1 << 3),
174    VarMaybePhysGhost = (1 << 4)
175  };
176
177  struct VariableInfo {
178    VariableInfo(const std::string &N, std::size_t S, bool IF, bool IS,
179                 bool PCX, bool PCY, bool PCZ, bool PG, std::size_t ES = 0)
180      : Name(N), Size(S), IsFloat(IF), IsSigned(IS),
181        IsPhysCoordX(PCX), IsPhysCoordY(PCY), IsPhysCoordZ(PCZ),
182        MaybePhysGhost(PG), ElementSize(ES ? ES : S) {}
183
184    std::string Name;
185    std::size_t Size;
186    bool IsFloat;
187    bool IsSigned;
188    bool IsPhysCoordX, IsPhysCoordY, IsPhysCoordZ;
189    bool MaybePhysGhost;
190    std::size_t ElementSize;
191  };
192
193public:
194  struct LossyCompressionInfo {
195    enum LCMode {
196      LCModeNone,
197      LCModeAbs,
198      LCModeRel,
199      LCModeAbsAndRel,
200      LCModeAbsOrRel,
201      LCModePSNR
202    };
203
204    LCMode Mode;
205    double AbsErrThreshold;
206    double RelErrThreshold;
207    double PSNRThreshold;
208
209    LossyCompressionInfo()
210      : Mode(LCModeNone), AbsErrThreshold(0.0),
211        RelErrThreshold(0.0), PSNRThreshold(0.0) {}
212  };
213
214  class Variable {
215  private:
216    template <typename ET>
217    void deduceTypeInfoFromElement(ET *) {
218      ElementSize = sizeof(ET);
219      IsFloat = !std::numeric_limits<ET>::is_integer;
220      IsSigned = std::numeric_limits<ET>::is_signed;
221    }
222
223    // There are specializations here to handle array types
224    // (e.g. typedef float float4[4];), struct types
225    // (e.g. struct float4 { float x, y, z, w; };), and scalar types.
226    // Builtin vector types
227    // (e.g. typedef float float4 __attribute__((ext_vector_type(4)));) should
228    // also work.
229    template <typename T>
230    typename detail::enable_if<detail::is_array<T>::value, void>::type
231    deduceTypeInfo(T *D) {
232      Size = sizeof(T);
233      deduceTypeInfoFromElement(&(*D)[0]);
234    }
235
236    template <typename T>
237    typename detail::enable_if<detail::has_x<T>::value &&
238                               !detail::is_array<T>::value, void>::type
239    deduceTypeInfo(T *D) {
240      Size = sizeof(T);
241      deduceTypeInfoFromElement(&(*D).x);
242    }
243
244    template <typename T>
245    typename detail::enable_if<!detail::has_x<T>::value &&
246                               !detail::is_array<T>::value, void>::type
247    deduceTypeInfo(T *D) {
248      Size = sizeof(T);
249      deduceTypeInfoFromElement(D);
250    }
251
252  public:
253    template <typename T>
254    Variable(const std::string &N, T* D, unsigned Flags = 0,
255        const LossyCompressionInfo &LCI = LossyCompressionInfo())
256      : Name(N), Data((void *) D), HasExtraSpace(Flags & VarHasExtraSpace),
257        IsPhysCoordX(Flags & VarIsPhysCoordX),
258        IsPhysCoordY(Flags & VarIsPhysCoordY),
259        IsPhysCoordZ(Flags & VarIsPhysCoordZ),
260        MaybePhysGhost(Flags & VarMaybePhysGhost),
261        LCI(LCI) {
262      deduceTypeInfo(D);
263    }
264
265    template <typename T>
266    Variable(const std::string &N, std::size_t NumElements, T* D,
267             unsigned Flags = 0,
268             const LossyCompressionInfo &LCI = LossyCompressionInfo())
269      : Name(N), Data((void *) D), HasExtraSpace(Flags & VarHasExtraSpace),
270        IsPhysCoordX(Flags & VarIsPhysCoordX),
271        IsPhysCoordY(Flags & VarIsPhysCoordY),
272        IsPhysCoordZ(Flags & VarIsPhysCoordZ),
273        MaybePhysGhost(Flags & VarMaybePhysGhost),
274        LCI(LCI) {
275      deduceTypeInfoFromElement(D);
276      Size = ElementSize*NumElements;
277    }
278
279    Variable(const VariableInfo &VI, void *D, unsigned Flags = 0,
280             const LossyCompressionInfo &LCI = LossyCompressionInfo())
281      : Name(VI.Name), Size(VI.Size), IsFloat(VI.IsFloat),
282        IsSigned(VI.IsSigned), Data(D),
283        HasExtraSpace(Flags & VarHasExtraSpace),
284        IsPhysCoordX((Flags & VarIsPhysCoordX) || VI.IsPhysCoordX),
285        IsPhysCoordY((Flags & VarIsPhysCoordY) || VI.IsPhysCoordY),
286        IsPhysCoordZ((Flags & VarIsPhysCoordZ) || VI.IsPhysCoordZ),
287        MaybePhysGhost((Flags & VarMaybePhysGhost) || VI.MaybePhysGhost),
288        ElementSize(VI.ElementSize), LCI(LCI) {}
289
290    template <typename ET>
291    bool hasElementType() {
292      if (ElementSize != sizeof(ET))
293        return false;
294      if (IsFloat != !std::numeric_limits<ET>::is_integer)
295        return false;
296      if (IsSigned != std::numeric_limits<ET>::is_signed)
297        return false;
298
299      return true;
300    }
301
302    std::string Name;
303    std::size_t Size;
304    bool IsFloat;
305    bool IsSigned;
306    void *Data;
307    bool HasExtraSpace;
308    bool IsPhysCoordX, IsPhysCoordY, IsPhysCoordZ;
309    bool MaybePhysGhost;
310    std::size_t ElementSize;
311
312    LossyCompressionInfo LCI;
313  };
314
315public:
316  enum FileIO {
317    FileIOMPI,
318    FileIOPOSIX,
319    FileIOMPICollective
320  };
321
322#ifndef GENERICIO_NO_MPI
323  GenericIO(const MPI_Comm &C, const std::string &FN, unsigned FIOT = -1)
324    : NElems(0), FileIOType(FIOT == (unsigned) -1 ? DefaultFileIOType : FIOT),
325      Partition(DefaultPartition), Comm(C), FileName(FN), Redistributing(false),
326      DisableCollErrChecking(false), SplitComm(MPI_COMM_NULL) {
327    std::fill(PhysOrigin, PhysOrigin + 3, 0.0);
328    std::fill(PhysScale,  PhysScale + 3, 0.0);
329  }
330#else
331  GenericIO(const std::string &FN, unsigned FIOT = -1)
332    : NElems(0), FileIOType(FIOT == (unsigned) -1 ? DefaultFileIOType : FIOT),
333      Partition(DefaultPartition), FileName(FN), Redistributing(false),
334      DisableCollErrChecking(false) {
335    std::fill(PhysOrigin, PhysOrigin + 3, 0.0);
336    std::fill(PhysScale,  PhysScale + 3, 0.0);
337  }
338#endif
339
340  ~GenericIO() {
341    close();
342
343#ifndef GENERICIO_NO_MPI
344    if (SplitComm != MPI_COMM_NULL)
345      MPI_Comm_free(&SplitComm);
346#endif
347  }
348
349public:
350  std::size_t requestedExtraSpace() const {
351    return 8;
352  }
353
354  void setNumElems(std::size_t E) {
355    NElems = E;
356
357#ifndef GENERICIO_NO_MPI
358    int IsLarge = E >= CollectiveMPIIOThreshold;
359    int AllIsLarge;
360    MPI_Allreduce(&IsLarge, &AllIsLarge, 1, MPI_INT, MPI_SUM, Comm);
361    if (!AllIsLarge)
362      FileIOType = FileIOMPICollective;
363#endif
364  }
365
366  void setPhysOrigin(double O, int Dim = -1) {
367    if (Dim >= 0)
368      PhysOrigin[Dim] = O;
369    else
370      std::fill(PhysOrigin, PhysOrigin + 3, O);
371  }
372
373  void setPhysScale(double S, int Dim = -1) {
374    if (Dim >= 0)
375      PhysScale[Dim] = S;
376    else
377      std::fill(PhysScale,  PhysScale + 3, S);
378  }
379
380  template <typename T>
381  void addVariable(const std::string &Name, T *Data,
382                   unsigned Flags = 0,
383                   const LossyCompressionInfo &LCI = LossyCompressionInfo()) {
384    Vars.push_back(Variable(Name, Data, Flags, LCI));
385  }
386
387  template <typename T, typename A>
388  void addVariable(const std::string &Name, std::vector<T, A> &Data,
389                   unsigned Flags = 0,
390                   const LossyCompressionInfo &LCI = LossyCompressionInfo()) {
391    T *D = Data.empty() ? 0 : &Data[0];
392    addVariable(Name, D, Flags, LCI);
393  }
394
395  void addVariable(const VariableInfo &VI, void *Data,
396                   unsigned Flags = 0,
397                   const LossyCompressionInfo &LCI = LossyCompressionInfo()) {
398    Vars.push_back(Variable(VI, Data, Flags, LCI));
399  }
400
401  template <typename T>
402  void addScalarizedVariable(const std::string &Name, T *Data,
403                             std::size_t NumElements, unsigned Flags = 0,
404                             const LossyCompressionInfo &LCI = LossyCompressionInfo()) {
405    Vars.push_back(Variable(Name, NumElements, Data, Flags, LCI));
406  }
407
408  template <typename T, typename A>
409  void addScalarizedVariable(const std::string &Name, std::vector<T, A> &Data,
410                             std::size_t NumElements, unsigned Flags = 0,
411                             const LossyCompressionInfo &LCI = LossyCompressionInfo()) {
412    T *D = Data.empty() ? 0 : &Data[0];
413    addScalarizedVariable(Name, D, NumElements, Flags, LCI);
414  }
415
416#ifndef GENERICIO_NO_MPI
417  // Writing
418  void write();
419#endif
420
421  enum MismatchBehavior {
422    MismatchAllowed,
423    MismatchDisallowed,
424    MismatchRedistribute
425  };
426
427  // Reading
428  void openAndReadHeader(MismatchBehavior MB = MismatchDisallowed,
429                         int EffRank = -1, bool CheckPartMap = true);
430
431  int readNRanks();
432  void readDims(int Dims[3]);
433
434  // Note: For partitioned inputs, this returns -1.
435  uint64_t readTotalNumElems();
436
437  void readPhysOrigin(double Origin[3]);
438  void readPhysScale(double Scale[3]);
439
440  void clearVariables() { this->Vars.clear(); };
441
442  int getNumberOfVariables() { return this->Vars.size(); };
443
444  void getVariableInfo(std::vector<VariableInfo> &VI);
445
446  std::size_t readNumElems(int EffRank = -1);
447  void readCoords(int Coords[3], int EffRank = -1);
448  int readGlobalRankNumber(int EffRank = -1);
449
450  void readData(int EffRank = -1, bool PrintStats = true, bool CollStats = true);
451
452  void getSourceRanks(std::vector<int> &SR);
453
454  void close() {
455    FH.close();
456  }
457
458  void setPartition(int P) {
459    Partition = P;
460  }
461
462  static void setDefaultFileIOType(unsigned FIOT) {
463    DefaultFileIOType = FIOT;
464  }
465
466  static void setDefaultPartition(int P) {
467    DefaultPartition = P;
468  }
469
470  static void setNaturalDefaultPartition();
471
472  static void setDefaultShouldCompress(bool C) {
473    DefaultShouldCompress = C;
474  }
475
476#ifndef GENERICIO_NO_MPI
477  static void setCollectiveMPIIOThreshold(std::size_t T) {
478#ifndef GENERICIO_NO_NEVER_USE_COLLECTIVE_IO
479    CollectiveMPIIOThreshold = T;
480#endif
481  }
482#endif
483
484private:
485  // Implementation functions templated on the Endianness of the underlying
486  // data.
487
488#ifndef GENERICIO_NO_MPI
489  template <bool IsBigEndian>
490  void write();
491#endif
492
493  template <bool IsBigEndian>
494  void readHeaderLeader(void *GHPtr, MismatchBehavior MB, int Rank, int NRanks,
495                        int SplitNRanks, std::string &LocalFileName,
496                        uint64_t &HeaderSize, std::vector<char> &Header);
497
498  template <bool IsBigEndian>
499  int readNRanks();
500
501  template <bool IsBigEndian>
502  void readDims(int Dims[3]);
503
504  template <bool IsBigEndian>
505  uint64_t readTotalNumElems();
506
507  template <bool IsBigEndian>
508  void readPhysOrigin(double Origin[3]);
509
510  template <bool IsBigEndian>
511  void readPhysScale(double Scale[3]);
512
513  template <bool IsBigEndian>
514  int readGlobalRankNumber(int EffRank);
515
516  template <bool IsBigEndian>
517  size_t readNumElems(int EffRank);
518
519  template <bool IsBigEndian>
520  void readCoords(int Coords[3], int EffRank);
521
522  void readData(int EffRank, size_t RowOffset, int Rank,
523                uint64_t &TotalReadSize, int NErrs[3]);
524
525  template <bool IsBigEndian>
526  void readData(int EffRank, size_t RowOffset,
527                int Rank, uint64_t &TotalReadSize, int NErrs[3]);
528
529  template <bool IsBigEndian>
530  void getVariableInfo(std::vector<VariableInfo> &VI);
531
532protected:
533  std::vector<Variable> Vars;
534  std::size_t NElems;
535
536  double PhysOrigin[3], PhysScale[3];
537
538  unsigned FileIOType;
539  int Partition;
540#ifndef GENERICIO_NO_MPI
541  MPI_Comm Comm;
542#endif
543  std::string FileName;
544
545  static unsigned DefaultFileIOType;
546  static int DefaultPartition;
547  static bool DefaultShouldCompress;
548
549#ifndef GENERICIO_NO_MPI
550  static std::size_t CollectiveMPIIOThreshold;
551#endif
552
553  // When redistributing, the rank blocks which this process should read.
554  bool Redistributing, DisableCollErrChecking;
555  std::vector<int> SourceRanks;
556
557  std::vector<int> RankMap;
558#ifndef GENERICIO_NO_MPI
559  MPI_Comm SplitComm;
560#endif
561  std::string OpenFileName;
562
563  // This reference counting mechanism allows the the GenericIO class
564  // to be used in a cursor mode. To do this, make a copy of the class
565  // after reading the header but prior to adding the variables.
566  struct FHManager {
567    FHManager() : CountedFH(0) {
568      allocate();
569    }
570
571    FHManager(const FHManager& F) {
572      CountedFH = F.CountedFH;
573      CountedFH->Cnt += 1;
574    }
575
576    ~FHManager() {
577      close();
578    }
579
580    GenericFileIO *&get() {
581      if (!CountedFH)
582        allocate();
583
584      return CountedFH->GFIO;
585    }
586
587    std::vector<char> &getHeaderCache() {
588      if (!CountedFH)
589        allocate();
590
591      return CountedFH->HeaderCache;
592    }
593
594    bool isBigEndian() {
595      return CountedFH ? CountedFH->IsBigEndian : false;
596    }
597
598    void setIsBigEndian(bool isBE) {
599      CountedFH->IsBigEndian = isBE;
600    }
601
602    void allocate() {
603      close();
604      CountedFH = new FHWCnt;
605    };
606
607    void close() {
608      if (CountedFH && CountedFH->Cnt == 1)
609        delete CountedFH;
610      else if (CountedFH)
611        CountedFH->Cnt -= 1;
612
613      CountedFH = 0;
614    }
615
616    struct FHWCnt {
617      FHWCnt() : GFIO(0), Cnt(1), IsBigEndian(false) {}
618
619      ~FHWCnt() {
620        close();
621      }
622
623protected:
624      void close() {
625        delete GFIO;
626        GFIO = 0;
627      }
628
629public:
630      GenericFileIO *GFIO;
631      size_t Cnt;
632
633      // Used for reading
634      std::vector<char> HeaderCache;
635      bool IsBigEndian;
636    };
637
638    FHWCnt *CountedFH;
639  } FH;
640};
641
642} /* END namespace cosmotk */
643#endif // GENERICIO_H
644
Note: See TracBrowser for help on using the repository browser.