blob: 7ab6c8901213d1111ce18010949ad3ba82f849c9 [file] [log] [blame]
#!/usr/bin/env python3
# Copyright (C) 2023 The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License a
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from python.generators.diff_tests.testing import Path, DataPath, Metric
from python.generators.diff_tests.testing import Csv, Json, TextProto
from python.generators.diff_tests.testing import DiffTestBlueprint
from python.generators.diff_tests.testing import TestSuite
class Graphics(TestSuite):
# Contains tests for graphics related events and tables. Graphics frame
# trace tests.
def test_graphics_frame_events(self):
return DiffTestBlueprint(
trace=Path('graphics_frame_events.py'),
query="""
SELECT ts, gpu_track.name AS track_name, dur, frame_slice.name AS slice_name,
frame_number, layer_name
FROM gpu_track
LEFT JOIN frame_slice ON gpu_track.id = frame_slice.track_id
WHERE scope = 'graphics_frame_event'
ORDER BY ts;
""",
out=Path('graphics_frame_events.out'))
# GPU Memory ftrace packets
def test_gpu_mem_total(self):
return DiffTestBlueprint(
trace=Path('gpu_mem_total.py'),
query=Path('gpu_mem_total_test.sql'),
out=Csv("""
"name","unit","description","ts","pid","value"
"GPU Memory","7","Total GPU memory used by the entire system",0,"[NULL]",123
"GPU Memory","7","Total GPU memory used by this process",0,1,100
"GPU Memory","7","Total GPU memory used by the entire system",5,"[NULL]",256
"GPU Memory","7","Total GPU memory used by this process",5,1,233
"GPU Memory","7","Total GPU memory used by the entire system",10,"[NULL]",123
"GPU Memory","7","Total GPU memory used by this process",10,1,0
"""))
def test_gpu_mem_total_after_free_gpu_mem_total(self):
return DiffTestBlueprint(
trace=Path('gpu_mem_total_after_free.py'),
query=Path('gpu_mem_total_test.sql'),
out=Csv("""
"name","unit","description","ts","pid","value"
"GPU Memory","7","Total GPU memory used by this process",0,1,100
"GPU Memory","7","Total GPU memory used by this process",5,1,233
"GPU Memory","7","Total GPU memory used by this process",10,1,50
"""))
# Clock sync
def test_clock_sync(self):
return DiffTestBlueprint(
trace=Path('clock_sync.py'),
query="""
SELECT ts, cast(value AS integer) AS int_value
FROM counters
WHERE name GLOB 'gpu_counter*';
""",
out=Csv("""
"ts","int_value"
1,3
102,5
1003,7
1005,9
2006,11
2010,12
2013,13
3007,14
3010,15
"""))
# Android SurfaceFlinger metrics
def test_frame_missed_event_frame_missed(self):
return DiffTestBlueprint(
trace=Path('frame_missed.py'),
query="""
SELECT RUN_METRIC('android/android_surfaceflinger.sql');
SELECT ts, dur
FROM android_surfaceflinger_event;
""",
out=Csv("""
"ts","dur"
100,1
102,1
103,1
"""))
def test_frame_missed_metrics(self):
return DiffTestBlueprint(
trace=Path('frame_missed.py'),
query=Metric('android_surfaceflinger'),
out=TextProto(r"""
android_surfaceflinger {
missed_frames: 3
missed_hwc_frames: 0
missed_gpu_frames: 0
missed_frame_rate: 0.42857142857142855 # = 3/7
gpu_invocations: 0
metrics_per_display: {
display_id: "101"
missed_frames: 2
missed_hwc_frames: 0
missed_gpu_frames: 0
missed_frame_rate: 0.5
}
metrics_per_display: {
display_id: "102"
missed_frames: 1
missed_hwc_frames: 0
missed_gpu_frames: 0
missed_frame_rate: 0.33333333333333333
}
}
"""))
def test_surfaceflinger_gpu_invocation(self):
return DiffTestBlueprint(
trace=Path('surfaceflinger_gpu_invocation.py'),
query=Metric('android_surfaceflinger'),
out=TextProto(r"""
android_surfaceflinger {
missed_frames: 0
missed_hwc_frames: 0
missed_gpu_frames: 0
gpu_invocations: 4
avg_gpu_waiting_dur_ms: 4
total_non_empty_gpu_waiting_dur_ms: 11
}
"""))
# GPU metrics
def test_gpu_metric(self):
return DiffTestBlueprint(
trace=Path('gpu_metric.py'),
query=Metric('android_gpu'),
out=TextProto(r"""
android_gpu {
processes {
name: "app_1"
mem_max: 8
mem_min: 2
mem_avg: 3
}
processes {
name: "app_2"
mem_max: 10
mem_min: 6
mem_avg: 8
}
mem_max: 4
mem_min: 1
mem_avg: 2
}
"""))
def test_gpu_frequency_metric(self):
return DiffTestBlueprint(
trace=Path('gpu_frequency_metric.textproto'),
query=Metric('android_gpu'),
out=Path('gpu_frequency_metric.out'))
# Android Jank CUJ metric
def test_android_jank_cuj(self):
return DiffTestBlueprint(
trace=Path('android_jank_cuj.py'),
query=Metric('android_jank_cuj'),
out=Path('android_jank_cuj.out'))
def test_android_jank_cuj_query(self):
return DiffTestBlueprint(
trace=Path('android_jank_cuj.py'),
query=Path('android_jank_cuj_query_test.sql'),
out=Path('android_jank_cuj_query.out'))
# Frame Timeline event trace tests
def test_expected_frame_timeline_events(self):
return DiffTestBlueprint(
trace=Path('frame_timeline_events.py'),
query=Path('expected_frame_timeline_events_test.sql'),
out=Csv("""
"ts","dur","pid","display_frame_token","surface_frame_token","layer_name"
20,6,666,2,0,"[NULL]"
21,15,1000,4,1,"Layer1"
40,6,666,4,0,"[NULL]"
41,15,1000,6,5,"Layer1"
80,6,666,6,0,"[NULL]"
90,16,1000,8,7,"Layer1"
120,6,666,8,0,"[NULL]"
140,6,666,12,0,"[NULL]"
150,20,1000,15,14,"Layer1"
170,6,666,15,0,"[NULL]"
200,6,666,17,0,"[NULL]"
220,10,666,18,0,"[NULL]"
"""))
def test_actual_frame_timeline_events(self):
return DiffTestBlueprint(
trace=Path('frame_timeline_events.py'),
query=Path('actual_frame_timeline_events_test.sql'),
out=Path('actual_frame_timeline_events.out'))
# Composition layer
def test_composition_layer_count(self):
return DiffTestBlueprint(
trace=Path('composition_layer.py'),
query="""
SELECT RUN_METRIC('android/android_hwcomposer.sql');
SELECT display_id, AVG(value)
FROM total_layers
GROUP BY display_id;
""",
out=Csv("""
"display_id","AVG(value)"
"0",3.000000
"1",5.000000
"""))
# G2D metrics TODO(rsavitski): find a real trace and double-check that the
# is realistic. One kernel's source I checked had tgid=0 for all counter
# Initial support was added/discussed in b/171296908.
def test_g2d_metrics(self):
return DiffTestBlueprint(
trace=Path('g2d_metrics.textproto'),
query=Metric('g2d'),
out=Path('g2d_metrics.out'))
# Composer execution
def test_composer_execution(self):
return DiffTestBlueprint(
trace=Path('composer_execution.py'),
query="""
SELECT RUN_METRIC('android/composer_execution.sql',
'output', 'hwc_execution_spans');
SELECT
validation_type,
display_id,
COUNT(*) AS count,
SUM(execution_time_ns) AS total
FROM hwc_execution_spans
GROUP BY validation_type, display_id
ORDER BY validation_type, display_id;
""",
out=Csv("""
"validation_type","display_id","count","total"
"separated_validation","1",1,200
"skipped_validation","0",2,200
"skipped_validation","1",1,100
"unknown","1",1,0
"unskipped_validation","0",1,200
"""))
# Display metrics
def test_display_metrics(self):
return DiffTestBlueprint(
trace=Path('display_metrics.py'),
query=Metric('display_metrics'),
out=TextProto(r"""
display_metrics {
total_duplicate_frames: 0
duplicate_frames_logged: 0
total_dpu_underrun_count: 0
refresh_rate_switches: 5
refresh_rate_stats {
refresh_rate_fps: 60
count: 2
total_dur_ms: 2
avg_dur_ms: 1
}
refresh_rate_stats {
refresh_rate_fps: 90
count: 2
total_dur_ms: 2
avg_dur_ms: 1
}
refresh_rate_stats {
refresh_rate_fps: 120
count: 1
total_dur_ms: 2
avg_dur_ms: 2
}
update_power_state {
avg_runtime_micro_secs: 4000
}
}
"""))
# DPU vote clock and bandwidth
def test_dpu_vote_clock_bw(self):
return DiffTestBlueprint(
trace=Path('dpu_vote_clock_bw.textproto'),
query=Metric('android_hwcomposer'),
out=TextProto(r"""
android_hwcomposer {
skipped_validation_count: 0
unskipped_validation_count: 0
separated_validation_count: 0
unknown_validation_count: 0
dpu_vote_metrics {
tid: 237
avg_dpu_vote_clock: 206250
avg_dpu_vote_avg_bw: 210000
avg_dpu_vote_peak_bw: 205000
avg_dpu_vote_rt_bw: 271000
}
dpu_vote_metrics {
tid: 299
avg_dpu_vote_clock: 250000
}
}
"""))
# Video 4 Linux 2 related tests
def test_v4l2_vidioc_slice(self):
return DiffTestBlueprint(
trace=Path('v4l2_vidioc.textproto'),
query="""
SELECT ts, dur, name
FROM slice
WHERE category = 'Video 4 Linux 2';
""",
out=Csv("""
"ts","dur","name"
593268475912,0,"VIDIOC_QBUF minor=0 seq=0 type=9 index=19"
593268603800,0,"VIDIOC_QBUF minor=0 seq=0 type=9 index=20"
593528238295,0,"VIDIOC_DQBUF minor=0 seq=0 type=9 index=19"
593544028229,0,"VIDIOC_DQBUF minor=0 seq=0 type=9 index=20"
"""))
def test_v4l2_vidioc_flow(self):
return DiffTestBlueprint(
trace=Path('v4l2_vidioc.textproto'),
query="""
SELECT qbuf.ts, qbuf.dur, qbuf.name, dqbuf.ts, dqbuf.dur, dqbuf.name
FROM flow
JOIN slice qbuf ON flow.slice_out = qbuf.id
JOIN slice dqbuf ON flow.slice_in = dqbuf.id;
""",
out=Path('v4l2_vidioc_flow.out'))
def test_virtio_video_slice(self):
return DiffTestBlueprint(
trace=Path('virtio_video.textproto'),
query="""
SELECT slice.ts, slice.dur, slice.name, track.name
FROM slice
JOIN track ON slice.track_id = track.id;
""",
out=Csv("""
"ts","dur","name","name"
593125003271,84500592,"Resource #102","virtio_video stream #4 OUTPUT"
593125003785,100000,"RESOURCE_QUEUE","virtio_video stream #4 Requests"
593125084611,709696,"Resource #62","virtio_video stream #3 OUTPUT"
593125084935,100000,"RESOURCE_QUEUE","virtio_video stream #3 Requests"
593125794194,100000,"RESOURCE_QUEUE","virtio_video stream #3 Responses"
593209502603,100000,"RESOURCE_QUEUE","virtio_video stream #4 Responses"
"""))
# virtgpu (drm/virtio) related tests
def test_virtio_gpu(self):
return DiffTestBlueprint(
trace=Path('virtio_gpu.textproto'),
query="""
SELECT
ts,
dur,
name
FROM
slice
ORDER BY ts;
""",
out=Csv("""
"ts","dur","name"
1345090723759,1180312,"SUBMIT_3D"
1345090746311,1167135,"CTX_DETACH_RESOURCE"
"""))
# mali GPU events
def test_mali(self):
return DiffTestBlueprint(
trace=TextProto(r"""
packet {
ftrace_events {
cpu: 2
event {
timestamp: 751796307210
pid: 2857
mali_mali_KCPU_CQS_WAIT_START {
info_val1: 1
info_val2: 0
kctx_tgid: 2201
kctx_id: 10
id: 0
}
}
event {
timestamp: 751800621175
pid: 2857
mali_mali_KCPU_CQS_WAIT_END {
info_val1: 412313493488
info_val2: 0
kctx_tgid: 2201
kctx_id: 10
id: 0
}
}
event {
timestamp: 751800638997
pid: 2857
mali_mali_KCPU_CQS_SET {
info_val1: 412313493480
info_val2: 0
kctx_tgid: 2201
kctx_id: 10
id: 0
}
}
}
}
"""),
query="""
SELECT ts, dur, name FROM slice WHERE name GLOB "mali_KCPU_CQS*";
""",
out=Csv("""
"ts","dur","name"
751796307210,4313965,"mali_KCPU_CQS_WAIT"
751800638997,0,"mali_KCPU_CQS_SET"
"""))
def test_mali_fence(self):
return DiffTestBlueprint(
trace=TextProto(r"""
packet {
ftrace_events {
cpu: 2
event {
timestamp: 751796307210
pid: 2857
mali_mali_KCPU_FENCE_WAIT_START {
info_val1: 1
info_val2: 0
kctx_tgid: 2201
kctx_id: 10
id: 0
}
}
event {
timestamp: 751800621175
pid: 2857
mali_mali_KCPU_FENCE_WAIT_END {
info_val1: 412313493488
info_val2: 0
kctx_tgid: 2201
kctx_id: 10
id: 0
}
}
event {
timestamp: 751800638997
pid: 2857
mali_mali_KCPU_FENCE_SIGNAL {
info_val1: 412313493480
info_val2: 0
kctx_tgid: 2201
kctx_id: 10
id: 0
}
}
}
}
"""),
query="""
SELECT ts, dur, name FROM slice WHERE name GLOB "mali_KCPU_FENCE*";
""",
out=Csv("""
"ts","dur","name"
751796307210,4313965,"mali_KCPU_FENCE_WAIT"
751800638997,0,"mali_KCPU_FENCE_SIGNAL"
"""))