WIP: MPI: RAIndex + RCArray + corresp tests

This commit is contained in:
Christian Zimmermann 2024-03-20 01:19:40 +01:00
parent 38e90bc2c6
commit bd2af23b15
5 changed files with 315 additions and 29 deletions

View file

@ -0,0 +1,119 @@
// -*- C++ -*-
/**
@file opt/mpi/include/raindex.cc.h
@brief RAIndex template implementations.
Copyright (c) 2024 Christian Zimmermann. All rights reserved.
Mail: chizeta@f3l.de
**/
#ifndef __cxz_mpi_raindex_cc_h__
#define __cxz_mpi_raindex_cc_h__
namespace CNOXRZ
{
namespace mpi
{
template <typename T>
RAIndex<T>::RAIndex(const T* loc, const RangePtr& range, SizeT lexpos) :
RIndex<YIndex,YIndex>(range, lexpos),
mLoc(loc),
mCur(i.rank()),
mThisRank(getRankNumber())
{
setBufferSize();
setBuffer();
}
template <typename T>
RAIndex<T>::RAIndex(const T* loc, const RIndex<YIndex,YIndex>& i) :
RIndex<YIndex,YIndex>(i)
mLoc(loc),
mCur(i.rank()),
mThisRank(getRankNumber())
{
setBufferSize();
setBuffer();
}
template <typename T>
RAIndex<T>::RAIndex(const T* loc, const RAIndex<T>& i) :
RAIndex(i)
{
mLoc = loc;
setBuffer();
}
template <typename T>
RAIndex<T> RAIndex<T>::operator+(Int n) const
{
RAIndex<T> o = *this;
return o += n;
}
template <typename T>
RAIndex<T> RAIndex<T>::operator-(Int n) const
{
RAIndex<T> o = *this;
return o -= n;
}
template <typename T>
const T& RAIndex<T>::operator*() const
{
if(rank() != mThisRank){
if(mCur != rank()){
setBuffer();
}
return mBuf[local()->pos() % mBufSize];
}
else {
mLoc[local()->pos()];
}
}
template <typename T>
const T* RAIndex<T>::operator->() const
{
if(rank() != mThisRank){
if(mCur != rank()){
setBuffer();
}
return mBuf + local()->pos() % mBufSize;
}
else {
return mLoc + local()->pos();
}
}
template <typename T>
void RAIndex<T>::setBufferSize()
{
// use the contiguous stride's size as buffer size:
mBufSize = 1;
const auto& df = deepFormat();
for(SizeT i = 0; i != df.size(); ++i){
if(df[i] == 1){
mBufSize = deepMax()[i];
}
}
}
template <typename T>
void RAIndex<T>::setBuffer()
{
if(mBuf.size() != mBufSize){
mBuf.resize(mBufSize);
}
// A Bcast alternative with const pointer to source would be better...
std::memcpy(mBuf.data(), mLoc + local()->pos() / mBufSize, mBufSize*sizeof(T));
MPI_Bcast(mBuf.data(), mBufSize*sizeof(T), MPI_BYTE, static_cast<int>(rank()),
MPI_COMM_WORLD );
}
} // namespace mpi
} // namespace CNOXRZ

View file

@ -15,12 +15,17 @@
#include "cnorxz.h" #include "cnorxz.h"
namespace CNORXZ namespace CNORXZ
{
namespace mpi
{ {
/** **** /** ****
Index for multi-ranked array. Index for multi-ranked array.
This is meant to be a global index. For local iterations This is meant to be a global index, its position must be equal on each rank,
a YIndex is sufficient. otherwise deadlocks will occur. This kind of index exists for
completeness (global array element access), it should not be used in
operations that require high performance.
For local iterations (which is what one usually does) a YIndex is sufficient.
@tparam T data type. @tparam T data type.
*/ */
template <typename T> template <typename T>
@ -38,13 +43,22 @@ namespace CNORXZ
RAIndex operator-(Int n) const; RAIndex operator-(Int n) const;
const T& operator*() const; const T& operator*() const;
const T& operator->() const; const T* operator->() const;
void setBufferSize();
private: private:
void setBuffer();
const T* mLoc = nullptr; const T* mLoc = nullptr;
Vector<T> mBuf; // used if iterating over content on different rank Vector<T> mBuf; // used if iterating over content on different rank
SizeT mCur; // current rank in the buffer
SizeT mBufSize;
SizeT mThisRank;
}; };
} } // namespace mpi
} // namespace CNOXRZ
#endif #endif

