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