Skip to content
Closed
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
6 changes: 3 additions & 3 deletions .github/workflows/ubuntu.yml
Original file line number Diff line number Diff line change
Expand Up @@ -332,9 +332,9 @@ jobs:
PPC_NUM_PROC: 1
PPC_ASAN_RUN: 1
gcc-build-codecov:
needs:
- gcc-test-extended
- clang-test-extended
# needs:
# - gcc-test-extended
# - clang-test-extended
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v4
Expand Down
208 changes: 146 additions & 62 deletions modules/performance/include/performance.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,112 +11,196 @@

#include "task/include/task.hpp"

using namespace ppc::task;

namespace ppc::performance {

/**
* @brief Default timer function used for performance measurement.
* @return A fake time value (-1.0).
*/
inline double DefaultTimer() { return -1.0; }

/**
* @brief Attributes used to configure performance measurement.
*/
struct PerfAttr {
/// @brief Number of times the task is run for performance evaluation.
/**
* @brief Number of repetitions of the task for averaging performance.
*/
uint64_t num_running = 5;
/// @brief Timer function returning current time in seconds.
/// @cond

/**
* @brief Timer function returning current time in seconds.
* Default is a fake function returning -1.0.
*/
std::function<double()> current_timer = DefaultTimer;
/// @endcond
};

/**
* @brief Stores the results of a performance test.
*/
struct PerfResults {
/// @brief Measured execution time in seconds.
/**
* @brief Measured execution time in seconds (average over runs).
*/
double time_sec = 0.0;
enum TypeOfRunning : uint8_t { kPipeline, kTaskRun, kNone } type_of_running = kNone;

/**
* @brief Type of performance test performed.
*/
enum TypeOfRunning : uint8_t {
kPipeline, ///< Full pipeline: Validation → PreProcessing → Run → PostProcessing
kTaskRun, ///< Only Run() function is measured
kNone ///< No performance test was executed
} type_of_running = kNone;

/**
* @brief Maximum allowed execution time in seconds.
*/
constexpr static double kMaxTime = 10.0;
};

/**
* @brief Converts a TypeOfRunning enum value to its string representation.
* @param type_of_running Enum value indicating which performance type was run.
* @return String name corresponding to the enum.
*/
inline std::string GetStringParamName(PerfResults::TypeOfRunning type_of_running) {
if (type_of_running == PerfResults::kTaskRun) {
return "task_run";
}
if (type_of_running == PerfResults::kPipeline) {
return "pipeline";
}
return "none";
}

/**
* @brief Measures performance of a given task using configured attributes.
* @tparam InType Input type of the task.
* @tparam OutType Output type of the task.
*/
template <typename InType, typename OutType>
class Perf {
public:
// Init performance analysis with an initialized task and initialized data
explicit Perf(const ppc::task::TaskPtr<InType, OutType>& task_ptr) : task_(task_ptr) {
task_ptr->GetStateOfTesting() = ppc::task::StateOfTesting::kPerf;
/**
* @brief Constructs a performance tester for the given task.
* @param task_ptr Shared pointer to a task object.
*/
explicit Perf(const ::TaskPtr<InType, OutType>& task_ptr) : task_(task_ptr) {
task_ptr->GetStateOfTesting() = ::StateOfTesting::kPerf;
}
// Check performance of full task's pipeline: PreProcessing() ->
// Validation() -> Run() -> PostProcessing()

/**
* @brief Runs the full task pipeline and measures its performance.
* The full pipeline includes: Validation → PreProcessing → Run → PostProcessing.
* @param perf_attr Performance measurement configuration.
*/
void PipelineRun(const PerfAttr& perf_attr) {
perf_results_.type_of_running = PerfResults::TypeOfRunning::kPipeline;

CommonRun(perf_attr, [&] {
task_->Validation();
task_->PreProcessing();
task_->Run();
task_->PostProcessing();
}, perf_results_);
perf_results_.type_of_running = PerfResults::kPipeline;
CommonRun(perf_attr, RunFullPipeline<::Task<InType, OutType>>);
}
// Check performance of task's Run() function

/**
* @brief Measures only the Run() part of the task.
* Pre- / Post-processing and validation are still invoked before and after.
* @param perf_attr Performance measurement configuration.
*/
void TaskRun(const PerfAttr& perf_attr) {
perf_results_.type_of_running = PerfResults::TypeOfRunning::kTaskRun;
perf_results_.type_of_running = PerfResults::kTaskRun;

task_->Validation();
task_->PreProcessing();
CommonRun(perf_attr, [&] { task_->Run(); }, perf_results_);
CommonRun(perf_attr, RunOnly<::Task<InType, OutType>>);
task_->PostProcessing();

// Ensure correctness after a performance run
task_->Validation();
task_->PreProcessing();
task_->Run();
task_->PostProcessing();
}
// Pint results for automation checkers

/**
* @brief Prints formatted performance results or throws if too slow.
* Prints output in format: test_id:type:time_in_seconds
* @param test_id Identifier for the current test (e.g., "omp_4_threads").
* @throws std::runtime_error if execution time exceeds allowed maximum.
*/
void PrintPerfStatistic(const std::string& test_id) const {
std::string type_test_name;
if (perf_results_.type_of_running == PerfResults::TypeOfRunning::kTaskRun) {
type_test_name = "task_run";
} else if (perf_results_.type_of_running == PerfResults::TypeOfRunning::kPipeline) {
type_test_name = "pipeline";
} else {
std::stringstream err_msg;
err_msg << '\n' << "The type of performance check for the task was not selected.\n";
throw std::runtime_error(err_msg.str().c_str());
const auto& type = perf_results_.type_of_running;
const std::string type_name = GetStringParamName(type);

if (type == PerfResults::kNone) {
throw std::runtime_error("The type of performance check for the task was not selected.\n");
}

auto time_secs = perf_results_.time_sec;
std::stringstream perf_res_str;
std::stringstream ss;
double time_secs = perf_results_.time_sec;

if (time_secs < PerfResults::kMaxTime) {
perf_res_str << std::fixed << std::setprecision(10) << time_secs;
std::cout << test_id << ":" << type_test_name << ":" << perf_res_str.str() << '\n';
ss << std::fixed << std::setprecision(10) << time_secs;
} else {
std::stringstream err_msg;
err_msg << '\n' << "Task execute time need to be: ";
err_msg << "time < " << PerfResults::kMaxTime << " secs." << '\n';
err_msg << "Original time in secs: " << time_secs << '\n';
perf_res_str << std::fixed << std::setprecision(10) << -1.0;
std::cout << test_id << ":" << type_test_name << ":" << perf_res_str.str() << '\n';
throw std::runtime_error(err_msg.str().c_str());
ss << std::fixed << std::setprecision(10) << -1.0;
std::stringstream err;
err << "Task execute time need to be: time < " << PerfResults::kMaxTime
<< " secs.\nOriginal time in secs: " << time_secs << '\n';
std::cout << test_id << ":" << type_name << ":" << ss.str() << '\n';
throw std::runtime_error(err.str());
}

std::cout << test_id << ":" << type_name << ":" << ss.str() << '\n';
}
/// @brief Retrieves the performance test results.
/// @return The latest PerfResults structure.

/**
* @brief Retrieves performance test results.
* @return Struct containing latest performance data.
*/
[[nodiscard]] PerfResults GetPerfResults() const { return perf_results_; }

private:
PerfResults perf_results_;
std::shared_ptr<ppc::task::Task<InType, OutType>> task_;
static void CommonRun(const PerfAttr& perf_attr, const std::function<void()>& pipeline, PerfResults& perf_results) {
auto begin = perf_attr.current_timer();
for (uint64_t i = 0; i < perf_attr.num_running; i++) {
pipeline();
}
auto end = perf_attr.current_timer();
perf_results.time_sec = (end - begin) / static_cast<double>(perf_attr.num_running);
PerfResults perf_results_; ///< Stores measurement results and mode.
std::shared_ptr<::Task<InType, OutType>> task_; ///< Pointer to task being tested.

/**
* @brief Executes the full pipeline for the given task.
* @tparam TaskType Type of the task.
* @param task Shared pointer to the task instance.
*/
template <typename TaskType>
static void RunFullPipeline(const std::shared_ptr<TaskType>& task) {
task->Validation();
task->PreProcessing();
task->Run();
task->PostProcessing();
}
};

inline std::string GetStringParamName(PerfResults::TypeOfRunning type_of_running) {
if (type_of_running == PerfResults::kTaskRun) {
return "task_run";
/**
* @brief Executes only the Run() method of the given task.
* @tparam TaskType Type of the task.
* @param task Shared pointer to the task instance.
*/
template <typename TaskType>
static void RunOnly(const std::shared_ptr<TaskType>& task) {
task->Run();
}
if (type_of_running == PerfResults::kPipeline) {
return "pipeline";

/**
* @brief Measures execution time of a given function over multiple runs.
* @tparam Func Type of callable taking shared_ptr to task.
* @param perf_attr Attributes controlling the number of runs and timer.
* @param func Callable that invokes the desired part of the task.
*/
template <typename Func>
void CommonRun(const PerfAttr& perf_attr, Func func) {
double begin = perf_attr.current_timer();
for (uint64_t i = 0; i < perf_attr.num_running; ++i) {
func(task_);
}
double end = perf_attr.current_timer();
perf_results_.time_sec = (end - begin) / static_cast<double>(perf_attr.num_running);
}
return "none";
}
};

} // namespace ppc::performance
Loading