Skip to content

Use template arguments rather than namespaces to distinguish CPU and GPU variants #255

Description

@dmorse

Current System:

The current (v1.4.0) organization of code for pscf_rpc and pscf_rpg involve classes defined in 5 namespaces:

  • Namespace Rp contains templates that implement most of the shared logic for CPU and GPU code.
  • Namespaces Rpc and Rpg contain classes analogous to those defined in Rp that are used only in one program (psf_rpg and pscf_rpc).
  • Namespaces Prdc::Cpu and Prdc::Cuda contain code for CPU and GPU versions of field and FFT classes

Almost every class in namespace Rp is a base class for specializations of two class templates defined in namespaces Rpc and Rpg, respectvely. Most of the subclasses defined in Rpc and Rpg are trivial, and exist only in order to segregate sets of classes used by different programs into different program level namespaces. Classes defined in Rpc and Rpg generally have a single template parameter, D, that represents the dimension of space.

Most classes in the Rp namespace are templates with two parameters - an integer D that represents the. dimension of space, and a type parameter T that represents a specialization of a "Types" class template, either Rpc::Types or Rpg::Types. The two "Types" class templates each contain a large set of aliases of classes that are defined in the Rpc or Rpg namespaces, and in the Prdc::Cpu or Prdc::Cuda namespace. The class templates defined in namespace Rp refer to classes defined in namespaces Rpc, Rpg, Prdc::Cpu and Prdc::Cuda on via these typename aliases, using e.g., "typename T::RField" or "typename T::System".

Proposal:

Make all of the classes defined in namespace Rp templates with two parameters: An integer D and a backend-identifier type parameter T. The argument assigned to parameter T will be a class that is used primarily as an identifier for what "backend" (e.g., CPU or Gpu) is being used for mathematical operations on large arrays. I propose calling these two classes Prdc::Cp (for CPU code) and Prdc::Cu (for Cuda code). These backend-identifier classes will play a role somewhat analogous to the current "Types" classes but will be much simpler: When conversion to the proposed new system is complete, the backend-identifier classes will not contain collections of aliases to classes defined in Rpc, Rpg, Prdc::Cpu and Prdc::Cuda similar to those currently defined by the Types classes, because these 4 backend-specific namespaces will have ceased to exist.

Get rid of all trivial subclasses that are defined in Rpc and Rpg namespaces and work directly with specializations of two-parameter templates defined in the shared Rp namespace. Change references to types defined as aliases by the current Types classes to direct references to two-parameter templates. Throughout namespace Rp, each type declaration of the form "typename T::Class" will thus be replaced by "Class<D,T>, where Class is the name of a two-parameter template defined in namespace Rp. When finished, there will be no class templates defined in the Rpc and Rpg namespaces, and so these specialized namespaces will cease to exist. The replacements for the current "Types" classes will also no longer need to contain aliases for classes defined in these two namespaces.

Convert the field classes (RField, RFieldDft, CField), associated FFT classes and other associated classes that are currently defined in namespaces Prdc::Cpu and Prdc::Cuda into templates that have two templates, D and T, and that are defined in namespace Prdc. For each such class, define two partial specializations with different explicit values of T=Cp and T=Cu. The current class template RField defined in namespace Prdc::Cpu will thus become a partial specialization "template RField<D, Cu> of a template <int D, typename T> RField defined in namespace Prdc. These partial specializations can be created simply by renaming the existing classes defined in Prdc::Cpu and Prdc::Cuda. Throughout namespace Rp, names of field and FFT classes that are referred to via aliases to names of two-parameter templates. For example, the alias "typename T::RField" will be replaced by "RField<D,T>" throughout class templates in namespace Rp. When finished, the Prdc::Cpu and Prdc::Cuda namespaces will be empty, and thus cease to exist. A a result, the replacements for the "Types" classes will also no longer need to contain aliases to class templates defined in these namespaces.

Special cases: Some analogous classes that are currently defined in Rpc and Rpg and are derived from a common base class defined in Rp have distinct implementations for some virtual functions but also some shared logic that is defined in the base class For example, some member functions defined by the Rpc::FieldIo and Rpg::FieldIo class templates differ because field IO operations for GPU code require explicit data transfer between host and device (because IO is done by the CPU but field data is stored in GPU global memory), while those for CPU code do not require any such data transfer. For such cases, change the name of the base class by adding a name suffix "Base" (e.g., Rp::FieldIoBase<D,T>) and define two explicit partial specializations of a template that does not have the name suffix "Base" with explicit choices T=Cp and T=Cu (e.g., template Rp::FieldIo<D,Cp> and template Rp::FieldIo<D,Cu>. Define virtual functions with distinct implementations in the partial specializations. Try to minimize the number of classes for which this use of inheritance is necessary to specialize behavior by finding ways to unify code in the base class template when possible.

When completed, it will be possible for a main program to construct an object of type Pscf::Rp::System<3,Cu> to create a 3D system that is designed to use a GPU backend with GPU kernels coded in Cuda.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

No labels
No labels

Projects

No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions