Update sources

This commit is contained in:
Alejandro Gallo 2021-11-08 17:33:13 +01:00
parent 7e5feccca9
commit 1d6d14c398
6 changed files with 273 additions and 123 deletions

View File

@ -22,6 +22,8 @@ namespace atrip {
static int rank; static int rank;
static int np; static int np;
static Timings chrono; static Timings chrono;
static size_t networkSend;
static size_t localSend;
static void init(); static void init();
struct Input { struct Input {
@ -46,6 +48,7 @@ namespace atrip {
GROUP_AND_SORT, GROUP_AND_SORT,
}; };
ADD_ATTRIBUTE(bool, rankRoundRobin, false)
ADD_ATTRIBUTE(bool, chrono, false) ADD_ATTRIBUTE(bool, chrono, false)
ADD_ATTRIBUTE(bool, barrier, false) ADD_ATTRIBUTE(bool, barrier, false)
ADD_ATTRIBUTE(int, maxIterations, 0) ADD_ATTRIBUTE(int, maxIterations, 0)

View File

@ -5,22 +5,36 @@
#include <algorithm> #include <algorithm>
#include <atrip/Slice.hpp> #include <atrip/Slice.hpp>
#include <atrip/Tuples.hpp>
namespace atrip { namespace atrip {
struct RankMap { struct RankMap {
static bool RANK_ROUND_ROBIN;
std::vector<size_t> const lengths; std::vector<size_t> const lengths;
size_t const np, size; size_t const np, size;
ClusterInfo const clusterInfo;
RankMap(std::vector<size_t> lens, size_t np_) RankMap(std::vector<size_t> lens, size_t np_, MPI_Comm comm)
: lengths(lens) : lengths(lens)
, np(np_) , np(np_)
, size(std::accumulate(lengths.begin(), lengths.end(), , size(std::accumulate(lengths.begin(), lengths.end(),
1UL, std::multiplies<size_t>())) 1UL, std::multiplies<size_t>()))
, clusterInfo(getClusterInfo(comm))
{ assert(lengths.size() <= 2); } { assert(lengths.size() <= 2); }
size_t find(Slice::Location const& p) const noexcept { size_t find(Slice::Location const& p) const noexcept {
return p.source * np + p.rank; if (RANK_ROUND_ROBIN) {
return p.source * np + p.rank;
} else {
const size_t
rankPosition = p.source * clusterInfo.ranksPerNode
+ clusterInfo.rankInfos[p.rank].localRank
;
return rankPosition * clusterInfo.nNodes
+ clusterInfo.rankInfos[p.rank].nodeId
;
}
} }
size_t nSources() const noexcept { size_t nSources() const noexcept {
@ -40,8 +54,9 @@ namespace atrip {
} }
Slice::Location Slice::Location
find(ABCTuple const& abc, Slice::Type sliceType) const noexcept { find(ABCTuple const& abc, Slice::Type sliceType) const {
// tuple = {11, 8} when abc = {11, 8, 9} and sliceType = AB // tuple = {11, 8} when abc = {11, 8, 9} and sliceType = AB
// tuple = {11, 0} when abc = {11, 8, 9} and sliceType = A
const auto tuple = Slice::subtupleBySlice(abc, sliceType); const auto tuple = Slice::subtupleBySlice(abc, sliceType);
const size_t index const size_t index
@ -49,9 +64,51 @@ namespace atrip {
+ tuple[1] * (lengths.size() > 1 ? lengths[0] : 0) + tuple[1] * (lengths.size() > 1 ? lengths[0] : 0)
; ;
size_t rank, source;
if (RANK_ROUND_ROBIN) {
rank = index % np;
source = index / np;
} else {
size_t const
// the node that will be assigned to
nodeId = index % clusterInfo.nNodes
// how many times it has been assigned to the node
, s_n = index / clusterInfo.nNodes
// which local rank in the node should be
, localRank = s_n % clusterInfo.ranksPerNode
// and the local source (how many times we chose this local rank)
, localSource = s_n / clusterInfo.ranksPerNode
;
// find the localRank-th entry in clusterInfo
auto const& it =
std::find_if(clusterInfo.rankInfos.begin(),
clusterInfo.rankInfos.end(),
[nodeId, localRank](RankInfo const& ri) {
return ri.nodeId == nodeId
&& ri.localRank == localRank
;
});
if (it == clusterInfo.rankInfos.end()) {
throw "FATAL! Error in node distribution of the slices";
}
rank = (*it).globalRank;
source = localSource;
}
return return
{ index % np { rank
, index / np , source
}; };
} }

View File

@ -178,8 +178,14 @@ namespace atrip {
if (blank.info.state == Slice::SelfSufficient) { if (blank.info.state == Slice::SelfSufficient) {
blank.data = sources[from.source].data(); blank.data = sources[from.source].data();
} else { } else {
if (freePointers.size() == 0) if (freePointers.size() == 0) {
throw std::domain_error("No more free pointers!"); std::stringstream stream;
stream << "No more free pointers "
<< "for type " << type
<< " and name " << name
;
throw std::domain_error(stream.str());
}
auto dataPointer = freePointers.begin(); auto dataPointer = freePointers.begin();
freePointers.erase(dataPointer); freePointers.erase(dataPointer);
blank.data = *dataPointer; blank.data = *dataPointer;
@ -332,7 +338,7 @@ namespace atrip {
, Slice::Name name_ , Slice::Name name_
, size_t nSliceBuffers = 4 , size_t nSliceBuffers = 4
) )
: rankMap(paramLength, np) : rankMap(paramLength, np, global_world)
, world(child_world) , world(child_world)
, universe(global_world) , universe(global_world)
, sliceLength(sliceLength_) , sliceLength(sliceLength_)
@ -419,16 +425,27 @@ namespace atrip {
* \brief Send asynchronously only if the state is Fetch * \brief Send asynchronously only if the state is Fetch
*/ */
void send( size_t otherRank void send( size_t otherRank
, Slice::Info const& info , Slice::LocalDatabaseElement const& el
, size_t tag) const noexcept { , size_t tag) const noexcept {
MPI_Request request; MPI_Request request;
bool sendData_p = false; bool sendData_p = false;
auto const& info = el.info;
if (info.state == Slice::Fetch) sendData_p = true; if (info.state == Slice::Fetch) sendData_p = true;
// TODO: remove this because I have SelfSufficient // TODO: remove this because I have SelfSufficient
if (otherRank == info.from.rank) sendData_p = false; if (otherRank == info.from.rank) sendData_p = false;
if (!sendData_p) return; if (!sendData_p) return;
switch (el.name) {
case Slice::Name::TA:
case Slice::Name::VIJKA:
if (otherRank / 48 == Atrip::rank / 48) {
Atrip::localSend++;
} else {
Atrip::networkSend++;
}
}
MPI_Isend( sources[info.from.source].data() MPI_Isend( sources[info.from.source].data()
, sources[info.from.source].size() , sources[info.from.source].size()
, MPI_DOUBLE /* TODO: adapt this with traits */ , MPI_DOUBLE /* TODO: adapt this with traits */

View File

@ -85,26 +85,30 @@ struct RankInfo {
const size_t ranksPerNode; const size_t ranksPerNode;
}; };
template <typename A>
std::vector<A> unique(std::vector<A> const &xs) {
auto result = xs;
std::sort(result.begin(), result.end());
auto const& last = std::unique(result.begin(), result.end());
result.erase(last, result.end());
return result;
}
std::vector<RankInfo> std::vector<RankInfo>
getNodeInfos(std::vector<string> const& nodeNames) { getNodeInfos(std::vector<string> const& nodeNames) {
std::vector<RankInfo> result; std::vector<RankInfo> result;
auto uniqueNames = nodeNames; auto const uniqueNames = unique(nodeNames);
{ auto const index = [&uniqueNames](std::string const& s) {
std::sort(uniqueNames.begin(), uniqueNames.end());
auto const& last = std::unique(uniqueNames.begin(), uniqueNames.end());
uniqueNames.erase(last, uniqueNames.end());
}
const auto index = [&uniqueNames](std::string const& s) {
auto const& it = std::find(uniqueNames.begin(), uniqueNames.end(), s); auto const& it = std::find(uniqueNames.begin(), uniqueNames.end(), s);
return std::distance(uniqueNames.begin(), it); return std::distance(uniqueNames.begin(), it);
}; };
std::vector<size_t> localRanks(uniqueNames.size(), 0); std::vector<size_t> localRanks(uniqueNames.size(), 0);
size_t rank = 0; size_t globalRank = 0;
for (auto const& name: nodeNames) { for (auto const& name: nodeNames) {
const size_t nodeId = index(name); const size_t nodeId = index(name);
result.push_back({name, result.push_back({name,
nodeId, nodeId,
rank++, globalRank++,
localRanks[nodeId]++, localRanks[nodeId]++,
std::count(nodeNames.begin(), std::count(nodeNames.begin(),
nodeNames.end(), nodeNames.end(),
@ -113,6 +117,25 @@ getNodeInfos(std::vector<string> const& nodeNames) {
} }
return result; return result;
} }
struct ClusterInfo {
const size_t nNodes, np, ranksPerNode;
const std::vector<RankInfo> rankInfos;
};
ClusterInfo
getClusterInfo(MPI_Comm comm) {
auto const names = getNodeNames(comm);
auto const rankInfos = getNodeInfos(names);
return ClusterInfo {
unique(names).size(),
names.size(),
rankInfos[0].ranksPerNode,
rankInfos
};
}
// Node information:2 ends here // Node information:2 ends here
// [[file:~/atrip/atrip.org::*Naive%20list][Naive list:1]] // [[file:~/atrip/atrip.org::*Naive%20list][Naive list:1]]
@ -189,8 +212,6 @@ size_t isOnNode(size_t tuple, size_t nodes) { return tuple % nodes; }
struct Info { struct Info {
size_t nNodes; size_t nNodes;
size_t Nv;
size_t np;
size_t nodeId; size_t nodeId;
}; };
@ -212,28 +233,33 @@ std::vector<size_t> getTupleNodes(ABCTuple t, size_t nNodes) {
// Utils:1 ends here // Utils:1 ends here
// [[file:~/atrip/atrip.org::*Distribution][Distribution:1]] // [[file:~/atrip/atrip.org::*Distribution][Distribution:1]]
std::vector<ABCTuple> ABCTuples specialDistribution(Info const& info, ABCTuples const& allTuples) {
specialDistribution(Info info, std::vector<ABCTuple> const& allTuples) {
std::vector<ABCTuple> nodeTuples; ABCTuples nodeTuples;
size_t nNodes(info.nNodes); size_t const nNodes(info.nNodes);
size_t np(info.np);
size_t N(allTuples.size());
// nodeid tuple list std::map< size_t /* nodeId */, ABCTuples >
std::map<size_t, std::vector<ABCTuple> > container1d; container1d, container2d, container3d;
std::map<size_t, std::vector<ABCTuple> > container2d;
std::map<size_t, std::vector<ABCTuple> > container3d;
// build container-n-d's // build container-n-d's
for (auto t: allTuples) { for (auto const& t: allTuples) {
// one which node(s) are the tuple elements located... // one which node(s) are the tuple elements located...
// put them into the right container // put them into the right container
auto nt = getTupleNodes(t, nNodes); auto const _nodes = getTupleNodes(t, nNodes);
if ( nt.size() == 1) container1d[nt[0]].push_back(t); switch (_nodes.size()) {
if ( nt.size() == 2) container2d[nt[0] + nNodes*nt[1]].push_back(t); case 1:
if ( nt.size() == 3) container1d[_nodes[0]].push_back(t);
container3d[nt[0] + nNodes*nt[1] + nNodes*nNodes*nt[2]].push_back(t); case 2:
container2d[ _nodes[0]
+ nNodes * _nodes[1]
].push_back(t);
case 3:
container3d[ _nodes[0]
+ nNodes * _nodes[1]
+ nNodes * nNodes * _nodes[2]
].push_back(t);
}
} }
if (info.nodeId == 0) if (info.nodeId == 0)
@ -241,97 +267,114 @@ specialDistribution(Info info, std::vector<ABCTuple> const& allTuples) {
// DISTRIBUTE 1-d containers // DISTRIBUTE 1-d containers
// every tuple which is only located at one node belongs to this node // every tuple which is only located at one node belongs to this node
{ {
auto const& tuplesVec = container1d[info.nodeId]; auto const& _tuplesVec = container1d[info.nodeId];
nodeTuples.resize(tuplesVec.size()); nodeTuples.resize(_tuplesVec.size());
std::copy(tuplesVec.begin(), tuplesVec.end(), nodeTuples.begin()); std::copy(_tuplesVec.begin(), _tuplesVec.end(), nodeTuples.begin());
} }
if (info.nodeId == 0) if (info.nodeId == 0)
std::cout << "\tBuilding 2-d containers\n"; std::cout << "\tBuilding 2-d containers\n";
// DISTRIBUTE 2-d containers // DISTRIBUTE 2-d containers
//the tuples which are located at two nodes are half/half given to these nodes //the tuples which are located at two nodes are half/half given to these nodes
for (auto &m: container2d) { for (auto const& m: container2d) {
size_t idx = m.first%nNodes;
size_t idy = m.first/nNodes;
size_t myNode = idx;
// either idx or idy is my node auto const& _tuplesVec = m.second;
if (idx != info.nodeId && idy != info.nodeId) continue; const
if (idy == info.nodeId) myNode = idy; size_t idx = m.first % nNodes
// remeber: m.first = idy * nNodes + idx
, idy = m.first / nNodes
, n_half = _tuplesVec.size() / 2
, size = nodeTuples.size()
;
auto tuplesVec = m.second; size_t nextra, nbegin, nend;
auto n = tuplesVec.size() / 2; if (info.nodeId == idx) {
auto size = nodeTuples.size(); nextra = n_half;
if (myNode == idx) { nbegin = 0 * n_half;
nodeTuples.resize(size + n); nend = n_half;
std::copy(tuplesVec.begin(), } else if (info.nodeId == idy) {
tuplesVec.begin() + n, nextra = _tuplesVec.size() - n_half;
nodeTuples.begin() + size); nbegin = 1 * n_half;
nend = _tuplesVec.size();
} else { } else {
auto ny = tuplesVec.size() - n; // either idx or idy is my node
nodeTuples.resize(size + ny); continue;
std::copy(tuplesVec.begin() + n,
tuplesVec.end(),
nodeTuples.begin() + size);
} }
nodeTuples.resize(size + nextra);
std::copy(_tuplesVec.begin() + nbegin,
_tuplesVec.begin() + nend,
nodeTuples.begin() + size);
} }
if (info.nodeId == 0) if (info.nodeId == 0)
std::cout << "\tBuilding 3-d containers\n"; std::cout << "\tBuilding 3-d containers\n";
// DISTRIBUTE 3-d containers // DISTRIBUTE 3-d containers
// similar game for the tuples which belong to three different nodes for (auto const& m: container3d){
for (auto m: container3d){ auto const& _tuplesVec = m.second;
auto tuplesVec = m.second;
auto idx = m.first%nNodes;
auto idy = (m.first/nNodes)%nNodes;
auto idz = m.first/nNodes/nNodes;
if (idx != info.nodeId && idy != info.nodeId && idz != info.nodeId) continue;
size_t nx = tuplesVec.size() / 3; const
size_t n, nbegin, nend; size_t idx = m.first % nNodes
, idy = (m.first / nNodes) % nNodes
// remember: m.first = idx + idy * nNodes + idz * nNodes^2
, idz = m.first / nNodes / nNodes
, n_third = _tuplesVec.size() / 3
, size = nodeTuples.size()
;
size_t nextra, nbegin, nend;
if (info.nodeId == idx) { if (info.nodeId == idx) {
n = nx; nextra = n_third;
nbegin = 0; nbegin = 0 * n_third;
nend = n; nend = nextra;
} else if (info.nodeId == idy) { } else if (info.nodeId == idy) {
n = nx; nextra = n_third;
nbegin = n; nbegin = 1 * n_third;
nend = n + n; nend = 2 * nextra;
} else if (info.nodeId == idz) {
nextra = _tuplesVec.size() - 2 * n_third;
nbegin = 2 * n_third;
nend = _tuplesVec.size();
} else { } else {
n = tuplesVec.size() - 2 * nx; // either idx or idy or idz is my node
nbegin = 2 * nx; continue;
nend = 2 * nx + n;
} }
auto size = nodeTuples.size(); nodeTuples.resize(size + nextra);
nodeTuples.resize(size + n); std::copy(_tuplesVec.begin() + nbegin,
std::copy(tuplesVec.begin() + nbegin, _tuplesVec.begin() + nend,
tuplesVec.begin() + nend,
nodeTuples.begin() + size); nodeTuples.begin() + size);
} }
if (info.nodeId == 0) if (info.nodeId == 0) std::cout << "\tswapping tuples...\n";
std::cout << "\tsorting...\n"; /*
// sort part of group-and-sort algorithm * sort part of group-and-sort algorithm
// every tuple on a given node is sorted in a way that * every tuple on a given node is sorted in a way that
// the 'home elements' are the fastest index. * the 'home elements' are the fastest index.
// 1:yyy 2:yyn(x) 3:yny(x) 4:ynn(x) 5:nyy 6:nyn(x) 7:nny 8:nnn * 1:yyy 2:yyn(x) 3:yny(x) 4:ynn(x) 5:nyy 6:nyn(x) 7:nny 8:nnn
size_t n = info.nodeId; */
for (auto &nt: nodeTuples){ for (auto &nt: nodeTuples){
if ( isOnNode(nt[0], nNodes) == n ){ // 1234 if ( isOnNode(nt[0], nNodes) == info.nodeId ){ // 1234
if ( isOnNode(nt[2], nNodes) != n ){ // 24 if ( isOnNode(nt[2], nNodes) != info.nodeId ){ // 24
size_t x(nt[0]); nt[0] = nt[2]; nt[2] = x; // switch first and last size_t const x(nt[0]);
nt[0] = nt[2]; // switch first and last
nt[2] = x;
} }
else if ( isOnNode(nt[1], nNodes) != n){ // 3 else if ( isOnNode(nt[1], nNodes) != info.nodeId){ // 3
size_t x(nt[0]); nt[0] = nt[1]; nt[1] = x; // switch first two size_t const x(nt[0]);
nt[0] = nt[1]; // switch first two
nt[1] = x;
} }
} else { } else {
if ( isOnNode(nt[1], nNodes) == n // 56 if ( isOnNode(nt[1], nNodes) == info.nodeId // 56
&& isOnNode(nt[2], nNodes) != n){ // 6 && isOnNode(nt[2], nNodes) != info.nodeId
size_t x(nt[1]); nt[1] = nt[2]; nt[2] = x; // switch last two ) { // 6
size_t const x(nt[1]);
nt[1] = nt[2]; // switch last two
nt[2] = x;
} }
} }
} }
@ -358,32 +401,22 @@ std::vector<ABCTuple> main(MPI_Comm universe, size_t Nv) {
std::vector<ABCTuple> result; std::vector<ABCTuple> result;
const auto nodeNames(getNodeNames(universe)); auto const nodeNames(getNodeNames(universe));
auto nodeNamesUnique(nodeNames); size_t const nNodes = unique(nodeNames).size();
{
const auto& last = std::unique(nodeNamesUnique.begin(),
nodeNamesUnique.end());
nodeNamesUnique.erase(last, nodeNamesUnique.end());
}
// we pick one rank from every node
auto const nodeInfos = getNodeInfos(nodeNames); auto const nodeInfos = getNodeInfos(nodeNames);
size_t const nNodes = nodeNamesUnique.size();
// We want to construct a communicator which only contains of one // We want to construct a communicator which only contains of one
// element per node // element per node
bool const makeDistribution bool const computeDistribution
= nodeInfos[rank].localRank == 0; = nodeInfos[rank].localRank == 0;
std::vector<ABCTuple> std::vector<ABCTuple>
nodeTuples = makeDistribution nodeTuples
? specialDistribution(Info{ nNodes = computeDistribution
, Nv ? specialDistribution(Info{nNodes, nodeInfos[rank].nodeId},
, np getAllTuplesList(Nv))
, nodeInfos[rank].nodeId : std::vector<ABCTuple>()
}, ;
getAllTuplesList(Nv))
: std::vector<ABCTuple>()
;
LOG(1,"Atrip") << "got nodeTuples\n"; LOG(1,"Atrip") << "got nodeTuples\n";
@ -400,7 +433,7 @@ std::vector<ABCTuple> main(MPI_Comm universe, size_t Nv) {
// Main:1 ends here // Main:1 ends here
// [[file:~/atrip/atrip.org::*Main][Main:2]] // [[file:~/atrip/atrip.org::*Main][Main:2]]
const size_t size_t const
tuplesPerRankLocal tuplesPerRankLocal
= nodeTuples.size() / nodeInfos[rank].ranksPerNode = nodeTuples.size() / nodeInfos[rank].ranksPerNode
+ size_t(nodeTuples.size() % nodeInfos[rank].ranksPerNode != 0) + size_t(nodeTuples.size() % nodeInfos[rank].ranksPerNode != 0)
@ -431,7 +464,8 @@ LOG(1,"Atrip") << "#nodes " << nNodes << "\n";
size_t const totalTuples size_t const totalTuples
= tuplesPerRankGlobal * nodeInfos[rank].ranksPerNode; = tuplesPerRankGlobal * nodeInfos[rank].ranksPerNode;
if (makeDistribution) { if (computeDistribution) {
// pad with FAKE_TUPLEs
nodeTuples.insert(nodeTuples.end(), nodeTuples.insert(nodeTuples.end(),
totalTuples - nodeTuples.size(), totalTuples - nodeTuples.size(),
FAKE_TUPLE); FAKE_TUPLE);
@ -462,13 +496,13 @@ if (makeDistribution) {
} }
// Main:4 ends here // Main:4 ends here
// [[file:~/atrip/atrip.org::*Main][Main:6]] // [[file:~/atrip/atrip.org::*Main][Main:5]]
LOG(1,"Atrip") << "scattering tuples \n"; LOG(1,"Atrip") << "scattering tuples \n";
return result; return result;
} }
// Main:6 ends here // Main:5 ends here
// [[file:~/atrip/atrip.org::*Interface][Interface:1]] // [[file:~/atrip/atrip.org::*Interface][Interface:1]]
struct Distribution : public TuplesDistribution { struct Distribution : public TuplesDistribution {

View File

@ -57,7 +57,7 @@ namespace atrip {
, child_world , child_world
, global_world , global_world
, Slice::TA , Slice::TA
, 4) { , 5) {
init(sourceTensor); init(sourceTensor);
} }
@ -94,7 +94,7 @@ namespace atrip {
, child_world , child_world
, global_world , global_world
, Slice::VIJKA , Slice::VIJKA
, 4) { , 5) {
init(sourceTensor); init(sourceTensor);
} }

View File

@ -9,13 +9,18 @@
using namespace atrip; using namespace atrip;
bool RankMap::RANK_ROUND_ROBIN;
int Atrip::rank; int Atrip::rank;
int Atrip::np; int Atrip::np;
Timings Atrip::chrono; Timings Atrip::chrono;
size_t Atrip::networkSend;
size_t Atrip::localSend;
void Atrip::init() { void Atrip::init() {
MPI_Comm_rank(MPI_COMM_WORLD, &Atrip::rank); MPI_Comm_rank(MPI_COMM_WORLD, &Atrip::rank);
MPI_Comm_size(MPI_COMM_WORLD, &Atrip::np); MPI_Comm_size(MPI_COMM_WORLD, &Atrip::np);
Atrip::networkSend = 0;
Atrip::localSend = 0;
} }
Atrip::Output Atrip::run(Atrip::Input const& in) { Atrip::Output Atrip::run(Atrip::Input const& in) {
@ -43,6 +48,15 @@ Atrip::Output Atrip::run(Atrip::Input const& in) {
in.ea->read_all(epsa.data()); in.ea->read_all(epsa.data());
in.Tph->read_all(Tai.data()); in.Tph->read_all(Tai.data());
RankMap::RANK_ROUND_ROBIN = in.rankRoundRobin;
if (RankMap::RANK_ROUND_ROBIN) {
LOG(0,"Atrip") << "Doing rank round robin slices distribution" << "\n";
} else {
LOG(0,"Atrip")
<< "Doing node > local rank round robin slices distribution" << "\n";
}
// COMMUNICATOR CONSTRUCTION ========================================={{{1 // COMMUNICATOR CONSTRUCTION ========================================={{{1
// //
// Construct a new communicator living only on a single rank // Construct a new communicator living only on a single rank
@ -224,7 +238,7 @@ Atrip::Output Atrip::run(Atrip::Input const& in) {
; ;
WITH_CHRONO("db:io:send", WITH_CHRONO("db:io:send",
u.send(otherRank, el.info, sendTag); u.send(otherRank, el, sendTag);
) )
} // send phase } // send phase
@ -268,6 +282,25 @@ Atrip::Output Atrip::run(Atrip::Input const& in) {
)) ))
if (iteration % in.iterationMod == 0) { if (iteration % in.iterationMod == 0) {
size_t networkSend;
MPI_Reduce(&Atrip::networkSend,
&networkSend,
1,
MPI_UINT64_T,
MPI_SUM,
0,
universe);
size_t localSend;
MPI_Reduce(&Atrip::localSend,
&localSend,
1,
MPI_UINT64_T,
MPI_SUM,
0,
universe);
LOG(0,"Atrip") LOG(0,"Atrip")
<< "iteration " << iteration << "iteration " << iteration
<< " [" << 100 * iteration / nIterations << "%]" << " [" << 100 * iteration / nIterations << "%]"
@ -275,7 +308,12 @@ Atrip::Output Atrip::run(Atrip::Input const& in) {
<< "GF)" << "GF)"
<< " (" << doublesFlops * iteration / Atrip::chrono["iterations"].count() << " (" << doublesFlops * iteration / Atrip::chrono["iterations"].count()
<< "GF)" << "GF)"
<< " ===========================\n"; << " :net " << networkSend
<< " :loc " << localSend
<< " :loc/net " << (double(localSend) / double(networkSend))
//<< " ===========================\n"
<< "\n";
// PRINT TIMINGS // PRINT TIMINGS
if (in.chrono) if (in.chrono)
@ -415,6 +453,7 @@ Atrip::Output Atrip::run(Atrip::Input const& in) {
} }
// TODO: remove this
if (isFakeTuple(i)) { if (isFakeTuple(i)) {
// fake iterations should also unwrap whatever they got // fake iterations should also unwrap whatever they got
WITH_RANK << iteration WITH_RANK << iteration