1
0
mirror of https://github.com/paboyle/Grid.git synced 2024-11-10 07:55:35 +00:00

Chunking layout reasonably efficient. Looks for small prime factors of each dimension, falling back to approximate size if needed.

This commit is contained in:
Michael Marshall 2019-02-25 11:07:29 +00:00
parent 44a2d4854a
commit 3c9f2d4106
2 changed files with 63 additions and 34 deletions

View File

@ -3,6 +3,7 @@
#include <stack> #include <stack>
#include <string> #include <string>
#include <list>
#include <vector> #include <vector>
#include <H5Cpp.h> #include <H5Cpp.h>
#include <Grid/tensors/Tensors.h> #include <Grid/tensors/Tensors.h>
@ -105,18 +106,17 @@ namespace Grid
template <> template <>
void Hdf5Writer::writeDefault(const std::string &s, const std::string &x); void Hdf5Writer::writeDefault(const std::string &s, const std::string &x);
static hsize_t alignup(hsize_t n) class SortNode {
{ public:
n--; // 1000 0011 --> 1000 0010 int index;
n |= n >> 1; // 1000 0010 | 0100 0001 = 1100 0011 hsize_t dimsize;
n |= n >> 2; // 1100 0011 | 0011 0000 = 1111 0011 //bool operator<(const SortNode &r) { return dimsize < r.dimsize || (dimsize == r.dimsize && index < r.index); }
n |= n >> 4; // 1111 0011 | 0000 1111 = 1111 1111 //SortNode() = default;
n |= n >> 8; // ... (At this point all bits are 1, so further bitwise-or SortNode(int Index, hsize_t DimSize) : index{Index}, dimsize{DimSize} {}
n |= n >> 16; // operations produce no effect.)
n++; // 1111 1111 --> 1 0000 0000
return n;
}; };
bool operator<(const SortNode &l, const SortNode &r) { return l.dimsize < r.dimsize || (l.dimsize == r.dimsize && l.index < r.index); }
template <typename U> template <typename U>
void Hdf5Writer::writeMultiDim(const std::string &s, const std::vector<size_t> & Dimensions, const U * pDataRowMajor, size_t NumElements) void Hdf5Writer::writeMultiDim(const std::string &s, const std::vector<size_t> & Dimensions, const U * pDataRowMajor, size_t NumElements)
{ {
@ -125,30 +125,64 @@ namespace Grid
std::vector<hsize_t> dim(rank); std::vector<hsize_t> dim(rank);
for(int i = 0; i < rank; i++) for(int i = 0; i < rank; i++)
dim[i] = Dimensions[i]; dim[i] = Dimensions[i];
// write to file // write the entire dataset to file
H5NS::DataSpace dataSpace(rank, dim.data()); H5NS::DataSpace dataSpace(rank, dim.data());
size_t DataSize = NumElements * sizeof(U); size_t DataSize = NumElements * sizeof(U);
if (DataSize > dataSetThres_) if (DataSize > dataSetThres_)
{ {
// Make sure the chunk size is < 4GB // First few prime numbers from https://oeis.org/A000040
static const unsigned short Primes[] = { 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31,
37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109,
113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193,
197, 199, 211, 223, 227, 229, 233, 239, 241, 251, 257, 263, 269, 271 };
constexpr int NumPrimes = sizeof( Primes ) / sizeof( Primes[0] );
// Make sure 1) each dimension; and 2) chunk size is < 4GB
const hsize_t MaxElements = ( sizeof( U ) == 1 ) ? 0xffffffff : 0x100000000 / sizeof( U ); const hsize_t MaxElements = ( sizeof( U ) == 1 ) ? 0xffffffff : 0x100000000 / sizeof( U );
hsize_t ElementsPerChunk = 1; hsize_t ElementsPerChunk = 1;
bool bTooBig = false; bool bTooBig = false;
for( unsigned int i = rank - 1; i != -1; i-- ) { for( int i = rank - 1 ; i != -1 ; i-- ) {
auto &d = dim[i];
if( bTooBig ) if( bTooBig )
// Chunk size is already as big as can be - remaining dimensions = 1 d = 1; // Chunk size is already as big as can be - remaining dimensions = 1
dim[i] = 1;
else { else {
// If individual dimension too big, reduce by prime factors if possible
for( int PrimeIdx = 0; d > MaxElements && PrimeIdx < NumPrimes; ) {
if( d % Primes[PrimeIdx] )
PrimeIdx++;
else
d /= Primes[PrimeIdx];
}
const char ErrorMsg[] = " dimension > 4GB without small prime factors. "
"Hdf5IO chunk size will be inefficient.";
if( d > MaxElements ) {
std::cout << GridLogMessage << "Individual" << ErrorMsg << std::endl;
hsize_t quotient = d / MaxElements;
if( d % MaxElements )
quotient++;
d /= quotient;
}
// Now make sure overall size is not too big // Now make sure overall size is not too big
ElementsPerChunk *= dim[i]; hsize_t OverflowCheck = ElementsPerChunk;
if( ElementsPerChunk >= MaxElements ) { ElementsPerChunk *= d;
assert( OverflowCheck == ElementsPerChunk / d && "Product of dimensions overflowed hsize_t" );
// If product of dimensions too big, reduce by prime factors
for( int PrimeIdx = 0; ElementsPerChunk > MaxElements && PrimeIdx < NumPrimes; ) {
bTooBig = true; bTooBig = true;
hsize_t dividend = ElementsPerChunk / MaxElements; if( d % Primes[PrimeIdx] )
hsize_t remainder = ElementsPerChunk % MaxElements; PrimeIdx++;
if( remainder ) else {
dividend++; d /= Primes[PrimeIdx];
dim[i] = dim[i] / dividend; ElementsPerChunk /= Primes[PrimeIdx];
}
}
if( ElementsPerChunk > MaxElements ) {
std::cout << GridLogMessage << "Product of" << ErrorMsg << std::endl;
hsize_t quotient = ElementsPerChunk / MaxElements;
if( ElementsPerChunk % MaxElements )
quotient++;
d /= quotient;
ElementsPerChunk /= quotient;
} }
} }
} }

View File

@ -114,7 +114,7 @@ typedef Eigen::TensorFixedSize<TestScalar, Eigen::Sizes<9,4,2>, Eigen::StorageOp
typedef std::vector<Tensor_9_4_2> aTensor_9_4_2; typedef std::vector<Tensor_9_4_2> aTensor_9_4_2;
typedef Eigen::TensorFixedSize<SpinColourVector, Eigen::Sizes<6,5>> LSCTensor; typedef Eigen::TensorFixedSize<SpinColourVector, Eigen::Sizes<6,5>> LSCTensor;
#ifdef DEBUG #ifdef DEBUG
typedef Eigen::TensorFixedSize<iMatrix<iVector<iMatrix<iVector<LorentzColourMatrix,5>,2>,7>,3>, Eigen::Sizes<2,2,11,10,9>, Eigen::StorageOptions::RowMajor> LCMTensor; typedef Eigen::TensorFixedSize<iMatrix<iVector<iMatrix<iVector<LorentzColourMatrix,5>,2>,7>,3>, Eigen::Sizes<2,4,11,10,9>, Eigen::StorageOptions::RowMajor> LCMTensor;
#endif #endif
class PerambIOTestClass: Serializable { class PerambIOTestClass: Serializable {
@ -132,9 +132,6 @@ public:
, Tensor_9_4_2, tensor_9_4_2 , Tensor_9_4_2, tensor_9_4_2
, aTensor_9_4_2, atensor_9_4_2 , aTensor_9_4_2, atensor_9_4_2
, LSCTensor, MyLSCTensor , LSCTensor, MyLSCTensor
#ifdef DEBUG
, LCMTensor, MyLCMTensor
#endif
); );
PerambIOTestClass() PerambIOTestClass()
: DistilParameterNames {"alpha", "beta", "gamma", "delta", "epsilon", "zeta"} : DistilParameterNames {"alpha", "beta", "gamma", "delta", "epsilon", "zeta"}
@ -153,23 +150,19 @@ public:
for( auto &t : atensor_9_4_2 ) for( auto &t : atensor_9_4_2 )
SequentialInit(t, Flag); SequentialInit(t, Flag);
SequentialInit( MyLSCTensor ); SequentialInit( MyLSCTensor );
#ifdef DEBUG
SequentialInit( MyLCMTensor );
#endif
} }
}; };
#define RDR_ Hdf5Reader
#define WTR_ Hdf5Writer
#define TensorWriteReadInnerNoInit( T ) \ #define TensorWriteReadInnerNoInit( T ) \
filename = "iotest_" + std::to_string(++TestNum) + "_" #T ".h5"; \ filename = "iotest_" + std::to_string(++TestNum) + "_" #T + pszExtension; \
ioTest<WTR_, RDR_, T>(filename, t, #T, #T); ioTest<WTR_, RDR_, T>(filename, t, #T, #T);
#define TensorWriteReadInner( T ) SequentialInit( t ); TensorWriteReadInnerNoInit( T ) #define TensorWriteReadInner( T ) SequentialInit( t ); TensorWriteReadInnerNoInit( T )
#define TensorWriteRead( T ) { T t ; TensorWriteReadInner( T ) } #define TensorWriteRead( T ) { T t ; TensorWriteReadInner( T ) }
#define TensorWriteReadV(T, ... ) { T t( __VA_ARGS__ ); TensorWriteReadInner( T ) } #define TensorWriteReadV(T, ... ) { T t( __VA_ARGS__ ); TensorWriteReadInner( T ) }
#define TensorWriteReadLarge( T ) { std::unique_ptr<T> p{new T}; T &t{*p}; TensorWriteReadInnerNoInit(T) } #define TensorWriteReadLarge( T ) { std::unique_ptr<T> p{new T}; T &t{*p}; TensorWriteReadInnerNoInit(T) }
void EigenHdf5IOTest(void) template <typename WTR_, typename RDR_>
void EigenHdf5IOTest(const char * pszExtension)
{ {
unsigned int TestNum = 0; unsigned int TestNum = 0;
std::string filename; std::string filename;
@ -300,8 +293,10 @@ int main(int argc,char **argv)
ioTest<Hdf5Writer, Hdf5Reader>("iotest.h5", obj, "HDF5 (object) "); ioTest<Hdf5Writer, Hdf5Reader>("iotest.h5", obj, "HDF5 (object) ");
ioTest<Hdf5Writer, Hdf5Reader>("iotest.h5", vec, "HDF5 (vector of objects)"); ioTest<Hdf5Writer, Hdf5Reader>("iotest.h5", vec, "HDF5 (vector of objects)");
std::cout << "\n==== detailed Hdf5 tensor tests (Grid::EigenIO)" << std::endl; std::cout << "\n==== detailed Hdf5 tensor tests (Grid::EigenIO)" << std::endl;
EigenHdf5IOTest(); EigenHdf5IOTest<Hdf5Writer, Hdf5Reader>(".h5");
#endif #endif
std::cout << "\n==== detailed binary tensor tests (Grid::EigenIO)" << std::endl;
EigenHdf5IOTest<BinaryWriter, BinaryReader>(".bin");
std::cout << "\n==== vector flattening/reconstruction" << std::endl; std::cout << "\n==== vector flattening/reconstruction" << std::endl;
typedef std::vector<std::vector<std::vector<double>>> vec3d; typedef std::vector<std::vector<std::vector<double>>> vec3d;