1 /*
2  * Copyright 2023 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package androidx.benchmark.macro.perfetto
18 
19 import androidx.benchmark.traceprocessor.TraceProcessor
20 import androidx.benchmark.traceprocessor.processNameLikePkg
21 
22 internal object MemoryCountersQuery {
23     // https://perfetto.dev/docs/data-sources/memory-counters
getQuerynull24     internal fun getQuery(targetPackageName: String) =
25         """
26         SELECT
27             track.name as counter_name,
28             SUM(value)
29         FROM counter
30             LEFT JOIN process_counter_track as track on counter.track_id = track.id
31             LEFT JOIN process using (upid)
32         WHERE
33             ${processNameLikePkg(targetPackageName)} AND
34             track.name LIKE 'mem.%.count'
35         GROUP BY counter_name
36     """
37             .trimIndent()
38 
39     private const val MINOR_PAGE_FAULTS_COUNT = "mem.mm.min_flt.count"
40     private const val MAJOR_PAGE_FAULTS_COUNT = "mem.mm.maj_flt.count"
41     private const val PAGE_FAULTS_BACKED_BY_SWAP_CACHE_COUNT = "mem.mm.swp_flt.count"
42     private const val PAGE_FAULTS_BACKED_BY_READ_IO_COUNT = "mem.mm.read_io.count"
43     private const val MEMORY_COMPACTION_EVENTS_COUNT = "mem.mm.compaction.count"
44     private const val MEMORY_RECLAIM_EVENTS_COUNT = "mem.mm.reclaim.count"
45 
46     data class SubMetrics(
47         // Minor Page Faults
48         val minorPageFaults: Double,
49         // Major Page Faults
50         val majorPageFaults: Double,
51         // Page Faults Served by Swap Cache
52         val pageFaultsBackedBySwapCache: Double,
53         // Read Page Faults backed by I/O
54         val pageFaultsBackedByReadIO: Double,
55         // Memory Compaction Events
56         val memoryCompactionEvents: Double,
57         // Memory Reclaim Events
58         val memoryReclaimEvents: Double
59     )
60 
61     fun getMemoryCounters(session: TraceProcessor.Session, targetPackageName: String): SubMetrics? {
62         val queryResultIterator =
63             session.query(query = getQuery(targetPackageName = targetPackageName))
64 
65         val rows = queryResultIterator.toList()
66         return if (rows.isEmpty()) {
67             null
68         } else {
69             val summations: Map<String, Double> =
70                 rows.associate { it.string("counter_name") to it.double("SUM(value)") }
71             SubMetrics(
72                 minorPageFaults = summations[MINOR_PAGE_FAULTS_COUNT] ?: 0.0,
73                 majorPageFaults = summations[MAJOR_PAGE_FAULTS_COUNT] ?: 0.0,
74                 pageFaultsBackedBySwapCache =
75                     summations[PAGE_FAULTS_BACKED_BY_SWAP_CACHE_COUNT] ?: 0.0,
76                 pageFaultsBackedByReadIO = summations[PAGE_FAULTS_BACKED_BY_READ_IO_COUNT] ?: 0.0,
77                 memoryCompactionEvents = summations[MEMORY_COMPACTION_EVENTS_COUNT] ?: 0.0,
78                 memoryReclaimEvents = summations[MEMORY_RECLAIM_EVENTS_COUNT] ?: 0.0
79             )
80         }
81     }
82 }
83