View file

@ -20,7 +20,8 @@ namespace CNORXZ
template <typename T> template <typename T>
RCArray<T>::RCArray(const Sptr<CArrayBase<T>> a, const RangePtr& geom) : RCArray<T>::RCArray(const Sptr<CArrayBase<T>> a, const RangePtr& geom) :
mA(a), mA(a),
mGeom(geom) mGeom(geom),
mGlobal(RRangeFactory(a->range(),mGeom).create())
{} {}
template <typename T> template <typename T>
@ -53,22 +54,30 @@ namespace CNORXZ
template <class... Indices> template <class... Indices>
T RCArray<T>::operator[](const SPack<Indices...>& pack) const T RCArray<T>::operator[](const SPack<Indices...>& pack) const
{ {
CXZ_ERROR("not implemented");
return T();
} }
template <typename T> template <typename T>
template <class... Indices> template <class... Indices>
T RCArray<T>::at(const SPack<Indices...>& pack) const T RCArray<T>::at(const SPack<Indices...>& pack) const
{ {
CXZ_ERROR("not implemented");
return T();
} }
template <typename T> template <typename T>
T RCArray<T>::operator[](const DPack& pack) const T RCArray<T>::operator[](const DPack& pack) const
{ {
CXZ_ERROR("not implemented");
return T();
} }
template <typename T> template <typename T>
T RCArray<T>::at(const DPack& pack) const T RCArray<T>::at(const DPack& pack) const
{ {
CXZ_ERROR("not implemented");
return T();
} }
template <typename T> template <typename T>
@ -76,23 +85,31 @@ namespace CNORXZ
Sptr<CArrayBase<T>> RCArray<T>::sl(const IndexInterface<I,M>& begin, Sptr<CArrayBase<T>> RCArray<T>::sl(const IndexInterface<I,M>& begin,
const IndexInterface<I,M>& end) const const IndexInterface<I,M>& end) const
{ {
CXZ_ERROR("not implemented");
return nullptr;
} }
template <typename T> template <typename T>
template <class Index> template <class Index>
COpRoot<T,Index> RCArray<T>::operator()(const Sptr<Index>& i) const COpRoot<T,Index> RCArray<T>::operator()(const Sptr<Index>& i) const
{ {
CXZ_ERROR("not implemented");
return COpRoot<T,Index>();
} }
template <typename T> template <typename T>
template <class... Indices> template <class... Indices>
inline decltype(auto) RCArray<T>::operator()(const SPack<Indices...>& pack) const inline decltype(auto) RCArray<T>::operator()(const SPack<Indices...>& pack) const
{ {
CXZ_ERROR("not implemented");
return COpRoot<T,Index>();
} }
template <typename T> template <typename T>
inline decltype(auto) RCArray<T>::operator()(const DPack& pack) const inline decltype(auto) RCArray<T>::operator()(const DPack& pack) const
{ {
CXZ_ERROR("not implemented");
return COpRoot<T,Index>();
} }
template <typename T> template <typename T>
@ -110,27 +127,31 @@ namespace CNORXZ
template <typename T> template <typename T>
RangePtr RCArray<T>::range() const RangePtr RCArray<T>::range() const
{ {
return RRangeFactory(mA->range(),mGeom).create(); return mGlobal;
} }
template <typename T> template <typename T>
const_iterator RCArray<T>::begin() const const_iterator RCArray<T>::begin() const
{ {
return const_iterator(mA.data(), mGlobal);
} }
template <typename T> template <typename T>
const_iterator RCArray<T>::end() const const_iterator RCArray<T>::end() const
{ {
return const_iterator(mA.data(), mGlobal, mGlobal->size());
} }
template <typename T> template <typename T>
const_iterator RCArray<T>::cbegin() const const_iterator RCArray<T>::cbegin() const
{ {
return const_iterator(mA.data(), mGlobal);
} }
template <typename T> template <typename T>
const_iterator RCArray<T>::cend() const const_iterator RCArray<T>::cend() const
{ {
return const_iterator(mA.data(), mGlobal, mGlobal->size());
} }
template <typename T> template <typename T>
@ -145,6 +166,11 @@ namespace CNORXZ
return *mA; return *mA;
} }
template <typename T>
RangePtr RCArray<T>::geom() const
{
return mGeom;
}
} // namespace mpi } // namespace mpi
} // namespace CNORXZ } // namespace CNORXZ

