New library compose:runtime:runtime-tracing
When added as a dependency to a Compose application, enables
recomposition tracing:
- declares a dependency on tracing-perfetto
- registers tracing-perfetto with Compose
Remaining steps to trace have to be performed by tooling (e.g. Android
Studio Profiler):
- provide tracing-perfetto-binary dependencies required for tracing
- notify the app to register with Perfetto SDK (using
androidx.tracing.perfetto.TracingReceiver)
- include track_event as a category in its Perfetto capture config
- capture and present a Perfetto trace
End-to-end test covered by TracingInitializerTest where Macrobenchmark
performs the steps described in the previous paragraph.
Bug: 214560409
Bug: 214560414
Bug: 214562374
Test: ./gradlew :compose:runtime:runtime-tracing:connectedCheck -Pandroid.testInstrumentationRunnerArguments.class=androidx.compose.runtime.tracing.test.TracingInitializerTest
Test: ./gradlew :compose:integration-tests:macrobenchmark-target:installRelease && ./gradlew :compose:integration-tests:macrobenchmark:connectedCheck -Pandroid.testInstrumentationRunnerArguments.class=androidx.compose.integration.macrobenchmark.TrivialTracingBenchmark
Change-Id: Id1ea30fdea39da8d63b8c0963d9e8e351704985b
diff --git a/benchmark/benchmark-common/src/main/java/androidx/benchmark/perfetto/PerfettoConfig.kt b/benchmark/benchmark-common/src/main/java/androidx/benchmark/perfetto/PerfettoConfig.kt
index 093758b..60d54ed 100644
--- a/benchmark/benchmark-common/src/main/java/androidx/benchmark/perfetto/PerfettoConfig.kt
+++ b/benchmark/benchmark-common/src/main/java/androidx/benchmark/perfetto/PerfettoConfig.kt
@@ -170,7 +170,8 @@
PROCESS_STATS_DATASOURCE,
LINUX_SYS_STATS_DATASOURCE,
ANDROID_POWER_DATASOURCE,
- TraceConfig.DataSource(DataSourceConfig("android.surfaceflinger.frametimeline"))
+ TraceConfig.DataSource(DataSourceConfig("android.surfaceflinger.frametimeline")),
+ TraceConfig.DataSource(DataSourceConfig("track_event")) // required by tracing-perfetto
),
// periodically dump to file, so we don't overrun our ring buffer
// buffers are expected to be big enough for 5 seconds, so conservatively set 2.5 dump
diff --git a/compose/integration-tests/macrobenchmark-target/build.gradle b/compose/integration-tests/macrobenchmark-target/build.gradle
index 37eacb5..0c1ddaf 100644
--- a/compose/integration-tests/macrobenchmark-target/build.gradle
+++ b/compose/integration-tests/macrobenchmark-target/build.gradle
@@ -32,6 +32,7 @@
implementation(project(":compose:foundation:foundation"))
implementation(project(":compose:material:material"))
implementation(project(":compose:runtime:runtime"))
+ implementation(project(":compose:runtime:runtime-tracing"))
implementation(project(":compose:ui:ui"))
implementation(project(":compose:ui:ui-tooling"))
}
diff --git a/compose/integration-tests/macrobenchmark-target/src/main/AndroidManifest.xml b/compose/integration-tests/macrobenchmark-target/src/main/AndroidManifest.xml
index 333c84e..d997cfc 100644
--- a/compose/integration-tests/macrobenchmark-target/src/main/AndroidManifest.xml
+++ b/compose/integration-tests/macrobenchmark-target/src/main/AndroidManifest.xml
@@ -103,5 +103,13 @@
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
+ <activity
+ android:name=".TrivialTracingActivity"
+ android:exported="true">
+ <intent-filter>
+ <action android:name="androidx.compose.integration.macrobenchmark.target.TRIVIAL_TRACING_ACTIVITY" />
+ <category android:name="android.intent.category.DEFAULT" />
+ </intent-filter>
+ </activity>
</application>
</manifest>
diff --git a/compose/integration-tests/macrobenchmark-target/src/main/java/androidx/compose/integration/macrobenchmark/target/TrivialTracingActivity.kt b/compose/integration-tests/macrobenchmark-target/src/main/java/androidx/compose/integration/macrobenchmark/target/TrivialTracingActivity.kt
new file mode 100644
index 0000000..00d60904
--- /dev/null
+++ b/compose/integration-tests/macrobenchmark-target/src/main/java/androidx/compose/integration/macrobenchmark/target/TrivialTracingActivity.kt
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2022 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.
+ */
+
+package androidx.compose.integration.macrobenchmark.target
+
+import android.os.Bundle
+import androidx.activity.ComponentActivity
+import androidx.activity.compose.setContent
+import androidx.compose.runtime.Composable
+
+class TrivialTracingActivity : ComponentActivity() {
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+
+ setContent {
+ Foo_BBC27C8E_13A7_4A5F_A735_AFDC433F54C3()
+ Baz_609801AB_F5A9_47C3_9405_2E82542F21B8()
+ }
+ }
+}
+
+@Composable
+private fun Foo_BBC27C8E_13A7_4A5F_A735_AFDC433F54C3() =
+ Bar_4888EA32_ABC5_4550_BA78_1247FEC1AAC9()
+
+@Composable
+private fun Bar_4888EA32_ABC5_4550_BA78_1247FEC1AAC9() {
+}
+
+@Composable
+private fun Baz_609801AB_F5A9_47C3_9405_2E82542F21B8() {
+}
\ No newline at end of file
diff --git a/compose/integration-tests/macrobenchmark/build.gradle b/compose/integration-tests/macrobenchmark/build.gradle
index 60103b8..52926c1 100644
--- a/compose/integration-tests/macrobenchmark/build.gradle
+++ b/compose/integration-tests/macrobenchmark/build.gradle
@@ -14,6 +14,8 @@
* limitations under the License.
*/
+import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
+
plugins {
id("AndroidXPlugin")
id("com.android.library")
@@ -42,3 +44,10 @@
// Define a task dependency so the app is installed before we run macro benchmarks.
tasks.getByPath(":compose:integration-tests:macrobenchmark:connectedCheck")
.dependsOn(tasks.getByPath(":compose:integration-tests:macrobenchmark-target:installRelease"))
+
+// Allow usage of Kotlin's @OptIn.
+tasks.withType(KotlinCompile).configureEach {
+ kotlinOptions {
+ freeCompilerArgs += ["-opt-in=kotlin.RequiresOptIn"]
+ }
+}
diff --git a/compose/integration-tests/macrobenchmark/src/androidTest/java/androidx/compose/integration/macrobenchmark/TrivialTracingBenchmark.kt b/compose/integration-tests/macrobenchmark/src/androidTest/java/androidx/compose/integration/macrobenchmark/TrivialTracingBenchmark.kt
new file mode 100644
index 0000000..2da52f3
--- /dev/null
+++ b/compose/integration-tests/macrobenchmark/src/androidTest/java/androidx/compose/integration/macrobenchmark/TrivialTracingBenchmark.kt
@@ -0,0 +1,78 @@
+/*
+ * Copyright 2022 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.
+ */
+
+package androidx.compose.integration.macrobenchmark
+
+import android.content.Intent
+import android.os.Build
+import androidx.annotation.RequiresApi
+import androidx.benchmark.macro.ExperimentalMetricApi
+import androidx.benchmark.macro.TraceSectionMetric
+import androidx.benchmark.macro.junit4.MacrobenchmarkRule
+import androidx.benchmark.perfetto.PerfettoCapture
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.LargeTest
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@LargeTest
+@RunWith(AndroidJUnit4::class)
+/**
+ * End-to-end test for compose-runtime-tracing verifying that names of Composables show up in
+ * a Perfetto trace.
+ */
+class TrivialTracingBenchmark {
+ @get:Rule
+ val benchmarkRule = MacrobenchmarkRule()
+
+ @RequiresApi(Build.VERSION_CODES.Q)
+ @OptIn(ExperimentalMetricApi::class)
+ @Test
+ fun test_composable_names_present_in_trace() {
+ val metrics = COMPOSABLE_NAMES.map { composableName ->
+ TraceSectionMetric("%$PACKAGE_NAME.$composableName %$FILE_NAME:% key=%")
+ }
+ benchmarkRule.measureRepeated(
+ packageName = PACKAGE_NAME,
+ metrics = metrics,
+ iterations = 1, // we are only verifying the presence of entries (not the timing data)
+ setupBlock = {
+ PerfettoCapture().enableAndroidxTracingPerfetto(
+ PACKAGE_NAME,
+ provideBinariesIfMissing = true
+ )
+ }
+ ) {
+ startActivityAndWait(Intent(ACTION))
+ }
+ }
+
+ companion object {
+ private const val PACKAGE_NAME = "androidx.compose.integration.macrobenchmark.target"
+
+ private const val ACTION =
+ "androidx.compose.integration.macrobenchmark.target.TRIVIAL_TRACING_ACTIVITY"
+
+ private const val FILE_NAME = "TrivialTracingActivity.kt"
+
+ private val COMPOSABLE_NAMES = listOf(
+ "Foo_BBC27C8E_13A7_4A5F_A735_AFDC433F54C3",
+ "Bar_4888EA32_ABC5_4550_BA78_1247FEC1AAC9",
+ "Baz_609801AB_F5A9_47C3_9405_2E82542F21B8"
+ )
+ }
+}
diff --git a/compose/runtime/runtime-tracing/build.gradle b/compose/runtime/runtime-tracing/build.gradle
new file mode 100644
index 0000000..4ed47d9
--- /dev/null
+++ b/compose/runtime/runtime-tracing/build.gradle
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+
+import androidx.build.Publish
+import androidx.build.RunApiTasks
+import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
+
+plugins {
+ id("AndroidXPlugin")
+ id("com.android.library")
+ id("kotlin-android")
+}
+
+android {
+ defaultConfig {
+ minSdkVersion 21
+ }
+}
+
+dependencies {
+ api("androidx.annotation:annotation:1.3.0")
+ implementation(libs.kotlinStdlib)
+ implementation(projectOrArtifact(":compose:runtime:runtime"))
+ implementation(projectOrArtifact(":tracing:tracing-perfetto"))
+ implementation("androidx.startup:startup-runtime:1.1.1")
+ androidTestImplementation(libs.testExtJunit)
+ androidTestImplementation(libs.testRunner)
+ androidTestImplementation(libs.truth)
+}
+
+tasks.withType(KotlinCompile).configureEach {
+ kotlinOptions {
+ freeCompilerArgs += "-opt-in=kotlin.RequiresOptIn"
+ }
+}
+
+androidx {
+ name = "Compose Runtime: Tracing"
+ runApiTasks= new RunApiTasks.No("The API is still evolving") // TODO(b/231444429)
+ publish = Publish.SNAPSHOT_AND_RELEASE
+ mavenVersion = LibraryVersions.COMPOSE_RUNTIME_TRACING
+ mavenGroup = LibraryGroups.COMPOSE_RUNTIME
+ inceptionYear = "2022"
+ description = "Allows for additional tracing in a Compose app (e.g. tracing of Composables taking part in a Recomposition"
+}
diff --git a/compose/runtime/runtime-tracing/src/androidTest/AndroidManifest.xml b/compose/runtime/runtime-tracing/src/androidTest/AndroidManifest.xml
new file mode 100644
index 0000000..0b0410b
--- /dev/null
+++ b/compose/runtime/runtime-tracing/src/androidTest/AndroidManifest.xml
@@ -0,0 +1,36 @@
+<!--
+ Copyright 2022 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.
+ -->
+
+<!--
+ ~ Copyright (C) 2022 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.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="androidx.compose.runtime.tracing.test">
+
+</manifest>
diff --git a/compose/runtime/runtime-tracing/src/androidTest/java/androidx/compose/runtime/tracing/test/TracingInitializerTest.kt b/compose/runtime/runtime-tracing/src/androidTest/java/androidx/compose/runtime/tracing/test/TracingInitializerTest.kt
new file mode 100644
index 0000000..93af8de
--- /dev/null
+++ b/compose/runtime/runtime-tracing/src/androidTest/java/androidx/compose/runtime/tracing/test/TracingInitializerTest.kt
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2022 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.
+ */
+
+/*
+ * Copyright 2022 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.
+ */
+
+package androidx.compose.runtime.tracing.test
+
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.google.common.truth.Truth.assertThat
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+/**
+ * Fake test. The module is actually tested inside
+ * [androidx.compose.integration.macrobenchmark.TrivialTracingBenchmark].
+ */
+class TracingInitializerTest {
+ @Test
+ fun two_plus_two() {
+ assertThat<Int>(2 + 2).isEqualTo(4)
+ }
+}
diff --git a/compose/runtime/runtime-tracing/src/main/AndroidManifest.xml b/compose/runtime/runtime-tracing/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..b3f90e5
--- /dev/null
+++ b/compose/runtime/runtime-tracing/src/main/AndroidManifest.xml
@@ -0,0 +1,49 @@
+<!--
+ Copyright 2022 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.
+ -->
+
+<!--
+ ~ Copyright (C) 2022 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.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
+ package="androidx.compose.runtime.tracing">
+
+ <application>
+ <provider
+ android:name="androidx.startup.InitializationProvider"
+ android:authorities="${applicationId}.androidx-startup"
+ android:exported="false"
+ tools:node="merge">
+ <meta-data
+ android:name="androidx.compose.runtime.tracing.TracingInitializer"
+ android:value="androidx.startup" />
+ </provider>
+ </application>
+
+</manifest>
diff --git a/compose/runtime/runtime-tracing/src/main/java/androidx/compose/runtime/tracing/TracingInitializer.kt b/compose/runtime/runtime-tracing/src/main/java/androidx/compose/runtime/tracing/TracingInitializer.kt
new file mode 100644
index 0000000..3721077
--- /dev/null
+++ b/compose/runtime/runtime-tracing/src/main/java/androidx/compose/runtime/tracing/TracingInitializer.kt
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2022 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.
+ */
+
+/*
+ * Copyright 2022 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.
+ */
+package androidx.compose.runtime.tracing
+
+import android.content.Context
+import androidx.compose.runtime.Composer
+import androidx.compose.runtime.CompositionTracer
+import androidx.compose.runtime.InternalComposeTracingApi
+import androidx.startup.Initializer
+import androidx.tracing.perfetto.Tracing
+
+@OptIn(InternalComposeTracingApi::class)
+class TracingInitializer : Initializer<Unit> {
+ override fun create(context: Context) {
+ Composer.setTracer(object : CompositionTracer {
+ override fun traceEventStart(key: Int, dirty1: Int, dirty2: Int, info: String) =
+ Tracing.traceEventStart(key, info)
+
+ override fun traceEventEnd() = Tracing.traceEventEnd()
+
+ override fun isTraceInProgress(): Boolean = Tracing.isEnabled
+ })
+ }
+
+ override fun dependencies(): List<Class<out Initializer<*>>> = emptyList()
+}
diff --git a/libraryversions.toml b/libraryversions.toml
index ec0529e..8dd392c 100644
--- a/libraryversions.toml
+++ b/libraryversions.toml
@@ -20,6 +20,7 @@
COLLECTION2 = "1.3.0-alpha01"
COMPOSE = "1.2.0-beta01"
COMPOSE_MATERIAL3 = "1.0.0-alpha11"
+COMPOSE_RUNTIME_TRACING = "1.0.0-alpha01"
CONTENTPAGER = "1.1.0-alpha01"
COORDINATORLAYOUT = "1.3.0-alpha01"
CORE = "1.8.0-rc01"
diff --git a/settings.gradle b/settings.gradle
index e669502..da82136 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -458,6 +458,7 @@
includeProject(":compose:runtime:runtime-lint", [BuildType.COMPOSE, BuildType.MAIN])
includeProject(":compose:runtime:runtime-livedata", [BuildType.COMPOSE])
includeProject(":compose:runtime:runtime-livedata:runtime-livedata-samples", "compose/runtime/runtime-livedata/samples", [BuildType.COMPOSE])
+includeProject(":compose:runtime:runtime-tracing", [BuildType.COMPOSE])
includeProject(":compose:runtime:runtime-rxjava2", [BuildType.COMPOSE])
includeProject(":compose:runtime:runtime-rxjava2:runtime-rxjava2-samples", "compose/runtime/runtime-rxjava2/samples", [BuildType.COMPOSE])
includeProject(":compose:runtime:runtime-rxjava3", [BuildType.COMPOSE])