Avi Drissman | e4622aa | 2022-09-08 20:36:06 | [diff] [blame] | 1 | // Copyright 2013 The Chromium Authors |
[email protected] | 669a0933 | 2013-08-30 22:59:14 | [diff] [blame] | 2 | // Use of this source code is governed by a BSD-style license that can be |
| 3 | // found in the LICENSE file. |
| 4 | |
Tom Sepez | 8726d30e | 2025-01-29 02:11:08 | [diff] [blame] | 5 | #ifdef UNSAFE_BUFFERS_BUILD |
| 6 | // TODO(crbug.com/390223051): Remove C-library calls to fix the errors. |
| 7 | #pragma allow_unsafe_libc_calls |
| 8 | #endif |
| 9 | |
[email protected] | 669a0933 | 2013-08-30 22:59:14 | [diff] [blame] | 10 | #include "base/process/process_metrics.h" |
| 11 | |
avi | beced7c | 2015-12-24 06:47:59 | [diff] [blame] | 12 | #include <stddef.h> |
| 13 | #include <stdint.h> |
| 14 | |
Peter Kasting | 025a9425 | 2025-01-29 21:28:37 | [diff] [blame] | 15 | #include <algorithm> |
Arthur Sonzogni | 0844a99 | 2024-12-12 11:36:20 | [diff] [blame] | 16 | #include <array> |
Peter Boström | 6b70182 | 2021-04-15 03:53:08 | [diff] [blame] | 17 | #include <memory> |
[email protected] | 669a0933 | 2013-08-30 22:59:14 | [diff] [blame] | 18 | #include <sstream> |
| 19 | #include <string> |
Joe Mason | f481218 | 2024-01-19 01:12:37 | [diff] [blame] | 20 | #include <utility> |
Benoit Lize | 448ee88 | 2017-08-31 13:32:12 | [diff] [blame] | 21 | #include <vector> |
[email protected] | 669a0933 | 2013-08-30 22:59:14 | [diff] [blame] | 22 | |
thestig | cf4c85b | 2015-12-16 08:33:30 | [diff] [blame] | 23 | #include "base/command_line.h" |
| 24 | #include "base/files/file.h" |
Joe Mason | f481218 | 2024-01-19 01:12:37 | [diff] [blame] | 25 | #include "base/files/file_path.h" |
thestig | cf4c85b | 2015-12-16 08:33:30 | [diff] [blame] | 26 | #include "base/files/file_util.h" |
| 27 | #include "base/files/scoped_temp_dir.h" |
Avi Drissman | 63e1f99 | 2023-01-13 18:54:43 | [diff] [blame] | 28 | #include "base/functional/bind.h" |
arthursonzogni | 38d9bf47 | 2019-04-15 13:00:11 | [diff] [blame] | 29 | #include "base/memory/shared_memory_mapping.h" |
| 30 | #include "base/memory/writable_shared_memory_region.h" |
Joe Mason | f481218 | 2024-01-19 01:12:37 | [diff] [blame] | 31 | #include "base/process/launch.h" |
| 32 | #include "base/process/process.h" |
| 33 | #include "base/process/process_handle.h" |
afakhry | 8c03da07 | 2015-12-03 01:26:19 | [diff] [blame] | 34 | #include "base/strings/string_number_conversions.h" |
Eric Seckler | dbc29da | 2020-07-10 11:54:05 | [diff] [blame] | 35 | #include "base/strings/string_util.h" |
Robert Sesek | 3aff336 | 2019-01-23 20:16:16 | [diff] [blame] | 36 | #include "base/strings/stringprintf.h" |
Sebastien Marchand | 75a7cdf | 2018-11-13 23:47:03 | [diff] [blame] | 37 | #include "base/system/sys_info.h" |
Joe Mason | 550eed6 | 2024-03-25 18:07:31 | [diff] [blame] | 38 | #include "base/test/gmock_expected_support.h" |
Joe Mason | f481218 | 2024-01-19 01:12:37 | [diff] [blame] | 39 | #include "base/test/gtest_util.h" |
thestig | cf4c85b | 2015-12-16 08:33:30 | [diff] [blame] | 40 | #include "base/test/multiprocess_test.h" |
Joe Mason | f481218 | 2024-01-19 01:12:37 | [diff] [blame] | 41 | #include "base/test/test_timeouts.h" |
[email protected] | cf46e375 | 2013-12-02 01:01:01 | [diff] [blame] | 42 | #include "base/threading/thread.h" |
Joe Mason | 550eed6 | 2024-03-25 18:07:31 | [diff] [blame] | 43 | #include "base/types/expected.h" |
Joe Mason | f481218 | 2024-01-19 01:12:37 | [diff] [blame] | 44 | #include "build/blink_buildflags.h" |
avi | beced7c | 2015-12-24 06:47:59 | [diff] [blame] | 45 | #include "build/build_config.h" |
Joe Mason | ba14528 | 2024-03-12 20:18:19 | [diff] [blame] | 46 | #include "testing/gmock/include/gmock/gmock.h" |
[email protected] | 669a0933 | 2013-08-30 22:59:14 | [diff] [blame] | 47 | #include "testing/gtest/include/gtest/gtest.h" |
thestig | cf4c85b | 2015-12-16 08:33:30 | [diff] [blame] | 48 | #include "testing/multiprocess_func_list.h" |
[email protected] | 669a0933 | 2013-08-30 22:59:14 | [diff] [blame] | 49 | |
Xiaohan Wang | 37e8161 | 2022-01-15 18:27:00 | [diff] [blame] | 50 | #if BUILDFLAG(IS_APPLE) |
erikchen | 863e474 | 2017-03-31 19:57:43 | [diff] [blame] | 51 | #include <sys/mman.h> |
| 52 | #endif |
| 53 | |
Dave Tapuska | 828a495c | 2024-03-26 17:33:03 | [diff] [blame] | 54 | #if BUILDFLAG(IS_MAC) |
Joe Mason | f481218 | 2024-01-19 01:12:37 | [diff] [blame] | 55 | #include <mach/mach.h> |
| 56 | |
| 57 | #include "base/apple/mach_logging.h" |
Mark Rowe | ced178d | 2024-10-08 21:16:09 | [diff] [blame] | 58 | #include "base/apple/mach_port_rendezvous.h" |
Joe Mason | f481218 | 2024-01-19 01:12:37 | [diff] [blame] | 59 | #include "base/apple/scoped_mach_port.h" |
Joe Mason | f481218 | 2024-01-19 01:12:37 | [diff] [blame] | 60 | #include "base/process/port_provider_mac.h" |
Eric Seckler | dbc29da | 2020-07-10 11:54:05 | [diff] [blame] | 61 | #endif |
| 62 | |
Georg Neis | ff37fb5 | 2025-02-05 09:05:26 | [diff] [blame] | 63 | #if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_WIN) || \ |
Joe Mason | f75bf18 | 2023-10-17 22:16:25 | [diff] [blame] | 64 | BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_FUCHSIA) || BUILDFLAG(IS_APPLE) |
| 65 | #define ENABLE_CPU_TESTS 1 |
| 66 | #else |
| 67 | #define ENABLE_CPU_TESTS 0 |
| 68 | #endif |
| 69 | |
| 70 | namespace base::debug { |
Fabrice de Gans | 4072fcf | 2021-08-20 21:35:29 | [diff] [blame] | 71 | |
afakhry | 8c03da07 | 2015-12-03 01:26:19 | [diff] [blame] | 72 | namespace { |
| 73 | |
Joe Mason | 550eed6 | 2024-03-25 18:07:31 | [diff] [blame] | 74 | using base::test::ErrorIs; |
| 75 | using base::test::ValueIs; |
| 76 | using ::testing::_; |
Joe Mason | ba14528 | 2024-03-12 20:18:19 | [diff] [blame] | 77 | using ::testing::AssertionFailure; |
| 78 | using ::testing::AssertionResult; |
| 79 | using ::testing::AssertionSuccess; |
| 80 | using ::testing::Ge; |
Joe Mason | ba14528 | 2024-03-12 20:18:19 | [diff] [blame] | 81 | |
Joe Mason | f75bf18 | 2023-10-17 22:16:25 | [diff] [blame] | 82 | #if ENABLE_CPU_TESTS |
| 83 | |
afakhry | 8c03da07 | 2015-12-03 01:26:19 | [diff] [blame] | 84 | void BusyWork(std::vector<std::string>* vec) { |
| 85 | int64_t test_value = 0; |
| 86 | for (int i = 0; i < 100000; ++i) { |
| 87 | ++test_value; |
Raul Tambre | a9c1364 | 2019-03-25 13:34:42 | [diff] [blame] | 88 | vec->push_back(NumberToString(test_value)); |
afakhry | 8c03da07 | 2015-12-03 01:26:19 | [diff] [blame] | 89 | } |
| 90 | } |
| 91 | |
Joe Mason | ba14528 | 2024-03-12 20:18:19 | [diff] [blame] | 92 | // Tests that GetCumulativeCPUUsage() returns a valid result that's equal to or |
| 93 | // greater than `prev_cpu_usage`, and returns the result. If |
| 94 | // GetCumulativeCPUUsage() returns an error, records a failed expectation and |
| 95 | // returns an empty TimeDelta so that each test doesn't need to check for |
| 96 | // nullopt repeatedly. |
Joe Mason | c2c3f72 | 2023-10-17 19:51:17 | [diff] [blame] | 97 | TimeDelta TestCumulativeCPU(ProcessMetrics* metrics, TimeDelta prev_cpu_usage) { |
Joe Mason | 550eed6 | 2024-03-25 18:07:31 | [diff] [blame] | 98 | const base::expected<TimeDelta, ProcessCPUUsageError> current_cpu_usage = |
Joe Mason | ba14528 | 2024-03-12 20:18:19 | [diff] [blame] | 99 | metrics->GetCumulativeCPUUsage(); |
Joe Mason | 550eed6 | 2024-03-25 18:07:31 | [diff] [blame] | 100 | EXPECT_THAT(current_cpu_usage, ValueIs(Ge(prev_cpu_usage))); |
| 101 | EXPECT_THAT(metrics->GetPlatformIndependentCPUUsage(), ValueIs(Ge(0.0))); |
Joe Mason | ba14528 | 2024-03-12 20:18:19 | [diff] [blame] | 102 | return current_cpu_usage.value_or(TimeDelta()); |
Joe Mason | c2c3f72 | 2023-10-17 19:51:17 | [diff] [blame] | 103 | } |
| 104 | |
Joe Mason | f75bf18 | 2023-10-17 22:16:25 | [diff] [blame] | 105 | #endif // ENABLE_CPU_TESTS |
Fabrice de Gans | 4072fcf | 2021-08-20 21:35:29 | [diff] [blame] | 106 | |
Joe Mason | f481218 | 2024-01-19 01:12:37 | [diff] [blame] | 107 | // Helper to deal with Mac process launching complexity. On other platforms this |
| 108 | // is just a thin wrapper around SpawnMultiProcessTestChild. |
| 109 | class TestChildLauncher { |
| 110 | public: |
| 111 | TestChildLauncher() = default; |
| 112 | ~TestChildLauncher() = default; |
| 113 | |
| 114 | TestChildLauncher(const TestChildLauncher&) = delete; |
| 115 | TestChildLauncher& operator=(const TestChildLauncher&) = delete; |
| 116 | |
| 117 | // Returns a reference to the command line for the child process. This can be |
| 118 | // used to add extra parameters before calling SpawnChildProcess(). |
| 119 | CommandLine& command_line() { return command_line_; } |
| 120 | |
| 121 | // Returns a reference to the child process object, which will be invalid |
| 122 | // until SpawnChildProcess() is called. |
| 123 | Process& child_process() { return child_process_; } |
| 124 | |
| 125 | // Spawns a multiprocess test child to execute the function `procname`. |
| 126 | AssertionResult SpawnChildProcess(const std::string& procname); |
| 127 | |
| 128 | // Returns a ProcessMetrics object for the child process created by |
| 129 | // SpawnChildProcess(). |
| 130 | std::unique_ptr<ProcessMetrics> CreateChildProcessMetrics(); |
| 131 | |
| 132 | // Terminates the child process created by SpawnChildProcess(). Returns true |
| 133 | // if the process successfully terminates within the allowed time. |
| 134 | bool TerminateChildProcess(); |
| 135 | |
| 136 | // Called from the child process to send data back to the parent if needed. |
| 137 | static void NotifyParent(); |
| 138 | |
| 139 | private: |
| 140 | CommandLine command_line_ = GetMultiProcessTestChildBaseCommandLine(); |
| 141 | Process child_process_; |
| 142 | |
Dave Tapuska | 828a495c | 2024-03-26 17:33:03 | [diff] [blame] | 143 | #if BUILDFLAG(IS_MAC) |
Joe Mason | f481218 | 2024-01-19 01:12:37 | [diff] [blame] | 144 | class TestChildPortProvider; |
| 145 | std::unique_ptr<TestChildPortProvider> port_provider_; |
Joe Mason | f75bf18 | 2023-10-17 22:16:25 | [diff] [blame] | 146 | #endif |
Joe Mason | f481218 | 2024-01-19 01:12:37 | [diff] [blame] | 147 | }; |
| 148 | |
Dave Tapuska | 828a495c | 2024-03-26 17:33:03 | [diff] [blame] | 149 | #if BUILDFLAG(IS_MAC) |
Joe Mason | f481218 | 2024-01-19 01:12:37 | [diff] [blame] | 150 | |
Mark Rowe | ced178d | 2024-10-08 21:16:09 | [diff] [blame] | 151 | // Adapted from base/apple/mach_port_rendezvous_unittest.cc and |
Joe Mason | f481218 | 2024-01-19 01:12:37 | [diff] [blame] | 152 | // https://mw.foldr.org/posts/computers/macosx/task-info-fun-with-mach/ |
| 153 | |
| 154 | constexpr MachPortsForRendezvous::key_type kTestChildRendezvousKey = 'test'; |
| 155 | |
| 156 | // A PortProvider that tracks child processes spawned by TestChildLauncher. |
| 157 | class TestChildLauncher::TestChildPortProvider final : public PortProvider { |
| 158 | public: |
| 159 | TestChildPortProvider(ProcessHandle handle, apple::ScopedMachSendRight port) |
| 160 | : handle_(handle), port_(std::move(port)) {} |
| 161 | |
| 162 | ~TestChildPortProvider() final = default; |
| 163 | |
| 164 | TestChildPortProvider(const TestChildPortProvider&) = delete; |
| 165 | TestChildPortProvider& operator=(const TestChildPortProvider&) = delete; |
| 166 | |
Francois Doray | 789889031 | 2024-02-05 18:24:26 | [diff] [blame] | 167 | mach_port_t TaskForHandle(ProcessHandle process_handle) const final { |
| 168 | return process_handle == handle_ ? port_.get() : MACH_PORT_NULL; |
Joe Mason | f481218 | 2024-01-19 01:12:37 | [diff] [blame] | 169 | } |
| 170 | |
| 171 | private: |
| 172 | ProcessHandle handle_; |
| 173 | apple::ScopedMachSendRight port_; |
| 174 | }; |
| 175 | |
| 176 | AssertionResult TestChildLauncher::SpawnChildProcess( |
| 177 | const std::string& procname) { |
| 178 | // Allocate a port for the parent to receive details from the child process. |
| 179 | apple::ScopedMachReceiveRight receive_port; |
| 180 | if (!apple::CreateMachPort(&receive_port, nullptr)) { |
| 181 | return AssertionFailure() << "Failed to allocate receive port"; |
| 182 | } |
| 183 | |
| 184 | // Pass the sending end of the port to the child. |
| 185 | LaunchOptions options = LaunchOptionsForTest(); |
| 186 | options.mach_ports_for_rendezvous.emplace( |
| 187 | kTestChildRendezvousKey, |
| 188 | MachRendezvousPort(receive_port.get(), MACH_MSG_TYPE_MAKE_SEND)); |
| 189 | child_process_ = |
| 190 | SpawnMultiProcessTestChild(procname, command_line_, std::move(options)); |
| 191 | if (!child_process_.IsValid()) { |
| 192 | return AssertionFailure() << "Failed to launch child process."; |
| 193 | } |
| 194 | |
| 195 | // Wait for the child to send back its mach_task_self(). |
| 196 | struct : mach_msg_base_t { |
| 197 | mach_msg_port_descriptor_t task_port; |
| 198 | mach_msg_trailer_t trailer; |
| 199 | } msg{}; |
| 200 | kern_return_t kr = |
| 201 | mach_msg(&msg.header, MACH_RCV_MSG | MACH_RCV_TIMEOUT, 0, sizeof(msg), |
| 202 | receive_port.get(), |
| 203 | TestTimeouts::action_timeout().InMilliseconds(), MACH_PORT_NULL); |
| 204 | if (kr != KERN_SUCCESS) { |
| 205 | return AssertionFailure() |
| 206 | << "Failed to read mach_task_self from child process: " |
| 207 | << mach_error_string(kr); |
| 208 | } |
| 209 | port_provider_ = std::make_unique<TestChildPortProvider>( |
| 210 | child_process_.Handle(), apple::ScopedMachSendRight(msg.task_port.name)); |
| 211 | return AssertionSuccess(); |
Joe Mason | f75bf18 | 2023-10-17 22:16:25 | [diff] [blame] | 212 | } |
| 213 | |
Joe Mason | f481218 | 2024-01-19 01:12:37 | [diff] [blame] | 214 | std::unique_ptr<ProcessMetrics> TestChildLauncher::CreateChildProcessMetrics() { |
Gyuyoung Kim | f41383e | 2024-01-22 14:30:10 | [diff] [blame] | 215 | #if BUILDFLAG(IS_MAC) |
Joe Mason | f481218 | 2024-01-19 01:12:37 | [diff] [blame] | 216 | return ProcessMetrics::CreateProcessMetrics(child_process_.Handle(), |
| 217 | port_provider_.get()); |
Gyuyoung Kim | f41383e | 2024-01-22 14:30:10 | [diff] [blame] | 218 | #else |
| 219 | return ProcessMetrics::CreateProcessMetrics(child_process_.Handle()); |
| 220 | #endif |
Joe Mason | f481218 | 2024-01-19 01:12:37 | [diff] [blame] | 221 | } |
| 222 | |
| 223 | bool TestChildLauncher::TerminateChildProcess() { |
| 224 | return TerminateMultiProcessTestChild(child_process_, /*exit_code=*/0, |
| 225 | /*wait=*/true); |
| 226 | } |
| 227 | |
| 228 | // static |
| 229 | void TestChildLauncher::NotifyParent() { |
| 230 | auto* client = MachPortRendezvousClient::GetInstance(); |
| 231 | ASSERT_TRUE(client); |
| 232 | apple::ScopedMachSendRight send_port = |
| 233 | client->TakeSendRight(kTestChildRendezvousKey); |
| 234 | ASSERT_TRUE(send_port.is_valid()); |
| 235 | |
| 236 | // Send mach_task_self to the parent process so that it can use the port to |
| 237 | // create ProcessMetrics. |
| 238 | struct : mach_msg_base_t { |
| 239 | mach_msg_port_descriptor_t task_port; |
| 240 | } msg{}; |
| 241 | msg.header.msgh_bits = |
| 242 | MACH_MSGH_BITS_REMOTE(MACH_MSG_TYPE_COPY_SEND) | MACH_MSGH_BITS_COMPLEX; |
| 243 | msg.header.msgh_remote_port = send_port.get(); |
| 244 | msg.header.msgh_size = sizeof(msg); |
| 245 | msg.body.msgh_descriptor_count = 1; |
| 246 | msg.task_port.name = mach_task_self(); |
| 247 | msg.task_port.disposition = MACH_MSG_TYPE_COPY_SEND; |
| 248 | msg.task_port.type = MACH_MSG_PORT_DESCRIPTOR; |
| 249 | kern_return_t kr = |
| 250 | mach_msg(&msg.header, MACH_SEND_MSG, msg.header.msgh_size, 0, |
| 251 | MACH_PORT_NULL, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL); |
| 252 | MACH_CHECK(kr == KERN_SUCCESS, kr); |
| 253 | } |
| 254 | |
| 255 | #else |
| 256 | |
| 257 | AssertionResult TestChildLauncher::SpawnChildProcess( |
| 258 | const std::string& procname) { |
| 259 | child_process_ = SpawnMultiProcessTestChild(procname, command_line_, |
| 260 | LaunchOptionsForTest()); |
| 261 | return child_process_.IsValid() |
| 262 | ? AssertionSuccess() |
| 263 | : AssertionFailure() << "Failed to launch child process."; |
| 264 | } |
| 265 | |
| 266 | std::unique_ptr<ProcessMetrics> TestChildLauncher::CreateChildProcessMetrics() { |
| 267 | return ProcessMetrics::CreateProcessMetrics(child_process_.Handle()); |
| 268 | } |
| 269 | |
| 270 | bool TestChildLauncher::TerminateChildProcess() { |
| 271 | [[maybe_unused]] const ProcessHandle child_handle = child_process_.Handle(); |
| 272 | if (!TerminateMultiProcessTestChild(child_process_, /*exit_code=*/0, |
| 273 | /*wait=*/true)) { |
| 274 | return false; |
| 275 | } |
| 276 | #if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_ANDROID) |
| 277 | // After the process exits, ProcessMetrics races to read /proc/<pid>/stat |
| 278 | // before it's deleted. Wait until it's definitely gone. |
| 279 | const auto stat_path = FilePath(FILE_PATH_LITERAL("/proc")) |
| 280 | .AppendASCII(NumberToString(child_handle)) |
| 281 | .Append(FILE_PATH_LITERAL("stat")); |
| 282 | |
| 283 | while (PathExists(stat_path)) { |
| 284 | PlatformThread::Sleep(TestTimeouts::tiny_timeout()); |
| 285 | } |
| 286 | #endif |
| 287 | return true; |
| 288 | } |
| 289 | |
| 290 | // static |
| 291 | void TestChildLauncher::NotifyParent() { |
| 292 | // Do nothing. |
| 293 | } |
| 294 | |
| 295 | #endif // BUILDFLAG(IS_MAC) |
| 296 | |
Joe Mason | f75bf18 | 2023-10-17 22:16:25 | [diff] [blame] | 297 | } // namespace |
afakhry | 8c03da07 | 2015-12-03 01:26:19 | [diff] [blame] | 298 | |
[email protected] | 669a0933 | 2013-08-30 22:59:14 | [diff] [blame] | 299 | // Tests for SystemMetrics. |
| 300 | // Exists as a class so it can be a friend of SystemMetrics. |
| 301 | class SystemMetricsTest : public testing::Test { |
| 302 | public: |
Chris Watkins | bb7211c | 2017-11-29 07:16:38 | [diff] [blame] | 303 | SystemMetricsTest() = default; |
[email protected] | 669a0933 | 2013-08-30 22:59:14 | [diff] [blame] | 304 | |
Peter Boström | 75cd3c0 | 2021-09-28 15:23:18 | [diff] [blame] | 305 | SystemMetricsTest(const SystemMetricsTest&) = delete; |
| 306 | SystemMetricsTest& operator=(const SystemMetricsTest&) = delete; |
[email protected] | 669a0933 | 2013-08-30 22:59:14 | [diff] [blame] | 307 | }; |
| 308 | |
Xiaohan Wang | 37e8161 | 2022-01-15 18:27:00 | [diff] [blame] | 309 | #if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_ANDROID) |
[email protected] | 669a0933 | 2013-08-30 22:59:14 | [diff] [blame] | 310 | TEST_F(SystemMetricsTest, IsValidDiskName) { |
Lei Zhang | 912563e | 2017-07-20 16:49:58 | [diff] [blame] | 311 | const char invalid_input1[] = ""; |
| 312 | const char invalid_input2[] = "s"; |
| 313 | const char invalid_input3[] = "sdz+"; |
| 314 | const char invalid_input4[] = "hda0"; |
| 315 | const char invalid_input5[] = "mmcbl"; |
| 316 | const char invalid_input6[] = "mmcblka"; |
| 317 | const char invalid_input7[] = "mmcblkb"; |
| 318 | const char invalid_input8[] = "mmmblk0"; |
[email protected] | 669a0933 | 2013-08-30 22:59:14 | [diff] [blame] | 319 | |
| 320 | EXPECT_FALSE(IsValidDiskName(invalid_input1)); |
| 321 | EXPECT_FALSE(IsValidDiskName(invalid_input2)); |
| 322 | EXPECT_FALSE(IsValidDiskName(invalid_input3)); |
| 323 | EXPECT_FALSE(IsValidDiskName(invalid_input4)); |
| 324 | EXPECT_FALSE(IsValidDiskName(invalid_input5)); |
| 325 | EXPECT_FALSE(IsValidDiskName(invalid_input6)); |
| 326 | EXPECT_FALSE(IsValidDiskName(invalid_input7)); |
| 327 | EXPECT_FALSE(IsValidDiskName(invalid_input8)); |
| 328 | |
Lei Zhang | 912563e | 2017-07-20 16:49:58 | [diff] [blame] | 329 | const char valid_input1[] = "sda"; |
| 330 | const char valid_input2[] = "sdaaaa"; |
| 331 | const char valid_input3[] = "hdz"; |
| 332 | const char valid_input4[] = "mmcblk0"; |
| 333 | const char valid_input5[] = "mmcblk999"; |
[email protected] | 669a0933 | 2013-08-30 22:59:14 | [diff] [blame] | 334 | |
| 335 | EXPECT_TRUE(IsValidDiskName(valid_input1)); |
| 336 | EXPECT_TRUE(IsValidDiskName(valid_input2)); |
| 337 | EXPECT_TRUE(IsValidDiskName(valid_input3)); |
| 338 | EXPECT_TRUE(IsValidDiskName(valid_input4)); |
| 339 | EXPECT_TRUE(IsValidDiskName(valid_input5)); |
| 340 | } |
[email protected] | ded8c42b | 2013-11-05 22:15:03 | [diff] [blame] | 341 | |
| 342 | TEST_F(SystemMetricsTest, ParseMeminfo) { |
Lei Zhang | 912563e | 2017-07-20 16:49:58 | [diff] [blame] | 343 | SystemMemoryInfoKB meminfo; |
| 344 | const char invalid_input1[] = "abc"; |
| 345 | const char invalid_input2[] = "MemTotal:"; |
[email protected] | ded8c42b | 2013-11-05 22:15:03 | [diff] [blame] | 346 | // Partial file with no MemTotal |
Lei Zhang | 912563e | 2017-07-20 16:49:58 | [diff] [blame] | 347 | const char invalid_input3[] = |
| 348 | "MemFree: 3913968 kB\n" |
| 349 | "Buffers: 2348340 kB\n" |
| 350 | "Cached: 49071596 kB\n" |
| 351 | "SwapCached: 12 kB\n" |
| 352 | "Active: 36393900 kB\n" |
| 353 | "Inactive: 21221496 kB\n" |
| 354 | "Active(anon): 5674352 kB\n" |
| 355 | "Inactive(anon): 633992 kB\n"; |
[email protected] | ded8c42b | 2013-11-05 22:15:03 | [diff] [blame] | 356 | EXPECT_FALSE(ParseProcMeminfo(invalid_input1, &meminfo)); |
| 357 | EXPECT_FALSE(ParseProcMeminfo(invalid_input2, &meminfo)); |
| 358 | EXPECT_FALSE(ParseProcMeminfo(invalid_input3, &meminfo)); |
| 359 | |
Lei Zhang | 912563e | 2017-07-20 16:49:58 | [diff] [blame] | 360 | const char valid_input1[] = |
| 361 | "MemTotal: 3981504 kB\n" |
| 362 | "MemFree: 140764 kB\n" |
| 363 | "MemAvailable: 535413 kB\n" |
| 364 | "Buffers: 116480 kB\n" |
| 365 | "Cached: 406160 kB\n" |
| 366 | "SwapCached: 21304 kB\n" |
| 367 | "Active: 3152040 kB\n" |
| 368 | "Inactive: 472856 kB\n" |
| 369 | "Active(anon): 2972352 kB\n" |
| 370 | "Inactive(anon): 270108 kB\n" |
| 371 | "Active(file): 179688 kB\n" |
| 372 | "Inactive(file): 202748 kB\n" |
| 373 | "Unevictable: 0 kB\n" |
| 374 | "Mlocked: 0 kB\n" |
| 375 | "SwapTotal: 5832280 kB\n" |
| 376 | "SwapFree: 3672368 kB\n" |
| 377 | "Dirty: 184 kB\n" |
| 378 | "Writeback: 0 kB\n" |
| 379 | "AnonPages: 3101224 kB\n" |
| 380 | "Mapped: 142296 kB\n" |
| 381 | "Shmem: 140204 kB\n" |
| 382 | "Slab: 54212 kB\n" |
| 383 | "SReclaimable: 30936 kB\n" |
| 384 | "SUnreclaim: 23276 kB\n" |
| 385 | "KernelStack: 2464 kB\n" |
| 386 | "PageTables: 24812 kB\n" |
| 387 | "NFS_Unstable: 0 kB\n" |
| 388 | "Bounce: 0 kB\n" |
| 389 | "WritebackTmp: 0 kB\n" |
| 390 | "CommitLimit: 7823032 kB\n" |
| 391 | "Committed_AS: 7973536 kB\n" |
| 392 | "VmallocTotal: 34359738367 kB\n" |
| 393 | "VmallocUsed: 375940 kB\n" |
| 394 | "VmallocChunk: 34359361127 kB\n" |
| 395 | "DirectMap4k: 72448 kB\n" |
| 396 | "DirectMap2M: 4061184 kB\n"; |
[email protected] | ded8c42b | 2013-11-05 22:15:03 | [diff] [blame] | 397 | // output from a much older kernel where the Active and Inactive aren't |
| 398 | // broken down into anon and file and Huge Pages are enabled |
Lei Zhang | 912563e | 2017-07-20 16:49:58 | [diff] [blame] | 399 | const char valid_input2[] = |
| 400 | "MemTotal: 255908 kB\n" |
| 401 | "MemFree: 69936 kB\n" |
| 402 | "Buffers: 15812 kB\n" |
| 403 | "Cached: 115124 kB\n" |
| 404 | "SwapCached: 0 kB\n" |
| 405 | "Active: 92700 kB\n" |
| 406 | "Inactive: 63792 kB\n" |
| 407 | "HighTotal: 0 kB\n" |
| 408 | "HighFree: 0 kB\n" |
| 409 | "LowTotal: 255908 kB\n" |
| 410 | "LowFree: 69936 kB\n" |
| 411 | "SwapTotal: 524280 kB\n" |
| 412 | "SwapFree: 524200 kB\n" |
| 413 | "Dirty: 4 kB\n" |
| 414 | "Writeback: 0 kB\n" |
| 415 | "Mapped: 42236 kB\n" |
| 416 | "Slab: 25912 kB\n" |
| 417 | "Committed_AS: 118680 kB\n" |
| 418 | "PageTables: 1236 kB\n" |
| 419 | "VmallocTotal: 3874808 kB\n" |
| 420 | "VmallocUsed: 1416 kB\n" |
| 421 | "VmallocChunk: 3872908 kB\n" |
| 422 | "HugePages_Total: 0\n" |
| 423 | "HugePages_Free: 0\n" |
| 424 | "Hugepagesize: 4096 kB\n"; |
[email protected] | ded8c42b | 2013-11-05 22:15:03 | [diff] [blame] | 425 | |
| 426 | EXPECT_TRUE(ParseProcMeminfo(valid_input1, &meminfo)); |
danakj | 94219a21 | 2015-03-09 22:27:25 | [diff] [blame] | 427 | EXPECT_EQ(meminfo.total, 3981504); |
| 428 | EXPECT_EQ(meminfo.free, 140764); |
mkolom | 01ac10b | 2017-03-22 01:47:29 | [diff] [blame] | 429 | EXPECT_EQ(meminfo.available, 535413); |
danakj | 94219a21 | 2015-03-09 22:27:25 | [diff] [blame] | 430 | EXPECT_EQ(meminfo.buffers, 116480); |
| 431 | EXPECT_EQ(meminfo.cached, 406160); |
| 432 | EXPECT_EQ(meminfo.active_anon, 2972352); |
| 433 | EXPECT_EQ(meminfo.active_file, 179688); |
| 434 | EXPECT_EQ(meminfo.inactive_anon, 270108); |
| 435 | EXPECT_EQ(meminfo.inactive_file, 202748); |
| 436 | EXPECT_EQ(meminfo.swap_total, 5832280); |
| 437 | EXPECT_EQ(meminfo.swap_free, 3672368); |
| 438 | EXPECT_EQ(meminfo.dirty, 184); |
mkolom | 01ac10b | 2017-03-22 01:47:29 | [diff] [blame] | 439 | EXPECT_EQ(meminfo.reclaimable, 30936); |
Eric Willigers | 611cf54 | 2022-04-28 02:22:14 | [diff] [blame] | 440 | #if BUILDFLAG(IS_CHROMEOS) |
danakj | 94219a21 | 2015-03-09 22:27:25 | [diff] [blame] | 441 | EXPECT_EQ(meminfo.shmem, 140204); |
| 442 | EXPECT_EQ(meminfo.slab, 54212); |
[email protected] | ded8c42b | 2013-11-05 22:15:03 | [diff] [blame] | 443 | #endif |
Peter Kasting | a0b914dc | 2022-07-14 18:43:19 | [diff] [blame] | 444 | EXPECT_EQ(355725u, |
mkolom | 01ac10b | 2017-03-22 01:47:29 | [diff] [blame] | 445 | base::SysInfo::AmountOfAvailablePhysicalMemory(meminfo) / 1024); |
| 446 | // Simulate as if there is no MemAvailable. |
| 447 | meminfo.available = 0; |
Peter Kasting | a0b914dc | 2022-07-14 18:43:19 | [diff] [blame] | 448 | EXPECT_EQ(374448u, |
mkolom | 01ac10b | 2017-03-22 01:47:29 | [diff] [blame] | 449 | base::SysInfo::AmountOfAvailablePhysicalMemory(meminfo) / 1024); |
| 450 | meminfo = {}; |
[email protected] | ded8c42b | 2013-11-05 22:15:03 | [diff] [blame] | 451 | EXPECT_TRUE(ParseProcMeminfo(valid_input2, &meminfo)); |
danakj | 94219a21 | 2015-03-09 22:27:25 | [diff] [blame] | 452 | EXPECT_EQ(meminfo.total, 255908); |
| 453 | EXPECT_EQ(meminfo.free, 69936); |
mkolom | 01ac10b | 2017-03-22 01:47:29 | [diff] [blame] | 454 | EXPECT_EQ(meminfo.available, 0); |
danakj | 94219a21 | 2015-03-09 22:27:25 | [diff] [blame] | 455 | EXPECT_EQ(meminfo.buffers, 15812); |
| 456 | EXPECT_EQ(meminfo.cached, 115124); |
| 457 | EXPECT_EQ(meminfo.swap_total, 524280); |
| 458 | EXPECT_EQ(meminfo.swap_free, 524200); |
| 459 | EXPECT_EQ(meminfo.dirty, 4); |
Peter Kasting | a0b914dc | 2022-07-14 18:43:19 | [diff] [blame] | 460 | EXPECT_EQ(69936u, |
mkolom | 01ac10b | 2017-03-22 01:47:29 | [diff] [blame] | 461 | base::SysInfo::AmountOfAvailablePhysicalMemory(meminfo) / 1024); |
Joe Mason | 87c33f1 | 2024-02-09 15:47:04 | [diff] [blame] | 462 | |
| 463 | // output from a system with a large page cache, to catch arithmetic errors |
| 464 | // that incorrectly assume free + buffers + cached <= total. (Copied from |
Hidehiko Abe | 89ebba17 | 2025-01-30 19:33:29 | [diff] [blame] | 465 | // chromeos/ash/experiences/arc/test/data/mem_profile/16G.) |
Joe Mason | 87c33f1 | 2024-02-09 15:47:04 | [diff] [blame] | 466 | const char large_cache_input[] = |
| 467 | "MemTotal: 18025572 kB\n" |
| 468 | "MemFree: 13150176 kB\n" |
| 469 | "MemAvailable: 15447672 kB\n" |
| 470 | "Buffers: 1524852 kB\n" |
| 471 | "Cached: 12645260 kB\n" |
| 472 | "SwapCached: 0 kB\n" |
| 473 | "Active: 2572904 kB\n" |
| 474 | "Inactive: 1064976 kB\n" |
| 475 | "Active(anon): 1047836 kB\n" |
| 476 | "Inactive(anon): 11736 kB\n" |
| 477 | "Active(file): 1525068 kB\n" |
| 478 | "Inactive(file): 1053240 kB\n" |
| 479 | "Unevictable: 611904 kB\n" |
| 480 | "Mlocked: 32884 kB\n" |
| 481 | "SwapTotal: 11756208 kB\n" |
| 482 | "SwapFree: 11756208 kB\n" |
| 483 | "Dirty: 4152 kB\n" |
| 484 | "Writeback: 0 kB\n" |
| 485 | "AnonPages: 1079660 kB\n" |
| 486 | "Mapped: 782152 kB\n" |
| 487 | "Shmem: 591820 kB\n" |
| 488 | "Slab: 366104 kB\n" |
| 489 | "SReclaimable: 254356 kB\n" |
| 490 | "SUnreclaim: 111748 kB\n" |
| 491 | "KernelStack: 22652 kB\n" |
| 492 | "PageTables: 41540 kB\n" |
| 493 | "NFS_Unstable: 0 kB\n" |
| 494 | "Bounce: 0 kB\n" |
| 495 | "WritebackTmp: 0 kB\n" |
| 496 | "CommitLimit: 15768992 kB\n" |
| 497 | "Committed_AS: 36120244 kB\n" |
| 498 | "VmallocTotal: 34359738367 kB\n" |
| 499 | "VmallocUsed: 0 kB\n" |
| 500 | "VmallocChunk: 0 kB\n" |
| 501 | "Percpu: 3328 kB\n" |
| 502 | "AnonHugePages: 32768 kB\n" |
| 503 | "ShmemHugePages: 0 kB\n" |
| 504 | "ShmemPmdMapped: 0 kB\n" |
| 505 | "DirectMap4k: 293036 kB\n" |
| 506 | "DirectMap2M: 6918144 kB\n" |
| 507 | "DirectMap1G: 2097152 kB\n"; |
| 508 | |
| 509 | meminfo = {}; |
| 510 | EXPECT_TRUE(ParseProcMeminfo(large_cache_input, &meminfo)); |
| 511 | EXPECT_EQ(meminfo.total, 18025572); |
| 512 | EXPECT_EQ(meminfo.free, 13150176); |
| 513 | EXPECT_EQ(meminfo.buffers, 1524852); |
| 514 | EXPECT_EQ(meminfo.cached, 12645260); |
| 515 | EXPECT_EQ(GetSystemCommitChargeFromMeminfo(meminfo), 0u); |
[email protected] | ded8c42b | 2013-11-05 22:15:03 | [diff] [blame] | 516 | } |
| 517 | |
| 518 | TEST_F(SystemMetricsTest, ParseVmstat) { |
Kenichi Ishibashi | 4487152 | 2017-10-23 07:12:19 | [diff] [blame] | 519 | VmStatInfo vmstat; |
Kuo-Hsin Yang | a141f59 | 2020-09-10 07:09:33 | [diff] [blame] | 520 | // Part of vmstat from a 4.19 kernel. |
Lei Zhang | 912563e | 2017-07-20 16:49:58 | [diff] [blame] | 521 | const char valid_input1[] = |
Kuo-Hsin Yang | a141f59 | 2020-09-10 07:09:33 | [diff] [blame] | 522 | "pgpgin 2358216\n" |
| 523 | "pgpgout 296072\n" |
| 524 | "pswpin 345219\n" |
| 525 | "pswpout 2605828\n" |
| 526 | "pgalloc_dma32 8380235\n" |
| 527 | "pgalloc_normal 3384525\n" |
Lei Zhang | 912563e | 2017-07-20 16:49:58 | [diff] [blame] | 528 | "pgalloc_movable 0\n" |
Kuo-Hsin Yang | a141f59 | 2020-09-10 07:09:33 | [diff] [blame] | 529 | "allocstall_dma32 0\n" |
| 530 | "allocstall_normal 2028\n" |
| 531 | "allocstall_movable 32559\n" |
| 532 | "pgskip_dma32 0\n" |
| 533 | "pgskip_normal 0\n" |
| 534 | "pgskip_movable 0\n" |
| 535 | "pgfree 11802722\n" |
| 536 | "pgactivate 894917\n" |
| 537 | "pgdeactivate 3255711\n" |
| 538 | "pglazyfree 48\n" |
| 539 | "pgfault 10043657\n" |
| 540 | "pgmajfault 358901\n" |
| 541 | "pgmajfault_s 2100\n" |
| 542 | "pgmajfault_a 343211\n" |
| 543 | "pgmajfault_f 13590\n" |
| 544 | "pglazyfreed 0\n" |
| 545 | "pgrefill 3429488\n" |
| 546 | "pgsteal_kswapd 1466893\n" |
| 547 | "pgsteal_direct 1771759\n" |
| 548 | "pgscan_kswapd 1907332\n" |
| 549 | "pgscan_direct 2118930\n" |
| 550 | "pgscan_direct_throttle 154\n" |
| 551 | "pginodesteal 3176\n" |
| 552 | "slabs_scanned 293804\n" |
| 553 | "kswapd_inodesteal 16753\n" |
| 554 | "kswapd_low_wmark_hit_quickly 10\n" |
| 555 | "kswapd_high_wmark_hit_quickly 423\n" |
| 556 | "pageoutrun 441\n" |
| 557 | "pgrotated 1636\n" |
| 558 | "drop_pagecache 0\n" |
| 559 | "drop_slab 0\n" |
| 560 | "oom_kill 18\n"; |
Lei Zhang | 912563e | 2017-07-20 16:49:58 | [diff] [blame] | 561 | const char valid_input2[] = |
Kuo-Hsin Yang | a141f59 | 2020-09-10 07:09:33 | [diff] [blame] | 562 | "pgpgin 2606135\n" |
| 563 | "pgpgout 1359128\n" |
| 564 | "pswpin 899959\n" |
| 565 | "pswpout 19761244\n" |
| 566 | "pgalloc_dma 31\n" |
| 567 | "pgalloc_dma32 18139339\n" |
| 568 | "pgalloc_normal 44085950\n" |
| 569 | "pgalloc_movable 0\n" |
| 570 | "allocstall_dma 0\n" |
| 571 | "allocstall_dma32 0\n" |
| 572 | "allocstall_normal 18881\n" |
| 573 | "allocstall_movable 169527\n" |
| 574 | "pgskip_dma 0\n" |
| 575 | "pgskip_dma32 0\n" |
| 576 | "pgskip_normal 0\n" |
| 577 | "pgskip_movable 0\n" |
| 578 | "pgfree 63060999\n" |
| 579 | "pgactivate 1703494\n" |
| 580 | "pgdeactivate 20537803\n" |
| 581 | "pglazyfree 163\n" |
| 582 | "pgfault 45201169\n" |
| 583 | "pgmajfault 609626\n" |
| 584 | "pgmajfault_s 7488\n" |
| 585 | "pgmajfault_a 591793\n" |
| 586 | "pgmajfault_f 10345\n" |
| 587 | "pglazyfreed 0\n" |
| 588 | "pgrefill 20673453\n" |
| 589 | "pgsteal_kswapd 11802772\n" |
| 590 | "pgsteal_direct 8618160\n" |
| 591 | "pgscan_kswapd 12640517\n" |
| 592 | "pgscan_direct 9092230\n" |
| 593 | "pgscan_direct_throttle 638\n" |
| 594 | "pginodesteal 1716\n" |
| 595 | "slabs_scanned 2594642\n" |
| 596 | "kswapd_inodesteal 67358\n" |
| 597 | "kswapd_low_wmark_hit_quickly 52\n" |
| 598 | "kswapd_high_wmark_hit_quickly 11\n" |
| 599 | "pageoutrun 83\n" |
| 600 | "pgrotated 977\n" |
| 601 | "drop_pagecache 1\n" |
| 602 | "drop_slab 1\n" |
| 603 | "oom_kill 1\n" |
| 604 | "pgmigrate_success 3202\n" |
| 605 | "pgmigrate_fail 795\n"; |
| 606 | const char valid_input3[] = |
Lei Zhang | 912563e | 2017-07-20 16:49:58 | [diff] [blame] | 607 | "pswpin 12\n" |
| 608 | "pswpout 901\n" |
Kuo-Hsin Yang | a141f59 | 2020-09-10 07:09:33 | [diff] [blame] | 609 | "pgmajfault 18881\n"; |
Kenichi Ishibashi | 4487152 | 2017-10-23 07:12:19 | [diff] [blame] | 610 | EXPECT_TRUE(ParseProcVmstat(valid_input1, &vmstat)); |
Kuo-Hsin Yang | a141f59 | 2020-09-10 07:09:33 | [diff] [blame] | 611 | EXPECT_EQ(345219LU, vmstat.pswpin); |
| 612 | EXPECT_EQ(2605828LU, vmstat.pswpout); |
| 613 | EXPECT_EQ(358901LU, vmstat.pgmajfault); |
| 614 | EXPECT_EQ(18LU, vmstat.oom_kill); |
Kenichi Ishibashi | 4487152 | 2017-10-23 07:12:19 | [diff] [blame] | 615 | EXPECT_TRUE(ParseProcVmstat(valid_input2, &vmstat)); |
Kuo-Hsin Yang | a141f59 | 2020-09-10 07:09:33 | [diff] [blame] | 616 | EXPECT_EQ(899959LU, vmstat.pswpin); |
| 617 | EXPECT_EQ(19761244LU, vmstat.pswpout); |
| 618 | EXPECT_EQ(609626LU, vmstat.pgmajfault); |
| 619 | EXPECT_EQ(1LU, vmstat.oom_kill); |
| 620 | EXPECT_TRUE(ParseProcVmstat(valid_input3, &vmstat)); |
Kenichi Ishibashi | 4487152 | 2017-10-23 07:12:19 | [diff] [blame] | 621 | EXPECT_EQ(12LU, vmstat.pswpin); |
| 622 | EXPECT_EQ(901LU, vmstat.pswpout); |
Kuo-Hsin Yang | a141f59 | 2020-09-10 07:09:33 | [diff] [blame] | 623 | EXPECT_EQ(18881LU, vmstat.pgmajfault); |
| 624 | EXPECT_EQ(0LU, vmstat.oom_kill); |
Lei Zhang | 912563e | 2017-07-20 16:49:58 | [diff] [blame] | 625 | |
| 626 | const char missing_pgmajfault_input[] = |
| 627 | "pswpin 12\n" |
| 628 | "pswpout 901\n"; |
Kenichi Ishibashi | 4487152 | 2017-10-23 07:12:19 | [diff] [blame] | 629 | EXPECT_FALSE(ParseProcVmstat(missing_pgmajfault_input, &vmstat)); |
Lei Zhang | 912563e | 2017-07-20 16:49:58 | [diff] [blame] | 630 | const char empty_input[] = ""; |
Kenichi Ishibashi | 4487152 | 2017-10-23 07:12:19 | [diff] [blame] | 631 | EXPECT_FALSE(ParseProcVmstat(empty_input, &vmstat)); |
[email protected] | ded8c42b | 2013-11-05 22:15:03 | [diff] [blame] | 632 | } |
Xiaohan Wang | 37e8161 | 2022-01-15 18:27:00 | [diff] [blame] | 633 | #endif // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || |
| 634 | // BUILDFLAG(IS_ANDROID) |
[email protected] | 669a0933 | 2013-08-30 22:59:14 | [diff] [blame] | 635 | |
Joe Mason | f75bf18 | 2023-10-17 22:16:25 | [diff] [blame] | 636 | #if ENABLE_CPU_TESTS |
Wez | 4ae8f29 | 2017-09-11 20:52:03 | [diff] [blame] | 637 | // Test that ProcessMetrics::GetPlatformIndependentCPUUsage() doesn't return |
| 638 | // negative values when the number of threads running on the process decreases |
| 639 | // between two successive calls to it. |
afakhry | 8c03da07 | 2015-12-03 01:26:19 | [diff] [blame] | 640 | TEST_F(SystemMetricsTest, TestNoNegativeCpuUsage) { |
Joe Mason | f481218 | 2024-01-19 01:12:37 | [diff] [blame] | 641 | std::unique_ptr<ProcessMetrics> metrics = |
| 642 | ProcessMetrics::CreateCurrentProcessMetrics(); |
afakhry | 8c03da07 | 2015-12-03 01:26:19 | [diff] [blame] | 643 | |
Joe Mason | 550eed6 | 2024-03-25 18:07:31 | [diff] [blame] | 644 | EXPECT_THAT(metrics->GetPlatformIndependentCPUUsage(), ValueIs(Ge(0.0))); |
Joe Mason | c2c3f72 | 2023-10-17 19:51:17 | [diff] [blame] | 645 | |
afakhry | 8c03da07 | 2015-12-03 01:26:19 | [diff] [blame] | 646 | Thread thread1("thread1"); |
| 647 | Thread thread2("thread2"); |
| 648 | Thread thread3("thread3"); |
| 649 | |
| 650 | thread1.StartAndWaitForTesting(); |
| 651 | thread2.StartAndWaitForTesting(); |
| 652 | thread3.StartAndWaitForTesting(); |
| 653 | |
| 654 | ASSERT_TRUE(thread1.IsRunning()); |
| 655 | ASSERT_TRUE(thread2.IsRunning()); |
| 656 | ASSERT_TRUE(thread3.IsRunning()); |
| 657 | |
| 658 | std::vector<std::string> vec1; |
| 659 | std::vector<std::string> vec2; |
| 660 | std::vector<std::string> vec3; |
| 661 | |
tzik | 92b7a42 | 2017-04-11 15:00:44 | [diff] [blame] | 662 | thread1.task_runner()->PostTask(FROM_HERE, BindOnce(&BusyWork, &vec1)); |
| 663 | thread2.task_runner()->PostTask(FROM_HERE, BindOnce(&BusyWork, &vec2)); |
| 664 | thread3.task_runner()->PostTask(FROM_HERE, BindOnce(&BusyWork, &vec3)); |
afakhry | 8c03da07 | 2015-12-03 01:26:19 | [diff] [blame] | 665 | |
Joe Mason | c2c3f72 | 2023-10-17 19:51:17 | [diff] [blame] | 666 | TimeDelta prev_cpu_usage = TestCumulativeCPU(metrics.get(), TimeDelta()); |
afakhry | 8c03da07 | 2015-12-03 01:26:19 | [diff] [blame] | 667 | |
| 668 | thread1.Stop(); |
Joe Mason | c2c3f72 | 2023-10-17 19:51:17 | [diff] [blame] | 669 | prev_cpu_usage = TestCumulativeCPU(metrics.get(), prev_cpu_usage); |
afakhry | 8c03da07 | 2015-12-03 01:26:19 | [diff] [blame] | 670 | |
| 671 | thread2.Stop(); |
Joe Mason | c2c3f72 | 2023-10-17 19:51:17 | [diff] [blame] | 672 | prev_cpu_usage = TestCumulativeCPU(metrics.get(), prev_cpu_usage); |
afakhry | 8c03da07 | 2015-12-03 01:26:19 | [diff] [blame] | 673 | |
| 674 | thread3.Stop(); |
Joe Mason | c2c3f72 | 2023-10-17 19:51:17 | [diff] [blame] | 675 | prev_cpu_usage = TestCumulativeCPU(metrics.get(), prev_cpu_usage); |
afakhry | 8c03da07 | 2015-12-03 01:26:19 | [diff] [blame] | 676 | } |
Joe Mason | f481218 | 2024-01-19 01:12:37 | [diff] [blame] | 677 | |
Dave Tapuska | 828a495c | 2024-03-26 17:33:03 | [diff] [blame] | 678 | #if !BUILDFLAG(IS_APPLE) |
Joe Mason | f481218 | 2024-01-19 01:12:37 | [diff] [blame] | 679 | |
| 680 | // Subprocess to test the child CPU usage. |
| 681 | MULTIPROCESS_TEST_MAIN(CPUUsageChildMain) { |
| 682 | TestChildLauncher::NotifyParent(); |
| 683 | // Busy wait until terminated. |
| 684 | while (true) { |
| 685 | std::vector<std::string> vec; |
| 686 | BusyWork(&vec); |
| 687 | } |
| 688 | } |
| 689 | |
| 690 | TEST_F(SystemMetricsTest, MeasureChildCpuUsage) { |
| 691 | TestChildLauncher child_launcher; |
| 692 | ASSERT_TRUE(child_launcher.SpawnChildProcess("CPUUsageChildMain")); |
| 693 | std::unique_ptr<ProcessMetrics> metrics = |
| 694 | child_launcher.CreateChildProcessMetrics(); |
| 695 | |
| 696 | const TimeDelta cpu_usage1 = TestCumulativeCPU(metrics.get(), TimeDelta()); |
Joe Mason | f481218 | 2024-01-19 01:12:37 | [diff] [blame] | 697 | |
Joe Mason | c4ad7dc | 2024-05-07 17:45:57 | [diff] [blame] | 698 | // The child thread does busy work, so it should get some CPU usage. There's a |
| 699 | // small chance it won't be scheduled during the delay so loop several times. |
| 700 | const auto abort_time = |
| 701 | base::TimeTicks::Now() + TestTimeouts::action_max_timeout(); |
| 702 | TimeDelta cpu_usage2; |
| 703 | while (cpu_usage2.is_zero() && !HasFailure() && |
| 704 | base::TimeTicks::Now() < abort_time) { |
| 705 | PlatformThread::Sleep(TestTimeouts::tiny_timeout()); |
| 706 | cpu_usage2 = TestCumulativeCPU(metrics.get(), cpu_usage1); |
| 707 | } |
Joe Mason | f481218 | 2024-01-19 01:12:37 | [diff] [blame] | 708 | EXPECT_TRUE(cpu_usage2.is_positive()); |
| 709 | |
| 710 | ASSERT_TRUE(child_launcher.TerminateChildProcess()); |
| 711 | |
| 712 | #if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_FUCHSIA) |
| 713 | // Windows and Fuchsia return final measurements of a process after it exits. |
| 714 | TestCumulativeCPU(metrics.get(), cpu_usage2); |
Joe Mason | f481218 | 2024-01-19 01:12:37 | [diff] [blame] | 715 | #else |
Joe Mason | ba14528 | 2024-03-12 20:18:19 | [diff] [blame] | 716 | // All other platforms return an error. |
Joe Mason | 550eed6 | 2024-03-25 18:07:31 | [diff] [blame] | 717 | EXPECT_THAT(metrics->GetCumulativeCPUUsage(), ErrorIs(_)); |
| 718 | EXPECT_THAT(metrics->GetPlatformIndependentCPUUsage(), ErrorIs(_)); |
Joe Mason | f481218 | 2024-01-19 01:12:37 | [diff] [blame] | 719 | #endif |
| 720 | } |
| 721 | |
Dave Tapuska | 828a495c | 2024-03-26 17:33:03 | [diff] [blame] | 722 | #endif // !BUILDFLAG(IS_APPLE) |
Joe Mason | f481218 | 2024-01-19 01:12:37 | [diff] [blame] | 723 | |
Joe Mason | f481218 | 2024-01-19 01:12:37 | [diff] [blame] | 724 | TEST_F(SystemMetricsTest, InvalidProcessCpuUsage) { |
| 725 | #if BUILDFLAG(IS_MAC) |
| 726 | std::unique_ptr<ProcessMetrics> metrics = |
| 727 | ProcessMetrics::CreateProcessMetrics(kNullProcessHandle, nullptr); |
| 728 | #else |
| 729 | std::unique_ptr<ProcessMetrics> metrics = |
| 730 | ProcessMetrics::CreateProcessMetrics(kNullProcessHandle); |
| 731 | #endif |
Joe Mason | 550eed6 | 2024-03-25 18:07:31 | [diff] [blame] | 732 | EXPECT_THAT(metrics->GetCumulativeCPUUsage(), ErrorIs(_)); |
| 733 | EXPECT_THAT(metrics->GetPlatformIndependentCPUUsage(), ErrorIs(_)); |
Joe Mason | f481218 | 2024-01-19 01:12:37 | [diff] [blame] | 734 | } |
Joe Mason | f481218 | 2024-01-19 01:12:37 | [diff] [blame] | 735 | |
Joe Mason | f75bf18 | 2023-10-17 22:16:25 | [diff] [blame] | 736 | #endif // ENABLE_CPU_TESTS |
afakhry | 8c03da07 | 2015-12-03 01:26:19 | [diff] [blame] | 737 | |
Etienne Pierre-doray | 490c80f | 2024-12-05 00:30:14 | [diff] [blame] | 738 | TEST_F(SystemMetricsTest, TestValidMemoryInfo) { |
| 739 | std::unique_ptr<ProcessMetrics> metrics = |
| 740 | ProcessMetrics::CreateCurrentProcessMetrics(); |
| 741 | |
| 742 | auto memory_info = metrics->GetMemoryInfo(); |
| 743 | EXPECT_TRUE(memory_info.has_value()); |
| 744 | EXPECT_GT(memory_info->resident_set_bytes, 0U); |
| 745 | |
| 746 | #if BUILDFLAG(IS_APPLE) |
| 747 | EXPECT_GT(memory_info->physical_footprint_bytes, 0U); |
| 748 | EXPECT_GT(memory_info->internal_bytes, 0U); |
| 749 | EXPECT_GE(memory_info->compressed_bytes, 0U); |
| 750 | #endif // BUILDFLAG(IS_APPLE) |
| 751 | |
| 752 | #if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_ANDROID) || \ |
| 753 | BUILDFLAG(IS_FUCHSIA) |
| 754 | EXPECT_GT(memory_info->rss_anon_bytes, 0U); |
| 755 | EXPECT_GE(memory_info->vm_swap_bytes, 0U); |
| 756 | #endif // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || |
| 757 | // BUILDFLAG(IS_ANDROID) |
| 758 | |
| 759 | #if BUILDFLAG(IS_WIN) |
| 760 | EXPECT_GT(memory_info->private_bytes, 0U); |
| 761 | #endif // BUILDFLAG(IS_WIN) |
| 762 | } |
| 763 | |
Eric Willigers | 611cf54 | 2022-04-28 02:22:14 | [diff] [blame] | 764 | #if BUILDFLAG(IS_CHROMEOS) |
Chung-Sheng Wu | 838f843b | 2017-07-21 04:17:58 | [diff] [blame] | 765 | TEST_F(SystemMetricsTest, ParseZramMmStat) { |
| 766 | SwapInfo swapinfo; |
| 767 | |
| 768 | const char invalid_input1[] = "aaa"; |
| 769 | const char invalid_input2[] = "1 2 3 4 5 6"; |
| 770 | const char invalid_input3[] = "a 2 3 4 5 6 7"; |
| 771 | EXPECT_FALSE(ParseZramMmStat(invalid_input1, &swapinfo)); |
| 772 | EXPECT_FALSE(ParseZramMmStat(invalid_input2, &swapinfo)); |
| 773 | EXPECT_FALSE(ParseZramMmStat(invalid_input3, &swapinfo)); |
| 774 | |
| 775 | const char valid_input1[] = |
| 776 | "17715200 5008166 566062 0 1225715712 127 183842"; |
| 777 | EXPECT_TRUE(ParseZramMmStat(valid_input1, &swapinfo)); |
| 778 | EXPECT_EQ(17715200ULL, swapinfo.orig_data_size); |
| 779 | EXPECT_EQ(5008166ULL, swapinfo.compr_data_size); |
| 780 | EXPECT_EQ(566062ULL, swapinfo.mem_used_total); |
| 781 | } |
| 782 | |
| 783 | TEST_F(SystemMetricsTest, ParseZramStat) { |
| 784 | SwapInfo swapinfo; |
| 785 | |
| 786 | const char invalid_input1[] = "aaa"; |
| 787 | const char invalid_input2[] = "1 2 3 4 5 6 7 8 9 10"; |
| 788 | const char invalid_input3[] = "a 2 3 4 5 6 7 8 9 10 11"; |
| 789 | EXPECT_FALSE(ParseZramStat(invalid_input1, &swapinfo)); |
| 790 | EXPECT_FALSE(ParseZramStat(invalid_input2, &swapinfo)); |
| 791 | EXPECT_FALSE(ParseZramStat(invalid_input3, &swapinfo)); |
| 792 | |
| 793 | const char valid_input1[] = |
| 794 | "299 0 2392 0 1 0 8 0 0 0 0"; |
| 795 | EXPECT_TRUE(ParseZramStat(valid_input1, &swapinfo)); |
| 796 | EXPECT_EQ(299ULL, swapinfo.num_reads); |
| 797 | EXPECT_EQ(1ULL, swapinfo.num_writes); |
| 798 | } |
Eric Willigers | 611cf54 | 2022-04-28 02:22:14 | [diff] [blame] | 799 | #endif // BUILDFLAG(IS_CHROMEOS) |
Chung-Sheng Wu | 838f843b | 2017-07-21 04:17:58 | [diff] [blame] | 800 | |
Xiaohan Wang | 37e8161 | 2022-01-15 18:27:00 | [diff] [blame] | 801 | #if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_APPLE) || BUILDFLAG(IS_LINUX) || \ |
| 802 | BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_ANDROID) |
Sonny Rao | 81a33e8 | 2020-02-13 19:30:26 | [diff] [blame] | 803 | TEST(SystemMetrics2Test, GetSystemMemoryInfo) { |
thestig | cf4c85b | 2015-12-16 08:33:30 | [diff] [blame] | 804 | SystemMemoryInfoKB info; |
| 805 | EXPECT_TRUE(GetSystemMemoryInfo(&info)); |
[email protected] | cf46e375 | 2013-12-02 01:01:01 | [diff] [blame] | 806 | |
| 807 | // Ensure each field received a value. |
| 808 | EXPECT_GT(info.total, 0); |
Xiaohan Wang | 37e8161 | 2022-01-15 18:27:00 | [diff] [blame] | 809 | #if BUILDFLAG(IS_WIN) |
mkolom | 01ac10b | 2017-03-22 01:47:29 | [diff] [blame] | 810 | EXPECT_GT(info.avail_phys, 0); |
| 811 | #else |
[email protected] | cf46e375 | 2013-12-02 01:01:01 | [diff] [blame] | 812 | EXPECT_GT(info.free, 0); |
mkolom | 01ac10b | 2017-03-22 01:47:29 | [diff] [blame] | 813 | #endif |
Xiaohan Wang | 37e8161 | 2022-01-15 18:27:00 | [diff] [blame] | 814 | #if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_ANDROID) |
[email protected] | cf46e375 | 2013-12-02 01:01:01 | [diff] [blame] | 815 | EXPECT_GT(info.buffers, 0); |
| 816 | EXPECT_GT(info.cached, 0); |
Sonny Rao | 81a33e8 | 2020-02-13 19:30:26 | [diff] [blame] | 817 | EXPECT_GT(info.active_anon + info.inactive_anon, 0); |
| 818 | EXPECT_GT(info.active_file + info.inactive_file, 0); |
Xiaohan Wang | 37e8161 | 2022-01-15 18:27:00 | [diff] [blame] | 819 | #endif // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || |
| 820 | // BUILDFLAG(IS_ANDROID) |
[email protected] | cf46e375 | 2013-12-02 01:01:01 | [diff] [blame] | 821 | |
| 822 | // All the values should be less than the total amount of memory. |
Xiaohan Wang | 37e8161 | 2022-01-15 18:27:00 | [diff] [blame] | 823 | #if !BUILDFLAG(IS_WIN) && !BUILDFLAG(IS_IOS) |
Alison Gale | 81f4f2c7 | 2024-04-22 19:33:31 | [diff] [blame] | 824 | // TODO(crbug.com/40515565): re-enable the following assertion on iOS. |
[email protected] | cf46e375 | 2013-12-02 01:01:01 | [diff] [blame] | 825 | EXPECT_LT(info.free, info.total); |
mkolom | 01ac10b | 2017-03-22 01:47:29 | [diff] [blame] | 826 | #endif |
Xiaohan Wang | 37e8161 | 2022-01-15 18:27:00 | [diff] [blame] | 827 | #if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_ANDROID) |
[email protected] | cf46e375 | 2013-12-02 01:01:01 | [diff] [blame] | 828 | EXPECT_LT(info.buffers, info.total); |
| 829 | EXPECT_LT(info.cached, info.total); |
| 830 | EXPECT_LT(info.active_anon, info.total); |
| 831 | EXPECT_LT(info.inactive_anon, info.total); |
| 832 | EXPECT_LT(info.active_file, info.total); |
| 833 | EXPECT_LT(info.inactive_file, info.total); |
Xiaohan Wang | 37e8161 | 2022-01-15 18:27:00 | [diff] [blame] | 834 | #endif // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || |
| 835 | // BUILDFLAG(IS_ANDROID) |
[email protected] | cf46e375 | 2013-12-02 01:01:01 | [diff] [blame] | 836 | |
Xiaohan Wang | 37e8161 | 2022-01-15 18:27:00 | [diff] [blame] | 837 | #if BUILDFLAG(IS_APPLE) |
mkolom | 01ac10b | 2017-03-22 01:47:29 | [diff] [blame] | 838 | EXPECT_GT(info.file_backed, 0); |
| 839 | #endif |
| 840 | |
Eric Willigers | 611cf54 | 2022-04-28 02:22:14 | [diff] [blame] | 841 | #if BUILDFLAG(IS_CHROMEOS) |
[email protected] | cf46e375 | 2013-12-02 01:01:01 | [diff] [blame] | 842 | // Chrome OS exposes shmem. |
| 843 | EXPECT_GT(info.shmem, 0); |
| 844 | EXPECT_LT(info.shmem, info.total); |
[email protected] | cf46e375 | 2013-12-02 01:01:01 | [diff] [blame] | 845 | #endif |
| 846 | } |
Xiaohan Wang | 37e8161 | 2022-01-15 18:27:00 | [diff] [blame] | 847 | #endif // BUILDFLAG(IS_WIN) || BUILDFLAG(IS_APPLE) || BUILDFLAG(IS_LINUX) || |
| 848 | // BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_ANDROID) |
[email protected] | cf46e375 | 2013-12-02 01:01:01 | [diff] [blame] | 849 | |
Xiaohan Wang | 37e8161 | 2022-01-15 18:27:00 | [diff] [blame] | 850 | #if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_ANDROID) |
[email protected] | cf46e375 | 2013-12-02 01:01:01 | [diff] [blame] | 851 | TEST(ProcessMetricsTest, ParseProcStatCPU) { |
| 852 | // /proc/self/stat for a process running "top". |
Joe Mason | f75bf18 | 2023-10-17 22:16:25 | [diff] [blame] | 853 | const char kTopStat[] = |
| 854 | "960 (top) S 16230 960 16230 34818 960 " |
[email protected] | cf46e375 | 2013-12-02 01:01:01 | [diff] [blame] | 855 | "4202496 471 0 0 0 " |
| 856 | "12 16 0 0 " // <- These are the goods. |
| 857 | "20 0 1 0 121946157 15077376 314 18446744073709551615 4194304 " |
| 858 | "4246868 140733983044336 18446744073709551615 140244213071219 " |
| 859 | "0 0 0 138047495 0 0 0 17 1 0 0 0 0 0"; |
thestig | cf4c85b | 2015-12-16 08:33:30 | [diff] [blame] | 860 | EXPECT_EQ(12 + 16, ParseProcStatCPU(kTopStat)); |
[email protected] | cf46e375 | 2013-12-02 01:01:01 | [diff] [blame] | 861 | |
| 862 | // cat /proc/self/stat on a random other machine I have. |
Joe Mason | f75bf18 | 2023-10-17 22:16:25 | [diff] [blame] | 863 | const char kSelfStat[] = |
| 864 | "5364 (cat) R 5354 5364 5354 34819 5364 " |
[email protected] | cf46e375 | 2013-12-02 01:01:01 | [diff] [blame] | 865 | "0 142 0 0 0 " |
| 866 | "0 0 0 0 " // <- No CPU, apparently. |
| 867 | "16 0 1 0 1676099790 2957312 114 4294967295 134512640 134528148 " |
| 868 | "3221224832 3221224344 3086339742 0 0 0 0 0 0 0 17 0 0 0"; |
| 869 | |
thestig | cf4c85b | 2015-12-16 08:33:30 | [diff] [blame] | 870 | EXPECT_EQ(0, ParseProcStatCPU(kSelfStat)); |
afakhry | 597a851 | 2015-02-05 00:51:57 | [diff] [blame] | 871 | |
| 872 | // Some weird long-running process with a weird name that I created for the |
| 873 | // purposes of this test. |
Joe Mason | f75bf18 | 2023-10-17 22:16:25 | [diff] [blame] | 874 | const char kWeirdNameStat[] = |
| 875 | "26115 (Hello) You ())) ) R 24614 26115 24614" |
afakhry | 597a851 | 2015-02-05 00:51:57 | [diff] [blame] | 876 | " 34839 26115 4218880 227 0 0 0 " |
| 877 | "5186 11 0 0 " |
| 878 | "20 0 1 0 36933953 4296704 90 18446744073709551615 4194304 4196116 " |
| 879 | "140735857761568 140735857761160 4195644 0 0 0 0 0 0 0 17 14 0 0 0 0 0 " |
| 880 | "6295056 6295616 16519168 140735857770710 140735857770737 " |
| 881 | "140735857770737 140735857774557 0"; |
thestig | cf4c85b | 2015-12-16 08:33:30 | [diff] [blame] | 882 | EXPECT_EQ(5186 + 11, ParseProcStatCPU(kWeirdNameStat)); |
[email protected] | cf46e375 | 2013-12-02 01:01:01 | [diff] [blame] | 883 | } |
Xiaohan Wang | 37e8161 | 2022-01-15 18:27:00 | [diff] [blame] | 884 | #endif // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || |
| 885 | // BUILDFLAG(IS_ANDROID) |
[email protected] | cf46e375 | 2013-12-02 01:01:01 | [diff] [blame] | 886 | |
| 887 | // Disable on Android because base_unittests runs inside a Dalvik VM that |
| 888 | // starts and stop threads (crbug.com/175563). |
Xiaohan Wang | 37e8161 | 2022-01-15 18:27:00 | [diff] [blame] | 889 | #if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) |
[email protected] | 9792d38 | 2014-08-11 16:12:37 | [diff] [blame] | 890 | // http://crbug.com/396455 |
| 891 | TEST(ProcessMetricsTest, DISABLED_GetNumberOfThreads) { |
thestig | cf4c85b | 2015-12-16 08:33:30 | [diff] [blame] | 892 | const ProcessHandle current = GetCurrentProcessHandle(); |
Peter Kasting | 25acd594 | 2022-07-07 17:45:15 | [diff] [blame] | 893 | const int64_t initial_threads = GetNumberOfThreads(current); |
[email protected] | cf46e375 | 2013-12-02 01:01:01 | [diff] [blame] | 894 | ASSERT_GT(initial_threads, 0); |
| 895 | const int kNumAdditionalThreads = 10; |
| 896 | { |
Arthur Sonzogni | 0844a99 | 2024-12-12 11:36:20 | [diff] [blame] | 897 | std::array<std::unique_ptr<Thread>, kNumAdditionalThreads> my_threads; |
[email protected] | cf46e375 | 2013-12-02 01:01:01 | [diff] [blame] | 898 | for (int i = 0; i < kNumAdditionalThreads; ++i) { |
Peter Boström | 6b70182 | 2021-04-15 03:53:08 | [diff] [blame] | 899 | my_threads[i] = std::make_unique<Thread>("GetNumberOfThreadsTest"); |
[email protected] | cf46e375 | 2013-12-02 01:01:01 | [diff] [blame] | 900 | my_threads[i]->Start(); |
thestig | cf4c85b | 2015-12-16 08:33:30 | [diff] [blame] | 901 | ASSERT_EQ(GetNumberOfThreads(current), initial_threads + 1 + i); |
[email protected] | cf46e375 | 2013-12-02 01:01:01 | [diff] [blame] | 902 | } |
| 903 | } |
| 904 | // The Thread destructor will stop them. |
thestig | cf4c85b | 2015-12-16 08:33:30 | [diff] [blame] | 905 | ASSERT_EQ(initial_threads, GetNumberOfThreads(current)); |
| 906 | } |
Xiaohan Wang | 37e8161 | 2022-01-15 18:27:00 | [diff] [blame] | 907 | #endif // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) |
thestig | cf4c85b | 2015-12-16 08:33:30 | [diff] [blame] | 908 | |
Dave Tapuska | 828a495c | 2024-03-26 17:33:03 | [diff] [blame] | 909 | #if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_MAC) |
thestig | cf4c85b | 2015-12-16 08:33:30 | [diff] [blame] | 910 | namespace { |
| 911 | |
Siddhartha | 5293d8a | 2017-12-21 01:09:54 | [diff] [blame] | 912 | // Keep these in sync so the GetChildOpenFdCount test can refer to correct test |
| 913 | // main. |
thestig | cf4c85b | 2015-12-16 08:33:30 | [diff] [blame] | 914 | #define ChildMain ChildFdCount |
| 915 | #define ChildMainString "ChildFdCount" |
| 916 | |
| 917 | // Command line flag name and file name used for synchronization. |
| 918 | const char kTempDirFlag[] = "temp-dir"; |
Robert Sesek | 3aff336 | 2019-01-23 20:16:16 | [diff] [blame] | 919 | |
| 920 | const char kSignalReady[] = "ready"; |
| 921 | const char kSignalReadyAck[] = "ready-ack"; |
| 922 | const char kSignalOpened[] = "opened"; |
| 923 | const char kSignalOpenedAck[] = "opened-ack"; |
thestig | cf4c85b | 2015-12-16 08:33:30 | [diff] [blame] | 924 | const char kSignalClosed[] = "closed"; |
| 925 | |
Robert Sesek | 3aff336 | 2019-01-23 20:16:16 | [diff] [blame] | 926 | const int kChildNumFilesToOpen = 100; |
| 927 | |
thestig | cf4c85b | 2015-12-16 08:33:30 | [diff] [blame] | 928 | bool SignalEvent(const FilePath& signal_dir, const char* signal_file) { |
| 929 | File file(signal_dir.AppendASCII(signal_file), |
| 930 | File::FLAG_CREATE | File::FLAG_WRITE); |
| 931 | return file.IsValid(); |
| 932 | } |
| 933 | |
| 934 | // Check whether an event was signaled. |
| 935 | bool CheckEvent(const FilePath& signal_dir, const char* signal_file) { |
| 936 | File file(signal_dir.AppendASCII(signal_file), |
| 937 | File::FLAG_OPEN | File::FLAG_READ); |
| 938 | return file.IsValid(); |
| 939 | } |
| 940 | |
| 941 | // Busy-wait for an event to be signaled. |
| 942 | void WaitForEvent(const FilePath& signal_dir, const char* signal_file) { |
Joe Mason | f75bf18 | 2023-10-17 22:16:25 | [diff] [blame] | 943 | while (!CheckEvent(signal_dir, signal_file)) { |
Peter Kasting | 53fd6ee | 2021-10-05 20:40:48 | [diff] [blame] | 944 | PlatformThread::Sleep(Milliseconds(10)); |
Joe Mason | f75bf18 | 2023-10-17 22:16:25 | [diff] [blame] | 945 | } |
thestig | cf4c85b | 2015-12-16 08:33:30 | [diff] [blame] | 946 | } |
| 947 | |
| 948 | // Subprocess to test the number of open file descriptors. |
| 949 | MULTIPROCESS_TEST_MAIN(ChildMain) { |
Joe Mason | f481218 | 2024-01-19 01:12:37 | [diff] [blame] | 950 | TestChildLauncher::NotifyParent(); |
| 951 | |
thestig | cf4c85b | 2015-12-16 08:33:30 | [diff] [blame] | 952 | CommandLine* command_line = CommandLine::ForCurrentProcess(); |
| 953 | const FilePath temp_path = command_line->GetSwitchValuePath(kTempDirFlag); |
| 954 | CHECK(DirectoryExists(temp_path)); |
| 955 | |
Robert Sesek | 3aff336 | 2019-01-23 20:16:16 | [diff] [blame] | 956 | CHECK(SignalEvent(temp_path, kSignalReady)); |
| 957 | WaitForEvent(temp_path, kSignalReadyAck); |
| 958 | |
| 959 | std::vector<File> files; |
| 960 | for (int i = 0; i < kChildNumFilesToOpen; ++i) { |
| 961 | files.emplace_back(temp_path.AppendASCII(StringPrintf("file.%d", i)), |
| 962 | File::FLAG_CREATE | File::FLAG_WRITE); |
| 963 | } |
| 964 | |
| 965 | CHECK(SignalEvent(temp_path, kSignalOpened)); |
| 966 | WaitForEvent(temp_path, kSignalOpenedAck); |
| 967 | |
| 968 | files.clear(); |
| 969 | |
thestig | cf4c85b | 2015-12-16 08:33:30 | [diff] [blame] | 970 | CHECK(SignalEvent(temp_path, kSignalClosed)); |
| 971 | |
| 972 | // Wait to be terminated. |
Joe Mason | f75bf18 | 2023-10-17 22:16:25 | [diff] [blame] | 973 | while (true) { |
Peter Kasting | 53fd6ee | 2021-10-05 20:40:48 | [diff] [blame] | 974 | PlatformThread::Sleep(Seconds(1)); |
Joe Mason | f75bf18 | 2023-10-17 22:16:25 | [diff] [blame] | 975 | } |
thestig | cf4c85b | 2015-12-16 08:33:30 | [diff] [blame] | 976 | } |
| 977 | |
| 978 | } // namespace |
| 979 | |
Siddhartha | 5293d8a | 2017-12-21 01:09:54 | [diff] [blame] | 980 | TEST(ProcessMetricsTest, GetChildOpenFdCount) { |
thestig | cf4c85b | 2015-12-16 08:33:30 | [diff] [blame] | 981 | ScopedTempDir temp_dir; |
| 982 | ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); |
vabr | 411f4fc | 2016-09-08 09:26:27 | [diff] [blame] | 983 | const FilePath temp_path = temp_dir.GetPath(); |
Joe Mason | f481218 | 2024-01-19 01:12:37 | [diff] [blame] | 984 | |
| 985 | TestChildLauncher child_launcher; |
| 986 | child_launcher.command_line().AppendSwitchPath(kTempDirFlag, temp_path); |
| 987 | ASSERT_TRUE(child_launcher.SpawnChildProcess(ChildMainString)); |
Robert Sesek | 3aff336 | 2019-01-23 20:16:16 | [diff] [blame] | 988 | |
| 989 | WaitForEvent(temp_path, kSignalReady); |
| 990 | |
| 991 | std::unique_ptr<ProcessMetrics> metrics = |
Joe Mason | f481218 | 2024-01-19 01:12:37 | [diff] [blame] | 992 | child_launcher.CreateChildProcessMetrics(); |
Robert Sesek | 3aff336 | 2019-01-23 20:16:16 | [diff] [blame] | 993 | |
| 994 | const int fd_count = metrics->GetOpenFdCount(); |
| 995 | EXPECT_GE(fd_count, 0); |
| 996 | |
| 997 | ASSERT_TRUE(SignalEvent(temp_path, kSignalReadyAck)); |
| 998 | WaitForEvent(temp_path, kSignalOpened); |
| 999 | |
| 1000 | EXPECT_EQ(fd_count + kChildNumFilesToOpen, metrics->GetOpenFdCount()); |
| 1001 | ASSERT_TRUE(SignalEvent(temp_path, kSignalOpenedAck)); |
| 1002 | |
thestig | cf4c85b | 2015-12-16 08:33:30 | [diff] [blame] | 1003 | WaitForEvent(temp_path, kSignalClosed); |
| 1004 | |
Robert Sesek | 3aff336 | 2019-01-23 20:16:16 | [diff] [blame] | 1005 | EXPECT_EQ(fd_count, metrics->GetOpenFdCount()); |
| 1006 | |
Joe Mason | f481218 | 2024-01-19 01:12:37 | [diff] [blame] | 1007 | ASSERT_TRUE(child_launcher.TerminateChildProcess()); |
[email protected] | cf46e375 | 2013-12-02 01:01:01 | [diff] [blame] | 1008 | } |
Siddhartha | 5293d8a | 2017-12-21 01:09:54 | [diff] [blame] | 1009 | |
| 1010 | TEST(ProcessMetricsTest, GetOpenFdCount) { |
Joe Mason | f481218 | 2024-01-19 01:12:37 | [diff] [blame] | 1011 | std::unique_ptr<ProcessMetrics> metrics = |
| 1012 | ProcessMetrics::CreateCurrentProcessMetrics(); |
Robert Sesek | 3aff336 | 2019-01-23 20:16:16 | [diff] [blame] | 1013 | |
| 1014 | ScopedTempDir temp_dir; |
| 1015 | ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); |
| 1016 | |
Siddhartha | 5293d8a | 2017-12-21 01:09:54 | [diff] [blame] | 1017 | int fd_count = metrics->GetOpenFdCount(); |
| 1018 | EXPECT_GT(fd_count, 0); |
Robert Sesek | 3aff336 | 2019-01-23 20:16:16 | [diff] [blame] | 1019 | File file(temp_dir.GetPath().AppendASCII("file"), |
| 1020 | File::FLAG_CREATE | File::FLAG_WRITE); |
Siddhartha | 5293d8a | 2017-12-21 01:09:54 | [diff] [blame] | 1021 | int new_fd_count = metrics->GetOpenFdCount(); |
| 1022 | EXPECT_GT(new_fd_count, 0); |
| 1023 | EXPECT_EQ(new_fd_count, fd_count + 1); |
| 1024 | } |
Dave Tapuska | 828a495c | 2024-03-26 17:33:03 | [diff] [blame] | 1025 | #endif // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_MAC) |
Robert Sesek | 3aff336 | 2019-01-23 20:16:16 | [diff] [blame] | 1026 | |
Xiaohan Wang | 37e8161 | 2022-01-15 18:27:00 | [diff] [blame] | 1027 | #if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) |
Eric Seckler | 9db2139 | 2020-06-12 08:48:19 | [diff] [blame] | 1028 | |
Benoit Lize | 448ee88 | 2017-08-31 13:32:12 | [diff] [blame] | 1029 | TEST(ProcessMetricsTestLinux, GetPageFaultCounts) { |
Joe Mason | f481218 | 2024-01-19 01:12:37 | [diff] [blame] | 1030 | std::unique_ptr<ProcessMetrics> process_metrics = |
| 1031 | ProcessMetrics::CreateCurrentProcessMetrics(); |
Benoit Lize | 448ee88 | 2017-08-31 13:32:12 | [diff] [blame] | 1032 | |
| 1033 | PageFaultCounts counts; |
| 1034 | ASSERT_TRUE(process_metrics->GetPageFaultCounts(&counts)); |
| 1035 | ASSERT_GT(counts.minor, 0); |
| 1036 | ASSERT_GE(counts.major, 0); |
| 1037 | |
arthursonzogni | 38d9bf47 | 2019-04-15 13:00:11 | [diff] [blame] | 1038 | // Allocate and touch memory. Touching it is required to make sure that the |
| 1039 | // page fault count goes up, as memory is typically mapped lazily. |
Benoit Lize | 448ee88 | 2017-08-31 13:32:12 | [diff] [blame] | 1040 | { |
arthursonzogni | 38d9bf47 | 2019-04-15 13:00:11 | [diff] [blame] | 1041 | const size_t kMappedSize = 4 << 20; // 4 MiB. |
| 1042 | |
| 1043 | WritableSharedMemoryRegion region = |
| 1044 | WritableSharedMemoryRegion::Create(kMappedSize); |
| 1045 | ASSERT_TRUE(region.IsValid()); |
| 1046 | |
| 1047 | WritableSharedMemoryMapping mapping = region.Map(); |
| 1048 | ASSERT_TRUE(mapping.IsValid()); |
| 1049 | |
| 1050 | memset(mapping.memory(), 42, kMappedSize); |
Benoit Lize | 448ee88 | 2017-08-31 13:32:12 | [diff] [blame] | 1051 | } |
| 1052 | |
| 1053 | PageFaultCounts counts_after; |
| 1054 | ASSERT_TRUE(process_metrics->GetPageFaultCounts(&counts_after)); |
| 1055 | ASSERT_GT(counts_after.minor, counts.minor); |
| 1056 | ASSERT_GE(counts_after.major, counts.major); |
| 1057 | } |
Eric Seckler | 9db2139 | 2020-06-12 08:48:19 | [diff] [blame] | 1058 | |
| 1059 | TEST(ProcessMetricsTestLinux, GetCumulativeCPUUsagePerThread) { |
Joe Mason | f481218 | 2024-01-19 01:12:37 | [diff] [blame] | 1060 | std::unique_ptr<ProcessMetrics> metrics = |
| 1061 | ProcessMetrics::CreateCurrentProcessMetrics(); |
Eric Seckler | 9db2139 | 2020-06-12 08:48:19 | [diff] [blame] | 1062 | |
| 1063 | Thread thread1("thread1"); |
| 1064 | thread1.StartAndWaitForTesting(); |
| 1065 | ASSERT_TRUE(thread1.IsRunning()); |
| 1066 | |
| 1067 | std::vector<std::string> vec1; |
| 1068 | thread1.task_runner()->PostTask(FROM_HERE, BindOnce(&BusyWork, &vec1)); |
| 1069 | |
| 1070 | ProcessMetrics::CPUUsagePerThread prev_thread_times; |
| 1071 | EXPECT_TRUE(metrics->GetCumulativeCPUUsagePerThread(prev_thread_times)); |
| 1072 | |
| 1073 | // Should have at least the test runner thread and the thread spawned above. |
| 1074 | EXPECT_GE(prev_thread_times.size(), 2u); |
Peter Kasting | 025a9425 | 2025-01-29 21:28:37 | [diff] [blame] | 1075 | EXPECT_TRUE(std::ranges::any_of( |
Anton Bikineev | a61fb57 | 2020-10-18 08:54:44 | [diff] [blame] | 1076 | prev_thread_times, |
Eric Seckler | 9db2139 | 2020-06-12 08:48:19 | [diff] [blame] | 1077 | [&thread1](const std::pair<PlatformThreadId, base::TimeDelta>& entry) { |
| 1078 | return entry.first == thread1.GetThreadId(); |
| 1079 | })); |
Peter Kasting | 025a9425 | 2025-01-29 21:28:37 | [diff] [blame] | 1080 | EXPECT_TRUE(std::ranges::any_of( |
Anton Bikineev | a61fb57 | 2020-10-18 08:54:44 | [diff] [blame] | 1081 | prev_thread_times, |
Eric Seckler | 9db2139 | 2020-06-12 08:48:19 | [diff] [blame] | 1082 | [](const std::pair<PlatformThreadId, base::TimeDelta>& entry) { |
| 1083 | return entry.first == base::PlatformThread::CurrentId(); |
| 1084 | })); |
| 1085 | |
| 1086 | for (const auto& entry : prev_thread_times) { |
| 1087 | EXPECT_GE(entry.second, base::TimeDelta()); |
| 1088 | } |
| 1089 | |
| 1090 | thread1.Stop(); |
| 1091 | |
| 1092 | ProcessMetrics::CPUUsagePerThread current_thread_times; |
| 1093 | EXPECT_TRUE(metrics->GetCumulativeCPUUsagePerThread(current_thread_times)); |
| 1094 | |
| 1095 | // The stopped thread may still be reported until the kernel cleans it up. |
| 1096 | EXPECT_GE(prev_thread_times.size(), 1u); |
Peter Kasting | 025a9425 | 2025-01-29 21:28:37 | [diff] [blame] | 1097 | EXPECT_TRUE(std::ranges::any_of( |
Anton Bikineev | a61fb57 | 2020-10-18 08:54:44 | [diff] [blame] | 1098 | current_thread_times, |
Eric Seckler | 9db2139 | 2020-06-12 08:48:19 | [diff] [blame] | 1099 | [](const std::pair<PlatformThreadId, base::TimeDelta>& entry) { |
| 1100 | return entry.first == base::PlatformThread::CurrentId(); |
| 1101 | })); |
| 1102 | |
| 1103 | // Reported times should not decrease. |
| 1104 | for (const auto& entry : current_thread_times) { |
Peter Kasting | 025a9425 | 2025-01-29 21:28:37 | [diff] [blame] | 1105 | auto prev_it = std::ranges::find_if( |
Anton Bikineev | a61fb57 | 2020-10-18 08:54:44 | [diff] [blame] | 1106 | prev_thread_times, |
Eric Seckler | 9db2139 | 2020-06-12 08:48:19 | [diff] [blame] | 1107 | [&entry]( |
| 1108 | const std::pair<PlatformThreadId, base::TimeDelta>& prev_entry) { |
| 1109 | return entry.first == prev_entry.first; |
| 1110 | }); |
| 1111 | |
Joe Mason | f75bf18 | 2023-10-17 22:16:25 | [diff] [blame] | 1112 | if (prev_it != prev_thread_times.end()) { |
Eric Seckler | 9db2139 | 2020-06-12 08:48:19 | [diff] [blame] | 1113 | EXPECT_GE(entry.second, prev_it->second); |
Joe Mason | f75bf18 | 2023-10-17 22:16:25 | [diff] [blame] | 1114 | } |
Eric Seckler | 9db2139 | 2020-06-12 08:48:19 | [diff] [blame] | 1115 | } |
| 1116 | } |
Xiaohan Wang | 37e8161 | 2022-01-15 18:27:00 | [diff] [blame] | 1117 | #endif // BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_LINUX) || |
| 1118 | // BUILDFLAG(IS_CHROMEOS) |
Benoit Lize | 448ee88 | 2017-08-31 13:32:12 | [diff] [blame] | 1119 | |
Joe Mason | f75bf18 | 2023-10-17 22:16:25 | [diff] [blame] | 1120 | } // namespace base::debug |