Add frame_times metric to experimental/

This is a port of the TBMv2 frame_time metric [1] to TBMv3.

Some features required by this metric to work on all platforms are still
missing (most notably the SurfaceFlinger events on Android), so adding
this to experimental folder for the time being.

[1] https://source.chromium.org/chromium/chromium/src/+/master:third_party/catapult/tracing/tracing/metrics/rendering/frame_time.html

Change-Id: I9562d93256617357bc4dc7413ca7685a4f496ed3
diff --git a/Android.bp b/Android.bp
index 6654141..6bca042 100644
--- a/Android.bp
+++ b/Android.bp
@@ -3579,6 +3579,7 @@
     "protos/perfetto/metrics/android/thread_time_in_state_metric.proto",
     "protos/perfetto/metrics/android/unsymbolized_frames.proto",
     "protos/perfetto/metrics/chrome/all_chrome_metrics.proto",
+    "protos/perfetto/metrics/chrome/frame_times.proto",
     "protos/perfetto/metrics/chrome/test_chrome_metric.proto",
     "protos/perfetto/metrics/custom_options.proto",
     "protos/perfetto/metrics/metrics.proto",
@@ -7592,6 +7593,7 @@
     "src/trace_processor/metrics/chrome/scroll_jank_cause_get_bitmap.sql",
     "src/trace_processor/metrics/chrome/scroll_jank_cause_queuing_delay.sql",
     "src/trace_processor/metrics/chrome/test_chrome_metric.sql",
+    "src/trace_processor/metrics/experimental/frame_times.sql",
     "src/trace_processor/metrics/trace_metadata.sql",
     "src/trace_processor/metrics/webview/webview_power_usage.sql",
   ],
diff --git a/BUILD b/BUILD
index 6b1204d..4ad0b3a 100644
--- a/BUILD
+++ b/BUILD
@@ -942,6 +942,7 @@
         "src/trace_processor/metrics/chrome/scroll_jank_cause_get_bitmap.sql",
         "src/trace_processor/metrics/chrome/scroll_jank_cause_queuing_delay.sql",
         "src/trace_processor/metrics/chrome/test_chrome_metric.sql",
+        "src/trace_processor/metrics/experimental/frame_times.sql",
         "src/trace_processor/metrics/trace_metadata.sql",
         "src/trace_processor/metrics/webview/webview_power_usage.sql",
     ],
@@ -2328,6 +2329,7 @@
     name = "protos_perfetto_metrics_chrome_protos",
     srcs = [
         "protos/perfetto/metrics/chrome/all_chrome_metrics.proto",
+        "protos/perfetto/metrics/chrome/frame_times.proto",
         "protos/perfetto/metrics/chrome/test_chrome_metric.proto",
     ],
     visibility = [
diff --git a/protos/perfetto/metrics/chrome/BUILD.gn b/protos/perfetto/metrics/chrome/BUILD.gn
index 6287d8c..a30c131 100644
--- a/protos/perfetto/metrics/chrome/BUILD.gn
+++ b/protos/perfetto/metrics/chrome/BUILD.gn
@@ -22,6 +22,7 @@
   ]
   sources = [
     "all_chrome_metrics.proto",
+    "frame_times.proto",
     "test_chrome_metric.proto",
   ]
 }
diff --git a/protos/perfetto/metrics/chrome/all_chrome_metrics.proto b/protos/perfetto/metrics/chrome/all_chrome_metrics.proto
index 6863170..442cba3 100644
--- a/protos/perfetto/metrics/chrome/all_chrome_metrics.proto
+++ b/protos/perfetto/metrics/chrome/all_chrome_metrics.proto
@@ -19,8 +19,10 @@
 package perfetto.protos;
 
 import "protos/perfetto/metrics/metrics.proto";
+import "protos/perfetto/metrics/chrome/frame_times.proto";
 import "protos/perfetto/metrics/chrome/test_chrome_metric.proto";
 
 extend TraceMetrics {
   optional TestChromeMetric test_chrome_metric = 1001;
+  optional FrameTimes frame_times = 1002;
 }
diff --git a/protos/perfetto/metrics/chrome/frame_times.proto b/protos/perfetto/metrics/chrome/frame_times.proto
new file mode 100644
index 0000000..5206a1c
--- /dev/null
+++ b/protos/perfetto/metrics/chrome/frame_times.proto
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2021 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.
+ */
+
+syntax = "proto2";
+
+package perfetto.protos;
+
+import "protos/perfetto/metrics/custom_options.proto";
+
+message FrameTimes {
+  repeated double frame_time = 1 [(unit) = "ms_smallerIsBetter"];
+  repeated double exp_frame_time = 2 [(unit) = "ms_smallerIsBetter"];
+  optional double avg_surface_fps = 3 [(unit) = "unitless_biggerIsBetter"];
+  optional double exp_avg_surface_fps = 4 [(unit) = "unitless_biggerIsBetter"];
+}
diff --git a/src/trace_processor/metrics/BUILD.gn b/src/trace_processor/metrics/BUILD.gn
index 7b3f630..500d1a8 100644
--- a/src/trace_processor/metrics/BUILD.gn
+++ b/src/trace_processor/metrics/BUILD.gn
@@ -79,6 +79,7 @@
   "chrome/scroll_flow_event.sql",
   "chrome/scroll_flow_event_queuing_delay.sql",
   "chrome/test_chrome_metric.sql",
