Skip to content

Add env-based time limits #525

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 8 commits into from
Jul 6, 2025
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
4 changes: 4 additions & 0 deletions docs/user_guide/environment_variables.rst
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,7 @@ The following environment variables can be used to configure the project's runti

- ``PPC_IGNORE_TEST_TIME_LIMIT``: Specifies that test time limits are ignored. Used by ``scripts/run_tests.py`` to disable time limit enforcement.
Default: ``0``
- ``PPC_TASK_MAX_TIME``: Maximum allowed execution time in seconds for functional tests.
Default: ``1.0``
- ``PPC_PERF_MAX_TIME``: Maximum allowed execution time in seconds for performance tests.
Default: ``10.0``
5 changes: 3 additions & 2 deletions modules/performance/include/performance.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -78,14 +78,15 @@ class Perf {
}

auto time_secs = perf_results_.time_sec;
const auto max_time = ppc::util::GetPerfMaxTime();
std::stringstream perf_res_str;
if (time_secs < PerfResults::kMaxTime) {
if (time_secs < max_time) {
perf_res_str << std::fixed << std::setprecision(10) << time_secs;
std::cout << test_id << ":" << type_test_name << ":" << perf_res_str.str() << '\n';
} else {
std::stringstream err_msg;
err_msg << '\n' << "Task execute time need to be: ";
err_msg << "time < " << PerfResults::kMaxTime << " secs." << '\n';
err_msg << "time < " << max_time << " 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';
Expand Down
24 changes: 24 additions & 0 deletions modules/performance/tests/perf_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

#include <chrono>
#include <cstdint>
#include <cstdlib>
#include <filesystem>
#include <fstream>
#include <memory>
Expand Down Expand Up @@ -107,6 +108,29 @@ TEST(perf_tests, check_perf_pipeline_uint8_t_slow_test) {
ASSERT_ANY_THROW(perf_analyzer.PrintPerfStatistic("check_perf_pipeline_uint8_t_slow_test"));
}

TEST(perf_tests, slow_perf_respects_env_override) {
const char* old = std::getenv("PPC_PERF_MAX_TIME");
setenv("PPC_PERF_MAX_TIME", "12", 1);
std::vector<uint8_t> in(128, 1);
auto test_task = std::make_shared<ppc::test::FakePerfTask<std::vector<uint8_t>, uint8_t>>(in);
Perf<std::vector<uint8_t>, uint8_t> perf_analyzer(test_task);
PerfAttr perf_attr;
perf_attr.num_running = 1;
const auto t0 = std::chrono::high_resolution_clock::now();
perf_attr.current_timer = [&] {
auto current_time_point = std::chrono::high_resolution_clock::now();
auto duration = std::chrono::duration_cast<std::chrono::nanoseconds>(current_time_point - t0).count();
return static_cast<double>(duration) * 1e-9;
};
perf_analyzer.PipelineRun(perf_attr);
EXPECT_NO_THROW(perf_analyzer.PrintPerfStatistic("slow_perf_respects_env_override"));
if (old) {
setenv("PPC_PERF_MAX_TIME", old, 1);
} else {
unsetenv("PPC_PERF_MAX_TIME");
}
}

TEST(perf_tests, check_perf_task_exception) {
std::vector<uint32_t> in(2000, 1);

Expand Down
6 changes: 3 additions & 3 deletions modules/task/include/task.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -215,12 +215,13 @@ class Task {
.count();
auto diff = static_cast<double>(duration) * 1e-9;

const auto max_time = ppc::util::GetTaskMaxTime();
std::stringstream err_msg;
if (diff < kMaxTestTime) {
if (diff < max_time) {
err_msg << "Test time:" << std::fixed << std::setprecision(10) << diff << '\n';
} else {
err_msg << "\nTask execute time need to be: ";
err_msg << "time < " << kMaxTestTime << " secs.\n";
err_msg << "time < " << max_time << " secs.\n";
err_msg << "Original time in secs: " << diff << '\n';
throw std::runtime_error(err_msg.str().c_str());
}
Expand Down Expand Up @@ -249,7 +250,6 @@ class Task {
StateOfTesting state_of_testing_ = kFunc;
TypeOfTask type_of_task_ = kUnknown;
StatusOfTask status_of_task_ = kEnabled;
static constexpr double kMaxTestTime = 1.0;
std::chrono::high_resolution_clock::time_point tmp_time_point_;
enum class PipelineStage : uint8_t {
kNone,
Expand Down
17 changes: 17 additions & 0 deletions modules/task/tests/task_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#include <chrono>
#include <cstddef>
#include <cstdint>
#include <cstdlib>
#include <exception>
#include <fstream>
#include <memory>
Expand Down Expand Up @@ -72,6 +73,22 @@ TEST(task_tests, check_int32_t_slow) {
ASSERT_ANY_THROW(test_task.PostProcessing());
}

TEST(task_tests, slow_task_respects_env_override) {
const char* old = std::getenv("PPC_TASK_MAX_TIME");
setenv("PPC_TASK_MAX_TIME", "3", 1);
std::vector<int32_t> in(20, 1);
ppc::test::FakeSlowTask<std::vector<int32_t>, int32_t> test_task(in);
ASSERT_EQ(test_task.Validation(), true);
test_task.PreProcessing();
test_task.Run();
EXPECT_NO_THROW(test_task.PostProcessing());
if (old) {
setenv("PPC_TASK_MAX_TIME", old, 1);
} else {
unsetenv("PPC_TASK_MAX_TIME");
}
}

TEST(task_tests, check_validate_func) {
std::vector<int32_t> in;
ppc::test::TestTask<std::vector<int32_t>, int32_t> test_task(in);
Expand Down
2 changes: 2 additions & 0 deletions modules/util/include/util.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,8 @@ enum GTestParamIndex : uint8_t { kTaskGetter, kNameTest, kTestParams };

std::string GetAbsoluteTaskPath(const std::string& id_path, const std::string& relative_path);
int GetNumThreads();
double GetTaskMaxTime();
double GetPerfMaxTime();

template <typename T>
std::string GetNamespace() {
Expand Down
16 changes: 16 additions & 0 deletions modules/util/src/util.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,22 @@ int ppc::util::GetNumThreads() {
return 1;
}

double ppc::util::GetTaskMaxTime() {
const auto val = env::get<double>("PPC_TASK_MAX_TIME");
if (val.has_value()) {
return val.value();
}
return 1.0;
}

double ppc::util::GetPerfMaxTime() {
const auto val = env::get<double>("PPC_PERF_MAX_TIME");
if (val.has_value()) {
return val.value();
}
return 10.0;
}

// List of environment variables that signal the application is running under
// an MPI launcher. The array size must match the number of entries to avoid
// looking up empty environment variable names.
Expand Down
41 changes: 41 additions & 0 deletions modules/util/tests/util.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

#include <gtest/gtest.h>

#include <cstdlib>
#include <libenvpp/detail/get.hpp>
#include <string>

Expand Down Expand Up @@ -75,3 +76,43 @@ TEST(GetNamespaceTest, NoTerminatorCharactersInPrettyFunction) {
std::string k_ns = ppc::util::GetNamespace<crazy::VeryLongTypeNameWithOnlyLettersAndUnderscores>();
EXPECT_EQ(k_ns, "crazy");
}

TEST(GetTaskMaxTime, ReturnsDefaultWhenUnset) {
const char* old = std::getenv("PPC_TASK_MAX_TIME");
unsetenv("PPC_TASK_MAX_TIME");
EXPECT_DOUBLE_EQ(ppc::util::GetTaskMaxTime(), 1.0);
if (old) {
setenv("PPC_TASK_MAX_TIME", old, 1);
}
}

TEST(GetTaskMaxTime, ReadsFromEnvironment) {
const char* old = std::getenv("PPC_TASK_MAX_TIME");
setenv("PPC_TASK_MAX_TIME", "2.5", 1);
EXPECT_DOUBLE_EQ(ppc::util::GetTaskMaxTime(), 2.5);
if (old) {
setenv("PPC_TASK_MAX_TIME", old, 1);
} else {
unsetenv("PPC_TASK_MAX_TIME");
}
}

TEST(GetPerfMaxTime, ReturnsDefaultWhenUnset) {
const char* old = std::getenv("PPC_PERF_MAX_TIME");
unsetenv("PPC_PERF_MAX_TIME");
EXPECT_DOUBLE_EQ(ppc::util::GetPerfMaxTime(), 10.0);
if (old) {
setenv("PPC_PERF_MAX_TIME", old, 1);
}
}

TEST(GetPerfMaxTime, ReadsFromEnvironment) {
const char* old = std::getenv("PPC_PERF_MAX_TIME");
setenv("PPC_PERF_MAX_TIME", "12.5", 1);
EXPECT_DOUBLE_EQ(ppc::util::GetPerfMaxTime(), 12.5);
if (old) {
setenv("PPC_PERF_MAX_TIME", old, 1);
} else {
unsetenv("PPC_PERF_MAX_TIME");
}
}
Loading