123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429 |
- // Copyright 2021 The Chromium Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style license that can be
- // found in the LICENSE file.
- #include "services/device/compute_pressure/procfs_stat_cpu_parser.h"
- #include <memory>
- #include <string>
- #include <vector>
- #include "base/files/file.h"
- #include "base/files/file_util.h"
- #include "base/files/scoped_temp_dir.h"
- #include "base/strings/string_piece_forward.h"
- #include "testing/gmock/include/gmock/gmock.h"
- #include "testing/gtest/include/gtest/gtest.h"
- namespace device {
- class ProcfsStatCpuParserTest : public testing::Test {
- public:
- ~ProcfsStatCpuParserTest() override = default;
- void SetUp() override {
- ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
- fake_stat_path_ = temp_dir_.GetPath().AppendASCII("stat");
- // Create the /proc/stat file before creating the parser, in case the parser
- // implementation keeps an open handle to the file indefinitely.
- stat_file_ = base::File(fake_stat_path_, base::File::FLAG_CREATE_ALWAYS |
- base::File::FLAG_WRITE);
- parser_ = std::make_unique<ProcfsStatCpuParser>(fake_stat_path_);
- }
- [[nodiscard]] bool WriteFakeStat(base::StringPiece contents) {
- if (!stat_file_.SetLength(0))
- return false;
- if (contents.size() > 0) {
- if (!stat_file_.Write(0, contents.data(), contents.size()))
- return false;
- }
- return true;
- }
- protected:
- base::ScopedTempDir temp_dir_;
- base::FilePath fake_stat_path_;
- base::File stat_file_;
- std::unique_ptr<ProcfsStatCpuParser> parser_;
- };
- TEST_F(ProcfsStatCpuParserTest, ProductionData_NoCrash) {
- base::FilePath production_path(ProcfsStatCpuParser::kProcfsStatPath);
- ProcfsStatCpuParser parser(production_path);
- bool parse_success = parser.Update();
- if (!parse_success) {
- // Log /proc/stat for debugging.
- std::string stat_file = "(failed to read /proc/stat)";
- base::ReadFileToString(production_path, &stat_file);
- FAIL() << stat_file;
- }
- }
- TEST_F(ProcfsStatCpuParserTest, MissingFile) {
- stat_file_ = base::File();
- ASSERT_TRUE(base::DeleteFile(fake_stat_path_));
- ProcfsStatCpuParser parser(fake_stat_path_);
- EXPECT_FALSE(parser.Update());
- EXPECT_EQ(parser_->core_times().size(), 0u);
- }
- TEST_F(ProcfsStatCpuParserTest, EmptyFile) {
- ASSERT_TRUE(WriteFakeStat(""));
- EXPECT_EQ(0, stat_file_.GetLength()) << "Incorrect empty file";
- EXPECT_TRUE(parser_->Update());
- EXPECT_EQ(parser_->core_times().size(), 0u);
- }
- TEST_F(ProcfsStatCpuParserTest, SingleCore_SingleDigit) {
- // Zero is not used as a value, because it is the initial value of CoreTimes
- // members. Avoiding that value brings assurance that Update() modified the
- // CoreTimes member.
- ASSERT_TRUE(WriteFakeStat("cpu0 1 2 3 4 5 6 7 8 9 1"));
- EXPECT_TRUE(parser_->Update());
- ASSERT_EQ(parser_->core_times().size(), 1u);
- EXPECT_EQ(parser_->core_times()[0].user(), 1u);
- EXPECT_EQ(parser_->core_times()[0].nice(), 2u);
- EXPECT_EQ(parser_->core_times()[0].system(), 3u);
- EXPECT_EQ(parser_->core_times()[0].idle(), 4u);
- EXPECT_EQ(parser_->core_times()[0].iowait(), 5u);
- EXPECT_EQ(parser_->core_times()[0].irq(), 6u);
- EXPECT_EQ(parser_->core_times()[0].softirq(), 7u);
- EXPECT_EQ(parser_->core_times()[0].steal(), 8u);
- EXPECT_EQ(parser_->core_times()[0].guest(), 9u);
- EXPECT_EQ(parser_->core_times()[0].guest_nice(), 1u);
- }
- TEST_F(ProcfsStatCpuParserTest, SingleCore_MultipleDigits) {
- // Checks that the number parser can parse numbers of various sizes. The sizes
- // are not in ascending order, to make sure that the number size isn't in sync
- // with a loop counter.
- //
- // Number of digits in each number: 2 4 3 6 5 8 7 9 1 10
- ASSERT_TRUE(WriteFakeStat(
- "cpu0 12 3456 789 102345 67890 12345678 9012345 678901234 5 1234567890"));
- EXPECT_TRUE(parser_->Update());
- ASSERT_EQ(parser_->core_times().size(), 1u);
- EXPECT_EQ(parser_->core_times()[0].user(), 12u);
- EXPECT_EQ(parser_->core_times()[0].nice(), 3456u);
- EXPECT_EQ(parser_->core_times()[0].system(), 789u);
- EXPECT_EQ(parser_->core_times()[0].idle(), 102345u);
- EXPECT_EQ(parser_->core_times()[0].iowait(), 67890u);
- EXPECT_EQ(parser_->core_times()[0].irq(), 12345678u);
- EXPECT_EQ(parser_->core_times()[0].softirq(), 9012345u);
- EXPECT_EQ(parser_->core_times()[0].steal(), 678901234u);
- EXPECT_EQ(parser_->core_times()[0].guest(), 5u);
- EXPECT_EQ(parser_->core_times()[0].guest_nice(), 1234567890u);
- }
- TEST_F(ProcfsStatCpuParserTest, SingleCore_TooManyNumbers) {
- ASSERT_TRUE(WriteFakeStat("cpu0 10 11 12 13 14 15 16 17 18 19 20 21 22 23"));
- EXPECT_TRUE(parser_->Update());
- ASSERT_EQ(parser_->core_times().size(), 1u);
- EXPECT_EQ(parser_->core_times()[0].user(), 10u);
- EXPECT_EQ(parser_->core_times()[0].nice(), 11u);
- EXPECT_EQ(parser_->core_times()[0].system(), 12u);
- EXPECT_EQ(parser_->core_times()[0].idle(), 13u);
- EXPECT_EQ(parser_->core_times()[0].iowait(), 14u);
- EXPECT_EQ(parser_->core_times()[0].irq(), 15u);
- EXPECT_EQ(parser_->core_times()[0].softirq(), 16u);
- EXPECT_EQ(parser_->core_times()[0].steal(), 17u);
- EXPECT_EQ(parser_->core_times()[0].guest(), 18u);
- EXPECT_EQ(parser_->core_times()[0].guest_nice(), 19u);
- }
- TEST_F(ProcfsStatCpuParserTest, SingleCore_TooFewNumbers) {
- const std::vector<const char*> test_cases = {
- "cpu0 1 2 3 4 5 6 7 8 9",
- "cpu0 1 2 3 4 5 6 7 8",
- "cpu0 1 2 3 4 5 6 7",
- "cpu0 1 2 3 4 5 6",
- "cpu0 1 2 3 4 5",
- "cpu0 1 2 3 4",
- "cpu0 1 2 3",
- "cpu0 1 2",
- "cpu0 1",
- };
- for (const char* test_case : test_cases) {
- SCOPED_TRACE(test_case);
- ProcfsStatCpuParser parser(fake_stat_path_);
- ASSERT_TRUE(WriteFakeStat(test_case));
- EXPECT_TRUE(parser.Update());
- ASSERT_EQ(parser.core_times().size(), 1u);
- EXPECT_EQ(parser.core_times()[0].user(), 0u);
- EXPECT_EQ(parser.core_times()[0].nice(), 0u);
- EXPECT_EQ(parser.core_times()[0].system(), 0u);
- EXPECT_EQ(parser.core_times()[0].idle(), 0u);
- EXPECT_EQ(parser.core_times()[0].iowait(), 0u);
- EXPECT_EQ(parser.core_times()[0].irq(), 0u);
- EXPECT_EQ(parser.core_times()[0].softirq(), 0u);
- EXPECT_EQ(parser.core_times()[0].steal(), 0u);
- EXPECT_EQ(parser.core_times()[0].guest(), 0u);
- EXPECT_EQ(parser.core_times()[0].guest_nice(), 0u);
- }
- }
- TEST_F(ProcfsStatCpuParserTest, SingleCore_NoNumbers) {
- ASSERT_TRUE(WriteFakeStat("cpu0"));
- EXPECT_TRUE(parser_->Update());
- EXPECT_EQ(parser_->core_times().size(), 0u);
- }
- TEST_F(ProcfsStatCpuParserTest, IncorrectCoreSpecifier) {
- const std::vector<const char*> test_cases = {
- "dpu0 1 2 3 4 5 6 7 8 9 0",
- "cru0 1 2 3 4 5 6 7 8 9 0",
- "cpv0 1 2 3 4 5 6 7 8 9 0",
- "cpu 1 2 3 4 5 6 7 8 9 0",
- "cpua 1 2 3 4 5 6 7 8 9 0",
- "cpu- 1 2 3 4 5 6 7 8 9 0",
- "cpu-1 1 2 3 4 5 6 7 8 9 0",
- "cpu-100 1 2 3 4 5 6 7 8 9 0",
- "cpu1a 1 2 3 4 5 6 7 8 9 0",
- "cpu1- 1 2 3 4 5 6 7 8 9 0",
- "cpu\U0001f41b 1 2 3 4 5 6 7 8 9 0",
- "cpu1\U0001f41b 1 2 3 4 5 6 7 8 9 0",
- "cpu\U0001f41b1 1 2 3 4 5 6 7 8 9 0",
- };
- for (const char* test_case : test_cases) {
- SCOPED_TRACE(test_case);
- ProcfsStatCpuParser parser(fake_stat_path_);
- ASSERT_TRUE(WriteFakeStat(test_case));
- EXPECT_TRUE(parser.Update());
- EXPECT_EQ(parser.core_times().size(), 0u);
- }
- }
- TEST_F(ProcfsStatCpuParserTest, InvalidFirstNumber) {
- const std::vector<const char*> test_cases = {
- "cpu0 a 2 3 4 5 6 7 8 9 10",
- "cpu0 - 2 3 4 5 6 7 8 9 10",
- "cpu0 -1 2 3 4 5 6 7 8 9 10",
- "cpu0 -100 2 3 4 5 6 7 8 9 10",
- "cpu0 1a 2 3 4 5 6 7 8 9 10",
- "cpu0 1234a 2 3 4 5 6 7 8 9 10",
- "cpu0 123456789012345678901 2 3 4 5 6 7 8 9 10",
- "cpu0 -123456789012345678901 2 3 4 5 6 7 8 9 10",
- "cpu0 18446744073709551616 2 3 4 5 6 7 8 9 10",
- "cpu0 \U0001f41b 2 3 4 5 6 7 8 9 10",
- "cpu0 1\U0001f41b 2 3 4 5 6 7 8 9 10",
- "cpu0 \U0001f41b1 2 3 4 5 6 7 8 9 10",
- };
- for (const char* test_case : test_cases) {
- SCOPED_TRACE(test_case);
- ProcfsStatCpuParser parser(fake_stat_path_);
- ASSERT_TRUE(WriteFakeStat(test_case));
- EXPECT_TRUE(parser.Update());
- ASSERT_EQ(parser.core_times().size(), 1u);
- EXPECT_EQ(parser.core_times()[0].user(), 0u);
- EXPECT_EQ(parser.core_times()[0].nice(), 0u);
- EXPECT_EQ(parser.core_times()[0].system(), 0u);
- EXPECT_EQ(parser.core_times()[0].idle(), 0u);
- EXPECT_EQ(parser.core_times()[0].iowait(), 0u);
- EXPECT_EQ(parser.core_times()[0].irq(), 0u);
- EXPECT_EQ(parser.core_times()[0].softirq(), 0u);
- EXPECT_EQ(parser.core_times()[0].steal(), 0u);
- EXPECT_EQ(parser.core_times()[0].guest(), 0u);
- EXPECT_EQ(parser.core_times()[0].guest_nice(), 0u);
- }
- }
- TEST_F(ProcfsStatCpuParserTest, InvalidNumberSkipped) {
- struct TestCase {
- const char* line;
- int invalid_index;
- };
- const std::vector<TestCase> test_cases = {
- {"cpu0 1 2 3 4 5 6 7 8 9 10", 10},
- {"cpu0 a 2 3 4 5 6 7 8 9 10", 0},
- {"cpu0 1 a 3 4 5 6 7 8 9 10", 1},
- {"cpu0 1 2 a 4 5 6 7 8 9 10", 2},
- {"cpu0 1 2 3 a 5 6 7 8 9 10", 3},
- {"cpu0 1 2 3 4 a 6 7 8 9 10", 4},
- {"cpu0 1 2 3 4 5 a 7 8 9 10", 5},
- {"cpu0 1 2 3 4 5 6 a 8 9 10", 6},
- {"cpu0 1 2 3 4 5 6 7 a 9 10", 7},
- {"cpu0 1 2 3 4 5 6 7 8 a 10", 8},
- {"cpu0 1 2 3 4 5 6 7 8 9 a", 9},
- {"cpu0 1 \U0001f41b 3 4 5 6 7 8 9 10", 1},
- {"cpu0 1 2 3\U0001f41b 4 5 6 7 8 9 10", 2},
- {"cpu0 1 2 3 \U0001f41b4 5 6 7 8 9 10", 3},
- };
- for (const TestCase& test_case : test_cases) {
- SCOPED_TRACE(test_case.line);
- ProcfsStatCpuParser parser(fake_stat_path_);
- ASSERT_TRUE(WriteFakeStat(test_case.line));
- EXPECT_TRUE(parser.Update());
- ASSERT_EQ(parser.core_times().size(), 1u);
- EXPECT_EQ(parser.core_times()[0].user(),
- (test_case.invalid_index <= 0) ? 0u : 1u);
- EXPECT_EQ(parser.core_times()[0].nice(),
- (test_case.invalid_index <= 1) ? 0u : 2u);
- EXPECT_EQ(parser.core_times()[0].system(),
- (test_case.invalid_index <= 2) ? 0u : 3u);
- EXPECT_EQ(parser.core_times()[0].idle(),
- (test_case.invalid_index <= 3) ? 0u : 4u);
- EXPECT_EQ(parser.core_times()[0].iowait(),
- (test_case.invalid_index <= 4) ? 0u : 5u);
- EXPECT_EQ(parser.core_times()[0].irq(),
- (test_case.invalid_index <= 5) ? 0u : 6u);
- EXPECT_EQ(parser.core_times()[0].softirq(),
- (test_case.invalid_index <= 6) ? 0u : 7u);
- EXPECT_EQ(parser.core_times()[0].steal(),
- (test_case.invalid_index <= 7) ? 0u : 8u);
- EXPECT_EQ(parser.core_times()[0].guest(),
- (test_case.invalid_index <= 8) ? 0u : 9u);
- EXPECT_EQ(parser.core_times()[0].guest_nice(),
- (test_case.invalid_index <= 9) ? 0u : 10u);
- }
- }
- TEST_F(ProcfsStatCpuParserTest, SingleCore_IgnoresCounterDecrease) {
- struct TestCase {
- const char* line;
- int invalid_index;
- };
- const std::vector<TestCase> test_cases = {
- {"cpu0 106 116 126 136 146 156 166 176 186 196", 10},
- {"cpu0 104 116 126 136 146 156 166 176 186 196", 0},
- {"cpu0 106 114 126 136 146 156 166 176 186 196", 1},
- {"cpu0 106 116 124 136 146 156 166 176 186 196", 2},
- {"cpu0 106 116 126 134 146 156 166 176 186 196", 3},
- {"cpu0 106 116 126 136 144 156 166 176 186 196", 4},
- {"cpu0 106 116 126 136 146 154 166 176 186 196", 5},
- {"cpu0 106 116 126 136 146 156 164 176 186 196", 6},
- {"cpu0 106 116 126 136 146 156 166 174 186 196", 7},
- {"cpu0 106 116 126 136 146 156 166 176 184 196", 8},
- {"cpu0 106 116 126 136 146 156 166 176 186 194", 9},
- };
- for (const TestCase& test_case : test_cases) {
- SCOPED_TRACE(test_case.line);
- ProcfsStatCpuParser parser(fake_stat_path_);
- ASSERT_TRUE(WriteFakeStat("cpu0 105 115 125 135 145 155 165 175 185 195"));
- EXPECT_TRUE(parser.Update());
- ASSERT_EQ(parser.core_times().size(), 1u);
- ASSERT_TRUE(WriteFakeStat(test_case.line));
- EXPECT_TRUE(parser.Update());
- EXPECT_EQ(parser.core_times()[0].user(),
- (test_case.invalid_index == 0) ? 105u : 106u);
- EXPECT_EQ(parser.core_times()[0].nice(),
- (test_case.invalid_index == 1) ? 115u : 116u);
- EXPECT_EQ(parser.core_times()[0].system(),
- (test_case.invalid_index == 2) ? 125u : 126u);
- EXPECT_EQ(parser.core_times()[0].idle(),
- (test_case.invalid_index == 3) ? 135u : 136u);
- EXPECT_EQ(parser.core_times()[0].iowait(),
- (test_case.invalid_index == 4) ? 145u : 146u);
- EXPECT_EQ(parser.core_times()[0].irq(),
- (test_case.invalid_index == 5) ? 155u : 156u);
- EXPECT_EQ(parser.core_times()[0].softirq(),
- (test_case.invalid_index == 6) ? 165u : 166u);
- EXPECT_EQ(parser.core_times()[0].steal(),
- (test_case.invalid_index == 7) ? 175u : 176u);
- EXPECT_EQ(parser.core_times()[0].guest(),
- (test_case.invalid_index == 8) ? 185u : 186u);
- EXPECT_EQ(parser.core_times()[0].guest_nice(),
- (test_case.invalid_index == 9) ? 195u : 196u);
- }
- }
- TEST_F(ProcfsStatCpuParserTest, MissingCores) {
- ASSERT_TRUE(WriteFakeStat("cpu5 1 2 3 4 5 6 7 8 9 1"));
- EXPECT_TRUE(parser_->Update());
- ASSERT_EQ(parser_->core_times().size(), 6u);
- EXPECT_EQ(parser_->core_times()[5].user(), 1u);
- EXPECT_EQ(parser_->core_times()[5].nice(), 2u);
- EXPECT_EQ(parser_->core_times()[5].system(), 3u);
- EXPECT_EQ(parser_->core_times()[5].idle(), 4u);
- EXPECT_EQ(parser_->core_times()[5].iowait(), 5u);
- EXPECT_EQ(parser_->core_times()[5].irq(), 6u);
- EXPECT_EQ(parser_->core_times()[5].softirq(), 7u);
- EXPECT_EQ(parser_->core_times()[5].steal(), 8u);
- EXPECT_EQ(parser_->core_times()[5].guest(), 9u);
- EXPECT_EQ(parser_->core_times()[5].guest_nice(), 1u);
- for (int i = 0; i < 5; ++i) {
- EXPECT_EQ(parser_->core_times()[i].user(), 0u);
- EXPECT_EQ(parser_->core_times()[i].nice(), 0u);
- EXPECT_EQ(parser_->core_times()[i].system(), 0u);
- EXPECT_EQ(parser_->core_times()[i].idle(), 0u);
- EXPECT_EQ(parser_->core_times()[i].iowait(), 0u);
- EXPECT_EQ(parser_->core_times()[i].irq(), 0u);
- EXPECT_EQ(parser_->core_times()[i].softirq(), 0u);
- EXPECT_EQ(parser_->core_times()[i].steal(), 0u);
- EXPECT_EQ(parser_->core_times()[i].guest(), 0u);
- EXPECT_EQ(parser_->core_times()[i].guest_nice(), 0u);
- }
- }
- TEST_F(ProcfsStatCpuParserTest, MultipleCores) {
- ASSERT_TRUE(WriteFakeStat(R"(
- cpu 100 101 102 103 104 105 106 107 108 109
- cpu2 30 31 32 33 34 35 36 37 38 39
- cpu3 40 41 42 43 44 45 46 47 48 49
- cpu0 10 11 12 13 14 15 16 17 18 19
- cpu5 60 61 62 63 64 65 66 67 68 69
- cpu1 20 21 22 23 24 25 26 27 28 29
- cpu4 50 51 52 53 54 55 56 57 58 59
- intr 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217
- ctxt 23456789012
- btime 1234567890
- processes 6789012
- procs_running 700
- procs_blocked 600
- softirq 900 901 902 903 904 905 906 907 908 909 910
- )"));
- EXPECT_TRUE(parser_->Update());
- ASSERT_EQ(parser_->core_times().size(), 6u);
- for (int i = 0; i < 6; ++i) {
- EXPECT_EQ(parser_->core_times()[i].user(),
- static_cast<uint64_t>(i * 10 + 10));
- EXPECT_EQ(parser_->core_times()[i].nice(),
- static_cast<uint64_t>(i * 10 + 11));
- EXPECT_EQ(parser_->core_times()[i].system(),
- static_cast<uint64_t>(i * 10 + 12));
- EXPECT_EQ(parser_->core_times()[i].idle(),
- static_cast<uint64_t>(i * 10 + 13));
- EXPECT_EQ(parser_->core_times()[i].iowait(),
- static_cast<uint64_t>(i * 10 + 14));
- EXPECT_EQ(parser_->core_times()[i].irq(),
- static_cast<uint64_t>(i * 10 + 15));
- EXPECT_EQ(parser_->core_times()[i].softirq(),
- static_cast<uint64_t>(i * 10 + 16));
- EXPECT_EQ(parser_->core_times()[i].steal(),
- static_cast<uint64_t>(i * 10 + 17));
- EXPECT_EQ(parser_->core_times()[i].guest(),
- static_cast<uint64_t>(i * 10 + 18));
- EXPECT_EQ(parser_->core_times()[i].guest_nice(),
- static_cast<uint64_t>(i * 10 + 19));
- }
- }
- } // namespace device
|