• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2013 The Chromium Authors. All rights reserved.
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 <sstream>
11 #include <string>
12 #include <vector>
13 
14 #include "base/bind.h"
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/macros.h"
20 #include "base/memory/shared_memory.h"
21 #include "base/strings/string_number_conversions.h"
22 #include "base/sys_info.h"
23 #include "base/test/multiprocess_test.h"
24 #include "base/threading/thread.h"
25 #include "build/build_config.h"
26 #include "testing/gtest/include/gtest/gtest.h"
27 #include "testing/multiprocess_func_list.h"
28 
29 #if defined(OS_MACOSX)
30 #include <sys/mman.h>
31 #endif
32 
33 namespace base {
34 namespace debug {
35 
36 #if defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_WIN)
37 namespace {
38 
BusyWork(std::vector<std::string> * vec)39 void BusyWork(std::vector<std::string>* vec) {
40   int64_t test_value = 0;
41   for (int i = 0; i < 100000; ++i) {
42     ++test_value;
43     vec->push_back(Int64ToString(test_value));
44   }
45 }
46 
47 }  // namespace
48 #endif  // defined(OS_LINUX) || defined(OS_CHROMEOS)
49 
50 // Tests for SystemMetrics.
51 // Exists as a class so it can be a friend of SystemMetrics.
52 class SystemMetricsTest : public testing::Test {
53  public:
54   SystemMetricsTest() = default;
55 
56  private:
57   DISALLOW_COPY_AND_ASSIGN(SystemMetricsTest);
58 };
59 
60 #if defined(OS_LINUX) || defined(OS_ANDROID)
TEST_F(SystemMetricsTest,IsValidDiskName)61 TEST_F(SystemMetricsTest, IsValidDiskName) {
62   const char invalid_input1[] = "";
63   const char invalid_input2[] = "s";
64   const char invalid_input3[] = "sdz+";
65   const char invalid_input4[] = "hda0";
66   const char invalid_input5[] = "mmcbl";
67   const char invalid_input6[] = "mmcblka";
68   const char invalid_input7[] = "mmcblkb";
69   const char invalid_input8[] = "mmmblk0";
70 
71   EXPECT_FALSE(IsValidDiskName(invalid_input1));
72   EXPECT_FALSE(IsValidDiskName(invalid_input2));
73   EXPECT_FALSE(IsValidDiskName(invalid_input3));
74   EXPECT_FALSE(IsValidDiskName(invalid_input4));
75   EXPECT_FALSE(IsValidDiskName(invalid_input5));
76   EXPECT_FALSE(IsValidDiskName(invalid_input6));
77   EXPECT_FALSE(IsValidDiskName(invalid_input7));
78   EXPECT_FALSE(IsValidDiskName(invalid_input8));
79 
80   const char valid_input1[] = "sda";
81   const char valid_input2[] = "sdaaaa";
82   const char valid_input3[] = "hdz";
83   const char valid_input4[] = "mmcblk0";
84   const char valid_input5[] = "mmcblk999";
85 
86   EXPECT_TRUE(IsValidDiskName(valid_input1));
87   EXPECT_TRUE(IsValidDiskName(valid_input2));
88   EXPECT_TRUE(IsValidDiskName(valid_input3));
89   EXPECT_TRUE(IsValidDiskName(valid_input4));
90   EXPECT_TRUE(IsValidDiskName(valid_input5));
91 }
92 
TEST_F(SystemMetricsTest,ParseMeminfo)93 TEST_F(SystemMetricsTest, ParseMeminfo) {
94   SystemMemoryInfoKB meminfo;
95   const char invalid_input1[] = "abc";
96   const char invalid_input2[] = "MemTotal:";
97   // Partial file with no MemTotal
98   const char invalid_input3[] =
99       "MemFree:         3913968 kB\n"
100       "Buffers:         2348340 kB\n"
101       "Cached:         49071596 kB\n"
102       "SwapCached:           12 kB\n"
103       "Active:         36393900 kB\n"
104       "Inactive:       21221496 kB\n"
105       "Active(anon):    5674352 kB\n"
106       "Inactive(anon):   633992 kB\n";
107   EXPECT_FALSE(ParseProcMeminfo(invalid_input1, &meminfo));
108   EXPECT_FALSE(ParseProcMeminfo(invalid_input2, &meminfo));
109   EXPECT_FALSE(ParseProcMeminfo(invalid_input3, &meminfo));
110 
111   const char valid_input1[] =
112       "MemTotal:        3981504 kB\n"
113       "MemFree:          140764 kB\n"
114       "MemAvailable:     535413 kB\n"
115       "Buffers:          116480 kB\n"
116       "Cached:           406160 kB\n"
117       "SwapCached:        21304 kB\n"
118       "Active:          3152040 kB\n"
119       "Inactive:         472856 kB\n"
120       "Active(anon):    2972352 kB\n"
121       "Inactive(anon):   270108 kB\n"
122       "Active(file):     179688 kB\n"
123       "Inactive(file):   202748 kB\n"
124       "Unevictable:           0 kB\n"
125       "Mlocked:               0 kB\n"
126       "SwapTotal:       5832280 kB\n"
127       "SwapFree:        3672368 kB\n"
128       "Dirty:               184 kB\n"
129       "Writeback:             0 kB\n"
130       "AnonPages:       3101224 kB\n"
131       "Mapped:           142296 kB\n"
132       "Shmem:            140204 kB\n"
133       "Slab:              54212 kB\n"
134       "SReclaimable:      30936 kB\n"
135       "SUnreclaim:        23276 kB\n"
136       "KernelStack:        2464 kB\n"
137       "PageTables:        24812 kB\n"
138       "NFS_Unstable:          0 kB\n"
139       "Bounce:                0 kB\n"
140       "WritebackTmp:          0 kB\n"
141       "CommitLimit:     7823032 kB\n"
142       "Committed_AS:    7973536 kB\n"
143       "VmallocTotal:   34359738367 kB\n"
144       "VmallocUsed:      375940 kB\n"
145       "VmallocChunk:   34359361127 kB\n"
146       "DirectMap4k:       72448 kB\n"
147       "DirectMap2M:     4061184 kB\n";
148   // output from a much older kernel where the Active and Inactive aren't
149   // broken down into anon and file and Huge Pages are enabled
150   const char valid_input2[] =
151       "MemTotal:       255908 kB\n"
152       "MemFree:         69936 kB\n"
153       "Buffers:         15812 kB\n"
154       "Cached:         115124 kB\n"
155       "SwapCached:          0 kB\n"
156       "Active:          92700 kB\n"
157       "Inactive:        63792 kB\n"
158       "HighTotal:           0 kB\n"
159       "HighFree:            0 kB\n"
160       "LowTotal:       255908 kB\n"
161       "LowFree:         69936 kB\n"
162       "SwapTotal:      524280 kB\n"
163       "SwapFree:       524200 kB\n"
164       "Dirty:               4 kB\n"
165       "Writeback:           0 kB\n"
166       "Mapped:          42236 kB\n"
167       "Slab:            25912 kB\n"
168       "Committed_AS:   118680 kB\n"
169       "PageTables:       1236 kB\n"
170       "VmallocTotal:  3874808 kB\n"
171       "VmallocUsed:      1416 kB\n"
172       "VmallocChunk:  3872908 kB\n"
173       "HugePages_Total:     0\n"
174       "HugePages_Free:      0\n"
175       "Hugepagesize:     4096 kB\n";
176 
177   EXPECT_TRUE(ParseProcMeminfo(valid_input1, &meminfo));
178   EXPECT_EQ(meminfo.total, 3981504);
179   EXPECT_EQ(meminfo.free, 140764);
180   EXPECT_EQ(meminfo.available, 535413);
181   EXPECT_EQ(meminfo.buffers, 116480);
182   EXPECT_EQ(meminfo.cached, 406160);
183   EXPECT_EQ(meminfo.active_anon, 2972352);
184   EXPECT_EQ(meminfo.active_file, 179688);
185   EXPECT_EQ(meminfo.inactive_anon, 270108);
186   EXPECT_EQ(meminfo.inactive_file, 202748);
187   EXPECT_EQ(meminfo.swap_total, 5832280);
188   EXPECT_EQ(meminfo.swap_free, 3672368);
189   EXPECT_EQ(meminfo.dirty, 184);
190   EXPECT_EQ(meminfo.reclaimable, 30936);
191 #if defined(OS_CHROMEOS)
192   EXPECT_EQ(meminfo.shmem, 140204);
193   EXPECT_EQ(meminfo.slab, 54212);
194 #endif
195   EXPECT_EQ(355725,
196             base::SysInfo::AmountOfAvailablePhysicalMemory(meminfo) / 1024);
197   // Simulate as if there is no MemAvailable.
198   meminfo.available = 0;
199   EXPECT_EQ(374448,
200             base::SysInfo::AmountOfAvailablePhysicalMemory(meminfo) / 1024);
201   meminfo = {};
202   EXPECT_TRUE(ParseProcMeminfo(valid_input2, &meminfo));
203   EXPECT_EQ(meminfo.total, 255908);
204   EXPECT_EQ(meminfo.free, 69936);
205   EXPECT_EQ(meminfo.available, 0);
206   EXPECT_EQ(meminfo.buffers, 15812);
207   EXPECT_EQ(meminfo.cached, 115124);
208   EXPECT_EQ(meminfo.swap_total, 524280);
209   EXPECT_EQ(meminfo.swap_free, 524200);
210   EXPECT_EQ(meminfo.dirty, 4);
211   EXPECT_EQ(69936,
212             base::SysInfo::AmountOfAvailablePhysicalMemory(meminfo) / 1024);
213 }
214 
TEST_F(SystemMetricsTest,ParseVmstat)215 TEST_F(SystemMetricsTest, ParseVmstat) {
216   VmStatInfo vmstat;
217   // part of vmstat from a 3.2 kernel with numa enabled
218   const char valid_input1[] =
219       "nr_free_pages 905104\n"
220       "nr_inactive_anon 142478"
221       "nr_active_anon 1520046\n"
222       "nr_inactive_file 4481001\n"
223       "nr_active_file 8313439\n"
224       "nr_unevictable 5044\n"
225       "nr_mlock 5044\n"
226       "nr_anon_pages 1633780\n"
227       "nr_mapped 104742\n"
228       "nr_file_pages 12828218\n"
229       "nr_dirty 245\n"
230       "nr_writeback 0\n"
231       "nr_slab_reclaimable 831609\n"
232       "nr_slab_unreclaimable 41164\n"
233       "nr_page_table_pages 31470\n"
234       "nr_kernel_stack 1735\n"
235       "nr_unstable 0\n"
236       "nr_bounce 0\n"
237       "nr_vmscan_write 406\n"
238       "nr_vmscan_immediate_reclaim 281\n"
239       "nr_writeback_temp 0\n"
240       "nr_isolated_anon 0\n"
241       "nr_isolated_file 0\n"
242       "nr_shmem 28820\n"
243       "nr_dirtied 84674644\n"
244       "nr_written 75307109\n"
245       "nr_anon_transparent_hugepages 0\n"
246       "nr_dirty_threshold 1536206\n"
247       "nr_dirty_background_threshold 768103\n"
248       "pgpgin 30777108\n"
249       "pgpgout 319023278\n"
250       "pswpin 179\n"
251       "pswpout 406\n"
252       "pgalloc_dma 0\n"
253       "pgalloc_dma32 20833399\n"
254       "pgalloc_normal 1622609290\n"
255       "pgalloc_movable 0\n"
256       "pgfree 1644355583\n"
257       "pgactivate 75391882\n"
258       "pgdeactivate 4121019\n"
259       "pgfault 2542879679\n"
260       "pgmajfault 487192\n";
261   const char valid_input2[] =
262       "nr_free_pages 180125\n"
263       "nr_inactive_anon 51\n"
264       "nr_active_anon 38832\n"
265       "nr_inactive_file 50171\n"
266       "nr_active_file 47510\n"
267       "nr_unevictable 0\n"
268       "nr_mlock 0\n"
269       "nr_anon_pages 38825\n"
270       "nr_mapped 24043\n"
271       "nr_file_pages 97733\n"
272       "nr_dirty 0\n"
273       "nr_writeback 0\n"
274       "nr_slab_reclaimable 4032\n"
275       "nr_slab_unreclaimable 2848\n"
276       "nr_page_table_pages 1505\n"
277       "nr_kernel_stack 626\n"
278       "nr_unstable 0\n"
279       "nr_bounce 0\n"
280       "nr_vmscan_write 0\n"
281       "nr_vmscan_immediate_reclaim 0\n"
282       "nr_writeback_temp 0\n"
283       "nr_isolated_anon 0\n"
284       "nr_isolated_file 0\n"
285       "nr_shmem 58\n"
286       "nr_dirtied 435358\n"
287       "nr_written 401258\n"
288       "nr_anon_transparent_hugepages 0\n"
289       "nr_dirty_threshold 18566\n"
290       "nr_dirty_background_threshold 4641\n"
291       "pgpgin 299464\n"
292       "pgpgout 2437788\n"
293       "pswpin 12\n"
294       "pswpout 901\n"
295       "pgalloc_normal 144213030\n"
296       "pgalloc_high 164501274\n"
297       "pgalloc_movable 0\n"
298       "pgfree 308894908\n"
299       "pgactivate 239320\n"
300       "pgdeactivate 1\n"
301       "pgfault 716044601\n"
302       "pgmajfault 2023\n"
303       "pgrefill_normal 0\n"
304       "pgrefill_high 0\n"
305       "pgrefill_movable 0\n";
306   EXPECT_TRUE(ParseProcVmstat(valid_input1, &vmstat));
307   EXPECT_EQ(179LU, vmstat.pswpin);
308   EXPECT_EQ(406LU, vmstat.pswpout);
309   EXPECT_EQ(487192LU, vmstat.pgmajfault);
310   EXPECT_TRUE(ParseProcVmstat(valid_input2, &vmstat));
311   EXPECT_EQ(12LU, vmstat.pswpin);
312   EXPECT_EQ(901LU, vmstat.pswpout);
313   EXPECT_EQ(2023LU, vmstat.pgmajfault);
314 
315   const char missing_pgmajfault_input[] =
316       "pswpin 12\n"
317       "pswpout 901\n";
318   EXPECT_FALSE(ParseProcVmstat(missing_pgmajfault_input, &vmstat));
319   const char empty_input[] = "";
320   EXPECT_FALSE(ParseProcVmstat(empty_input, &vmstat));
321 }
322 #endif  // defined(OS_LINUX) || defined(OS_ANDROID)
323 
324 #if defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_WIN)
325 
326 // Test that ProcessMetrics::GetPlatformIndependentCPUUsage() doesn't return
327 // negative values when the number of threads running on the process decreases
328 // between two successive calls to it.
TEST_F(SystemMetricsTest,TestNoNegativeCpuUsage)329 TEST_F(SystemMetricsTest, TestNoNegativeCpuUsage) {
330   ProcessHandle handle = GetCurrentProcessHandle();
331   std::unique_ptr<ProcessMetrics> metrics(
332       ProcessMetrics::CreateProcessMetrics(handle));
333 
334   EXPECT_GE(metrics->GetPlatformIndependentCPUUsage(), 0.0);
335   Thread thread1("thread1");
336   Thread thread2("thread2");
337   Thread thread3("thread3");
338 
339   thread1.StartAndWaitForTesting();
340   thread2.StartAndWaitForTesting();
341   thread3.StartAndWaitForTesting();
342 
343   ASSERT_TRUE(thread1.IsRunning());
344   ASSERT_TRUE(thread2.IsRunning());
345   ASSERT_TRUE(thread3.IsRunning());
346 
347   std::vector<std::string> vec1;
348   std::vector<std::string> vec2;
349   std::vector<std::string> vec3;
350 
351   thread1.task_runner()->PostTask(FROM_HERE, BindOnce(&BusyWork, &vec1));
352   thread2.task_runner()->PostTask(FROM_HERE, BindOnce(&BusyWork, &vec2));
353   thread3.task_runner()->PostTask(FROM_HERE, BindOnce(&BusyWork, &vec3));
354 
355   TimeDelta prev_cpu_usage = metrics->GetCumulativeCPUUsage();
356   EXPECT_GE(prev_cpu_usage, TimeDelta());
357   EXPECT_GE(metrics->GetPlatformIndependentCPUUsage(), 0.0);
358 
359   thread1.Stop();
360   TimeDelta current_cpu_usage = metrics->GetCumulativeCPUUsage();
361   EXPECT_GE(current_cpu_usage, prev_cpu_usage);
362   prev_cpu_usage = current_cpu_usage;
363   EXPECT_GE(metrics->GetPlatformIndependentCPUUsage(), 0.0);
364 
365   thread2.Stop();
366   current_cpu_usage = metrics->GetCumulativeCPUUsage();
367   EXPECT_GE(current_cpu_usage, prev_cpu_usage);
368   prev_cpu_usage = current_cpu_usage;
369   EXPECT_GE(metrics->GetPlatformIndependentCPUUsage(), 0.0);
370 
371   thread3.Stop();
372   current_cpu_usage = metrics->GetCumulativeCPUUsage();
373   EXPECT_GE(current_cpu_usage, prev_cpu_usage);
374   EXPECT_GE(metrics->GetPlatformIndependentCPUUsage(), 0.0);
375 }
376 
377 #endif  // defined(OS_LINUX) || defined(OS_CHROMEOS)
378 
379 #if defined(OS_CHROMEOS)
TEST_F(SystemMetricsTest,ParseZramMmStat)380 TEST_F(SystemMetricsTest, ParseZramMmStat) {
381   SwapInfo swapinfo;
382 
383   const char invalid_input1[] = "aaa";
384   const char invalid_input2[] = "1 2 3 4 5 6";
385   const char invalid_input3[] = "a 2 3 4 5 6 7";
386   EXPECT_FALSE(ParseZramMmStat(invalid_input1, &swapinfo));
387   EXPECT_FALSE(ParseZramMmStat(invalid_input2, &swapinfo));
388   EXPECT_FALSE(ParseZramMmStat(invalid_input3, &swapinfo));
389 
390   const char valid_input1[] =
391       "17715200 5008166 566062  0 1225715712  127 183842";
392   EXPECT_TRUE(ParseZramMmStat(valid_input1, &swapinfo));
393   EXPECT_EQ(17715200ULL, swapinfo.orig_data_size);
394   EXPECT_EQ(5008166ULL, swapinfo.compr_data_size);
395   EXPECT_EQ(566062ULL, swapinfo.mem_used_total);
396 }
397 
TEST_F(SystemMetricsTest,ParseZramStat)398 TEST_F(SystemMetricsTest, ParseZramStat) {
399   SwapInfo swapinfo;
400 
401   const char invalid_input1[] = "aaa";
402   const char invalid_input2[] = "1 2 3 4 5 6 7 8 9 10";
403   const char invalid_input3[] = "a 2 3 4 5 6 7 8 9 10 11";
404   EXPECT_FALSE(ParseZramStat(invalid_input1, &swapinfo));
405   EXPECT_FALSE(ParseZramStat(invalid_input2, &swapinfo));
406   EXPECT_FALSE(ParseZramStat(invalid_input3, &swapinfo));
407 
408   const char valid_input1[] =
409       "299    0    2392    0    1    0    8    0    0    0    0";
410   EXPECT_TRUE(ParseZramStat(valid_input1, &swapinfo));
411   EXPECT_EQ(299ULL, swapinfo.num_reads);
412   EXPECT_EQ(1ULL, swapinfo.num_writes);
413 }
414 #endif  // defined(OS_CHROMEOS)
415 
416 #if defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_LINUX) || \
417     defined(OS_ANDROID)
TEST(SystemMetrics2Test,GetSystemMemoryInfo)418 TEST(SystemMetrics2Test, GetSystemMemoryInfo) {
419   SystemMemoryInfoKB info;
420   EXPECT_TRUE(GetSystemMemoryInfo(&info));
421 
422   // Ensure each field received a value.
423   EXPECT_GT(info.total, 0);
424 #if defined(OS_WIN)
425   EXPECT_GT(info.avail_phys, 0);
426 #else
427   EXPECT_GT(info.free, 0);
428 #endif
429 #if defined(OS_LINUX) || defined(OS_ANDROID)
430   EXPECT_GT(info.buffers, 0);
431   EXPECT_GT(info.cached, 0);
432   EXPECT_GT(info.active_anon, 0);
433   EXPECT_GT(info.inactive_anon, 0);
434   EXPECT_GT(info.active_file, 0);
435   EXPECT_GT(info.inactive_file, 0);
436 #endif  // defined(OS_LINUX) || defined(OS_ANDROID)
437 
438   // All the values should be less than the total amount of memory.
439 #if !defined(OS_WIN) && !defined(OS_IOS)
440   // TODO(crbug.com/711450): re-enable the following assertion on iOS.
441   EXPECT_LT(info.free, info.total);
442 #endif
443 #if defined(OS_LINUX) || defined(OS_ANDROID)
444   EXPECT_LT(info.buffers, info.total);
445   EXPECT_LT(info.cached, info.total);
446   EXPECT_LT(info.active_anon, info.total);
447   EXPECT_LT(info.inactive_anon, info.total);
448   EXPECT_LT(info.active_file, info.total);
449   EXPECT_LT(info.inactive_file, info.total);
450 #endif  // defined(OS_LINUX) || defined(OS_ANDROID)
451 
452 #if defined(OS_MACOSX) || defined(OS_IOS)
453   EXPECT_GT(info.file_backed, 0);
454 #endif
455 
456 #if defined(OS_CHROMEOS)
457   // Chrome OS exposes shmem.
458   EXPECT_GT(info.shmem, 0);
459   EXPECT_LT(info.shmem, info.total);
460   // Chrome unit tests are not run on actual Chrome OS hardware, so gem_objects
461   // and gem_size cannot be tested here.
462 #endif
463 }
464 #endif  // defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_LINUX) ||
465         // defined(OS_ANDROID)
466 
467 #if defined(OS_LINUX) || defined(OS_ANDROID)
TEST(ProcessMetricsTest,ParseProcStatCPU)468 TEST(ProcessMetricsTest, ParseProcStatCPU) {
469   // /proc/self/stat for a process running "top".
470   const char kTopStat[] = "960 (top) S 16230 960 16230 34818 960 "
471       "4202496 471 0 0 0 "
472       "12 16 0 0 "  // <- These are the goods.
473       "20 0 1 0 121946157 15077376 314 18446744073709551615 4194304 "
474       "4246868 140733983044336 18446744073709551615 140244213071219 "
475       "0 0 0 138047495 0 0 0 17 1 0 0 0 0 0";
476   EXPECT_EQ(12 + 16, ParseProcStatCPU(kTopStat));
477 
478   // cat /proc/self/stat on a random other machine I have.
479   const char kSelfStat[] = "5364 (cat) R 5354 5364 5354 34819 5364 "
480       "0 142 0 0 0 "
481       "0 0 0 0 "  // <- No CPU, apparently.
482       "16 0 1 0 1676099790 2957312 114 4294967295 134512640 134528148 "
483       "3221224832 3221224344 3086339742 0 0 0 0 0 0 0 17 0 0 0";
484 
485   EXPECT_EQ(0, ParseProcStatCPU(kSelfStat));
486 
487   // Some weird long-running process with a weird name that I created for the
488   // purposes of this test.
489   const char kWeirdNameStat[] = "26115 (Hello) You ()))  ) R 24614 26115 24614"
490       " 34839 26115 4218880 227 0 0 0 "
491       "5186 11 0 0 "
492       "20 0 1 0 36933953 4296704 90 18446744073709551615 4194304 4196116 "
493       "140735857761568 140735857761160 4195644 0 0 0 0 0 0 0 17 14 0 0 0 0 0 "
494       "6295056 6295616 16519168 140735857770710 140735857770737 "
495       "140735857770737 140735857774557 0";
496   EXPECT_EQ(5186 + 11, ParseProcStatCPU(kWeirdNameStat));
497 }
498 #endif  // defined(OS_LINUX) || defined(OS_ANDROID)
499 
500 // Disable on Android because base_unittests runs inside a Dalvik VM that
501 // starts and stop threads (crbug.com/175563).
502 #if defined(OS_LINUX)
503 // http://crbug.com/396455
TEST(ProcessMetricsTest,DISABLED_GetNumberOfThreads)504 TEST(ProcessMetricsTest, DISABLED_GetNumberOfThreads) {
505   const ProcessHandle current = GetCurrentProcessHandle();
506   const int initial_threads = GetNumberOfThreads(current);
507   ASSERT_GT(initial_threads, 0);
508   const int kNumAdditionalThreads = 10;
509   {
510     std::unique_ptr<Thread> my_threads[kNumAdditionalThreads];
511     for (int i = 0; i < kNumAdditionalThreads; ++i) {
512       my_threads[i].reset(new Thread("GetNumberOfThreadsTest"));
513       my_threads[i]->Start();
514       ASSERT_EQ(GetNumberOfThreads(current), initial_threads + 1 + i);
515     }
516   }
517   // The Thread destructor will stop them.
518   ASSERT_EQ(initial_threads, GetNumberOfThreads(current));
519 }
520 #endif  // defined(OS_LINUX)
521 
522 #if defined(OS_LINUX)
523 namespace {
524 
525 // Keep these in sync so the GetChildOpenFdCount test can refer to correct test
526 // main.
527 #define ChildMain ChildFdCount
528 #define ChildMainString "ChildFdCount"
529 
530 // Command line flag name and file name used for synchronization.
531 const char kTempDirFlag[] = "temp-dir";
532 const char kSignalClosed[] = "closed";
533 
SignalEvent(const FilePath & signal_dir,const char * signal_file)534 bool SignalEvent(const FilePath& signal_dir, const char* signal_file) {
535   File file(signal_dir.AppendASCII(signal_file),
536             File::FLAG_CREATE | File::FLAG_WRITE);
537   return file.IsValid();
538 }
539 
540 // Check whether an event was signaled.
CheckEvent(const FilePath & signal_dir,const char * signal_file)541 bool CheckEvent(const FilePath& signal_dir, const char* signal_file) {
542   File file(signal_dir.AppendASCII(signal_file),
543             File::FLAG_OPEN | File::FLAG_READ);
544   return file.IsValid();
545 }
546 
547 // Busy-wait for an event to be signaled.
WaitForEvent(const FilePath & signal_dir,const char * signal_file)548 void WaitForEvent(const FilePath& signal_dir, const char* signal_file) {
549   while (!CheckEvent(signal_dir, signal_file))
550     PlatformThread::Sleep(TimeDelta::FromMilliseconds(10));
551 }
552 
553 // Subprocess to test the number of open file descriptors.
MULTIPROCESS_TEST_MAIN(ChildMain)554 MULTIPROCESS_TEST_MAIN(ChildMain) {
555   CommandLine* command_line = CommandLine::ForCurrentProcess();
556   const FilePath temp_path = command_line->GetSwitchValuePath(kTempDirFlag);
557   CHECK(DirectoryExists(temp_path));
558 
559   // Try to close all the file descriptors, so the open count goes to 0.
560   for (size_t i = 0; i < 1000; ++i)
561     close(i);
562   CHECK(SignalEvent(temp_path, kSignalClosed));
563 
564   // Wait to be terminated.
565   while (true)
566     PlatformThread::Sleep(TimeDelta::FromSeconds(1));
567   return 0;
568 }
569 
570 }  // namespace
571 
572 // ARC note: don't compile as SpawnMultiProcessTestChild brings in a lot of
573 // extra dependency.
574 #if !defined(OS_ANDROID) && !defined(__ANDROID__) && !defined(__ANDROID_HOST__)
TEST(ProcessMetricsTest,GetChildOpenFdCount)575 TEST(ProcessMetricsTest, GetChildOpenFdCount) {
576   ScopedTempDir temp_dir;
577   ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
578   const FilePath temp_path = temp_dir.GetPath();
579   CommandLine child_command_line(GetMultiProcessTestChildBaseCommandLine());
580   child_command_line.AppendSwitchPath(kTempDirFlag, temp_path);
581   Process child = SpawnMultiProcessTestChild(
582       ChildMainString, child_command_line, LaunchOptions());
583   ASSERT_TRUE(child.IsValid());
584   WaitForEvent(temp_path, kSignalClosed);
585 
586   std::unique_ptr<ProcessMetrics> metrics(
587       ProcessMetrics::CreateProcessMetrics(child.Handle()));
588   // Try a couple times to observe the child with 0 fds open.
589   // Sometimes we've seen that the child can have 1 remaining
590   // fd shortly after receiving the signal.  Potentially this
591   // is actually the signal file still open in the child.
592   int open_fds = -1;
593   for (int tries = 0; tries < 5; ++tries) {
594     open_fds = metrics->GetOpenFdCount();
595     if (!open_fds) {
596       break;
597     }
598     PlatformThread::Sleep(TimeDelta::FromMilliseconds(1));
599   }
600   EXPECT_EQ(0, open_fds);
601   ASSERT_TRUE(child.Terminate(0, true));
602 }
603 #endif  // !defined(__ANDROID__)
604 
605 #endif  // defined(OS_LINUX)
606 
607 #if defined(OS_ANDROID) || defined(OS_LINUX)
608 
TEST(ProcessMetricsTest,GetOpenFdCount)609 TEST(ProcessMetricsTest, GetOpenFdCount) {
610   std::unique_ptr<base::ProcessMetrics> metrics(
611       base::ProcessMetrics::CreateProcessMetrics(
612           base::GetCurrentProcessHandle()));
613   int fd_count = metrics->GetOpenFdCount();
614   EXPECT_GT(fd_count, 0);
615   ScopedFILE file(fopen("/proc/self/statm", "r"));
616   EXPECT_TRUE(file);
617   int new_fd_count = metrics->GetOpenFdCount();
618   EXPECT_GT(new_fd_count, 0);
619   EXPECT_EQ(new_fd_count, fd_count + 1);
620 }
621 
TEST(ProcessMetricsTestLinux,GetPageFaultCounts)622 TEST(ProcessMetricsTestLinux, GetPageFaultCounts) {
623   std::unique_ptr<base::ProcessMetrics> process_metrics(
624       base::ProcessMetrics::CreateProcessMetrics(
625           base::GetCurrentProcessHandle()));
626 
627   PageFaultCounts counts;
628   ASSERT_TRUE(process_metrics->GetPageFaultCounts(&counts));
629   ASSERT_GT(counts.minor, 0);
630   ASSERT_GE(counts.major, 0);
631 
632   {
633     // Allocate and touch memory. Touching it is required to make sure that the
634     // page fault count goes up, as memory is typically mapped lazily.
635     const size_t kMappedSize = 4 * (1 << 20);
636     SharedMemory memory;
637     ASSERT_TRUE(memory.CreateAndMapAnonymous(kMappedSize));
638     memset(memory.memory(), 42, kMappedSize);
639     memory.Unmap();
640   }
641 
642   PageFaultCounts counts_after;
643   ASSERT_TRUE(process_metrics->GetPageFaultCounts(&counts_after));
644   ASSERT_GT(counts_after.minor, counts.minor);
645   ASSERT_GE(counts_after.major, counts.major);
646 }
647 #endif  // defined(OS_ANDROID) || defined(OS_LINUX)
648 
649 }  // namespace debug
650 }  // namespace base
651