Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 24 additions & 19 deletions modules/task/include/task.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -203,7 +203,11 @@ template <typename InType, typename OutType>
/// @tparam OutType Output data type.
class Task {
public:
using InputType = InType;
using OutputType = OutType;

Task() = default;
explicit Task(InType input, TypeOfTask type_of_task) : input_(std::move(input)), type_of_task_(type_of_task) {}
Task(const Task &) = delete;
Task(Task &&) = delete;
Task &operator=(const Task &) = delete;
Expand Down Expand Up @@ -263,16 +267,14 @@ class Task {
return PostProcessingImpl();
}

/// @brief Returns the current testing mode.
/// @return Reference to the current StateOfTesting.
StateOfTesting &GetStateOfTesting() {
return state_of_testing_;
/// @brief Sets the current testing mode.
void SetStateOfTesting(StateOfTesting state_of_testing) {
state_of_testing_ = state_of_testing;
}

/// @brief Sets the dynamic task type.
/// @param type_of_task Task type to set.
void SetTypeOfTask(TypeOfTask type_of_task) {
type_of_task_ = type_of_task;
/// @brief Returns the current testing mode.
[[nodiscard]] StateOfTesting GetStateOfTesting() const {
return state_of_testing_;
}

/// @brief Returns the dynamic task type.
Expand All @@ -281,12 +283,6 @@ class Task {
return type_of_task_;
}

/// @brief Returns the current task status.
/// @return Task status (enabled or disabled).
[[nodiscard]] StatusOfTask GetStatusOfTask() const {
return status_of_task_;
}

/// @brief Returns the static task type.
/// @return Static task type (default: kUnknown).
static constexpr TypeOfTask GetStaticTypeOfTask() {
Expand All @@ -295,13 +291,13 @@ class Task {

/// @brief Returns a reference to the input data.
/// @return Reference to the task's input data.
InType &GetInput() {
[[nodiscard]] const InType &GetInput() const {
return input_;
}

/// @brief Returns a reference to the output data.
/// @return Reference to the task's output data.
OutType &GetOutput() {
[[nodiscard]] const OutType &GetOutput() const {
return output_;
}

Expand All @@ -317,6 +313,16 @@ class Task {
}

protected:
/// @brief Returns mutable access to the input for task implementations.
InType &GetMutableInput() {
return input_;
}

/// @brief Returns mutable access to the output for task implementations.
OutType &GetMutableOutput() {
return output_;
}

/// @brief Measures execution time between preprocessing and postprocessing steps.
/// @throws std::runtime_error If execution exceeds the allowed time limit.
virtual void InternalTimeTest() final {
Expand Down Expand Up @@ -364,7 +370,6 @@ class Task {
OutType output_{};
StateOfTesting state_of_testing_ = StateOfTesting::kFunc;
TypeOfTask type_of_task_ = TypeOfTask::kUnknown;
StatusOfTask status_of_task_ = StatusOfTask::kEnabled;
std::chrono::high_resolution_clock::time_point tmp_time_point_;
enum class PipelineStage : uint8_t {
kNone,
Expand All @@ -388,8 +393,8 @@ using TaskPtr = std::unique_ptr<Task<InType, OutType>>;
/// @param in Input to pass to the task constructor.
/// @return Unique pointer to the newly created task.
template <typename TaskType, typename InType>
std::unique_ptr<TaskType> TaskGetter(const InType &in) {
return std::make_unique<TaskType>(in);
std::unique_ptr<TaskType> TaskGetter(InType &&in) {
return std::make_unique<TaskType>(std::forward<InType>(in));
}

} // namespace ppc::task
28 changes: 11 additions & 17 deletions modules/task/tests/task_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -46,23 +46,21 @@ namespace ppc::test {
template <typename InType, typename OutType>
class TestTask : public ppc::task::Task<InType, OutType> {
public:
explicit TestTask(const InType &in) {
this->GetInput() = in;
}
explicit TestTask(InType in) : ppc::task::Task<InType, OutType>(std::move(in), TypeOfTask::kUnknown) {}

protected:
bool ValidationImpl() override {
return !this->GetInput().empty();
}

bool PreProcessingImpl() override {
this->GetOutput() = 0;
this->GetMutableOutput() = 0;
return true;
}

bool RunImpl() override {
for (const auto &value : this->GetInput()) {
this->GetOutput() += value;
this->GetMutableOutput() += value;
}
return true;
}
Expand Down Expand Up @@ -287,9 +285,8 @@ TEST(TaskTest, TaskDestructorThrowsIfStageIncomplete) {
std::vector<int32_t> in(20, 1);
struct LocalTask : Task<std::vector<int32_t>, int32_t> {
public:
explicit LocalTask(const std::vector<int32_t> &in) {
this->GetInput() = in;
}
explicit LocalTask(std::vector<int32_t> in)
: Task<std::vector<int32_t>, int32_t>(std::move(in), TypeOfTask::kUnknown) {}

protected:
bool ValidationImpl() override {
Expand All @@ -316,9 +313,8 @@ TEST(TaskTest, TaskDestructorThrowsIfEmpty) {
std::vector<int32_t> in(20, 1);
struct LocalTask : Task<std::vector<int32_t>, int32_t> {
public:
explicit LocalTask(const std::vector<int32_t> &in) {
this->GetInput() = in;
}
explicit LocalTask(std::vector<int32_t> in)
: Task<std::vector<int32_t>, int32_t>(std::move(in), TypeOfTask::kUnknown) {}

protected:
bool ValidationImpl() override {
Expand All @@ -345,9 +341,8 @@ TEST(TaskTest, InternalTimeTestThrowsIfTimeoutExceeded) {
#endif
struct SlowTask : Task<std::vector<int32_t>, int32_t> {
public:
explicit SlowTask(const std::vector<int32_t> &in) {
this->GetInput() = in;
}
explicit SlowTask(std::vector<int32_t> in)
: Task<std::vector<int32_t>, int32_t>(std::move(in), TypeOfTask::kUnknown) {}

protected:
bool ValidationImpl() override {
Expand All @@ -367,7 +362,7 @@ TEST(TaskTest, InternalTimeTestThrowsIfTimeoutExceeded) {

std::vector<int32_t> in(20, 1);
SlowTask task(in);
task.GetStateOfTesting() = StateOfTesting::kFunc;
task.SetStateOfTesting(StateOfTesting::kFunc);
task.Validation();
EXPECT_NO_THROW(task.PreProcessing());
task.Run();
Expand All @@ -394,8 +389,7 @@ class DummyTask : public Task<int, int> {
};

TEST(TaskTest, GetDynamicTypeReturnsCorrectEnum) {
DummyTask task;
task.SetTypeOfTask(TypeOfTask::kOMP);
DummyTask task(0, TypeOfTask::kOMP);
task.Validation();
task.PreProcessing();
task.Run();
Expand Down
31 changes: 18 additions & 13 deletions modules/util/include/func_test_util.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,14 @@
namespace ppc::util {

template <typename InType, typename OutType, typename TestType = void>
using FuncTestParam = std::tuple<std::function<ppc::task::TaskPtr<InType, OutType>(InType)>, std::string, TestType,
ppc::task::TaskDescriptor>;
struct FuncTestCase {
std::function<ppc::task::TaskPtr<InType, OutType>(InType)> task_getter;
TestType test_param;
ppc::task::TaskDescriptor descriptor;
};

template <typename InType, typename OutType, typename TestType = void>
using FuncTestParam = FuncTestCase<InType, OutType, TestType>;

template <typename InType, typename OutType, typename TestType = void>
using GTestFuncParam = ::testing::TestParamInfo<FuncTestParam<InType, OutType, TestType>>;
Expand Down Expand Up @@ -49,12 +55,11 @@ class BaseRunFuncTests : public ::testing::TestWithParam<FuncTestParam<InType, O
template <typename Derived>
static std::string PrintFuncTestName(const GTestFuncParam<InType, OutType, TestType> &info) {
RequireStaticInterface<Derived>();
TestType test_param = std::get<static_cast<std::size_t>(ppc::util::GTestParamIndex::kTestParams)>(info.param);
return GetTaskDescriptor(info.param).display_name + "_" + Derived::PrintTestParam(test_param);
return info.param.descriptor.display_name + "_" + Derived::PrintTestParam(info.param.test_param);
}

protected:
virtual bool CheckTestOutputData(OutType &output_data) = 0;
virtual bool CheckTestOutputData(const OutType &output_data) = 0;
/// @brief Provides input data for the task.
/// @return Initialized input data.
virtual InType GetTestInputData() = 0;
Expand All @@ -70,7 +75,7 @@ class BaseRunFuncTests : public ::testing::TestWithParam<FuncTestParam<InType, O
}

void ExecuteTest(const FuncTestParam<InType, OutType, TestType> &test_param) {
const auto &descriptor = GetTaskDescriptor(test_param);
const auto &descriptor = test_param.descriptor;

ValidateTaskDescriptor(descriptor);

Expand Down Expand Up @@ -101,13 +106,13 @@ class BaseRunFuncTests : public ::testing::TestWithParam<FuncTestParam<InType, O
}

bool ShouldSkipTestCase(const FuncTestParam<InType, OutType, TestType> &test_param) {
const auto &descriptor = GetTaskDescriptor(test_param);
const auto &descriptor = test_param.descriptor;
return IsTestDisabled(descriptor) || ShouldSkipNonMpiTask(descriptor);
}

/// @brief Initializes task instance and runs it through the full pipeline.
void InitializeAndRunTask(const FuncTestParam<InType, OutType, TestType> &test_param) {
task_ = std::get<static_cast<std::size_t>(GTestParamIndex::kTaskGetter)>(test_param)(GetTestInputData());
task_ = test_param.task_getter(GetTestInputData());
ExecuteTaskPipeline();
}

Expand Down Expand Up @@ -161,7 +166,7 @@ void RunTestCasesWithTag(const TestTasksList &test_tasks_list, std::string_view
bool has_matching_task = false;
std::apply([&](const auto &...test_params) {
auto run_if_tagged = [&](const auto &test_param) {
const auto &descriptor = GetTaskDescriptor(test_param);
const auto &descriptor = test_param.descriptor;
if (descriptor.type == task_type) {
has_matching_task = true;
std::invoke(run_test_case, test_param);
Expand All @@ -186,10 +191,10 @@ auto ExpandToValues(const Tuple &t) {
template <typename Task, typename InType, typename SizesContainer, std::size_t... Is>
auto GenTaskTuplesImpl(const SizesContainer &sizes, const std::string &settings_path,
std::string_view settings_task_path, std::index_sequence<Is...> /*unused*/) {
const auto descriptor =
MakeTaskDescriptor(GetNamespace<Task>(), Task::GetStaticTypeOfTask(), settings_path, settings_task_path);
return std::make_tuple(std::make_tuple(ppc::task::TaskGetter<Task, InType>, descriptor.display_name,
std::get<Is>(sizes), descriptor)...);
const auto descriptor = MakeTaskDescriptor(ResolveTaskIdentifier<Task>(settings_path), Task::GetStaticTypeOfTask(),
settings_path, settings_task_path);
return std::make_tuple(FuncTestCase<InType, typename Task::OutputType, std::decay_t<decltype(std::get<Is>(sizes))>>{
ppc::task::TaskGetter<Task, InType>, std::get<Is>(sizes), descriptor}...);
}

template <typename Task, typename InType, typename SizesContainer>
Expand Down
35 changes: 20 additions & 15 deletions modules/util/include/perf_test_util.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ template <typename InType, typename OutType>
double RunTaskForBenchmark(const ppc::task::TaskPtr<InType, OutType> &task) {
const auto task_type = task->GetDynamicTypeOfTask();
const auto timer = MakeTechnologyTimer(task_type);
task->GetStateOfTesting() = ppc::task::StateOfTesting::kPerf;
task->SetStateOfTesting(ppc::task::StateOfTesting::kPerf);

task->Validation();
task->PreProcessing();
Expand All @@ -137,7 +137,8 @@ void RunBenchmarkBody(const TaskGetter &task_getter, const InType &input_data, c
auto task = task_getter(input_data);
const double elapsed = RunTaskForBenchmark(task);
state.SetIterationTime(elapsed);
benchmark::DoNotOptimize(task->GetOutput());
auto output = task->GetOutput();
benchmark::DoNotOptimize(output);
}
} catch (const std::exception &e) {
PerformanceFailureFlag::Set();
Expand Down Expand Up @@ -169,8 +170,13 @@ class BenchmarkTaskBody final {
} // namespace detail

template <typename InType, typename OutType>
using PerfTestParam = std::tuple<std::function<ppc::task::TaskPtr<InType, OutType>(InType)>, std::string,
ppc::task::TaskCategory, ppc::task::TaskDescriptor>;
struct PerfTestCase {
std::function<ppc::task::TaskPtr<InType, OutType>(InType)> task_getter;
ppc::task::TaskDescriptor descriptor;
};

template <typename InType, typename OutType>
using PerfTestParam = PerfTestCase<InType, OutType>;

template <typename InType, typename OutType>
/// @brief Base class for performance testing of parallel tasks.
Expand All @@ -180,11 +186,11 @@ class BaseRunPerfTests : public ::testing::TestWithParam<PerfTestParam<InType, O
public:
/// @brief Generates a readable name for the performance test case.
static std::string CustomPerfTestName(const ::testing::TestParamInfo<PerfTestParam<InType, OutType>> &info) {
return GetTaskDescriptor(info.param).display_name;
return info.param.descriptor.display_name;
}

protected:
virtual bool CheckTestOutputData(OutType &output_data) = 0;
virtual bool CheckTestOutputData(const OutType &output_data) = 0;
/// @brief Supplies input data for performance testing.
virtual InType GetTestInputData() = 0;

Expand All @@ -193,8 +199,8 @@ class BaseRunPerfTests : public ::testing::TestWithParam<PerfTestParam<InType, O
}

void ExecuteTest(const PerfTestParam<InType, OutType> &perf_test_param) {
auto task_getter = std::get<static_cast<std::size_t>(GTestParamIndex::kTaskGetter)>(perf_test_param);
const auto &descriptor = GetTaskDescriptor(perf_test_param);
auto task_getter = perf_test_param.task_getter;
const auto &descriptor = perf_test_param.descriptor;

ASSERT_NE(descriptor.type, ppc::task::TypeOfTask::kUnknown);
if (descriptor.status == ppc::task::StatusOfTask::kDisabled) {
Expand All @@ -209,12 +215,11 @@ class BaseRunPerfTests : public ::testing::TestWithParam<PerfTestParam<InType, O

const auto input_data = GetTestInputData();
task_ = task_getter(input_data);
task_->GetStateOfTesting() = ppc::task::StateOfTesting::kPerf;
task_->SetStateOfTesting(ppc::task::StateOfTesting::kPerf);
SynchronizeMpiRanks();
detail::RunTaskForValidation(task_);

OutType output_data = task_->GetOutput();
ASSERT_TRUE(CheckTestOutputData(output_data));
ASSERT_TRUE(CheckTestOutputData(task_->GetOutput()));

PerfAttr perf_attr;
SetPerfAttributes(perf_attr);
Expand All @@ -236,11 +241,11 @@ class BaseRunPerfTests : public ::testing::TestWithParam<PerfTestParam<InType, O

template <typename TaskType, typename InputType>
auto MakePerfTaskTuples(const std::string &settings_path, std::string_view settings_task_path = {}) {
const auto descriptor =
MakeTaskDescriptor(GetNamespace<TaskType>(), TaskType::GetStaticTypeOfTask(), settings_path, settings_task_path);
const auto descriptor = MakeTaskDescriptor(ResolveTaskIdentifier<TaskType>(settings_path),
TaskType::GetStaticTypeOfTask(), settings_path, settings_task_path);

return std::make_tuple(std::make_tuple(ppc::task::TaskGetter<TaskType, InputType>, descriptor.display_name,
descriptor.category, descriptor));
return std::make_tuple(
PerfTestCase<InputType, typename TaskType::OutputType>{ppc::task::TaskGetter<TaskType, InputType>, descriptor});
}

template <typename Tuple, std::size_t... I>
Expand Down
21 changes: 14 additions & 7 deletions modules/util/include/task_descriptor_util.hpp
Original file line number Diff line number Diff line change
@@ -1,14 +1,26 @@
#pragma once

#include <cstddef>
#include <concepts>
#include <filesystem>
#include <string>
#include <string_view>

#include "task/include/task.hpp"
#include "util/include/util.hpp"

namespace ppc::util {

template <typename Task>
std::string ResolveTaskIdentifier(const std::string &settings_path) {
if constexpr (requires {
{ Task::GetTaskIdentifier() } -> std::convertible_to<std::string_view>;
}) {
return std::string(Task::GetTaskIdentifier());
} else {
const std::filesystem::path path(settings_path);
return path.has_parent_path() ? path.parent_path().filename().string() : path.stem().string();
}
}

inline ppc::task::TaskDescriptor MakeTaskDescriptor(std::string_view task_namespace, ppc::task::TypeOfTask task_type,
const std::string &settings_path,
std::string_view settings_task_path = {}) {
Expand All @@ -23,11 +35,6 @@ inline ppc::task::TaskDescriptor MakeTaskDescriptor(std::string_view task_namesp
.display_name = std::string(task_namespace) + "_" + task_name};
}

template <typename TestParam>
const ppc::task::TaskDescriptor &GetTaskDescriptor(const TestParam &test_param) {
return std::get<static_cast<std::size_t>(GTestParamIndex::kTaskDescriptor)>(test_param);
}

inline bool IsMpiTaskType(ppc::task::TypeOfTask type) {
return type == ppc::task::TypeOfTask::kMPI || type == ppc::task::TypeOfTask::kALL;
}
Expand Down
Loading
Loading