Skip to content

Commit 8ab7b17

Browse files
allnesaobolensk
andauthored
Rework example task layout (#786)
## What changed - Reworked the old example directories into one `tasks/example` tree with `threads` and `processes/t1`, `processes/t2`, `processes/t3` sections. - Removed the old physical example directories: `tasks/example_threads`, `tasks/example_processes`, `tasks/example_processes_2`, and `tasks/example_processes_3`. - Added unified example metadata and shared resources at `tasks/example/settings.json`, `tasks/example/info.json`, `tasks/example/common`, and `tasks/example/data`. - Updated CMake support for the example meta-layout and `-DPPC_TASKS=example`. - Updated example functional and performance tests for the new `threads` and `processes/t1..t3` layout. - Updated nested settings handling so each example implementation can be enabled or disabled independently. - Updated the performance table parser and scoreboard support for the new example layout. --------- Co-authored-by: Arseniy Obolenskiy <gooddoog@student.su>
1 parent 3b1f08c commit 8ab7b17

88 files changed

Lines changed: 617 additions & 444 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

cmake/functions.cmake

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,3 +97,54 @@ function(ppc_configure_subproject SUBDIR)
9797
"${CMAKE_CURRENT_SOURCE_DIR}/${SUBDIR}")
9898
endforeach()
9999
endfunction()
100+
101+
function(ppc_configure_meta_part PROJ_NAME BASE_DIR)
102+
set(TEST_DIR "${BASE_DIR}/tests")
103+
set(TEST_EXECUTABLES "")
104+
105+
add_tests(USE_FUNC_TESTS ${FUNC_TEST_EXEC} functional)
106+
add_tests(USE_PERF_TESTS ${PERF_TEST_EXEC} performance)
107+
108+
message(STATUS " -- ${PROJ_NAME}")
109+
110+
foreach(IMPL IN LISTS PPC_IMPLEMENTATIONS)
111+
setup_implementation(
112+
NAME
113+
${IMPL}
114+
PROJ_NAME
115+
${PROJ_NAME}
116+
TESTS
117+
"${TEST_EXECUTABLES}"
118+
BASE_DIR
119+
"${BASE_DIR}")
120+
endforeach()
121+
endfunction()
122+
123+
function(ppc_configure_meta_project SUBDIR)
124+
add_compile_definitions(
125+
PPC_SETTINGS_${SUBDIR}="${CMAKE_CURRENT_SOURCE_DIR}/${SUBDIR}/settings.json"
126+
PPC_ID_${SUBDIR}="${SUBDIR}")
127+
128+
project(${SUBDIR})
129+
message(STATUS "${SUBDIR}")
130+
131+
if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/${SUBDIR}/threads")
132+
ppc_configure_meta_part(${SUBDIR}_threads
133+
"${CMAKE_CURRENT_SOURCE_DIR}/${SUBDIR}/threads")
134+
endif()
135+
136+
file(
137+
GLOB process_task_dirs
138+
RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}/${SUBDIR}/processes"
139+
"${CMAKE_CURRENT_SOURCE_DIR}/${SUBDIR}/processes/*")
140+
list(SORT process_task_dirs)
141+
foreach(PROCESS_TASK IN LISTS process_task_dirs)
142+
if(NOT IS_DIRECTORY
143+
"${CMAKE_CURRENT_SOURCE_DIR}/${SUBDIR}/processes/${PROCESS_TASK}")
144+
continue()
145+
endif()
146+
ppc_configure_meta_part(
147+
${SUBDIR}_processes_${PROCESS_TASK}
148+
"${CMAKE_CURRENT_SOURCE_DIR}/${SUBDIR}/processes/${PROCESS_TASK}")
149+
endforeach()
150+
endfunction()

modules/task/include/task.hpp

Lines changed: 34 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -78,9 +78,11 @@ inline std::string GetStringTaskStatus(StatusOfTask status_of_task) {
7878
/// @brief Returns a string representation of the task type based on the JSON settings file.
7979
/// @param type_of_task Type of the task.
8080
/// @param settings_file_path Path to the JSON file containing task type strings.
81+
/// @param settings_task_path Optional dot-separated nested path inside the `tasks` object.
8182
/// @return Formatted string combining the task type and its corresponding value from the file.
82-
/// @throws std::runtime_error If the file cannot be opened.
83-
inline std::string GetStringTaskType(TypeOfTask type_of_task, const std::string &settings_file_path) {
83+
/// @throws std::runtime_error If the file cannot be opened or the requested settings key is missing.
84+
inline std::string GetStringTaskType(TypeOfTask type_of_task, const std::string &settings_file_path,
85+
std::string_view settings_task_path = {}) {
8486
std::ifstream file(settings_file_path);
8587
if (!file.is_open()) {
8688
throw std::runtime_error("Failed to open " + settings_file_path);
@@ -94,8 +96,36 @@ inline std::string GetStringTaskType(TypeOfTask type_of_task, const std::string
9496
return std::string(type_str);
9597
}
9698

97-
const auto &tasks = list_settings->at("tasks");
98-
return std::string(type_str) + "_" + std::string(tasks.at(std::string(type_str)));
99+
auto get_required_node = [&settings_file_path](const nlohmann::json &node, const std::string &key,
100+
const std::string &settings_key_path) -> const nlohmann::json & {
101+
if (!node.is_object() || !node.contains(key)) {
102+
throw std::runtime_error("Missing settings key '" + settings_key_path + "' in " + settings_file_path);
103+
}
104+
return *node.find(key);
105+
};
106+
107+
std::string settings_key_path = "tasks";
108+
const auto *settings_node = &get_required_node(*list_settings, "tasks", settings_key_path);
109+
for (size_t start = 0; start < settings_task_path.size();) {
110+
const size_t separator = settings_task_path.find('.', start);
111+
const size_t key_size = separator == std::string_view::npos ? settings_task_path.size() - start : separator - start;
112+
if (key_size == 0) {
113+
throw std::runtime_error("Empty settings key in '" + std::string(settings_task_path) + "' from " +
114+
settings_file_path);
115+
}
116+
const std::string key(settings_task_path.substr(start, key_size));
117+
settings_key_path += "." + key;
118+
settings_node = &get_required_node(*settings_node, key, settings_key_path);
119+
if (separator == std::string_view::npos) {
120+
break;
121+
}
122+
start = separator + 1;
123+
}
124+
125+
const std::string type_key(type_str);
126+
settings_key_path += "." + type_key;
127+
const auto &type_node = get_required_node(*settings_node, type_key, settings_key_path);
128+
return type_key + "_" + type_node.get<std::string>();
99129
}
100130

101131
enum class StateOfTesting : uint8_t {

modules/task/tests/task_tests.cpp

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -210,6 +210,32 @@ TEST(TaskTest, GetStringTaskTypeEachTypeWithValidFile) {
210210
EXPECT_NO_THROW(GetStringTaskType(TypeOfTask::kSEQ, path));
211211
}
212212

213+
TEST(TaskTest, GetStringTaskTypeReadsNestedTaskPath) {
214+
std::string path = "settings_nested.json";
215+
ScopedFile cleaner(path);
216+
std::ofstream file(path);
217+
file << R"({"tasks": {"processes": {"t2": {"mpi": "disabled", "seq": "enabled"}}}})";
218+
file.close();
219+
220+
EXPECT_EQ(GetStringTaskType(TypeOfTask::kMPI, path, "processes.t2"), "mpi_disabled");
221+
EXPECT_EQ(GetStringTaskType(TypeOfTask::kSEQ, path, "processes.t2"), "seq_enabled");
222+
}
223+
224+
TEST(TaskTest, GetStringTaskTypeReportsMissingNestedTaskPath) {
225+
std::string path = "settings_missing_nested.json";
226+
ScopedFile cleaner(path);
227+
std::ofstream file(path);
228+
file << R"({"tasks": {"processes": {"t1": {"mpi": "enabled"}}}})";
229+
file.close();
230+
231+
try {
232+
GetStringTaskType(TypeOfTask::kMPI, path, "processes.t2");
233+
FAIL() << "Expected std::runtime_error";
234+
} catch (const std::runtime_error &e) {
235+
EXPECT_NE(std::string(e.what()).find("tasks.processes.t2"), std::string::npos);
236+
}
237+
}
238+
213239
TEST(TaskTest, GetStringTaskTypeReturnsUnknownOnDefault) {
214240
std::string path = "settings_valid_unknown.json";
215241
ScopedFile cleaner(path);

modules/util/include/func_test_util.hpp

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,11 @@
44
#include <tbb/tick_count.h>
55

66
#include <concepts>
7-
#include <csignal>
87
#include <cstddef>
98
#include <functional>
109
#include <iostream>
1110
#include <string>
11+
#include <string_view>
1212
#include <tuple>
1313
#include <type_traits>
1414
#include <utility>
@@ -133,22 +133,25 @@ auto ExpandToValues(const Tuple &t) {
133133

134134
template <typename Task, typename InType, typename SizesContainer, std::size_t... Is>
135135
auto GenTaskTuplesImpl(const SizesContainer &sizes, const std::string &settings_path,
136-
std::index_sequence<Is...> /*unused*/) {
137-
return std::make_tuple(std::make_tuple(ppc::task::TaskGetter<Task, InType>,
138-
std::string(GetNamespace<Task>()) + "_" +
139-
ppc::task::GetStringTaskType(Task::GetStaticTypeOfTask(), settings_path),
140-
std::get<Is>(sizes))...);
136+
std::string_view settings_task_path, std::index_sequence<Is...> /*unused*/) {
137+
return std::make_tuple(
138+
std::make_tuple(ppc::task::TaskGetter<Task, InType>,
139+
std::string(GetNamespace<Task>()) + "_" +
140+
ppc::task::GetStringTaskType(Task::GetStaticTypeOfTask(), settings_path, settings_task_path),
141+
std::get<Is>(sizes))...);
141142
}
142143

143144
template <typename Task, typename InType, typename SizesContainer>
144-
auto TaskListGenerator(const SizesContainer &sizes, const std::string &settings_path) {
145-
return GenTaskTuplesImpl<Task, InType>(sizes, settings_path,
145+
auto TaskListGenerator(const SizesContainer &sizes, const std::string &settings_path,
146+
std::string_view settings_task_path = {}) {
147+
return GenTaskTuplesImpl<Task, InType>(sizes, settings_path, settings_task_path,
146148
std::make_index_sequence<std::tuple_size_v<std::decay_t<SizesContainer>>>{});
147149
}
148150

149151
template <typename Task, typename InType, typename SizesContainer>
150-
constexpr auto AddFuncTask(const SizesContainer &sizes, const std::string &settings_path) {
151-
return TaskListGenerator<Task, InType>(sizes, settings_path);
152+
constexpr auto AddFuncTask(const SizesContainer &sizes, const std::string &settings_path,
153+
std::string_view settings_task_path = {}) {
154+
return TaskListGenerator<Task, InType>(sizes, settings_path, settings_task_path);
152155
}
153156

154157
} // namespace ppc::util

modules/util/include/perf_test_util.hpp

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,12 @@
55
#include <tbb/tick_count.h>
66

77
#include <chrono>
8-
#include <csignal>
98
#include <cstddef>
109
#include <functional>
1110
#include <sstream>
1211
#include <stdexcept>
1312
#include <string>
13+
#include <string_view>
1414
#include <tuple>
1515
#include <type_traits>
1616
#include <utility>
@@ -77,7 +77,8 @@ class BaseRunPerfTests : public ::testing::TestWithParam<PerfTestParam<InType, O
7777

7878
ASSERT_FALSE(test_name.find("unknown") != std::string::npos);
7979
if (test_name.find("disabled") != std::string::npos) {
80-
GTEST_SKIP();
80+
// A single perf test body may execute several implementations; do not abort the enabled ones.
81+
return;
8182
}
8283

8384
const auto test_env_scope = ppc::util::test::MakePerTestEnvForCurrentGTest(test_name);
@@ -111,9 +112,9 @@ class BaseRunPerfTests : public ::testing::TestWithParam<PerfTestParam<InType, O
111112
};
112113

113114
template <typename TaskType, typename InputType>
114-
auto MakePerfTaskTuples(const std::string &settings_path) {
115+
auto MakePerfTaskTuples(const std::string &settings_path, std::string_view settings_task_path = {}) {
115116
const auto name = std::string(GetNamespace<TaskType>()) + "_" +
116-
ppc::task::GetStringTaskType(TaskType::GetStaticTypeOfTask(), settings_path);
117+
ppc::task::GetStringTaskType(TaskType::GetStaticTypeOfTask(), settings_path, settings_task_path);
117118

118119
return std::make_tuple(std::make_tuple(ppc::task::TaskGetter<TaskType, InputType>, name,
119120
ppc::performance::PerfResults::TypeOfRunning::kPipeline),
@@ -133,8 +134,8 @@ auto TupleToGTestValues(Tuple &&tup) {
133134
}
134135

135136
template <typename InputType, typename... TaskTypes>
136-
auto MakeAllPerfTasks(const std::string &settings_path) {
137-
return std::tuple_cat(MakePerfTaskTuples<TaskTypes, InputType>(settings_path)...);
137+
auto MakeAllPerfTasks(const std::string &settings_path, std::string_view settings_task_path = {}) {
138+
return std::tuple_cat(MakePerfTaskTuples<TaskTypes, InputType>(settings_path, settings_task_path)...);
138139
}
139140

140141
} // namespace ppc::util

scoreboard/data/copying.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,6 @@ threads:
99
processes:
1010
copying:
1111
mpi:
12-
- example_processes
12+
- example_processes_t1
1313
seq:
14-
- example_processes
14+
- example_processes_t1

0 commit comments

Comments
 (0)