.. |br| raw:: html
Topology Design Idioms
======================
FleCSI uses three C++ idioms to implement topology types:
template specialization, template function overload, and tuple walkers.
* **Template Specialization** |br|
Explicit or partial template specializations use C++ type inference to
match a template type parameter to a specific implementation, thus
allowing users to customize the behavior of a class or struct
depending on the type of the parameter that is passed:
.. code-block:: cpp
// Unspecialized (default) behavior.
template
struct type {};
template<>
struct type {
static void method() {
// Implementation for type one.
} // method
}; // struct type
template<>
struct type {
static void method() {
// Implementation for type two.
} // method
}; // struct type
The distinction between *explicit* and *partial* specialization is
whether or not the specialized type is fully (explicit) or partially
qualified, i.e., partially specialized types leave some template
parameters unspecified.
* **Template Function Overload** |br|
Template function overloads are similar to template specialization,
but allow specialization of a method or function:
.. code-block:: cpp
struct enclosing_type_t {
template
void method(type_one & arg) {
// Implementation for type one.
} // method
template
void method(type_two & arg) {
// Implementation for type two.
} // method
}; // struct enclosing_type_t
* **Tuple Walker** |br|
The tuple walker idiom is really a calling technique used in
conjunction with template function overload that applies a *visit*
method, defined via the function template overload, to each
*type* or *value* of a
`std::tuple `_. The
distinction between tuple types and values is an important one, as it
distinguishes between static (type information, available at compile
time) and dynamic (variable information, available at runtime) state.
An example of FleCSI's use of the tuple walker idiom, applied to
dynamic tuple values, is the *task_prologue_t* type, used to add region
requirements for the Legion implementation of *flecsi_execute_task*:
.. code-block:: cpp
struct task_prologue_t : public
flecsi::utils::tuple_walker {
template
void visit(index_t::accessor &
accessor) {
// Implmentation for type
// index_t::accessor.
} // visit
}; // struct task_prologue_t
You may notice that I lied to you before about there only being three
idioms: Our tuple walker type also uses the CRTP idiom documented
`here `_.
Adding New Topologies
=====================
1. **Topology Type**: Add a new subdirectory to the *flecsi/topology*
directory named for the new topology type, e.g., *ntree*.
This subdirectory should include:
* interface.h: This file defines the topology interface, e.g.,
.. code-block:: cpp
namespace flecsi {
namespace topology {
template
struct ntree : ntree_base {
// interface ...
}; // struct ntree
} // namespace flecsi
} // namespace topology
* types.h: This file defines types that are used by FleCSI, and by
the new topology type. At a minimum, this file should define a base
type from which the new topology type shall inherit, and a
*coloring* type. The base class will be used to identify
specializations of the new type in explicit/partial specializations
and template function overloads. The coloring type should include
whatever interface and data members are required to form a
distributed-memory representation of the new topology:
.. code-block:: cpp
struct ntree_base {
using coloring = ntree_coloring_t;
// interface ...
}; // struct ntree_base
The base type should be named consistently with the new topology
type name, and should follow FleCSI naming conventions. The base
type must define the public *coloring* type.
2. **Topology Registration**: Define a partial specialization of the
*topology_registration* type in
*flecsi/data/topology_registration.h*. This type must
implement a *register_fields* method that adds the fields required to
represent the meta data associated with an instance of the new
topology type.
3. **Topology Instance**: Define runtime-specific topology instance types in
*data/runtime/topologies.h*, where *runtime* is implemented for each
supported backend runtime type, e.g., Legion, MPI, and HPX
(currently).
The new type must define a *set_coloring* method that takes the
*coloring* type defined in assocaited *types.h* file:
.. code-block:: cpp
template
struct topology_instance> {
using topology_reference_t =
topology_reference>;
static void set_coloring(topology_reference_t const & topology_reference,
ntree::coloring const & colorint) {
} // set_coloring
}; // topology_instance>
4. **Initialize Arguments**: Define a template function
overload of the *task_prologue_t* type in
*flecsi/execution/.../task_prologue.h* that adds the region
requirements for the given type instance (for Legion only),
updates distributed-memory data dependencies, and
sets a dirty (modified) bit for any fields or topologies that were
accessed with write privileges (write-only, or read-write).
5. **Bind Accessors**: Define a template function overload of the
*bind_accessors_t* type in
*flecsi/execution/runtime/bind_accessors.h*, where
*runtime* is implmented for each backend runtime. This function binds
backend data buffers into the topology accesor instance. The accessor
is defined as part of the topology type, and implements a
*proxy* `pattern `_.
6. **Unbind Accessors**: Define a template function overload of the
*unbind_accessors_t* type in
*flecsi/execution/runtime/unbind_accessors.h*, where
*runtime* is implmented for each backend runtime. This function unbinds
backend data buffers, and does any cleanup operations that are
necessary to complete task execution, e.g., committing changes to
sparse or dynamic storage class fields.
Topology Initialization Workflow
================================
1. User defines specialization policy
2. User defines topology type with policy
3. Register meta data fields for specialized topology type
4. User adds fields to topology-defined index spaces
5. User gets topology instance
6. User generates coloring and calls set_coloring on instance
7. FleCSI creates index spaces and index partitions
8. FleCSI invokes task to initialize topology meta data
9. User invokes task to initialize field state
.. vim: set tabstop=2 shiftwidth=2 expandtab fo=cqt tw=72 :