Commit 5d57155c authored by Hal Finkel's avatar Hal Finkel
Browse files

Add support for float4 (and other homogeneous aggregates)

parent fb69232d
......@@ -321,6 +321,7 @@ struct VariableHeader {
char Name[NameSize];
endian_specific_value<uint64_t, IsBigEndian> Flags;
endian_specific_value<uint64_t, IsBigEndian> Size;
endian_specific_value<uint64_t, IsBigEndian> ElementSize;
};
template <bool IsBigEndian>
......@@ -582,6 +583,7 @@ nocomp:
if (Vars[i].MaybePhysGhost) VFlags |= ValueMaybePhysGhost;
VH->Flags = VFlags;
RecordSize += VH->Size = Vars[i].Size;
VH->ElementSize = Vars[i].ElementSize;
}
MPI_Gather(&RHLocal, sizeof(RHLocal), MPI_BYTE,
......@@ -1378,6 +1380,10 @@ void GenericIO::readData(int EffRank, size_t RowOffset, int Rank,
continue;
}
size_t ElementSize = VH->Size;
if (offsetof_safe(VH, ElementSize) < GH->VarsSize)
ElementSize = VH->ElementSize;
VarFound = true;
bool IsFloat = (bool) (VH->Flags & FloatValue),
IsSigned = (bool) (VH->Flags & SignedValue);
......@@ -1387,6 +1393,12 @@ void GenericIO::readData(int EffRank, size_t RowOffset, int Rank,
" in: " << OpenFileName << ": current: " << Vars[i].Size <<
", file: " << VH->Size;
throw runtime_error(ss.str());
} else if (ElementSize != Vars[i].ElementSize) {
stringstream ss;
ss << "Element size mismatch for variable " << Vars[i].Name <<
" in: " << OpenFileName << ": current: " << Vars[i].ElementSize <<
", file: " << ElementSize;
throw runtime_error(ss.str());
} else if (IsFloat != Vars[i].IsFloat) {
string Float("float"), Int("integer");
stringstream ss;
......@@ -1564,9 +1576,10 @@ void GenericIO::readData(int EffRank, size_t RowOffset, int Rank,
// Byte swap the data if necessary.
if (IsBigEndian != isBigEndian())
for (size_t j = 0; j < RH->NElems; ++j) {
char *Offset = ((char *) VarData) + j*Vars[i].Size;
bswap(Offset, Vars[i].Size);
for (size_t j = 0;
j < RH->NElems*(Vars[i].Size/Vars[i].ElementSize); ++j) {
char *Offset = ((char *) VarData) + j*Vars[i].ElementSize;
bswap(Offset, Vars[i].ElementSize);
}
break;
......@@ -1625,6 +1638,10 @@ void GenericIO::getVariableInfo(vector<VariableInfo> &VI) {
if (VNameNull < NameSize)
VName.resize(VNameNull);
size_t ElementSize = VH->Size;
if (offsetof_safe(VH, ElementSize) < GH->VarsSize)
ElementSize = VH->ElementSize;
bool IsFloat = (bool) (VH->Flags & FloatValue),
IsSigned = (bool) (VH->Flags & SignedValue),
IsPhysCoordX = (bool) (VH->Flags & ValueIsPhysCoordX),
......@@ -1633,7 +1650,7 @@ void GenericIO::getVariableInfo(vector<VariableInfo> &VI) {
MaybePhysGhost = (bool) (VH->Flags & ValueMaybePhysGhost);
VI.push_back(VariableInfo(VName, (size_t) VH->Size, IsFloat, IsSigned,
IsPhysCoordX, IsPhysCoordY, IsPhysCoordZ,
MaybePhysGhost));
MaybePhysGhost, ElementSize));
}
}
......
......@@ -117,6 +117,50 @@ protected:
int FH;
};
namespace detail {
// A standard enable_if idiom (we include our own here for pre-C++11 support).
template <bool B, typename T = void>
struct enable_if {};
template <typename T>
struct enable_if<true, T> { typedef T type; };
// A SFINAE-based trait to detect whether a type has a member named x. This is
// designed to work both with structs/classes and also with OpenCL-style vector
// types.
template <typename T>
class has_x {
typedef char yes[1];
typedef char no[2];
template <typename C>
static yes &test(char(*)[sizeof((*((C *) 0)).x)]);
template <typename C>
static no &test(...);
public:
enum { value = sizeof(test<T>(0)) == sizeof(yes) };
};
// A SFINAE-based trait to detect whether a type is array-like (i.e. supports
// the [] operator).
template <typename T>
class is_array {
typedef char yes[1];
typedef char no[2];
template <typename C>
static yes &test(char(*)[sizeof((*((C *) 0))[0])]);
template <typename C>
static no &test(...);
public:
enum { value = sizeof(test<T>(0)) == sizeof(yes) };
};
} // namespace detail
class GenericIO {
public:
enum VariableFlags {
......@@ -132,10 +176,10 @@ public:
struct VariableInfo {
VariableInfo(const std::string &N, std::size_t S, bool IF, bool IS,
bool PCX, bool PCY, bool PCZ, bool PG)
bool PCX, bool PCY, bool PCZ, bool PG, std::size_t ES = 0)
: Name(N), Size(S), IsFloat(IF), IsSigned(IS),
IsPhysCoordX(PCX), IsPhysCoordY(PCY), IsPhysCoordZ(PCZ),
MaybePhysGhost(PG) {}
MaybePhysGhost(PG), ElementSize(ES ? ES : S) {}
std::string Name;
std::size_t Size;
......@@ -143,20 +187,70 @@ public:
bool IsSigned;
bool IsPhysCoordX, IsPhysCoordY, IsPhysCoordZ;
bool MaybePhysGhost;
std::size_t ElementSize;
};
public:
struct Variable {
class Variable {
private:
template <typename ET>
void deduceTypeInfoFromElement(ET *) {
ElementSize = sizeof(ET);
IsFloat = !std::numeric_limits<ET>::is_integer;
IsSigned = std::numeric_limits<ET>::is_signed;
}
// There are specializations here to handle array types
// (e.g. typedef float float4[4];), struct types
// (e.g. struct float4 { float x, y, z, w; };), and scalar types.
// Builtin vector types
// (e.g. typedef float float4 __attribute__((ext_vector_type(4)));) should
// also work.
template <typename T>
typename detail::enable_if<detail::is_array<T>::value, void>::type
deduceTypeInfo(T *D) {
Size = sizeof(T);
deduceTypeInfoFromElement(&(*D)[0]);
}
template <typename T>
typename detail::enable_if<detail::has_x<T>::value &&
!detail::is_array<T>::value, void>::type
deduceTypeInfo(T *D) {
Size = sizeof(T);
deduceTypeInfoFromElement(&(*D).x);
}
template <typename T>
typename detail::enable_if<!detail::has_x<T>::value &&
!detail::is_array<T>::value, void>::type
deduceTypeInfo(T *D) {
Size = sizeof(T);
deduceTypeInfoFromElement(D);
}
public:
template <typename T>
Variable(const std::string &N, T* D, unsigned Flags = 0)
: Name(N), Size(sizeof(T)),
IsFloat(!std::numeric_limits<T>::is_integer),
IsSigned(std::numeric_limits<T>::is_signed),
Data((void *) D), HasExtraSpace(Flags & VarHasExtraSpace),
: Name(N), Data((void *) D), HasExtraSpace(Flags & VarHasExtraSpace),
IsPhysCoordX(Flags & VarIsPhysCoordX),
IsPhysCoordY(Flags & VarIsPhysCoordY),
IsPhysCoordZ(Flags & VarIsPhysCoordZ),
MaybePhysGhost(Flags & VarMaybePhysGhost) {}
MaybePhysGhost(Flags & VarMaybePhysGhost) {
deduceTypeInfo(D);
}
template <typename T>
Variable(const std::string &N, std::size_t NumElements, T* D,
unsigned Flags = 0)
: Name(N), Data((void *) D), HasExtraSpace(Flags & VarHasExtraSpace),
IsPhysCoordX(Flags & VarIsPhysCoordX),
IsPhysCoordY(Flags & VarIsPhysCoordY),
IsPhysCoordZ(Flags & VarIsPhysCoordZ),
MaybePhysGhost(Flags & VarMaybePhysGhost) {
deduceTypeInfoFromElement(D);
Size = ElementSize*NumElements;
}
Variable(const VariableInfo &VI, void *D, unsigned Flags = 0)
: Name(VI.Name), Size(VI.Size), IsFloat(VI.IsFloat),
......@@ -165,7 +259,8 @@ public:
IsPhysCoordX((Flags & VarIsPhysCoordX) || VI.IsPhysCoordX),
IsPhysCoordY((Flags & VarIsPhysCoordY) || VI.IsPhysCoordY),
IsPhysCoordZ((Flags & VarIsPhysCoordZ) || VI.IsPhysCoordZ),
MaybePhysGhost((Flags & VarMaybePhysGhost) || VI.MaybePhysGhost) {}
MaybePhysGhost((Flags & VarMaybePhysGhost) || VI.MaybePhysGhost),
ElementSize(VI.ElementSize) {}
std::string Name;
std::size_t Size;
......@@ -175,6 +270,7 @@ public:
bool HasExtraSpace;
bool IsPhysCoordX, IsPhysCoordY, IsPhysCoordZ;
bool MaybePhysGhost;
std::size_t ElementSize;
};
public:
......@@ -260,6 +356,19 @@ public:
Vars.push_back(Variable(VI, Data, Flags));
}
template <typename T>
void addScalarizedVariable(const std::string &Name, T *Data,
std::size_t NumElements, unsigned Flags = 0) {
Vars.push_back(Variable(Name, NumElements, Data, Flags));
}
template <typename T, typename A>
void addScalarizedVariable(const std::string &Name, std::vector<T, A> &Data,
std::size_t NumElements, unsigned Flags = 0) {
T *D = Data.empty() ? 0 : &Data[0];
addScalarizedVariable(Name, D, NumElements, Flags);
}
#ifndef GENERICIO_NO_MPI
// Writing
void write();
......
......@@ -53,6 +53,10 @@
#define ID_T int64_t
#define MASK_T uint16_t
struct pos_t {
POSVEL_T x, y, z, w;
};
using namespace std;
using namespace gio;
......@@ -63,17 +67,27 @@ int main(int argc, char *argv[]) {
MPI_Comm_rank(MPI_COMM_WORLD, &commRank);
MPI_Comm_size(MPI_COMM_WORLD, &commRanks);
bool UseAOS = false;
int a = 1;
if (argc > 1 && string(argv[a]) == "-a") {
UseAOS = true;
--argc;
++a;
}
if(argc != 2) {
fprintf(stderr,"USAGE: %s <mpiioName>\n", argv[0]);
fprintf(stderr,"USAGE: %s [-a] <mpiioName>\n", argv[0]);
exit(-1);
}
char *mpiioName = argv[1];
char *mpiioName = argv[a];
vector<POSVEL_T> xx, yy, zz, vx, vy, vz, phi;
vector<ID_T> id;
vector<MASK_T> mask;
vector<pos_t> pos, vel;
assert(sizeof(ID_T) == 8);
size_t Np = 0;
......@@ -92,36 +106,51 @@ int main(int argc, char *argv[]) {
Np = GIO.readNumElems();
xx.resize(Np + GIO.requestedExtraSpace()/sizeof(POSVEL_T));
yy.resize(Np + GIO.requestedExtraSpace()/sizeof(POSVEL_T));
zz.resize(Np + GIO.requestedExtraSpace()/sizeof(POSVEL_T));
vx.resize(Np + GIO.requestedExtraSpace()/sizeof(POSVEL_T));
vy.resize(Np + GIO.requestedExtraSpace()/sizeof(POSVEL_T));
vz.resize(Np + GIO.requestedExtraSpace()/sizeof(POSVEL_T));
phi.resize(Np + GIO.requestedExtraSpace()/sizeof(POSVEL_T));
if (UseAOS) {
pos.resize(Np + (GIO.requestedExtraSpace() + sizeof(pos_t) - 1)/sizeof(pos_t));
vel.resize(Np + (GIO.requestedExtraSpace() + sizeof(pos_t) - 1)/sizeof(pos_t));
} else {
xx.resize(Np + GIO.requestedExtraSpace()/sizeof(POSVEL_T));
yy.resize(Np + GIO.requestedExtraSpace()/sizeof(POSVEL_T));
zz.resize(Np + GIO.requestedExtraSpace()/sizeof(POSVEL_T));
vx.resize(Np + GIO.requestedExtraSpace()/sizeof(POSVEL_T));
vy.resize(Np + GIO.requestedExtraSpace()/sizeof(POSVEL_T));
vz.resize(Np + GIO.requestedExtraSpace()/sizeof(POSVEL_T));
phi.resize(Np + GIO.requestedExtraSpace()/sizeof(POSVEL_T));
}
id.resize(Np + GIO.requestedExtraSpace()/sizeof(ID_T));
mask.resize(Np + GIO.requestedExtraSpace()/sizeof(MASK_T));
GIO.addVariable("x", xx, true);
GIO.addVariable("y", yy, true);
GIO.addVariable("z", zz, true);
GIO.addVariable("vx", vx, true);
GIO.addVariable("vy", vy, true);
GIO.addVariable("vz", vz, true);
GIO.addVariable("phi", phi, true);
GIO.addVariable("id", id, true);
GIO.addVariable("mask", mask, true);
if (UseAOS) {
GIO.addVariable("pos", pos, GenericIO::VarHasExtraSpace);
GIO.addVariable("vel", vel, GenericIO::VarHasExtraSpace);
} else {
GIO.addVariable("x", xx, GenericIO::VarHasExtraSpace);
GIO.addVariable("y", yy, GenericIO::VarHasExtraSpace);
GIO.addVariable("z", zz, GenericIO::VarHasExtraSpace);
GIO.addVariable("vx", vx, GenericIO::VarHasExtraSpace);
GIO.addVariable("vy", vy, GenericIO::VarHasExtraSpace);
GIO.addVariable("vz", vz, GenericIO::VarHasExtraSpace);
GIO.addVariable("phi", phi, GenericIO::VarHasExtraSpace);
}
GIO.addVariable("id", id, GenericIO::VarHasExtraSpace);
GIO.addVariable("mask", mask, GenericIO::VarHasExtraSpace);
GIO.readData();
} // destroy GIO prior to calling MPI_Finalize
xx.resize(Np);
yy.resize(Np);
zz.resize(Np);
vx.resize(Np);
vy.resize(Np);
vz.resize(Np);
phi.resize(Np);
if (UseAOS) {
pos.resize(Np);
vel.resize(Np);
} else {
xx.resize(Np);
yy.resize(Np);
zz.resize(Np);
vx.resize(Np);
vy.resize(Np);
vz.resize(Np);
phi.resize(Np);
}
id.resize(Np);
mask.resize(Np);
......
......@@ -69,6 +69,28 @@ struct Generator {
T inc;
};
struct pos_t {
POSVEL_T x, y, z, w;
};
template <>
struct Generator<pos_t> {
Generator(POSVEL_T start, POSVEL_T inc) :
GenX(start, inc), GenY(start, inc), GenZ(start, inc), GenW(start, inc) {}
pos_t operator()() {
pos_t v;
v.x = GenX();
v.y = GenY();
v.z = GenZ();
v.w = GenW();
return v;
}
Generator<POSVEL_T> GenX, GenY, GenZ, GenW;
};
int main(int argc, char *argv[]) {
MPI_Init(&argc, &argv);
......@@ -76,7 +98,14 @@ int main(int argc, char *argv[]) {
MPI_Comm_rank(MPI_COMM_WORLD, &commRank);
MPI_Comm_size(MPI_COMM_WORLD, &commRanks);
bool UseAOS = false;
int a = 1;
if (argc > 1 && string(argv[a]) == "-a") {
UseAOS = true;
--argc;
++a;
}
if (argc > 1 && string(argv[a]) == "-c") {
GenericIO::setDefaultShouldCompress(true);
--argc;
......@@ -84,7 +113,7 @@ int main(int argc, char *argv[]) {
}
if(argc != 4) {
fprintf(stderr,"USAGE: %s [-c] <mpiioName> <NP> <seed>\n", argv[0]);
fprintf(stderr,"USAGE: %s [-a] [-c] <mpiioName> <NP> <seed>\n", argv[0]);
exit(-1);
}
......@@ -103,6 +132,8 @@ int main(int argc, char *argv[]) {
vector<ID_T> id;
vector<MASK_T> mask;
vector<pos_t> pos, vel;
assert(sizeof(ID_T) == 8);
unsigned Method = GenericIO::FileIOPOSIX;
......@@ -122,46 +153,67 @@ int main(int argc, char *argv[]) {
GIO.setPhysOrigin(0.0);
GIO.setPhysScale(256.0);
xx.resize(Np + GIO.requestedExtraSpace()/sizeof(POSVEL_T));
yy.resize(Np + GIO.requestedExtraSpace()/sizeof(POSVEL_T));
zz.resize(Np + GIO.requestedExtraSpace()/sizeof(POSVEL_T));
vx.resize(Np + GIO.requestedExtraSpace()/sizeof(POSVEL_T));
vy.resize(Np + GIO.requestedExtraSpace()/sizeof(POSVEL_T));
vz.resize(Np + GIO.requestedExtraSpace()/sizeof(POSVEL_T));
phi.resize(Np + GIO.requestedExtraSpace()/sizeof(POSVEL_T));
if (UseAOS) {
pos.resize(Np + (GIO.requestedExtraSpace() + sizeof(pos_t) - 1)/sizeof(pos_t));
vel.resize(Np + (GIO.requestedExtraSpace() + sizeof(pos_t) - 1)/sizeof(pos_t));
} else {
xx.resize(Np + GIO.requestedExtraSpace()/sizeof(POSVEL_T));
yy.resize(Np + GIO.requestedExtraSpace()/sizeof(POSVEL_T));
zz.resize(Np + GIO.requestedExtraSpace()/sizeof(POSVEL_T));
vx.resize(Np + GIO.requestedExtraSpace()/sizeof(POSVEL_T));
vy.resize(Np + GIO.requestedExtraSpace()/sizeof(POSVEL_T));
vz.resize(Np + GIO.requestedExtraSpace()/sizeof(POSVEL_T));
phi.resize(Np + GIO.requestedExtraSpace()/sizeof(POSVEL_T));
}
id.resize(Np + GIO.requestedExtraSpace()/sizeof(ID_T));
mask.resize(Np + GIO.requestedExtraSpace()/sizeof(MASK_T));
std::generate(xx.begin(), xx.end(), Generator<POSVEL_T>(25, 3));
std::generate(yy.begin(), yy.end(), Generator<POSVEL_T>(25, 3));
std::generate(zz.begin(), zz.end(), Generator<POSVEL_T>(25, 3));
std::generate(vx.begin(), vx.end(), Generator<POSVEL_T>(25, 3));
std::generate(vy.begin(), vy.end(), Generator<POSVEL_T>(25, 3));
std::generate(vz.begin(), vz.end(), Generator<POSVEL_T>(25, 3));
std::generate(phi.begin(), phi.end(), Generator<POSVEL_T>(25, 3));
if (UseAOS) {
std::generate(pos.begin(), pos.end(), Generator<pos_t>(25, 3));
std::generate(vel.begin(), vel.end(), Generator<pos_t>(25, 3));
} else {
std::generate(xx.begin(), xx.end(), Generator<POSVEL_T>(25, 3));
std::generate(yy.begin(), yy.end(), Generator<POSVEL_T>(25, 3));
std::generate(zz.begin(), zz.end(), Generator<POSVEL_T>(25, 3));
std::generate(vx.begin(), vx.end(), Generator<POSVEL_T>(25, 3));
std::generate(vy.begin(), vy.end(), Generator<POSVEL_T>(25, 3));
std::generate(vz.begin(), vz.end(), Generator<POSVEL_T>(25, 3));
std::generate(phi.begin(), phi.end(), Generator<POSVEL_T>(25, 3));
}
std::generate(id.begin(), id.end(), Generator<ID_T>(25, 3));
std::fill(mask.begin(), mask.end(), 25);
GIO.addVariable("x", xx, CoordFlagsX | GenericIO::VarHasExtraSpace);
GIO.addVariable("y", yy, CoordFlagsY | GenericIO::VarHasExtraSpace);
GIO.addVariable("z", zz, CoordFlagsZ | GenericIO::VarHasExtraSpace);
GIO.addVariable("vx", vx, GenericIO::VarHasExtraSpace);
GIO.addVariable("vy", vy, GenericIO::VarHasExtraSpace);
GIO.addVariable("vz", vz, GenericIO::VarHasExtraSpace);
GIO.addVariable("phi", phi, GenericIO::VarHasExtraSpace);
if (UseAOS) {
GIO.addVariable("pos", pos, CoordFlagsX | CoordFlagsY | CoordFlagsZ |
GenericIO::VarHasExtraSpace);
GIO.addVariable("vel", vel, GenericIO::VarHasExtraSpace);
} else {
GIO.addVariable("x", xx, CoordFlagsX | GenericIO::VarHasExtraSpace);
GIO.addVariable("y", yy, CoordFlagsY | GenericIO::VarHasExtraSpace);
GIO.addVariable("z", zz, CoordFlagsZ | GenericIO::VarHasExtraSpace);
GIO.addVariable("vx", vx, GenericIO::VarHasExtraSpace);
GIO.addVariable("vy", vy, GenericIO::VarHasExtraSpace);
GIO.addVariable("vz", vz, GenericIO::VarHasExtraSpace);
GIO.addVariable("phi", phi, GenericIO::VarHasExtraSpace);
}
GIO.addVariable("id", id, GenericIO::VarHasExtraSpace);
GIO.addVariable("mask", mask, GenericIO::VarHasExtraSpace);
GIO.write();
} // destroy GIO prior to calling MPI_Finalize
xx.resize(Np);
yy.resize(Np);
zz.resize(Np);
vx.resize(Np);
vy.resize(Np);
vz.resize(Np);
phi.resize(Np);
if (UseAOS) {
pos.resize(Np);
vel.resize(Np);
} else {
xx.resize(Np);
yy.resize(Np);
zz.resize(Np);
vx.resize(Np);
vy.resize(Np);
vz.resize(Np);
phi.resize(Np);
}
id.resize(Np);
mask.resize(Np);
......
......@@ -62,23 +62,30 @@ public:
template <class T>
class Printer : public PrinterBase {
public:
Printer(GenericIO &G, size_t MNE, const string &N)
: Data(MNE + G.requestedExtraSpace()/sizeof(T)) {
G.addVariable(N, Data, true);
Printer(GenericIO &G, size_t MNE, size_t NE, const string &N)
: NumElements(NE), Data(MNE*NE + G.requestedExtraSpace()/sizeof(T)) {
G.addScalarizedVariable(N, Data, NE, GenericIO::VarHasExtraSpace);
}
virtual void print(ostream &os, size_t i) {
os << scientific << setprecision(numeric_limits<T>::digits10) << Data[i];
for (size_t j = 0; j < NumElements; ++j) {
os << scientific << setprecision(numeric_limits<T>::digits10) <<
Data[i*NumElements + j];
if (j != NumElements - 1)
os << "\t";
}
}
protected:
size_t NumElements;
vector<T> Data;
};
template <typename T>
PrinterBase *addPrinter(GenericIO::VariableInfo &V,
GenericIO &GIO, size_t MNE) {
if (sizeof(T) != V.Size)
if (sizeof(T) != V.ElementSize)
return 0;
if (V.IsFloat == numeric_limits<T>::is_integer)
......@@ -86,7 +93,7 @@ PrinterBase *addPrinter(GenericIO::VariableInfo &V,
if (V.IsSigned != numeric_limits<T>::is_signed)
return 0;
return new Printer<T>(GIO, MNE, V.Name);
return new Printer<T>(GIO, MNE, V.Size/V.ElementSize, V.Name);
}
int main(int argc, char *argv[]) {
......@@ -240,7 +247,29 @@ int main(int argc, char *argv[]) {
cout << "# ";
for (size_t i = 0; i < VI.size(); ++i) {
cout << VI[i].Name;
if (VI[i].Size == VI[i].ElementSize) {
cout << VI[i].Name;
} else {
size_t NumElements = VI[i].Size/VI[i].ElementSize;
for (size_t j = 0; j < NumElements; ++j) {
cout << VI[i].Name;
if (j == 0) {
cout << ".x";
} else if (j == 1) {
cout << ".y";
} else if (j == 2) {
cout << ".z";
} else if (j == 3) {
cout << ".w";
} else {
cout << ".w" << (j - 3);
}
if (j != NumElements - 1)
cout << "\t";
}
}
if (i != VI.size() - 1)
cout << "\t";
}
......