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