cts: add perf profiler e2e tests for apps
The test apps now have an additional activity that
busy-waits (as we're looking to sample it).
Bug: 144281346
Change-Id: I2bf7db43cc56dd07d121104efef5f56fee0a0922
diff --git a/Android.bp b/Android.bp
index fd0c8c8..ef5cacc 100644
--- a/Android.bp
+++ b/Android.bp
@@ -828,6 +828,7 @@
"test/cts/end_to_end_integrationtest_cts.cc",
"test/cts/heapprofd_java_test_cts.cc",
"test/cts/heapprofd_test_cts.cc",
+ "test/cts/traced_perf_test_cts.cc",
"test/cts/utils.cc",
],
static_libs: [
diff --git a/test/cts/Android.bp b/test/cts/Android.bp
index 4871ebb..302a358 100644
--- a/test/cts/Android.bp
+++ b/test/cts/Android.bp
@@ -3,8 +3,9 @@
srcs: [
"device_feature_test_cts.cc",
"end_to_end_integrationtest_cts.cc",
- "heapprofd_test_cts.cc",
"heapprofd_java_test_cts.cc",
+ "heapprofd_test_cts.cc",
+ "traced_perf_test_cts.cc",
"utils.cc",
":perfetto_protos_perfetto_config_cpp_gen",
],
diff --git a/test/cts/AndroidTest.xml b/test/cts/AndroidTest.xml
index 6dfeac1..3d40593 100644
--- a/test/cts/AndroidTest.xml
+++ b/test/cts/AndroidTest.xml
@@ -34,6 +34,7 @@
</target_preparer>
<target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
<option name="run-command" value="setprop persist.heapprofd.enable 1" />
+ <option name="run-command" value="setprop persist.traced_perf.enable 1" />
</target_preparer>
<test class="com.android.tradefed.testtype.GTest" >
<option name="native-test-device-path" value="/data/local/tmp" />
diff --git a/test/cts/BUILD.gn b/test/cts/BUILD.gn
index 84aba0c..84a7860 100644
--- a/test/cts/BUILD.gn
+++ b/test/cts/BUILD.gn
@@ -37,6 +37,7 @@
"end_to_end_integrationtest_cts.cc",
"heapprofd_java_test_cts.cc",
"heapprofd_test_cts.cc",
+ "traced_perf_test_cts.cc",
"utils.cc",
]
}
diff --git a/test/cts/heapprofd_test_apps/Android.bp b/test/cts/test_apps/Android.bp
similarity index 93%
rename from test/cts/heapprofd_test_apps/Android.bp
rename to test/cts/test_apps/Android.bp
index bc2b323..543c1f6 100644
--- a/test/cts/heapprofd_test_apps/Android.bp
+++ b/test/cts/test_apps/Android.bp
@@ -27,7 +27,7 @@
srcs: ["src/**/*.java"],
sdk_version: "current",
jni_libs: [
- "libperfettocts_heapprofdtarget",
+ "libperfettocts_native",
"libnativehelper_compat_libc++",
],
}
@@ -47,7 +47,7 @@
srcs: ["src/**/*.java"],
sdk_version: "current",
jni_libs: [
- "libperfettocts_heapprofdtarget",
+ "libperfettocts_native",
"libnativehelper_compat_libc++",
],
}
@@ -67,7 +67,7 @@
srcs: ["src/**/*.java"],
sdk_version: "current",
jni_libs: [
- "libperfettocts_heapprofdtarget",
+ "libperfettocts_native",
"libnativehelper_compat_libc++",
],
}
diff --git a/test/cts/heapprofd_test_apps/AndroidManifest_debuggable.xml b/test/cts/test_apps/AndroidManifest_debuggable.xml
similarity index 71%
rename from test/cts/heapprofd_test_apps/AndroidManifest_debuggable.xml
rename to test/cts/test_apps/AndroidManifest_debuggable.xml
index 999541e..c85ab05 100755
--- a/test/cts/heapprofd_test_apps/AndroidManifest_debuggable.xml
+++ b/test/cts/test_apps/AndroidManifest_debuggable.xml
@@ -31,6 +31,18 @@
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity-alias>
+ <activity
+ android:name="android.perfetto.cts.app.BusyWaitActivity"
+ android:exported="false">
+ </activity>
+ <activity-alias
+ android:name="android.perfetto.cts.app.debuggable.BusyWaitActivity"
+ android:targetActivity="android.perfetto.cts.app.BusyWaitActivity">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity-alias>
</application>
</manifest>
diff --git a/test/cts/heapprofd_test_apps/AndroidManifest_profileable.xml b/test/cts/test_apps/AndroidManifest_profileable.xml
similarity index 71%
rename from test/cts/heapprofd_test_apps/AndroidManifest_profileable.xml
rename to test/cts/test_apps/AndroidManifest_profileable.xml
index 99ceda2..129e922 100755
--- a/test/cts/heapprofd_test_apps/AndroidManifest_profileable.xml
+++ b/test/cts/test_apps/AndroidManifest_profileable.xml
@@ -32,6 +32,18 @@
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity-alias>
+ <activity
+ android:name="android.perfetto.cts.app.BusyWaitActivity"
+ android:exported="false">
+ </activity>
+ <activity-alias
+ android:name="android.perfetto.cts.app.profileable.BusyWaitActivity"
+ android:targetActivity="android.perfetto.cts.app.BusyWaitActivity">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity-alias>
</application>
</manifest>
diff --git a/test/cts/heapprofd_test_apps/AndroidManifest_release.xml b/test/cts/test_apps/AndroidManifest_release.xml
similarity index 71%
rename from test/cts/heapprofd_test_apps/AndroidManifest_release.xml
rename to test/cts/test_apps/AndroidManifest_release.xml
index b2dfd25..5b64a94 100755
--- a/test/cts/heapprofd_test_apps/AndroidManifest_release.xml
+++ b/test/cts/test_apps/AndroidManifest_release.xml
@@ -31,6 +31,18 @@
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity-alias>
+ <activity
+ android:name="android.perfetto.cts.app.BusyWaitActivity"
+ android:exported="false">
+ </activity>
+ <activity-alias
+ android:name="android.perfetto.cts.app.release.BusyWaitActivity"
+ android:targetActivity="android.perfetto.cts.app.BusyWaitActivity">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity-alias>
</application>
</manifest>
diff --git a/test/cts/heapprofd_test_apps/jni/Android.bp b/test/cts/test_apps/jni/Android.bp
similarity index 95%
rename from test/cts/heapprofd_test_apps/jni/Android.bp
rename to test/cts/test_apps/jni/Android.bp
index de090d2..3f50e72 100644
--- a/test/cts/heapprofd_test_apps/jni/Android.bp
+++ b/test/cts/test_apps/jni/Android.bp
@@ -14,7 +14,7 @@
// limitations under the License.
cc_library_shared {
- name: "libperfettocts_heapprofdtarget",
+ name: "libperfettocts_native",
srcs: [
"target.cc",
],
diff --git a/test/cts/heapprofd_test_apps/jni/target.cc b/test/cts/test_apps/jni/target.cc
similarity index 77%
rename from test/cts/heapprofd_test_apps/jni/target.cc
rename to test/cts/test_apps/jni/target.cc
index 6bedf84..8f847c4 100644
--- a/test/cts/heapprofd_test_apps/jni/target.cc
+++ b/test/cts/test_apps/jni/target.cc
@@ -36,9 +36,21 @@
}
}
+// Runs continuously as a target for the sampling perf profiler tests.
+__attribute__((noreturn)) void perfetto_busy_wait() {
+ for (volatile unsigned i = 0;; i++) {
+ }
+}
+
} // namespace
extern "C" JNIEXPORT void JNICALL
Java_android_perfetto_cts_app_MainActivity_runNative(JNIEnv*, jclass) {
perfetto_test_allocations();
}
+
+extern "C" JNIEXPORT void JNICALL
+Java_android_perfetto_cts_app_BusyWaitActivity_runNativeBusyWait(JNIEnv*,
+ jclass) {
+ perfetto_busy_wait();
+}
diff --git a/test/cts/heapprofd_test_apps/src/android/perfetto/cts/app/MainActivity.java b/test/cts/test_apps/src/android/perfetto/cts/app/BusyWaitActivity.java
similarity index 82%
copy from test/cts/heapprofd_test_apps/src/android/perfetto/cts/app/MainActivity.java
copy to test/cts/test_apps/src/android/perfetto/cts/app/BusyWaitActivity.java
index 0e26bfc..689c98a 100644
--- a/test/cts/heapprofd_test_apps/src/android/perfetto/cts/app/MainActivity.java
+++ b/test/cts/test_apps/src/android/perfetto/cts/app/BusyWaitActivity.java
@@ -19,9 +19,9 @@
import android.app.Activity;
import android.os.Bundle;
-public class MainActivity extends Activity {
+public class BusyWaitActivity extends Activity {
static {
- System.loadLibrary("perfettocts_heapprofdtarget");
+ System.loadLibrary("perfettocts_native");
}
@Override
@@ -31,14 +31,13 @@
new Thread(new Runnable() {
public void run() {
try {
- runNative();
+ runNativeBusyWait();
} catch (Exception ex) {
ex.printStackTrace();
}
}
- })
- .start();
+ }).start();
}
- private static native void runNative();
+ private static native void runNativeBusyWait();
}
diff --git a/test/cts/heapprofd_test_apps/src/android/perfetto/cts/app/MainActivity.java b/test/cts/test_apps/src/android/perfetto/cts/app/MainActivity.java
similarity index 92%
rename from test/cts/heapprofd_test_apps/src/android/perfetto/cts/app/MainActivity.java
rename to test/cts/test_apps/src/android/perfetto/cts/app/MainActivity.java
index 0e26bfc..0cabd16 100644
--- a/test/cts/heapprofd_test_apps/src/android/perfetto/cts/app/MainActivity.java
+++ b/test/cts/test_apps/src/android/perfetto/cts/app/MainActivity.java
@@ -21,7 +21,7 @@
public class MainActivity extends Activity {
static {
- System.loadLibrary("perfettocts_heapprofdtarget");
+ System.loadLibrary("perfettocts_native");
}
@Override
@@ -36,8 +36,7 @@
ex.printStackTrace();
}
}
- })
- .start();
+ }).start();
}
private static native void runNative();
diff --git a/test/cts/traced_perf_test_cts.cc b/test/cts/traced_perf_test_cts.cc
new file mode 100644
index 0000000..d6745fc
--- /dev/null
+++ b/test/cts/traced_perf_test_cts.cc
@@ -0,0 +1,147 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdlib.h>
+#include <sys/types.h>
+
+#include "perfetto/base/logging.h"
+#include "perfetto/tracing/core/data_source_config.h"
+#include "src/base/test/test_task_runner.h"
+#include "test/cts/utils.h"
+#include "test/gtest_and_gmock.h"
+#include "test/test_helper.h"
+
+#include "protos/perfetto/config/profiling/perf_event_config.gen.h"
+#include "protos/perfetto/trace/profiling/profile_common.gen.h"
+#include "protos/perfetto/trace/profiling/profile_packet.gen.h"
+#include "protos/perfetto/trace/trace_packet.gen.h"
+
+namespace perfetto {
+namespace {
+
+std::vector<protos::gen::TracePacket> ProfileSystemWide(std::string app_name) {
+ base::TestTaskRunner task_runner;
+
+ // (re)start the target app's main activity
+ if (IsAppRunning(app_name)) {
+ StopApp(app_name, "old.app.stopped", &task_runner);
+ task_runner.RunUntilCheckpoint("old.app.stopped", 1000 /*ms*/);
+ }
+ StartAppActivity(app_name, "BusyWaitActivity", "target.app.running",
+ &task_runner,
+ /*delay_ms=*/100);
+ task_runner.RunUntilCheckpoint("target.app.running", 1000 /*ms*/);
+
+ // set up tracing
+ TestHelper helper(&task_runner);
+ helper.ConnectConsumer();
+ helper.WaitForConsumerConnect();
+
+ TraceConfig trace_config;
+ trace_config.add_buffers()->set_size_kb(10 * 1024);
+ trace_config.set_duration_ms(2000);
+
+ auto* ds_config = trace_config.add_data_sources()->mutable_config();
+ ds_config->set_name("linux.perf");
+ ds_config->set_target_buffer(0);
+
+ protos::gen::PerfEventConfig perf_config;
+
+ perf_config.set_all_cpus(true);
+ perf_config.set_sampling_frequency(10); // Hz
+ ds_config->set_perf_event_config_raw(perf_config.SerializeAsString());
+
+ // start tracing
+ helper.StartTracing(trace_config);
+ helper.WaitForTracingDisabled(10000 /*ms*/);
+ helper.ReadData();
+ helper.WaitForReadData();
+
+ return helper.trace();
+}
+
+void AssertHasSampledStacksForPid(std::vector<protos::gen::TracePacket> packets,
+ int target_pid) {
+ ASSERT_GT(packets.size(), 0u);
+
+ int samples_found = 0;
+ for (const auto& packet : packets) {
+ if (!packet.has_perf_sample())
+ continue;
+
+ EXPECT_GT(packet.timestamp(), 0u) << "all samples should have a timestamp";
+ const auto& sample = packet.perf_sample();
+ if (sample.pid() != static_cast<uint32_t>(target_pid))
+ continue;
+
+ // TODO(rsavitski): include |sample.has_sample_skipped_reason| once that is
+ // merged.
+ if (sample.has_kernel_records_lost())
+ continue;
+
+ // A full sample
+ EXPECT_GT(sample.tid(), 0u);
+ EXPECT_GT(sample.callstack_iid(), 0u);
+ samples_found += 1;
+ }
+ EXPECT_GT(samples_found, 0);
+}
+
+void AssertNoStacksForPid(std::vector<protos::gen::TracePacket> packets,
+ int target_pid) {
+ for (const auto& packet : packets) {
+ if (packet.perf_sample().pid() == static_cast<uint32_t>(target_pid)) {
+ EXPECT_EQ(packet.perf_sample().callstack_iid(), 0u);
+ }
+ }
+}
+
+TEST(TracedPerfCtsTest, SystemWideDebuggableApp) {
+ std::string app_name = "android.perfetto.cts.app.debuggable";
+ const auto& packets = ProfileSystemWide(app_name);
+ int app_pid = PidForProcessName(app_name);
+ ASSERT_GT(app_pid, 0) << "failed to find pid for target process";
+
+ AssertHasSampledStacksForPid(packets, app_pid);
+ StopApp(app_name);
+}
+
+TEST(TracedPerfCtsTest, SystemWideProfileableApp) {
+ std::string app_name = "android.perfetto.cts.app.profileable";
+ const auto& packets = ProfileSystemWide(app_name);
+ int app_pid = PidForProcessName(app_name);
+ ASSERT_GT(app_pid, 0) << "failed to find pid for target process";
+
+ AssertHasSampledStacksForPid(packets, app_pid);
+ StopApp(app_name);
+}
+
+TEST(TracedPerfCtsTest, SystemWideReleaseApp) {
+ std::string app_name = "android.perfetto.cts.app.release";
+ const auto& packets = ProfileSystemWide(app_name);
+ int app_pid = PidForProcessName(app_name);
+ ASSERT_GT(app_pid, 0) << "failed to find pid for target process";
+
+ if (IsDebuggableBuild())
+ AssertHasSampledStacksForPid(packets, app_pid);
+ else
+ AssertNoStacksForPid(packets, app_pid);
+
+ StopApp(app_name);
+}
+
+} // namespace
+} // namespace perfetto
diff --git a/test/cts/utils.cc b/test/cts/utils.cc
index 4ea9309..b11cddf 100644
--- a/test/cts/utils.cc
+++ b/test/cts/utils.cc
@@ -20,6 +20,7 @@
#include <sys/system_properties.h>
#include "perfetto/base/logging.h"
+#include "perfetto/ext/base/file_utils.h"
#include "test/gtest_and_gmock.h"
namespace perfetto {
@@ -48,10 +49,7 @@
char buf[PROP_VALUE_MAX + 1] = {};
int ret = __system_property_get("ro.debuggable", buf);
PERFETTO_CHECK(ret >= 0);
- std::string debuggable(buf);
- if (debuggable == "1")
- return true;
- return false;
+ return std::string(buf) == "1";
}
// note: cannot use gtest macros due to return type
@@ -67,6 +65,25 @@
PERFETTO_FATAL("unexpected exit status from system(pgrep): %d", exit_status);
}
+int PidForProcessName(const std::string& name) {
+ // quirk: need to exclude ourselves from the result as the pgrep's cmdline
+ // matches itself when invoked via popen.
+ std::string cmd = "pgrep -f " + name + " | grep -v $$";
+ FILE* fp = popen(cmd.c_str(), "re");
+ if (!fp)
+ return -1;
+
+ std::string out;
+ base::ReadFileStream(fp, &out);
+ pclose(fp);
+
+ char* endptr = nullptr;
+ int pid = static_cast<int>(strtol(out.c_str(), &endptr, 10));
+ if (*endptr != '\0' && *endptr != '\n')
+ return -1;
+ return pid;
+}
+
void WaitForProcess(const std::string& process,
const std::string& checkpoint_name,
base::TestTaskRunner* task_runner,
diff --git a/test/cts/utils.h b/test/cts/utils.h
index e2796ef..3fd5a3e 100644
--- a/test/cts/utils.h
+++ b/test/cts/utils.h
@@ -27,6 +27,9 @@
bool IsAppRunning(const std::string& name);
+// returns -1 if the process wasn't found
+int PidForProcessName(const std::string& name);
+
void WaitForProcess(const std::string& process,
const std::string& checkpoint_name,
base::TestTaskRunner* task_runner,