From 77acf9cf6efeefdb6aeb7d5423dbd89edeb97958 Mon Sep 17 00:00:00 2001 From: Daniel Trugman Date: Fri, 2 Jul 2021 15:37:12 +0000 Subject: [PATCH] Add cgroup controllers parser --- include/pfs/parsers.hpp | 1 + include/pfs/procfs.hpp | 2 + include/pfs/types.hpp | 8 +++ sample/enum_system.cpp | 3 + sample/format.hpp | 11 ++++ src/parsers/cgroup_controller.cpp | 102 ++++++++++++++++++++++++++++++ src/procfs.cpp | 13 ++++ test/cgroup_controller.cpp | 49 ++++++++++++++ 8 files changed, 189 insertions(+) create mode 100644 src/parsers/cgroup_controller.cpp create mode 100644 test/cgroup_controller.cpp diff --git a/include/pfs/parsers.hpp b/include/pfs/parsers.hpp index 9ae644e..2006770 100644 --- a/include/pfs/parsers.hpp +++ b/include/pfs/parsers.hpp @@ -67,6 +67,7 @@ std::pair parse_filesystems_line(const std::string& line); std::pair parse_meminfo_line(const std::string& line); zone parse_buddyinfo_line(const std::string& line); +cgroup_controller parse_cgroup_controller_line(const std::string& line); load_average parse_loadavg_line(const std::string& line); uptime parse_uptime_line(const std::string& line); module parse_modules_line(const std::string& line); diff --git a/include/pfs/procfs.hpp b/include/pfs/procfs.hpp index 87312d3..f2263fb 100644 --- a/include/pfs/procfs.hpp +++ b/include/pfs/procfs.hpp @@ -53,6 +53,8 @@ class procfs final public: // System API std::vector get_buddyinfo() const; + std::vector get_cgroups() const; + std::string get_cmdline() const; std::unordered_map get_filesystems() const; diff --git a/include/pfs/types.hpp b/include/pfs/types.hpp index f8dbad7..9bdc2a8 100644 --- a/include/pfs/types.hpp +++ b/include/pfs/types.hpp @@ -551,6 +551,14 @@ struct netlink_socket } }; +struct cgroup_controller +{ + std::string subsys_name; + unsigned hierarchy; + unsigned num_cgroups; + bool enabled; +}; + } // namespace pfs #endif // PFS_TYPES_HPP diff --git a/sample/enum_system.cpp b/sample/enum_system.cpp index 3289fdb..19ab36f 100644 --- a/sample/enum_system.cpp +++ b/sample/enum_system.cpp @@ -61,6 +61,9 @@ int enum_system(std::vector&& args) auto version_signature = pfs.get_version_signature(); print(version_signature); + + auto controllers = pfs.get_cgroups(); + print(controllers); } catch (const std::runtime_error& ex) { diff --git a/sample/format.hpp b/sample/format.hpp index bf9a5e0..96ae0db 100644 --- a/sample/format.hpp +++ b/sample/format.hpp @@ -652,3 +652,14 @@ inline std::ostream& operator<<(std::ostream& out, const pfs::fd& fd) out << "target[" << fd.get_target() << "] "; return out; } + +inline std::ostream& operator<<(std::ostream& out, + const pfs::cgroup_controller& controller) +{ + out << std::boolalpha; + out << "subsys_name[" << controller.subsys_name << "] "; + out << "hierarchy[" << controller.hierarchy << "] "; + out << "num_cgroups[" << controller.num_cgroups << "] "; + out << "enabled[" << controller.enabled << "] "; + return out; +} diff --git a/src/parsers/cgroup_controller.cpp b/src/parsers/cgroup_controller.cpp new file mode 100644 index 0000000..52315cd --- /dev/null +++ b/src/parsers/cgroup_controller.cpp @@ -0,0 +1,102 @@ +/* + * Copyright 2020-present Daniel Trugman + * + * 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. + */ + +#include "pfs/parsers.hpp" +#include "pfs/utils.hpp" + +namespace pfs { +namespace impl { +namespace parsers { + +cgroup_controller parse_cgroup_controller_line(const std::string& line) +{ + // Some examples: + // clang-format off + // #subsys_name hierarchy num_cgroups enabled + // cpuset 6 1 1 + // cpu 5 33 1 + // cpuacct 5 33 1 + // blkio 7 33 1 + // memory 8 76 1 + // devices 12 33 1 + // freezer 3 1 1 + // net_cls 2 1 1 + // perf_event 11 1 1 + // net_prio 2 1 1 + // hugetlb 10 1 1 + // pids 4 38 1 + // rdma 9 1 1 + // clang-format on + + enum token + { + SUBSYS_NAME = 0, + HIERARCHY = 1, + NUM_CGROUPS = 2, + ENABLED = 3, + COUNT + }; + + static const char DELIM = '\t'; + + auto tokens = utils::split(line, DELIM); + if (tokens.size() != COUNT) + { + throw parser_error( + "Corrupted cgroup controller line - Unexpected tokens count", line); + } + + try + { + cgroup_controller controller; + + controller.subsys_name = tokens[SUBSYS_NAME]; + + utils::stot(tokens[HIERARCHY], controller.hierarchy); + + utils::stot(tokens[NUM_CGROUPS], controller.num_cgroups); + + if (tokens[ENABLED] == "0") + { + controller.enabled = false; + } + else if (tokens[ENABLED] == "1") + { + controller.enabled = true; + } + else + { + throw parser_error( + "Corrupted cgroup controller line - Unexpected enabled value", + tokens[ENABLED]); + } + + return controller; + } + catch (const std::invalid_argument& ex) + { + throw parser_error("Corrupted cgroup controller - Invalid argument", + line); + } + catch (const std::out_of_range& ex) + { + throw parser_error("Corrupted cgroup controller - Out of range", line); + } +} + +} // namespace parsers +} // namespace impl +} // namespace pfs diff --git a/src/procfs.cpp b/src/procfs.cpp index aed098f..744dc5a 100644 --- a/src/procfs.cpp +++ b/src/procfs.cpp @@ -89,6 +89,19 @@ std::vector procfs::get_buddyinfo() const return output; } +std::vector procfs::get_cgroups() const +{ + static const size_t HEADER_LINES = 1; + + static const std::string CGROUPS_FILE("cgroups"); + auto path = _root + CGROUPS_FILE; + + std::vector output; + parsers::parse_lines(path, std::back_inserter(output), + parsers::parse_cgroup_controller_line, HEADER_LINES); + return output; +} + std::string procfs::get_cmdline() const { static const std::string CMDLINE_FILE("cmdline"); diff --git a/test/cgroup_controller.cpp b/test/cgroup_controller.cpp new file mode 100644 index 0000000..2fee84e --- /dev/null +++ b/test/cgroup_controller.cpp @@ -0,0 +1,49 @@ +#include + +#include "catch.hpp" +#include "test_utils.hpp" + +#include "pfs/parsers.hpp" + +using namespace pfs::impl::parsers; + +TEST_CASE("Parse corrupted cgroup controller", "[procfs][cgroup]") +{ + // Missing last token (enabled) + std::string line = "devices 12 33"; + + REQUIRE_THROWS_AS(parse_cgroup_controller_line(line), pfs::parser_error); +} + +TEST_CASE("Parse cgroup controller", "[procfs][cgroup]") +{ + pfs::cgroup_controller expected; + + SECTION("Enabled") + { + expected.subsys_name = "perf_event"; + expected.hierarchy = 11; + expected.num_cgroups = 1; + expected.enabled = true; + } + + SECTION("Disabled") + { + expected.subsys_name = "hugetlb"; + expected.hierarchy = 0; + expected.num_cgroups = 1; + expected.enabled = false; + } + + std::ostringstream line; + line << expected.subsys_name << '\t'; + line << expected.hierarchy << '\t'; + line << expected.num_cgroups << '\t'; + line << (expected.enabled ? '1' : '0'); + + auto controller = parse_cgroup_controller_line(line.str()); + REQUIRE(controller.subsys_name == expected.subsys_name); + REQUIRE(controller.hierarchy == expected.hierarchy); + REQUIRE(controller.num_cgroups == expected.num_cgroups); + REQUIRE(controller.enabled == expected.enabled); +}