Demeter is a performance measurement library that could simplify performance issues investigation in your app. It's also useful to give a specially prepared build with Demeter inside to your QA team to use it during regression testing process and upload performance reports in the end.
- Tracer: Measures project methods with information about execution thread, execution time and helps to sort by hazard level
- Inject: Wraps and calculates Injected constructors and their dependencies. It's useful to identify problems with a dagger graph
- Enriches methods with profileable sections that help to investigate problems in Android Profiler or Perfetto
- Compose: observes StateObject changes and discovers them
- Exports measurements to Excel format and Flipper
Injected constructor
Tracer for methods
Method export
Inspect Compose recompositions and ObjectStates
Integrated Demeter represents an Activity that starts by notification click in any place of your application.
Demeter foundation consists of libraries:
demeter-core- contains base interface without implementations. It also could be applied for release build typedemeter-profiler- the main profiler implementation that should be applied for dev build type. You must check this artifact is not attached to release build type!-
base- base profiler logic
-
ui- profiler ui
demeter-gradle-plugin- main Demeter Gradle Plugin
Functionality is provided via specifying profiler plugins by consumer needs:
demeter-tracer-profiler-plugin- tracing methodsdemeter-inject-profiler-plugin- analyzing @Inject constructor initializationdemeter-compose-profiler-plugin- Jetpack Compose analyzer
Note: When using published Maven artifacts (not building from source), you need to explicitly add plugin dependencies in addition to the main profiler dependency.
For dev build type:
- Add demeter plugin
plugins {
id("com.yandex.demeter")
}- Add implementation of the profiler:
dependencies {
// if buildType == Dev/Debug/etc...
implementation("com.yandex.demeter:profiler")
// Add plugin dependencies for Maven artifacts (required when using published artifacts)
// Only add the plugins you actually need
// It enables plain plugin with reporter that your are able to override:
implementation("com.yandex.demeter:profiler-tracer-plugin:VERSION") // for TracerDemeterPlugin()
implementation("com.yandex.demeter:profiler-inject-plugin:VERSION") // for InjectDemeterPlugin()
implementation("com.yandex.demeter:profiler-compose-plugin:VERSION") // for ComposeDemeterPlugin()
// Also it's possible to enable UI interface. See below how to initialize it:
implementation("com.yandex.demeter:profiler-tracer-ui-plugin:VERSION")
implementation("com.yandex.demeter:profiler-inject-ui-plugin:VERSION")
implementation("com.yandex.demeter:profiler-compose-ui-plugin:VERSION")
}- Open your AndroidManifest and add:
<profileable
android:enabled="true"
android:shell="true"
tools:ignore="UnusedAttribute" />That helps Demeter to check and profile methods better. Do it only for Dev build types!
- Add in your Application class:
override fun onCreate() {
super.onCreate()
...
Demeter.init(
DemeterInitializer(
plugins = listOf(
TracerDemeterPlugin(), // turn on Tracer plugin
InjectDemeterPlugin(), // turn on Inject plugin
ComposeDemeterPlugin(), // turn on Compose plugin
),
)
)
...
}If you'd like to turn on plugins UI:
override fun onCreate() {
super.onCreate()
...
Demeter.init(
UiDemeterInitializer(
context = this,
uiPlugins = listOf(
TracerUiDemeterPlugin(), // turn on Tracer plugin
InjectUiDemeterPlugin(), // turn on Inject plugin
ComposeUiDemeterPlugin(), // turn on Compose plugin
),
)
)
...
}- Configure demeter plugin. You can apply only subplugins you need:
demeter {
tracer {
includedClasses = listOf("com.yandex.myapp") // list of packages that should be analyzed
}
inject {
includedClasses = listOf("com.yandex.myapp") // list of packages that should be analyzed
excludedClasses = listOf("com.yandex.myapp.excluded") // list of packages that shouldn't be analyzed
}
compose() // turn on compose inspections
}It's also possible to configure inside builtTypes block separately:
android {
...
buildTypes {
getByName("debug") {
demeter {
tracer()
inject()
compose()
}
}
}
}- Run and control!
Demeter feature plugins can be applied via main plugin:
plugins {
id("com.yandex.demeter")
}or directly:
plugins {
id("com.yandex.demeter.tracer")
id("com.yandex.demeter.inject")
...
}Main plugin applies only plugins you specified in demeter block
Feature plugins:
tracer-gradle-plugininject-gradle-plugincompose-gradle-plugin
Problem: I get crash with stacktrace like
java.lang.AssertionError: Built-in class kotlin.Any is not found
Solution: Check you don't exclude .kotlin_builtins files from build
packagingOptions {
resources {
excludes += ['**/kotlin/**', '**.kotlin_builtins'] // or any other .kotlin_builtins exclude options
}
}




