xref: /aosp_15_r20/external/perfetto/test/cts/heapprofd_test_cts.cc (revision 6dbdd20afdafa5e3ca9b8809fa73465d530080dc)
1*6dbdd20aSAndroid Build Coastguard Worker /*
2*6dbdd20aSAndroid Build Coastguard Worker  * Copyright (C) 2019 The Android Open Source Project
3*6dbdd20aSAndroid Build Coastguard Worker  *
4*6dbdd20aSAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*6dbdd20aSAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*6dbdd20aSAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*6dbdd20aSAndroid Build Coastguard Worker  *
8*6dbdd20aSAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*6dbdd20aSAndroid Build Coastguard Worker  *
10*6dbdd20aSAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*6dbdd20aSAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*6dbdd20aSAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*6dbdd20aSAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*6dbdd20aSAndroid Build Coastguard Worker  * limitations under the License.
15*6dbdd20aSAndroid Build Coastguard Worker  */
16*6dbdd20aSAndroid Build Coastguard Worker 
17*6dbdd20aSAndroid Build Coastguard Worker #include <stdlib.h>
18*6dbdd20aSAndroid Build Coastguard Worker #include <sys/system_properties.h>
19*6dbdd20aSAndroid Build Coastguard Worker #include <sys/types.h>
20*6dbdd20aSAndroid Build Coastguard Worker #include <sys/wait.h>
21*6dbdd20aSAndroid Build Coastguard Worker 
22*6dbdd20aSAndroid Build Coastguard Worker #include <random>
23*6dbdd20aSAndroid Build Coastguard Worker #include <string>
24*6dbdd20aSAndroid Build Coastguard Worker #include <string_view>
25*6dbdd20aSAndroid Build Coastguard Worker 
26*6dbdd20aSAndroid Build Coastguard Worker #include "perfetto/base/logging.h"
27*6dbdd20aSAndroid Build Coastguard Worker #include "perfetto/ext/base/android_utils.h"
28*6dbdd20aSAndroid Build Coastguard Worker #include "perfetto/ext/base/string_utils.h"
29*6dbdd20aSAndroid Build Coastguard Worker #include "perfetto/tracing/core/data_source_config.h"
30*6dbdd20aSAndroid Build Coastguard Worker #include "src/base/test/test_task_runner.h"
31*6dbdd20aSAndroid Build Coastguard Worker #include "src/base/test/tmp_dir_tree.h"
32*6dbdd20aSAndroid Build Coastguard Worker #include "test/android_test_utils.h"
33*6dbdd20aSAndroid Build Coastguard Worker #include "test/gtest_and_gmock.h"
34*6dbdd20aSAndroid Build Coastguard Worker #include "test/test_helper.h"
35*6dbdd20aSAndroid Build Coastguard Worker 
36*6dbdd20aSAndroid Build Coastguard Worker #include "protos/perfetto/config/process_stats/process_stats_config.gen.h"
37*6dbdd20aSAndroid Build Coastguard Worker #include "protos/perfetto/config/profiling/heapprofd_config.gen.h"
38*6dbdd20aSAndroid Build Coastguard Worker #include "protos/perfetto/trace/profiling/profile_common.gen.h"
39*6dbdd20aSAndroid Build Coastguard Worker #include "protos/perfetto/trace/profiling/profile_packet.gen.h"
40*6dbdd20aSAndroid Build Coastguard Worker #include "protos/perfetto/trace/trace_packet.gen.h"
41*6dbdd20aSAndroid Build Coastguard Worker 
42*6dbdd20aSAndroid Build Coastguard Worker namespace perfetto {
43*6dbdd20aSAndroid Build Coastguard Worker namespace {
44*6dbdd20aSAndroid Build Coastguard Worker 
45*6dbdd20aSAndroid Build Coastguard Worker // Size of individual (repeated) allocations done by the test apps (must be kept
46*6dbdd20aSAndroid Build Coastguard Worker // in sync with their sources).
47*6dbdd20aSAndroid Build Coastguard Worker constexpr uint64_t kTestSamplingInterval = 4096;
48*6dbdd20aSAndroid Build Coastguard Worker constexpr uint64_t kExpectedIndividualAllocSz = 4153;
49*6dbdd20aSAndroid Build Coastguard Worker // Tests rely on the sampling behaviour where allocations larger than the
50*6dbdd20aSAndroid Build Coastguard Worker // sampling interval are recorded at their actual size.
51*6dbdd20aSAndroid Build Coastguard Worker static_assert(kExpectedIndividualAllocSz > kTestSamplingInterval,
52*6dbdd20aSAndroid Build Coastguard Worker               "kTestSamplingInterval invalid");
53*6dbdd20aSAndroid Build Coastguard Worker 
54*6dbdd20aSAndroid Build Coastguard Worker // Path in the app external directory where the app writes an interation
55*6dbdd20aSAndroid Build Coastguard Worker // counter. It is used to wait for the test apps to actually perform
56*6dbdd20aSAndroid Build Coastguard Worker // allocations.
57*6dbdd20aSAndroid Build Coastguard Worker constexpr std::string_view kReportCyclePath = "report_cycle.txt";
58*6dbdd20aSAndroid Build Coastguard Worker 
59*6dbdd20aSAndroid Build Coastguard Worker // Activity that runs a JNI thread that repeatedly calls
60*6dbdd20aSAndroid Build Coastguard Worker // malloc(kExpectedIndividualAllocSz).
61*6dbdd20aSAndroid Build Coastguard Worker static char kMallocActivity[] = "MainActivity";
62*6dbdd20aSAndroid Build Coastguard Worker // Activity that runs a java thread that repeatedly constructs small java
63*6dbdd20aSAndroid Build Coastguard Worker // objects.
64*6dbdd20aSAndroid Build Coastguard Worker static char kJavaAllocActivity[] = "JavaAllocActivity";
65*6dbdd20aSAndroid Build Coastguard Worker 
RandomSessionName()66*6dbdd20aSAndroid Build Coastguard Worker std::string RandomSessionName() {
67*6dbdd20aSAndroid Build Coastguard Worker   std::random_device rd;
68*6dbdd20aSAndroid Build Coastguard Worker   std::default_random_engine generator(rd());
69*6dbdd20aSAndroid Build Coastguard Worker   std::uniform_int_distribution<> distribution('a', 'z');
70*6dbdd20aSAndroid Build Coastguard Worker 
71*6dbdd20aSAndroid Build Coastguard Worker   constexpr size_t kSessionNameLen = 20;
72*6dbdd20aSAndroid Build Coastguard Worker   std::string result(kSessionNameLen, '\0');
73*6dbdd20aSAndroid Build Coastguard Worker   for (size_t i = 0; i < kSessionNameLen; ++i)
74*6dbdd20aSAndroid Build Coastguard Worker     result[i] = static_cast<char>(distribution(generator));
75*6dbdd20aSAndroid Build Coastguard Worker   return result;
76*6dbdd20aSAndroid Build Coastguard Worker }
77*6dbdd20aSAndroid Build Coastguard Worker 
78*6dbdd20aSAndroid Build Coastguard Worker // Asks FileContentProvider.java inside the app to read a file.
79*6dbdd20aSAndroid Build Coastguard Worker class ContentProviderReader {
80*6dbdd20aSAndroid Build Coastguard Worker  public:
ContentProviderReader(const std::string & app,const std::string & path)81*6dbdd20aSAndroid Build Coastguard Worker   explicit ContentProviderReader(const std::string& app,
82*6dbdd20aSAndroid Build Coastguard Worker                                  const std::string& path) {
83*6dbdd20aSAndroid Build Coastguard Worker     tmp_dir_.TrackFile("contents.txt");
84*6dbdd20aSAndroid Build Coastguard Worker     tempfile_ = tmp_dir_.AbsolutePath("contents.txt");
85*6dbdd20aSAndroid Build Coastguard Worker 
86*6dbdd20aSAndroid Build Coastguard Worker     std::optional<int32_t> sdk =
87*6dbdd20aSAndroid Build Coastguard Worker         base::StringToInt32(base::GetAndroidProp("ro.build.version.sdk"));
88*6dbdd20aSAndroid Build Coastguard Worker     bool multiuser_support = sdk && *sdk >= 34;
89*6dbdd20aSAndroid Build Coastguard Worker     cmd_ = "content read";
90*6dbdd20aSAndroid Build Coastguard Worker     if (multiuser_support) {
91*6dbdd20aSAndroid Build Coastguard Worker       // This is required only starting from android U.
92*6dbdd20aSAndroid Build Coastguard Worker       cmd_ += " --user `am get-current-user`";
93*6dbdd20aSAndroid Build Coastguard Worker     }
94*6dbdd20aSAndroid Build Coastguard Worker     cmd_ += std::string(" --uri content://") + app + std::string("/") + path;
95*6dbdd20aSAndroid Build Coastguard Worker     cmd_ += " >" + tempfile_;
96*6dbdd20aSAndroid Build Coastguard Worker   }
97*6dbdd20aSAndroid Build Coastguard Worker 
ReadInt64()98*6dbdd20aSAndroid Build Coastguard Worker   std::optional<int64_t> ReadInt64() {
99*6dbdd20aSAndroid Build Coastguard Worker     if (system(cmd_.c_str()) != 0) {
100*6dbdd20aSAndroid Build Coastguard Worker       return std::nullopt;
101*6dbdd20aSAndroid Build Coastguard Worker     }
102*6dbdd20aSAndroid Build Coastguard Worker     return ReadInt64FromFile(tempfile_);
103*6dbdd20aSAndroid Build Coastguard Worker   }
104*6dbdd20aSAndroid Build Coastguard Worker 
105*6dbdd20aSAndroid Build Coastguard Worker  private:
ReadInt64FromFile(const std::string & path)106*6dbdd20aSAndroid Build Coastguard Worker   std::optional<int64_t> ReadInt64FromFile(const std::string& path) {
107*6dbdd20aSAndroid Build Coastguard Worker     std::string contents;
108*6dbdd20aSAndroid Build Coastguard Worker     if (!base::ReadFile(path, &contents)) {
109*6dbdd20aSAndroid Build Coastguard Worker       return std::nullopt;
110*6dbdd20aSAndroid Build Coastguard Worker     }
111*6dbdd20aSAndroid Build Coastguard Worker     return base::StringToInt64(contents);
112*6dbdd20aSAndroid Build Coastguard Worker   }
113*6dbdd20aSAndroid Build Coastguard Worker 
114*6dbdd20aSAndroid Build Coastguard Worker   base::TmpDirTree tmp_dir_;
115*6dbdd20aSAndroid Build Coastguard Worker   std::string tempfile_;
116*6dbdd20aSAndroid Build Coastguard Worker   std::string cmd_;
117*6dbdd20aSAndroid Build Coastguard Worker };
118*6dbdd20aSAndroid Build Coastguard Worker 
WaitForAppAllocationCycle(const std::string & app_name,size_t timeout_ms)119*6dbdd20aSAndroid Build Coastguard Worker bool WaitForAppAllocationCycle(const std::string& app_name, size_t timeout_ms) {
120*6dbdd20aSAndroid Build Coastguard Worker   const size_t sleep_per_attempt_us = 100 * 1000;
121*6dbdd20aSAndroid Build Coastguard Worker   const size_t max_attempts = timeout_ms * 1000 / sleep_per_attempt_us;
122*6dbdd20aSAndroid Build Coastguard Worker 
123*6dbdd20aSAndroid Build Coastguard Worker   ContentProviderReader app_reader(app_name, std::string(kReportCyclePath));
124*6dbdd20aSAndroid Build Coastguard Worker 
125*6dbdd20aSAndroid Build Coastguard Worker   for (size_t attempts = 0; attempts < max_attempts;) {
126*6dbdd20aSAndroid Build Coastguard Worker     int64_t first_value;
127*6dbdd20aSAndroid Build Coastguard Worker     for (; attempts < max_attempts; attempts++) {
128*6dbdd20aSAndroid Build Coastguard Worker       std::optional<int64_t> val = app_reader.ReadInt64();
129*6dbdd20aSAndroid Build Coastguard Worker       if (val) {
130*6dbdd20aSAndroid Build Coastguard Worker         first_value = *val;
131*6dbdd20aSAndroid Build Coastguard Worker         break;
132*6dbdd20aSAndroid Build Coastguard Worker       }
133*6dbdd20aSAndroid Build Coastguard Worker       base::SleepMicroseconds(sleep_per_attempt_us);
134*6dbdd20aSAndroid Build Coastguard Worker     }
135*6dbdd20aSAndroid Build Coastguard Worker 
136*6dbdd20aSAndroid Build Coastguard Worker     for (; attempts < max_attempts; attempts++) {
137*6dbdd20aSAndroid Build Coastguard Worker       std::optional<int64_t> val = app_reader.ReadInt64();
138*6dbdd20aSAndroid Build Coastguard Worker       if (!val || *val < first_value) {
139*6dbdd20aSAndroid Build Coastguard Worker         break;
140*6dbdd20aSAndroid Build Coastguard Worker       }
141*6dbdd20aSAndroid Build Coastguard Worker       if (*val >= first_value + 2) {
142*6dbdd20aSAndroid Build Coastguard Worker         // We've observed the counter being incremented twice. We can be sure
143*6dbdd20aSAndroid Build Coastguard Worker         // that the app has gone through a full allocation cycle.
144*6dbdd20aSAndroid Build Coastguard Worker         return true;
145*6dbdd20aSAndroid Build Coastguard Worker       }
146*6dbdd20aSAndroid Build Coastguard Worker       base::SleepMicroseconds(sleep_per_attempt_us);
147*6dbdd20aSAndroid Build Coastguard Worker     }
148*6dbdd20aSAndroid Build Coastguard Worker   }
149*6dbdd20aSAndroid Build Coastguard Worker   return false;
150*6dbdd20aSAndroid Build Coastguard Worker }
151*6dbdd20aSAndroid Build Coastguard Worker 
152*6dbdd20aSAndroid Build Coastguard Worker // Starts the activity `activity` of the app `app_name` and later starts
153*6dbdd20aSAndroid Build Coastguard Worker // recording a trace with the allocations in `heap_names`.
154*6dbdd20aSAndroid Build Coastguard Worker //
155*6dbdd20aSAndroid Build Coastguard Worker // `heap_names` is a list of the heap names whose allocations will be recorded.
156*6dbdd20aSAndroid Build Coastguard Worker // An empty list means that only the allocations in the default malloc heap
157*6dbdd20aSAndroid Build Coastguard Worker // ("libc.malloc") are recorded.
158*6dbdd20aSAndroid Build Coastguard Worker //
159*6dbdd20aSAndroid Build Coastguard Worker // Returns the recorded trace.
ProfileRuntime(const std::string & app_name,const std::string & activity,const std::vector<std::string> & heap_names)160*6dbdd20aSAndroid Build Coastguard Worker std::vector<protos::gen::TracePacket> ProfileRuntime(
161*6dbdd20aSAndroid Build Coastguard Worker     const std::string& app_name,
162*6dbdd20aSAndroid Build Coastguard Worker     const std::string& activity,
163*6dbdd20aSAndroid Build Coastguard Worker     const std::vector<std::string>& heap_names) {
164*6dbdd20aSAndroid Build Coastguard Worker   base::TestTaskRunner task_runner;
165*6dbdd20aSAndroid Build Coastguard Worker 
166*6dbdd20aSAndroid Build Coastguard Worker   // (re)start the target app's main activity
167*6dbdd20aSAndroid Build Coastguard Worker   if (IsAppRunning(app_name)) {
168*6dbdd20aSAndroid Build Coastguard Worker     StopApp(app_name, "old.app.stopped", &task_runner);
169*6dbdd20aSAndroid Build Coastguard Worker     task_runner.RunUntilCheckpoint("old.app.stopped", 10000 /*ms*/);
170*6dbdd20aSAndroid Build Coastguard Worker   }
171*6dbdd20aSAndroid Build Coastguard Worker   StartAppActivity(app_name, activity, "target.app.running", &task_runner,
172*6dbdd20aSAndroid Build Coastguard Worker                    /*delay_ms=*/100);
173*6dbdd20aSAndroid Build Coastguard Worker   task_runner.RunUntilCheckpoint("target.app.running", 10000 /*ms*/);
174*6dbdd20aSAndroid Build Coastguard Worker 
175*6dbdd20aSAndroid Build Coastguard Worker   // set up tracing
176*6dbdd20aSAndroid Build Coastguard Worker   TestHelper helper(&task_runner);
177*6dbdd20aSAndroid Build Coastguard Worker   helper.ConnectConsumer();
178*6dbdd20aSAndroid Build Coastguard Worker   helper.WaitForConsumerConnect();
179*6dbdd20aSAndroid Build Coastguard Worker 
180*6dbdd20aSAndroid Build Coastguard Worker   TraceConfig trace_config;
181*6dbdd20aSAndroid Build Coastguard Worker   trace_config.add_buffers()->set_size_kb(10 * 1024);
182*6dbdd20aSAndroid Build Coastguard Worker   trace_config.set_unique_session_name(RandomSessionName().c_str());
183*6dbdd20aSAndroid Build Coastguard Worker 
184*6dbdd20aSAndroid Build Coastguard Worker   auto* ds_config = trace_config.add_data_sources()->mutable_config();
185*6dbdd20aSAndroid Build Coastguard Worker   ds_config->set_name("android.heapprofd");
186*6dbdd20aSAndroid Build Coastguard Worker   ds_config->set_target_buffer(0);
187*6dbdd20aSAndroid Build Coastguard Worker 
188*6dbdd20aSAndroid Build Coastguard Worker   protos::gen::HeapprofdConfig heapprofd_config;
189*6dbdd20aSAndroid Build Coastguard Worker   heapprofd_config.set_sampling_interval_bytes(kTestSamplingInterval);
190*6dbdd20aSAndroid Build Coastguard Worker   heapprofd_config.add_process_cmdline(app_name.c_str());
191*6dbdd20aSAndroid Build Coastguard Worker   heapprofd_config.set_block_client(true);
192*6dbdd20aSAndroid Build Coastguard Worker   heapprofd_config.set_all(false);
193*6dbdd20aSAndroid Build Coastguard Worker   for (const std::string& heap_name : heap_names) {
194*6dbdd20aSAndroid Build Coastguard Worker     heapprofd_config.add_heaps(heap_name);
195*6dbdd20aSAndroid Build Coastguard Worker   }
196*6dbdd20aSAndroid Build Coastguard Worker   ds_config->set_heapprofd_config_raw(heapprofd_config.SerializeAsString());
197*6dbdd20aSAndroid Build Coastguard Worker 
198*6dbdd20aSAndroid Build Coastguard Worker   // start tracing
199*6dbdd20aSAndroid Build Coastguard Worker   helper.StartTracing(trace_config);
200*6dbdd20aSAndroid Build Coastguard Worker 
201*6dbdd20aSAndroid Build Coastguard Worker   EXPECT_TRUE(WaitForAppAllocationCycle(app_name, /*timeout_ms=*/10000));
202*6dbdd20aSAndroid Build Coastguard Worker 
203*6dbdd20aSAndroid Build Coastguard Worker   helper.DisableTracing();
204*6dbdd20aSAndroid Build Coastguard Worker   helper.WaitForTracingDisabled();
205*6dbdd20aSAndroid Build Coastguard Worker   helper.ReadData();
206*6dbdd20aSAndroid Build Coastguard Worker   helper.WaitForReadData();
207*6dbdd20aSAndroid Build Coastguard Worker 
208*6dbdd20aSAndroid Build Coastguard Worker   return helper.trace();
209*6dbdd20aSAndroid Build Coastguard Worker }
210*6dbdd20aSAndroid Build Coastguard Worker 
211*6dbdd20aSAndroid Build Coastguard Worker // Starts recording a trace with the allocations in `heap_names` and later
212*6dbdd20aSAndroid Build Coastguard Worker // starts the activity `activity` of the app `app_name`
213*6dbdd20aSAndroid Build Coastguard Worker //
214*6dbdd20aSAndroid Build Coastguard Worker // `heap_names` is a list of the heap names whose allocations will be recorded.
215*6dbdd20aSAndroid Build Coastguard Worker // An empty list means that only the allocation in the default malloc heap
216*6dbdd20aSAndroid Build Coastguard Worker // ("libc.malloc") are recorded.
217*6dbdd20aSAndroid Build Coastguard Worker //
218*6dbdd20aSAndroid Build Coastguard Worker // Returns the recorded trace.
ProfileStartup(const std::string & app_name,const std::string & activity,const std::vector<std::string> & heap_names,const bool enable_extra_guardrails=false)219*6dbdd20aSAndroid Build Coastguard Worker std::vector<protos::gen::TracePacket> ProfileStartup(
220*6dbdd20aSAndroid Build Coastguard Worker     const std::string& app_name,
221*6dbdd20aSAndroid Build Coastguard Worker     const std::string& activity,
222*6dbdd20aSAndroid Build Coastguard Worker     const std::vector<std::string>& heap_names,
223*6dbdd20aSAndroid Build Coastguard Worker     const bool enable_extra_guardrails = false) {
224*6dbdd20aSAndroid Build Coastguard Worker   base::TestTaskRunner task_runner;
225*6dbdd20aSAndroid Build Coastguard Worker 
226*6dbdd20aSAndroid Build Coastguard Worker   if (IsAppRunning(app_name)) {
227*6dbdd20aSAndroid Build Coastguard Worker     StopApp(app_name, "old.app.stopped", &task_runner);
228*6dbdd20aSAndroid Build Coastguard Worker     task_runner.RunUntilCheckpoint("old.app.stopped", 10000 /*ms*/);
229*6dbdd20aSAndroid Build Coastguard Worker   }
230*6dbdd20aSAndroid Build Coastguard Worker 
231*6dbdd20aSAndroid Build Coastguard Worker   // set up tracing
232*6dbdd20aSAndroid Build Coastguard Worker   TestHelper helper(&task_runner);
233*6dbdd20aSAndroid Build Coastguard Worker   helper.ConnectConsumer();
234*6dbdd20aSAndroid Build Coastguard Worker   helper.WaitForConsumerConnect();
235*6dbdd20aSAndroid Build Coastguard Worker 
236*6dbdd20aSAndroid Build Coastguard Worker   TraceConfig trace_config;
237*6dbdd20aSAndroid Build Coastguard Worker   trace_config.add_buffers()->set_size_kb(10 * 1024);
238*6dbdd20aSAndroid Build Coastguard Worker   trace_config.set_enable_extra_guardrails(enable_extra_guardrails);
239*6dbdd20aSAndroid Build Coastguard Worker   trace_config.set_unique_session_name(RandomSessionName().c_str());
240*6dbdd20aSAndroid Build Coastguard Worker 
241*6dbdd20aSAndroid Build Coastguard Worker   auto* ds_config = trace_config.add_data_sources()->mutable_config();
242*6dbdd20aSAndroid Build Coastguard Worker   ds_config->set_name("android.heapprofd");
243*6dbdd20aSAndroid Build Coastguard Worker   ds_config->set_target_buffer(0);
244*6dbdd20aSAndroid Build Coastguard Worker 
245*6dbdd20aSAndroid Build Coastguard Worker   protos::gen::HeapprofdConfig heapprofd_config;
246*6dbdd20aSAndroid Build Coastguard Worker   heapprofd_config.set_sampling_interval_bytes(kTestSamplingInterval);
247*6dbdd20aSAndroid Build Coastguard Worker   heapprofd_config.add_process_cmdline(app_name.c_str());
248*6dbdd20aSAndroid Build Coastguard Worker   heapprofd_config.set_block_client(true);
249*6dbdd20aSAndroid Build Coastguard Worker   heapprofd_config.set_all(false);
250*6dbdd20aSAndroid Build Coastguard Worker   for (const std::string& heap_name : heap_names) {
251*6dbdd20aSAndroid Build Coastguard Worker     heapprofd_config.add_heaps(heap_name);
252*6dbdd20aSAndroid Build Coastguard Worker   }
253*6dbdd20aSAndroid Build Coastguard Worker   ds_config->set_heapprofd_config_raw(heapprofd_config.SerializeAsString());
254*6dbdd20aSAndroid Build Coastguard Worker 
255*6dbdd20aSAndroid Build Coastguard Worker   // start tracing
256*6dbdd20aSAndroid Build Coastguard Worker   helper.StartTracing(trace_config);
257*6dbdd20aSAndroid Build Coastguard Worker 
258*6dbdd20aSAndroid Build Coastguard Worker   // start app
259*6dbdd20aSAndroid Build Coastguard Worker   StartAppActivity(app_name, activity, "target.app.running", &task_runner,
260*6dbdd20aSAndroid Build Coastguard Worker                    /*delay_ms=*/100);
261*6dbdd20aSAndroid Build Coastguard Worker   task_runner.RunUntilCheckpoint("target.app.running", 10000 /*ms*/);
262*6dbdd20aSAndroid Build Coastguard Worker 
263*6dbdd20aSAndroid Build Coastguard Worker   EXPECT_TRUE(WaitForAppAllocationCycle(app_name, /*timeout_ms=*/10000));
264*6dbdd20aSAndroid Build Coastguard Worker 
265*6dbdd20aSAndroid Build Coastguard Worker   helper.DisableTracing();
266*6dbdd20aSAndroid Build Coastguard Worker   helper.WaitForTracingDisabled();
267*6dbdd20aSAndroid Build Coastguard Worker   helper.ReadData();
268*6dbdd20aSAndroid Build Coastguard Worker   helper.WaitForReadData();
269*6dbdd20aSAndroid Build Coastguard Worker 
270*6dbdd20aSAndroid Build Coastguard Worker   return helper.trace();
271*6dbdd20aSAndroid Build Coastguard Worker }
272*6dbdd20aSAndroid Build Coastguard Worker 
273*6dbdd20aSAndroid Build Coastguard Worker // Check that `packets` contain some allocations performed by kMallocActivity.
AssertExpectedMallocsPresent(const std::vector<protos::gen::TracePacket> & packets)274*6dbdd20aSAndroid Build Coastguard Worker void AssertExpectedMallocsPresent(
275*6dbdd20aSAndroid Build Coastguard Worker     const std::vector<protos::gen::TracePacket>& packets) {
276*6dbdd20aSAndroid Build Coastguard Worker   ASSERT_GT(packets.size(), 0u);
277*6dbdd20aSAndroid Build Coastguard Worker 
278*6dbdd20aSAndroid Build Coastguard Worker   // TODO(rsavitski): assert particular stack frames once we clarify the
279*6dbdd20aSAndroid Build Coastguard Worker   // expected behaviour of unwinding native libs within an apk.
280*6dbdd20aSAndroid Build Coastguard Worker   // Until then, look for an allocation that is a multiple of the expected
281*6dbdd20aSAndroid Build Coastguard Worker   // allocation size.
282*6dbdd20aSAndroid Build Coastguard Worker   bool found_alloc = false;
283*6dbdd20aSAndroid Build Coastguard Worker   bool found_proc_dump = false;
284*6dbdd20aSAndroid Build Coastguard Worker   for (const auto& packet : packets) {
285*6dbdd20aSAndroid Build Coastguard Worker     for (const auto& proc_dump : packet.profile_packet().process_dumps()) {
286*6dbdd20aSAndroid Build Coastguard Worker       found_proc_dump = true;
287*6dbdd20aSAndroid Build Coastguard Worker       for (const auto& sample : proc_dump.samples()) {
288*6dbdd20aSAndroid Build Coastguard Worker         if (sample.self_allocated() > 0 &&
289*6dbdd20aSAndroid Build Coastguard Worker             sample.self_allocated() % kExpectedIndividualAllocSz == 0) {
290*6dbdd20aSAndroid Build Coastguard Worker           found_alloc = true;
291*6dbdd20aSAndroid Build Coastguard Worker 
292*6dbdd20aSAndroid Build Coastguard Worker           EXPECT_TRUE(sample.self_freed() > 0 &&
293*6dbdd20aSAndroid Build Coastguard Worker                       sample.self_freed() % kExpectedIndividualAllocSz == 0)
294*6dbdd20aSAndroid Build Coastguard Worker               << "self_freed: " << sample.self_freed();
295*6dbdd20aSAndroid Build Coastguard Worker         }
296*6dbdd20aSAndroid Build Coastguard Worker       }
297*6dbdd20aSAndroid Build Coastguard Worker     }
298*6dbdd20aSAndroid Build Coastguard Worker   }
299*6dbdd20aSAndroid Build Coastguard Worker   ASSERT_TRUE(found_proc_dump);
300*6dbdd20aSAndroid Build Coastguard Worker   ASSERT_TRUE(found_alloc);
301*6dbdd20aSAndroid Build Coastguard Worker }
302*6dbdd20aSAndroid Build Coastguard Worker 
AssertHasSampledAllocs(const std::vector<protos::gen::TracePacket> & packets)303*6dbdd20aSAndroid Build Coastguard Worker void AssertHasSampledAllocs(
304*6dbdd20aSAndroid Build Coastguard Worker     const std::vector<protos::gen::TracePacket>& packets) {
305*6dbdd20aSAndroid Build Coastguard Worker   ASSERT_GT(packets.size(), 0u);
306*6dbdd20aSAndroid Build Coastguard Worker 
307*6dbdd20aSAndroid Build Coastguard Worker   bool found_alloc = false;
308*6dbdd20aSAndroid Build Coastguard Worker   bool found_proc_dump = false;
309*6dbdd20aSAndroid Build Coastguard Worker   for (const auto& packet : packets) {
310*6dbdd20aSAndroid Build Coastguard Worker     for (const auto& proc_dump : packet.profile_packet().process_dumps()) {
311*6dbdd20aSAndroid Build Coastguard Worker       found_proc_dump = true;
312*6dbdd20aSAndroid Build Coastguard Worker       for (const auto& sample : proc_dump.samples()) {
313*6dbdd20aSAndroid Build Coastguard Worker         if (sample.self_allocated() > 0) {
314*6dbdd20aSAndroid Build Coastguard Worker           found_alloc = true;
315*6dbdd20aSAndroid Build Coastguard Worker         }
316*6dbdd20aSAndroid Build Coastguard Worker       }
317*6dbdd20aSAndroid Build Coastguard Worker     }
318*6dbdd20aSAndroid Build Coastguard Worker   }
319*6dbdd20aSAndroid Build Coastguard Worker   ASSERT_TRUE(found_proc_dump);
320*6dbdd20aSAndroid Build Coastguard Worker   ASSERT_TRUE(found_alloc);
321*6dbdd20aSAndroid Build Coastguard Worker }
322*6dbdd20aSAndroid Build Coastguard Worker 
AssertNoProfileContents(const std::vector<protos::gen::TracePacket> & packets)323*6dbdd20aSAndroid Build Coastguard Worker void AssertNoProfileContents(
324*6dbdd20aSAndroid Build Coastguard Worker     const std::vector<protos::gen::TracePacket>& packets) {
325*6dbdd20aSAndroid Build Coastguard Worker   // If profile packets are present, they must be empty.
326*6dbdd20aSAndroid Build Coastguard Worker   for (const auto& packet : packets) {
327*6dbdd20aSAndroid Build Coastguard Worker     ASSERT_EQ(packet.profile_packet().process_dumps_size(), 0);
328*6dbdd20aSAndroid Build Coastguard Worker   }
329*6dbdd20aSAndroid Build Coastguard Worker }
330*6dbdd20aSAndroid Build Coastguard Worker 
TEST(HeapprofdCtsTest,DebuggableAppRuntime)331*6dbdd20aSAndroid Build Coastguard Worker TEST(HeapprofdCtsTest, DebuggableAppRuntime) {
332*6dbdd20aSAndroid Build Coastguard Worker   std::string app_name = "android.perfetto.cts.app.debuggable";
333*6dbdd20aSAndroid Build Coastguard Worker   const auto& packets =
334*6dbdd20aSAndroid Build Coastguard Worker       ProfileRuntime(app_name, kMallocActivity, /*heap_names=*/{});
335*6dbdd20aSAndroid Build Coastguard Worker   AssertExpectedMallocsPresent(packets);
336*6dbdd20aSAndroid Build Coastguard Worker   StopApp(app_name);
337*6dbdd20aSAndroid Build Coastguard Worker }
338*6dbdd20aSAndroid Build Coastguard Worker 
TEST(HeapprofdCtsTest,DebuggableAppStartup)339*6dbdd20aSAndroid Build Coastguard Worker TEST(HeapprofdCtsTest, DebuggableAppStartup) {
340*6dbdd20aSAndroid Build Coastguard Worker   std::string app_name = "android.perfetto.cts.app.debuggable";
341*6dbdd20aSAndroid Build Coastguard Worker   const auto& packets =
342*6dbdd20aSAndroid Build Coastguard Worker       ProfileStartup(app_name, kMallocActivity, /*heap_names=*/{});
343*6dbdd20aSAndroid Build Coastguard Worker   AssertExpectedMallocsPresent(packets);
344*6dbdd20aSAndroid Build Coastguard Worker   StopApp(app_name);
345*6dbdd20aSAndroid Build Coastguard Worker }
346*6dbdd20aSAndroid Build Coastguard Worker 
TEST(HeapprofdCtsTest,ProfileableAppRuntime)347*6dbdd20aSAndroid Build Coastguard Worker TEST(HeapprofdCtsTest, ProfileableAppRuntime) {
348*6dbdd20aSAndroid Build Coastguard Worker   std::string app_name = "android.perfetto.cts.app.profileable";
349*6dbdd20aSAndroid Build Coastguard Worker   const auto& packets =
350*6dbdd20aSAndroid Build Coastguard Worker       ProfileRuntime(app_name, kMallocActivity, /*heap_names=*/{});
351*6dbdd20aSAndroid Build Coastguard Worker   AssertExpectedMallocsPresent(packets);
352*6dbdd20aSAndroid Build Coastguard Worker   StopApp(app_name);
353*6dbdd20aSAndroid Build Coastguard Worker }
354*6dbdd20aSAndroid Build Coastguard Worker 
TEST(HeapprofdCtsTest,ProfileableAppStartup)355*6dbdd20aSAndroid Build Coastguard Worker TEST(HeapprofdCtsTest, ProfileableAppStartup) {
356*6dbdd20aSAndroid Build Coastguard Worker   std::string app_name = "android.perfetto.cts.app.profileable";
357*6dbdd20aSAndroid Build Coastguard Worker   const auto& packets =
358*6dbdd20aSAndroid Build Coastguard Worker       ProfileStartup(app_name, kMallocActivity, /*heap_names=*/{});
359*6dbdd20aSAndroid Build Coastguard Worker   AssertExpectedMallocsPresent(packets);
360*6dbdd20aSAndroid Build Coastguard Worker   StopApp(app_name);
361*6dbdd20aSAndroid Build Coastguard Worker }
362*6dbdd20aSAndroid Build Coastguard Worker 
TEST(HeapprofdCtsTest,ReleaseAppRuntime)363*6dbdd20aSAndroid Build Coastguard Worker TEST(HeapprofdCtsTest, ReleaseAppRuntime) {
364*6dbdd20aSAndroid Build Coastguard Worker   std::string app_name = "android.perfetto.cts.app.release";
365*6dbdd20aSAndroid Build Coastguard Worker   const auto& packets =
366*6dbdd20aSAndroid Build Coastguard Worker       ProfileRuntime(app_name, kMallocActivity, /*heap_names=*/{});
367*6dbdd20aSAndroid Build Coastguard Worker 
368*6dbdd20aSAndroid Build Coastguard Worker   if (IsUserBuild())
369*6dbdd20aSAndroid Build Coastguard Worker     AssertNoProfileContents(packets);
370*6dbdd20aSAndroid Build Coastguard Worker   else
371*6dbdd20aSAndroid Build Coastguard Worker     AssertExpectedMallocsPresent(packets);
372*6dbdd20aSAndroid Build Coastguard Worker   StopApp(app_name);
373*6dbdd20aSAndroid Build Coastguard Worker }
374*6dbdd20aSAndroid Build Coastguard Worker 
TEST(HeapprofdCtsTest,ReleaseAppStartup)375*6dbdd20aSAndroid Build Coastguard Worker TEST(HeapprofdCtsTest, ReleaseAppStartup) {
376*6dbdd20aSAndroid Build Coastguard Worker   std::string app_name = "android.perfetto.cts.app.release";
377*6dbdd20aSAndroid Build Coastguard Worker   const auto& packets =
378*6dbdd20aSAndroid Build Coastguard Worker       ProfileStartup(app_name, kMallocActivity, /*heap_names=*/{});
379*6dbdd20aSAndroid Build Coastguard Worker 
380*6dbdd20aSAndroid Build Coastguard Worker   if (IsUserBuild())
381*6dbdd20aSAndroid Build Coastguard Worker     AssertNoProfileContents(packets);
382*6dbdd20aSAndroid Build Coastguard Worker   else
383*6dbdd20aSAndroid Build Coastguard Worker     AssertExpectedMallocsPresent(packets);
384*6dbdd20aSAndroid Build Coastguard Worker   StopApp(app_name);
385*6dbdd20aSAndroid Build Coastguard Worker }
386*6dbdd20aSAndroid Build Coastguard Worker 
TEST(HeapprofdCtsTest,NonProfileableAppRuntime)387*6dbdd20aSAndroid Build Coastguard Worker TEST(HeapprofdCtsTest, NonProfileableAppRuntime) {
388*6dbdd20aSAndroid Build Coastguard Worker   std::string app_name = "android.perfetto.cts.app.nonprofileable";
389*6dbdd20aSAndroid Build Coastguard Worker   const auto& packets =
390*6dbdd20aSAndroid Build Coastguard Worker       ProfileRuntime(app_name, kMallocActivity, /*heap_names=*/{});
391*6dbdd20aSAndroid Build Coastguard Worker   if (IsUserBuild())
392*6dbdd20aSAndroid Build Coastguard Worker     AssertNoProfileContents(packets);
393*6dbdd20aSAndroid Build Coastguard Worker   else
394*6dbdd20aSAndroid Build Coastguard Worker     AssertExpectedMallocsPresent(packets);
395*6dbdd20aSAndroid Build Coastguard Worker   StopApp(app_name);
396*6dbdd20aSAndroid Build Coastguard Worker }
397*6dbdd20aSAndroid Build Coastguard Worker 
TEST(HeapprofdCtsTest,NonProfileableAppStartup)398*6dbdd20aSAndroid Build Coastguard Worker TEST(HeapprofdCtsTest, NonProfileableAppStartup) {
399*6dbdd20aSAndroid Build Coastguard Worker   std::string app_name = "android.perfetto.cts.app.nonprofileable";
400*6dbdd20aSAndroid Build Coastguard Worker   const auto& packets =
401*6dbdd20aSAndroid Build Coastguard Worker       ProfileStartup(app_name, kMallocActivity, /*heap_names=*/{});
402*6dbdd20aSAndroid Build Coastguard Worker   if (IsUserBuild())
403*6dbdd20aSAndroid Build Coastguard Worker     AssertNoProfileContents(packets);
404*6dbdd20aSAndroid Build Coastguard Worker   else
405*6dbdd20aSAndroid Build Coastguard Worker     AssertExpectedMallocsPresent(packets);
406*6dbdd20aSAndroid Build Coastguard Worker   StopApp(app_name);
407*6dbdd20aSAndroid Build Coastguard Worker }
408*6dbdd20aSAndroid Build Coastguard Worker 
TEST(HeapprofdCtsTest,JavaHeapRuntime)409*6dbdd20aSAndroid Build Coastguard Worker TEST(HeapprofdCtsTest, JavaHeapRuntime) {
410*6dbdd20aSAndroid Build Coastguard Worker   std::string app_name = "android.perfetto.cts.app.debuggable";
411*6dbdd20aSAndroid Build Coastguard Worker   const auto& packets = ProfileRuntime(app_name, kJavaAllocActivity,
412*6dbdd20aSAndroid Build Coastguard Worker                                        /*heap_names=*/{"com.android.art"});
413*6dbdd20aSAndroid Build Coastguard Worker   AssertHasSampledAllocs(packets);
414*6dbdd20aSAndroid Build Coastguard Worker   StopApp(app_name);
415*6dbdd20aSAndroid Build Coastguard Worker }
416*6dbdd20aSAndroid Build Coastguard Worker 
TEST(HeapprofdCtsTest,JavaHeapStartup)417*6dbdd20aSAndroid Build Coastguard Worker TEST(HeapprofdCtsTest, JavaHeapStartup) {
418*6dbdd20aSAndroid Build Coastguard Worker   std::string app_name = "android.perfetto.cts.app.debuggable";
419*6dbdd20aSAndroid Build Coastguard Worker   const auto& packets = ProfileStartup(app_name, kJavaAllocActivity,
420*6dbdd20aSAndroid Build Coastguard Worker                                        /*heap_names=*/{"com.android.art"});
421*6dbdd20aSAndroid Build Coastguard Worker   AssertHasSampledAllocs(packets);
422*6dbdd20aSAndroid Build Coastguard Worker   StopApp(app_name);
423*6dbdd20aSAndroid Build Coastguard Worker }
424*6dbdd20aSAndroid Build Coastguard Worker 
TEST(HeapprofdCtsTest,ProfilePlatformProcess)425*6dbdd20aSAndroid Build Coastguard Worker TEST(HeapprofdCtsTest, ProfilePlatformProcess) {
426*6dbdd20aSAndroid Build Coastguard Worker   int target_pid = PidForProcessName("/system/bin/traced_probes");
427*6dbdd20aSAndroid Build Coastguard Worker   ASSERT_GT(target_pid, 0) << "failed to find pid for target process";
428*6dbdd20aSAndroid Build Coastguard Worker 
429*6dbdd20aSAndroid Build Coastguard Worker   // Construct config.
430*6dbdd20aSAndroid Build Coastguard Worker   TraceConfig trace_config;
431*6dbdd20aSAndroid Build Coastguard Worker   trace_config.add_buffers()->set_size_kb(20 * 1024);
432*6dbdd20aSAndroid Build Coastguard Worker   trace_config.set_duration_ms(3000);
433*6dbdd20aSAndroid Build Coastguard Worker   trace_config.set_data_source_stop_timeout_ms(8000);
434*6dbdd20aSAndroid Build Coastguard Worker   trace_config.set_unique_session_name(RandomSessionName().c_str());
435*6dbdd20aSAndroid Build Coastguard Worker 
436*6dbdd20aSAndroid Build Coastguard Worker   // process.stats to cause work in traced_probes
437*6dbdd20aSAndroid Build Coastguard Worker   protos::gen::ProcessStatsConfig ps_config;
438*6dbdd20aSAndroid Build Coastguard Worker   ps_config.set_proc_stats_poll_ms(100);
439*6dbdd20aSAndroid Build Coastguard Worker   ps_config.set_record_thread_names(true);
440*6dbdd20aSAndroid Build Coastguard Worker 
441*6dbdd20aSAndroid Build Coastguard Worker   auto* ds_config = trace_config.add_data_sources()->mutable_config();
442*6dbdd20aSAndroid Build Coastguard Worker   ds_config->set_name("linux.process_stats");
443*6dbdd20aSAndroid Build Coastguard Worker   ds_config->set_process_stats_config_raw(ps_config.SerializeAsString());
444*6dbdd20aSAndroid Build Coastguard Worker 
445*6dbdd20aSAndroid Build Coastguard Worker   // profile native heap of traced_probes
446*6dbdd20aSAndroid Build Coastguard Worker   protos::gen::HeapprofdConfig heapprofd_config;
447*6dbdd20aSAndroid Build Coastguard Worker   heapprofd_config.set_sampling_interval_bytes(kTestSamplingInterval);
448*6dbdd20aSAndroid Build Coastguard Worker   heapprofd_config.add_pid(static_cast<uint64_t>(target_pid));
449*6dbdd20aSAndroid Build Coastguard Worker   heapprofd_config.set_block_client(true);
450*6dbdd20aSAndroid Build Coastguard Worker 
451*6dbdd20aSAndroid Build Coastguard Worker   ds_config = trace_config.add_data_sources()->mutable_config();
452*6dbdd20aSAndroid Build Coastguard Worker   ds_config->set_name("android.heapprofd");
453*6dbdd20aSAndroid Build Coastguard Worker   ds_config->set_heapprofd_config_raw(heapprofd_config.SerializeAsString());
454*6dbdd20aSAndroid Build Coastguard Worker 
455*6dbdd20aSAndroid Build Coastguard Worker   // Collect trace.
456*6dbdd20aSAndroid Build Coastguard Worker   base::TestTaskRunner task_runner;
457*6dbdd20aSAndroid Build Coastguard Worker   TestHelper helper(&task_runner);
458*6dbdd20aSAndroid Build Coastguard Worker   helper.ConnectConsumer();
459*6dbdd20aSAndroid Build Coastguard Worker   helper.WaitForConsumerConnect();
460*6dbdd20aSAndroid Build Coastguard Worker 
461*6dbdd20aSAndroid Build Coastguard Worker   helper.StartTracing(trace_config);
462*6dbdd20aSAndroid Build Coastguard Worker   helper.WaitForTracingDisabled(15000 /*ms*/);
463*6dbdd20aSAndroid Build Coastguard Worker   helper.ReadData();
464*6dbdd20aSAndroid Build Coastguard Worker   helper.WaitForReadData();
465*6dbdd20aSAndroid Build Coastguard Worker   auto packets = helper.trace();
466*6dbdd20aSAndroid Build Coastguard Worker 
467*6dbdd20aSAndroid Build Coastguard Worker   int target_pid_after = PidForProcessName("/system/bin/traced_probes");
468*6dbdd20aSAndroid Build Coastguard Worker   ASSERT_EQ(target_pid, target_pid_after) << "traced_probes died during test";
469*6dbdd20aSAndroid Build Coastguard Worker 
470*6dbdd20aSAndroid Build Coastguard Worker   if (IsUserBuild())
471*6dbdd20aSAndroid Build Coastguard Worker     AssertNoProfileContents(packets);
472*6dbdd20aSAndroid Build Coastguard Worker   else
473*6dbdd20aSAndroid Build Coastguard Worker     AssertHasSampledAllocs(packets);
474*6dbdd20aSAndroid Build Coastguard Worker }
475*6dbdd20aSAndroid Build Coastguard Worker 
476*6dbdd20aSAndroid Build Coastguard Worker }  // namespace
477*6dbdd20aSAndroid Build Coastguard Worker }  // namespace perfetto
478