blob: 9d4e5437c091c948858bd270f18a65f54c1e247f [file] [log] [blame]
Primiano Tucci401a4732022-01-19 00:26:49 +00001/*
2 * Copyright (C) 2022 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 "perfetto/base/build_config.h"
18
19#if PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID)
20
21#include "perfetto/base/logging.h"
22#include "perfetto/ext/base/file_utils.h"
23#include "perfetto/ext/base/pipe.h"
24#include "perfetto/ext/base/scoped_file.h"
25#include "perfetto/ext/base/string_utils.h"
26#include "perfetto/ext/base/utils.h"
27#include "perfetto/ext/tracing/core/commit_data_request.h"
28#include "perfetto/ext/tracing/core/trace_packet.h"
29#include "perfetto/ext/tracing/core/tracing_service.h"
30#include "perfetto/protozero/scattered_heap_buffer.h"
31#include "src/base/test/test_task_runner.h"
32#include "src/base/test/utils.h"
33#include "test/gtest_and_gmock.h"
34#include "test/test_helper.h"
35
36#include "protos/perfetto/config/power/android_power_config.pbzero.h"
37#include "protos/perfetto/config/test_config.gen.h"
38#include "protos/perfetto/config/trace_config.gen.h"
39#include "protos/perfetto/trace/ftrace/ftrace.gen.h"
40#include "protos/perfetto/trace/ftrace/ftrace_event.gen.h"
41#include "protos/perfetto/trace/ftrace/ftrace_event_bundle.gen.h"
42#include "protos/perfetto/trace/ftrace/ftrace_stats.gen.h"
43#include "protos/perfetto/trace/perfetto/tracing_service_event.gen.h"
44#include "protos/perfetto/trace/power/battery_counters.gen.h"
45#include "protos/perfetto/trace/test_event.gen.h"
46#include "protos/perfetto/trace/trace.gen.h"
47#include "protos/perfetto/trace/trace_packet.gen.h"
48#include "protos/perfetto/trace/trace_packet.pbzero.h"
49#include "protos/perfetto/trace/trigger.gen.h"
50
51#include "protos/perfetto/common/sys_stats_counters.gen.h"
52#include "protos/perfetto/config/sys_stats/sys_stats_config.gen.h"
53#include "protos/perfetto/trace/sys_stats/sys_stats.gen.h"
54
55namespace perfetto {
56
57namespace {
58
59using ::testing::ContainsRegex;
60using ::testing::Each;
61using ::testing::ElementsAreArray;
62using ::testing::HasSubstr;
63using ::testing::Property;
64using ::testing::SizeIs;
65
Primiano Tucci401a4732022-01-19 00:26:49 +000066} // namespace
67
68TEST(PerfettoAndroidIntegrationTest, TestKmemActivity) {
69 using C = protos::gen::VmstatCounters;
70
71 base::TestTaskRunner task_runner;
72
73 TestHelper helper(&task_runner);
74
75 helper.StartServiceIfRequired();
76
77#if PERFETTO_BUILDFLAG(PERFETTO_START_DAEMONS)
78 ProbesProducerThread probes(GetTestProducerSockName());
79 probes.Connect();
80#endif
81
82 auto* producer = helper.ConnectFakeProducer();
83 helper.ConnectConsumer();
84 helper.WaitForConsumerConnect();
85 helper.WaitForDataSourceConnected("linux.ftrace");
86
87 TraceConfig trace_config;
88 trace_config.add_buffers()->set_size_kb(1024);
89 trace_config.set_unique_session_name("kmem_activity_test");
90
91 auto* ftrace_ds_config = trace_config.add_data_sources()->mutable_config();
92 ftrace_ds_config->set_name("linux.ftrace");
93 protos::gen::FtraceConfig ftrace_config = CreateFtraceConfig({
94 "vmscan/mm_vmscan_kswapd_wake",
95 "vmscan/mm_vmscan_kswapd_sleep",
96 "vmscan/mm_vmscan_direct_reclaim_begin",
97 "vmscan/mm_vmscan_direct_reclaim_end",
98 "compaction/mm_compaction_begin",
99 "compaction/mm_compaction_end",
100 });
101 ftrace_ds_config->set_ftrace_config_raw(ftrace_config.SerializeAsString());
102
103 auto* sys_stats_ds_config = trace_config.add_data_sources()->mutable_config();
104 sys_stats_ds_config->set_name("linux.sys_stats");
105 protos::gen::SysStatsConfig sys_stats_config;
106 sys_stats_config.set_vmstat_period_ms(50);
107 std::vector<C> vmstat_counters = {
108 C::VMSTAT_NR_FREE_PAGES,
109 C::VMSTAT_NR_SLAB_RECLAIMABLE,
110 C::VMSTAT_NR_SLAB_UNRECLAIMABLE,
111 C::VMSTAT_NR_ACTIVE_FILE,
112 C::VMSTAT_NR_INACTIVE_FILE,
113 C::VMSTAT_NR_ACTIVE_ANON,
114 C::VMSTAT_NR_INACTIVE_ANON,
115 C::VMSTAT_WORKINGSET_REFAULT,
116 C::VMSTAT_WORKINGSET_ACTIVATE,
117 C::VMSTAT_NR_FILE_PAGES,
118 C::VMSTAT_PGPGIN,
119 C::VMSTAT_PGPGOUT,
120 C::VMSTAT_PSWPIN,
121 C::VMSTAT_PSWPOUT,
122 C::VMSTAT_PGSTEAL_KSWAPD_DMA,
123 C::VMSTAT_PGSTEAL_KSWAPD_NORMAL,
124 C::VMSTAT_PGSTEAL_KSWAPD_MOVABLE,
125 C::VMSTAT_PGSTEAL_DIRECT_DMA,
126 C::VMSTAT_PGSTEAL_DIRECT_NORMAL,
127 C::VMSTAT_PGSTEAL_DIRECT_MOVABLE,
128 C::VMSTAT_PGSCAN_KSWAPD_DMA,
129 C::VMSTAT_PGSCAN_KSWAPD_NORMAL,
130 C::VMSTAT_PGSCAN_KSWAPD_MOVABLE,
131 C::VMSTAT_PGSCAN_DIRECT_DMA,
132 C::VMSTAT_PGSCAN_DIRECT_NORMAL,
133 C::VMSTAT_PGSCAN_DIRECT_MOVABLE,
134 C::VMSTAT_COMPACT_MIGRATE_SCANNED,
135 C::VMSTAT_COMPACT_FREE_SCANNED,
136 };
137 for (const auto& counter : vmstat_counters) {
138 sys_stats_config.add_vmstat_counters(counter);
139 }
140 sys_stats_ds_config->set_sys_stats_config_raw(
141 sys_stats_config.SerializeAsString());
142
143 auto* trigger_cfg = trace_config.mutable_trigger_config();
144 trigger_cfg->set_trigger_mode(
145 protos::gen::TraceConfig::TriggerConfig::START_TRACING);
146 trigger_cfg->set_trigger_timeout_ms(15000);
147 auto* trigger = trigger_cfg->add_triggers();
148 trigger->set_name("kmem_activity");
149 // |stop_delay_ms| must be long enough that we can write the packets in
150 // before the trace finishes.
151 trigger->set_stop_delay_ms(1000);
152
153 helper.StartTracing(trace_config);
154
155 // Linearize with StartTracing. This ensures that the service has seen the
156 // StartTracing IPC and has armed the triggers.
157 helper.FlushAndWait(kDefaultTestTimeoutMs);
158
159 // Generating synthetic memory pressure to trigger kmem activity is
160 // inherently flaky on different devices. The same goes for writing
161 // /proc/sys/vm/compact_memory to trigger compaction, since compaction is
162 // only started if needed (even if explicitly triggered from proc).
163 // Trigger kmem activity using perfetto trigger.
164 producer->ActivateTrigger("kmem_activity");
165
166 helper.WaitForTracingDisabled();
167
168 helper.ReadData();
169 helper.WaitForReadData();
170
171 const auto& packets = helper.trace();
172 ASSERT_GT(packets.size(), 0u);
173
174 bool sys_stats_captured = false;
175 for (const auto& packet : packets) {
176 for (int ev = 0; ev < packet.ftrace_events().event_size(); ev++) {
177 auto ftrace_event =
178 packet.ftrace_events().event()[static_cast<size_t>(ev)];
179 ASSERT_TRUE(ftrace_event.has_mm_vmscan_kswapd_wake() ||
180 ftrace_event.has_mm_vmscan_kswapd_sleep() ||
181 ftrace_event.has_mm_vmscan_direct_reclaim_begin() ||
182 ftrace_event.has_mm_vmscan_direct_reclaim_end() ||
183 ftrace_event.has_mm_compaction_begin() ||
184 ftrace_event.has_mm_compaction_end());
185 }
186
187 if (packet.has_sys_stats()) {
188 sys_stats_captured = true;
189 const auto& sys_stats = packet.sys_stats();
190 const auto& vmstat = sys_stats.vmstat();
191 ASSERT_GT(vmstat.size(), 0u);
192 for (const auto& vmstat_value : vmstat) {
193 ASSERT_NE(std::find(vmstat_counters.begin(), vmstat_counters.end(),
194 vmstat_value.key()),
195 vmstat_counters.end());
196 }
197 }
198 }
199
200 // Don't explicitly check that ftrace events were captured, since this test
201 // doesn't rely on memory pressure.
202 ASSERT_TRUE(sys_stats_captured);
203}
204
205TEST(PerfettoAndroidIntegrationTest, TestBatteryTracing) {
206 base::TestTaskRunner task_runner;
207
208 TestHelper helper(&task_runner);
209 helper.StartServiceIfRequired();
210
211#if PERFETTO_BUILDFLAG(PERFETTO_START_DAEMONS)
212 ProbesProducerThread probes(GetTestProducerSockName());
213 probes.Connect();
214#endif
215
216 helper.ConnectConsumer();
217 helper.WaitForConsumerConnect();
218
219 TraceConfig trace_config;
220 trace_config.add_buffers()->set_size_kb(128);
221 trace_config.set_duration_ms(3000);
222
223 auto* ds_config = trace_config.add_data_sources()->mutable_config();
224 ds_config->set_name("android.power");
225 ds_config->set_target_buffer(0);
226
227 using protos::pbzero::AndroidPowerConfig;
228 protozero::HeapBuffered<AndroidPowerConfig> power_config;
229 power_config->set_battery_poll_ms(250);
230 power_config->add_battery_counters(
231 AndroidPowerConfig::BATTERY_COUNTER_CHARGE);
232 power_config->add_battery_counters(
233 AndroidPowerConfig::BATTERY_COUNTER_CAPACITY_PERCENT);
234 ds_config->set_android_power_config_raw(power_config.SerializeAsString());
235
236 helper.StartTracing(trace_config);
237 helper.WaitForTracingDisabled();
238
239 helper.ReadData();
240 helper.WaitForReadData();
241
242 const auto& packets = helper.trace();
243 ASSERT_GT(packets.size(), 0u);
244
245 bool has_battery_packet = false;
246 for (const auto& packet : packets) {
247 if (!packet.has_battery())
248 continue;
249 has_battery_packet = true;
250 // Unfortunately we cannot make any assertions on the charge counter.
251 // On some devices it can reach negative values (b/64685329).
252 EXPECT_GE(packet.battery().capacity_percent(), 0.f);
253 EXPECT_LE(packet.battery().capacity_percent(), 100.f);
254 }
255
256 ASSERT_TRUE(has_battery_packet);
257}
258
Primiano Tucci401a4732022-01-19 00:26:49 +0000259} // namespace perfetto
260
261#endif // PERFETTO_OS_ANDROID