Skip to content

Instantly share code, notes, and snippets.

@willkill07
Last active July 20, 2017 03:53
Show Gist options
  • Save willkill07/4b46ec5ef8ac89e1e3552e83fa6ce462 to your computer and use it in GitHub Desktop.
Save willkill07/4b46ec5ef8ac89e1e3552e83fa6ce462 to your computer and use it in GitHub Desktop.
OpenMP policy tag dispatching
#ifndef FORALL_OPENMP_HPP_
#define FORALL_OPENMP_HPP_
#include "openmp.hpp"
namespace omp {
template <typename Exec, typename TagList>
exact<Exec, TagList, tags::For>
forall_impl(const Exec &) {
puts(" #pragma omp for nowait");
puts(" OMP_LOOP()");
}
template <typename Exec, typename TagList>
exact<Exec, TagList, tags::For, tags::Static>
forall_impl(const Exec &) {
printf(" #pragma omp for schedule(static,%d) nowait\n", Exec::chunk_size);
puts(" OMP_LOOP()");
}
template <typename Exec, typename TagList>
exact<Exec, TagList, tags::Parallel>
forall_impl(const Exec &) {
puts(" #pragma omp parallel");
puts(" {");
forall(typename Exec::inner());
puts(" }");
}
template <typename Exec, typename TagList>
exact<Exec, TagList, tags::BarrierBefore>
forall_impl(const Exec &) {
puts(" #pragma omp barrier");
forall(typename Exec::inner());
}
template <typename Exec, typename TagList>
exact<Exec, TagList, tags::BarrierAfter>
forall_impl(const Exec &) {
forall(typename Exec::inner());
puts(" #pragma omp barrier");
}
} // end namespace omp
// dispatch to omp policy
template <typename Exec>
typename std::enable_if<Exec::policy == Policy::openmp>::type
forall(const Exec &p) {
omp::forall_impl<Exec, omp::tag_list>(p);
}
#endif
#ifndef FORALL_SEQUENTIAL_HPP_
#define FORALL_SEQUENTIAL_HPP_
#include "sequential.hpp"
namespace sequential {
template <typename Exec>
void
forall_impl(const Exec &) {
puts(" SEQ_LOOP()");
}
}
// dispatch to sequential policy
template <typename Exec>
typename std::enable_if<Exec::policy == Policy::seq>::type
forall(const Exec &p) {
sequential::forall_impl(p);
}
#endif
#ifndef FORALL_TARGET_OPENMP_HPP_
#define FORALL_TARGET_OPENMP_HPP_
#include "target_openmp.hpp"
namespace target_omp {
template <typename Exec, typename TagList>
exact<Exec, TagList, tags::Target, tags::Teams, tags::Distribute>
forall_impl(const Exec &) {
printf(" #pragma omp target teams distribute num_teams(%d)\n",
Exec::num_teams);
forall(typename Exec::inner());
}
template <typename Exec, typename TagList>
exact<Exec, TagList, tags::Target, tags::Teams, tags::Distribute,
tags::Parallel, tags::For>
forall_impl(const Exec &) {
printf(" #pragma omp target teams distribute num_teams(%d) parallel for\n",
Exec::num_teams);
puts(" TARGET_OMP_LOOP();");
}
template <typename Exec, typename TagList>
exact<Exec, TagList, tags::Target, tags::Teams, tags::Distribute,
tags::Parallel, tags::For, tags::Static>
forall_impl(const Exec &) {
printf(
" #pragma omp target teams distribute num_teams(%d) parallel for schedule(static,%d)\n",
Exec::num_teams, Exec::chunk_size);
puts(" TARGET_OMP_LOOP();");
}
} // end namespace target_omp
// dispatch to target omp policy
template <typename Exec>
typename std::enable_if<Exec::policy == Policy::target_openmp>::type
forall(const Exec &p) {
target_omp::forall_impl<Exec, target_omp::tag_list>(p);
}
#endif
#ifndef FORALL_HPP_
#define FORALL_HPP_
#include "forall-openmp.hpp"
#include "forall-sequential.hpp"
#include "forall-target_openmp.hpp"
// template type -> value-based
template <typename Exec>
void
forall() {
forall(Exec());
}
#endif
#ifndef META_HPP_
#define META_HPP_
#include <type_traits>
// metaprogramming utils
template <bool...>
struct blist;
template <typename... Args>
struct list {};
template <typename... Args>
struct voider {
using type = void;
};
namespace detail {
template <typename Exec, typename T, typename... Ts>
struct count {
using child = count<Exec, Ts...>;
constexpr static bool res = std::is_base_of<T, Exec>::value;
constexpr static int true_ = res + child::true_;
constexpr static int false_ = !res + child::false_;
};
template <typename Exec, typename T>
struct count<Exec, T> {
constexpr static bool res = std::is_base_of<T, Exec>::value;
constexpr static int true_ = res;
constexpr static int false_ = !res;
};
template <typename Exec, typename TagList, typename... Tags>
struct exact;
template <typename Exec, typename... AvailableTags, typename... ExpectedTags>
struct exact<Exec, list<AvailableTags...>, ExpectedTags...> {
using A = count<Exec, AvailableTags...>;
using E = count<Exec, ExpectedTags...>;
constexpr static bool value = (A::true_ == E::true_) && (E::false_ == 0);
};
} // end namespace detail
template <typename Exec, typename TagList, typename... Tags>
using exact =
typename std::enable_if<detail::exact<Exec, TagList, Tags...>::value>::type;
#endif
#include <cstdio>
#include <type_traits>
#include "PolicyBase.hpp"
#include "sequential.hpp"
#include "openmp.hpp"
#include "target_openmp.hpp"
#include "forall.hpp"
int
main() {
puts("forall<seq_exec>();\n");
forall<seq_exec>();
putchar('\n');
puts("forall<omp_for_exec>();\n");
forall<omp_for_exec>();
putchar('\n');
puts("forall<omp_parallel_for_exec>();\n");
forall<omp_parallel_for_exec>();
putchar('\n');
puts("forall<omp_parallel_static_exec<16>>();\n");
forall<omp_parallel_static_exec<16>>();
putchar('\n');
puts("forall<omp_static_exec<8>>();\n");
forall<omp_static_exec<8>>();
putchar('\n');
puts("forall<omp_for_nowait_exec>();\n");
forall<omp_for_nowait_exec>();
putchar('\n');
puts("forall<omp_static_nowait_exec<8>>();\n");
forall<omp_static_nowait_exec<8>>();
putchar('\n');
puts("forall<omp_target_teams_distribute_parallel_for_exec<256>>();\n");
forall<omp_target_teams_distribute_parallel_for_exec<256>>();
putchar('\n');
puts("forall<omp_target_teams_distribute_parallel_static_exec<128,1>>();\n");
forall<omp_target_teams_distribute_parallel_static_exec<128, 1>>();
putchar('\n');
return 0;
}
#ifndef OPENMP_HPP_
#define OPENMP_HPP_
#include "meta.hpp"
#include "PolicyBase.hpp"
// OpenMP policy tags and types
namespace omp {
namespace tags {
struct Parallel {};
struct Static {};
struct BarrierAfter {};
struct BarrierBefore {};
struct For {};
} // end namespace tags
using tag_list = list<tags::Parallel, tags::Static, tags::BarrierAfter,
tags::BarrierBefore, tags::For>;
template <typename... Args>
using policy = PolicyBaseT<Policy::openmp, Platform::undefined, Args...>;
template <typename Inner>
struct Parallel : policy<tags::Parallel> {
using inner = Inner;
};
template <typename Loop>
struct BarrierAfter : policy<tags::BarrierAfter> {
using inner = Loop;
};
template <typename Loop>
struct BarrierBefore : policy<tags::BarrierBefore> {
using inner = Loop;
};
template <typename... Options>
struct For : policy<Options...>, tags::For {};
template <unsigned int N>
struct Static : policy<>, tags::Static {
static constexpr unsigned int chunk_size = N;
};
} // end namespace omp
using omp_for_exec = omp::BarrierAfter<omp::For<>>;
template <unsigned int N>
using omp_static_exec = omp::BarrierAfter<omp::For<omp::Static<N>>>;
using omp_for_nowait_exec = omp::For<>;
template <unsigned int N>
using omp_static_nowait_exec = omp::For<omp::Static<N>>;
template <typename Inner>
using omp_parallel_exec = omp::Parallel<Inner>;
using omp_parallel_for_exec = omp_parallel_exec<omp_for_exec>;
template <unsigned int N>
using omp_parallel_static_exec = omp_parallel_exec<omp_static_exec<N>>;
#endif
#ifndef POLICY_BASE_HPP_
#define POLICY_BASE_HPP_
#include <cstdio>
#include "meta.hpp"
// Policy base
enum class Policy { seq, openmp, target_openmp };
enum class Platform { undefined, cpu };
template <Policy Pol, Platform P, typename... Args>
struct PolicyBaseT : public Args... {
static constexpr Policy policy = Pol;
static constexpr Platform platform = P;
};
template <Policy Exec, Policy P, Policy... Rest>
struct NoneOf {
static constexpr bool value = (Exec != P) && NoneOf<Exec, Rest...>::value;
};
template <Policy Exec, Policy P>
struct NoneOf<Exec, P> {
static constexpr bool value = (Exec != P);
};
template <typename Exec>
typename std::enable_if<Exec::policy == Policy::seq>::type
forall(const Exec &p);
template <typename Exec>
typename std::enable_if<Exec::policy == Policy::openmp>::type
forall(const Exec &p);
template <typename Exec>
typename std::enable_if<Exec::policy == Policy::target_openmp>::type
forall(const Exec &p);
template <typename Exec>
typename std::enable_if<NoneOf<Exec::policy, Policy::seq, Policy::openmp,
Policy::target_openmp>::value>::type
forall(const Exec &) {
puts("We don't support the passed execution policy with forall");
}
#endif
#ifndef SEQUENTIAL_HPP_
#define SEQUENTIAL_HPP_
#include "PolicyBase.hpp"
struct seq_exec : PolicyBaseT<Policy::seq, Platform::undefined> {};
#endif
#ifndef TARGET_OPENMP_HPP_
#define TARGET_OPENMP_HPP_
#include "openmp.hpp"
// OpenMP policy tags and types
namespace target_omp {
namespace tags {
using namespace omp::tags;
struct Target {};
struct Teams {};
struct Distribute {};
} // end namespace tags
using tag_list =
list<tags::Target, tags::Teams, tags::Distribute, tags::Parallel,
tags::Static, tags::BarrierAfter, tags::BarrierBefore, tags::For>;
template <typename... Args>
using policy = PolicyBaseT<Policy::target_openmp, Platform::undefined, Args...>;
using omp::BarrierAfter;
using omp::BarrierBefore;
using omp::For;
using omp::Parallel;
using omp::Static;
template <unsigned int N>
struct TargetTeamsDistribute
: policy<tags::Target, tags::Teams, tags::Distribute> {
constexpr static unsigned int num_teams = N;
};
template <unsigned int N>
struct TargetTeamsDistributeParallelFor
: policy<tags::Target, tags::Teams, tags::Distribute, tags::Parallel,
tags::For> {
constexpr static unsigned int num_teams = N;
};
template <unsigned int N, unsigned int M>
struct TargetTeamsDistributeParallelStatic
: policy<tags::Target, tags::Teams, tags::Distribute, tags::Parallel,
tags::For, tags::Static> {
constexpr static unsigned int num_teams = N;
constexpr static unsigned int chunk_size = M;
};
} // end namespace target_omp
template <unsigned int N>
using omp_target_teams_distribute_exec = target_omp::TargetTeamsDistribute<N>;
template <unsigned int N>
using omp_target_teams_distribute_parallel_for_exec =
target_omp::TargetTeamsDistributeParallelFor<N>;
template <unsigned int N, unsigned int M>
using omp_target_teams_distribute_parallel_static_exec =
target_omp::TargetTeamsDistributeParallelStatic<N, M>;
#endif
@willkill07
Copy link
Author

