1 /*
2  * Copyright (C) 2018 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include <unistd.h>
18 
19 #include "perfetto/ext/base/temp_file.h"
20 #include "src/base/test/test_task_runner.h"
21 #include "src/traced/probes/sys_stats/sys_stats_data_source.h"
22 #include "src/tracing/core/trace_writer_for_testing.h"
23 #include "test/gtest_and_gmock.h"
24 
25 #include "protos/perfetto/common/sys_stats_counters.gen.h"
26 #include "protos/perfetto/config/data_source_config.gen.h"
27 #include "protos/perfetto/config/sys_stats/sys_stats_config.gen.h"
28 #include "protos/perfetto/trace/sys_stats/sys_stats.gen.h"
29 
30 using ::testing::_;
31 using ::testing::Invoke;
32 using ::testing::Return;
33 using ::testing::UnorderedElementsAre;
34 
35 namespace perfetto {
36 namespace {
37 
38 const char kMockMeminfo[] = R"(
39 MemTotal:        3744240 kB
40 MemFree:           73328 kB
41 MemAvailable:     629896 kB
42 Buffers:           19296 kB
43 Cached:           731032 kB
44 SwapCached:         4936 kB
45 Active:          1616348 kB
46 Inactive:         745492 kB
47 Active(anon):    1322636 kB
48 Inactive(anon):   449172 kB
49 Active(file):     293712 kB
50 Inactive(file):   296320 kB
51 Unevictable:      142152 kB
52 Mlocked:          142152 kB
53 SwapTotal:        524284 kB
54 SwapFree:            128 kB
55 Dirty:                 0 kB
56 Writeback:             0 kB
57 AnonPages:       1751140 kB
58 Mapped:           508372 kB
59 Shmem:             18604 kB
60 Slab:             240352 kB
61 SReclaimable:      64684 kB
62 SUnreclaim:       175668 kB
63 KernelStack:       62672 kB
64 PageTables:        70108 kB
65 NFS_Unstable:          0 kB
66 Bounce:                0 kB
67 WritebackTmp:          0 kB
68 CommitLimit:     2396404 kB
69 Committed_AS:   81911488 kB
70 VmallocTotal:   258867136 kB
71 VmallocUsed:           0 kB
72 VmallocChunk:          0 kB
73 CmaTotal:         196608 kB
74 CmaFree:              60 kB)";
75 
76 const char kMockVmstat[] = R"(
77 nr_free_pages 16449
78 nr_alloc_batch 79
79 nr_inactive_anon 112545
80 nr_active_anon 322027
81 nr_inactive_file 75904
82 nr_active_file 87939
83 nr_unevictable 35538
84 nr_mlock 35538
85 nr_anon_pages 429005
86 nr_mapped 125844
87 nr_file_pages 205523
88 nr_dirty 23
89 nr_writeback 0
90 nr_slab_reclaimable 15840
91 nr_slab_unreclaimable 43912
92 nr_page_table_pages 17158
93 nr_kernel_stack 3822
94 nr_overhead 0
95 nr_unstable 0
96 nr_bounce 0
97 nr_vmscan_write 558690
98 nr_vmscan_immediate_reclaim 14853
99 nr_writeback_temp 0
100 nr_isolated_anon 0
101 nr_isolated_file 0
102 nr_shmem 5027
103 nr_dirtied 6732417
104 nr_written 6945513
105 nr_pages_scanned 0
106 workingset_refault 32784684
107 workingset_activate 8200928
108 workingset_nodereclaim 0
109 nr_anon_transparent_hugepages 0
110 nr_free_cma 0
111 nr_swapcache 1254
112 nr_dirty_threshold 33922
113 nr_dirty_background_threshold 8449
114 pgpgin 161257156
115 pgpgout 35973852
116 pgpgoutclean 37181384
117 pswpin 185308
118 pswpout 557662
119 pgalloc_dma 79259070
120 pgalloc_normal 88265512
121 pgalloc_movable 0
122 pgfree 175051592
123 pgactivate 11897892
124 pgdeactivate 20412230
125 pgfault 181696234
126 pgmajfault 1060871
127 pgrefill_dma 12970047
128 pgrefill_normal 14391564
129 pgrefill_movable 0
130 pgsteal_kswapd_dma 19471476
131 pgsteal_kswapd_normal 21138380
132 pgsteal_kswapd_movable 0
133 pgsteal_direct_dma 40625
134 pgsteal_direct_normal 50912
135 pgsteal_direct_movable 0
136 pgscan_kswapd_dma 23544417
137 pgscan_kswapd_normal 25623715
138 pgscan_kswapd_movable 0
139 pgscan_direct_dma 50369
140 pgscan_direct_normal 66284
141 pgscan_direct_movable 0
142 pgscan_direct_throttle 0
143 pginodesteal 0
144 slabs_scanned 39582828
145 kswapd_inodesteal 110199
146 kswapd_low_wmark_hit_quickly 21321
147 kswapd_high_wmark_hit_quickly 4112
148 pageoutrun 37666
149 allocstall 1587
150 pgrotated 12086
151 drop_pagecache 0
152 drop_slab 0
153 pgmigrate_success 5923482
154 pgmigrate_fail 3439
155 compact_migrate_scanned 92906456
156 compact_free_scanned 467077168
157 compact_isolated 13456528
158 compact_stall 197
159 compact_fail 42
160 compact_success 155
161 compact_daemon_wake 2131
162 unevictable_pgs_culled 50170
163 unevictable_pgs_scanned 0
164 unevictable_pgs_rescued 14640
165 unevictable_pgs_mlocked 52520
166 unevictable_pgs_munlocked 14640
167 unevictable_pgs_cleared 2342
168 unevictable_pgs_stranded 2342)";
169 
170 const char kMockStat[] = R"(
171 cpu  2655987 822682 2352153 8801203 41917 322733 175055 0 0 0
172 cpu0 762178 198125 902284 8678856 41716 152974 68262 0 0 0
173 cpu1 613833 243394 504323 15194 96 60625 28785 0 0 0
174 cpu2 207349 95060 248856 17351 42 32148 26108 0 0 0
175 cpu3 138474 92158 174852 17537 48 25076 25035 0 0 0
176 cpu4 278720 34689 141048 18117 1 20782 5873 0 0 0
177 cpu5 235376 33907 85098 18278 2 10049 3774 0 0 0
178 cpu6 239568 67149 155814 17890 5 11518 3807 0 0 0
179 cpu7 180484 58196 139874 17975 3 9556 13407 0 0 0
180 intr 238128517 0 0 0 63500984 0 6253792 6 4 5 0 0 0 0 0 0 0 160331 0 0 14 0 0 0 0 0 0 0 0 0 0 0 20430 2279 11 11 83272 0 0 0 0 0 0 0 5754 220829 0 154753 908545 1824602 7314228 0 0 0 6898259 0 0 10 0 0 2 0 0 0 0 0 0 0 42 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 6 575816 1447531 134022 0 0 0 0 0 435008 319921 2755476 0 0 0 0 91 310212 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 6 4 0 0 545 901 554 9 3377 4184 12 10 588851 0 2 1109045 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 6 8 0 0 0 0 0 0 0 0 0 0 0 0 497 0 0 0 0 0 26172 0 0 0 0 0 0 0 1362 0 0 0 0 0 0 0 424 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 23427 0 0 0 0 1 1298 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 108 0 0 0 0 86 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1784935 407979 2140 10562241 52374 74699 6976 84926 222 169088 0 0 0 0 174 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2789 51543 0 83 0 0 0 0 0 0 0 0 0 0 0 0 0 0 8 8 0 13 11 17 1393 0 0 0 0 0 0 0 0 0 0 26 0 0 2 106 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 11150 0 13 0 1 390 6 0 6 4 0 0 0 0 352 284743 2 0 0 24 3 0 3 0 0 0 12 0 668788 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 680 0 0
181 ctxt 373122860
182 btime 1536912218
183 processes 243320
184 procs_running 1
185 procs_blocked 0
186 softirq 84611084 10220177 28299167 155083 3035679 6390543 66234 4396819 15604187 0 16443195)";
187 
MockOpenReadOnly(const char * path)188 base::ScopedFile MockOpenReadOnly(const char* path) {
189   base::TempFile tmp_ = base::TempFile::CreateUnlinked();
190   if (!strcmp(path, "/proc/meminfo")) {
191     EXPECT_GT(pwrite(tmp_.fd(), kMockMeminfo, strlen(kMockMeminfo), 0), 0);
192   } else if (!strcmp(path, "/proc/vmstat")) {
193     EXPECT_GT(pwrite(tmp_.fd(), kMockVmstat, strlen(kMockVmstat), 0), 0);
194   } else if (!strcmp(path, "/proc/stat")) {
195     EXPECT_GT(pwrite(tmp_.fd(), kMockStat, strlen(kMockStat), 0), 0);
196   } else {
197     PERFETTO_FATAL("Unexpected file opened %s", path);
198   }
199   return tmp_.ReleaseFD();
200 }
201 
202 class SysStatsDataSourceTest : public ::testing::Test {
203  protected:
GetSysStatsDataSource(const DataSourceConfig & cfg)204   std::unique_ptr<SysStatsDataSource> GetSysStatsDataSource(
205       const DataSourceConfig& cfg) {
206     auto writer =
207         std::unique_ptr<TraceWriterForTesting>(new TraceWriterForTesting());
208     writer_raw_ = writer.get();
209     auto instance = std::unique_ptr<SysStatsDataSource>(new SysStatsDataSource(
210         &task_runner_, 0, std::move(writer), cfg, MockOpenReadOnly));
211     instance->set_ns_per_user_hz_for_testing(1000000000ull / 100);  // 100 Hz.
212     instance->Start();
213     return instance;
214   }
215 
Poller(SysStatsDataSource * ds,std::function<void ()> checkpoint)216   void Poller(SysStatsDataSource* ds, std::function<void()> checkpoint) {
217     if (ds->tick_for_testing())
218       checkpoint();
219     else
220       task_runner_.PostDelayedTask(
221           [ds, checkpoint, this] { Poller(ds, checkpoint); }, 1);
222   }
223 
WaitTick(SysStatsDataSource * data_source)224   void WaitTick(SysStatsDataSource* data_source) {
225     auto checkpoint = task_runner_.CreateCheckpoint("on_tick");
226     Poller(data_source, checkpoint);
227     task_runner_.RunUntilCheckpoint("on_tick");
228   }
229 
230   TraceWriterForTesting* writer_raw_ = nullptr;
231   base::TestTaskRunner task_runner_;
232 };
233 
TEST_F(SysStatsDataSourceTest,Meminfo)234 TEST_F(SysStatsDataSourceTest, Meminfo) {
235   using C = protos::gen::MeminfoCounters;
236   DataSourceConfig config;
237   protos::gen::SysStatsConfig sys_cfg;
238   sys_cfg.set_meminfo_period_ms(10);
239   sys_cfg.add_meminfo_counters(C::MEMINFO_MEM_TOTAL);
240   sys_cfg.add_meminfo_counters(C::MEMINFO_MEM_FREE);
241   sys_cfg.add_meminfo_counters(C::MEMINFO_ACTIVE_ANON);
242   sys_cfg.add_meminfo_counters(C::MEMINFO_INACTIVE_FILE);
243   sys_cfg.add_meminfo_counters(C::MEMINFO_CMA_FREE);
244   config.set_sys_stats_config_raw(sys_cfg.SerializeAsString());
245   auto data_source = GetSysStatsDataSource(config);
246 
247   WaitTick(data_source.get());
248 
249   protos::gen::TracePacket packet = writer_raw_->GetOnlyTracePacket();
250   ASSERT_TRUE(packet.has_sys_stats());
251   const auto& sys_stats = packet.sys_stats();
252   EXPECT_EQ(sys_stats.vmstat_size(), 0);
253   EXPECT_EQ(sys_stats.cpu_stat_size(), 0);
254 
255   using KV = std::pair<int, uint64_t>;
256   std::vector<KV> kvs;
257   for (const auto& kv : sys_stats.meminfo())
258     kvs.push_back({kv.key(), kv.value()});
259 
260   EXPECT_THAT(kvs,
261               UnorderedElementsAre(KV{C::MEMINFO_MEM_TOTAL, 3744240},     //
262                                    KV{C::MEMINFO_MEM_FREE, 73328},        //
263                                    KV{C::MEMINFO_ACTIVE_ANON, 1322636},   //
264                                    KV{C::MEMINFO_INACTIVE_FILE, 296320},  //
265                                    KV{C::MEMINFO_CMA_FREE, 60}));
266 }
267 
TEST_F(SysStatsDataSourceTest,MeminfoAll)268 TEST_F(SysStatsDataSourceTest, MeminfoAll) {
269   DataSourceConfig config;
270   protos::gen::SysStatsConfig sys_cfg;
271   sys_cfg.set_meminfo_period_ms(10);
272   config.set_sys_stats_config_raw(sys_cfg.SerializeAsString());
273   auto data_source = GetSysStatsDataSource(config);
274 
275   WaitTick(data_source.get());
276 
277   protos::gen::TracePacket packet = writer_raw_->GetOnlyTracePacket();
278   ASSERT_TRUE(packet.has_sys_stats());
279   const auto& sys_stats = packet.sys_stats();
280   EXPECT_EQ(sys_stats.vmstat_size(), 0);
281   EXPECT_EQ(sys_stats.cpu_stat_size(), 0);
282   EXPECT_GE(sys_stats.meminfo_size(), 10);
283 }
284 
TEST_F(SysStatsDataSourceTest,Vmstat)285 TEST_F(SysStatsDataSourceTest, Vmstat) {
286   using C = protos::gen::VmstatCounters;
287   DataSourceConfig config;
288   protos::gen::SysStatsConfig sys_cfg;
289   sys_cfg.set_vmstat_period_ms(10);
290   sys_cfg.add_vmstat_counters(C::VMSTAT_NR_FREE_PAGES);
291   sys_cfg.add_vmstat_counters(C::VMSTAT_PGACTIVATE);
292   sys_cfg.add_vmstat_counters(C::VMSTAT_PGMIGRATE_FAIL);
293   config.set_sys_stats_config_raw(sys_cfg.SerializeAsString());
294   auto data_source = GetSysStatsDataSource(config);
295 
296   WaitTick(data_source.get());
297 
298   protos::gen::TracePacket packet = writer_raw_->GetOnlyTracePacket();
299   ASSERT_TRUE(packet.has_sys_stats());
300   const auto& sys_stats = packet.sys_stats();
301   EXPECT_EQ(sys_stats.meminfo_size(), 0);
302   EXPECT_EQ(sys_stats.cpu_stat_size(), 0);
303 
304   using KV = std::pair<int, uint64_t>;
305   std::vector<KV> kvs;
306   for (const auto& kv : sys_stats.vmstat())
307     kvs.push_back({kv.key(), kv.value()});
308 
309   EXPECT_THAT(kvs, UnorderedElementsAre(KV{C::VMSTAT_NR_FREE_PAGES, 16449},  //
310                                         KV{C::VMSTAT_PGACTIVATE, 11897892},  //
311                                         KV{C::VMSTAT_PGMIGRATE_FAIL, 3439}));
312 }
313 
TEST_F(SysStatsDataSourceTest,VmstatAll)314 TEST_F(SysStatsDataSourceTest, VmstatAll) {
315   DataSourceConfig config;
316   protos::gen::SysStatsConfig sys_cfg;
317   sys_cfg.set_vmstat_period_ms(10);
318   config.set_sys_stats_config_raw(sys_cfg.SerializeAsString());
319   auto data_source = GetSysStatsDataSource(config);
320 
321   WaitTick(data_source.get());
322 
323   protos::gen::TracePacket packet = writer_raw_->GetOnlyTracePacket();
324   ASSERT_TRUE(packet.has_sys_stats());
325   const auto& sys_stats = packet.sys_stats();
326   EXPECT_EQ(sys_stats.meminfo_size(), 0);
327   EXPECT_EQ(sys_stats.cpu_stat_size(), 0);
328   EXPECT_GE(sys_stats.vmstat_size(), 10);
329 }
330 
TEST_F(SysStatsDataSourceTest,StatAll)331 TEST_F(SysStatsDataSourceTest, StatAll) {
332   DataSourceConfig config;
333   protos::gen::SysStatsConfig sys_cfg;
334   sys_cfg.set_stat_period_ms(10);
335   config.set_sys_stats_config_raw(sys_cfg.SerializeAsString());
336   auto data_source = GetSysStatsDataSource(config);
337 
338   WaitTick(data_source.get());
339 
340   protos::gen::TracePacket packet = writer_raw_->GetOnlyTracePacket();
341   ASSERT_TRUE(packet.has_sys_stats());
342   const auto& sys_stats = packet.sys_stats();
343   EXPECT_EQ(sys_stats.meminfo_size(), 0);
344   EXPECT_EQ(sys_stats.vmstat_size(), 0);
345 
346   ASSERT_EQ(sys_stats.cpu_stat_size(), 8);
347   EXPECT_EQ(sys_stats.cpu_stat()[0].user_ns(), 762178 * 10000000ull);
348   EXPECT_EQ(sys_stats.cpu_stat()[0].system_mode_ns(), 902284 * 10000000ull);
349   EXPECT_EQ(sys_stats.cpu_stat()[0].softirq_ns(), 68262 * 10000000ull);
350   EXPECT_EQ(sys_stats.cpu_stat()[7].user_ns(), 180484 * 10000000ull);
351   EXPECT_EQ(sys_stats.cpu_stat()[7].system_mode_ns(), 139874 * 10000000ull);
352   EXPECT_EQ(sys_stats.cpu_stat()[7].softirq_ns(), 13407 * 10000000ull);
353 
354   EXPECT_EQ(sys_stats.num_forks(), 243320u);
355 
356   EXPECT_EQ(sys_stats.num_irq_total(), 238128517u);
357   ASSERT_EQ(sys_stats.num_irq_size(), 102);
358   EXPECT_EQ(sys_stats.num_irq()[0].count(), 63500984u);
359   EXPECT_EQ(sys_stats.num_irq()[0].irq(), 3);
360   EXPECT_EQ(sys_stats.num_irq()[1].count(), 6253792u);
361   EXPECT_EQ(sys_stats.num_irq()[1].irq(), 5);
362   EXPECT_EQ(sys_stats.num_irq()[101].count(), 680u);
363 
364   EXPECT_EQ(sys_stats.num_softirq_total(), 84611084u);
365   ASSERT_EQ(sys_stats.num_softirq_size(), 10);
366   EXPECT_EQ(sys_stats.num_softirq()[0].count(), 10220177u);
367   EXPECT_EQ(sys_stats.num_softirq()[9].count(), 16443195u);
368 
369   EXPECT_EQ(sys_stats.num_softirq_total(), 84611084u);
370 }
371 
TEST_F(SysStatsDataSourceTest,StatForksOnly)372 TEST_F(SysStatsDataSourceTest, StatForksOnly) {
373   protos::gen::SysStatsConfig cfg;
374   cfg.set_stat_period_ms(10);
375   cfg.add_stat_counters(protos::gen::SysStatsConfig::STAT_FORK_COUNT);
376   DataSourceConfig config_obj;
377   config_obj.set_sys_stats_config_raw(cfg.SerializeAsString());
378   auto data_source = GetSysStatsDataSource(config_obj);
379 
380   WaitTick(data_source.get());
381 
382   protos::gen::TracePacket packet = writer_raw_->GetOnlyTracePacket();
383   ASSERT_TRUE(packet.has_sys_stats());
384   const auto& sys_stats = packet.sys_stats();
385   EXPECT_EQ(sys_stats.meminfo_size(), 0);
386   EXPECT_EQ(sys_stats.vmstat_size(), 0);
387   ASSERT_EQ(sys_stats.cpu_stat_size(), 0);
388   EXPECT_EQ(sys_stats.num_forks(), 243320u);
389   EXPECT_EQ(sys_stats.num_irq_total(), 0u);
390   ASSERT_EQ(sys_stats.num_irq_size(), 0);
391   EXPECT_EQ(sys_stats.num_softirq_total(), 0u);
392   ASSERT_EQ(sys_stats.num_softirq_size(), 0);
393 }
394 
395 }  // namespace
396 }  // namespace perfetto
397