Comment most of Slice section
This commit is contained in:
parent
06c9f31bcd
commit
51c3203fda
775
atrip.org
775
atrip.org
@ -8,7 +8,9 @@ The algorithm uses two main data types, the =Slice= and the
|
|||||||
|
|
||||||
** The slice
|
** The slice
|
||||||
|
|
||||||
|
The following section introduces the idea of a slice.
|
||||||
|
|
||||||
|
*** Prolog :noexport:
|
||||||
#+begin_src c++ :tangle (atrip-slice-h)
|
#+begin_src c++ :tangle (atrip-slice-h)
|
||||||
#pragma once
|
#pragma once
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
@ -26,6 +28,7 @@ struct Slice {
|
|||||||
|
|
||||||
using F = double;
|
using F = double;
|
||||||
#+end_src
|
#+end_src
|
||||||
|
*** Introduction
|
||||||
|
|
||||||
A slice is the concept of a subset of values of a given tensor.
|
A slice is the concept of a subset of values of a given tensor.
|
||||||
As an example, for the doubles amplitudes \( T^{ab}_{ij} \), one need two kinds of objects:
|
As an example, for the doubles amplitudes \( T^{ab}_{ij} \), one need two kinds of objects:
|
||||||
@ -35,13 +38,63 @@ As an example, for the doubles amplitudes \( T^{ab}_{ij} \), one need two kinds
|
|||||||
- the object \( \mathsf{T}(a,b)_{ij} \) which for every pair of \( a, b \)
|
- the object \( \mathsf{T}(a,b)_{ij} \) which for every pair of \( a, b \)
|
||||||
corresponds the \( N_\mathrm{o}^2 \)-sized tensor \( T^{ab}_{ij} \).
|
corresponds the \( N_\mathrm{o}^2 \)-sized tensor \( T^{ab}_{ij} \).
|
||||||
|
|
||||||
|
*** Location
|
||||||
|
|
||||||
|
Every slice set, for instance,
|
||||||
|
\( S_k = \left\{
|
||||||
|
a \mapsto \mathsf{T}(a)^{b}_{ij}
|
||||||
|
\mid
|
||||||
|
a \in A_k
|
||||||
|
\right\} \)
|
||||||
|
where \( A_k \) is some subset of
|
||||||
|
\( \mathsf{N}_\mathrm{v} \),
|
||||||
|
gets stored in some rank \( k \).
|
||||||
|
In general however, the number of elements in \( A_k \) can be bigger
|
||||||
|
than the number of processes \( n_p \). Therefore in order to uniquely
|
||||||
|
indentify a given slice in \( S_k \) we need two identifiers,
|
||||||
|
the rank \( k \), which tells us in which core's memory the slice is
|
||||||
|
allocated, and an additional tag which we will call =source=.
|
||||||
|
|
||||||
|
The datatype that simply models this state of affairs
|
||||||
|
is therefore a simple structure:
|
||||||
|
|
||||||
|
#+begin_src c++ :tangle (atrip-slice-h)
|
||||||
|
struct Location { size_t rank; size_t source; };
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
*** Type
|
||||||
|
|
||||||
|
Due to the permutation operators in the equations
|
||||||
|
it is noticeable that for every one dimensional
|
||||||
|
slice and triple \( (a,b,c) \)
|
||||||
|
\begin{equation*}
|
||||||
|
a \mapsto \mathsf{t}(a)
|
||||||
|
\end{equation*}
|
||||||
|
one needs at the same time
|
||||||
|
\( \mathsf{t}(a) \),
|
||||||
|
\( \mathsf{t}(b) \) and
|
||||||
|
\( \mathsf{t}(c) \).
|
||||||
|
For two dimensional slices, i.e., slices of the form
|
||||||
|
\begin{equation*}
|
||||||
|
(a,b) \mapsto \mathsf{t}(a,b)
|
||||||
|
\end{equation*}
|
||||||
|
one needs in the equations the slices
|
||||||
|
\( \mathsf{t}(a,b) \),
|
||||||
|
\( \mathsf{t}(b,c) \) and
|
||||||
|
\( \mathsf{t}(a,c) \).
|
||||||
|
In addition, in the case of diagrams where
|
||||||
|
the integral \( V^{ab}_{ci} \) appears,
|
||||||
|
we additionaly need the permuted slices
|
||||||
|
from before, i.e.
|
||||||
|
\( \mathsf{t}(b,a) \),
|
||||||
|
\( \mathsf{t}(c,b) \) and
|
||||||
|
\( \mathsf{t}(c,a) \).
|
||||||
|
|
||||||
|
This means, every slice has associated with it
|
||||||
|
a type which denotes which permutation it is.
|
||||||
|
|
||||||
|
|
||||||
#+begin_src c++ :tangle (atrip-slice-h)
|
#+begin_src c++ :tangle (atrip-slice-h)
|
||||||
// ASSOCIATED TYPES %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
||||||
|
|
||||||
struct Location { size_t rank; size_t source; };
|
|
||||||
|
|
||||||
enum Type
|
enum Type
|
||||||
{ A = 10
|
{ A = 10
|
||||||
, B
|
, B
|
||||||
@ -57,53 +110,102 @@ As an example, for the doubles amplitudes \( T^{ab}_{ij} \), one need two kinds
|
|||||||
// The non-typed slice
|
// The non-typed slice
|
||||||
, Blank = 404
|
, Blank = 404
|
||||||
};
|
};
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
*** State
|
||||||
|
|
||||||
|
Every slice can be in different states and every state
|
||||||
|
denotes which function the slice is going to provide
|
||||||
|
and which relations they have between themselves.
|
||||||
|
|
||||||
|
- Fetch ::
|
||||||
|
A slice is in state =Fetch= when it
|
||||||
|
has a valid data pointer that **must** be written to.
|
||||||
|
A =Fetch= slice should not live very long, this means
|
||||||
|
that after the database send and receive phase,
|
||||||
|
=Fetch= slices should be changed into =Dispatched=
|
||||||
|
in order to start the process of writing to the
|
||||||
|
data pointer from some other rank.
|
||||||
|
- Dispatched ::
|
||||||
|
A =Dispatched= slice indicates that at some point
|
||||||
|
send and receive MPI calls have been dispatched
|
||||||
|
in order to get the data.
|
||||||
|
However, the calls have just been dispatched and there
|
||||||
|
is no warranty for the data to be there, for that,
|
||||||
|
the slice must be unwrapped.
|
||||||
|
- Ready ::
|
||||||
|
=Ready= means that the data pointer can be read from
|
||||||
|
directly.
|
||||||
|
- SelfSufficient ::
|
||||||
|
A slice is =SelfSufficient= when its contents are located
|
||||||
|
in the same rank that it lives, so that it does not have to
|
||||||
|
fetch from no other rank.
|
||||||
|
This is important in order to handle the data pointers correctly
|
||||||
|
and in order to save calls to MPI receive and send functions.
|
||||||
|
- Recycled ::
|
||||||
|
=Recycled= means that this slice gets its data pointer from another
|
||||||
|
slice, so it should not be written to
|
||||||
|
- Acceptor ::
|
||||||
|
=Acceptor= means that the slice can accept a new slice, it is
|
||||||
|
the counterpart of the =Blank= type, but for states
|
||||||
|
|
||||||
|
Again the implementation is a simple enum type.
|
||||||
|
|
||||||
|
#+begin_src c++ :tangle (atrip-slice-h)
|
||||||
enum State {
|
enum State {
|
||||||
// Fetch represents the state where a slice is to be fetched
|
|
||||||
// and has a valid data pointer that can be written to
|
|
||||||
Fetch = 0,
|
Fetch = 0,
|
||||||
// Dispatches represents the state that an MPI call has been
|
|
||||||
// dispatched in order to get the data, but the data has not been
|
|
||||||
// yet unwrapped, the data might be there or we might have to wait.
|
|
||||||
Dispatched = 2,
|
Dispatched = 2,
|
||||||
// Ready means that the data pointer can be read from
|
|
||||||
Ready = 1,
|
Ready = 1,
|
||||||
// Self sufficient is a slice when its contents are located
|
|
||||||
// in the same rank that it lives, so that it does not have to
|
|
||||||
// fetch from no one else.
|
|
||||||
SelfSufficient = 911,
|
SelfSufficient = 911,
|
||||||
// Recycled means that this slice gets its data pointer from another
|
|
||||||
// slice, so it should not be written to
|
|
||||||
Recycled = 123,
|
Recycled = 123,
|
||||||
// Acceptor means that the Slice can accept a new Slice, it is
|
|
||||||
// the counterpart of the Blank type, but for states
|
|
||||||
Acceptor = 405
|
Acceptor = 405
|
||||||
};
|
};
|
||||||
|
#+end_src
|
||||||
|
|
||||||
struct Info {
|
*** The Info structure
|
||||||
// which part of a,b,c the slice holds
|
|
||||||
PartialTuple tuple;
|
|
||||||
// The type of slice for the user to retrieve the correct one
|
|
||||||
Type type;
|
|
||||||
// What is the state of the slice
|
|
||||||
State state;
|
|
||||||
// Where the slice is to be retrieved
|
|
||||||
// NOTE: this can actually be computed from tuple
|
|
||||||
Location from;
|
|
||||||
// If the data are actually to be found in this other slice
|
|
||||||
Type recycling;
|
|
||||||
|
|
||||||
Info() : tuple{0,0}
|
Every slice has an information structure associated with it
|
||||||
, type{Blank}
|
that keeps track of the **variable** type, state and so on.
|
||||||
, state{Acceptor}
|
|
||||||
, from{0,0}
|
|
||||||
, recycling{Blank}
|
|
||||||
{}
|
|
||||||
};
|
|
||||||
|
|
||||||
using Ty_x_Tu = std::pair< Type, PartialTuple >;
|
#+begin_src c++ :tangle (atrip-slice-h)
|
||||||
|
struct Info {
|
||||||
|
// which part of a,b,c the slice holds
|
||||||
|
PartialTuple tuple;
|
||||||
|
// The type of slice for the user to retrieve the correct one
|
||||||
|
Type type;
|
||||||
|
// What is the state of the slice
|
||||||
|
State state;
|
||||||
|
// Where the slice is to be retrieved
|
||||||
|
Location from;
|
||||||
|
// If the data are actually to be found in this other slice
|
||||||
|
Type recycling;
|
||||||
|
|
||||||
// Names of the integrals that are considered in CCSD(T)
|
Info() : tuple{0,0}
|
||||||
|
, type{Blank}
|
||||||
|
, state{Acceptor}
|
||||||
|
, from{0,0}
|
||||||
|
, recycling{Blank}
|
||||||
|
{}
|
||||||
|
};
|
||||||
|
|
||||||
|
using Ty_x_Tu = std::pair< Type, PartialTuple >;
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
*** Name
|
||||||
|
|
||||||
|
CCSD(T) needs in this algorithm 5 types of tensor slices,
|
||||||
|
namely
|
||||||
|
\( V^{ij}_{ka} \), \( V^{ab}_{ci} \),
|
||||||
|
\( V^{ab}_{ij} \)
|
||||||
|
and two times \( T^{ab}_{ij} \).
|
||||||
|
The reason why we need two times the doubles
|
||||||
|
amplitudes is because in the doubles contribution
|
||||||
|
to the energy, the \( T \) amplidutes will be sliced
|
||||||
|
through one parameter for the particle contribution
|
||||||
|
and through two parameters for the hole contribution.
|
||||||
|
|
||||||
|
|
||||||
|
#+begin_src c++ :tangle (atrip-slice-h)
|
||||||
enum Name
|
enum Name
|
||||||
{ TA = 100
|
{ TA = 100
|
||||||
, VIJKA = 101
|
, VIJKA = 101
|
||||||
@ -111,257 +213,352 @@ As an example, for the doubles amplitudes \( T^{ab}_{ij} \), one need two kinds
|
|||||||
, TABIJ = 201
|
, TABIJ = 201
|
||||||
, VABIJ = 202
|
, VABIJ = 202
|
||||||
};
|
};
|
||||||
|
#+end_src
|
||||||
|
|
||||||
// DATABASE ==========================================================={{{1
|
*** Database
|
||||||
|
|
||||||
|
The database is a simple representation of the slices of a slice union.
|
||||||
|
Every element of the database is given by the name of the tensor it
|
||||||
|
represents and the internal information structure.
|
||||||
|
|
||||||
|
#+begin_src c++ :tangle (atrip-slice-h)
|
||||||
struct LocalDatabaseElement {
|
struct LocalDatabaseElement {
|
||||||
Slice::Name name;
|
Slice::Name name;
|
||||||
Slice::Info info;
|
Slice::Info info;
|
||||||
};
|
};
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
A local database (of a given rank) and the global database is thus simply
|
||||||
|
a vector of these elements.
|
||||||
|
|
||||||
|
#+begin_src c++ :tangle (atrip-slice-h)
|
||||||
using LocalDatabase = std::vector<LocalDatabaseElement>;
|
using LocalDatabase = std::vector<LocalDatabaseElement>;
|
||||||
using Database = LocalDatabase;
|
using Database = LocalDatabase;
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
*** MPI Types
|
||||||
|
#+begin_src c++ :tangle (atrip-slice-h)
|
||||||
|
struct mpi {
|
||||||
|
|
||||||
// STATIC METHODS ===========================================================
|
static MPI_Datatype vector(size_t n, MPI_Datatype const& DT) {
|
||||||
//
|
MPI_Datatype dt;
|
||||||
// They are useful to organize the structure of slices
|
MPI_Type_vector(n, 1, 1, DT, &dt);
|
||||||
|
MPI_Type_commit(&dt);
|
||||||
struct mpi {
|
return dt;
|
||||||
|
|
||||||
static MPI_Datatype vector(size_t n, MPI_Datatype const& DT) {
|
|
||||||
MPI_Datatype dt;
|
|
||||||
MPI_Type_vector(n, 1, 1, DT, &dt);
|
|
||||||
MPI_Type_commit(&dt);
|
|
||||||
return dt;
|
|
||||||
}
|
|
||||||
|
|
||||||
static MPI_Datatype sliceLocation () {
|
|
||||||
constexpr int n = 2;
|
|
||||||
// create a sliceLocation to measure in the current architecture
|
|
||||||
// the packing of the struct
|
|
||||||
Slice::Location measure;
|
|
||||||
MPI_Datatype dt;
|
|
||||||
const std::vector<int> lengths(n, 1);
|
|
||||||
const MPI_Datatype types[n] = {usizeDt(), usizeDt()};
|
|
||||||
|
|
||||||
// measure the displacements in the struct
|
|
||||||
size_t j = 0;
|
|
||||||
MPI_Aint displacements[n];
|
|
||||||
MPI_Get_address(&measure.rank, &displacements[j++]);
|
|
||||||
MPI_Get_address(&measure.source, &displacements[j++]);
|
|
||||||
for (size_t i = 1; i < n; i++) displacements[i] -= displacements[0];
|
|
||||||
displacements[0] = 0;
|
|
||||||
|
|
||||||
MPI_Type_create_struct(n, lengths.data(), displacements, types, &dt);
|
|
||||||
MPI_Type_commit(&dt);
|
|
||||||
return dt;
|
|
||||||
}
|
|
||||||
|
|
||||||
static MPI_Datatype enumDt() { return MPI_INT; }
|
|
||||||
static MPI_Datatype usizeDt() { return MPI_UINT64_T; }
|
|
||||||
|
|
||||||
static MPI_Datatype sliceInfo () {
|
|
||||||
constexpr int n = 5;
|
|
||||||
MPI_Datatype dt;
|
|
||||||
Slice::Info measure;
|
|
||||||
const std::vector<int> lengths(n, 1);
|
|
||||||
const MPI_Datatype types[n]
|
|
||||||
= { vector(2, usizeDt())
|
|
||||||
, enumDt()
|
|
||||||
, enumDt()
|
|
||||||
, sliceLocation()
|
|
||||||
, enumDt()
|
|
||||||
};
|
|
||||||
|
|
||||||
// create the displacements from the info measurement struct
|
|
||||||
size_t j = 0;
|
|
||||||
MPI_Aint displacements[n];
|
|
||||||
MPI_Get_address(measure.tuple.data(), &displacements[j++]);
|
|
||||||
MPI_Get_address(&measure.type, &displacements[j++]);
|
|
||||||
MPI_Get_address(&measure.state, &displacements[j++]);
|
|
||||||
MPI_Get_address(&measure.from, &displacements[j++]);
|
|
||||||
MPI_Get_address(&measure.recycling, &displacements[j++]);
|
|
||||||
for (size_t i = 1; i < n; i++) displacements[i] -= displacements[0];
|
|
||||||
displacements[0] = 0;
|
|
||||||
|
|
||||||
MPI_Type_create_struct(n, lengths.data(), displacements, types, &dt);
|
|
||||||
MPI_Type_commit(&dt);
|
|
||||||
return dt;
|
|
||||||
}
|
|
||||||
|
|
||||||
static MPI_Datatype localDatabaseElement () {
|
|
||||||
constexpr int n = 2;
|
|
||||||
MPI_Datatype dt;
|
|
||||||
LocalDatabaseElement measure;
|
|
||||||
const std::vector<int> lengths(n, 1);
|
|
||||||
const MPI_Datatype types[n]
|
|
||||||
= { enumDt()
|
|
||||||
, sliceInfo()
|
|
||||||
};
|
|
||||||
|
|
||||||
// measure the displacements in the struct
|
|
||||||
size_t j = 0;
|
|
||||||
MPI_Aint displacements[n];
|
|
||||||
MPI_Get_address(&measure.name, &displacements[j++]);
|
|
||||||
MPI_Get_address(&measure.info, &displacements[j++]);
|
|
||||||
for (size_t i = 1; i < n; i++) displacements[i] -= displacements[0];
|
|
||||||
displacements[0] = 0;
|
|
||||||
|
|
||||||
MPI_Type_create_struct(n, lengths.data(), displacements, types, &dt);
|
|
||||||
MPI_Type_commit(&dt);
|
|
||||||
return dt;
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
static
|
|
||||||
PartialTuple subtupleBySlice(ABCTuple abc, Type sliceType) {
|
|
||||||
switch (sliceType) {
|
|
||||||
case AB: return {abc[0], abc[1]};
|
|
||||||
case BC: return {abc[1], abc[2]};
|
|
||||||
case AC: return {abc[0], abc[2]};
|
|
||||||
case CB: return {abc[2], abc[1]};
|
|
||||||
case BA: return {abc[1], abc[0]};
|
|
||||||
case CA: return {abc[2], abc[0]};
|
|
||||||
case A: return {abc[0], 0};
|
|
||||||
case B: return {abc[1], 0};
|
|
||||||
case C: return {abc[2], 0};
|
|
||||||
default: throw "Switch statement not exhaustive!";
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static MPI_Datatype sliceLocation () {
|
||||||
|
constexpr int n = 2;
|
||||||
|
// create a sliceLocation to measure in the current architecture
|
||||||
|
// the packing of the struct
|
||||||
|
Slice::Location measure;
|
||||||
|
MPI_Datatype dt;
|
||||||
|
const std::vector<int> lengths(n, 1);
|
||||||
|
const MPI_Datatype types[n] = {usizeDt(), usizeDt()};
|
||||||
|
|
||||||
/**
|
// measure the displacements in the struct
|
||||||
,* It is important here to return a reference to a Slice
|
size_t j = 0;
|
||||||
,* not to accidentally copy the associated buffer of the slice.
|
MPI_Aint displacements[n];
|
||||||
,*/
|
MPI_Get_address(&measure.rank, &displacements[j++]);
|
||||||
static Slice& findOneByType(std::vector<Slice> &slices, Slice::Type type) {
|
MPI_Get_address(&measure.source, &displacements[j++]);
|
||||||
const auto sliceIt
|
for (size_t i = 1; i < n; i++) displacements[i] -= displacements[0];
|
||||||
= std::find_if(slices.begin(), slices.end(),
|
displacements[0] = 0;
|
||||||
[&type](Slice const& s) {
|
|
||||||
return type == s.info.type;
|
|
||||||
});
|
|
||||||
WITH_CRAZY_DEBUG
|
|
||||||
WITH_RANK
|
|
||||||
<< "\t__ looking for " << type << "\n";
|
|
||||||
if (sliceIt == slices.end())
|
|
||||||
throw std::domain_error("Slice by type not found!");
|
|
||||||
return *sliceIt;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
MPI_Type_create_struct(n, lengths.data(), displacements, types, &dt);
|
||||||
,* Check if an info has
|
MPI_Type_commit(&dt);
|
||||||
,*
|
return dt;
|
||||||
,*/
|
}
|
||||||
static std::vector<Slice*> hasRecycledReferencingToIt
|
|
||||||
( std::vector<Slice> &slices
|
|
||||||
, Info const& info
|
|
||||||
) {
|
|
||||||
std::vector<Slice*> result;
|
|
||||||
|
|
||||||
for (auto& s: slices)
|
static MPI_Datatype enumDt() { return MPI_INT; }
|
||||||
if ( s.info.recycling == info.type
|
static MPI_Datatype usizeDt() { return MPI_UINT64_T; }
|
||||||
&& s.info.tuple == info.tuple
|
|
||||||
&& s.info.state == Recycled
|
|
||||||
) result.push_back(&s);
|
|
||||||
|
|
||||||
return result;
|
static MPI_Datatype sliceInfo () {
|
||||||
}
|
constexpr int n = 5;
|
||||||
|
MPI_Datatype dt;
|
||||||
|
Slice::Info measure;
|
||||||
|
const std::vector<int> lengths(n, 1);
|
||||||
|
const MPI_Datatype types[n]
|
||||||
|
= { vector(2, usizeDt())
|
||||||
|
, enumDt()
|
||||||
|
, enumDt()
|
||||||
|
, sliceLocation()
|
||||||
|
, enumDt()
|
||||||
|
};
|
||||||
|
|
||||||
static Slice&
|
// create the displacements from the info measurement struct
|
||||||
findRecycledSource (std::vector<Slice> &slices, Slice::Info info) {
|
size_t j = 0;
|
||||||
const auto sliceIt
|
MPI_Aint displacements[n];
|
||||||
= std::find_if(slices.begin(), slices.end(),
|
MPI_Get_address(measure.tuple.data(), &displacements[j++]);
|
||||||
[&info](Slice const& s) {
|
MPI_Get_address(&measure.type, &displacements[j++]);
|
||||||
return info.recycling == s.info.type
|
MPI_Get_address(&measure.state, &displacements[j++]);
|
||||||
&& info.tuple == s.info.tuple
|
MPI_Get_address(&measure.from, &displacements[j++]);
|
||||||
&& State::Recycled != s.info.state
|
MPI_Get_address(&measure.recycling, &displacements[j++]);
|
||||||
;
|
for (size_t i = 1; i < n; i++) displacements[i] -= displacements[0];
|
||||||
});
|
displacements[0] = 0;
|
||||||
|
|
||||||
WITH_CRAZY_DEBUG
|
MPI_Type_create_struct(n, lengths.data(), displacements, types, &dt);
|
||||||
WITH_RANK << "__slice__:find: recycling source of "
|
MPI_Type_commit(&dt);
|
||||||
<< pretty_print(info) << "\n";
|
return dt;
|
||||||
if (sliceIt == slices.end())
|
}
|
||||||
throw std::domain_error( "Slice not found: "
|
|
||||||
+ pretty_print(info)
|
|
||||||
+ " rank: "
|
|
||||||
+ pretty_print(Atrip::rank)
|
|
||||||
);
|
|
||||||
WITH_RANK << "__slice__:find: " << pretty_print(sliceIt->info) << "\n";
|
|
||||||
return *sliceIt;
|
|
||||||
}
|
|
||||||
|
|
||||||
static Slice& findByTypeAbc
|
static MPI_Datatype localDatabaseElement () {
|
||||||
( std::vector<Slice> &slices
|
constexpr int n = 2;
|
||||||
, Slice::Type type
|
MPI_Datatype dt;
|
||||||
, ABCTuple const& abc
|
LocalDatabaseElement measure;
|
||||||
) {
|
const std::vector<int> lengths(n, 1);
|
||||||
const auto tuple = Slice::subtupleBySlice(abc, type);
|
const MPI_Datatype types[n]
|
||||||
const auto sliceIt
|
= { enumDt()
|
||||||
= std::find_if(slices.begin(), slices.end(),
|
, sliceInfo()
|
||||||
[&type, &tuple](Slice const& s) {
|
};
|
||||||
return type == s.info.type
|
|
||||||
&& tuple == s.info.tuple
|
|
||||||
;
|
|
||||||
});
|
|
||||||
WITH_CRAZY_DEBUG
|
|
||||||
WITH_RANK << "__slice__:find:" << type << " and tuple "
|
|
||||||
<< pretty_print(tuple)
|
|
||||||
<< "\n";
|
|
||||||
if (sliceIt == slices.end())
|
|
||||||
throw std::domain_error( "Slice not found: "
|
|
||||||
+ pretty_print(tuple)
|
|
||||||
+ ", "
|
|
||||||
+ pretty_print(type)
|
|
||||||
+ " rank: "
|
|
||||||
+ pretty_print(Atrip::rank)
|
|
||||||
);
|
|
||||||
return *sliceIt;
|
|
||||||
}
|
|
||||||
|
|
||||||
static Slice& findByInfo(std::vector<Slice> &slices,
|
// measure the displacements in the struct
|
||||||
Slice::Info const& info) {
|
size_t j = 0;
|
||||||
const auto sliceIt
|
MPI_Aint displacements[n];
|
||||||
= std::find_if(slices.begin(), slices.end(),
|
MPI_Get_address(&measure.name, &displacements[j++]);
|
||||||
[&info](Slice const& s) {
|
MPI_Get_address(&measure.info, &displacements[j++]);
|
||||||
// TODO: maybe implement comparison in Info struct
|
for (size_t i = 1; i < n; i++) displacements[i] -= displacements[0];
|
||||||
return info.type == s.info.type
|
displacements[0] = 0;
|
||||||
&& info.state == s.info.state
|
|
||||||
&& info.tuple == s.info.tuple
|
|
||||||
&& info.from.rank == s.info.from.rank
|
|
||||||
&& info.from.source == s.info.from.source
|
|
||||||
;
|
|
||||||
});
|
|
||||||
WITH_CRAZY_DEBUG
|
|
||||||
WITH_RANK << "__slice__:find:looking for " << pretty_print(info) << "\n";
|
|
||||||
if (sliceIt == slices.end())
|
|
||||||
throw std::domain_error( "Slice by info not found: "
|
|
||||||
+ pretty_print(info));
|
|
||||||
return *sliceIt;
|
|
||||||
}
|
|
||||||
|
|
||||||
// SLICE DEFINITION =================================================={{{1
|
MPI_Type_create_struct(n, lengths.data(), displacements, types, &dt);
|
||||||
|
MPI_Type_commit(&dt);
|
||||||
|
return dt;
|
||||||
|
}
|
||||||
|
|
||||||
// ATTRIBUTES ============================================================
|
};
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
*** Static utilities
|
||||||
|
|
||||||
|
This section presents some functions which are useful to work with
|
||||||
|
slices and are inside the namespace created by the slice struct.
|
||||||
|
|
||||||
|
|
||||||
|
The function =subtupleBySlice= gives to every =Slice::Type=
|
||||||
|
its meaning in terms of the triples \( (a,b,c) \).
|
||||||
|
|
||||||
|
Notice that since in general the relation
|
||||||
|
\( a < b < c \) holds (in our implementation), the case
|
||||||
|
of one-dimensional parametrizations =A=, =B= and =C= is well
|
||||||
|
defined.
|
||||||
|
|
||||||
|
The function should only throw if there is an implementation
|
||||||
|
error where the =Slice::Type= enum has been expanded and this
|
||||||
|
function has not been updated accordingly.
|
||||||
|
|
||||||
|
#+begin_src c++ :tangle (atrip-slice-h)
|
||||||
|
static
|
||||||
|
PartialTuple subtupleBySlice(ABCTuple abc, Type sliceType) {
|
||||||
|
switch (sliceType) {
|
||||||
|
case AB: return {abc[0], abc[1]};
|
||||||
|
case BC: return {abc[1], abc[2]};
|
||||||
|
case AC: return {abc[0], abc[2]};
|
||||||
|
case CB: return {abc[2], abc[1]};
|
||||||
|
case BA: return {abc[1], abc[0]};
|
||||||
|
case CA: return {abc[2], abc[0]};
|
||||||
|
case A: return {abc[0], 0};
|
||||||
|
case B: return {abc[1], 0};
|
||||||
|
case C: return {abc[2], 0};
|
||||||
|
default: throw "Switch statement not exhaustive!";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
In the context of cleaning up slices during the main loop,
|
||||||
|
it is important to check if a given slice has some slices
|
||||||
|
referencing to it in quality of recycled slices.
|
||||||
|
|
||||||
|
This function should therefore return a vector of pointers
|
||||||
|
of slices referencing to the given slice's info, when
|
||||||
|
the length of the vector is zero, then there are no dangling
|
||||||
|
links.
|
||||||
|
#+begin_src c++ :tangle (atrip-slice-h)
|
||||||
|
static std::vector<Slice*> hasRecycledReferencingToIt
|
||||||
|
( std::vector<Slice> &slices
|
||||||
|
, Info const& info
|
||||||
|
) {
|
||||||
|
std::vector<Slice*> result;
|
||||||
|
|
||||||
|
for (auto& s: slices)
|
||||||
|
if ( s.info.recycling == info.type
|
||||||
|
&& s.info.tuple == info.tuple
|
||||||
|
&& s.info.state == Recycled
|
||||||
|
) result.push_back(&s);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
The rest of the coming functions are utilities in order to find in a vector
|
||||||
|
of slices a given slice by reference. Mostly they are merely convenience
|
||||||
|
wrappers to the standard library function =std::find_if=.
|
||||||
|
|
||||||
|
They are named as =find<...>=, where =<...>= represents some condition
|
||||||
|
and must always return a reference to the found slice, i.e., =Slice&=.
|
||||||
|
=Atrip= relies on these functions to find the sought for slices,
|
||||||
|
therefore these functions will throw a =std::domain_error= if the
|
||||||
|
given slice could not be found.
|
||||||
|
|
||||||
|
#+begin_src c++ :tangle (atrip-slice-h)
|
||||||
|
static Slice& findOneByType(std::vector<Slice> &slices, Slice::Type type) {
|
||||||
|
const auto sliceIt
|
||||||
|
= std::find_if(slices.begin(), slices.end(),
|
||||||
|
[&type](Slice const& s) {
|
||||||
|
return type == s.info.type;
|
||||||
|
});
|
||||||
|
WITH_CRAZY_DEBUG
|
||||||
|
WITH_RANK
|
||||||
|
<< "\t__ looking for " << type << "\n";
|
||||||
|
if (sliceIt == slices.end())
|
||||||
|
throw std::domain_error("Slice by type not found!");
|
||||||
|
return *sliceIt;
|
||||||
|
}
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
#+begin_src c++ :tangle (atrip-slice-h)
|
||||||
|
static Slice&
|
||||||
|
findRecycledSource (std::vector<Slice> &slices, Slice::Info info) {
|
||||||
|
const auto sliceIt
|
||||||
|
= std::find_if(slices.begin(), slices.end(),
|
||||||
|
[&info](Slice const& s) {
|
||||||
|
return info.recycling == s.info.type
|
||||||
|
&& info.tuple == s.info.tuple
|
||||||
|
&& State::Recycled != s.info.state
|
||||||
|
;
|
||||||
|
});
|
||||||
|
|
||||||
|
WITH_CRAZY_DEBUG
|
||||||
|
WITH_RANK << "__slice__:find: recycling source of "
|
||||||
|
<< pretty_print(info) << "\n";
|
||||||
|
if (sliceIt == slices.end())
|
||||||
|
throw std::domain_error( "Slice not found: "
|
||||||
|
+ pretty_print(info)
|
||||||
|
+ " rank: "
|
||||||
|
+ pretty_print(Atrip::rank)
|
||||||
|
);
|
||||||
|
WITH_RANK << "__slice__:find: " << pretty_print(sliceIt->info) << "\n";
|
||||||
|
return *sliceIt;
|
||||||
|
}
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
#+begin_src c++ :tangle (atrip-slice-h)
|
||||||
|
static Slice& findByTypeAbc
|
||||||
|
( std::vector<Slice> &slices
|
||||||
|
, Slice::Type type
|
||||||
|
, ABCTuple const& abc
|
||||||
|
) {
|
||||||
|
const auto tuple = Slice::subtupleBySlice(abc, type);
|
||||||
|
const auto sliceIt
|
||||||
|
= std::find_if(slices.begin(), slices.end(),
|
||||||
|
[&type, &tuple](Slice const& s) {
|
||||||
|
return type == s.info.type
|
||||||
|
&& tuple == s.info.tuple
|
||||||
|
;
|
||||||
|
});
|
||||||
|
WITH_CRAZY_DEBUG
|
||||||
|
WITH_RANK << "__slice__:find:" << type << " and tuple "
|
||||||
|
<< pretty_print(tuple)
|
||||||
|
<< "\n";
|
||||||
|
if (sliceIt == slices.end())
|
||||||
|
throw std::domain_error( "Slice not found: "
|
||||||
|
+ pretty_print(tuple)
|
||||||
|
+ ", "
|
||||||
|
+ pretty_print(type)
|
||||||
|
+ " rank: "
|
||||||
|
+ pretty_print(Atrip::rank)
|
||||||
|
);
|
||||||
|
return *sliceIt;
|
||||||
|
}
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
#+begin_src c++ :tangle (atrip-slice-h)
|
||||||
|
static Slice& findByInfo(std::vector<Slice> &slices,
|
||||||
|
Slice::Info const& info) {
|
||||||
|
const auto sliceIt
|
||||||
|
= std::find_if(slices.begin(), slices.end(),
|
||||||
|
[&info](Slice const& s) {
|
||||||
|
// TODO: maybe implement comparison in Info struct
|
||||||
|
return info.type == s.info.type
|
||||||
|
&& info.state == s.info.state
|
||||||
|
&& info.tuple == s.info.tuple
|
||||||
|
&& info.from.rank == s.info.from.rank
|
||||||
|
&& info.from.source == s.info.from.source
|
||||||
|
;
|
||||||
|
});
|
||||||
|
WITH_CRAZY_DEBUG
|
||||||
|
WITH_RANK << "__slice__:find:looking for " << pretty_print(info) << "\n";
|
||||||
|
if (sliceIt == slices.end())
|
||||||
|
throw std::domain_error( "Slice by info not found: "
|
||||||
|
+ pretty_print(info));
|
||||||
|
return *sliceIt;
|
||||||
|
}
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
*** Attributes
|
||||||
|
|
||||||
|
A slice object does not own data, it is just a container
|
||||||
|
or a pointer to data together with additional bookkeeping facilities.
|
||||||
|
|
||||||
|
It includes an info structure with the information about the slice,
|
||||||
|
=Type=, =State= etc, which will be later communicated to other ranks.
|
||||||
|
|
||||||
|
#+begin_src c++ :tangle (atrip-slice-h)
|
||||||
Info info;
|
Info info;
|
||||||
F *data;
|
#+end_src
|
||||||
MPI_Request request;
|
|
||||||
const size_t size;
|
|
||||||
|
|
||||||
|
A pointer to data is also necessary for the =Slice= but not necessary
|
||||||
|
to be communicated to other ranks. The =Slice= should never allocate
|
||||||
|
or deallocate itself the pointer.
|
||||||
|
#+begin_src c++ :tangle (atrip-slice-h)
|
||||||
|
F *data;
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
An =MPI_Request= handle is also included so that the slices that are
|
||||||
|
to receive data through MPI can know which request they belong to.
|
||||||
|
#+begin_src c++ :tangle (atrip-slice-h)
|
||||||
|
MPI_Request request;
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
For practical purposes in MPI calls, the number of elements in =data= is also included.
|
||||||
|
#+begin_src c++ :tangle (atrip-slice-h)
|
||||||
|
const size_t size;
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
*** Member functions
|
||||||
|
|
||||||
|
It is important to note that a ready slice should not be recycled from
|
||||||
|
any other slice, so that it can have access by itself to the data.
|
||||||
|
#+begin_src c++ :tangle (atrip-slice-h)
|
||||||
void markReady() noexcept {
|
void markReady() noexcept {
|
||||||
info.state = Ready;
|
info.state = Ready;
|
||||||
info.recycling = Blank;
|
info.recycling = Blank;
|
||||||
}
|
}
|
||||||
|
#+end_src
|
||||||
|
|
||||||
/*
|
|
||||||
,* This means that the data is there
|
The following function asks wether or not
|
||||||
,*/
|
the slice has effectively been unwrapped or not,
|
||||||
|
i.e., wether or not the data are accessible and already
|
||||||
|
there. This can only happen in two ways, either
|
||||||
|
is the slice =Ready= or it is =SelfSufficient=,
|
||||||
|
i.e., the data pointed to was pre-distributed to the current node.
|
||||||
|
#+begin_src c++ :tangle (atrip-slice-h)
|
||||||
bool isUnwrapped() const noexcept {
|
bool isUnwrapped() const noexcept {
|
||||||
return info.state == Ready
|
return info.state == Ready
|
||||||
|| info.state == SelfSufficient
|
|| info.state == SelfSufficient
|
||||||
;
|
;
|
||||||
}
|
}
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
The function =isUnwrappable= answers which slices can be unwrapped
|
||||||
|
potentially. Unwrapped slices can be unwrapped again idempotentially.
|
||||||
|
Also =Recycled= slices can be unwrapped, i.e. the slices pointed to by them
|
||||||
|
will be unwrapped.
|
||||||
|
The only other possibility is that the slice has been dispatched
|
||||||
|
in the past and can be unwrapped. The case where the state
|
||||||
|
is =Dispatched= is the canonical intuitive case where a real process
|
||||||
|
of unwrapping, i.e. waiting for the data to get through the network,
|
||||||
|
is done.
|
||||||
|
#+begin_src c++ :tangle (atrip-slice-h)
|
||||||
bool isUnwrappable() const noexcept {
|
bool isUnwrappable() const noexcept {
|
||||||
return isUnwrapped()
|
return isUnwrapped()
|
||||||
|| info.state == Recycled
|
|| info.state == Recycled
|
||||||
@ -393,19 +590,20 @@ As an example, for the doubles amplitudes \( T^{ab}_{ij} \), one need two kinds
|
|||||||
;
|
;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#+end_src
|
||||||
|
|
||||||
/*
|
The function =isRecylable= answers the question, which slices can be recycled.
|
||||||
,* This function answers the question, which slices can be recycled.
|
|
||||||
,*
|
A slice can only be recycled if it is Fetch or Ready and has
|
||||||
,* A slice can only be recycled if it is Fetch or Ready and has
|
a valid datapointer.
|
||||||
,* a valid datapointer.
|
|
||||||
,*
|
In particular, SelfSufficient are not recyclable, since it is easier
|
||||||
,* In particular, SelfSufficient are not recyclable, since it is easier
|
just to create a SelfSufficient slice than deal with data dependencies.
|
||||||
,* just to create a SelfSufficient slice than deal with data dependencies.
|
|
||||||
,*
|
Furthermore, a recycled slice is not recyclable, if this is the case
|
||||||
,* Furthermore, a recycled slice is not recyclable, if this is the case
|
then it is either bad design or a bug.
|
||||||
,* then it is either bad design or a bug.
|
|
||||||
,*/
|
#+begin_src c++ :tangle (atrip-slice-h)
|
||||||
inline bool isRecyclable() const noexcept {
|
inline bool isRecyclable() const noexcept {
|
||||||
return ( info.state == Dispatched
|
return ( info.state == Dispatched
|
||||||
|| info.state == Ready
|
|| info.state == Ready
|
||||||
@ -414,21 +612,38 @@ As an example, for the doubles amplitudes \( T^{ab}_{ij} \), one need two kinds
|
|||||||
&& hasValidDataPointer()
|
&& hasValidDataPointer()
|
||||||
;
|
;
|
||||||
}
|
}
|
||||||
|
#+end_src
|
||||||
|
|
||||||
/*
|
|
||||||
,* This function describes if a slice has a valid data pointer.
|
The function =hasValidDataPointer= describes if a slice has a valid
|
||||||
,*
|
data pointer.
|
||||||
,* This is important to know if the slice has some data to it, also
|
|
||||||
,* some structural checks are done, so that it should not be Acceptor
|
This is important to know if the slice has some data to it, also
|
||||||
,* or Blank, if this is the case then it is a bug.
|
some structural checks are done, so that it should not be =Acceptor=
|
||||||
,*/
|
or =Blank=, if this is the case then it is a bug.
|
||||||
|
|
||||||
|
#+begin_src c++ :tangle (atrip-slice-h)
|
||||||
inline bool hasValidDataPointer() const noexcept {
|
inline bool hasValidDataPointer() const noexcept {
|
||||||
return data != nullptr
|
return data != nullptr
|
||||||
&& info.state != Acceptor
|
&& info.state != Acceptor
|
||||||
&& info.type != Blank
|
&& info.type != Blank
|
||||||
;
|
;
|
||||||
}
|
}
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
|
||||||
|
The function
|
||||||
|
=unwrapAndMarkReady=
|
||||||
|
calls the low-level MPI functions
|
||||||
|
in order to wait whenever the state of the slice is correct.
|
||||||
|
The main behaviour of the function should
|
||||||
|
- return if state is =Ready=, since then there is nothing to be done.
|
||||||
|
- throw if the state is not =Dispatched=, only a dispatched slice
|
||||||
|
can be unwrapped through MPI.
|
||||||
|
- throw if an MPI error happens.
|
||||||
|
|
||||||
|
|
||||||
|
#+begin_src c++ :tangle (atrip-slice-h)
|
||||||
void unwrapAndMarkReady() {
|
void unwrapAndMarkReady() {
|
||||||
if (info.state == Ready) return;
|
if (info.state == Ready) return;
|
||||||
if (info.state != Dispatched)
|
if (info.state != Dispatched)
|
||||||
@ -458,7 +673,10 @@ As an example, for the doubles amplitudes \( T^{ab}_{ij} \), one need two kinds
|
|||||||
<< "\n";
|
<< "\n";
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
*** Epilog :noexport:
|
||||||
|
#+begin_src c++ :tangle (atrip-slice-h)
|
||||||
Slice(size_t size_)
|
Slice(size_t size_)
|
||||||
: info({})
|
: info({})
|
||||||
, data(nullptr)
|
, data(nullptr)
|
||||||
@ -468,7 +686,11 @@ As an example, for the doubles amplitudes \( T^{ab}_{ij} \), one need two kinds
|
|||||||
|
|
||||||
}; // struct Slice
|
}; // struct Slice
|
||||||
|
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
*** Debug :noexport:
|
||||||
|
|
||||||
|
#+begin_src c++ :tangle (atrip-slice-h)
|
||||||
std::ostream& operator<<(std::ostream& out, Slice::Location const& v) {
|
std::ostream& operator<<(std::ostream& out, Slice::Location const& v) {
|
||||||
// TODO: remove me
|
// TODO: remove me
|
||||||
out << "{.r(" << v.rank << "), .s(" << v.source << ")};";
|
out << "{.r(" << v.rank << "), .s(" << v.source << ")};";
|
||||||
@ -528,6 +750,11 @@ namespace atrip {
|
|||||||
#+end_src
|
#+end_src
|
||||||
|
|
||||||
** The rank mapping
|
** The rank mapping
|
||||||
|
|
||||||
|
This section introduces the concept of rank mapping,
|
||||||
|
which defines how slices will be allocated to every
|
||||||
|
rank.
|
||||||
|
|
||||||
#+begin_src c++ :tangle (atrip-rankmap-h)
|
#+begin_src c++ :tangle (atrip-rankmap-h)
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
// [[file:../../atrip.org::*The slice][The slice:1]]
|
// [[file:../../atrip.org::*Prolog][Prolog:1]]
|
||||||
#pragma once
|
#pragma once
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
@ -14,401 +14,393 @@ namespace atrip {
|
|||||||
struct Slice {
|
struct Slice {
|
||||||
|
|
||||||
using F = double;
|
using F = double;
|
||||||
// The slice:1 ends here
|
// Prolog:1 ends here
|
||||||
|
|
||||||
// [[file:../../atrip.org::*The slice][The slice:2]]
|
// [[file:../../atrip.org::*Location][Location:1]]
|
||||||
// ASSOCIATED TYPES %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
struct Location { size_t rank; size_t source; };
|
||||||
|
// Location:1 ends here
|
||||||
|
|
||||||
struct Location { size_t rank; size_t source; };
|
// [[file:../../atrip.org::*Type][Type:1]]
|
||||||
|
enum Type
|
||||||
enum Type
|
{ A = 10
|
||||||
{ A = 10
|
, B
|
||||||
, B
|
, C
|
||||||
, C
|
// Two-parameter slices
|
||||||
// Two-parameter slices
|
, AB = 20
|
||||||
, AB = 20
|
, BC
|
||||||
, BC
|
, AC
|
||||||
, AC
|
// for abci and the doubles
|
||||||
// for abci and the doubles
|
, CB
|
||||||
, CB
|
, BA
|
||||||
, BA
|
, CA
|
||||||
, CA
|
// The non-typed slice
|
||||||
// The non-typed slice
|
, Blank = 404
|
||||||
, Blank = 404
|
|
||||||
};
|
|
||||||
|
|
||||||
enum State {
|
|
||||||
// Fetch represents the state where a slice is to be fetched
|
|
||||||
// and has a valid data pointer that can be written to
|
|
||||||
Fetch = 0,
|
|
||||||
// Dispatches represents the state that an MPI call has been
|
|
||||||
// dispatched in order to get the data, but the data has not been
|
|
||||||
// yet unwrapped, the data might be there or we might have to wait.
|
|
||||||
Dispatched = 2,
|
|
||||||
// Ready means that the data pointer can be read from
|
|
||||||
Ready = 1,
|
|
||||||
// Self sufficient is a slice when its contents are located
|
|
||||||
// in the same rank that it lives, so that it does not have to
|
|
||||||
// fetch from no one else.
|
|
||||||
SelfSufficient = 911,
|
|
||||||
// Recycled means that this slice gets its data pointer from another
|
|
||||||
// slice, so it should not be written to
|
|
||||||
Recycled = 123,
|
|
||||||
// Acceptor means that the Slice can accept a new Slice, it is
|
|
||||||
// the counterpart of the Blank type, but for states
|
|
||||||
Acceptor = 405
|
|
||||||
};
|
};
|
||||||
|
// Type:1 ends here
|
||||||
|
|
||||||
struct Info {
|
// [[file:../../atrip.org::*State][State:1]]
|
||||||
// which part of a,b,c the slice holds
|
enum State {
|
||||||
PartialTuple tuple;
|
Fetch = 0,
|
||||||
// The type of slice for the user to retrieve the correct one
|
Dispatched = 2,
|
||||||
Type type;
|
Ready = 1,
|
||||||
// What is the state of the slice
|
SelfSufficient = 911,
|
||||||
State state;
|
Recycled = 123,
|
||||||
// Where the slice is to be retrieved
|
Acceptor = 405
|
||||||
// NOTE: this can actually be computed from tuple
|
};
|
||||||
Location from;
|
// State:1 ends here
|
||||||
// If the data are actually to be found in this other slice
|
|
||||||
Type recycling;
|
|
||||||
|
|
||||||
Info() : tuple{0,0}
|
// [[file:../../atrip.org::*The Info structure][The Info structure:1]]
|
||||||
, type{Blank}
|
struct Info {
|
||||||
, state{Acceptor}
|
// which part of a,b,c the slice holds
|
||||||
, from{0,0}
|
PartialTuple tuple;
|
||||||
, recycling{Blank}
|
// The type of slice for the user to retrieve the correct one
|
||||||
{}
|
Type type;
|
||||||
|
// What is the state of the slice
|
||||||
|
State state;
|
||||||
|
// Where the slice is to be retrieved
|
||||||
|
Location from;
|
||||||
|
// If the data are actually to be found in this other slice
|
||||||
|
Type recycling;
|
||||||
|
|
||||||
|
Info() : tuple{0,0}
|
||||||
|
, type{Blank}
|
||||||
|
, state{Acceptor}
|
||||||
|
, from{0,0}
|
||||||
|
, recycling{Blank}
|
||||||
|
{}
|
||||||
|
};
|
||||||
|
|
||||||
|
using Ty_x_Tu = std::pair< Type, PartialTuple >;
|
||||||
|
// The Info structure:1 ends here
|
||||||
|
|
||||||
|
// [[file:../../atrip.org::*Name][Name:1]]
|
||||||
|
enum Name
|
||||||
|
{ TA = 100
|
||||||
|
, VIJKA = 101
|
||||||
|
, VABCI = 200
|
||||||
|
, TABIJ = 201
|
||||||
|
, VABIJ = 202
|
||||||
};
|
};
|
||||||
|
// Name:1 ends here
|
||||||
|
|
||||||
using Ty_x_Tu = std::pair< Type, PartialTuple >;
|
// [[file:../../atrip.org::*Database][Database:1]]
|
||||||
|
struct LocalDatabaseElement {
|
||||||
|
Slice::Name name;
|
||||||
|
Slice::Info info;
|
||||||
|
};
|
||||||
|
// Database:1 ends here
|
||||||
|
|
||||||
// Names of the integrals that are considered in CCSD(T)
|
// [[file:../../atrip.org::*Database][Database:2]]
|
||||||
enum Name
|
using LocalDatabase = std::vector<LocalDatabaseElement>;
|
||||||
{ TA = 100
|
using Database = LocalDatabase;
|
||||||
, VIJKA = 101
|
// Database:2 ends here
|
||||||
, VABCI = 200
|
|
||||||
, TABIJ = 201
|
|
||||||
, VABIJ = 202
|
|
||||||
};
|
|
||||||
|
|
||||||
// DATABASE ==========================================================={{{1
|
// [[file:../../atrip.org::*MPI Types][MPI Types:1]]
|
||||||
struct LocalDatabaseElement {
|
struct mpi {
|
||||||
Slice::Name name;
|
|
||||||
Slice::Info info;
|
|
||||||
};
|
|
||||||
using LocalDatabase = std::vector<LocalDatabaseElement>;
|
|
||||||
using Database = LocalDatabase;
|
|
||||||
|
|
||||||
|
static MPI_Datatype vector(size_t n, MPI_Datatype const& DT) {
|
||||||
// STATIC METHODS ===========================================================
|
MPI_Datatype dt;
|
||||||
//
|
MPI_Type_vector(n, 1, 1, DT, &dt);
|
||||||
// They are useful to organize the structure of slices
|
MPI_Type_commit(&dt);
|
||||||
|
return dt;
|
||||||
struct mpi {
|
|
||||||
|
|
||||||
static MPI_Datatype vector(size_t n, MPI_Datatype const& DT) {
|
|
||||||
MPI_Datatype dt;
|
|
||||||
MPI_Type_vector(n, 1, 1, DT, &dt);
|
|
||||||
MPI_Type_commit(&dt);
|
|
||||||
return dt;
|
|
||||||
}
|
|
||||||
|
|
||||||
static MPI_Datatype sliceLocation () {
|
|
||||||
constexpr int n = 2;
|
|
||||||
// create a sliceLocation to measure in the current architecture
|
|
||||||
// the packing of the struct
|
|
||||||
Slice::Location measure;
|
|
||||||
MPI_Datatype dt;
|
|
||||||
const std::vector<int> lengths(n, 1);
|
|
||||||
const MPI_Datatype types[n] = {usizeDt(), usizeDt()};
|
|
||||||
|
|
||||||
// measure the displacements in the struct
|
|
||||||
size_t j = 0;
|
|
||||||
MPI_Aint displacements[n];
|
|
||||||
MPI_Get_address(&measure.rank, &displacements[j++]);
|
|
||||||
MPI_Get_address(&measure.source, &displacements[j++]);
|
|
||||||
for (size_t i = 1; i < n; i++) displacements[i] -= displacements[0];
|
|
||||||
displacements[0] = 0;
|
|
||||||
|
|
||||||
MPI_Type_create_struct(n, lengths.data(), displacements, types, &dt);
|
|
||||||
MPI_Type_commit(&dt);
|
|
||||||
return dt;
|
|
||||||
}
|
|
||||||
|
|
||||||
static MPI_Datatype enumDt() { return MPI_INT; }
|
|
||||||
static MPI_Datatype usizeDt() { return MPI_UINT64_T; }
|
|
||||||
|
|
||||||
static MPI_Datatype sliceInfo () {
|
|
||||||
constexpr int n = 5;
|
|
||||||
MPI_Datatype dt;
|
|
||||||
Slice::Info measure;
|
|
||||||
const std::vector<int> lengths(n, 1);
|
|
||||||
const MPI_Datatype types[n]
|
|
||||||
= { vector(2, usizeDt())
|
|
||||||
, enumDt()
|
|
||||||
, enumDt()
|
|
||||||
, sliceLocation()
|
|
||||||
, enumDt()
|
|
||||||
};
|
|
||||||
|
|
||||||
// create the displacements from the info measurement struct
|
|
||||||
size_t j = 0;
|
|
||||||
MPI_Aint displacements[n];
|
|
||||||
MPI_Get_address(measure.tuple.data(), &displacements[j++]);
|
|
||||||
MPI_Get_address(&measure.type, &displacements[j++]);
|
|
||||||
MPI_Get_address(&measure.state, &displacements[j++]);
|
|
||||||
MPI_Get_address(&measure.from, &displacements[j++]);
|
|
||||||
MPI_Get_address(&measure.recycling, &displacements[j++]);
|
|
||||||
for (size_t i = 1; i < n; i++) displacements[i] -= displacements[0];
|
|
||||||
displacements[0] = 0;
|
|
||||||
|
|
||||||
MPI_Type_create_struct(n, lengths.data(), displacements, types, &dt);
|
|
||||||
MPI_Type_commit(&dt);
|
|
||||||
return dt;
|
|
||||||
}
|
|
||||||
|
|
||||||
static MPI_Datatype localDatabaseElement () {
|
|
||||||
constexpr int n = 2;
|
|
||||||
MPI_Datatype dt;
|
|
||||||
LocalDatabaseElement measure;
|
|
||||||
const std::vector<int> lengths(n, 1);
|
|
||||||
const MPI_Datatype types[n]
|
|
||||||
= { enumDt()
|
|
||||||
, sliceInfo()
|
|
||||||
};
|
|
||||||
|
|
||||||
// measure the displacements in the struct
|
|
||||||
size_t j = 0;
|
|
||||||
MPI_Aint displacements[n];
|
|
||||||
MPI_Get_address(&measure.name, &displacements[j++]);
|
|
||||||
MPI_Get_address(&measure.info, &displacements[j++]);
|
|
||||||
for (size_t i = 1; i < n; i++) displacements[i] -= displacements[0];
|
|
||||||
displacements[0] = 0;
|
|
||||||
|
|
||||||
MPI_Type_create_struct(n, lengths.data(), displacements, types, &dt);
|
|
||||||
MPI_Type_commit(&dt);
|
|
||||||
return dt;
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
static
|
|
||||||
PartialTuple subtupleBySlice(ABCTuple abc, Type sliceType) {
|
|
||||||
switch (sliceType) {
|
|
||||||
case AB: return {abc[0], abc[1]};
|
|
||||||
case BC: return {abc[1], abc[2]};
|
|
||||||
case AC: return {abc[0], abc[2]};
|
|
||||||
case CB: return {abc[2], abc[1]};
|
|
||||||
case BA: return {abc[1], abc[0]};
|
|
||||||
case CA: return {abc[2], abc[0]};
|
|
||||||
case A: return {abc[0], 0};
|
|
||||||
case B: return {abc[1], 0};
|
|
||||||
case C: return {abc[2], 0};
|
|
||||||
default: throw "Switch statement not exhaustive!";
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static MPI_Datatype sliceLocation () {
|
||||||
|
constexpr int n = 2;
|
||||||
|
// create a sliceLocation to measure in the current architecture
|
||||||
|
// the packing of the struct
|
||||||
|
Slice::Location measure;
|
||||||
|
MPI_Datatype dt;
|
||||||
|
const std::vector<int> lengths(n, 1);
|
||||||
|
const MPI_Datatype types[n] = {usizeDt(), usizeDt()};
|
||||||
|
|
||||||
/**
|
// measure the displacements in the struct
|
||||||
* It is important here to return a reference to a Slice
|
size_t j = 0;
|
||||||
* not to accidentally copy the associated buffer of the slice.
|
MPI_Aint displacements[n];
|
||||||
*/
|
MPI_Get_address(&measure.rank, &displacements[j++]);
|
||||||
static Slice& findOneByType(std::vector<Slice> &slices, Slice::Type type) {
|
MPI_Get_address(&measure.source, &displacements[j++]);
|
||||||
const auto sliceIt
|
for (size_t i = 1; i < n; i++) displacements[i] -= displacements[0];
|
||||||
= std::find_if(slices.begin(), slices.end(),
|
displacements[0] = 0;
|
||||||
[&type](Slice const& s) {
|
|
||||||
return type == s.info.type;
|
|
||||||
});
|
|
||||||
WITH_CRAZY_DEBUG
|
|
||||||
WITH_RANK
|
|
||||||
<< "\t__ looking for " << type << "\n";
|
|
||||||
if (sliceIt == slices.end())
|
|
||||||
throw std::domain_error("Slice by type not found!");
|
|
||||||
return *sliceIt;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
MPI_Type_create_struct(n, lengths.data(), displacements, types, &dt);
|
||||||
* Check if an info has
|
MPI_Type_commit(&dt);
|
||||||
*
|
return dt;
|
||||||
*/
|
}
|
||||||
static std::vector<Slice*> hasRecycledReferencingToIt
|
|
||||||
( std::vector<Slice> &slices
|
|
||||||
, Info const& info
|
|
||||||
) {
|
|
||||||
std::vector<Slice*> result;
|
|
||||||
|
|
||||||
for (auto& s: slices)
|
static MPI_Datatype enumDt() { return MPI_INT; }
|
||||||
if ( s.info.recycling == info.type
|
static MPI_Datatype usizeDt() { return MPI_UINT64_T; }
|
||||||
&& s.info.tuple == info.tuple
|
|
||||||
&& s.info.state == Recycled
|
|
||||||
) result.push_back(&s);
|
|
||||||
|
|
||||||
return result;
|
static MPI_Datatype sliceInfo () {
|
||||||
}
|
constexpr int n = 5;
|
||||||
|
MPI_Datatype dt;
|
||||||
|
Slice::Info measure;
|
||||||
|
const std::vector<int> lengths(n, 1);
|
||||||
|
const MPI_Datatype types[n]
|
||||||
|
= { vector(2, usizeDt())
|
||||||
|
, enumDt()
|
||||||
|
, enumDt()
|
||||||
|
, sliceLocation()
|
||||||
|
, enumDt()
|
||||||
|
};
|
||||||
|
|
||||||
static Slice&
|
// create the displacements from the info measurement struct
|
||||||
findRecycledSource (std::vector<Slice> &slices, Slice::Info info) {
|
size_t j = 0;
|
||||||
const auto sliceIt
|
MPI_Aint displacements[n];
|
||||||
= std::find_if(slices.begin(), slices.end(),
|
MPI_Get_address(measure.tuple.data(), &displacements[j++]);
|
||||||
[&info](Slice const& s) {
|
MPI_Get_address(&measure.type, &displacements[j++]);
|
||||||
return info.recycling == s.info.type
|
MPI_Get_address(&measure.state, &displacements[j++]);
|
||||||
&& info.tuple == s.info.tuple
|
MPI_Get_address(&measure.from, &displacements[j++]);
|
||||||
&& State::Recycled != s.info.state
|
MPI_Get_address(&measure.recycling, &displacements[j++]);
|
||||||
;
|
for (size_t i = 1; i < n; i++) displacements[i] -= displacements[0];
|
||||||
});
|
displacements[0] = 0;
|
||||||
|
|
||||||
WITH_CRAZY_DEBUG
|
MPI_Type_create_struct(n, lengths.data(), displacements, types, &dt);
|
||||||
WITH_RANK << "__slice__:find: recycling source of "
|
MPI_Type_commit(&dt);
|
||||||
<< pretty_print(info) << "\n";
|
return dt;
|
||||||
if (sliceIt == slices.end())
|
}
|
||||||
throw std::domain_error( "Slice not found: "
|
|
||||||
+ pretty_print(info)
|
|
||||||
+ " rank: "
|
|
||||||
+ pretty_print(Atrip::rank)
|
|
||||||
);
|
|
||||||
WITH_RANK << "__slice__:find: " << pretty_print(sliceIt->info) << "\n";
|
|
||||||
return *sliceIt;
|
|
||||||
}
|
|
||||||
|
|
||||||
static Slice& findByTypeAbc
|
static MPI_Datatype localDatabaseElement () {
|
||||||
( std::vector<Slice> &slices
|
constexpr int n = 2;
|
||||||
, Slice::Type type
|
MPI_Datatype dt;
|
||||||
, ABCTuple const& abc
|
LocalDatabaseElement measure;
|
||||||
) {
|
const std::vector<int> lengths(n, 1);
|
||||||
const auto tuple = Slice::subtupleBySlice(abc, type);
|
const MPI_Datatype types[n]
|
||||||
const auto sliceIt
|
= { enumDt()
|
||||||
= std::find_if(slices.begin(), slices.end(),
|
, sliceInfo()
|
||||||
[&type, &tuple](Slice const& s) {
|
};
|
||||||
return type == s.info.type
|
|
||||||
&& tuple == s.info.tuple
|
|
||||||
;
|
|
||||||
});
|
|
||||||
WITH_CRAZY_DEBUG
|
|
||||||
WITH_RANK << "__slice__:find:" << type << " and tuple "
|
|
||||||
<< pretty_print(tuple)
|
|
||||||
<< "\n";
|
|
||||||
if (sliceIt == slices.end())
|
|
||||||
throw std::domain_error( "Slice not found: "
|
|
||||||
+ pretty_print(tuple)
|
|
||||||
+ ", "
|
|
||||||
+ pretty_print(type)
|
|
||||||
+ " rank: "
|
|
||||||
+ pretty_print(Atrip::rank)
|
|
||||||
);
|
|
||||||
return *sliceIt;
|
|
||||||
}
|
|
||||||
|
|
||||||
static Slice& findByInfo(std::vector<Slice> &slices,
|
// measure the displacements in the struct
|
||||||
Slice::Info const& info) {
|
size_t j = 0;
|
||||||
const auto sliceIt
|
MPI_Aint displacements[n];
|
||||||
= std::find_if(slices.begin(), slices.end(),
|
MPI_Get_address(&measure.name, &displacements[j++]);
|
||||||
[&info](Slice const& s) {
|
MPI_Get_address(&measure.info, &displacements[j++]);
|
||||||
// TODO: maybe implement comparison in Info struct
|
for (size_t i = 1; i < n; i++) displacements[i] -= displacements[0];
|
||||||
return info.type == s.info.type
|
displacements[0] = 0;
|
||||||
&& info.state == s.info.state
|
|
||||||
&& info.tuple == s.info.tuple
|
|
||||||
&& info.from.rank == s.info.from.rank
|
|
||||||
&& info.from.source == s.info.from.source
|
|
||||||
;
|
|
||||||
});
|
|
||||||
WITH_CRAZY_DEBUG
|
|
||||||
WITH_RANK << "__slice__:find:looking for " << pretty_print(info) << "\n";
|
|
||||||
if (sliceIt == slices.end())
|
|
||||||
throw std::domain_error( "Slice by info not found: "
|
|
||||||
+ pretty_print(info));
|
|
||||||
return *sliceIt;
|
|
||||||
}
|
|
||||||
|
|
||||||
// SLICE DEFINITION =================================================={{{1
|
MPI_Type_create_struct(n, lengths.data(), displacements, types, &dt);
|
||||||
|
MPI_Type_commit(&dt);
|
||||||
|
return dt;
|
||||||
|
}
|
||||||
|
|
||||||
// ATTRIBUTES ============================================================
|
};
|
||||||
Info info;
|
// MPI Types:1 ends here
|
||||||
F *data;
|
|
||||||
MPI_Request request;
|
|
||||||
const size_t size;
|
|
||||||
|
|
||||||
void markReady() noexcept {
|
// [[file:../../atrip.org::*Static utilities][Static utilities:1]]
|
||||||
info.state = Ready;
|
static
|
||||||
info.recycling = Blank;
|
PartialTuple subtupleBySlice(ABCTuple abc, Type sliceType) {
|
||||||
}
|
switch (sliceType) {
|
||||||
|
case AB: return {abc[0], abc[1]};
|
||||||
|
case BC: return {abc[1], abc[2]};
|
||||||
|
case AC: return {abc[0], abc[2]};
|
||||||
|
case CB: return {abc[2], abc[1]};
|
||||||
|
case BA: return {abc[1], abc[0]};
|
||||||
|
case CA: return {abc[2], abc[0]};
|
||||||
|
case A: return {abc[0], 0};
|
||||||
|
case B: return {abc[1], 0};
|
||||||
|
case C: return {abc[2], 0};
|
||||||
|
default: throw "Switch statement not exhaustive!";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Static utilities:1 ends here
|
||||||
|
|
||||||
/*
|
// [[file:../../atrip.org::*Static utilities][Static utilities:2]]
|
||||||
* This means that the data is there
|
static std::vector<Slice*> hasRecycledReferencingToIt
|
||||||
*/
|
( std::vector<Slice> &slices
|
||||||
bool isUnwrapped() const noexcept {
|
, Info const& info
|
||||||
return info.state == Ready
|
) {
|
||||||
|| info.state == SelfSufficient
|
std::vector<Slice*> result;
|
||||||
;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool isUnwrappable() const noexcept {
|
for (auto& s: slices)
|
||||||
return isUnwrapped()
|
if ( s.info.recycling == info.type
|
||||||
|| info.state == Recycled
|
&& s.info.tuple == info.tuple
|
||||||
|| info.state == Dispatched
|
&& s.info.state == Recycled
|
||||||
;
|
) result.push_back(&s);
|
||||||
}
|
|
||||||
|
|
||||||
inline bool isDirectlyFetchable() const noexcept {
|
return result;
|
||||||
return info.state == Ready || info.state == Dispatched;
|
}
|
||||||
}
|
// Static utilities:2 ends here
|
||||||
|
|
||||||
void free() noexcept {
|
// [[file:../../atrip.org::*Static utilities][Static utilities:3]]
|
||||||
info.tuple = {0, 0};
|
static Slice& findOneByType(std::vector<Slice> &slices, Slice::Type type) {
|
||||||
info.type = Blank;
|
const auto sliceIt
|
||||||
info.state = Acceptor;
|
= std::find_if(slices.begin(), slices.end(),
|
||||||
info.from = {0, 0};
|
[&type](Slice const& s) {
|
||||||
info.recycling = Blank;
|
return type == s.info.type;
|
||||||
data = nullptr;
|
});
|
||||||
}
|
WITH_CRAZY_DEBUG
|
||||||
|
WITH_RANK
|
||||||
|
<< "\t__ looking for " << type << "\n";
|
||||||
|
if (sliceIt == slices.end())
|
||||||
|
throw std::domain_error("Slice by type not found!");
|
||||||
|
return *sliceIt;
|
||||||
|
}
|
||||||
|
// Static utilities:3 ends here
|
||||||
|
|
||||||
inline bool isFree() const noexcept {
|
// [[file:../../atrip.org::*Static utilities][Static utilities:4]]
|
||||||
return info.tuple == PartialTuple{0, 0}
|
static Slice&
|
||||||
&& info.type == Blank
|
findRecycledSource (std::vector<Slice> &slices, Slice::Info info) {
|
||||||
&& info.state == Acceptor
|
const auto sliceIt
|
||||||
&& info.from.rank == 0
|
= std::find_if(slices.begin(), slices.end(),
|
||||||
&& info.from.source == 0
|
[&info](Slice const& s) {
|
||||||
&& info.recycling == Blank
|
return info.recycling == s.info.type
|
||||||
&& data == nullptr
|
&& info.tuple == s.info.tuple
|
||||||
;
|
&& State::Recycled != s.info.state
|
||||||
}
|
;
|
||||||
|
});
|
||||||
|
|
||||||
|
WITH_CRAZY_DEBUG
|
||||||
|
WITH_RANK << "__slice__:find: recycling source of "
|
||||||
|
<< pretty_print(info) << "\n";
|
||||||
|
if (sliceIt == slices.end())
|
||||||
|
throw std::domain_error( "Slice not found: "
|
||||||
|
+ pretty_print(info)
|
||||||
|
+ " rank: "
|
||||||
|
+ pretty_print(Atrip::rank)
|
||||||
|
);
|
||||||
|
WITH_RANK << "__slice__:find: " << pretty_print(sliceIt->info) << "\n";
|
||||||
|
return *sliceIt;
|
||||||
|
}
|
||||||
|
// Static utilities:4 ends here
|
||||||
|
|
||||||
/*
|
// [[file:../../atrip.org::*Static utilities][Static utilities:5]]
|
||||||
* This function answers the question, which slices can be recycled.
|
static Slice& findByTypeAbc
|
||||||
*
|
( std::vector<Slice> &slices
|
||||||
* A slice can only be recycled if it is Fetch or Ready and has
|
, Slice::Type type
|
||||||
* a valid datapointer.
|
, ABCTuple const& abc
|
||||||
*
|
) {
|
||||||
* In particular, SelfSufficient are not recyclable, since it is easier
|
const auto tuple = Slice::subtupleBySlice(abc, type);
|
||||||
* just to create a SelfSufficient slice than deal with data dependencies.
|
const auto sliceIt
|
||||||
*
|
= std::find_if(slices.begin(), slices.end(),
|
||||||
* Furthermore, a recycled slice is not recyclable, if this is the case
|
[&type, &tuple](Slice const& s) {
|
||||||
* then it is either bad design or a bug.
|
return type == s.info.type
|
||||||
*/
|
&& tuple == s.info.tuple
|
||||||
inline bool isRecyclable() const noexcept {
|
;
|
||||||
return ( info.state == Dispatched
|
});
|
||||||
|| info.state == Ready
|
WITH_CRAZY_DEBUG
|
||||||
|| info.state == Fetch
|
WITH_RANK << "__slice__:find:" << type << " and tuple "
|
||||||
)
|
<< pretty_print(tuple)
|
||||||
&& hasValidDataPointer()
|
<< "\n";
|
||||||
;
|
if (sliceIt == slices.end())
|
||||||
}
|
throw std::domain_error( "Slice not found: "
|
||||||
|
+ pretty_print(tuple)
|
||||||
|
+ ", "
|
||||||
|
+ pretty_print(type)
|
||||||
|
+ " rank: "
|
||||||
|
+ pretty_print(Atrip::rank)
|
||||||
|
);
|
||||||
|
return *sliceIt;
|
||||||
|
}
|
||||||
|
// Static utilities:5 ends here
|
||||||
|
|
||||||
/*
|
// [[file:../../atrip.org::*Static utilities][Static utilities:6]]
|
||||||
* This function describes if a slice has a valid data pointer.
|
static Slice& findByInfo(std::vector<Slice> &slices,
|
||||||
*
|
Slice::Info const& info) {
|
||||||
* This is important to know if the slice has some data to it, also
|
const auto sliceIt
|
||||||
* some structural checks are done, so that it should not be Acceptor
|
= std::find_if(slices.begin(), slices.end(),
|
||||||
* or Blank, if this is the case then it is a bug.
|
[&info](Slice const& s) {
|
||||||
*/
|
// TODO: maybe implement comparison in Info struct
|
||||||
inline bool hasValidDataPointer() const noexcept {
|
return info.type == s.info.type
|
||||||
return data != nullptr
|
&& info.state == s.info.state
|
||||||
&& info.state != Acceptor
|
&& info.tuple == s.info.tuple
|
||||||
&& info.type != Blank
|
&& info.from.rank == s.info.from.rank
|
||||||
;
|
&& info.from.source == s.info.from.source
|
||||||
}
|
;
|
||||||
|
});
|
||||||
|
WITH_CRAZY_DEBUG
|
||||||
|
WITH_RANK << "__slice__:find:looking for " << pretty_print(info) << "\n";
|
||||||
|
if (sliceIt == slices.end())
|
||||||
|
throw std::domain_error( "Slice by info not found: "
|
||||||
|
+ pretty_print(info));
|
||||||
|
return *sliceIt;
|
||||||
|
}
|
||||||
|
// Static utilities:6 ends here
|
||||||
|
|
||||||
void unwrapAndMarkReady() {
|
// [[file:../../atrip.org::*Attributes][Attributes:1]]
|
||||||
|
Info info;
|
||||||
|
// Attributes:1 ends here
|
||||||
|
|
||||||
|
// [[file:../../atrip.org::*Attributes][Attributes:2]]
|
||||||
|
F *data;
|
||||||
|
// Attributes:2 ends here
|
||||||
|
|
||||||
|
// [[file:../../atrip.org::*Attributes][Attributes:3]]
|
||||||
|
MPI_Request request;
|
||||||
|
// Attributes:3 ends here
|
||||||
|
|
||||||
|
// [[file:../../atrip.org::*Attributes][Attributes:4]]
|
||||||
|
const size_t size;
|
||||||
|
// Attributes:4 ends here
|
||||||
|
|
||||||
|
// [[file:../../atrip.org::*Member functions][Member functions:1]]
|
||||||
|
void markReady() noexcept {
|
||||||
|
info.state = Ready;
|
||||||
|
info.recycling = Blank;
|
||||||
|
}
|
||||||
|
// Member functions:1 ends here
|
||||||
|
|
||||||
|
// [[file:../../atrip.org::*Member functions][Member functions:2]]
|
||||||
|
bool isUnwrapped() const noexcept {
|
||||||
|
return info.state == Ready
|
||||||
|
|| info.state == SelfSufficient
|
||||||
|
;
|
||||||
|
}
|
||||||
|
// Member functions:2 ends here
|
||||||
|
|
||||||
|
// [[file:../../atrip.org::*Member functions][Member functions:3]]
|
||||||
|
bool isUnwrappable() const noexcept {
|
||||||
|
return isUnwrapped()
|
||||||
|
|| info.state == Recycled
|
||||||
|
|| info.state == Dispatched
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool isDirectlyFetchable() const noexcept {
|
||||||
|
return info.state == Ready || info.state == Dispatched;
|
||||||
|
}
|
||||||
|
|
||||||
|
void free() noexcept {
|
||||||
|
info.tuple = {0, 0};
|
||||||
|
info.type = Blank;
|
||||||
|
info.state = Acceptor;
|
||||||
|
info.from = {0, 0};
|
||||||
|
info.recycling = Blank;
|
||||||
|
data = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool isFree() const noexcept {
|
||||||
|
return info.tuple == PartialTuple{0, 0}
|
||||||
|
&& info.type == Blank
|
||||||
|
&& info.state == Acceptor
|
||||||
|
&& info.from.rank == 0
|
||||||
|
&& info.from.source == 0
|
||||||
|
&& info.recycling == Blank
|
||||||
|
&& data == nullptr
|
||||||
|
;
|
||||||
|
}
|
||||||
|
// Member functions:3 ends here
|
||||||
|
|
||||||
|
// [[file:../../atrip.org::*Member functions][Member functions:4]]
|
||||||
|
inline bool isRecyclable() const noexcept {
|
||||||
|
return ( info.state == Dispatched
|
||||||
|
|| info.state == Ready
|
||||||
|
|| info.state == Fetch
|
||||||
|
)
|
||||||
|
&& hasValidDataPointer()
|
||||||
|
;
|
||||||
|
}
|
||||||
|
// Member functions:4 ends here
|
||||||
|
|
||||||
|
// [[file:../../atrip.org::*Member functions][Member functions:5]]
|
||||||
|
inline bool hasValidDataPointer() const noexcept {
|
||||||
|
return data != nullptr
|
||||||
|
&& info.state != Acceptor
|
||||||
|
&& info.type != Blank
|
||||||
|
;
|
||||||
|
}
|
||||||
|
// Member functions:5 ends here
|
||||||
|
|
||||||
|
// [[file:../../atrip.org::*Member functions][Member functions:6]]
|
||||||
|
void unwrapAndMarkReady() {
|
||||||
if (info.state == Ready) return;
|
if (info.state == Ready) return;
|
||||||
if (info.state != Dispatched)
|
if (info.state != Dispatched)
|
||||||
throw
|
throw
|
||||||
@ -437,17 +429,20 @@ struct Slice {
|
|||||||
<< "\n";
|
<< "\n";
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
// Member functions:6 ends here
|
||||||
|
|
||||||
Slice(size_t size_)
|
// [[file:../../atrip.org::*Epilog][Epilog:1]]
|
||||||
: info({})
|
Slice(size_t size_)
|
||||||
, data(nullptr)
|
: info({})
|
||||||
, size(size_)
|
, data(nullptr)
|
||||||
{}
|
, size(size_)
|
||||||
|
{}
|
||||||
|
|
||||||
|
|
||||||
}; // struct Slice
|
}; // struct Slice
|
||||||
|
// Epilog:1 ends here
|
||||||
|
|
||||||
|
// [[file:../../atrip.org::*Debug][Debug:1]]
|
||||||
std::ostream& operator<<(std::ostream& out, Slice::Location const& v) {
|
std::ostream& operator<<(std::ostream& out, Slice::Location const& v) {
|
||||||
// TODO: remove me
|
// TODO: remove me
|
||||||
out << "{.r(" << v.rank << "), .s(" << v.source << ")};";
|
out << "{.r(" << v.rank << "), .s(" << v.source << ")};";
|
||||||
@ -464,4 +459,4 @@ std::ostream& operator<<(std::ostream& out, Slice::Info const& i) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
} // namespace atrip
|
} // namespace atrip
|
||||||
// The slice:2 ends here
|
// Debug:1 ends here
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user