tp: Add pixel.touch stdlib module for touch events Introduces the pixel.touch module to parse Pixel-specific touch events (IRQ top-half/bottom-half and Twoshay processing timestamps) from the trace. Bug: 454761692
diff --git a/Android.bp b/Android.bp index 01c98aa..d42dc41 100644 --- a/Android.bp +++ b/Android.bp
@@ -18700,6 +18700,7 @@ name: "perfetto_src_trace_processor_perfetto_sql_stdlib_pixel_pixel", srcs: [ "src/trace_processor/perfetto_sql/stdlib/pixel/camera.sql", + "src/trace_processor/perfetto_sql/stdlib/pixel/touch.sql", ], }
diff --git a/BUILD b/BUILD index e509f73..e8c9122 100644 --- a/BUILD +++ b/BUILD
@@ -4049,6 +4049,7 @@ name = "src_trace_processor_perfetto_sql_stdlib_pixel_pixel", srcs = [ "src/trace_processor/perfetto_sql/stdlib/pixel/camera.sql", + "src/trace_processor/perfetto_sql/stdlib/pixel/touch.sql", ], )
diff --git a/src/trace_processor/perfetto_sql/stdlib/pixel/BUILD.gn b/src/trace_processor/perfetto_sql/stdlib/pixel/BUILD.gn index cd19df3..4f872b0 100644 --- a/src/trace_processor/perfetto_sql/stdlib/pixel/BUILD.gn +++ b/src/trace_processor/perfetto_sql/stdlib/pixel/BUILD.gn
@@ -15,5 +15,8 @@ import("../../../../../gn/perfetto_sql.gni") perfetto_sql_source_set("pixel") { - sources = [ "camera.sql" ] + sources = [ + "camera.sql", + "touch.sql", + ] }
diff --git a/src/trace_processor/perfetto_sql/stdlib/pixel/touch.sql b/src/trace_processor/perfetto_sql/stdlib/pixel/touch.sql new file mode 100644 index 0000000..240d13f --- /dev/null +++ b/src/trace_processor/perfetto_sql/stdlib/pixel/touch.sql
@@ -0,0 +1,155 @@ +-- Copyright (C) 2026 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 at +-- +-- 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. + +INCLUDE PERFETTO MODULE intervals.intersect; + +CREATE PERFETTO TABLE _pixel_touch_twoshay_events AS +WITH + base AS ( + SELECT + s.id AS twoshay_slice_id, + s.ts AS twoshay_ts, + s.dur AS twoshay_dur, + cast_int!(STR_SPLIT(STR_SPLIT(s.name, 'IN_TS=', 1), '.', 0)) AS in_ts + FROM slice AS s + WHERE + s.name GLOB 'algo->processFrame:*' + ) +SELECT + twoshay_slice_id, + twoshay_ts, + twoshay_dur, + in_ts, + cast_int!(IFNULL( + ( + SELECT c.value + FROM counter AS c + WHERE + c.track_id + = ( + SELECT id FROM track WHERE name = 'Resample latency offset' LIMIT 1 + ) + AND c.ts >= twoshay_ts + AND c.ts <= twoshay_ts + twoshay_dur + LIMIT 1 + ), + 0 + )) AS resample_latency_offset +FROM base; + +CREATE PERFETTO TABLE _pixel_touch_bottom_half_events AS +WITH + bh_base AS ( + SELECT + id AS bh_slice_id, + ts AS bh_start_ts, + dur AS bh_dur, + track_id, + cast_int!(STR_SPLIT(STR_SPLIT(name, 'IRQ_IDX=', 1), '.', 0)) AS irq_idx + FROM slice + WHERE + name GLOB 'gti_irq_thread_fn: IRQ_IDX=*' + ), + bh_with_in_ts AS ( + SELECT + b.*, + ( + SELECT cast_int!(STR_SPLIT(STR_SPLIT(s.name, 'IN_TS=', 1), '.', 0)) + FROM slice AS s + WHERE + s.parent_id = b.bh_slice_id + AND s.name GLOB 'goog_offload_populate_frame:*' + LIMIT 1 + ) AS in_ts + FROM bh_base AS b + ) +SELECT * FROM bh_with_in_ts; + +CREATE PERFETTO TABLE _pixel_touch_top_half_events AS +WITH + irq_counters AS ( + SELECT id, ts, 0 AS dur, value, track_id + FROM counter + WHERE + track_id = (SELECT id FROM track WHERE name = 'gti_th_irq_index' LIMIT 1) + ), + irq_slices AS ( + SELECT id, ts, dur, track_id FROM slice WHERE name GLOB 'IRQ (*)' + ) +SELECT + s.id AS th_slice_id, + s.ts AS th_start_ts, + s.dur AS th_dur, + s.track_id AS th_track_id, + c.value AS irq_idx +FROM _interval_intersect!((irq_slices, irq_counters), ()) AS ii +JOIN irq_slices AS s + ON s.id = ii.id_0 +JOIN irq_counters AS c + ON c.id = ii.id_1; + +-- Pixel-specific touch events, including top and bottom half IRQ, and Twoshay touch processing. +CREATE PERFETTO TABLE pixel_touch_events( + -- Hardware input event timestamp parsed from Twoshay driver logs. + in_ts LONG, + -- Start timestamp of the top-half touch IRQ. + ts_pixel_touch_th TIMESTAMP, + -- Duration of the top-half touch IRQ. + dur_pixel_touch_th DURATION, + -- Slice ID of the top-half touch IRQ. + id_pixel_touch_th LONG, + -- Track ID of the top-half touch IRQ. + track_pixel_touch_th JOINID(track.id), + -- Start timestamp of the bottom-half touch IRQ thread. + ts_pixel_touch_bh TIMESTAMP, + -- Duration of the bottom-half touch IRQ thread. + dur_pixel_touch_bh DURATION, + -- Slice ID of the bottom-half touch IRQ thread. + id_pixel_touch_bh LONG, + -- Track ID of the bottom-half touch IRQ thread. + track_pixel_touch_bh JOINID(track.id), + -- Start timestamp of the Twoshay processing frame. + ts_pixel_touch TIMESTAMP, + -- Duration of the Twoshay processing frame. + dur_pixel_touch DURATION, + -- Slice ID of the Twoshay processing frame. + id_pixel_touch LONG, + -- Track ID of the Twoshay processing frame. + track_pixel_touch JOINID(track.id), + -- Resample latency offset (in nanoseconds). + resample_latency_offset LONG +) +AS +SELECT + t.in_ts AS in_ts, + th.th_start_ts AS ts_pixel_touch_th, + th.th_dur AS dur_pixel_touch_th, + th.th_slice_id AS id_pixel_touch_th, + th.th_track_id AS track_pixel_touch_th, + bh.bh_start_ts AS ts_pixel_touch_bh, + bh.bh_dur AS dur_pixel_touch_bh, + bh.bh_slice_id AS id_pixel_touch_bh, + bh.track_id AS track_pixel_touch_bh, + t.twoshay_ts AS ts_pixel_touch, + t.twoshay_dur AS dur_pixel_touch, + t.twoshay_slice_id AS id_pixel_touch, + s.track_id AS track_pixel_touch, + t.resample_latency_offset AS resample_latency_offset +FROM _pixel_touch_twoshay_events AS t +LEFT JOIN _pixel_touch_bottom_half_events AS bh + ON bh.in_ts = t.in_ts +LEFT JOIN _pixel_touch_top_half_events AS th + ON th.irq_idx = bh.irq_idx +LEFT JOIN slice AS s + ON s.id = t.twoshay_slice_id;
diff --git a/test/trace_processor/diff_tests/stdlib/pixel/tests.py b/test/trace_processor/diff_tests/stdlib/pixel/tests.py index 1cbc02b..04ccb8b 100644 --- a/test/trace_processor/diff_tests/stdlib/pixel/tests.py +++ b/test/trace_processor/diff_tests/stdlib/pixel/tests.py
@@ -55,3 +55,364 @@ "ts","node","port_group","frame_number","cam_id","dur" 2200,"filter","output",123,1,500 """)) + + def test_pixel_touch_events(self): + return DiffTestBlueprint( + trace=TextProto(r""" + packet { + system_info { + utsname { + sysname: "Linux" + machine: "x86_64" + } + } + } + packet { + process_tree { + processes { + pid: 2 + ppid: 0 + cmdline: "kthreadd" + } + processes { + pid: 30724 + ppid: 2 + cmdline: "irq/764-touch_dev" + } + processes { + pid: 9876 + ppid: 1 + cmdline: "twoshay" + } + threads { + tid: 30724 + tgid: 30724 + name: "irq/764-touch_dev" + } + threads { + tid: 9876 + tgid: 9876 + name: "twoshay" + } + } + } + # ============================================================================== + # CASE 1: Happy path - complete touch event sequence (TH IRQ -> BH Thread -> Twoshay) + # ============================================================================== + packet { + ftrace_events { + cpu: 0 + event { + timestamp: 280000 + pid: 0 + irq_handler_entry { + irq: 764 + name: "touch_dev" + } + } + event { + timestamp: 282600 + pid: 0 + irq_handler_exit { + irq: 764 + ret: 1 + } + } + } + } + packet { + ftrace_events { + cpu: 0 + # Counter event (value: 98756) + event { + timestamp: 281300 + pid: 0 + zero { + flag: 4 # Counter + name: "gti_th_irq_index" + pid: 0 + value: 98756 + } + } + # BH parent starts: gti_irq_thread_fn: IRQ_IDX=98756. + event { + timestamp: 305000 + pid: 30724 + zero { + flag: 1 # Begin + name: "gti_irq_thread_fn: IRQ_IDX=98756." + pid: 0 + value: 0 + } + } + # BH child: goog_offload_populate_frame: IDX=98570 IN_TS=0. + event { + timestamp: 2290000 + pid: 30724 + zero { + flag: 1 # Begin + name: "goog_offload_populate_frame: IDX=98570 IN_TS=0." + pid: 0 + value: 0 + } + } + # BH child ends + event { + timestamp: 2310000 + pid: 30724 + zero { + flag: 2 # End + name: "" + pid: 0 + value: 0 + } + } + # BH parent ends + event { + timestamp: 2325000 + pid: 30724 + zero { + flag: 2 # End + name: "" + pid: 0 + value: 0 + } + } + # Twoshay starts: algo->processFrame: INDEX=98570 IN_TS=0. + event { + timestamp: 2505000 + pid: 9876 + print { + buf: "B|9876|algo->processFrame: INDEX=98570 IN_TS=0.\n" + } + } + # Resample latency offset counter + event { + timestamp: 2600000 + pid: 9876 + zero { + flag: 4 # Counter + name: "Resample latency offset" + pid: 9876 + value: 5000000 + } + } + # Twoshay ends + event { + timestamp: 2955000 + pid: 9876 + print { + buf: "E|9876\n" + } + } + } + } + + # ============================================================================== + # CASE 2: Missing TH only (ts: 10000000 + offsets) + # - Twoshay IN_TS = 10000000 + # - BH IN_TS = 10000000 + # - No TH IRQ provided + # ============================================================================== + packet { + ftrace_events { + cpu: 0 + event { + timestamp: 10305000 + pid: 30724 + zero { + flag: 1 # Begin + name: "gti_irq_thread_fn: IRQ_IDX=98757." + pid: 0 + value: 0 + } + } + event { + timestamp: 12290000 + pid: 30724 + zero { + flag: 1 # Begin + name: "goog_offload_populate_frame: IDX=98571 IN_TS=10000000." + pid: 0 + value: 0 + } + } + event { + timestamp: 12310000 + pid: 30724 + zero { + flag: 2 # End + name: "" + pid: 0 + value: 0 + } + } + event { + timestamp: 12325000 + pid: 30724 + zero { + flag: 2 # End + name: "" + pid: 0 + value: 0 + } + } + event { + timestamp: 12505000 + pid: 9876 + print { + buf: "B|9876|algo->processFrame: INDEX=98571 IN_TS=10000000.\n" + } + } + event { + timestamp: 12955000 + pid: 9876 + print { + buf: "E|9876\n" + } + } + } + } + + # ============================================================================== + # CASE 3: Missing BH and TH (ts: 20000000 + offsets) + # - Only Twoshay event is present + # ============================================================================== + packet { + ftrace_events { + cpu: 0 + event { + timestamp: 22505000 + pid: 9876 + print { + buf: "B|9876|algo->processFrame: INDEX=98572 IN_TS=20000000.\n" + } + } + event { + timestamp: 22955000 + pid: 9876 + print { + buf: "E|9876\n" + } + } + } + } + + # ============================================================================== + # CASE 4: Counter Outside TH Boundary (ts: 30000000 + offsets) + # - TH IRQ is at 30280000 to 30282600 + # - Counter event is at 30000000 (before TH starts) -> Should NOT join + # ============================================================================== + packet { + ftrace_events { + cpu: 0 + event { + timestamp: 30280000 + pid: 0 + irq_handler_entry { + irq: 764 + name: "touch_dev" + } + } + event { + timestamp: 30282600 + pid: 0 + irq_handler_exit { + irq: 764 + ret: 1 + } + } + } + } + packet { + ftrace_events { + cpu: 0 + event { + timestamp: 30000000 + pid: 0 + zero { + flag: 4 # Counter + name: "gti_th_irq_index" + pid: 0 + value: 98758 + } + } + event { + timestamp: 30305000 + pid: 30724 + zero { + flag: 1 # Begin + name: "gti_irq_thread_fn: IRQ_IDX=98758." + pid: 0 + value: 0 + } + } + event { + timestamp: 32290000 + pid: 30724 + zero { + flag: 1 # Begin + name: "goog_offload_populate_frame: IDX=98573 IN_TS=30000000." + pid: 0 + value: 0 + } + } + event { + timestamp: 32310000 + pid: 30724 + zero { + flag: 2 # End + name: "" + pid: 0 + value: 0 + } + } + event { + timestamp: 32325000 + pid: 30724 + zero { + flag: 2 # End + name: "" + pid: 0 + value: 0 + } + } + event { + timestamp: 32505000 + pid: 9876 + print { + buf: "B|9876|algo->processFrame: INDEX=98573 IN_TS=30000000.\n" + } + } + event { + timestamp: 32955000 + pid: 9876 + print { + buf: "E|9876\n" + } + } + } + } + """), + query=""" + INCLUDE PERFETTO MODULE pixel.touch; + + SELECT + in_ts, + ts_pixel_touch_th, + dur_pixel_touch_th, + ts_pixel_touch_bh, + dur_pixel_touch_bh, + ts_pixel_touch, + dur_pixel_touch, + resample_latency_offset + FROM pixel_touch_events + ORDER BY ts_pixel_touch; + """, + out=Csv(""" + "in_ts","ts_pixel_touch_th","dur_pixel_touch_th","ts_pixel_touch_bh","dur_pixel_touch_bh","ts_pixel_touch","dur_pixel_touch","resample_latency_offset" + 0,280000,2600,305000,2020000,2505000,450000,5000000 + 10000000,"[NULL]","[NULL]",10305000,2020000,12505000,450000,0 + 20000000,"[NULL]","[NULL]","[NULL]","[NULL]",22505000,450000,0 + 30000000,"[NULL]","[NULL]",30305000,2020000,32505000,450000,0 + """))