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