+  "experimental/frame_times.sql",
   "webview/webview_power_usage.sql",
 ]
 
diff --git a/src/trace_processor/metrics/experimental/frame_times.sql b/src/trace_processor/metrics/experimental/frame_times.sql
new file mode 100644
index 0000000..b43ad74
--- /dev/null
+++ b/src/trace_processor/metrics/experimental/frame_times.sql
@@ -0,0 +1,168 @@
+--
+-- Copyright 2021 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
+--
+--     https://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.
+
+CREATE VIEW InteractionEvents AS
+SELECT
+  ts, dur, ts AS ts_ir, dur AS dur_ir
+FROM slice WHERE name LIKE 'Interaction.%';
+
+CREATE VIEW GestureLegacyEvents AS
+SELECT
+  ts,
+  EXTRACT_ARG(arg_set_id, 'legacy_event.phase') AS phase
+FROM raw
+WHERE EXTRACT_ARG(arg_set_id, 'legacy_event.name') = 'SyntheticGestureController::running';
+
+-- Convert pairs of 'S' and 'F' events into slices with ts and dur.
+CREATE VIEW GestureEvents AS
+SELECT
+  ts, dur, ts AS ts_ge, dur AS dur_ge
+FROM (
+  SELECT
+    ts,
+    phase,
+    LEAD(ts) OVER (ORDER BY ts) - ts as dur
+  FROM GestureLegacyEvents
+)
+WHERE phase = 'S';
+
+CREATE VIRTUAL TABLE InteractionEventsJoinGestureEvents
+USING SPAN_LEFT_JOIN(InteractionEvents, GestureEvents);
+
+--------------------------------------------------------------------------------
+-- Interesting segments are:
+-- 1) If there's a gesture overlapping with interaction, then gesture's range.
+-- 2) Else, interaction's range.
+
+CREATE VIEW InterestingSegments AS
+SELECT  -- 1) Gestures overlapping interactions.
+  ts_ge AS ts,
+  dur_ge AS dur
+FROM InteractionEventsJoinGestureEvents
+WHERE ts_ge IS NOT NULL
+GROUP BY ts_ge
+UNION ALL
+SELECT  -- 2) Interactions without gestures.
+  ts_ir AS ts,
+  dur_ir AS dur
+FROM InteractionEventsJoinGestureEvents
+WHERE ts_ge IS NULL
+GROUP BY ts_ir
+HAVING COUNT(*) = 1;
+
+--------------------------------------------------------------------------------
+-- On ChromeOS, DRM events, if they exist, are the source of truth. Otherwise,
+-- look for display rendering stats.
+-- On Android, the TBMv2 version relied on Surface Flinger events that are
+-- currently unavailable in proto traces. So results may be different from
+-- the TBMv2 version on this platform.
+
+CREATE TABLE DisplayCompositorPresentationEvents AS
+SELECT ts, FALSE AS exp
+FROM slice
+WHERE name = 'DrmEventFlipComplete'
+GROUP BY ts;
+
+INSERT INTO DisplayCompositorPresentationEvents
+SELECT ts, FALSE AS exp
+FROM slice
+WHERE
+  name = 'vsync_before'
+  AND NOT EXISTS (SELECT * FROM DisplayCompositorPresentationEvents)
+GROUP BY ts;
+
+INSERT INTO DisplayCompositorPresentationEvents
+SELECT ts, FALSE AS exp
+FROM slice
+WHERE
+  name = 'BenchmarkInstrumentation::DisplayRenderingStats'
+  AND NOT EXISTS (SELECT * FROM DisplayCompositorPresentationEvents)
+GROUP BY ts;
+
+INSERT INTO DisplayCompositorPresentationEvents
+SELECT ts, TRUE AS exp
+FROM slice
+WHERE name = 'Display::FrameDisplayed'
+GROUP BY ts;
+
+CREATE VIEW FrameSegments AS
+SELECT
+  ts,
+  LEAD(ts) OVER wnd - ts as dur,
+  ts as ts_fs,
+  LEAD(ts) OVER wnd - ts as dur_fs,
+  exp
+FROM DisplayCompositorPresentationEvents
+WINDOW wnd AS (PARTITION BY exp ORDER BY ts);
+
+CREATE VIRTUAL TABLE FrameSegmentsJoinInterestingSegments USING
+SPAN_JOIN(FrameSegments, InterestingSegments);
+
+CREATE VIEW FrameTimes AS
+SELECT dur / 1e6 AS dur_ms, exp
+FROM FrameSegmentsJoinInterestingSegments
+WHERE ts = ts_fs AND dur = dur_fs;
+
+--------------------------------------------------------------------------------
+-- Determine frame rate
+
+CREATE VIEW RefreshPeriodAndroid AS
+-- Not implemented yet.
+SELECT NULL AS interval_ms
+;
+
+CREATE VIEW RefreshPeriodNonAndroid AS
+SELECT EXTRACT_ARG(arg_set_id, 'debug.args.interval_us') / 1e3 AS interval_ms
+FROM slice
+JOIN thread_track ON (slice.track_id = thread_track.id)
+JOIN thread ON (thread_track.utid = thread.utid)
+WHERE thread.name = 'Compositor' AND slice.name = 'Scheduler::BeginFrame'
+LIMIT 1;
+
+CREATE VIEW RefreshPeriodDefault AS
+SELECT 1000.0 / 60 AS interval_ms;
+
+CREATE TABLE RefreshPeriod AS
+SELECT COALESCE(
+  (SELECT interval_ms FROM RefreshPeriodAndroid),
+  (SELECT interval_ms FROM RefreshPeriodNonAndroid),
+  (SELECT interval_ms FROM RefreshPeriodDefault)
+) AS interval_ms;
+
+--------------------------------------------------------------------------------
+-- Compute average FPS
+
+CREATE VIEW ValidFrameTimes AS
+SELECT
+  dur_ms / (SELECT interval_ms FROM RefreshPeriod) AS length,
+  exp
+FROM FrameTimes
+WHERE dur_ms / (SELECT interval_ms FROM RefreshPeriod) >= 0.5;
+
+CREATE VIEW AvgSurfaceFps AS
+SELECT
+  exp,
+  1e3 * COUNT(*) / (SELECT SUM(dur_ms) FROM FrameTimes WHERE exp = valid.exp) AS fps
+FROM ValidFrameTimes valid
+GROUP BY exp;
+
+CREATE VIEW frame_times_output AS
+SELECT FrameTimes(
+  'frame_time', (SELECT RepeatedField(dur_ms) FROM FrameTimes WHERE NOT exp),
+  'exp_frame_time', (SELECT RepeatedField(dur_ms) FROM FrameTimes WHERE exp),
+  'avg_surface_fps', (SELECT fps FROM AvgSurfaceFps WHERE NOT exp),
+  'exp_avg_surface_fps', (SELECT fps FROM AvgSurfaceFps WHERE exp)
+);
+
diff --git a/test/trace_processor/chrome/frame_times_metric.out b/test/trace_processor/chrome/frame_times_metric.out
new file mode 100644
index 0000000..447a2e4
--- /dev/null
+++ b/test/trace_processor/chrome/frame_times_metric.out
@@ -0,0 +1,4 @@
+
+"exp","fps"
+0,59.860088
+1,59.861592
diff --git a/test/trace_processor/chrome/frame_times_metric.sql b/test/trace_processor/chrome/frame_times_metric.sql
new file mode 100644
index 0000000..28c0c42
--- /dev/null
+++ b/test/trace_processor/chrome/frame_times_metric.sql
@@ -0,0 +1,18 @@
+--
+-- Copyright 2021 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
+--
+--     https://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.
+
+SELECT RUN_METRIC('experimental/frame_times.sql') AS suppress_query_output;
+
+SELECT * FROM AvgSurfaceFps;
diff --git a/test/trace_processor/chrome/index b/test/trace_processor/chrome/index
index fffc0a8..005a948 100644
--- a/test/trace_processor/chrome/index
+++ b/test/trace_processor/chrome/index
@@ -12,6 +12,7 @@
 ../../data/chrome_scroll_without_vsync.pftrace scroll_jank_cause_queuing_delay_general_validation.sql scroll_jank_cause_queuing_delay_general_validation.out
 ../../data/chrome_scroll_without_vsync.pftrace chrome_thread_slice_with_cpu_time.sql chrome_thread_slice_with_cpu_time.out
 ../track_event/track_event_counters.textproto chrome_thread_slice_with_cpu_time_repeated.sql chrome_thread_slice_with_cpu_time_repeated.out
+../../data/chrome_rendering_desktop.pftrace frame_times_metric.sql frame_times_metric.out
 
 # Chrome memory snapshots.
 ../../data/chrome_memory_snapshot.pftrace memory_snapshot_general_validation.sql memory_snapshot_general_validation.out
diff --git a/tools/install-build-deps b/tools/install-build-deps
index 81534a6..44bfc4a 100755
--- a/tools/install-build-deps
+++ b/tools/install-build-deps
@@ -229,8 +229,8 @@
     # Example traces for regression tests.
     Dependency(
         'test/data.zip',
-        'https://storage.googleapis.com/perfetto/test-data-20210105-174747.zip',
-        'e4fe27c8aad5bf0c447b2e853302d5431d0f134e368b73b68e5f56a293945d52',
+        'https://storage.googleapis.com/perfetto/test-data-20210128-172149.zip',
+        'f83f9336a2d0d9ac5c3154b949e3237a6c7119b2e8a70b31c7789aff0066b9eb',
         'all',
     ),