Commit 4723fcf6 authored by Quentin Khan's avatar Quentin Khan
Browse files

PerfTest: code refactor

Add more precise information per descriptor through the optional `info`
static method. The adaptive tree descriptor gives information about the
options.

Remove old help message hints that aren't relevant anymore.

Rename DescriptorLookup.hpp to TestDriver.hpp

Allow tree descriptor to adapt to kernel descriptor: the node data and
particle containers are now retrieved from the kernel descriptor type
definitions.

Add some comments.

Add FCountKernel descriptor.
parent 6fad4f1a
......@@ -5,7 +5,7 @@
#include "PerfTest/FPerfTestParams.hpp"
#include "PerfTest/DescriptorLookup.hpp"
#include "PerfTest/TestDriver.hpp"
#include <omp.h>
......@@ -14,10 +14,10 @@
using FReal = double;
namespace ParName {
const FParameterNames Algo = {{"--algo"},"Algorithm to run (basic, task, costzones, sectiontask, autobalance)."};
const FParameterNames Kern = {{"--kernel"},"Kernel to use (lagrange)."};
const FParameterNames Algo = {{"--algo"},"Algorithm to run."};
const FParameterNames Kern = {{"--kernel"},"Kernel to use."};
const FParameterNames Density = {{"--density"},"Maximum particle count per leaf in adaptive algorihtms."};
const FParameterNames Schedule = {{"--schedule"},"OpenMP scheduling policy (static, dynamic)."};
const FParameterNames Schedule = {{"--schedule"},"OpenMP scheduling policy."};
const FParameterNames ChunkSize = {{"--chunk-size"},"OpenMP chunk size for basic dynamic algorithm."};
const FParameterNames PerfFile = {{"--perf-file"},"Output file for performance measures."};
}
......
......@@ -17,8 +17,10 @@ struct kernel_descriptor {
/// Kernel name for runtime lookup, must be unique
constexpr static const char* name = "";
/// Cell type used by kernel
/// Cell tree type used by kernel
using cell_data_t = void;
/// Particle container type used in tree
using container_t = void;
/// Used after a successful kernel lookup to build the kernel
template<typename tree_desc> struct kernel_factory {
......@@ -38,8 +40,6 @@ struct kernel_descriptor {
/// Tree descriptor base model
struct tree_descriptor {
/// Particle container type used in tree
using container_t = void;
/// Used to build the tree
template<typename algo_desc, typename kernel_desc>
struct tree_factory {
......@@ -109,6 +109,8 @@ struct algo_descriptor {
// Lagrange kernel descriptor ////////////////////
#include "Kernels/P2P/FP2PParticleContainerIndexed.hpp"
#include "Kernels/Interpolation/FInterpMatrixKernel.hpp"
#include "Kernels/Uniform/FUnifCell.hpp"
#include "Adaptive/new/FAdaptUnifKernel.hpp"
......@@ -124,13 +126,13 @@ struct kernel_descriptor<FReal, 0> {
constexpr static const int ORDER = 7;
/// Kernel cell data type
using cell_data_t = FUnifCell<FReal, ORDER>;
/// Particle container data type
using container_t = FP2PParticleContainerIndexed<FReal>;
/// Direct interaction kernel type
using MatrixKernelClass = FInterpMatrixKernelR<FReal>;
template<typename tree_descriptor>
struct kernel_factory {
/// Container type retreived from tree_descriptor
using container_t = typename tree_descriptor::container_t;
/// Kernel type
using kernel_t = FAdaptUnifKernel<FReal, cell_data_t, container_t , MatrixKernelClass, ORDER>;
......@@ -161,20 +163,20 @@ template<typename FReal> struct kernel_descriptor<FReal, 1> {
constexpr static const int ORDER = 7;
/// Kernel cell data
using cell_data_t = FChebCell<FReal, ORDER>;
/// Particle container data type
using container_t = FP2PParticleContainerIndexed<FReal>;
/// Direct interaction kernel type
using MatrixKernelClass = FInterpMatrixKernelR<FReal>;
template<typename tree_descriptor>
struct kernel_factory {
/// Container type retreived from tree_descriptor
using container_t = typename tree_descriptor::container_t;
/// Kernel type
using kernel_t = FAdaptChebKernel<FReal, cell_data_t, container_t , MatrixKernelClass, ORDER>;
/// Direct interaction kernel instance
MatrixKernelClass MatrixKernel;
/** \biref Build method */
/** \brief Build method */
template<typename tree_t>
std::unique_ptr<kernel_t> build(const FPerfTestParams&, tree_t& tree) {
return std::make_unique<kernel_t>(static_cast<int>(tree.getHeight()),
......@@ -186,21 +188,54 @@ template<typename FReal> struct kernel_descriptor<FReal, 1> {
};
// Count kernel descriptor ///////////////////////
#include "../Adaptive/FCountKernel.hpp"
template<typename FReal> struct kernel_descriptor<FReal, 2> {
/// Kernel lookup name
constexpr static const char* name = "count";
/// Kernel cell data
using cell_data_t = TestCountNodeData;
/// Particle type
using particle_t = TestCountParticle<FReal, 3>;
/// Particle container type
using container_t = FVariadicParticleContainer<particle_t>;
/// Kernel type
using kernel_t = FCountKernel<cell_data_t, container_t>;
template<typename tree_descriptor>
struct kernel_factory {
/// Kernel type
using kernel_t = kernel_t;
/** \brief Build method */
template<typename tree_t>
std::unique_ptr<kernel_t> build(const FPerfTestParams&, tree_t& /*tree*/) {
return std::make_unique<kernel_t>();
}
};
static void info(FPerfTestParams& params, const kernel_t& kernel) {
for(auto t : kernel.call_count) {
params.json["calls"][t.first] = t.second;
}
}
};
// Shared memory adaptive tree descriptor ////////
#include "Adaptive/new/FTree.hpp"
#include "Kernels/P2P/FP2PParticleContainerIndexed.hpp"
template<typename FReal>
struct adaptive_tree_descriptor {
constexpr static const char* name = "adaptive-tree";
using container_t = FP2PParticleContainerIndexed<FReal>;
using leaf_t = void;
template<typename algo_desc, typename kernel_desc>
struct tree_factory {
using tree_t = FTree<container_t, typename kernel_desc::cell_data_t>;
using tree_t = FTree<typename kernel_desc::container_t, typename kernel_desc::cell_data_t>;
template<typename loader_t>
std::unique_ptr<tree_t> build(const FPerfTestParams& params, loader_t& loader) {
......@@ -209,6 +244,30 @@ struct adaptive_tree_descriptor {
return tree;
}
};
template<typename tree_t>
static void info(FPerfTestParams& params, const tree_t& tree) {
params.json["config"]["tree"]["height"] = tree.height();
params.json["config"]["tree"]["leaf density"] = tree.leaf_max_particle_count();
std::size_t min = std::numeric_limits<std::size_t>::max(), max = 0;
for(auto& leaf : tree.leaves()) {
if(leaf->getParticleContainer() && leaf->getParticleContainer()->size()) {
auto size = leaf->getParticleContainer()->size();
min = std::min(min, size);
max = std::max(max, size);
}
}
params.json["config"]["tree"]["min"] = min;
params.json["config"]["tree"]["max"] = max;
std::fstream fout("test.obj", std::ios::out);
fout << scalfmm::fmt::obj << tree;
fout << std::flush;
fout.close();
}
};
......@@ -221,12 +280,14 @@ template<typename FReal>
struct uniform_tree_descriptor {
constexpr static const char* name = "uniform-tree";
using container_t = FP2PParticleContainerIndexed<FReal>;
using leaf_t = FSimpleLeaf<FReal, container_t>;
template<typename kernel_desc>
using leaf_tpl = FSimpleLeaf<FReal, typename kernel_desc::container_t>;
template<typename algo_desc, typename kernel_desc>
struct tree_factory {
using tree_t = FOctree<FReal, typename kernel_desc::cell_data_t, container_t, leaf_t>;
using leaf_t = leaf_tpl<kernel_desc>;
using tree_t = FOctree<FReal, typename kernel_desc::cell_data_t, typename kernel_desc::container_t, leaf_t>;
template<typename loader_t>
std::unique_ptr<tree_t> build(const FPerfTestParams& params, loader_t& loader) {
......@@ -234,6 +295,11 @@ struct uniform_tree_descriptor {
}
};
template<typename tree_t>
static void info(FPerfTestParams& params, tree_t& tree) {
params.json["config"]["tree"]["height"] = tree.getHeight();
}
};
......@@ -257,13 +323,14 @@ struct default_loader_descriptor {
while(run) {
sstr.str("");
sstr.clear();
sstr.precision(4);
double p = static_cast<double>(idx) * 100.
/ static_cast<double>(this->getNumberOfParticles());
sstr << "Loading particles: [";
for(double i = 0; i < 100; i += 7.5) {
sstr << (i < p ? '|' : ' ');
}
sstr << "] " << p << "% ";
sstr << "] " << p << "% ";
std::cout << '\r' << sstr.str() << std::flush;
run = idx < this->getNumberOfParticles();
std::this_thread::sleep_for(std::chrono::milliseconds(200));
......@@ -373,8 +440,8 @@ template<typename FReal> struct algo_descriptor<FReal, 2> {
template<typename tree_t, typename kernel_t>
using algo_t = FFmmAlgorithm<
tree_t, typename kernel_descriptor::cell_data_t,
typename tree_desc::container_t, kernel_t,
typename tree_desc::leaf_t>;
typename kernel_descriptor::container_t, kernel_t,
typename tree_desc::template leaf_tpl<kernel_descriptor> >;
template<typename tree_t, typename kernel_t>
std::unique_ptr< algo_t<tree_t, kernel_t> >
......@@ -401,8 +468,8 @@ template<typename FReal> struct algo_descriptor<FReal, 3> {
template<typename tree_t, typename kernel_t>
using algo_t = FFmmAlgorithmThread<
tree_t, typename kernel_descriptor::cell_data_t,
typename tree_desc::container_t, kernel_t,
typename tree_desc::leaf_t>;
typename kernel_descriptor::container_t, kernel_t,
typename tree_desc::template leaf_tpl<kernel_descriptor> >;
template<typename tree_t, typename kernel_t>
std::unique_ptr< algo_t<tree_t, kernel_t> >
......@@ -429,8 +496,8 @@ template<typename FReal> struct algo_descriptor<FReal, 4> {
template<typename tree_t, typename kernel_t>
using algo_t = FFmmAlgorithmTask<
tree_t, typename kernel_descriptor::cell_data_t,
typename tree_desc::container_t, kernel_t,
typename tree_desc::leaf_t>;
typename kernel_descriptor::container_t, kernel_t,
typename tree_desc::template leaf_tpl<kernel_descriptor> >;
template<typename tree_t, typename kernel_t>
std::unique_ptr< algo_t<tree_t, kernel_t> >
......@@ -456,8 +523,8 @@ template<typename FReal> struct algo_descriptor<FReal, 5> {
template<typename tree_t, typename kernel_t>
using algo_t = FFmmAlgorithmSectionTask<
tree_t, typename kernel_descriptor::cell_data_t,
typename tree_desc::container_t, kernel_t,
typename tree_desc::leaf_t>;
typename kernel_descriptor::container_t, kernel_t,
typename tree_desc::template leaf_tpl<kernel_descriptor> >;
template<typename tree_t, typename kernel_t>
std::unique_ptr< algo_t<tree_t, kernel_t> >
......@@ -486,8 +553,8 @@ template<typename FReal> struct algo_descriptor<FReal, 6> {
template<typename tree_t, typename kernel_t>
using algo_t = FFmmAlgorithmOmp4<
tree_t, typename kernel_descriptor::cell_data_t,
typename tree_desc::container_t, kernel_t,
typename tree_desc::leaf_t>;
typename kernel_descriptor::container_t, kernel_t,
typename tree_desc::template leaf_tpl<kernel_descriptor> >;
template<typename tree_t, typename kernel_t>
std::unique_ptr< algo_t<tree_t, kernel_t> >
......@@ -499,4 +566,5 @@ template<typename FReal> struct algo_descriptor<FReal, 6> {
#endif
#endif /* DESCRIPTORS_HPP */
......@@ -27,7 +27,7 @@ namespace scalfmm {
template<class U, class = void_t<> >
struct disabled: std::false_type {};
/// Disabled type trait found specialisation
/// Disabled type trait specialisation
template<class U>
struct disabled<U, void_t<decltype(U::disabled)> >
{ enum : bool { value = U::disabled }; };
......@@ -261,10 +261,13 @@ namespace scalfmm {
/**
* \brief Compile time type list
*
* Used to pass type packs using template argument deduction.
* Used to pass type lists using template argument deduction.
*/
template<typename ...>
struct type_list {};
template<typename ... Ts>
struct type_list {
template<typename T>
using append = type_list<Ts..., T>;
};
/**
......@@ -287,6 +290,61 @@ namespace scalfmm {
using kernel_factory = typename kernel_desc::template kernel_factory<tree_desc>;
using algo_factory = typename algo_desc::template algo_factory<kernel_desc>;
/**
* \brief Detect existence of static `info` method in class
*
* \tparam K Class to check
* \tparam Args Types of `K::info` arguments if it exists
*/
template<typename K, typename ... Args>
struct has_info {
/// Void alias used by SFINAE
template<typename...> using void_t = void;
/// Default SFINAE `check`, equals false
template<typename k, typename = void_t<> >
struct check : std::false_type {};
/// `check` specialisation in case the `info` method exists
template<typename k>
struct check<k, void_t<decltype(k::info(std::declval<Args>()...))> >
: std::true_type {};
/// True if `K::info(Args...)` exists, false otherwise
constexpr static const bool value = check<K>::value;
static void print() {
auto l = {0, (std::cerr << typeid(Args).name() << ' ', 0)...};
(void)l;
std::cerr << '\n';
}
};
/**
* \brief Call static `info` method if it exists
*
* \note This method is disabled through SFINAE if the method does
* not exist.
*
* \tparam T Class that may offer an info static method
* \tparam Args Parameter type pack for T::info arguments
*
* \param args Arguments to forward to T::info
*/
template<typename T, typename... Args,
typename std::enable_if<has_info<T, Args...>::value>::type* = nullptr >
static void call_info(Args&&... args) {
T::info(std::forward<Args>(args)...);
}
/**
* \brief Ignore inexistent `info` call
*/
template<typename T, typename... Args>
static void call_info(const Args&..., ...) {
// Uncomment to debug
// std::cerr << T::name << ": ";
// has_info<T, Args...>::print();
}
/**
* \brief Build everything and run algorithm
*
......@@ -295,40 +353,48 @@ namespace scalfmm {
static void run(FPerfTestParams& params) {
FTimerMap& timers = params.timers;
// The factories return unique_ptr specializations
tree_factory tree_f;
loader_factory loader_f;
kernel_factory kernel_f;
algo_factory algo_f;
// The factories return unique_ptr specialisations
// Build tree and load it
auto loader = loader_f.build(params);
auto tree = tree_f.build(params, *loader);
timers["load"].tic();
loader->load(*tree);
timers["load"].tac();
// Build kernel and algorithm
auto kernel = kernel_f.build(params, *tree);
auto algo = algo_f.build(params, *tree, *kernel);
std::cout << algo->name() << '\n';
std::cout << algo->name() << ": ";
std::cout << algo->description() << '\n';
// Run the algorithm
timers["algo"].tic();
algo->execute();
timers["algo"].tac();
// Gather general data
params.json["config"]["algo"]["name"] = params.algo;
params.json["config"]["algo"]["threads"] = params.nbThreads;
params.json["config"]["particle files"] =
{params.filename.substr(params.filename.find_last_of('/')+1)};
params.json["config"]["kernel"]["name"] = params.kernel;
// Gather timing data
for(auto t : algo->Timers) {
params.json["time"]["operator"][t.first] = t.second.cumulated();
}
for(auto t : params.timers) {
params.json["time"][t.first] = t.second.cumulated();
}
params.json["config"]["algo"]["name"] = params.algo;
params.json["config"]["algo"]["threads"] = params.nbThreads;
params.json["config"]["tree"]["height"] = tree->getHeight();
params.json["config"]["particle files"] =
{params.filename.substr(params.filename.find_last_of('/')+1)};
params.json["config"]["kernel"]["name"] = params.kernel;
// Gather descriptor specific data
setup_step::call_info<tree_desc>(params, *tree);
setup_step::call_info<kernel_desc>(params, *kernel);
}
};
......@@ -389,6 +455,17 @@ namespace scalfmm {
}
};
/**
* \brief Kernel lookup disabled case
*
* Recursive template class to find whether the kernel name given in
* `params` matches a kernel descriptor. If so, calls the final step.
*
* This specialization skips *disabled* kernel descriptors.
*
* \tparam FReal Floating point type
* \tparam I Current kernel index
*/
template<typename FReal, std::size_t I>
struct kernel_lookup<FReal, I, false, true> {
template<typename T>
......@@ -403,6 +480,9 @@ namespace scalfmm {
* Recursive template class to find whether the kernel name given in
* `params` matches a kernel descriptor. If so, calls the final step.
*
* This specialization ends the kernel lookup, no fitting kernel was
* found.
*
* \tparam FReal Floating point type
* \tparam I Current kernel index
*/
......
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