xref: /aosp_15_r20/external/perfetto/src/traced/probes/sys_stats/sys_stats_data_source_unittest.cc (revision 6dbdd20afdafa5e3ca9b8809fa73465d530080dc)
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/file_utils.h"
20 #include "perfetto/ext/base/string_utils.h"
21 #include "perfetto/ext/base/temp_file.h"
22 #include "src/base/test/test_task_runner.h"
23 #include "src/traced/probes/common/cpu_freq_info_for_testing.h"
24 #include "src/traced/probes/sys_stats/sys_stats_data_source.h"
25 #include "src/tracing/core/trace_writer_for_testing.h"
26 #include "test/gtest_and_gmock.h"
27 
28 #include "protos/perfetto/common/sys_stats_counters.gen.h"
29 #include "protos/perfetto/config/data_source_config.gen.h"
30 #include "protos/perfetto/config/sys_stats/sys_stats_config.gen.h"
31 #include "protos/perfetto/trace/sys_stats/sys_stats.gen.h"
32 
33 using ::testing::_;
34 using ::testing::Invoke;
35 using ::testing::Return;
36 using ::testing::UnorderedElementsAre;
37 
38 namespace perfetto {
39 namespace {
40 
41 const char kMockMeminfo[] = R"(
42 MemTotal:        3744240 kB
43 MemFree:           73328 kB
44 MemAvailable:     629896 kB
45 Buffers:           19296 kB
46 Cached:           731032 kB
47 SwapCached:         4936 kB
48 Active:          1616348 kB
49 Inactive:         745492 kB
50 Active(anon):    1322636 kB
51 Inactive(anon):   449172 kB
52 Active(file):     293712 kB
53 Inactive(file):   296320 kB
54 Unevictable:      142152 kB
55 Mlocked:          142152 kB
56 SwapTotal:        524284 kB
57 SwapFree:            128 kB
58 Dirty:                 0 kB
59 Writeback:             0 kB
60 AnonPages:       1751140 kB
61 Mapped:           508372 kB
62 Shmem:             18604 kB
63 Slab:             240352 kB
64 SReclaimable:      64684 kB
65 SUnreclaim:       175668 kB
66 KernelStack:       62672 kB
67 PageTables:        70108 kB
68 NFS_Unstable:          0 kB
69 Bounce:                0 kB
70 WritebackTmp:          0 kB
71 CommitLimit:     2396404 kB
72 Committed_AS:   81911488 kB
73 VmallocTotal:   258867136 kB
74 VmallocUsed:           0 kB
75 VmallocChunk:          0 kB
76 CmaTotal:         196608 kB
77 CmaFree:              60 kB)";
78 
79 const char kMockVmstat[] = R"(
80 nr_free_pages 16449
81 nr_alloc_batch 79
82 nr_inactive_anon 112545
83 nr_active_anon 322027
84 nr_inactive_file 75904
85 nr_active_file 87939
86 nr_unevictable 35538
87 nr_mlock 35538
88 nr_anon_pages 429005
89 nr_mapped 125844
90 nr_file_pages 205523
91 nr_dirty 23
92 nr_writeback 0
93 nr_slab_reclaimable 15840
94 nr_slab_unreclaimable 43912
95 nr_page_table_pages 17158
96 nr_kernel_stack 3822
97 nr_overhead 0
98 nr_unstable 0
99 nr_bounce 0
100 nr_vmscan_write 558690
101 nr_vmscan_immediate_reclaim 14853
102 nr_writeback_temp 0
103 nr_isolated_anon 0
104 nr_isolated_file 0
105 nr_shmem 5027
106 nr_dirtied 6732417
107 nr_written 6945513
108 nr_pages_scanned 0
109 workingset_refault 32784684
110 workingset_activate 8200928
111 workingset_nodereclaim 0
112 nr_anon_transparent_hugepages 0
113 nr_free_cma 0
114 nr_swapcache 1254
115 nr_dirty_threshold 33922
116 nr_dirty_background_threshold 8449
117 pgpgin 161257156
118 pgpgout 35973852
119 pgpgoutclean 37181384
120 pswpin 185308
121 pswpout 557662
122 pgalloc_dma 79259070
123 pgalloc_normal 88265512
124 pgalloc_movable 0
125 pgfree 175051592
126 pgactivate 11897892
127 pgdeactivate 20412230
128 pgfault 181696234
129 pgmajfault 1060871
130 pgrefill_dma 12970047
131 pgrefill_normal 14391564
132 pgrefill_movable 0
133 pgsteal_kswapd_dma 19471476
134 pgsteal_kswapd_normal 21138380
135 pgsteal_kswapd_movable 0
136 pgsteal_direct 91537
137 pgsteal_direct_dma 40625
138 pgsteal_direct_normal 50912
139 pgsteal_direct_movable 0
140 pgscan_kswapd_dma 23544417
141 pgscan_kswapd_normal 25623715
142 pgscan_kswapd_movable 0
143 pgscan_direct_dma 50369
144 pgscan_direct_normal 66284
145 pgscan_direct_movable 0
146 pgscan_direct_throttle 0
147 pginodesteal 0
148 slabs_scanned 39582828
149 kswapd_inodesteal 110199
150 kswapd_low_wmark_hit_quickly 21321
151 kswapd_high_wmark_hit_quickly 4112
152 pageoutrun 37666
153 allocstall 1587
154 pgrotated 12086
155 drop_pagecache 0
156 drop_slab 0
157 pgmigrate_success 5923482
158 pgmigrate_fail 3439
159 compact_migrate_scanned 92906456
160 compact_free_scanned 467077168
161 compact_isolated 13456528
162 compact_stall 197
163 compact_fail 42
164 compact_success 155
165 compact_daemon_wake 2131
166 unevictable_pgs_culled 50170
167 unevictable_pgs_scanned 0
168 unevictable_pgs_rescued 14640
169 unevictable_pgs_mlocked 52520
170 unevictable_pgs_munlocked 14640
171 unevictable_pgs_cleared 2342
172 unevictable_pgs_stranded 2342
173 vma_lock_abort 1173728)";
174 
175 const char kMockStat[] = R"(
176 cpu  2655987 822682 2352153 8801203 41917 322733 175055 0 0 0
177 cpu0 762178 198125 902284 8678856 41716 152974 68262 0 0 0
178 cpu1 613833 243394 504323 15194 96 60625 28785 0 0 0
179 cpu2 207349 95060 248856 17351 42 32148 26108 0 0 0
180 cpu3 138474 92158 174852 17537 48 25076 25035 0 0 0
181 cpu4 278720 34689 141048 18117 1 20782 5873 0 0 0
182 cpu5 235376 33907 85098 18278 2 10049 3774 0 0 0
183 cpu6 239568 67149 155814 17890 5 11518 3807 0 0 0
184 cpu7 180484 58196 139874 17975 3 9556 13407 0 0 0
185 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
186 ctxt 373122860
187 btime 1536912218
188 processes 243320
189 procs_running 1
190 procs_blocked 0
191 softirq 84611084 10220177 28299167 155083 3035679 6390543 66234 4396819 15604187 0 16443195)";
192 
193 const char kMockBuddy[] = R"(
194 Node 0, zone  DMA      2743  1659  2063  685   27   4  0  0  0  0  0
195 Node 0, zone  Normal   143   744   89    1080  105  1  0  2  0  2  2
196 Node 0, zone  HighMem  345   90    156   3     5    2  0  0  0  0  0
197 Node 1, zone  Normal   233   123   453   10    5    1  0  2  0  0  3)";
198 
199 const char kDevfreq1[] = "1000000";
200 const char kDevfreq2[] = "20000000";
201 
202 const char kMockDiskStat[] = R"(
203  253       0 zram0 13886 0 111088 128 57298 0 458384 48 0 15248 176 0 0 0 0 0 0
204    8       0 sda 54133 5368 8221736 75929 30333 1157434 9599744 143190 0 63672 249858 9595 0 2160072 19411 6649 11327
205    8       1 sda1 18 6 632 7 39 49 704 92 0 156 100 0 0 0 0 0 0)";
206 
207 const char kMockPsi[] = R"(
208 some avg10=23.10 avg60=5.06 avg300=15.10 total=417963
209 full avg10=9.00 avg60=19.20 avg300=3.23 total=205933)";
210 
211 const uint64_t kMockThermalTemp = 25000;
212 const char kMockThermalType[] = "TSR0";
213 const uint64_t kMockCpuIdleStateTime = 10000;
214 const char kMockCpuIdleStateName[] = "MOCK_STATE_NAME";
215 const uint64_t kMockIntelGpuFreq = 300;
216 // kMockAMDGpuFreq whitespace is intentional.
217 const char kMockAMDGpuFreq[] = R"(
218 0: 200Mhz
219 1: 400Mhz *
220 2: 2000Mhz
221 )";
222 class TestSysStatsDataSource : public SysStatsDataSource {
223  public:
TestSysStatsDataSource(base::TaskRunner * task_runner,TracingSessionID id,std::unique_ptr<TraceWriter> writer,const DataSourceConfig & config,std::unique_ptr<CpuFreqInfo> cpu_freq_info,OpenFunction open_fn)224   TestSysStatsDataSource(base::TaskRunner* task_runner,
225                          TracingSessionID id,
226                          std::unique_ptr<TraceWriter> writer,
227                          const DataSourceConfig& config,
228                          std::unique_ptr<CpuFreqInfo> cpu_freq_info,
229                          OpenFunction open_fn)
230       : SysStatsDataSource(task_runner,
231                            id,
232                            std::move(writer),
233                            config,
234                            std::move(cpu_freq_info),
235                            open_fn) {}
236 
237   MOCK_METHOD(base::ScopedDir,
238               OpenDirAndLogOnErrorOnce,
239               (const std::string& dir_path, bool* already_logged),
240               (override));
241   MOCK_METHOD(const char*,
242               ReadDevfreqCurFreq,
243               (const std::string& deviceName),
244               (override));
245   MOCK_METHOD(std::optional<uint64_t>,
246               ReadFileToUInt64,
247               (const std::string& name),
248               (override));
249   MOCK_METHOD(std::optional<std::string>,
250               ReadFileToString,
251               (const std::string& name),
252               (override));
GetDevfreqErrorLoggedAddress()253   bool* GetDevfreqErrorLoggedAddress() { return &devfreq_error_logged_; }
GetThermalErrorLoggedAddress()254   bool* GetThermalErrorLoggedAddress() { return &thermal_error_logged_; }
GetCpuIdleErrorLoggedAddress()255   bool* GetCpuIdleErrorLoggedAddress() { return &cpuidle_error_logged_; }
256 };
257 
MockOpenReadOnly(const char * path)258 base::ScopedFile MockOpenReadOnly(const char* path) {
259   base::TempFile tmp_ = base::TempFile::CreateUnlinked();
260   if (!strcmp(path, "/proc/meminfo")) {
261     EXPECT_GT(pwrite(tmp_.fd(), kMockMeminfo, strlen(kMockMeminfo), 0), 0);
262   } else if (!strcmp(path, "/proc/vmstat")) {
263     EXPECT_GT(pwrite(tmp_.fd(), kMockVmstat, strlen(kMockVmstat), 0), 0);
264   } else if (!strcmp(path, "/proc/stat")) {
265     EXPECT_GT(pwrite(tmp_.fd(), kMockStat, strlen(kMockStat), 0), 0);
266   } else if (!strcmp(path, "/proc/buddyinfo")) {
267     EXPECT_GT(pwrite(tmp_.fd(), kMockBuddy, strlen(kMockBuddy), 0), 0);
268   } else if (!strcmp(path, "/proc/diskstats")) {
269     EXPECT_GT(pwrite(tmp_.fd(), kMockDiskStat, strlen(kMockDiskStat), 0), 0);
270   } else if (base::StartsWith(path, "/proc/pressure/")) {
271     EXPECT_GT(pwrite(tmp_.fd(), kMockPsi, strlen(kMockPsi), 0), 0);
272   } else {
273     PERFETTO_FATAL("Unexpected file opened %s", path);
274   }
275   return tmp_.ReleaseFD();
276 }
277 
278 class SysStatsDataSourceTest : public ::testing::Test {
279  protected:
GetSysStatsDataSource(const DataSourceConfig & cfg)280   std::unique_ptr<TestSysStatsDataSource> GetSysStatsDataSource(
281       const DataSourceConfig& cfg) {
282     auto writer =
283         std::unique_ptr<TraceWriterForTesting>(new TraceWriterForTesting());
284     writer_raw_ = writer.get();
285     auto instance =
286         std::unique_ptr<TestSysStatsDataSource>(new TestSysStatsDataSource(
287             &task_runner_, 0, std::move(writer), cfg,
288             cpu_freq_info_for_testing_.GetInstance(), MockOpenReadOnly));
289     instance->set_ns_per_user_hz_for_testing(1000000000ull / 100);  // 100 Hz.
290     instance->Start();
291     return instance;
292   }
293 
Poller(SysStatsDataSource * ds,std::function<void ()> checkpoint)294   void Poller(SysStatsDataSource* ds, std::function<void()> checkpoint) {
295     if (ds->tick_for_testing())
296       checkpoint();
297     else
298       task_runner_.PostDelayedTask(
299           [ds, checkpoint, this] { Poller(ds, checkpoint); }, 1);
300   }
301 
WaitTick(SysStatsDataSource * data_source)302   void WaitTick(SysStatsDataSource* data_source) {
303     auto checkpoint = task_runner_.CreateCheckpoint("on_tick");
304     Poller(data_source, checkpoint);
305     task_runner_.RunUntilCheckpoint("on_tick");
306   }
307 
308   TraceWriterForTesting* writer_raw_ = nullptr;
309   base::TestTaskRunner task_runner_;
310   CpuFreqInfoForTesting cpu_freq_info_for_testing_;
311 };
312 
TEST_F(SysStatsDataSourceTest,Meminfo)313 TEST_F(SysStatsDataSourceTest, Meminfo) {
314   using C = protos::gen::MeminfoCounters;
315   DataSourceConfig config;
316   protos::gen::SysStatsConfig sys_cfg;
317   sys_cfg.set_meminfo_period_ms(10);
318   sys_cfg.add_meminfo_counters(C::MEMINFO_MEM_TOTAL);
319   sys_cfg.add_meminfo_counters(C::MEMINFO_MEM_FREE);
320   sys_cfg.add_meminfo_counters(C::MEMINFO_ACTIVE_ANON);
321   sys_cfg.add_meminfo_counters(C::MEMINFO_INACTIVE_FILE);
322   sys_cfg.add_meminfo_counters(C::MEMINFO_CMA_FREE);
323   config.set_sys_stats_config_raw(sys_cfg.SerializeAsString());
324   auto data_source = GetSysStatsDataSource(config);
325 
326   WaitTick(data_source.get());
327 
328   protos::gen::TracePacket packet = writer_raw_->GetOnlyTracePacket();
329   ASSERT_TRUE(packet.has_sys_stats());
330   const auto& sys_stats = packet.sys_stats();
331   EXPECT_EQ(sys_stats.vmstat_size(), 0);
332   EXPECT_EQ(sys_stats.buddy_info_size(), 0);
333   EXPECT_EQ(sys_stats.cpu_stat_size(), 0);
334   EXPECT_EQ(sys_stats.devfreq_size(), 0);
335 
336   using KV = std::pair<int, uint64_t>;
337   std::vector<KV> kvs;
338   for (const auto& kv : sys_stats.meminfo())
339     kvs.push_back({kv.key(), kv.value()});
340 
341   EXPECT_THAT(kvs,
342               UnorderedElementsAre(KV{C::MEMINFO_MEM_TOTAL, 3744240},     //
343                                    KV{C::MEMINFO_MEM_FREE, 73328},        //
344                                    KV{C::MEMINFO_ACTIVE_ANON, 1322636},   //
345                                    KV{C::MEMINFO_INACTIVE_FILE, 296320},  //
346                                    KV{C::MEMINFO_CMA_FREE, 60}));
347 }
348 
TEST_F(SysStatsDataSourceTest,MeminfoAll)349 TEST_F(SysStatsDataSourceTest, MeminfoAll) {
350   DataSourceConfig config;
351   protos::gen::SysStatsConfig sys_cfg;
352   sys_cfg.set_meminfo_period_ms(10);
353   config.set_sys_stats_config_raw(sys_cfg.SerializeAsString());
354   auto data_source = GetSysStatsDataSource(config);
355 
356   WaitTick(data_source.get());
357 
358   protos::gen::TracePacket packet = writer_raw_->GetOnlyTracePacket();
359   ASSERT_TRUE(packet.has_sys_stats());
360   const auto& sys_stats = packet.sys_stats();
361   EXPECT_EQ(sys_stats.vmstat_size(), 0);
362   EXPECT_EQ(sys_stats.buddy_info_size(), 0);
363   EXPECT_EQ(sys_stats.cpu_stat_size(), 0);
364   EXPECT_EQ(sys_stats.devfreq_size(), 0);
365   EXPECT_GE(sys_stats.meminfo_size(), 10);
366 }
367 
TEST_F(SysStatsDataSourceTest,Vmstat)368 TEST_F(SysStatsDataSourceTest, Vmstat) {
369   using C = protos::gen::VmstatCounters;
370   DataSourceConfig config;
371   protos::gen::SysStatsConfig sys_cfg;
372   sys_cfg.set_vmstat_period_ms(10);
373   sys_cfg.add_vmstat_counters(C::VMSTAT_NR_FREE_PAGES);
374   sys_cfg.add_vmstat_counters(C::VMSTAT_PGACTIVATE);
375   sys_cfg.add_vmstat_counters(C::VMSTAT_PGMIGRATE_FAIL);
376   sys_cfg.add_vmstat_counters(C::VMSTAT_PGSTEAL_DIRECT);
377   sys_cfg.add_vmstat_counters(C::VMSTAT_VMA_LOCK_ABORT);
378   config.set_sys_stats_config_raw(sys_cfg.SerializeAsString());
379   auto data_source = GetSysStatsDataSource(config);
380 
381   WaitTick(data_source.get());
382 
383   protos::gen::TracePacket packet = writer_raw_->GetOnlyTracePacket();
384   ASSERT_TRUE(packet.has_sys_stats());
385   const auto& sys_stats = packet.sys_stats();
386   EXPECT_EQ(sys_stats.meminfo_size(), 0);
387   EXPECT_EQ(sys_stats.cpu_stat_size(), 0);
388   EXPECT_EQ(sys_stats.devfreq_size(), 0);
389 
390   using KV = std::pair<int, uint64_t>;
391   std::vector<KV> kvs;
392   for (const auto& kv : sys_stats.vmstat())
393     kvs.push_back({kv.key(), kv.value()});
394 
395   EXPECT_THAT(kvs,
396               UnorderedElementsAre(KV{C::VMSTAT_NR_FREE_PAGES, 16449},    //
397                                    KV{C::VMSTAT_PGACTIVATE, 11897892},    //
398                                    KV{C::VMSTAT_PGMIGRATE_FAIL, 3439},    //
399                                    KV{C::VMSTAT_PGSTEAL_DIRECT, 91537},   //
400                                    KV{C::VMSTAT_VMA_LOCK_ABORT, 1173728}  //
401                                    ));
402 }
403 
TEST_F(SysStatsDataSourceTest,VmstatAll)404 TEST_F(SysStatsDataSourceTest, VmstatAll) {
405   DataSourceConfig config;
406   protos::gen::SysStatsConfig sys_cfg;
407   sys_cfg.set_vmstat_period_ms(10);
408   config.set_sys_stats_config_raw(sys_cfg.SerializeAsString());
409   auto data_source = GetSysStatsDataSource(config);
410 
411   WaitTick(data_source.get());
412 
413   protos::gen::TracePacket packet = writer_raw_->GetOnlyTracePacket();
414   ASSERT_TRUE(packet.has_sys_stats());
415   const auto& sys_stats = packet.sys_stats();
416   EXPECT_EQ(sys_stats.meminfo_size(), 0);
417   EXPECT_EQ(sys_stats.cpu_stat_size(), 0);
418   EXPECT_EQ(sys_stats.devfreq_size(), 0);
419   EXPECT_EQ(sys_stats.buddy_info_size(), 0);
420   EXPECT_GE(sys_stats.vmstat_size(), 10);
421 }
422 
TEST_F(SysStatsDataSourceTest,BuddyinfoAll)423 TEST_F(SysStatsDataSourceTest, BuddyinfoAll) {
424   DataSourceConfig config;
425   protos::gen::SysStatsConfig sys_cfg;
426   sys_cfg.set_buddyinfo_period_ms(10);
427   config.set_sys_stats_config_raw(sys_cfg.SerializeAsString());
428   auto data_source = GetSysStatsDataSource(config);
429 
430   WaitTick(data_source.get());
431 
432   protos::gen::TracePacket packet = writer_raw_->GetOnlyTracePacket();
433   ASSERT_TRUE(packet.has_sys_stats());
434   const auto& sys_stats = packet.sys_stats();
435   EXPECT_EQ(sys_stats.meminfo_size(), 0);
436   EXPECT_EQ(sys_stats.cpu_stat_size(), 0);
437   EXPECT_EQ(sys_stats.devfreq_size(), 0);
438   EXPECT_GE(sys_stats.vmstat_size(), 0);
439   EXPECT_EQ(sys_stats.buddy_info_size(), 4);
440 
441   EXPECT_EQ(sys_stats.buddy_info()[0].node(), "0");
442   EXPECT_EQ(sys_stats.buddy_info()[0].zone(), "DMA");
443   EXPECT_EQ(sys_stats.buddy_info()[0].order_pages()[0], 2743u);
444   EXPECT_EQ(sys_stats.buddy_info()[0].order_pages()[5], 4u);
445   EXPECT_EQ(sys_stats.buddy_info()[0].order_pages()[10], 0u);
446 
447   EXPECT_EQ(sys_stats.buddy_info()[1].node(), "0");
448   EXPECT_EQ(sys_stats.buddy_info()[1].zone(), "Normal");
449   EXPECT_EQ(sys_stats.buddy_info()[1].order_pages()[0], 143u);
450   EXPECT_EQ(sys_stats.buddy_info()[1].order_pages()[5], 1u);
451   EXPECT_EQ(sys_stats.buddy_info()[1].order_pages()[10], 2u);
452 
453   EXPECT_EQ(sys_stats.buddy_info()[2].node(), "0");
454   EXPECT_EQ(sys_stats.buddy_info()[2].zone(), "HighMem");
455   EXPECT_EQ(sys_stats.buddy_info()[2].order_pages()[0], 345u);
456   EXPECT_EQ(sys_stats.buddy_info()[2].order_pages()[5], 2u);
457   EXPECT_EQ(sys_stats.buddy_info()[2].order_pages()[10], 0u);
458 
459   EXPECT_EQ(sys_stats.buddy_info()[3].node(), "1");
460   EXPECT_EQ(sys_stats.buddy_info()[3].zone(), "Normal");
461   EXPECT_EQ(sys_stats.buddy_info()[3].order_pages()[0], 233u);
462   EXPECT_EQ(sys_stats.buddy_info()[3].order_pages()[5], 1u);
463   EXPECT_EQ(sys_stats.buddy_info()[3].order_pages()[10], 3u);
464 }
465 
TEST_F(SysStatsDataSourceTest,ThermalZones)466 TEST_F(SysStatsDataSourceTest, ThermalZones) {
467   DataSourceConfig config;
468   protos::gen::SysStatsConfig sys_cfg;
469   sys_cfg.set_thermal_period_ms(10);
470   config.set_sys_stats_config_raw(sys_cfg.SerializeAsString());
471   auto data_source = GetSysStatsDataSource(config);
472 
473   // Create dirs and symlinks, but only read the symlinks.
474   std::vector<std::string> dirs_to_delete;
475   std::vector<std::string> symlinks_to_delete;
476   auto make_thermal_paths = [&symlinks_to_delete, &dirs_to_delete](
477                                 base::TempDir& temp_dir, base::TempDir& sym_dir,
478                                 const char* name) {
479     base::StackString<256> path("%s/%s", temp_dir.path().c_str(), name);
480     dirs_to_delete.push_back(path.ToStdString());
481     mkdir(path.c_str(), 0755);
482     base::StackString<256> sym_path("%s/%s", sym_dir.path().c_str(), name);
483     symlinks_to_delete.push_back(sym_path.ToStdString());
484     symlink(path.c_str(), sym_path.c_str());
485   };
486   auto fake_thermal = base::TempDir::Create();
487   auto fake_thermal_symdir = base::TempDir::Create();
488   static const char* const thermalzone_names[] = {"thermal_zone0"};
489   for (auto dev : thermalzone_names) {
490     make_thermal_paths(fake_thermal, fake_thermal_symdir, dev);
491   }
492 
493   EXPECT_CALL(*data_source, OpenDirAndLogOnErrorOnce(
494                                 "/sys/class/thermal/",
495                                 data_source->GetThermalErrorLoggedAddress()))
496       .WillRepeatedly(Invoke([&fake_thermal_symdir] {
497         return base::ScopedDir(opendir(fake_thermal_symdir.path().c_str()));
498       }));
499 
500   EXPECT_CALL(*data_source,
501               ReadFileToUInt64("/sys/class/thermal/thermal_zone0/temp"))
502       .WillRepeatedly(Return(std::optional<uint64_t>(kMockThermalTemp)));
503   EXPECT_CALL(*data_source,
504               ReadFileToString("/sys/class/thermal/thermal_zone0/type"))
505       .WillRepeatedly(Return(std::optional<std::string>(kMockThermalType)));
506 
507   WaitTick(data_source.get());
508 
509   protos::gen::TracePacket packet = writer_raw_->GetOnlyTracePacket();
510   ASSERT_TRUE(packet.has_sys_stats());
511   const auto& sys_stats = packet.sys_stats();
512 
513   ASSERT_EQ(sys_stats.thermal_zone_size(), 1);
514   EXPECT_EQ(sys_stats.thermal_zone()[0].name(), "thermal_zone0");
515   EXPECT_EQ(sys_stats.thermal_zone()[0].temp(), kMockThermalTemp / 1000);
516   EXPECT_EQ(sys_stats.thermal_zone()[0].type(), kMockThermalType);
517 
518   for (const std::string& path : dirs_to_delete)
519     base::Rmdir(path);
520   for (const std::string& path : symlinks_to_delete)
521     remove(path.c_str());
522 }
523 
TEST_F(SysStatsDataSourceTest,CpuIdleStates)524 TEST_F(SysStatsDataSourceTest, CpuIdleStates) {
525   DataSourceConfig config;
526   protos::gen::SysStatsConfig sys_cfg;
527   sys_cfg.set_cpuidle_period_ms(10);
528   config.set_sys_stats_config_raw(sys_cfg.SerializeAsString());
529   auto data_source = GetSysStatsDataSource(config);
530 
531   // Create dirs.
532   std::vector<std::string> dirs_to_delete;
533   auto make_cpuidle_paths = [&dirs_to_delete](base::TempDir& temp_dir,
534                                               std::string name) {
535     std::string path = temp_dir.path() + "/" + name;
536     dirs_to_delete.push_back(path);
537     mkdir(path.c_str(), 0755);
538   };
539   auto fake_cpuidle = base::TempDir::Create();
540 
541   std::string cpu_name[3] = {"/cpu0", "/cpu0/cpuidle", "/cpu0/cpuidle/state0"};
542   for (const std::string& path : cpu_name) {
543     make_cpuidle_paths(fake_cpuidle, path);
544   }
545 
546   EXPECT_CALL(*data_source, OpenDirAndLogOnErrorOnce(
547                                 "/sys/devices/system/cpu/",
548                                 data_source->GetCpuIdleErrorLoggedAddress()))
549       .WillOnce(Invoke([&fake_cpuidle] {
550         return base::ScopedDir(opendir(fake_cpuidle.path().c_str()));
551       }));
552 
553   EXPECT_CALL(*data_source, OpenDirAndLogOnErrorOnce(
554                                 "/sys/devices/system/cpu/cpu0/cpuidle/",
555                                 data_source->GetCpuIdleErrorLoggedAddress()))
556       .WillRepeatedly(Invoke([&fake_cpuidle] {
557         std::string path = fake_cpuidle.path() + "/cpu0/cpuidle";
558         return base::ScopedDir(opendir(path.c_str()));
559       }));
560 
561   EXPECT_CALL(
562       *data_source,
563       ReadFileToUInt64("/sys/devices/system/cpu/cpu0/cpuidle/state0/time"))
564       .WillRepeatedly(Return(std::optional<uint64_t>(kMockCpuIdleStateTime)));
565   EXPECT_CALL(
566       *data_source,
567       ReadFileToString("/sys/devices/system/cpu/cpu0/cpuidle/state0/name"))
568       .WillRepeatedly(
569           Return(std::optional<std::string>(kMockCpuIdleStateName)));
570 
571   WaitTick(data_source.get());
572 
573   protos::gen::TracePacket packet = writer_raw_->GetOnlyTracePacket();
574   ASSERT_TRUE(packet.has_sys_stats());
575   const auto& sys_stats = packet.sys_stats();
576   EXPECT_EQ(sys_stats.cpuidle_state_size(), 1);
577   uint32_t cpu_id = 0;
578   EXPECT_EQ(sys_stats.cpuidle_state()[0].cpu_id(), cpu_id);
579   EXPECT_EQ(sys_stats.cpuidle_state()[0].cpuidle_state_entry_size(), 1);
580   EXPECT_EQ(sys_stats.cpuidle_state()[0].cpuidle_state_entry()[0].state(),
581             kMockCpuIdleStateName);
582   EXPECT_EQ(sys_stats.cpuidle_state()[0].cpuidle_state_entry()[0].duration_us(),
583             kMockCpuIdleStateTime);
584 
585   for (auto i = dirs_to_delete.size(); i > 0; i--) {
586     base::Rmdir(dirs_to_delete[i - 1]);
587   }
588 }
589 
TEST_F(SysStatsDataSourceTest,IntelGpuFrequency)590 TEST_F(SysStatsDataSourceTest, IntelGpuFrequency) {
591   DataSourceConfig config;
592   protos::gen::SysStatsConfig sys_cfg;
593   sys_cfg.set_gpufreq_period_ms(10);
594   config.set_sys_stats_config_raw(sys_cfg.SerializeAsString());
595   auto data_source = GetSysStatsDataSource(config);
596 
597   EXPECT_CALL(*data_source,
598               ReadFileToUInt64("/sys/class/drm/card0/gt_act_freq_mhz"))
599       .WillRepeatedly(Return(std::optional<uint64_t>(kMockIntelGpuFreq)));
600 
601   WaitTick(data_source.get());
602 
603   protos::gen::TracePacket packet = writer_raw_->GetOnlyTracePacket();
604   ASSERT_TRUE(packet.has_sys_stats());
605   const auto& sys_stats = packet.sys_stats();
606   EXPECT_EQ(sys_stats.gpufreq_mhz_size(), 1);
607   uint32_t intel_gpufreq = 300;
608   EXPECT_EQ(sys_stats.gpufreq_mhz()[0], intel_gpufreq);
609 }
610 
TEST_F(SysStatsDataSourceTest,AMDGpuFrequency)611 TEST_F(SysStatsDataSourceTest, AMDGpuFrequency) {
612   DataSourceConfig config;
613   protos::gen::SysStatsConfig sys_cfg;
614   sys_cfg.set_gpufreq_period_ms(10);
615   config.set_sys_stats_config_raw(sys_cfg.SerializeAsString());
616   auto data_source = GetSysStatsDataSource(config);
617 
618   // Ignore other GPU freq calls.
619   EXPECT_CALL(*data_source,
620               ReadFileToUInt64("/sys/class/drm/card0/gt_act_freq_mhz"));
621   EXPECT_CALL(*data_source,
622               ReadFileToString("/sys/class/drm/card0/device/pp_dpm_sclk"))
623       .WillRepeatedly(Return(std::optional<std::string>(kMockAMDGpuFreq)));
624 
625   WaitTick(data_source.get());
626 
627   protos::gen::TracePacket packet = writer_raw_->GetOnlyTracePacket();
628   ASSERT_TRUE(packet.has_sys_stats());
629   const auto& sys_stats = packet.sys_stats();
630   EXPECT_EQ(sys_stats.gpufreq_mhz_size(), 1);
631   uint32_t amd_gpufreq = 400;
632   EXPECT_EQ(sys_stats.gpufreq_mhz()[0], amd_gpufreq);
633 }
634 
TEST_F(SysStatsDataSourceTest,DevfreqAll)635 TEST_F(SysStatsDataSourceTest, DevfreqAll) {
636   DataSourceConfig config;
637   protos::gen::SysStatsConfig sys_cfg;
638   sys_cfg.set_devfreq_period_ms(10);
639   config.set_sys_stats_config_raw(sys_cfg.SerializeAsString());
640   auto data_source = GetSysStatsDataSource(config);
641 
642   // Create dirs and symlinks, but only read the symlinks.
643   std::vector<std::string> dirs_to_delete;
644   std::vector<std::string> symlinks_to_delete;
645   auto make_devfreq_paths = [&symlinks_to_delete, &dirs_to_delete](
646                                 base::TempDir& temp_dir, base::TempDir& sym_dir,
647                                 const char* name) {
648     base::StackString<256> path("%s/%s", temp_dir.path().c_str(), name);
649     dirs_to_delete.push_back(path.ToStdString());
650     mkdir(path.c_str(), 0755);
651     base::StackString<256> sym_path("%s/%s", sym_dir.path().c_str(), name);
652     symlinks_to_delete.push_back(sym_path.ToStdString());
653     symlink(path.c_str(), sym_path.c_str());
654   };
655   auto fake_devfreq = base::TempDir::Create();
656   auto fake_devfreq_symdir = base::TempDir::Create();
657   static const char* const devfreq_names[] = {"10010.devfreq_device_a",
658                                               "10020.devfreq_device_b"};
659   for (auto dev : devfreq_names) {
660     make_devfreq_paths(fake_devfreq, fake_devfreq_symdir, dev);
661   }
662 
663   EXPECT_CALL(*data_source, OpenDirAndLogOnErrorOnce(
664                                 "/sys/class/devfreq/",
665                                 data_source->GetDevfreqErrorLoggedAddress()))
666       .WillRepeatedly(Invoke([&fake_devfreq_symdir] {
667         return base::ScopedDir(opendir(fake_devfreq_symdir.path().c_str()));
668       }));
669   EXPECT_CALL(*data_source, ReadDevfreqCurFreq("10010.devfreq_device_a"))
670       .WillRepeatedly(Return(kDevfreq1));
671   EXPECT_CALL(*data_source, ReadDevfreqCurFreq("10020.devfreq_device_b"))
672       .WillRepeatedly(Return(kDevfreq2));
673 
674   WaitTick(data_source.get());
675 
676   protos::gen::TracePacket packet = writer_raw_->GetOnlyTracePacket();
677   ASSERT_TRUE(packet.has_sys_stats());
678   const auto& sys_stats = packet.sys_stats();
679   EXPECT_EQ(sys_stats.meminfo_size(), 0);
680   EXPECT_EQ(sys_stats.cpu_stat_size(), 0);
681 
682   using KV = std::pair<std::string, uint64_t>;
683   std::vector<KV> kvs;
684   for (const auto& kv : sys_stats.devfreq())
685     kvs.push_back({kv.key(), kv.value()});
686   EXPECT_THAT(kvs,
687               UnorderedElementsAre(KV{"10010.devfreq_device_a", 1000000},
688                                    KV{"10020.devfreq_device_b", 20000000}));
689   for (const std::string& path : dirs_to_delete)
690     base::Rmdir(path);
691   for (const std::string& path : symlinks_to_delete)
692     remove(path.c_str());
693 }
694 
TEST_F(SysStatsDataSourceTest,StatAll)695 TEST_F(SysStatsDataSourceTest, StatAll) {
696   DataSourceConfig config;
697   protos::gen::SysStatsConfig sys_cfg;
698   sys_cfg.set_stat_period_ms(10);
699   config.set_sys_stats_config_raw(sys_cfg.SerializeAsString());
700   auto data_source = GetSysStatsDataSource(config);
701 
702   WaitTick(data_source.get());
703 
704   protos::gen::TracePacket packet = writer_raw_->GetOnlyTracePacket();
705   ASSERT_TRUE(packet.has_sys_stats());
706   const auto& sys_stats = packet.sys_stats();
707   EXPECT_EQ(sys_stats.meminfo_size(), 0);
708   EXPECT_EQ(sys_stats.vmstat_size(), 0);
709   EXPECT_EQ(sys_stats.buddy_info_size(), 0);
710 
711   ASSERT_EQ(sys_stats.cpu_stat_size(), 8);
712   EXPECT_EQ(sys_stats.cpu_stat()[0].user_ns(), 762178 * 10000000ull);
713   EXPECT_EQ(sys_stats.cpu_stat()[0].system_mode_ns(), 902284 * 10000000ull);
714   EXPECT_EQ(sys_stats.cpu_stat()[0].softirq_ns(), 68262 * 10000000ull);
715   EXPECT_EQ(sys_stats.cpu_stat()[7].user_ns(), 180484 * 10000000ull);
716   EXPECT_EQ(sys_stats.cpu_stat()[7].system_mode_ns(), 139874 * 10000000ull);
717   EXPECT_EQ(sys_stats.cpu_stat()[7].softirq_ns(), 13407 * 10000000ull);
718 
719   EXPECT_EQ(sys_stats.num_forks(), 243320u);
720 
721   EXPECT_EQ(sys_stats.num_irq_total(), 238128517u);
722   ASSERT_EQ(sys_stats.num_irq_size(), 102);
723   EXPECT_EQ(sys_stats.num_irq()[0].count(), 63500984u);
724   EXPECT_EQ(sys_stats.num_irq()[0].irq(), 3);
725   EXPECT_EQ(sys_stats.num_irq()[1].count(), 6253792u);
726   EXPECT_EQ(sys_stats.num_irq()[1].irq(), 5);
727   EXPECT_EQ(sys_stats.num_irq()[101].count(), 680u);
728 
729   EXPECT_EQ(sys_stats.num_softirq_total(), 84611084u);
730   ASSERT_EQ(sys_stats.num_softirq_size(), 10);
731   EXPECT_EQ(sys_stats.num_softirq()[0].count(), 10220177u);
732   EXPECT_EQ(sys_stats.num_softirq()[9].count(), 16443195u);
733 
734   EXPECT_EQ(sys_stats.num_softirq_total(), 84611084u);
735 }
736 
TEST_F(SysStatsDataSourceTest,StatForksOnly)737 TEST_F(SysStatsDataSourceTest, StatForksOnly) {
738   protos::gen::SysStatsConfig cfg;
739   cfg.set_stat_period_ms(10);
740   cfg.add_stat_counters(protos::gen::SysStatsConfig::STAT_FORK_COUNT);
741   DataSourceConfig config_obj;
742   config_obj.set_sys_stats_config_raw(cfg.SerializeAsString());
743   auto data_source = GetSysStatsDataSource(config_obj);
744 
745   WaitTick(data_source.get());
746 
747   protos::gen::TracePacket packet = writer_raw_->GetOnlyTracePacket();
748   ASSERT_TRUE(packet.has_sys_stats());
749   const auto& sys_stats = packet.sys_stats();
750   EXPECT_EQ(sys_stats.meminfo_size(), 0);
751   EXPECT_EQ(sys_stats.vmstat_size(), 0);
752   EXPECT_EQ(sys_stats.buddy_info_size(), 0);
753   ASSERT_EQ(sys_stats.cpu_stat_size(), 0);
754   EXPECT_EQ(sys_stats.num_forks(), 243320u);
755   EXPECT_EQ(sys_stats.num_irq_total(), 0u);
756   ASSERT_EQ(sys_stats.num_irq_size(), 0);
757   EXPECT_EQ(sys_stats.num_softirq_total(), 0u);
758   ASSERT_EQ(sys_stats.num_softirq_size(), 0);
759 }
760 
TEST_F(SysStatsDataSourceTest,Cpufreq)761 TEST_F(SysStatsDataSourceTest, Cpufreq) {
762   protos::gen::SysStatsConfig cfg;
763   cfg.set_cpufreq_period_ms(10);
764   DataSourceConfig config_obj;
765   config_obj.set_sys_stats_config_raw(cfg.SerializeAsString());
766   auto data_source = GetSysStatsDataSource(config_obj);
767 
768   WaitTick(data_source.get());
769 
770   protos::gen::TracePacket packet = writer_raw_->GetOnlyTracePacket();
771   ASSERT_TRUE(packet.has_sys_stats());
772   const auto& sys_stats = packet.sys_stats();
773   EXPECT_GT(sys_stats.cpufreq_khz_size(), 0);
774   EXPECT_EQ(sys_stats.cpufreq_khz()[0], 2650000u);
775   if (sys_stats.cpufreq_khz_size() > 1) {
776     // We emulated 2 CPUs but it is possible the test system is single core.
777     EXPECT_EQ(sys_stats.cpufreq_khz()[1], 3698200u);
778   }
779   for (unsigned int i = 2;
780        i < static_cast<unsigned int>(sys_stats.cpufreq_khz_size()); i++) {
781     // For cpux which scaling_cur_freq was not emulated in unittest, cpufreq
782     // should be recorded as 0
783     EXPECT_EQ(sys_stats.cpufreq_khz()[i], 0u);
784   }
785 }
786 
TEST_F(SysStatsDataSourceTest,DiskStat)787 TEST_F(SysStatsDataSourceTest, DiskStat) {
788   protos::gen::SysStatsConfig cfg;
789   cfg.set_diskstat_period_ms(10);
790   DataSourceConfig config_obj;
791   config_obj.set_sys_stats_config_raw(cfg.SerializeAsString());
792   auto data_source = GetSysStatsDataSource(config_obj);
793 
794   WaitTick(data_source.get());
795 
796   protos::gen::TracePacket packet = writer_raw_->GetOnlyTracePacket();
797   ASSERT_TRUE(packet.has_sys_stats());
798   const auto& sys_stats = packet.sys_stats();
799   EXPECT_EQ(sys_stats.disk_stat_size(), 3);
800 
801   EXPECT_EQ(sys_stats.disk_stat()[0].device_name(), "zram0");
802   EXPECT_EQ(sys_stats.disk_stat()[0].read_sectors(), 111088u);
803   EXPECT_EQ(sys_stats.disk_stat()[0].write_sectors(), 458384u);
804   EXPECT_EQ(sys_stats.disk_stat()[0].discard_sectors(), 0u);
805   EXPECT_EQ(sys_stats.disk_stat()[0].flush_count(), 0u);
806   EXPECT_EQ(sys_stats.disk_stat()[0].read_time_ms(), 128u);
807   EXPECT_EQ(sys_stats.disk_stat()[0].write_time_ms(), 48u);
808   EXPECT_EQ(sys_stats.disk_stat()[0].discard_time_ms(), 0u);
809   EXPECT_EQ(sys_stats.disk_stat()[0].flush_time_ms(), 0u);
810   EXPECT_EQ(sys_stats.disk_stat()[1].device_name(), "sda");
811   EXPECT_EQ(sys_stats.disk_stat()[1].read_sectors(), 8221736u);
812   EXPECT_EQ(sys_stats.disk_stat()[1].write_sectors(), 9599744u);
813   EXPECT_EQ(sys_stats.disk_stat()[1].discard_sectors(), 2160072u);
814   EXPECT_EQ(sys_stats.disk_stat()[1].flush_count(), 6649u);
815   EXPECT_EQ(sys_stats.disk_stat()[1].read_time_ms(), 75929u);
816   EXPECT_EQ(sys_stats.disk_stat()[1].write_time_ms(), 143190u);
817   EXPECT_EQ(sys_stats.disk_stat()[1].discard_time_ms(), 19411u);
818   EXPECT_EQ(sys_stats.disk_stat()[1].flush_time_ms(), 11327u);
819   EXPECT_EQ(sys_stats.disk_stat()[2].device_name(), "sda1");
820   EXPECT_EQ(sys_stats.disk_stat()[2].read_sectors(), 632u);
821   EXPECT_EQ(sys_stats.disk_stat()[2].write_sectors(), 704u);
822   EXPECT_EQ(sys_stats.disk_stat()[2].discard_sectors(), 0u);
823   EXPECT_EQ(sys_stats.disk_stat()[2].flush_count(), 0u);
824   EXPECT_EQ(sys_stats.disk_stat()[2].read_time_ms(), 7u);
825   EXPECT_EQ(sys_stats.disk_stat()[2].write_time_ms(), 92u);
826   EXPECT_EQ(sys_stats.disk_stat()[2].discard_time_ms(), 0u);
827   EXPECT_EQ(sys_stats.disk_stat()[2].flush_time_ms(), 0u);
828 }
829 
TEST_F(SysStatsDataSourceTest,Psi)830 TEST_F(SysStatsDataSourceTest, Psi) {
831   protos::gen::SysStatsConfig cfg;
832   cfg.set_psi_period_ms(10);
833   DataSourceConfig config_obj;
834   config_obj.set_sys_stats_config_raw(cfg.SerializeAsString());
835   auto data_source = GetSysStatsDataSource(config_obj);
836 
837   WaitTick(data_source.get());
838 
839   protos::gen::TracePacket packet = writer_raw_->GetOnlyTracePacket();
840   ASSERT_TRUE(packet.has_sys_stats());
841   const auto& sys_stats = packet.sys_stats();
842   ASSERT_EQ(sys_stats.psi_size(), 6);
843 
844   using PsiSample = protos::gen::SysStats::PsiSample;
845   EXPECT_EQ(sys_stats.psi()[0].resource(), PsiSample::PSI_RESOURCE_CPU_SOME);
846   EXPECT_EQ(sys_stats.psi()[0].total_ns(), 417963000u);
847   EXPECT_EQ(sys_stats.psi()[1].resource(), PsiSample::PSI_RESOURCE_CPU_FULL);
848   EXPECT_EQ(sys_stats.psi()[1].total_ns(), 205933000U);
849   EXPECT_EQ(sys_stats.psi()[2].resource(), PsiSample::PSI_RESOURCE_IO_SOME);
850   EXPECT_EQ(sys_stats.psi()[2].total_ns(), 417963000u);
851   EXPECT_EQ(sys_stats.psi()[3].resource(), PsiSample::PSI_RESOURCE_IO_FULL);
852   EXPECT_EQ(sys_stats.psi()[3].total_ns(), 205933000U);
853   EXPECT_EQ(sys_stats.psi()[4].resource(), PsiSample::PSI_RESOURCE_MEMORY_SOME);
854   EXPECT_EQ(sys_stats.psi()[4].total_ns(), 417963000u);
855   EXPECT_EQ(sys_stats.psi()[5].resource(), PsiSample::PSI_RESOURCE_MEMORY_FULL);
856   EXPECT_EQ(sys_stats.psi()[5].total_ns(), 205933000U);
857 }
858 
859 }  // namespace
860 }  // namespace perfetto
861