View file

@ -103,9 +103,13 @@ namespace CNORXZ
/** Get local array object. */ /** Get local array object. */
const CArrayBase<T>& local() const; const CArrayBase<T>& local() const;
/** Get rank geometry. */
RangePtr geom() const;
private: private:
ObjHandle<CArrayBase<T>> mA; ObjHandle<CArrayBase<T>> mA;
RangePtr mGeom; RangePtr mGeom;
RangePtr mGlobal;
}; };
/** **** /** ****

View file

@ -0,0 +1,123 @@
// -*- C++ -*-
/**
@file opt/mpi/tests/rarray_unit_test.cc
@brief RArray unit tests.
Copyright (c) 2024 Christian Zimmermann. All rights reserved.
Mail: chizeta@f3l.de
**/
#include <cstdlib>
#include <iostream>
#include "gtest/gtest.h"
#include "cnorxz.h"
#include "cnorxz_mpi.h"
#include "test_numbers.h"
#include "rrange.cc.h"
#include "rarray.cc.h"
namespace
{
using namespace CNORXZ;
using Test::Numbers;
using namespace CNORXZ::mpi;
class MPIEnv : public ::testing::Environment
{
public:
MPIEnv(int argc, char** argv) : mArgc(argc), mArgv(argv) {}
virtual ~MPIEnv() override {}
virtual void SetUp() override
{
MPI_Init(&mArgc, &mArgv);
}
virtual void TearDown() override
{
MPI_Finalize();
}
protected:
int mArgc;
char** mArgv;
};
class RCArray_Test : public ::testing::Test
{
protected:
RCArray_Test()
{
CXZ_ASSERT(getNumRanks() == 4, "exptected 4 ranks");
Vector<Int> xs(12);
Vector<Int> ts(16);
for(SizeT i = 0; i != xs.size(); ++i){
const Int x = static_cast<Int>(i) - static_cast<Int>(xs.size()/2);
xs[i] = x;
}
for(SizeT i = 0; i != ts.size(); ++i){
const Int t = static_cast<Int>(i) - static_cast<Int>(ts.size()/2);
ts[i] = t;
}
mXRange = URangeFactory<Int>(xs).create();
mTRange = URangeFactory<Int>(ts).create();
Vector<RangePtr> rs { mTRange, mXRange, mXRange, mXRange };
mGRange = YRangeFactory(rs).create();
RangePtr g1 = CRangeFactory(1).create();
RangePtr g2 = CRangeFactory(2).create();
Vector<RangePtr> gs { g2, g1, g1, g2 };
mGeom = YRangeFactory(gs).create();
mRRange = rrange(mGRange, mGeom);
const SizeT size = ts.size()*xs.size()*xs.size()*xs.size();
Vector<Double> vec = Numbers::get(0,size/4+10);
Vector<Double> data(size);
Vector<Double> mData(size*4);
const SizeT myrank = getRankNumber();
for(SizeT i = 0; i != size; ++i){
data[i] = vec[i] * vec[i+myrank] / vec[i+2*myrank];
mData[i + size*myrank] = data[i];
MPI_Bcast(mData.data() + size*i, size, MPI_DOUBLE, i, MPI_COMM_WORLD);
}
mLoc = std::make_shared<MArray<Double>>( mRRange->sub(1), data);
mA = RCArray<Double>(mLoc, mGeom);
}
RangePtr mXRange;
RangePtr mTRange;
RangePtr mGRange;
RangePtr mGeom;
RangePtr mRRange;
Sptr<MArray<Double>> mLoc;
RCArray mA;
Vector<Double> mData;
};
TEST_F(RArray_Test, Basics)
{
EXPECT_EQ(mA.size(), mRRange->size());
}
TEST_F(RArray_Test, GlobalIterate)
{
const SizeT size = mRRange->sub(1)->size();
auto e = mA.end();
for(auto i = mA.begin(); i != e; ++i){
EXPECT_EQ(*i, mData[i.rank()*size + i.local().pos()]);
}
}
}
int main(int argc, char** argv)
{
::testing::InitGoogleTest(&argc, argv);
::testing::AddGlobalTestEnvironment( new MPIEnv(argc, argv) );
return RUN_ALL_TESTS();
}