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 """))