MemoryCountersQuery.kt
/*
* Copyright 2023 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.macro.perfetto
import android.util.Log
import androidx.benchmark.macro.TAG
import androidx.benchmark.perfetto.PerfettoTraceProcessor
import androidx.benchmark.perfetto.processNameLikePkg
import org.intellij.lang.annotations.Language
internal object MemoryCountersQuery {
// https://perfetto.dev/docs/data-sources/memory-counters
@Language("sql")
internal fun getFullQuery(targetPackageName: String) = """
SELECT
track.name as counter_name,
process.name as process_name,
ts,
value
FROM counter
LEFT JOIN process_counter_track as track on counter.track_id = track.id
LEFT JOIN process using (upid)
WHERE
${processNameLikePkg(targetPackageName)} AND
track.name LIKE 'mem.%.count'
""".trimIndent()
private const val MINOR_PAGE_FAULTS_COUNT = "mem.mm.min_flt.count"
private const val MAJOR_PAGE_FAULTS_COUNT = "mem.mm.maj_flt.count"
private const val PAGE_FAULTS_BACKED_BY_SWAP_CACHE_COUNT = "mem.mm.swp_flt.count"
private const val PAGE_FAULTS_BACKED_BY_READ_IO_COUNT = "mem.mm.read_io.count"
private const val MEMORY_COMPACTION_EVENTS_COUNT = "mem.mm.compaction.count"
private const val MEMORY_RECLAIM_EVENTS_COUNT = "mem.mm.reclaim.count"
data class SubMetrics(
// Minor Page Faults
val minorPageFaults: Double,
// Major Page Faults
val majorPageFaults: Double,
// Page Faults Served by Swap Cache
val pageFaultsBackedBySwapCache: Double,
// Read Page Faults backed by I/O
val pageFaultsBackedByReadIO: Double,
// Memory Compaction Events
val memoryCompactionEvents: Double,
// Memory Reclaim Events
val memoryReclaimEvents: Double
)
fun getMemoryCounters(
session: PerfettoTraceProcessor.Session,
targetPackageName: String
): SubMetrics? {
val queryResultIterator = session.query(
query = getFullQuery(targetPackageName = targetPackageName)
)
var minorPageFaults = 0.0
var majorPageFaults = 0.0
var faultsBackedBySwapCache = 0.0
var faultsBackedByReadIO = 0.0
var memoryCompactionEvents = 0.0
var memoryReclaimEvents = 0.0
val rows = queryResultIterator.toList()
if (rows.isEmpty()) {
return null
} else {
rows.forEach { row ->
when (row.string("counter_name")) {
MINOR_PAGE_FAULTS_COUNT -> {
minorPageFaults += row.double("value")
}
MAJOR_PAGE_FAULTS_COUNT -> {
majorPageFaults += row.double("value")
}
PAGE_FAULTS_BACKED_BY_SWAP_CACHE_COUNT -> {
faultsBackedBySwapCache += row.double("value")
}
PAGE_FAULTS_BACKED_BY_READ_IO_COUNT -> {
faultsBackedByReadIO += row.double("value")
}
MEMORY_COMPACTION_EVENTS_COUNT -> {
memoryCompactionEvents += row.double("value")
}
MEMORY_RECLAIM_EVENTS_COUNT -> {
memoryReclaimEvents += row.double("value")
}
else -> Log.d(TAG, "Unknown counter: $row")
}
}
return SubMetrics(
minorPageFaults = minorPageFaults,
majorPageFaults = majorPageFaults,
pageFaultsBackedBySwapCache = faultsBackedBySwapCache,
pageFaultsBackedByReadIO = faultsBackedByReadIO,
memoryCompactionEvents = memoryCompactionEvents,
memoryReclaimEvents = memoryReclaimEvents
)
}
}
}