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