blob: 60d54ed3d336fe9ab9482213d30c3fbe7b3619b4 [file] [log] [blame]
/*
* Copyright 2021 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.benchmark.perfetto
import android.os.Build
import androidx.annotation.RequiresApi
import androidx.annotation.RestrictTo
import androidx.benchmark.Shell
import perfetto.protos.DataSourceConfig
import perfetto.protos.AndroidPowerConfig
import perfetto.protos.FtraceConfig
import perfetto.protos.MeminfoCounters
import perfetto.protos.ProcessStatsConfig
import perfetto.protos.SysStatsConfig
import perfetto.protos.TraceConfig
import perfetto.protos.TraceConfig.BufferConfig
import perfetto.protos.TraceConfig.BufferConfig.FillPolicy
private fun ftraceDataSource(
atraceApps: List<String>
) = TraceConfig.DataSource(
config = DataSourceConfig(
name = "linux.ftrace",
target_buffer = 0,
ftrace_config = FtraceConfig(
ftrace_events = listOf(
// We need to do process tracking to ensure kernel ftrace events targeted at short-lived
// threads are associated correctly
"task/task_newtask",
"task/task_rename",
"sched/sched_process_exit",
"sched/sched_process_free",
// Memory events
"mm_event/mm_event_record",
"kmem/rss_stat",
"kmem/ion_heap_shrink",
"kmem/ion_heap_grow",
"ion/ion_stat",
"oom/oom_score_adj_update",
// Old (kernel) LMK
"lowmemorykiller/lowmemory_kill",
),
atrace_categories = listOf(
AtraceTag.ActivityManager,
AtraceTag.Audio,
AtraceTag.BinderDriver,
AtraceTag.Camera,
AtraceTag.Dalvik,
AtraceTag.Frequency,
AtraceTag.Graphics,
AtraceTag.HardwareModules,
AtraceTag.Idle,
AtraceTag.Input,
AtraceTag.MemReclaim,
AtraceTag.Resources,
AtraceTag.Scheduling,
AtraceTag.Synchronization,
AtraceTag.View,
AtraceTag.WindowManager
// "webview" not included to workaround b/190743595
// "memory" not included as some Q devices requiring ftrace_event
// configuration directly to collect this data. See b/171085599
).filter {
// filter to only supported tags on unrooted build
// TODO: use root-only tags as needed
it.supported(api = Build.VERSION.SDK_INT, rooted = false)
}.map {
it.tag
},
atrace_apps = atraceApps,
compact_sched = FtraceConfig.CompactSchedConfig(enabled = true)
)
)
)
private val PROCESS_STATS_DATASOURCE = TraceConfig.DataSource(
config = DataSourceConfig(
name = "linux.process_stats",
target_buffer = 1,
process_stats_config = ProcessStatsConfig(
proc_stats_poll_ms = 10000,
// This flag appears to be unreliable on API 29 unbundled perfetto, so to avoid very
// frequent proc stats polling to name processes correctly, we currently use unbundled
// perfetto on API 29, even though the bundled version exists. (b/218668335)
scan_all_processes_on_start = true
)
)
)
private val LINUX_SYS_STATS_DATASOURCE = TraceConfig.DataSource(
config = DataSourceConfig(
name = "linux.sys_stats",
target_buffer = 1,
sys_stats_config = SysStatsConfig(
meminfo_period_ms = 1000,
meminfo_counters = listOf(
MeminfoCounters.MEMINFO_MEM_TOTAL,
MeminfoCounters.MEMINFO_MEM_FREE,
MeminfoCounters.MEMINFO_MEM_AVAILABLE,
MeminfoCounters.MEMINFO_BUFFERS,
MeminfoCounters.MEMINFO_CACHED,
MeminfoCounters.MEMINFO_SWAP_CACHED,
MeminfoCounters.MEMINFO_ACTIVE,
MeminfoCounters.MEMINFO_INACTIVE,
MeminfoCounters.MEMINFO_ACTIVE_ANON,
MeminfoCounters.MEMINFO_INACTIVE_ANON,
MeminfoCounters.MEMINFO_ACTIVE_FILE,
MeminfoCounters.MEMINFO_INACTIVE_FILE,
MeminfoCounters.MEMINFO_UNEVICTABLE,
MeminfoCounters.MEMINFO_SWAP_TOTAL,
MeminfoCounters.MEMINFO_SWAP_FREE,
MeminfoCounters.MEMINFO_DIRTY,
MeminfoCounters.MEMINFO_WRITEBACK,
MeminfoCounters.MEMINFO_ANON_PAGES,
MeminfoCounters.MEMINFO_MAPPED,
MeminfoCounters.MEMINFO_SHMEM,
)
)
)
)
private val ANDROID_POWER_DATASOURCE = TraceConfig.DataSource(
config = DataSourceConfig(
name = "android.power",
android_power_config = AndroidPowerConfig(
battery_poll_ms = 250,
battery_counters = listOf(
AndroidPowerConfig.BatteryCounters.BATTERY_COUNTER_CAPACITY_PERCENT,
AndroidPowerConfig.BatteryCounters.BATTERY_COUNTER_CHARGE,
AndroidPowerConfig.BatteryCounters.BATTERY_COUNTER_CURRENT
),
collect_power_rails = true
)
)
)
/**
* Config for perfetto.
*
* Eventually, this should be more configurable.
*
* @suppress
*/
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
fun perfettoConfig(
atraceApps: List<String>
) = TraceConfig(
buffers = listOf(
BufferConfig(size_kb = 32768, FillPolicy.RING_BUFFER),
BufferConfig(size_kb = 4096, FillPolicy.RING_BUFFER)
),
data_sources = listOf(
ftraceDataSource(atraceApps),
PROCESS_STATS_DATASOURCE,
LINUX_SYS_STATS_DATASOURCE,
ANDROID_POWER_DATASOURCE,
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
write_into_file = true,
file_write_period_ms = 2500,
// multiple of file_write_period_ms, enables trace processor to work in batches
flush_period_ms = 5000
)
@RequiresApi(21) // needed for shell access
internal fun TraceConfig.validateAndEncode(): ByteArray {
val ftraceConfig = data_sources
.mapNotNull { it.config?.ftrace_config }
.first()
// check tags against known-supported tags based on SDK_INT / root status
val supportedTags = AtraceTag.supported(
api = Build.VERSION.SDK_INT,
rooted = Shell.isSessionRooted()
).map { it.tag }.toSet()
val unsupportedTags = (ftraceConfig.atrace_categories - supportedTags)
check(unsupportedTags.isEmpty()) {
"Error - attempted to use unsupported atrace tags: $unsupportedTags"
}
if (Build.VERSION.SDK_INT < 28) {
check(!ftraceConfig.atrace_apps.contains("*")) {
"Support for wildcard (*) app matching in atrace added in API 28"
}
}
if (Build.VERSION.SDK_INT < 24) {
val packageList = ftraceConfig.atrace_apps.joinToString(",")
check(packageList.length <= 91) {
"Unable to trace package list (\"$packageList\").length = " +
"${packageList.length} > 91 chars, which is the limit before API 24"
}
}
return encode()
}