• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1#!/usr/bin/env python3
2# Copyright (C) 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 a
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
16from python.generators.diff_tests.testing import Path, DataPath, Metric
17from python.generators.diff_tests.testing import Csv, Json, TextProto
18from python.generators.diff_tests.testing import DiffTestBlueprint
19from python.generators.diff_tests.testing import TestSuite
20
21
22class GraphicsMetrics(TestSuite):
23  def test_frame_missed_metrics(self):
24    return DiffTestBlueprint(
25        trace=Path('frame_missed.py'),
26        query=Metric('android_surfaceflinger'),
27        out=TextProto(r"""
28        android_surfaceflinger {
29          missed_frames: 3
30          missed_hwc_frames: 0
31          missed_gpu_frames: 0
32          missed_frame_rate: 0.42857142857142855 # = 3/7
33          gpu_invocations: 0
34          metrics_per_display: {
35            display_id: "101"
36            missed_frames: 2
37            missed_hwc_frames: 0
38            missed_gpu_frames: 0
39            missed_frame_rate: 0.5
40          }
41          metrics_per_display: {
42            display_id: "102"
43            missed_frames: 1
44            missed_hwc_frames: 0
45            missed_gpu_frames: 0
46            missed_frame_rate: 0.33333333333333333
47          }
48        }
49        """))
50
51  def test_surfaceflinger_gpu_invocation(self):
52    return DiffTestBlueprint(
53        trace=Path('surfaceflinger_gpu_invocation.py'),
54        query=Metric('android_surfaceflinger'),
55        out=TextProto(r"""
56        android_surfaceflinger {
57          missed_frames: 0
58          missed_hwc_frames: 0
59          missed_gpu_frames: 0
60          gpu_invocations: 4
61          avg_gpu_waiting_dur_ms: 4
62          total_non_empty_gpu_waiting_dur_ms: 11
63        }
64        """))
65
66  # GPU metrics
67  def test_gpu_metric(self):
68    return DiffTestBlueprint(
69        trace=Path('gpu_metric.py'),
70        query=Metric('android_gpu'),
71        out=TextProto(r"""
72        android_gpu {
73          processes {
74            name: "app_1"
75            mem_max: 8
76            mem_min: 2
77            mem_avg: 3
78          }
79          processes {
80            name: "app_2"
81            mem_max: 10
82            mem_min: 6
83            mem_avg: 8
84          }
85          mem_max: 4
86          mem_min: 1
87          mem_avg: 1
88        }
89        """))
90
91  def test_gpu_frequency_metric(self):
92    return DiffTestBlueprint(
93        trace=Path('gpu_frequency_metric.textproto'),
94        query=Metric('android_gpu'),
95        out=Path('gpu_frequency_metric.out'))
96
97  # Android Jank CUJ metric
98  def test_android_jank_cuj(self):
99    return DiffTestBlueprint(
100        trace=Path('android_jank_cuj.py'),
101        query=Metric('android_jank_cuj'),
102        out=Path('android_jank_cuj.out'))
103
104  def test_android_jank_cuj_query(self):
105    return DiffTestBlueprint(
106        trace=Path('android_jank_cuj.py'),
107        query=Path('android_jank_cuj_query_test.sql'),
108        out=Path('android_jank_cuj_query.out'))
109
110  # Composition layer
111  def test_composition_layer_count(self):
112    return DiffTestBlueprint(
113        trace=Path('composition_layer.py'),
114        query="""
115        SELECT RUN_METRIC('android/android_hwcomposer.sql');
116
117        SELECT display_id, AVG(value)
118        FROM total_layers
119        GROUP BY display_id;
120        """,
121        out=Csv("""
122        "display_id","AVG(value)"
123        "0",3.000000
124        "1",5.000000
125        """))
126
127  # G2D metrics TODO(rsavitski): find a real trace and double-check that the
128  # is realistic. One kernel's source I checked had tgid=0 for all counter
129  # Initial support was added/discussed in b/171296908.
130  def test_g2d_metrics(self):
131    return DiffTestBlueprint(
132        trace=Path('g2d_metrics.textproto'),
133        query=Metric('g2d'),
134        out=Path('g2d_metrics.out'))
135
136  # Composer execution
137  def test_composer_execution(self):
138    return DiffTestBlueprint(
139        trace=Path('composer_execution.py'),
140        query="""
141        SELECT RUN_METRIC('android/composer_execution.sql',
142          'output', 'hwc_execution_spans');
143
144        SELECT
145          validation_type,
146          display_id,
147          COUNT(*) AS count,
148          SUM(execution_time_ns) AS total
149        FROM hwc_execution_spans
150        GROUP BY validation_type, display_id
151        ORDER BY validation_type, display_id;
152        """,
153        out=Csv("""
154        "validation_type","display_id","count","total"
155        "separated_validation","1",1,200
156        "skipped_validation","0",2,200
157        "skipped_validation","1",1,100
158        "unknown","1",1,0
159        "unskipped_validation","0",1,200
160        """))
161
162  # Display metrics
163  def test_display_metrics(self):
164    return DiffTestBlueprint(
165        trace=Path('display_metrics.py'),
166        query=Metric('display_metrics'),
167        out=TextProto(r"""
168        display_metrics {
169          total_duplicate_frames: 0
170          duplicate_frames_logged: 0
171          total_dpu_underrun_count: 0
172          refresh_rate_switches: 5
173          refresh_rate_stats {
174            refresh_rate_fps: 60
175            count: 2
176            total_dur_ms: 2
177            avg_dur_ms: 1
178          }
179          refresh_rate_stats {
180            refresh_rate_fps: 90
181            count: 2
182            total_dur_ms: 2
183            avg_dur_ms: 1
184          }
185          refresh_rate_stats {
186            refresh_rate_fps: 120
187            count: 1
188            total_dur_ms: 2
189            avg_dur_ms: 2
190          }
191          update_power_state {
192            avg_runtime_micro_secs: 4000
193          }
194        }
195        """))
196
197  # DPU vote clock and bandwidth
198  def test_dpu_vote_clock_bw(self):
199    return DiffTestBlueprint(
200        trace=Path('dpu_vote_clock_bw.textproto'),
201        query=Metric('android_hwcomposer'),
202        out=TextProto(r"""
203        android_hwcomposer {
204          skipped_validation_count: 0
205          unskipped_validation_count: 0
206          separated_validation_count: 0
207          unknown_validation_count: 0
208          dpu_vote_metrics {
209            tid: 237
210            avg_dpu_vote_clock: 206250
211            avg_dpu_vote_avg_bw: 210000
212            avg_dpu_vote_peak_bw: 205000
213            avg_dpu_vote_rt_bw: 271000
214          }
215          dpu_vote_metrics {
216            tid: 299
217            avg_dpu_vote_clock: 250000
218          }
219        }
220        """))