• 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 #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 <vector>
14 
15 #include "base/command_line.h"
16 #include "base/files/file.h"
17 #include "base/files/file_util.h"
18 #include "base/files/scoped_temp_dir.h"
19 #include "base/functional/bind.h"
20 #include "base/memory/shared_memory_mapping.h"
21 #include "base/memory/writable_shared_memory_region.h"
22 #include "base/ranges/algorithm.h"
23 #include "base/strings/string_number_conversions.h"
24 #include "base/strings/string_util.h"
25 #include "base/strings/stringprintf.h"
26 #include "base/system/sys_info.h"
27 #include "base/test/multiprocess_test.h"
28 #include "base/threading/thread.h"
29 #include "build/build_config.h"
30 #include "build/chromeos_buildflags.h"
31 #include "testing/gtest/include/gtest/gtest.h"
32 #include "testing/multiprocess_func_list.h"
33 
34 #if BUILDFLAG(IS_APPLE)
35 #include <sys/mman.h>
36 #endif
37 
38 #if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_ANDROID)
39 #include "base/process/internal_linux.h"
40 #endif
41 
42 #if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) ||      \
43     BUILDFLAG(IS_CHROMEOS_LACROS) || BUILDFLAG(IS_WIN) || \
44     BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_FUCHSIA) || BUILDFLAG(IS_APPLE)
45 #define ENABLE_CPU_TESTS 1
46 #else
47 #define ENABLE_CPU_TESTS 0
48 #endif
49 
50 namespace base::debug {
51 
52 namespace {
53 
54 #if ENABLE_CPU_TESTS
55 
BusyWork(std::vector<std::string> * vec)56 void BusyWork(std::vector<std::string>* vec) {
57   int64_t test_value = 0;
58   for (int i = 0; i < 100000; ++i) {
59     ++test_value;
60     vec->push_back(NumberToString(test_value));
61   }
62 }
63 
TestCumulativeCPU(ProcessMetrics * metrics,TimeDelta prev_cpu_usage)64 TimeDelta TestCumulativeCPU(ProcessMetrics* metrics, TimeDelta prev_cpu_usage) {
65   const TimeDelta current_cpu_usage = metrics->GetCumulativeCPUUsage();
66   EXPECT_GE(current_cpu_usage, prev_cpu_usage);
67   EXPECT_GE(metrics->GetPlatformIndependentCPUUsage(), 0.0);
68   return current_cpu_usage;
69 }
70 
TestPreciseCumulativeCPU(ProcessMetrics * metrics,TimeDelta prev_cpu_usage)71 TimeDelta TestPreciseCumulativeCPU(ProcessMetrics* metrics,
72                                    TimeDelta prev_cpu_usage) {
73 #if BUILDFLAG(IS_WIN)
74   const TimeDelta current_cpu_usage = metrics->GetPreciseCumulativeCPUUsage();
75   EXPECT_GE(current_cpu_usage, prev_cpu_usage);
76   EXPECT_GE(metrics->GetPreciseCPUUsage(), 0.0);
77   return current_cpu_usage;
78 #else
79   // Do nothing. Not supported on this platform.
80   return base::TimeDelta();
81 #endif
82 }
83 
84 #endif  // ENABLE_CPU_TESTS
85 
CreateProcessMetricsForTest(ProcessHandle handle)86 std::unique_ptr<ProcessMetrics> CreateProcessMetricsForTest(
87     ProcessHandle handle) {
88 #if BUILDFLAG(IS_MAC)
89   return ProcessMetrics::CreateProcessMetrics(handle, nullptr);
90 #else
91   return ProcessMetrics::CreateProcessMetrics(handle);
92 #endif
93 }
94 
95 }  // namespace
96 
97 // Tests for SystemMetrics.
98 // Exists as a class so it can be a friend of SystemMetrics.
99 class SystemMetricsTest : public testing::Test {
100  public:
101   SystemMetricsTest() = default;
102 
103   SystemMetricsTest(const SystemMetricsTest&) = delete;
104   SystemMetricsTest& operator=(const SystemMetricsTest&) = delete;
105 };
106 
107 #if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_ANDROID)
TEST_F(SystemMetricsTest,IsValidDiskName)108 TEST_F(SystemMetricsTest, IsValidDiskName) {
109   const char invalid_input1[] = "";
110   const char invalid_input2[] = "s";
111   const char invalid_input3[] = "sdz+";
112   const char invalid_input4[] = "hda0";
113   const char invalid_input5[] = "mmcbl";
114   const char invalid_input6[] = "mmcblka";
115   const char invalid_input7[] = "mmcblkb";
116   const char invalid_input8[] = "mmmblk0";
117 
118   EXPECT_FALSE(IsValidDiskName(invalid_input1));
119   EXPECT_FALSE(IsValidDiskName(invalid_input2));
120   EXPECT_FALSE(IsValidDiskName(invalid_input3));
121   EXPECT_FALSE(IsValidDiskName(invalid_input4));
122   EXPECT_FALSE(IsValidDiskName(invalid_input5));
123   EXPECT_FALSE(IsValidDiskName(invalid_input6));
124   EXPECT_FALSE(IsValidDiskName(invalid_input7));
125   EXPECT_FALSE(IsValidDiskName(invalid_input8));
126 
127   const char valid_input1[] = "sda";
128   const char valid_input2[] = "sdaaaa";
129   const char valid_input3[] = "hdz";
130   const char valid_input4[] = "mmcblk0";
131   const char valid_input5[] = "mmcblk999";
132 
133   EXPECT_TRUE(IsValidDiskName(valid_input1));
134   EXPECT_TRUE(IsValidDiskName(valid_input2));
135   EXPECT_TRUE(IsValidDiskName(valid_input3));
136   EXPECT_TRUE(IsValidDiskName(valid_input4));
137   EXPECT_TRUE(IsValidDiskName(valid_input5));
138 }
139 
TEST_F(SystemMetricsTest,ParseMeminfo)140 TEST_F(SystemMetricsTest, ParseMeminfo) {
141   SystemMemoryInfoKB meminfo;
142   const char invalid_input1[] = "abc";
143   const char invalid_input2[] = "MemTotal:";
144   // Partial file with no MemTotal
145   const char invalid_input3[] =
146       "MemFree:         3913968 kB\n"
147       "Buffers:         2348340 kB\n"
148       "Cached:         49071596 kB\n"
149       "SwapCached:           12 kB\n"
150       "Active:         36393900 kB\n"
151       "Inactive:       21221496 kB\n"
152       "Active(anon):    5674352 kB\n"
153       "Inactive(anon):   633992 kB\n";
154   EXPECT_FALSE(ParseProcMeminfo(invalid_input1, &meminfo));
155   EXPECT_FALSE(ParseProcMeminfo(invalid_input2, &meminfo));
156   EXPECT_FALSE(ParseProcMeminfo(invalid_input3, &meminfo));
157 
158   const char valid_input1[] =
159       "MemTotal:        3981504 kB\n"
160       "MemFree:          140764 kB\n"
161       "MemAvailable:     535413 kB\n"
162       "Buffers:          116480 kB\n"
163       "Cached:           406160 kB\n"
164       "SwapCached:        21304 kB\n"
165       "Active:          3152040 kB\n"
166       "Inactive:         472856 kB\n"
167       "Active(anon):    2972352 kB\n"
168       "Inactive(anon):   270108 kB\n"
169       "Active(file):     179688 kB\n"
170       "Inactive(file):   202748 kB\n"
171       "Unevictable:           0 kB\n"
172       "Mlocked:               0 kB\n"
173       "SwapTotal:       5832280 kB\n"
174       "SwapFree:        3672368 kB\n"
175       "Dirty:               184 kB\n"
176       "Writeback:             0 kB\n"
177       "AnonPages:       3101224 kB\n"
178       "Mapped:           142296 kB\n"
179       "Shmem:            140204 kB\n"
180       "Slab:              54212 kB\n"
181       "SReclaimable:      30936 kB\n"
182       "SUnreclaim:        23276 kB\n"
183       "KernelStack:        2464 kB\n"
184       "PageTables:        24812 kB\n"
185       "NFS_Unstable:          0 kB\n"
186       "Bounce:                0 kB\n"
187       "WritebackTmp:          0 kB\n"
188       "CommitLimit:     7823032 kB\n"
189       "Committed_AS:    7973536 kB\n"
190       "VmallocTotal:   34359738367 kB\n"
191       "VmallocUsed:      375940 kB\n"
192       "VmallocChunk:   34359361127 kB\n"
193       "DirectMap4k:       72448 kB\n"
194       "DirectMap2M:     4061184 kB\n";
195   // output from a much older kernel where the Active and Inactive aren't
196   // broken down into anon and file and Huge Pages are enabled
197   const char valid_input2[] =
198       "MemTotal:       255908 kB\n"
199       "MemFree:         69936 kB\n"
200       "Buffers:         15812 kB\n"
201       "Cached:         115124 kB\n"
202       "SwapCached:          0 kB\n"
203       "Active:          92700 kB\n"
204       "Inactive:        63792 kB\n"
205       "HighTotal:           0 kB\n"
206       "HighFree:            0 kB\n"
207       "LowTotal:       255908 kB\n"
208       "LowFree:         69936 kB\n"
209       "SwapTotal:      524280 kB\n"
210       "SwapFree:       524200 kB\n"
211       "Dirty:               4 kB\n"
212       "Writeback:           0 kB\n"
213       "Mapped:          42236 kB\n"
214       "Slab:            25912 kB\n"
215       "Committed_AS:   118680 kB\n"
216       "PageTables:       1236 kB\n"
217       "VmallocTotal:  3874808 kB\n"
218       "VmallocUsed:      1416 kB\n"
219       "VmallocChunk:  3872908 kB\n"
220       "HugePages_Total:     0\n"
221       "HugePages_Free:      0\n"
222       "Hugepagesize:     4096 kB\n";
223 
224   EXPECT_TRUE(ParseProcMeminfo(valid_input1, &meminfo));
225   EXPECT_EQ(meminfo.total, 3981504);
226   EXPECT_EQ(meminfo.free, 140764);
227   EXPECT_EQ(meminfo.available, 535413);
228   EXPECT_EQ(meminfo.buffers, 116480);
229   EXPECT_EQ(meminfo.cached, 406160);
230   EXPECT_EQ(meminfo.active_anon, 2972352);
231   EXPECT_EQ(meminfo.active_file, 179688);
232   EXPECT_EQ(meminfo.inactive_anon, 270108);
233   EXPECT_EQ(meminfo.inactive_file, 202748);
234   EXPECT_EQ(meminfo.swap_total, 5832280);
235   EXPECT_EQ(meminfo.swap_free, 3672368);
236   EXPECT_EQ(meminfo.dirty, 184);
237   EXPECT_EQ(meminfo.reclaimable, 30936);
238 #if BUILDFLAG(IS_CHROMEOS)
239   EXPECT_EQ(meminfo.shmem, 140204);
240   EXPECT_EQ(meminfo.slab, 54212);
241 #endif
242   EXPECT_EQ(355725u,
243             base::SysInfo::AmountOfAvailablePhysicalMemory(meminfo) / 1024);
244   // Simulate as if there is no MemAvailable.
245   meminfo.available = 0;
246   EXPECT_EQ(374448u,
247             base::SysInfo::AmountOfAvailablePhysicalMemory(meminfo) / 1024);
248   meminfo = {};
249   EXPECT_TRUE(ParseProcMeminfo(valid_input2, &meminfo));
250   EXPECT_EQ(meminfo.total, 255908);
251   EXPECT_EQ(meminfo.free, 69936);
252   EXPECT_EQ(meminfo.available, 0);
253   EXPECT_EQ(meminfo.buffers, 15812);
254   EXPECT_EQ(meminfo.cached, 115124);
255   EXPECT_EQ(meminfo.swap_total, 524280);
256   EXPECT_EQ(meminfo.swap_free, 524200);
257   EXPECT_EQ(meminfo.dirty, 4);
258   EXPECT_EQ(69936u,
259             base::SysInfo::AmountOfAvailablePhysicalMemory(meminfo) / 1024);
260 }
261 
TEST_F(SystemMetricsTest,ParseVmstat)262 TEST_F(SystemMetricsTest, ParseVmstat) {
263   VmStatInfo vmstat;
264   // Part of vmstat from a 4.19 kernel.
265   const char valid_input1[] =
266       "pgpgin 2358216\n"
267       "pgpgout 296072\n"
268       "pswpin 345219\n"
269       "pswpout 2605828\n"
270       "pgalloc_dma32 8380235\n"
271       "pgalloc_normal 3384525\n"
272       "pgalloc_movable 0\n"
273       "allocstall_dma32 0\n"
274       "allocstall_normal 2028\n"
275       "allocstall_movable 32559\n"
276       "pgskip_dma32 0\n"
277       "pgskip_normal 0\n"
278       "pgskip_movable 0\n"
279       "pgfree 11802722\n"
280       "pgactivate 894917\n"
281       "pgdeactivate 3255711\n"
282       "pglazyfree 48\n"
283       "pgfault 10043657\n"
284       "pgmajfault 358901\n"
285       "pgmajfault_s 2100\n"
286       "pgmajfault_a 343211\n"
287       "pgmajfault_f 13590\n"
288       "pglazyfreed 0\n"
289       "pgrefill 3429488\n"
290       "pgsteal_kswapd 1466893\n"
291       "pgsteal_direct 1771759\n"
292       "pgscan_kswapd 1907332\n"
293       "pgscan_direct 2118930\n"
294       "pgscan_direct_throttle 154\n"
295       "pginodesteal 3176\n"
296       "slabs_scanned 293804\n"
297       "kswapd_inodesteal 16753\n"
298       "kswapd_low_wmark_hit_quickly 10\n"
299       "kswapd_high_wmark_hit_quickly 423\n"
300       "pageoutrun 441\n"
301       "pgrotated 1636\n"
302       "drop_pagecache 0\n"
303       "drop_slab 0\n"
304       "oom_kill 18\n";
305   const char valid_input2[] =
306       "pgpgin 2606135\n"
307       "pgpgout 1359128\n"
308       "pswpin 899959\n"
309       "pswpout 19761244\n"
310       "pgalloc_dma 31\n"
311       "pgalloc_dma32 18139339\n"
312       "pgalloc_normal 44085950\n"
313       "pgalloc_movable 0\n"
314       "allocstall_dma 0\n"
315       "allocstall_dma32 0\n"
316       "allocstall_normal 18881\n"
317       "allocstall_movable 169527\n"
318       "pgskip_dma 0\n"
319       "pgskip_dma32 0\n"
320       "pgskip_normal 0\n"
321       "pgskip_movable 0\n"
322       "pgfree 63060999\n"
323       "pgactivate 1703494\n"
324       "pgdeactivate 20537803\n"
325       "pglazyfree 163\n"
326       "pgfault 45201169\n"
327       "pgmajfault 609626\n"
328       "pgmajfault_s 7488\n"
329       "pgmajfault_a 591793\n"
330       "pgmajfault_f 10345\n"
331       "pglazyfreed 0\n"
332       "pgrefill 20673453\n"
333       "pgsteal_kswapd 11802772\n"
334       "pgsteal_direct 8618160\n"
335       "pgscan_kswapd 12640517\n"
336       "pgscan_direct 9092230\n"
337       "pgscan_direct_throttle 638\n"
338       "pginodesteal 1716\n"
339       "slabs_scanned 2594642\n"
340       "kswapd_inodesteal 67358\n"
341       "kswapd_low_wmark_hit_quickly 52\n"
342       "kswapd_high_wmark_hit_quickly 11\n"
343       "pageoutrun 83\n"
344       "pgrotated 977\n"
345       "drop_pagecache 1\n"
346       "drop_slab 1\n"
347       "oom_kill 1\n"
348       "pgmigrate_success 3202\n"
349       "pgmigrate_fail 795\n";
350   const char valid_input3[] =
351       "pswpin 12\n"
352       "pswpout 901\n"
353       "pgmajfault 18881\n";
354   EXPECT_TRUE(ParseProcVmstat(valid_input1, &vmstat));
355   EXPECT_EQ(345219LU, vmstat.pswpin);
356   EXPECT_EQ(2605828LU, vmstat.pswpout);
357   EXPECT_EQ(358901LU, vmstat.pgmajfault);
358   EXPECT_EQ(18LU, vmstat.oom_kill);
359   EXPECT_TRUE(ParseProcVmstat(valid_input2, &vmstat));
360   EXPECT_EQ(899959LU, vmstat.pswpin);
361   EXPECT_EQ(19761244LU, vmstat.pswpout);
362   EXPECT_EQ(609626LU, vmstat.pgmajfault);
363   EXPECT_EQ(1LU, vmstat.oom_kill);
364   EXPECT_TRUE(ParseProcVmstat(valid_input3, &vmstat));
365   EXPECT_EQ(12LU, vmstat.pswpin);
366   EXPECT_EQ(901LU, vmstat.pswpout);
367   EXPECT_EQ(18881LU, vmstat.pgmajfault);
368   EXPECT_EQ(0LU, vmstat.oom_kill);
369 
370   const char missing_pgmajfault_input[] =
371       "pswpin 12\n"
372       "pswpout 901\n";
373   EXPECT_FALSE(ParseProcVmstat(missing_pgmajfault_input, &vmstat));
374   const char empty_input[] = "";
375   EXPECT_FALSE(ParseProcVmstat(empty_input, &vmstat));
376 }
377 #endif  // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) ||
378         // BUILDFLAG(IS_ANDROID)
379 
380 #if ENABLE_CPU_TESTS
381 // Test that ProcessMetrics::GetPlatformIndependentCPUUsage() doesn't return
382 // negative values when the number of threads running on the process decreases
383 // between two successive calls to it.
TEST_F(SystemMetricsTest,TestNoNegativeCpuUsage)384 TEST_F(SystemMetricsTest, TestNoNegativeCpuUsage) {
385   ProcessHandle handle = GetCurrentProcessHandle();
386   std::unique_ptr<ProcessMetrics> metrics(CreateProcessMetricsForTest(handle));
387 
388   EXPECT_GE(metrics->GetPlatformIndependentCPUUsage(), 0.0);
389 #if BUILDFLAG(IS_WIN)
390   EXPECT_GE(metrics->GetPreciseCPUUsage(), 0.0);
391 #endif
392 
393   Thread thread1("thread1");
394   Thread thread2("thread2");
395   Thread thread3("thread3");
396 
397   thread1.StartAndWaitForTesting();
398   thread2.StartAndWaitForTesting();
399   thread3.StartAndWaitForTesting();
400 
401   ASSERT_TRUE(thread1.IsRunning());
402   ASSERT_TRUE(thread2.IsRunning());
403   ASSERT_TRUE(thread3.IsRunning());
404 
405   std::vector<std::string> vec1;
406   std::vector<std::string> vec2;
407   std::vector<std::string> vec3;
408 
409   thread1.task_runner()->PostTask(FROM_HERE, BindOnce(&BusyWork, &vec1));
410   thread2.task_runner()->PostTask(FROM_HERE, BindOnce(&BusyWork, &vec2));
411   thread3.task_runner()->PostTask(FROM_HERE, BindOnce(&BusyWork, &vec3));
412 
413   TimeDelta prev_cpu_usage = TestCumulativeCPU(metrics.get(), TimeDelta());
414   TimeDelta prev_precise_cpu_usage =
415       TestPreciseCumulativeCPU(metrics.get(), TimeDelta());
416 
417   thread1.Stop();
418   prev_cpu_usage = TestCumulativeCPU(metrics.get(), prev_cpu_usage);
419   prev_precise_cpu_usage =
420       TestPreciseCumulativeCPU(metrics.get(), prev_precise_cpu_usage);
421 
422   thread2.Stop();
423   prev_cpu_usage = TestCumulativeCPU(metrics.get(), prev_cpu_usage);
424   prev_precise_cpu_usage =
425       TestPreciseCumulativeCPU(metrics.get(), prev_precise_cpu_usage);
426 
427   thread3.Stop();
428   prev_cpu_usage = TestCumulativeCPU(metrics.get(), prev_cpu_usage);
429   prev_precise_cpu_usage =
430       TestPreciseCumulativeCPU(metrics.get(), prev_precise_cpu_usage);
431 }
432 #endif  // ENABLE_CPU_TESTS
433 
434 #if BUILDFLAG(IS_CHROMEOS)
TEST_F(SystemMetricsTest,ParseZramMmStat)435 TEST_F(SystemMetricsTest, ParseZramMmStat) {
436   SwapInfo swapinfo;
437 
438   const char invalid_input1[] = "aaa";
439   const char invalid_input2[] = "1 2 3 4 5 6";
440   const char invalid_input3[] = "a 2 3 4 5 6 7";
441   EXPECT_FALSE(ParseZramMmStat(invalid_input1, &swapinfo));
442   EXPECT_FALSE(ParseZramMmStat(invalid_input2, &swapinfo));
443   EXPECT_FALSE(ParseZramMmStat(invalid_input3, &swapinfo));
444 
445   const char valid_input1[] =
446       "17715200 5008166 566062  0 1225715712  127 183842";
447   EXPECT_TRUE(ParseZramMmStat(valid_input1, &swapinfo));
448   EXPECT_EQ(17715200ULL, swapinfo.orig_data_size);
449   EXPECT_EQ(5008166ULL, swapinfo.compr_data_size);
450   EXPECT_EQ(566062ULL, swapinfo.mem_used_total);
451 }
452 
TEST_F(SystemMetricsTest,ParseZramStat)453 TEST_F(SystemMetricsTest, ParseZramStat) {
454   SwapInfo swapinfo;
455 
456   const char invalid_input1[] = "aaa";
457   const char invalid_input2[] = "1 2 3 4 5 6 7 8 9 10";
458   const char invalid_input3[] = "a 2 3 4 5 6 7 8 9 10 11";
459   EXPECT_FALSE(ParseZramStat(invalid_input1, &swapinfo));
460   EXPECT_FALSE(ParseZramStat(invalid_input2, &swapinfo));
461   EXPECT_FALSE(ParseZramStat(invalid_input3, &swapinfo));
462 
463   const char valid_input1[] =
464       "299    0    2392    0    1    0    8    0    0    0    0";
465   EXPECT_TRUE(ParseZramStat(valid_input1, &swapinfo));
466   EXPECT_EQ(299ULL, swapinfo.num_reads);
467   EXPECT_EQ(1ULL, swapinfo.num_writes);
468 }
469 #endif  // BUILDFLAG(IS_CHROMEOS)
470 
471 #if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_APPLE) || BUILDFLAG(IS_LINUX) || \
472     BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_ANDROID)
TEST(SystemMetrics2Test,GetSystemMemoryInfo)473 TEST(SystemMetrics2Test, GetSystemMemoryInfo) {
474   SystemMemoryInfoKB info;
475   EXPECT_TRUE(GetSystemMemoryInfo(&info));
476 
477   // Ensure each field received a value.
478   EXPECT_GT(info.total, 0);
479 #if BUILDFLAG(IS_WIN)
480   EXPECT_GT(info.avail_phys, 0);
481 #else
482   EXPECT_GT(info.free, 0);
483 #endif
484 #if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_ANDROID)
485   EXPECT_GT(info.buffers, 0);
486   EXPECT_GT(info.cached, 0);
487   EXPECT_GT(info.active_anon + info.inactive_anon, 0);
488   EXPECT_GT(info.active_file + info.inactive_file, 0);
489 #endif  // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) ||
490         // BUILDFLAG(IS_ANDROID)
491 
492   // All the values should be less than the total amount of memory.
493 #if !BUILDFLAG(IS_WIN) && !BUILDFLAG(IS_IOS)
494   // TODO(crbug.com/711450): re-enable the following assertion on iOS.
495   EXPECT_LT(info.free, info.total);
496 #endif
497 #if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_ANDROID)
498   EXPECT_LT(info.buffers, info.total);
499   EXPECT_LT(info.cached, info.total);
500   EXPECT_LT(info.active_anon, info.total);
501   EXPECT_LT(info.inactive_anon, info.total);
502   EXPECT_LT(info.active_file, info.total);
503   EXPECT_LT(info.inactive_file, info.total);
504 #endif  // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) ||
505         // BUILDFLAG(IS_ANDROID)
506 
507 #if BUILDFLAG(IS_APPLE)
508   EXPECT_GT(info.file_backed, 0);
509 #endif
510 
511 #if BUILDFLAG(IS_CHROMEOS)
512   // Chrome OS exposes shmem.
513   EXPECT_GT(info.shmem, 0);
514   EXPECT_LT(info.shmem, info.total);
515 #endif
516 }
517 #endif  // BUILDFLAG(IS_WIN) || BUILDFLAG(IS_APPLE) || BUILDFLAG(IS_LINUX) ||
518         // BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_ANDROID)
519 
520 #if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_ANDROID)
TEST(ProcessMetricsTest,ParseProcStatCPU)521 TEST(ProcessMetricsTest, ParseProcStatCPU) {
522   // /proc/self/stat for a process running "top".
523   const char kTopStat[] =
524       "960 (top) S 16230 960 16230 34818 960 "
525       "4202496 471 0 0 0 "
526       "12 16 0 0 "  // <- These are the goods.
527       "20 0 1 0 121946157 15077376 314 18446744073709551615 4194304 "
528       "4246868 140733983044336 18446744073709551615 140244213071219 "
529       "0 0 0 138047495 0 0 0 17 1 0 0 0 0 0";
530   EXPECT_EQ(12 + 16, ParseProcStatCPU(kTopStat));
531 
532   // cat /proc/self/stat on a random other machine I have.
533   const char kSelfStat[] =
534       "5364 (cat) R 5354 5364 5354 34819 5364 "
535       "0 142 0 0 0 "
536       "0 0 0 0 "  // <- No CPU, apparently.
537       "16 0 1 0 1676099790 2957312 114 4294967295 134512640 134528148 "
538       "3221224832 3221224344 3086339742 0 0 0 0 0 0 0 17 0 0 0";
539 
540   EXPECT_EQ(0, ParseProcStatCPU(kSelfStat));
541 
542   // Some weird long-running process with a weird name that I created for the
543   // purposes of this test.
544   const char kWeirdNameStat[] =
545       "26115 (Hello) You ()))  ) R 24614 26115 24614"
546       " 34839 26115 4218880 227 0 0 0 "
547       "5186 11 0 0 "
548       "20 0 1 0 36933953 4296704 90 18446744073709551615 4194304 4196116 "
549       "140735857761568 140735857761160 4195644 0 0 0 0 0 0 0 17 14 0 0 0 0 0 "
550       "6295056 6295616 16519168 140735857770710 140735857770737 "
551       "140735857770737 140735857774557 0";
552   EXPECT_EQ(5186 + 11, ParseProcStatCPU(kWeirdNameStat));
553 }
554 #endif  // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) ||
555         // BUILDFLAG(IS_ANDROID)
556 
557 // Disable on Android because base_unittests runs inside a Dalvik VM that
558 // starts and stop threads (crbug.com/175563).
559 #if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
560 // http://crbug.com/396455
TEST(ProcessMetricsTest,DISABLED_GetNumberOfThreads)561 TEST(ProcessMetricsTest, DISABLED_GetNumberOfThreads) {
562   const ProcessHandle current = GetCurrentProcessHandle();
563   const int64_t initial_threads = GetNumberOfThreads(current);
564   ASSERT_GT(initial_threads, 0);
565   const int kNumAdditionalThreads = 10;
566   {
567     std::unique_ptr<Thread> my_threads[kNumAdditionalThreads];
568     for (int i = 0; i < kNumAdditionalThreads; ++i) {
569       my_threads[i] = std::make_unique<Thread>("GetNumberOfThreadsTest");
570       my_threads[i]->Start();
571       ASSERT_EQ(GetNumberOfThreads(current), initial_threads + 1 + i);
572     }
573   }
574   // The Thread destructor will stop them.
575   ASSERT_EQ(initial_threads, GetNumberOfThreads(current));
576 }
577 #endif  // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
578 
579 #if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || \
580     (BUILDFLAG(IS_APPLE) && BUILDFLAG(USE_BLINK))
581 namespace {
582 
583 // Keep these in sync so the GetChildOpenFdCount test can refer to correct test
584 // main.
585 #define ChildMain ChildFdCount
586 #define ChildMainString "ChildFdCount"
587 
588 // Command line flag name and file name used for synchronization.
589 const char kTempDirFlag[] = "temp-dir";
590 
591 const char kSignalReady[] = "ready";
592 const char kSignalReadyAck[] = "ready-ack";
593 const char kSignalOpened[] = "opened";
594 const char kSignalOpenedAck[] = "opened-ack";
595 const char kSignalClosed[] = "closed";
596 
597 const int kChildNumFilesToOpen = 100;
598 
SignalEvent(const FilePath & signal_dir,const char * signal_file)599 bool SignalEvent(const FilePath& signal_dir, const char* signal_file) {
600   File file(signal_dir.AppendASCII(signal_file),
601             File::FLAG_CREATE | File::FLAG_WRITE);
602   return file.IsValid();
603 }
604 
605 // Check whether an event was signaled.
CheckEvent(const FilePath & signal_dir,const char * signal_file)606 bool CheckEvent(const FilePath& signal_dir, const char* signal_file) {
607   File file(signal_dir.AppendASCII(signal_file),
608             File::FLAG_OPEN | File::FLAG_READ);
609   return file.IsValid();
610 }
611 
612 // Busy-wait for an event to be signaled.
WaitForEvent(const FilePath & signal_dir,const char * signal_file)613 void WaitForEvent(const FilePath& signal_dir, const char* signal_file) {
614   while (!CheckEvent(signal_dir, signal_file)) {
615     PlatformThread::Sleep(Milliseconds(10));
616   }
617 }
618 
619 // Subprocess to test the number of open file descriptors.
MULTIPROCESS_TEST_MAIN(ChildMain)620 MULTIPROCESS_TEST_MAIN(ChildMain) {
621   CommandLine* command_line = CommandLine::ForCurrentProcess();
622   const FilePath temp_path = command_line->GetSwitchValuePath(kTempDirFlag);
623   CHECK(DirectoryExists(temp_path));
624 
625   CHECK(SignalEvent(temp_path, kSignalReady));
626   WaitForEvent(temp_path, kSignalReadyAck);
627 
628   std::vector<File> files;
629   for (int i = 0; i < kChildNumFilesToOpen; ++i) {
630     files.emplace_back(temp_path.AppendASCII(StringPrintf("file.%d", i)),
631                        File::FLAG_CREATE | File::FLAG_WRITE);
632   }
633 
634   CHECK(SignalEvent(temp_path, kSignalOpened));
635   WaitForEvent(temp_path, kSignalOpenedAck);
636 
637   files.clear();
638 
639   CHECK(SignalEvent(temp_path, kSignalClosed));
640 
641   // Wait to be terminated.
642   while (true) {
643     PlatformThread::Sleep(Seconds(1));
644   }
645 }
646 
647 }  // namespace
648 
TEST(ProcessMetricsTest,GetChildOpenFdCount)649 TEST(ProcessMetricsTest, GetChildOpenFdCount) {
650   ScopedTempDir temp_dir;
651   ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
652   const FilePath temp_path = temp_dir.GetPath();
653   CommandLine child_command_line(GetMultiProcessTestChildBaseCommandLine());
654   child_command_line.AppendSwitchPath(kTempDirFlag, temp_path);
655   Process child = SpawnMultiProcessTestChild(
656       ChildMainString, child_command_line, LaunchOptions());
657   ASSERT_TRUE(child.IsValid());
658 
659   WaitForEvent(temp_path, kSignalReady);
660 
661   std::unique_ptr<ProcessMetrics> metrics =
662       CreateProcessMetricsForTest(child.Handle());
663 
664   const int fd_count = metrics->GetOpenFdCount();
665   EXPECT_GE(fd_count, 0);
666 
667   ASSERT_TRUE(SignalEvent(temp_path, kSignalReadyAck));
668   WaitForEvent(temp_path, kSignalOpened);
669 
670   EXPECT_EQ(fd_count + kChildNumFilesToOpen, metrics->GetOpenFdCount());
671   ASSERT_TRUE(SignalEvent(temp_path, kSignalOpenedAck));
672 
673   WaitForEvent(temp_path, kSignalClosed);
674 
675   EXPECT_EQ(fd_count, metrics->GetOpenFdCount());
676 
677   ASSERT_TRUE(child.Terminate(0, true));
678 }
679 
TEST(ProcessMetricsTest,GetOpenFdCount)680 TEST(ProcessMetricsTest, GetOpenFdCount) {
681   base::ProcessHandle process = base::GetCurrentProcessHandle();
682   std::unique_ptr<base::ProcessMetrics> metrics =
683       CreateProcessMetricsForTest(process);
684 
685   ScopedTempDir temp_dir;
686   ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
687 
688   int fd_count = metrics->GetOpenFdCount();
689   EXPECT_GT(fd_count, 0);
690   File file(temp_dir.GetPath().AppendASCII("file"),
691             File::FLAG_CREATE | File::FLAG_WRITE);
692   int new_fd_count = metrics->GetOpenFdCount();
693   EXPECT_GT(new_fd_count, 0);
694   EXPECT_EQ(new_fd_count, fd_count + 1);
695 }
696 #endif  // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_APPLE)
697 
698 #if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
699 
TEST(ProcessMetricsTestLinux,GetPageFaultCounts)700 TEST(ProcessMetricsTestLinux, GetPageFaultCounts) {
701   std::unique_ptr<base::ProcessMetrics> process_metrics(
702       base::ProcessMetrics::CreateProcessMetrics(
703           base::GetCurrentProcessHandle()));
704 
705   PageFaultCounts counts;
706   ASSERT_TRUE(process_metrics->GetPageFaultCounts(&counts));
707   ASSERT_GT(counts.minor, 0);
708   ASSERT_GE(counts.major, 0);
709 
710   // Allocate and touch memory. Touching it is required to make sure that the
711   // page fault count goes up, as memory is typically mapped lazily.
712   {
713     const size_t kMappedSize = 4 << 20;  // 4 MiB.
714 
715     WritableSharedMemoryRegion region =
716         WritableSharedMemoryRegion::Create(kMappedSize);
717     ASSERT_TRUE(region.IsValid());
718 
719     WritableSharedMemoryMapping mapping = region.Map();
720     ASSERT_TRUE(mapping.IsValid());
721 
722     memset(mapping.memory(), 42, kMappedSize);
723   }
724 
725   PageFaultCounts counts_after;
726   ASSERT_TRUE(process_metrics->GetPageFaultCounts(&counts_after));
727   ASSERT_GT(counts_after.minor, counts.minor);
728   ASSERT_GE(counts_after.major, counts.major);
729 }
730 
TEST(ProcessMetricsTestLinux,GetCumulativeCPUUsagePerThread)731 TEST(ProcessMetricsTestLinux, GetCumulativeCPUUsagePerThread) {
732   ProcessHandle handle = GetCurrentProcessHandle();
733   std::unique_ptr<ProcessMetrics> metrics(
734       ProcessMetrics::CreateProcessMetrics(handle));
735 
736   Thread thread1("thread1");
737   thread1.StartAndWaitForTesting();
738   ASSERT_TRUE(thread1.IsRunning());
739 
740   std::vector<std::string> vec1;
741   thread1.task_runner()->PostTask(FROM_HERE, BindOnce(&BusyWork, &vec1));
742 
743   ProcessMetrics::CPUUsagePerThread prev_thread_times;
744   EXPECT_TRUE(metrics->GetCumulativeCPUUsagePerThread(prev_thread_times));
745 
746   // Should have at least the test runner thread and the thread spawned above.
747   EXPECT_GE(prev_thread_times.size(), 2u);
748   EXPECT_TRUE(ranges::any_of(
749       prev_thread_times,
750       [&thread1](const std::pair<PlatformThreadId, base::TimeDelta>& entry) {
751         return entry.first == thread1.GetThreadId();
752       }));
753   EXPECT_TRUE(ranges::any_of(
754       prev_thread_times,
755       [](const std::pair<PlatformThreadId, base::TimeDelta>& entry) {
756         return entry.first == base::PlatformThread::CurrentId();
757       }));
758 
759   for (const auto& entry : prev_thread_times) {
760     EXPECT_GE(entry.second, base::TimeDelta());
761   }
762 
763   thread1.Stop();
764 
765   ProcessMetrics::CPUUsagePerThread current_thread_times;
766   EXPECT_TRUE(metrics->GetCumulativeCPUUsagePerThread(current_thread_times));
767 
768   // The stopped thread may still be reported until the kernel cleans it up.
769   EXPECT_GE(prev_thread_times.size(), 1u);
770   EXPECT_TRUE(ranges::any_of(
771       current_thread_times,
772       [](const std::pair<PlatformThreadId, base::TimeDelta>& entry) {
773         return entry.first == base::PlatformThread::CurrentId();
774       }));
775 
776   // Reported times should not decrease.
777   for (const auto& entry : current_thread_times) {
778     auto prev_it = ranges::find_if(
779         prev_thread_times,
780         [&entry](
781             const std::pair<PlatformThreadId, base::TimeDelta>& prev_entry) {
782           return entry.first == prev_entry.first;
783         });
784 
785     if (prev_it != prev_thread_times.end()) {
786       EXPECT_GE(entry.second, prev_it->second);
787     }
788   }
789 }
790 #endif  // BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_LINUX) ||
791         // BUILDFLAG(IS_CHROMEOS)
792 
793 }  // namespace base::debug
794