1 /*
<lambda>null2  * 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.macro.MemoryUsageMetric
20 import androidx.benchmark.macro.MemoryUsageMetric.Mode
21 import androidx.benchmark.traceprocessor.TraceProcessor
22 import androidx.benchmark.traceprocessor.processNameLikePkg
23 
24 internal object MemoryUsageQuery {
25     // https://perfetto.dev/docs/data-sources/memory-counters
26     internal fun getQuery(targetPackageName: String, mode: Mode) =
27         when (mode) {
28             Mode.Last -> "SELECT track.name as counter_name, MAX(ts), value "
29             Mode.Max -> "SELECT track.name as counter_name, MAX(value) as value "
30         } +
31             """
32             FROM counter
33                 LEFT JOIN process_counter_track as track on counter.track_id = track.id
34                 LEFT JOIN process using (upid)
35             WHERE
36                 ${processNameLikePkg(targetPackageName)} AND
37                 (
38                     track.name LIKE 'mem.rss%' OR
39                     track.name LIKE 'Heap size (KB)' OR
40                     track.name LIKE 'GPU Memory'
41                 )
42             GROUP BY counter_name
43         """
44                 .trimIndent()
45 
46     fun getMemoryUsageKb(
47         session: TraceProcessor.Session,
48         targetPackageName: String,
49         mode: Mode
50     ): Map<MemoryUsageMetric.SubMetric, Int>? {
51         val queryResultIterator =
52             session.query(query = getQuery(targetPackageName = targetPackageName, mode))
53 
54         val rows = queryResultIterator.toList()
55         return if (rows.isEmpty()) {
56             null
57         } else {
58             rows
59                 .mapNotNull { row ->
60                     val counterName = row.string("counter_name")
61                     val metric =
62                         MemoryUsageMetric.SubMetric.values().firstOrNull {
63                             it.counterName == counterName
64                         }
65                     if (metric == null) {
66                         null
67                     } else {
68                         val measurement = row.double("value")
69                         metric to
70                             if (metric.alreadyInKb) {
71                                 measurement.toInt()
72                             } else {
73                                 measurement.toInt() / 1024
74                             }
75                     }
76                 }
77                 .toMap()
78         }
79     }
80 }
81