willkill07 commented Jul 20, 2017

Output:

forall<seq_exec>();

    SEQ_LOOP()

forall<omp_for_exec>();

    #pragma omp for nowait
    OMP_LOOP()
    #pragma omp barrier

forall<omp_parallel_for_exec>();

    #pragma omp parallel
    {
    #pragma omp for nowait
    OMP_LOOP()
    #pragma omp barrier
    }

forall<omp_parallel_static_exec<16>>();

    #pragma omp parallel
    {
    #pragma omp for schedule(static,16) nowait
    OMP_LOOP()
    #pragma omp barrier
    }

forall<omp_static_exec<8>>();

    #pragma omp for schedule(static,8) nowait
    OMP_LOOP()
    #pragma omp barrier

forall<omp_for_nowait_exec>();

    #pragma omp for nowait
    OMP_LOOP()

forall<omp_static_nowait_exec<8>>();

    #pragma omp for schedule(static,8) nowait
    OMP_LOOP()

forall<omp_target_teams_distribute_parallel_for_exec<256>>();

    #pragma omp target teams distribute num_teams(256) parallel for
    TARGET_OMP_LOOP();

forall<omp_target_teams_distribute_parallel_static_exec<128,1>>();

    #pragma omp target teams distribute num_teams(128) parallel for schedule(static,1)
    TARGET_OMP_LOOP();

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