Commit 5ada23d8 authored by Quentin Khan's avatar Quentin Khan
Browse files

PerfTest: factorise configuration lookup

PerfTest compiles all FLL implementations configurations and then allows
to choosej one at run-time. The lookup phase was split between algorithm
and kernel. Both lookups code, which was almost identical, has been
factorized.

It is also easier to add a new lookup phase by creating a parameter
matcher.
parent d3c2965a
......@@ -420,138 +420,199 @@ namespace scalfmm {
};
/**
* \brief Kernel lookup
* \brief Find out if the Ith configuration of the first matcher is enabled
*
* Recursive template class to find whether the kernel name given in
* `params` matches a kernel descriptor. If so, calls the final step.
*
* \tparam FReal Floating point type
* \tparam I Current kernel index
*/
template<typename FReal, std::size_t I = 0,
bool = sfinae::is_enabled<kernel_descriptor<FReal, I> >::value,
bool = (I < max_descriptor_count)
>
struct kernel_lookup {
/// `I`th kernel descriptor type
using kernel_desc = kernel_descriptor<FReal, I>;
/**
* \brief Kernel lookup method
*
* Checks whether `I`th kernel descriptor name matches the given
* kernel. If so, calls the final step, otherwise checks next kernel
* desriptor.
*
* \tparam other_descs Descriptors found in previous steps
*
* \param params Program parameters
*/
template<typename... other_descs>
static void check(FPerfTestParams& params, type_list<other_descs...>) {
if(params.kernel == kernel_desc::name) {
setup_step<kernel_desc, other_descs...>::run(params);
} else {
kernel_lookup<FReal, I+1>::check(params, type_list<other_descs...>{});
}
}
template<class FReal, std::size_t I, class MatcherList> struct is_first_matcher_enabled {
enum {value = false};
};
template<class FReal, std::size_t I, template<class...> class List, class Matcher, class... Matchers>
struct is_first_matcher_enabled<FReal, I, List<Matcher, Matchers...>> {
enum {value = sfinae::is_enabled<typename Matcher::template desc<FReal, I> >::value};
};
/**
* \brief Kernel lookup disabled case
* \brief Runtime class lookup
*
* Recursive class template to find a run-time given FMM configuration
* (algorithm, kernel, etc). The configurations are all generated at
* compile-time.
*
* Each configuration element has a dedicated matcher. A matcher is a
* class that defines a descriptor template, a `match` and a `not_found`
* static methods.
*
* The matchers are stored in a template type list and are used one by
* one in a recursive manner. The match method is called with the index
* of the object to match. If the match result is `false`, a recursive
* call is made with the next index.
*
* Recursive template class to find whether the kernel name given in
* `params` matches a kernel descriptor. If so, calls the final step.
* #### Example
*
* ~~~{cpp}
* struct Matcher {
* template<class FReal, std::size_t I>
* using desc = my_descriptor<FReal, I>;
*
* template<class FReal, std::size_t I>
* static bool match(Params& params) {
* return I==params.i;
* }
*
* template<class FReal, std::size_t I>
* static void not_found(Params& params) {
* std::cerr << "Parameter was not found...";
* }
* };
*
* lookup<FReal, std::tuple<Matcher>>::check(params, {});
* ~~~
*
* This specialization skips *disabled* kernel descriptors.
*
* \tparam FReal Floating point type
* \tparam I Current kernel index
* \tparam MatcherList The remaining matcher types
* \tparam I Current configuration index
* \tparam A Must remain unspecified, used to choose the right template
* specialisation for disabled configurations
* \tparam B Must remain unspecified, used to stop the recursion after
* `max_descriptor_count` is reached.
*/
template<typename FReal, std::size_t I>
struct kernel_lookup<FReal, I, false, true> {
template<typename T>
static void check(FPerfTestParams& params, T) {
kernel_lookup<FReal, I+1>::check(params, T{});
}
template<class FReal, class MatcherList, std::size_t I = 0,
bool A = is_first_matcher_enabled<FReal, I, MatcherList >::value,
bool B = (I < max_descriptor_count)>
struct lookup {
static_assert(std::is_same<MatcherList,int>::value, "This Lookup decaration should never be instanciated");
};
/**
* \brief Kernel lookup recursion end
*
* Recursive template class to find whether the kernel name given in
* `params` matches a kernel descriptor. If so, calls the final step.
* \brief Runtime class lookup recursion end.
*
* This specialization ends the kernel lookup, no fitting kernel was
* found.
* This specialisation ends the recursion when the matcher list is empty
* and calls the final setup and run steps.
*
* \tparam FReal Floating point type
* \tparam I Current kernel index
* \tparam I Current configuration index
* \tparam A unused boolean
* \tparam B unused boolean
* \tparam List Template type list
*/
template<typename FReal, std::size_t I>
struct kernel_lookup<FReal, I, false, false> {
template<typename T>
static void check(const FPerfTestParams& params, T) {
std::cerr << "Kernel " << params.kernel << " does not exist.\n";
template<class FReal, std::size_t I, bool A, bool B, template<class...> class List>
struct lookup<FReal, List<>, I, A, B> {
/**
* \brief Start the test with found configuration
*
* \tparam descs Descriptors found in previous steps
*
* \param params Program parameters
*/
template<class... descs>
static void check(FPerfTestParams& params, List<descs...>) {
setup_step<descs...>::run(params);
}
};
/**
* \brief Algorithm lookup
* \brief Runtime class lookup main specialisation.
*
* Recursive template class to find whether the algorithm name given in
* `params` matches an algorithm descriptor. If so, calls the final step.
* This specialisation is chosen when the $I^{th}$ configuration is not
* disabled. It checks whether the configuration name is recognised by
* the matcher. If it is, it recurses and removes the current matcher
* from the list ; if not it increases I and recurses.
*
* \tparam FReal Floating point type
* \tparam I Current kernel index
* \tparam I Current configuration index
* \tparam Matcher Current matcher class
* \tparam OtherMatchers Next matcher classes to use
* \tparam List Template type list
*/
template<typename FReal, std::size_t I = 0,
bool = sfinae::is_enabled<algo_descriptor<FReal, I> >::value,
bool = (I < max_descriptor_count) >
struct algorithm_lookup {
/// `I`th algorithm descriptor
using algo_desc = algo_descriptor<FReal, I>;
/**
* \brief Algorithm lookup method
*
* Checks whether `I`th algorithm descriptor name matches the given
* algorithm. If so, calls the final step, otherwise checks next
* algorithm desriptor.
*
* \tparam other_descs Descriptors found in previous steps
*
* \param params Program parameters
*/
template<typename... other_descs>
static void check(FPerfTestParams& params, type_list<other_descs...>) {
if(params.algo == algo_desc::name) {
kernel_lookup<FReal>
::check(params, type_list<algo_desc, other_descs...>{});
template<class FReal, class Matcher, std::size_t I, class... OtherMatchers, template<class...> class List>
struct lookup<FReal, List<Matcher, OtherMatchers...>, I, true, true> {
using crit_desc = typename Matcher::template desc<FReal,I>;
template<class... other_descs>
static void check(FPerfTestParams& params, List<other_descs...>) {
if(Matcher::template match<FReal, I>(params)) {
lookup<FReal, List<OtherMatchers...>>
::check(params, List<crit_desc, other_descs...>{});
} else {
algorithm_lookup<FReal, I+1>::check(params, type_list<other_descs...>{});
lookup<FReal, List<Matcher, OtherMatchers...>, I+1>
::check(params, List<other_descs...>{});
}
}
};
template<typename FReal, std::size_t I>
struct algorithm_lookup<FReal, I, false, true> {
template<typename T>
static void check(FPerfTestParams& params, T) {
algorithm_lookup<FReal, I+1>::check(params, T{});
/**
* \brief Runtime class lookup disabled specialisation
*
* This specialization skips *disabled* configurations.
*
* \tparam FReal Floating point type
* \tparam I Current kernel index
* \tparam Matcher Current matcher class
* \tparam OtherMatchers Next matcher classes to use
* \tparam List Template type list
*/
template<class FReal, class Matcher, std::size_t I, class... OtherMatchers, template<class...> class List>
struct lookup<FReal, List<Matcher, OtherMatchers...>, I, false, true> {
template<class... other_descs>
static void check(FPerfTestParams& params, List<other_descs...>) {
lookup<FReal, List<Matcher, OtherMatchers...>, I+1>
::check(params, List<other_descs...>{});
}
};
/** \brief Algorithm lookup recursion end */
template<typename FReal, std::size_t I>
struct algorithm_lookup<FReal, I, false, false> {
template<typename T>
static void check(const FPerfTestParams& params, T) {
std::cerr << "Algorithm " << params.algo << " does not exist.\n";
/**
* \brief Runtime class lookup recursion end
*
* This specialization ends the configuration lookup when none was
* found.
*
* \tparam FReal Floating point type
* \tparam I Current matcher index
* \tparam Matcher Current matcher class
* \tparam OtherMatchers Next matcher classes to use
* \tparam List Template type list
*/
template<class FReal, std::size_t I, class Matcher, class... OtherMatchers, template<class...> class List>
struct lookup<FReal, List<Matcher, OtherMatchers...>, I, false, false> {
template<class T>
static void check(FPerfTestParams& params, T&&) {
Matcher::not_found(params);
}
};
}
/**
* \brief Algorithm configuration matcher.
*
* See @lookup.
*/
struct AlgorithmMatcher {
template<class FReal, std::size_t I> using desc = algo_descriptor<FReal, I>;
template<class FReal, std::size_t I> static bool match(FPerfTestParams& params) {
return algo_descriptor<FReal, I>::name == params.algo;
}
static void not_found(const FPerfTestParams& params) {
std::cerr << "Algorithm " << params.algo << " not found...\n";
}
};
/**
* \brief Kernel configuration matcher.
*
* See @lookup.
*/
struct KernelMatcher {
template<class FReal, std::size_t I> using desc = kernel_descriptor<FReal, I>;
template<class FReal, std::size_t I> static bool match(FPerfTestParams& params) {
return kernel_descriptor<FReal, I>::name == params.kernel;
}
static void not_found(const FPerfTestParams& params) {
std::cerr << "Kernel " << params.kernel << " not found...\n";
}
};
/**
* \brief Look for algorithm and kernel asked in parameter and run
......@@ -560,7 +621,8 @@ namespace scalfmm {
*/
template<typename FReal>
void run(FPerfTestParams& params) {
details::algorithm_lookup<FReal>::check(params, details::type_list<>{});
using matcher_list = details::type_list<AlgorithmMatcher, KernelMatcher>;
details::lookup<FReal, matcher_list>::check(params, {});
}
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment