diff --git a/source/libs/sgeobj/CMakeLists.txt b/source/libs/sgeobj/CMakeLists.txt index 183757de1..20540a606 100644 --- a/source/libs/sgeobj/CMakeLists.txt +++ b/source/libs/sgeobj/CMakeLists.txt @@ -25,6 +25,7 @@ set(LIBRARY_SOURCES cull_parse_util.cc ocs_binding_io.cc ocs_DataStore.cc + ocs_HostTopology.cc ocs_Session.cc parse.cc sge_ack.cc diff --git a/source/libs/sgeobj/ocs_HostTopology.cc b/source/libs/sgeobj/ocs_HostTopology.cc new file mode 100644 index 000000000..373d997aa --- /dev/null +++ b/source/libs/sgeobj/ocs_HostTopology.cc @@ -0,0 +1,137 @@ +/*___INFO__MARK_BEGIN_NEW__*/ +/*************************************************************************** + * + * Copyright 2024 HPC-Gridware GmbH + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ***************************************************************************/ +/*___INFO__MARK_END_NEW__*/ + +#include +#include + +#include "ocs_HostTopology.h" + +ocs::HostTopology::HostTopology(std::string &topo_mask) : topo_mask(topo_mask) { + parseTopoMask(topo_mask); + numberTopoNodes(sockets); + sortNodes(sockets); +} + +/** @brief Parses the topology mask and builds the topology tree. + * + * EBNF format of a well-formed topology mask: + * topo_mask := socket_mask+ + * socket_mask := socket_char core_mask+ + * core_mask := core_char thread_mask+ + * thread_mask := thread_char + * socket_char := 'S' | 's' + * core_char := 'C' | 'c' | 'E' | 'e' + * thread_char := 'T' | 't' + * + * @param topo_mask + */ +void +ocs::HostTopology::parseTopoMask(std::string &topo_mask){ + std::vector cores; + std::vector threads; + + // We reverse the topo_mask to simplify the parsing! + for (char &it : std::ranges::reverse_view(topo_mask)) { + if (it == 'S' || it == 's') { + // put collected cores into a socket +// std::reverse is not available at su0-0-lx-riscv64. Why? + //std::reverse(cores.begin(), cores.end()); + Node socket(it, std::move(cores)); + cores = std::vector(); + + // collect all sockets + this->sockets.push_back(std::move(socket)); + } else if (it == 'C' || it == 'c' || it == 'E' || it == 'e') { + // put collected threads into a core + //std::reverse(threads.begin(), threads.end()); + Node core(it, std::move(threads)); + threads = std::vector(); + + // collect all cores + cores.push_back(std::move(core)); + } else if (it == 'T' || it == 't') { + Node thread(it); + + // collect all threads + threads.push_back(std::move(thread)); + } + } + //std::reverse(sockets.begin(), sockets.end()); + + // We did not strictly parse the EBNF syntax of the topology mask. But need to ensure that it is really well-formed. + // Therefor, we compare the parsed topology mask with the original one. + if (topo_mask != getTopoMask()) { + throw std::runtime_error("Invalid topology mask"); + } +} + +void +ocs::HostTopology::buildTopoMask(const Node& node, std::ostringstream& oss) const { + oss << node.c; + for (const auto& child : node.nodes) { + buildTopoMask(child, oss); + } +} + +void +ocs::HostTopology::buildFullTopoMask(const Node& node, std::ostringstream& oss) const { + oss << node.c << node.id; + for (const auto& child : node.nodes) { + buildFullTopoMask(child, oss); + } +} + +std::string +ocs::HostTopology::getTopoMask() const { + std::ostringstream oss; + for (const auto& socket : sockets) { + buildTopoMask(socket, oss); + } + return oss.str(); +} + +std::string +ocs::HostTopology::getFullTopoMask() const { + std::ostringstream oss; + for (const auto& socket : sockets) { + buildFullTopoMask(socket, oss); + } + return oss.str(); +} + +void +ocs::HostTopology::numberTopoNodes(std::vector &nodes) { + size_t id = 0; + for (auto &node : nodes) { + node.id = id++; + numberTopoNodes(node.nodes); + } +} + +void +ocs::HostTopology::sortNodes(std::vector& nodes) { + // also not available on su0-0-lx-riscv64 ? + //std::sort(nodes.begin(), nodes.end(), [](const Node& a, const Node& b) { + // return a.c < b.c; + //}); + for (auto& node : nodes) { + sortNodes(node.nodes); + } +} diff --git a/source/libs/sgeobj/ocs_HostTopology.h b/source/libs/sgeobj/ocs_HostTopology.h new file mode 100644 index 000000000..dbcdee8a1 --- /dev/null +++ b/source/libs/sgeobj/ocs_HostTopology.h @@ -0,0 +1,56 @@ +#pragma once + +/*___INFO__MARK_BEGIN_NEW__*/ +/*************************************************************************** + * + * Copyright 2024 HPC-Gridware GmbH + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ***************************************************************************/ +/*___INFO__MARK_END_NEW__*/ + +#include +#include +#include +#include + +namespace ocs { + class HostTopology { + class Node { + public: + char c; + size_t id; + std::vector nodes; + + explicit Node(char c, std::vector nodes) : c(c), id(0), nodes(std::move(nodes)) {} + explicit Node(char c) : c(c), id(0), nodes() {} + ~Node() = default; + }; + + std::string topo_mask; + std::vector sockets; + + void parseTopoMask(std::string &topo_mask); + void buildTopoMask(const Node& node, std::ostringstream& oss) const; + void buildFullTopoMask(const Node& node, std::ostringstream& oss) const; + void numberTopoNodes(std::vector &nodes); + void sortNodes(std::vector& nodes); + + public: + HostTopology(std::string &topo_mask); + + std::string getTopoMask() const; + std::string getFullTopoMask() const; + }; +} diff --git a/test/libs/sgeobj/CMakeLists.txt b/test/libs/sgeobj/CMakeLists.txt index ea1754261..c66cbc501 100644 --- a/test/libs/sgeobj/CMakeLists.txt +++ b/test/libs/sgeobj/CMakeLists.txt @@ -40,6 +40,11 @@ target_include_directories(test_sgeobj_fgl PRIVATE "./") target_link_libraries(test_sgeobj_fgl PRIVATE sgeobj cull commlists uti ${SGE_LIBS}) add_test(NAME test_sgeobj_fgl COMMAND test_sgeobj_fgl) +add_executable(test_sgeobj_HostTopology test_sgeobj_HostTopology.cc) +target_include_directories(test_sgeobj_HostTopology PRIVATE "./") +target_link_libraries(test_sgeobj_HostTopology PRIVATE sched gdi sgeobj gdi cull comm uti commlists ${SGE_LIBS}) +add_test(NAME test_sgeobj_HostTopology COMMAND test_sgeobj_HostTopology) + add_executable(test_sgeobj_object test_sgeobj_object.cc) target_include_directories(test_sgeobj_object PRIVATE "./") target_link_libraries(test_sgeobj_object PRIVATE sgeobj cull comm uti commlists ${SGE_LIBS}) @@ -75,6 +80,7 @@ if (INSTALL_SGE_TEST) install(TARGETS test_sgeobj_performance DESTINATION testbin/${SGE_ARCH}) install(TARGETS test_sgeobj_attr DESTINATION testbin/${SGE_ARCH}) install(TARGETS test_sgeobj_fgl DESTINATION testbin/${SGE_ARCH}) + install(TARGETS test_sgeobj_HostTopology DESTINATION testbin/${SGE_ARCH}) install(TARGETS test_sgeobj_object DESTINATION testbin/${SGE_ARCH}) install(TARGETS test_sgeobj_range DESTINATION testbin/${SGE_ARCH}) install(TARGETS test_sgeobj_resource_quota DESTINATION testbin/${SGE_ARCH}) diff --git a/test/libs/sgeobj/test_sgeobj_HostTopology.cc b/test/libs/sgeobj/test_sgeobj_HostTopology.cc new file mode 100644 index 000000000..4730d90e9 --- /dev/null +++ b/test/libs/sgeobj/test_sgeobj_HostTopology.cc @@ -0,0 +1,33 @@ +/*___INFO__MARK_BEGIN_NEW__*/ +/*************************************************************************** + * + * Copyright 2024 HPC-Gridware GmbH + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ***************************************************************************/ +/*___INFO__MARK_END_NEW__*/ + +#include + +#include "sgeobj/ocs_HostTopology.h" + +int main (int argc, char *argv[]) { + std::string topo_mask = "ScTTCtTsctTtt"; + ocs::HostTopology ht = ocs::HostTopology(topo_mask); + + std::cout << topo_mask << std::endl; + std::cout << ht.getTopoMask() << std::endl; + std::cout << ht.getFullTopoMask() << std::endl; + return 0; +} \ No newline at end of file