Commit e2815223 authored by Quentin Khan's avatar Quentin Khan

Factorise kernel related methods in adaptive algorithms

The functions call the kernel setup() and cleanup() member function with
the tree (optionally) if they exist or do nothing.
parent 821206aa
......@@ -14,6 +14,8 @@
#include "Kernels/FKernelConcepts.hpp"
#include "kernel_utilities.hpp"
template<
class _Tree, class _Kernel,
class = inria::require<
......@@ -36,24 +38,6 @@ private:
tree_t& _tree;
kernel_t& _kernel;
template<typename K, typename Ret, typename... Args>
using has_setup = typename std::enable_if<
std::is_same<Ret, decltype(std::declval<K>().setup(std::declval<Args>()...))>::value
>::type*;
template<typename K, has_setup<K, void, tree_t> = nullptr>
void setup_kernel(K*) {
_kernel.setup(_tree);
}
template<typename K, has_setup<K, void> = nullptr>
void setup_kernel(K*) {
_kernel.setup();
}
void setup_kernel(...) {}
public:
FAdaptiveSequential(tree_t* tree, kernel_t* kernel) :
......@@ -82,7 +66,7 @@ public:
void run(int operations = FFmmNearAndFarFields) {
this->setup_kernel(&(this->_kernel));
scalfmm::setup_kernel(this->_kernel, this->_tree);
if(operations & FFmmP2M) {
// 1. source to up, P2M
......
......@@ -17,6 +17,8 @@
#include "Kernels/FKernelConcepts.hpp"
#include "kernel_utilities.hpp"
template<class _Tree, class _Kernel,
class = inria::require<
scalfmm::meta::adaptive_compatible<_Tree,_Kernel>
......@@ -84,7 +86,7 @@ public:
void run(int operations = FFmmNearAndFarFields) {
this->setup_kernel(&(this->_ref_kernel));
scalfmm::setup_kernel(this->_ref_kernel, this->_tree);
this->setup_starpu();
auto run = [this](const char* name, void (FAdaptiveStarPU::*op)()) {
......@@ -127,34 +129,11 @@ public:
}
this->cleanup_starpu();
this->cleanup_kernel(&this->_ref_kernel);
scalfmm::cleanup_kernel(this->_ref_kernel, this->_tree);
}
private:
template<class K>
auto setup_kernel(K* ker) -> decltype(ker->setup(_tree)) {
ker->setup(_tree);
}
template<class K>
auto setup_kernel(K* ker) -> decltype(ker->setup()) {
ker->setup();
}
void setup_kernel(...) {}
template<class K>
auto cleanup_kernel(K* ker) -> decltype(ker->cleanup(_tree)){
return ker->cleanup(_tree);
}
template<class K>
auto cleanup_kernel(K* ker) -> decltype(ker->cleanup()){
return ker->cleanup();
}
void cleanup_kernel(...) {}
template<class K>
auto fuse_kernel_results(K* ref, K* other) -> decltype(ref->fuse_results(*other)) {
......@@ -241,7 +220,7 @@ private:
int id = starpu_worker_get_id();
std::cout << "initialising worker " << id << '\n';
kernels[id].reset(new kernel_t(ref_kernel));
algo->setup_kernel(kernels[id].get());
scalfmm::setup_kernel(*kernels[id].get(), algo->_tree);
}
void setup_starpu() {
......@@ -289,7 +268,7 @@ private:
int id = starpu_worker_get_id();
std::cout << "cleaning up worker " << id << '\n';
algo->fuse_kernel_results(&ref_kernel, kernels[id].get());
algo->cleanup_kernel(kernels[id].get());
scalfmm::cleanup_kernel(*kernels[id].get(), algo->_tree);
}
......
......@@ -23,6 +23,8 @@
#include "Kernels/FKernelConcepts.hpp"
#include "kernel_utilities.hpp"
template<class _Tree, class _Kernel,
class = inria::require<
scalfmm::meta::adaptive_compatible<_Tree,_Kernel>
......@@ -46,28 +48,6 @@ protected:
/// Vector of kernels, one per thread
std::vector<std::unique_ptr<kernel_t>> _kernels;
/** \brief SFINAE shortcut to check `K.setup(Args...)` existence */
template<typename K, typename Ret, typename... Args>
using has_setup_member = typename std::enable_if<
std::is_same<Ret, decltype(std::declval<K>().setup(std::declval<Args>()...))>::value
>::type*;
/** \brief Calls K.setup(tree_t) if it exists, otherwise deleted by SFINAE */
template<typename K, has_setup_member<K, void, tree_t> = nullptr>
void setup_kernel(K* kernel) {
kernel->setup(_tree);
}
/** \brief Calls K.setup() if it exists, otherwise deleted by SFINAE */
template<typename K, has_setup_member<K, void> = nullptr>
void setup_kernel(K* kernel) {
kernel->setup();
}
/** \brief Fallback if both other overloads are deleted by SFINAE */
void setup_kernel(...) {}
/**
* \brief Data pool for mock dependency
*
......@@ -194,7 +174,8 @@ public:
#pragma omp parallel
{
this->setup_kernel(this->_kernels[omp_get_thread_num()].get());
scalfmm::setup_kernel(*(this->_kernels[omp_get_thread_num()].get()),
this->_tree);
#pragma omp barrier
#pragma omp single nowait
......
#ifndef _SCALFMM_KERNEL_UTILITIES_HPP_
#define _SCALFMM_KERNEL_UTILITIES_HPP_
#include "inria/meta.hpp"
namespace scalfmm {
namespace details {
/**
* \brief Check for kernel.setup(tree) existence
*/
template<class Kernel, class... Args>
struct has_setup {
template<class K>
constexpr static auto check(K* k, Args* ... args)
-> decltype(k->setup(*args...), void(), true)
{ return true; }
constexpr static bool check(...) {return false;}
static constexpr bool value = check((Kernel*)0, (Args*)0 ...);
};
/**
* \brief Call kernel.setup(tree)
*
* \param kernel Kernel to setup
* \param tree Tree to setup with
*
* \tparam Kernel Kernel type
* \tparam Tree Tree type
*/
template<class Kernel, class Tree>
void setup_kernel(has_setup<Kernel, Tree>, Kernel& kernel, Tree& tree) {
kernel.setup(tree);
}
/**
* \brief Call kernel.setup()
*
* \param kernel Kernel to setup
*
* \tparam Kernel Kernel type
* \tparam Tree Tree type, the tree is not used
*/
template<class Kernel, class Tree>
void setup_kernel(has_setup<Kernel>, Kernel& kernel, const Tree&) {
kernel.setup();
}
/**
* \brief No-op
*
* \tparam Args Unused arguments
*/
template<class... Args>
void setup_kernel(std::true_type, const Args&...) {}
} // close namespace [scalfmm]::details
/**
* \brief Call kernel setup method with arguments if possible
*
* Current behaviour calls (first defined):
* - kernel.setup(tree)
* - kernel.setup()
*
* \param kernel Kernel to setup
* \param tree Tree to setup kernel (if needed)
*/
template<class Kernel, class Tree>
void setup_kernel(Kernel& kernel, Tree& tree) {
using tag = inria::first_true_t<
details::has_setup<Kernel, Tree>,
details::has_setup<Kernel>,
std::true_type
>;
details::setup_kernel(tag{}, kernel, tree);
}
namespace details {
/**
* \brief Check for kernel.cleanup(tree) existence
*/
template<class Kernel, class... Args>
struct has_cleanup {
template<class K>
constexpr static auto check(K* k, Args* ... args)
-> decltype(k->cleanup(*args...), void(), true)
{ return true; }
constexpr static bool check(...) {return false;}
static constexpr bool value = check((Kernel*)0, (Args*)0 ...);
};
/**
* \brief Call kernel.cleanup(tree)
*
* \param kernel Kernel to cleanup
* \param tree Tree to cleanup with
*
* \tparam Kernel Kernel type
* \tparam Tree Tree type
*/
template<class Kernel, class Tree>
void cleanup_kernel(has_cleanup<Kernel, Tree>, Kernel& kernel, Tree& tree) {
kernel.cleanup(tree);
}
/**
* \brief Call kernel.cleanup()
*
* \param kernel Kernel to cleanup
*
* \tparam Kernel Kernel type
* \tparam Tree Tree type, the tree is not used
*/
template<class Kernel, class Tree>
void cleanup_kernel(has_cleanup<Kernel>, Kernel& kernel, const Tree&) {
kernel.cleanup();
}
/**
* \brief No-op
*
* \tparam Args Unused arguments
*/
template<class... Args>
void cleanup_kernel(std::true_type, const Args&...) {}
} // close namespace [scalfmm]::details
/**
* \brief Call kernel cleanup method with arguments if possible
*
* Current behaviour calls (first defined):
* - kernel.cleanup(tree)
* - kernel.cleanup()
*
* \param kernel Kernel to cleanup
* \param tree Tree to cleanup kernel (if needed)
*/
template<class Kernel, class Tree>
void cleanup_kernel(Kernel& kernel, Tree& tree) {
using tag = inria::first_true_t<
details::has_cleanup<Kernel, Tree>,
details::has_cleanup<Kernel>,
std::true_type
>;
details::cleanup_kernel(tag{}, kernel, tree);
}
} // close namespace scalfmm
#endif /* _SCALFMM_KERNEL_UTILITIES_HPP_ */
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