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 "gmock/gmock.h" 20 #include "gtest/gtest.h" 21 #include "perfetto/base/temp_file.h" 22 #include "src/base/test/test_task_runner.h" 23 #include "src/traced/probes/sys_stats/sys_stats_data_source.h" 24 #include "src/tracing/core/trace_writer_for_testing.h" 25 26 #include "perfetto/config/sys_stats/sys_stats_config.pb.h" 27 #include "perfetto/trace/trace_packet.pb.h" 28 #include "perfetto/trace/trace_packet.pbzero.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 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: 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 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 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 234 TEST_F(SysStatsDataSourceTest, Meminfo) { 235 using C = protos::MeminfoCounters; 236 protos::DataSourceConfig config; 237 config.mutable_sys_stats_config()->set_meminfo_period_ms(1); 238 config.mutable_sys_stats_config()->add_meminfo_counters(C::MEMINFO_MEM_TOTAL); 239 config.mutable_sys_stats_config()->add_meminfo_counters(C::MEMINFO_MEM_FREE); 240 config.mutable_sys_stats_config()->add_meminfo_counters( 241 C::MEMINFO_ACTIVE_ANON); 242 config.mutable_sys_stats_config()->add_meminfo_counters( 243 C::MEMINFO_INACTIVE_FILE); 244 config.mutable_sys_stats_config()->add_meminfo_counters(C::MEMINFO_CMA_FREE); 245 DataSourceConfig config_obj; 246 config_obj.FromProto(config); 247 auto data_source = GetSysStatsDataSource(config_obj); 248 249 WaitTick(data_source.get()); 250 251 std::unique_ptr<protos::TracePacket> packet = writer_raw_->ParseProto(); 252 ASSERT_TRUE(packet->has_sys_stats()); 253 const auto& sys_stats = packet->sys_stats(); 254 EXPECT_EQ(sys_stats.vmstat_size(), 0); 255 EXPECT_EQ(sys_stats.cpu_stat_size(), 0); 256 257 using KV = std::pair<int, uint64_t>; 258 std::vector<KV> kvs; 259 for (const auto& kv : sys_stats.meminfo()) 260 kvs.push_back({kv.key(), kv.value()}); 261 262 EXPECT_THAT(kvs, 263 UnorderedElementsAre(KV{C::MEMINFO_MEM_TOTAL, 3744240}, // 264 KV{C::MEMINFO_MEM_FREE, 73328}, // 265 KV{C::MEMINFO_ACTIVE_ANON, 1322636}, // 266 KV{C::MEMINFO_INACTIVE_FILE, 296320}, // 267 KV{C::MEMINFO_CMA_FREE, 60})); 268 } 269 270 TEST_F(SysStatsDataSourceTest, Vmstat) { 271 using C = protos::VmstatCounters; 272 protos::DataSourceConfig config; 273 config.mutable_sys_stats_config()->set_vmstat_period_ms(1); 274 config.mutable_sys_stats_config()->add_vmstat_counters( 275 C::VMSTAT_NR_FREE_PAGES); 276 config.mutable_sys_stats_config()->add_vmstat_counters(C::VMSTAT_PGACTIVATE); 277 config.mutable_sys_stats_config()->add_vmstat_counters( 278 C::VMSTAT_PGMIGRATE_FAIL); 279 DataSourceConfig config_obj; 280 config_obj.FromProto(config); 281 auto data_source = GetSysStatsDataSource(config_obj); 282 283 WaitTick(data_source.get()); 284 285 std::unique_ptr<protos::TracePacket> packet = writer_raw_->ParseProto(); 286 ASSERT_TRUE(packet->has_sys_stats()); 287 const auto& sys_stats = packet->sys_stats(); 288 EXPECT_EQ(sys_stats.meminfo_size(), 0); 289 EXPECT_EQ(sys_stats.cpu_stat_size(), 0); 290 291 using KV = std::pair<int, uint64_t>; 292 std::vector<KV> kvs; 293 for (const auto& kv : sys_stats.vmstat()) 294 kvs.push_back({kv.key(), kv.value()}); 295 296 EXPECT_THAT(kvs, UnorderedElementsAre(KV{C::VMSTAT_NR_FREE_PAGES, 16449}, // 297 KV{C::VMSTAT_PGACTIVATE, 11897892}, // 298 KV{C::VMSTAT_PGMIGRATE_FAIL, 3439})); 299 } 300 301 TEST_F(SysStatsDataSourceTest, StatAll) { 302 using C = protos::SysStatsConfig; 303 protos::DataSourceConfig config; 304 config.mutable_sys_stats_config()->set_stat_period_ms(1); 305 config.mutable_sys_stats_config()->add_stat_counters(C::STAT_CPU_TIMES); 306 config.mutable_sys_stats_config()->add_stat_counters(C::STAT_IRQ_COUNTS); 307 config.mutable_sys_stats_config()->add_stat_counters(C::STAT_SOFTIRQ_COUNTS); 308 config.mutable_sys_stats_config()->add_stat_counters(C::STAT_FORK_COUNT); 309 DataSourceConfig config_obj; 310 config_obj.FromProto(config); 311 auto data_source = GetSysStatsDataSource(config_obj); 312 313 WaitTick(data_source.get()); 314 315 std::unique_ptr<protos::TracePacket> packet = writer_raw_->ParseProto(); 316 ASSERT_TRUE(packet); 317 ASSERT_TRUE(packet->has_sys_stats()); 318 const auto& sys_stats = packet->sys_stats(); 319 EXPECT_EQ(sys_stats.meminfo_size(), 0); 320 EXPECT_EQ(sys_stats.vmstat_size(), 0); 321 322 ASSERT_EQ(sys_stats.cpu_stat_size(), 8); 323 EXPECT_EQ(sys_stats.cpu_stat(0).user_ns(), 762178 * 10000000ull); 324 EXPECT_EQ(sys_stats.cpu_stat(0).system_mode_ns(), 902284 * 10000000ull); 325 EXPECT_EQ(sys_stats.cpu_stat(0).softirq_ns(), 68262 * 10000000ull); 326 EXPECT_EQ(sys_stats.cpu_stat(7).user_ns(), 180484 * 10000000ull); 327 EXPECT_EQ(sys_stats.cpu_stat(7).system_mode_ns(), 139874 * 10000000ull); 328 EXPECT_EQ(sys_stats.cpu_stat(7).softirq_ns(), 13407 * 10000000ull); 329 330 EXPECT_EQ(sys_stats.num_forks(), 243320); 331 332 EXPECT_EQ(sys_stats.num_irq_total(), 238128517); 333 ASSERT_EQ(sys_stats.num_irq_size(), 793); 334 EXPECT_EQ(sys_stats.num_irq(0).count(), 0); 335 EXPECT_EQ(sys_stats.num_irq(3).count(), 63500984); 336 EXPECT_EQ(sys_stats.num_irq(790).count(), 680); 337 338 EXPECT_EQ(sys_stats.num_softirq_total(), 84611084); 339 ASSERT_EQ(sys_stats.num_softirq_size(), 10); 340 EXPECT_EQ(sys_stats.num_softirq(0).count(), 10220177); 341 EXPECT_EQ(sys_stats.num_softirq(9).count(), 16443195); 342 343 EXPECT_EQ(sys_stats.num_softirq_total(), 84611084); 344 } 345 346 TEST_F(SysStatsDataSourceTest, StatForksOnly) { 347 using C = protos::SysStatsConfig; 348 protos::DataSourceConfig config; 349 config.mutable_sys_stats_config()->set_stat_period_ms(1); 350 config.mutable_sys_stats_config()->add_stat_counters(C::STAT_FORK_COUNT); 351 DataSourceConfig config_obj; 352 config_obj.FromProto(config); 353 auto data_source = GetSysStatsDataSource(config_obj); 354 355 WaitTick(data_source.get()); 356 357 std::unique_ptr<protos::TracePacket> packet = writer_raw_->ParseProto(); 358 ASSERT_TRUE(packet->has_sys_stats()); 359 const auto& sys_stats = packet->sys_stats(); 360 EXPECT_EQ(sys_stats.meminfo_size(), 0); 361 EXPECT_EQ(sys_stats.vmstat_size(), 0); 362 ASSERT_EQ(sys_stats.cpu_stat_size(), 0); 363 EXPECT_EQ(sys_stats.num_forks(), 243320); 364 EXPECT_EQ(sys_stats.num_irq_total(), 0); 365 ASSERT_EQ(sys_stats.num_irq_size(), 0); 366 EXPECT_EQ(sys_stats.num_softirq_total(), 0); 367 ASSERT_EQ(sys_stats.num_softirq_size(), 0); 368 } 369 370 } // namespace 371 } // namespace perfetto 372