Merge changes Ief462c4e,I59e158ce
* changes:
Add TP support for SurfaceFlinger's transactions data source
Add TP support for SurfaceFlinger's layers data source
diff --git a/docs/faq.md b/docs/faq.md
index 3978a26..df41ff3 100644
--- a/docs/faq.md
+++ b/docs/faq.md
@@ -20,12 +20,26 @@
tools/open_trace_in_ui -i /path/to/trace
```
-## Incorrectly displayed overlapping events in JSON trace
+## Why does Perfetto not support <some obscure JSON format feature>?
-NOTE: JSON is considered a legacy trace format and is supported on a best-effort
-basis.
+The JSON trace format is considered a legacy trace format and is supported on a
+best-effort basis. While we try our best to maintain compatibility with the
+chrome://tracing UI and the [format spec](https://docs.google.com/document/d/1CvAClvFfyA5R-PhYUmn5OOQtYMH4h6I0nSsKchNAySU/preview#heading=h.nso4gcezn7n1)
+in how events are parsed and displayed, this is not always possible.
+This is especially the case for traces which are programmatically generated
+outside of Chrome and depend on the implementation details of chrome://tracing.
-The Perfetto UI and trace processor do support overlapping B/E/X events, in
+If supporting a feature would introduce a misproportional amount of technical
+debt, we generally make the choice not to support that feature. Users
+are recommended to emit [TrackEvent](/docs/instrumentation/track-events.md)
+instead, Perfetto's native trace format. See
+[this guide](/docs/reference/synthetic-track-event.md) for how common JSON
+events can be represented using
+TrackEvent.
+
+## Why are overlapping events in JSON traces not displayed correctly?
+
+The Perfetto UI and trace processor do not support overlapping B/E/X events, in
compliance with the
[JSON spec](https://docs.google.com/document/d/1CvAClvFfyA5R-PhYUmn5OOQtYMH4h6I0nSsKchNAySU/preview#heading=h.nso4gcezn7n1).
As stated in the spec, events are only allowed to perfecty nest.
diff --git a/gn/standalone/BUILD.gn b/gn/standalone/BUILD.gn
index af6438a..19c8029 100644
--- a/gn/standalone/BUILD.gn
+++ b/gn/standalone/BUILD.gn
@@ -261,9 +261,7 @@
} else if (current_cpu == "riscv64") {
if (!is_clang) {
# https://gcc.gnu.org/bugzilla/show_bug.cgi?id=104338
- libs += [
- "atomic",
- ]
+ libs += [ "atomic" ]
}
} else if (current_cpu == "x86") {
asmflags += [ "-m32" ]
diff --git a/include/perfetto/tracing/data_source.h b/include/perfetto/tracing/data_source.h
index 879e59e..91e29fe 100644
--- a/include/perfetto/tracing/data_source.h
+++ b/include/perfetto/tracing/data_source.h
@@ -93,6 +93,9 @@
// be retained.
const DataSourceConfig* config = nullptr;
+ // Backend type.
+ BackendType backend_type = kUnspecifiedBackend;
+
// The index of this data source instance (0..kMaxDataSourceInstances - 1).
uint32_t internal_instance_index = 0;
};
diff --git a/protos/perfetto/trace/android/BUILD.gn b/protos/perfetto/trace/android/BUILD.gn
index 0a3e9e9..c5e842f 100644
--- a/protos/perfetto/trace/android/BUILD.gn
+++ b/protos/perfetto/trace/android/BUILD.gn
@@ -37,9 +37,9 @@
perfetto_proto_library("winscope_deps") {
proto_generators = [ "source_set" ]
sources = [
+ "surfaceflinger_common.proto",
"surfaceflinger_layers.proto",
"surfaceflinger_transactions.proto",
- "surfaceflinger_common.proto",
]
}
diff --git a/protos/third_party/chromium/chrome_track_event.proto b/protos/third_party/chromium/chrome_track_event.proto
index 347b36e..2547a8e 100644
--- a/protos/third_party/chromium/chrome_track_event.proto
+++ b/protos/third_party/chromium/chrome_track_event.proto
@@ -46,10 +46,16 @@
}
message ChromeTaskAnnotator {
+ enum DelayPolicy {
+ FLEXIBLE_NO_SOONER = 0;
+ FLEXIBLE_PREFER_EARLY = 1;
+ PRECISE = 2;
+ }
optional uint32 ipc_hash = 1;
// The delay in microseconds that was specified, if any, when this task was
// posted. This is only valid for delayed tasks.
optional uint64 task_delay_us = 2;
+ optional DelayPolicy delay_policy = 3;
}
message ChromeBrowserContext {
@@ -1208,6 +1214,35 @@
repeated float segregated_predicted_deltas_in_gpu_frame_y = 14;
}
+// Debug information for system layer of audio rendering on Windows.
+message WinRenderAudioFromSource {
+ // Buffer size used by the platform.
+ optional uint32 iaudioclient_buffer_size_frames = 1;
+ // Number of available frames in the platform buffer.
+ optional uint32 iaudioclient_buffer_unfilled_frames = 2;
+ // Number of frames requested from the audio stream client.
+ optional uint32 packet_size_frames = 3;
+ // Total number of frames requested from the client and written to the
+ // platform buffer during the stream lifetime.
+ optional uint64 num_written_frames = 4;
+ // Total number of frames played by the platform during the stream lifetime.
+ optional uint64 num_played_out_frames = 5;
+ // Device frequency reported by the platform; used to convert the stream
+ // position to frames.
+ optional uint64 iaudioclock_device_frequency = 6;
+ // Stream position reported by the platform.
+ optional uint64 iaudioclock_stream_position = 7;
+ // Performance counter position reported by the platform.
+ optional uint64 iaudioclock_qpc_position = 8;
+ // Stream position increase since the last call, converted to milliseconds.
+ optional int64 iaudioclock_stream_position_increase_ms = 9;
+ // Performance counter position since the last call, converted to
+ // milliseconds.
+ optional int64 iaudioclock_qpc_position_increase_ms = 10;
+ // Estimated playout delay, milliseconds.
+ optional int64 playout_delay_ms = 11;
+};
+
message ChromeTrackEvent {
// Extension range for Chrome: 1000-1999
// Next ID: 1048
@@ -1312,5 +1347,7 @@
optional TabSwitchMeasurement tab_switch_measurement = 1046;
optional ScrollDeltas scroll_deltas = 1047;
+
+ optional WinRenderAudioFromSource win_render_audio_from_source = 1048;
}
}
diff --git a/python/generators/stdlib_docs/utils.py b/python/generators/stdlib_docs/utils.py
index d635b08..52ddfac 100644
--- a/python/generators/stdlib_docs/utils.py
+++ b/python/generators/stdlib_docs/utils.py
@@ -22,34 +22,34 @@
ANY_NON_QUOTE = r'[^\']*.*'
TYPE = r'[A-Z]+'
SQL = r'[\s\S]*?'
+WS = r'\s*'
CREATE_TABLE_VIEW_PATTERN = (
# Match create table/view and catch type
- r'CREATE (?:VIRTUAL )?(TABLE|VIEW)?(?:IF NOT EXISTS)?\s*'
+ fr'CREATE{WS}(?:VIRTUAL )?{WS}(TABLE|VIEW){WS}(?:IF NOT EXISTS)?{WS}'
# Catch the name
- fr'({LOWER_NAME})\s*(?:AS|USING)?.*')
+ fr'{WS}({LOWER_NAME}){WS}(?:AS|USING)?{WS}.*')
CREATE_FUNCTION_PATTERN = (
- r"SELECT\s*CREATE_FUNCTION\(\s*"
# Function name: we are matching everything [A-Z]* between ' and ).
- fr"'\s*({UPPER_NAME})\s*\("
- # Args: anything before closing bracket with '.
- fr"({ANY_WORDS})\)',\s*"
+ fr"CREATE{WS}PERFETTO{WS}FUNCTION{WS}({UPPER_NAME}){WS}"
+ # Args: anything before closing bracket.
+ fr"{WS}\({WS}({ANY_WORDS}){WS}\){WS}"
# Type: [A-Z]* between two '.
- fr"'({TYPE})',\s*"
+ fr"{WS}RETURNS{WS}({TYPE}){WS}AS{WS}"
# Sql: Anything between ' and ');. We are catching \'.
- fr"'({SQL})'\s*\);")
+ fr"{WS}({SQL});")
CREATE_VIEW_FUNCTION_PATTERN = (
- r"SELECT\s*CREATE_VIEW_FUNCTION\(\s*"
+ fr"SELECT{WS}CREATE_VIEW_FUNCTION\({WS}"
# Function name: we are matching everything [A-Z]* between ' and ).
- fr"'({UPPER_NAME})\s*\("
+ fr"{WS}'{WS}({UPPER_NAME}){WS}\({WS}"
# Args: anything before closing bracket with '.
- fr"({ANY_WORDS})\)',\s*"
+ fr"{WS}({ANY_WORDS}){WS}\){WS}'{WS},{WS}"
# Return columns: anything between two '.
- fr"'\s*({ANY_NON_QUOTE})\s*',\s*"
+ fr"'{WS}({ANY_NON_QUOTE}){WS}',{WS}"
# Sql: Anything between ' and ');. We are catching \'.
- fr"'({SQL})'\s*\);")
+ fr"{WS}'{WS}({SQL}){WS}'{WS}\){WS};")
class ObjKind(str, Enum):
diff --git a/python/test/stdlib_unittest.py b/python/test/stdlib_unittest.py
index 1f609d0..649cf4d 100644
--- a/python/test/stdlib_unittest.py
+++ b/python/test/stdlib_unittest.py
@@ -73,11 +73,10 @@
{DESC}
{ARGS_STR}
{RET_STR}
-SELECT CREATE_FUNCTION(
- 'FOO_FN({ARGS_SQL_STR})',
- '{RET_SQL_STR}',
- '{SQL_STR}'
-);
+CREATE PERFETTO FUNCTION FOO_FN({ARGS_SQL_STR})
+RETURNS {RET_SQL_STR}
+AS
+{SQL_STR};
'''.strip())
assert isinstance(res, dict)
@@ -183,11 +182,10 @@
-- @arg utid2 INT Uint.
-- @arg name STRING String name.
{RET_STR}
-SELECT CREATE_FUNCTION(
- 'FOO_FN({ARGS_SQL_STR})',
- '{RET_SQL_STR}',
- '{SQL_STR}'
-);
+CREATE PERFETTO FUNCTION FOO_FN({ARGS_SQL_STR})
+RETURNS {RET_SQL_STR}
+AS
+{SQL_STR};
'''.strip())
assert isinstance(res, list)
@@ -199,11 +197,10 @@
-- @arg utid INT
-- @arg name STRING String name.
{RET_STR}
-SELECT CREATE_FUNCTION(
- 'FOO_FN({ARGS_SQL_STR})',
- '{RET_SQL_STR}',
- '{SQL_STR}'
-);
+CREATE PERFETTO FUNCTION FOO_FN({ARGS_SQL_STR})
+RETURNS {RET_SQL_STR}
+AS
+{SQL_STR};
'''.strip())
assert isinstance(res, list)
@@ -214,11 +211,10 @@
{ARGS_STR}
--
-- @ret BOOL
-SELECT CREATE_FUNCTION(
- 'FOO_FN({ARGS_SQL_STR})',
- '{RET_SQL_STR}',
- '{SQL_STR}'
-);
+CREATE PERFETTO FUNCTION FOO_FN({ARGS_SQL_STR})
+RETURNS {RET_SQL_STR}
+AS
+{SQL_STR};
'''.strip())
assert isinstance(res, list)
@@ -236,11 +232,10 @@
-- description.
{ARGS_STR}
{RET_STR}
-SELECT CREATE_FUNCTION(
- 'FOO_FN({ARGS_SQL_STR})',
- '{RET_SQL_STR}',
- '{SQL_STR}'
-);
+CREATE PERFETTO FUNCTION FOO_FN({ARGS_SQL_STR})
+RETURNS {RET_SQL_STR}
+AS
+{SQL_STR};
'''.strip())
assert isinstance(res, dict)
@@ -260,11 +255,10 @@
-- which spans across multiple lines
-- inconsistently.
{RET_STR}
-SELECT CREATE_FUNCTION(
- 'FOO_FN({ARGS_SQL_STR})',
- '{RET_SQL_STR}',
- '{SQL_STR}'
-);
+CREATE PERFETTO FUNCTION FOO_FN({ARGS_SQL_STR})
+RETURNS {RET_SQL_STR}
+AS
+{SQL_STR};
'''.strip())
assert isinstance(res, dict)
diff --git a/src/trace_processor/importers/proto/android_probes_module.cc b/src/trace_processor/importers/proto/android_probes_module.cc
index fece007..d26b6ef 100644
--- a/src/trace_processor/importers/proto/android_probes_module.cc
+++ b/src/trace_processor/importers/proto/android_probes_module.cc
@@ -46,7 +46,7 @@
return "cpu.big";
} else if (raw == "S5M_VDD_INT") {
return "system.fabric";
- } else if (raw == "S10M_VDD_TPU") {
+ } else if (raw == "S10M_VDD_TPU" || raw == "S7M_VDD_TPU") {
return "tpu";
} else if (raw == "PPVAR_VSYS_PWR_DISP" || raw == "VSYS_PWR_DISPLAY") {
return "display";
diff --git a/src/trace_processor/metrics/sql/android/BUILD.gn b/src/trace_processor/metrics/sql/android/BUILD.gn
index d61d0e3..8884dd8 100644
--- a/src/trace_processor/metrics/sql/android/BUILD.gn
+++ b/src/trace_processor/metrics/sql/android/BUILD.gn
@@ -22,7 +22,6 @@
"android_batt.sql",
"android_binder.sql",
"android_blocking_calls_cuj_metric.sql",
- "android_sysui_notifications_blocking_calls_metric.sql",
"android_camera.sql",
"android_camera_unagg.sql",
"android_cpu.sql",
@@ -55,6 +54,7 @@
"android_simpleperf.sql",
"android_startup.sql",
"android_surfaceflinger.sql",
+ "android_sysui_notifications_blocking_calls_metric.sql",
"android_task_names.sql",
"android_trace_quality.sql",
"android_trusty_workqueues.sql",
diff --git a/src/trace_processor/metrics/sql/android/android_batt.sql b/src/trace_processor/metrics/sql/android/android_batt.sql
index a5cfd5a..acd256f 100644
--- a/src/trace_processor/metrics/sql/android/android_batt.sql
+++ b/src/trace_processor/metrics/sql/android/android_batt.sql
@@ -191,10 +191,10 @@
dur,
value_name AS slice_name,
CASE track_name
- WHEN 'battery_stats.mobile_radio' THEN 'Cellular radio'
+ WHEN 'battery_stats.mobile_radio' THEN 'Cellular interface'
WHEN 'battery_stats.data_conn' THEN 'Cellular connection'
WHEN 'battery_stats.phone_signal_strength' THEN 'Cellular strength'
- WHEN 'battery_stats.wifi_radio' THEN 'WiFi radio'
+ WHEN 'battery_stats.wifi_radio' THEN 'WiFi interface'
WHEN 'battery_stats.wifi_suppl' THEN 'Wifi supplicant state'
WHEN 'battery_stats.wifi_signal_strength' THEN 'WiFi strength'
ELSE NULL
diff --git a/src/trace_processor/metrics/sql/android/android_startup.sql b/src/trace_processor/metrics/sql/android/android_startup.sql
index ab69d2b..d619612 100644
--- a/src/trace_processor/metrics/sql/android/android_startup.sql
+++ b/src/trace_processor/metrics/sql/android/android_startup.sql
@@ -59,27 +59,23 @@
);
-- Returns the fully drawn slice proto given a launch id.
-SELECT CREATE_FUNCTION(
- 'REPORT_FULLY_DRAWN_FOR_LAUNCH(startup_id INT)',
- 'PROTO',
- '
- SELECT
- STARTUP_SLICE_PROTO(report_fully_drawn_ts - launch_ts)
- FROM (
- SELECT
- launches.ts AS launch_ts,
- min(slice.ts) AS report_fully_drawn_ts
- FROM android_startups launches
- JOIN android_startup_processes ON (launches.startup_id = android_startup_processes.startup_id)
- JOIN thread USING (upid)
- JOIN thread_track USING (utid)
- JOIN slice ON (slice.track_id = thread_track.id)
- WHERE
- slice.name GLOB "reportFullyDrawn*" AND
- slice.ts >= launches.ts AND
- launches.startup_id = $startup_id
- )
- '
+CREATE PERFETTO FUNCTION REPORT_FULLY_DRAWN_FOR_LAUNCH(startup_id INT)
+RETURNS PROTO AS
+SELECT
+ STARTUP_SLICE_PROTO(report_fully_drawn_ts - launch_ts)
+FROM (
+ SELECT
+ launches.ts AS launch_ts,
+ min(slice.ts) AS report_fully_drawn_ts
+ FROM android_startups launches
+ JOIN android_startup_processes ON (launches.startup_id = android_startup_processes.startup_id)
+ JOIN thread USING (upid)
+ JOIN thread_track USING (utid)
+ JOIN slice ON (slice.track_id = thread_track.id)
+ WHERE
+ slice.name GLOB "reportFullyDrawn*" AND
+ slice.ts >= launches.ts AND
+ launches.startup_id = $startup_id
);
-- Given a launch id and GLOB for a slice name, returns the N longest slice name and duration.
diff --git a/src/trace_processor/metrics/sql/android/counter_span_view_merged.sql b/src/trace_processor/metrics/sql/android/counter_span_view_merged.sql
index 01b7079..2a89f21 100644
--- a/src/trace_processor/metrics/sql/android/counter_span_view_merged.sql
+++ b/src/trace_processor/metrics/sql/android/counter_span_view_merged.sql
@@ -14,7 +14,7 @@
-- limitations under the License.
--
--- Creates a span view for counters that may be global or associated with a
+-- Creates a span view for counters that may be global or associated with a
-- process, assuming that in the latter case we don't actually care about the
-- process (probably because it's always system_server). We may want to erase
-- this distinction for example when merging system properties and atrace
diff --git a/src/trace_processor/metrics/sql/android/jank/internal/counters.sql b/src/trace_processor/metrics/sql/android/jank/internal/counters.sql
index d04229d..9f197fa 100644
--- a/src/trace_processor/metrics/sql/android/jank/internal/counters.sql
+++ b/src/trace_processor/metrics/sql/android/jank/internal/counters.sql
@@ -36,20 +36,19 @@
FROM counter
JOIN cuj_counter_track ON counter.track_id = cuj_counter_track.track_id;
-SELECT CREATE_FUNCTION(
- 'ANDROID_JANK_CUJ_COUNTER_VALUE(cuj_name STRING, counter_name STRING, ts_min INT, ts_max INT)',
- 'INT',
- '
- SELECT value
- FROM android_jank_cuj_counter
- WHERE
- cuj_name = $cuj_name
- AND counter_name = $counter_name
- AND ts >= $ts_min
- AND ($ts_max IS NULL OR ts <= $ts_max)
- ORDER BY ts ASC LIMIT 1
- '
-);
+CREATE PERFETTO FUNCTION ANDROID_JANK_CUJ_COUNTER_VALUE(cuj_name STRING,
+ counter_name STRING,
+ ts_min INT,
+ ts_max INT)
+RETURNS INT AS
+SELECT value
+FROM android_jank_cuj_counter
+WHERE
+ cuj_name = $cuj_name
+ AND counter_name = $counter_name
+ AND ts >= $ts_min
+ AND ($ts_max IS NULL OR ts <= $ts_max)
+ORDER BY ts ASC LIMIT 1;
DROP TABLE IF EXISTS cuj_marker_missed_callback;
CREATE TABLE cuj_marker_missed_callback AS
@@ -61,19 +60,21 @@
JOIN track marker_track on marker_track.id = marker.track_id
WHERE marker.name GLOB '*FT#Missed*';
-SELECT CREATE_FUNCTION(
- 'ANDROID_MISSED_VSYNCS_FOR_CALLBACK(cuj_slice_name STRING, ts_min INT, ts_max INT, callback_missed STRING)',
- 'INT',
- '
- SELECT IFNULL(SUM(marker_name GLOB $callback_missed), 0)
- FROM cuj_marker_missed_callback
- WHERE
- cuj_slice_name = $cuj_slice_name
- AND ts >= $ts_min
- AND ($ts_max IS NULL OR ts <= $ts_max)
- ORDER BY ts ASC LIMIT 1
- '
-);
+CREATE PERFETTO FUNCTION ANDROID_MISSED_VSYNCS_FOR_CALLBACK(
+ cuj_slice_name STRING,
+ ts_min INT,
+ ts_max INT,
+ callback_missed STRING
+)
+RETURNS INT AS
+SELECT IFNULL(SUM(marker_name GLOB $callback_missed), 0)
+FROM cuj_marker_missed_callback
+WHERE
+ cuj_slice_name = $cuj_slice_name
+ AND ts >= $ts_min
+ AND ($ts_max IS NULL OR ts <= $ts_max)
+ORDER BY ts ASC
+LIMIT 1;
DROP TABLE IF EXISTS android_jank_cuj_counter_metrics;
CREATE TABLE android_jank_cuj_counter_metrics AS
diff --git a/src/trace_processor/metrics/sql/android/jank/internal/query_base.sql b/src/trace_processor/metrics/sql/android/jank/internal/query_base.sql
index b205f79..76bcec6 100644
--- a/src/trace_processor/metrics/sql/android/jank/internal/query_base.sql
+++ b/src/trace_processor/metrics/sql/android/jank/internal/query_base.sql
@@ -64,38 +64,43 @@
-- Functions below retrieve specific columns for a given table set.
-SELECT CREATE_FUNCTION(
- 'ANDROID_JANK_CUJ_TABLE_SET_SLICE(table_set STRING)',
- 'STRING',
- 'SELECT slice_table_name FROM android_jank_cuj_table_set ts WHERE ts.name = $table_set'
-);
+CREATE PERFETTO FUNCTION ANDROID_JANK_CUJ_TABLE_SET_SLICE(table_set STRING)
+RETURNS STRING AS
+SELECT slice_table_name
+FROM android_jank_cuj_table_set ts
+WHERE ts.name = $table_set;
-SELECT CREATE_FUNCTION(
- 'ANDROID_JANK_CUJ_TABLE_SET_FRAME_BOUNDARY(table_set STRING)',
- 'STRING',
- 'SELECT frame_boundary_table_name FROM android_jank_cuj_table_set ts WHERE ts.name = $table_set'
-);
+CREATE PERFETTO FUNCTION ANDROID_JANK_CUJ_TABLE_SET_FRAME_BOUNDARY(
+ table_set STRING
+)
+RETURNS STRING AS
+SELECT frame_boundary_table_name
+FROM android_jank_cuj_table_set ts
+WHERE ts.name = $table_set;
-SELECT CREATE_FUNCTION(
- 'ANDROID_JANK_CUJ_TABLE_SET_CUJ_BOUNDARY(table_set STRING)',
- 'STRING',
- 'SELECT cuj_boundary_table_name FROM android_jank_cuj_table_set ts WHERE ts.name = $table_set'
-);
+CREATE PERFETTO FUNCTION ANDROID_JANK_CUJ_TABLE_SET_CUJ_BOUNDARY(
+ table_set STRING
+)
+RETURNS STRING AS
+SELECT cuj_boundary_table_name
+FROM android_jank_cuj_table_set ts
+WHERE ts.name = $table_set;
-SELECT CREATE_FUNCTION(
- 'ANDROID_JANK_CUJ_TABLE_SET_FRAME(table_set STRING)',
- 'STRING',
- 'SELECT frame_table_name FROM android_jank_cuj_table_set ts WHERE ts.name = $table_set'
-);
+CREATE PERFETTO FUNCTION ANDROID_JANK_CUJ_TABLE_SET_FRAME(table_set STRING)
+RETURNS STRING AS
+SELECT frame_table_name
+FROM android_jank_cuj_table_set ts
+WHERE ts.name = $table_set;
-- Checks if two slices, described by ts and dur, ts_second and dur_second, overlap.
-- Does not handle cases where slices are unfinished (dur = -1).
+CREATE PERFETTO FUNCTION ANDROID_JANK_CUJ_SLICE_OVERLAPS(ts LONG,
+ dur LONG,
+ ts_second LONG,
+ dur_second LONG)
+RETURNS BOOL AS
SELECT
- CREATE_FUNCTION(
- 'ANDROID_JANK_CUJ_SLICE_OVERLAPS(ts LONG, dur LONG, ts_second LONG, dur_second LONG)',
- 'BOOL',
- 'SELECT
- -- A starts before B ends and A ends after B starts
- ($ts < $ts_second + $dur_second AND $ts + $dur > $ts_second)
- -- or A starts after B starts and A ends before B ends
- OR ($ts > $ts_second AND $ts < $ts_second + $ts_dur)');
+ -- A starts before B ends and A ends after B starts
+ ($ts < $ts_second + $dur_second AND $ts + $dur > $ts_second)
+ -- or A starts after B starts and A ends before B ends
+ OR ($ts > $ts_second AND $ts < $ts_second + $ts_dur);
diff --git a/src/trace_processor/metrics/sql/android/jank/query_functions.sql b/src/trace_processor/metrics/sql/android/jank/query_functions.sql
index e96b587..c37dc42 100644
--- a/src/trace_processor/metrics/sql/android/jank/query_functions.sql
+++ b/src/trace_processor/metrics/sql/android/jank/query_functions.sql
@@ -13,7 +13,6 @@
-- See the License for the specific language governing permissions and
-- limitations under the License.
-
-- Consider calling ANDROID_JANK_CORRELATE_FRAME_SLICE which passes a default value for
-- `table_name_prefix`.
--
@@ -28,40 +27,52 @@
--
-- CREATE VIEW example_table AS
-- SELECT * FROM android_jank_cuj_slice WHERE name = 'binder transaction';
--- SELECT ANDROID_JANK_CORRELATE_FRAME_SLICE_IMPL('MainThread', 'example_table', 'jank_query');
+-- SELECT ANDROID_JANK_CORRELATE_FRAME_SLICE_IMPL('MainThread',
+-- 'example_table',
+-- 'jank_query');
-- SELECT * FROM jank_query_slice_in_frame_agg;
--
-- Function arguments:
--
-- table_set - Name of a set of tables from `android_jank_cuj_table_set`.
--- Groups releated tables to simplify passing them as arguments to functions.
+-- Groups releated tables to simplify passing them as arguments to
+-- functions.
--
--- relevant_slice_table_name - Table or View which selects slices for analysis from the
--- `android_jank_cuj_slice` table.
+-- relevant_slice_table_name - Table or View which selects slices for analysis
+-- from the `android_jank_cuj_slice` table.
--
--- table_name_prefix - Running the function will create multiple tables. This value will be used
--- as a prefx for their names to avoid name collisions with other tables.
-SELECT CREATE_FUNCTION(
- 'ANDROID_JANK_CORRELATE_FRAME_SLICE_IMPL(table_set STRING, relevant_slice_table_name STRING, table_name_prefix STRING)',
- 'STRING',
- '
- SELECT COALESCE( -- COALESCE to return the text with table names to the caller instead of NULL
- RUN_METRIC(
- "android/jank/internal/query_frame_slice.sql",
- "table_name_prefix", $table_name_prefix,
- "relevant_slice_table_name", $relevant_slice_table_name,
- "slice_table_name", (SELECT ANDROID_JANK_CUJ_TABLE_SET_SLICE($table_set)),
- "frame_boundary_table_name", (SELECT ANDROID_JANK_CUJ_TABLE_SET_FRAME_BOUNDARY($table_set)),
- "frame_table_name", (SELECT ANDROID_JANK_CUJ_TABLE_SET_FRAME($table_set))),
- "Query results in `" || $table_name_prefix || "_slice_in_frame_agg` and `" || $table_name_prefix || "_slice_in_frame`.")
- '
+-- table_name_prefix - Running the function will create multiple tables. This
+-- value will be used as a prefx for their names to avoid
+-- name collisions with other tables.
+CREATE PERFETTO FUNCTION ANDROID_JANK_CORRELATE_FRAME_SLICE_IMPL(
+ table_set STRING,
+ relevant_slice_table_name STRING,
+ table_name_prefix STRING
+)
+RETURNS STRING AS
+-- COALESCE to return the text with table names to the caller instead of NULL
+SELECT COALESCE(
+ RUN_METRIC(
+ "android/jank/internal/query_frame_slice.sql",
+ "table_name_prefix", $table_name_prefix,
+ "relevant_slice_table_name", $relevant_slice_table_name,
+ "slice_table_name", (SELECT ANDROID_JANK_CUJ_TABLE_SET_SLICE($table_set)),
+ "frame_boundary_table_name", (SELECT ANDROID_JANK_CUJ_TABLE_SET_FRAME_BOUNDARY($table_set)),
+ "frame_table_name", (SELECT ANDROID_JANK_CUJ_TABLE_SET_FRAME($table_set))
+ ),
+ "Query results in `" || $table_name_prefix || "_slice_in_frame_agg` and `" || $table_name_prefix || "_slice_in_frame`."
);
-
--- Provides a default value for table_name_prefix in ANDROID_JANK_CORRELATE_FRAME_SLICE_IMPL.
+-- Provides a default value for table_name_prefix in
+-- ANDROID_JANK_CORRELATE_FRAME_SLICE_IMPL.
-- See documentation for ANDROID_JANK_CORRELATE_FRAME_SLICE_IMPL.
-SELECT CREATE_FUNCTION(
- 'ANDROID_JANK_CORRELATE_FRAME_SLICE(table_set STRING, relevant_slice_table_name STRING)',
- 'STRING',
- 'SELECT ANDROID_JANK_CORRELATE_FRAME_SLICE_IMPL($table_set, $relevant_slice_table_name, "jank_query")'
+CREATE PERFETTO FUNCTION ANDROID_JANK_CORRELATE_FRAME_SLICE(
+ table_set STRING,
+ relevant_slice_table_name STRING
+)
+RETURNS STRING AS
+SELECT ANDROID_JANK_CORRELATE_FRAME_SLICE_IMPL(
+ $table_set,
+ $relevant_slice_table_name,
+ "jank_query"
);
diff --git a/src/trace_processor/metrics/sql/android/jank/relevant_slices.sql b/src/trace_processor/metrics/sql/android/jank/relevant_slices.sql
index bd72bd2..5894e64 100644
--- a/src/trace_processor/metrics/sql/android/jank/relevant_slices.sql
+++ b/src/trace_processor/metrics/sql/android/jank/relevant_slices.sql
@@ -13,41 +13,36 @@
-- See the License for the specific language governing permissions and
-- limitations under the License.
-SELECT CREATE_FUNCTION(
- 'VSYNC_FROM_NAME(slice_name STRING)',
- 'STRING',
- 'SELECT CAST(STR_SPLIT($slice_name, " ", 1) AS INTEGER)'
-);
+CREATE PERFETTO FUNCTION VSYNC_FROM_NAME(slice_name STRING)
+RETURNS STRING AS
+SELECT CAST(STR_SPLIT($slice_name, " ", 1) AS INTEGER);
-SELECT CREATE_FUNCTION(
- 'GPU_COMPLETION_FENCE_ID_FROM_NAME(slice_name STRING)',
- 'STRING',
- 'SELECT
- CASE
- WHEN
- $slice_name GLOB "GPU completion fence *"
- THEN
- CAST(STR_SPLIT($slice_name, " ", 3) AS INTEGER)
- WHEN
- $slice_name GLOB "Trace GPU completion fence *"
- THEN
- CAST(STR_SPLIT($slice_name, " ", 4) AS INTEGER)
- WHEN
- $slice_name GLOB "waiting for GPU completion *"
- THEN
- CAST(STR_SPLIT($slice_name, " ", 4) AS INTEGER)
- WHEN
- $slice_name GLOB "Trace HWC release fence *"
- THEN
- CAST(STR_SPLIT($slice_name, " ", 4) AS INTEGER)
- WHEN
- $slice_name GLOB "waiting for HWC release *"
- THEN
- CAST(STR_SPLIT($slice_name, " ", 4) AS INTEGER)
- ELSE NULL
- END
- '
-);
+CREATE PERFETTO FUNCTION GPU_COMPLETION_FENCE_ID_FROM_NAME(slice_name STRING)
+RETURNS STRING AS
+SELECT
+ CASE
+ WHEN
+ $slice_name GLOB "GPU completion fence *"
+ THEN
+ CAST(STR_SPLIT($slice_name, " ", 3) AS INTEGER)
+ WHEN
+ $slice_name GLOB "Trace GPU completion fence *"
+ THEN
+ CAST(STR_SPLIT($slice_name, " ", 4) AS INTEGER)
+ WHEN
+ $slice_name GLOB "waiting for GPU completion *"
+ THEN
+ CAST(STR_SPLIT($slice_name, " ", 4) AS INTEGER)
+ WHEN
+ $slice_name GLOB "Trace HWC release fence *"
+ THEN
+ CAST(STR_SPLIT($slice_name, " ", 4) AS INTEGER)
+ WHEN
+ $slice_name GLOB "waiting for HWC release *"
+ THEN
+ CAST(STR_SPLIT($slice_name, " ", 4) AS INTEGER)
+ ELSE NULL
+ END;
-- Find Choreographer#doFrame slices that are between the CUJ markers.
-- We extract vsync IDs from doFrame slice names and use these as the source
diff --git a/src/trace_processor/metrics/sql/android/process_metadata.sql b/src/trace_processor/metrics/sql/android/process_metadata.sql
index 5ccf2b1..3f6b9e8 100644
--- a/src/trace_processor/metrics/sql/android/process_metadata.sql
+++ b/src/trace_processor/metrics/sql/android/process_metadata.sql
@@ -56,13 +56,9 @@
LEFT JOIN upid_packages USING (upid);
-- Given a process name, return if it is debuggable.
-SELECT CREATE_FUNCTION(
- 'IS_PROCESS_DEBUGGABLE(process_name STRING)',
- 'BOOL',
- '
- SELECT p.debuggable
- FROM process_metadata_table p
- WHERE p.process_name = $process_name
- LIMIT 1
- '
-);
+CREATE PERFETTO FUNCTION IS_PROCESS_DEBUGGABLE(process_name STRING)
+RETURNS BOOL AS
+SELECT p.debuggable
+FROM process_metadata_table p
+WHERE p.process_name = $process_name
+LIMIT 1;
diff --git a/src/trace_processor/metrics/sql/android/startup/launches.sql b/src/trace_processor/metrics/sql/android/startup/launches.sql
index 8387cfe..e8441b9 100644
--- a/src/trace_processor/metrics/sql/android/startup/launches.sql
+++ b/src/trace_processor/metrics/sql/android/startup/launches.sql
@@ -13,7 +13,7 @@
-- See the License for the specific language governing permissions and
-- limitations under the License.
--- This metric will be deprecated soon. All of the tables have been
+-- This metric will be deprecated soon. All of the tables have been
-- migrated to SQL standard library and can be imported from:
SELECT IMPORT('android.startup.startups');
diff --git a/src/trace_processor/metrics/sql/android/startup/mcycles_per_launch.sql b/src/trace_processor/metrics/sql/android/startup/mcycles_per_launch.sql
index b47381e..6944625 100644
--- a/src/trace_processor/metrics/sql/android/startup/mcycles_per_launch.sql
+++ b/src/trace_processor/metrics/sql/android/startup/mcycles_per_launch.sql
@@ -55,15 +55,11 @@
-- Given a launch id and core type, returns the number of mcycles consumed
-- on CPUs of that core type during the launch.
-SELECT CREATE_FUNCTION(
- 'MCYCLES_FOR_LAUNCH_AND_CORE_TYPE(startup_id INT, core_type STRING)',
- 'INT',
- '
- SELECT mcycles
- FROM mcycles_per_core_type_per_launch m
- WHERE m.startup_id = $startup_id AND m.core_type = $core_type
- '
-);
+CREATE PERFETTO FUNCTION MCYCLES_FOR_LAUNCH_AND_CORE_TYPE(startup_id INT, core_type STRING)
+RETURNS INT AS
+SELECT mcycles
+FROM mcycles_per_core_type_per_launch m
+WHERE m.startup_id = $startup_id AND m.core_type = $core_type;
-- Contains the process using the most mcycles during the launch
-- *excluding the process being started*.
@@ -97,30 +93,23 @@
-- Given a launch id, returns the name of the processes consuming the most
-- mcycles during the launch excluding the process being started.
-SELECT CREATE_FUNCTION(
- 'N_MOST_ACTIVE_PROCESS_NAMES_FOR_LAUNCH(startup_id INT)',
- 'STRING',
- '
- SELECT RepeatedField(process_name)
- FROM (
- SELECT IFNULL(process.name, "[NULL]") AS process_name
- FROM top_mcyles_process_excluding_started_per_launch
- JOIN process USING (upid)
- WHERE startup_id = $startup_id
- ORDER BY mcycles DESC
- );
- '
+CREATE PERFETTO FUNCTION N_MOST_ACTIVE_PROCESS_NAMES_FOR_LAUNCH(startup_id INT)
+RETURNS STRING AS
+SELECT RepeatedField(process_name)
+FROM (
+ SELECT IFNULL(process.name, "[NULL]") AS process_name
+ FROM top_mcyles_process_excluding_started_per_launch
+ JOIN process USING (upid)
+ WHERE startup_id = $startup_id
+ ORDER BY mcycles DESC
);
-- Given a launch id, returns the most active process name.
-SELECT CREATE_FUNCTION(
- 'MOST_ACTIVE_PROCESS_FOR_LAUNCH(startup_id INT)',
- 'STRING',
- '
- SELECT process.name AS process_name
- FROM top_mcyles_process_excluding_started_per_launch
- JOIN process USING (upid)
- WHERE startup_id = $startup_id
- ORDER BY mcycles DESC LIMIT 1;
- '
-);
+CREATE PERFETTO FUNCTION MOST_ACTIVE_PROCESS_FOR_LAUNCH(startup_id INT)
+RETURNS STRING AS
+SELECT process.name AS process_name
+FROM top_mcyles_process_excluding_started_per_launch
+JOIN process USING (upid)
+WHERE startup_id = $startup_id
+ORDER BY mcycles DESC
+LIMIT 1;
diff --git a/src/trace_processor/metrics/sql/android/startup/slice_functions.sql b/src/trace_processor/metrics/sql/android/startup/slice_functions.sql
index 0939e0d..6c4eb25 100644
--- a/src/trace_processor/metrics/sql/android/startup/slice_functions.sql
+++ b/src/trace_processor/metrics/sql/android/startup/slice_functions.sql
@@ -17,12 +17,12 @@
SELECT IMPORT('android.startup.startups');
-- Helper function to build a Slice proto from a duration.
-SELECT CREATE_FUNCTION('STARTUP_SLICE_PROTO(dur INT)', 'PROTO', '
- SELECT AndroidStartupMetric_Slice(
- "dur_ns", $dur,
- "dur_ms", $dur / 1e6
- )
-');
+CREATE PERFETTO FUNCTION STARTUP_SLICE_PROTO(dur INT)
+RETURNS PROTO AS
+SELECT AndroidStartupMetric_Slice(
+ "dur_ns", $dur,
+ "dur_ms", $dur / 1e6
+);
-- View containing all the slices for all launches. Generally, this view
-- should not be used. Instead, one of the helper functions below which wrap
@@ -31,149 +31,112 @@
CREATE VIEW thread_slices_for_all_launches AS
SELECT * FROM android_thread_slices_for_all_startups;
-
--- Given a launch id and GLOB for a slice name,
--- summing the slice durations across the whole startup.
-SELECT CREATE_FUNCTION(
- 'ANDROID_SUM_DUR_FOR_STARTUP_AND_SLICE(startup_id LONG, slice_name STRING)',
- 'INT',
- '
- SELECT SUM(slice_dur)
- FROM android_thread_slices_for_all_startups
- WHERE startup_id = $startup_id AND slice_name GLOB $slice_name
- '
-);
-
-- Given a launch id and GLOB for a slice name, returns the startup slice proto,
-- summing the slice durations across the whole startup.
-SELECT CREATE_FUNCTION(
- 'DUR_SUM_SLICE_PROTO_FOR_LAUNCH(startup_id LONG, slice_name STRING)',
- 'PROTO',
- '
- SELECT NULL_IF_EMPTY(
- STARTUP_SLICE_PROTO(
- ANDROID_SUM_DUR_FOR_STARTUP_AND_SLICE($startup_id, $slice_name)
- )
- )
- '
+CREATE PERFETTO FUNCTION DUR_SUM_SLICE_PROTO_FOR_LAUNCH(startup_id LONG, slice_name STRING)
+RETURNS PROTO AS
+SELECT NULL_IF_EMPTY(
+ STARTUP_SLICE_PROTO(
+ ANDROID_SUM_DUR_FOR_STARTUP_AND_SLICE($startup_id, $slice_name)
+ )
);
-- Same as |DUR_SUM_SLICE_PROTO_FOR_LAUNCH| except only counting slices happening
-- on the main thread.
-SELECT CREATE_FUNCTION(
- 'DUR_SUM_MAIN_THREAD_SLICE_PROTO_FOR_LAUNCH(startup_id LONG, slice_name STRING)',
- 'PROTO',
- '
- SELECT NULL_IF_EMPTY(
- STARTUP_SLICE_PROTO(
- ANDROID_SUM_DUR_ON_MAIN_THREAD_FOR_STARTUP_AND_SLICE($startup_id, $slice_name)
- )
- )
- '
+CREATE PERFETTO FUNCTION DUR_SUM_MAIN_THREAD_SLICE_PROTO_FOR_LAUNCH(startup_id LONG, slice_name STRING)
+RETURNS PROTO AS
+SELECT NULL_IF_EMPTY(
+ STARTUP_SLICE_PROTO(
+ ANDROID_SUM_DUR_ON_MAIN_THREAD_FOR_STARTUP_AND_SLICE($startup_id, $slice_name)
+ )
);
-- Given a launch id and GLOB for a slice name, returns the startup slice proto by
-- taking the duration between the start of the launch and start of the slice.
-- If multiple slices match, picks the latest one which started during the launch.
-SELECT CREATE_FUNCTION(
- 'LAUNCH_TO_MAIN_THREAD_SLICE_PROTO(startup_id INT, slice_name STRING)',
- 'PROTO',
- '
- SELECT NULL_IF_EMPTY(STARTUP_SLICE_PROTO(MAX(slice_ts) - startup_ts))
- FROM android_thread_slices_for_all_startups s
- JOIN thread t USING (utid)
- WHERE
- s.slice_name GLOB $slice_name AND
- s.startup_id = $startup_id AND
- s.is_main_thread AND
- (t.end_ts IS NULL OR t.end_ts >= s.startup_ts_end)
- '
-);
+CREATE PERFETTO FUNCTION LAUNCH_TO_MAIN_THREAD_SLICE_PROTO(startup_id INT, slice_name STRING)
+RETURNS PROTO AS
+SELECT NULL_IF_EMPTY(STARTUP_SLICE_PROTO(MAX(slice_ts) - startup_ts))
+FROM android_thread_slices_for_all_startups s
+JOIN thread t USING (utid)
+WHERE
+ s.slice_name GLOB $slice_name AND
+ s.startup_id = $startup_id AND
+ s.is_main_thread AND
+ (t.end_ts IS NULL OR t.end_ts >= s.startup_ts_end);
-- Given a lauch id, returns the total time spent in GC
-SELECT CREATE_FUNCTION(
- 'TOTAL_GC_TIME_BY_LAUNCH(startup_id LONG)',
- 'INT',
- '
- SELECT SUM(slice_dur)
- FROM android_thread_slices_for_all_startups slice
- WHERE
- slice.startup_id = $startup_id AND
- (
- slice_name GLOB "*semispace GC" OR
- slice_name GLOB "*mark sweep GC" OR
- slice_name GLOB "*concurrent copying GC"
- )
- '
-);
+CREATE PERFETTO FUNCTION TOTAL_GC_TIME_BY_LAUNCH(startup_id LONG)
+RETURNS INT AS
+SELECT SUM(slice_dur)
+FROM android_thread_slices_for_all_startups slice
+WHERE
+ slice.startup_id = $startup_id AND
+ (
+ slice_name GLOB "*semispace GC" OR
+ slice_name GLOB "*mark sweep GC" OR
+ slice_name GLOB "*concurrent copying GC"
+ );
-- Given a launch id and package name, returns if baseline or cloud profile is missing.
-SELECT CREATE_FUNCTION(
- 'MISSING_BASELINE_PROFILE_FOR_LAUNCH(startup_id LONG, pkg_name STRING)',
- 'BOOL',
- '
- SELECT (COUNT(slice_name) > 0)
- FROM (
- SELECT *
- FROM ANDROID_SLICES_FOR_STARTUP_AND_SLICE_NAME(
- $startup_id,
- "location=* status=* filter=* reason=*"
- )
- ORDER BY slice_name
- )
- WHERE
- -- when location is the package odex file and the reason is "install" or "install-dm",
- -- if the compilation filter is not "speed-profile", baseline/cloud profile is missing.
- SUBSTR(STR_SPLIT(slice_name, " status=", 0), LENGTH("location=") + 1)
- GLOB ("*" || $pkg_name || "*odex")
- AND (STR_SPLIT(slice_name, " reason=", 1) = "install"
- OR STR_SPLIT(slice_name, " reason=", 1) = "install-dm")
- AND STR_SPLIT(STR_SPLIT(slice_name, " filter=", 1), " reason=", 0) != "speed-profile"
- '
-);
+CREATE PERFETTO FUNCTION MISSING_BASELINE_PROFILE_FOR_LAUNCH(startup_id LONG, pkg_name STRING)
+RETURNS BOOL AS
+SELECT (COUNT(slice_name) > 0)
+FROM (
+ SELECT *
+ FROM ANDROID_SLICES_FOR_STARTUP_AND_SLICE_NAME(
+ $startup_id,
+ "location=* status=* filter=* reason=*"
+ )
+ ORDER BY slice_name
+)
+WHERE
+ -- when location is the package odex file and the reason is "install" or "install-dm",
+ -- if the compilation filter is not "speed-profile", baseline/cloud profile is missing.
+ SUBSTR(STR_SPLIT(slice_name, " status=", 0), LENGTH("location=") + 1)
+ GLOB ("*" || $pkg_name || "*odex")
+ AND (STR_SPLIT(slice_name, " reason=", 1) = "install"
+ OR STR_SPLIT(slice_name, " reason=", 1) = "install-dm")
+ AND STR_SPLIT(STR_SPLIT(slice_name, " filter=", 1), " reason=", 0) != "speed-profile";
-- Given a launch id, returns if there is a main thread run-from-apk slice.
-- Add an exception if "split_config" is in parent slice's name(b/277809828).
-- TODO: remove the exception after Sep 2023 (b/78772867)
-SELECT CREATE_FUNCTION(
- 'RUN_FROM_APK_FOR_LAUNCH(launch_id LONG)',
- 'BOOL',
- '
- SELECT EXISTS(
- SELECT slice_name, startup_id, is_main_thread
- FROM android_thread_slices_for_all_startups s
- JOIN slice ON slice.id = s.slice_id
- LEFT JOIN slice parent ON slice.parent_id = parent.id
- WHERE
- startup_id = $launch_id AND is_main_thread AND
- slice_name GLOB "location=* status=* filter=* reason=*" AND
- STR_SPLIT(STR_SPLIT(slice_name, " filter=", 1), " reason=", 0)
- GLOB ("*" || "run-from-apk" || "*") AND
- (parent.name IS NULL OR
- parent.name NOT GLOB ("OpenDexFilesFromOat(*split_config*apk)"))
- )
- '
+CREATE PERFETTO FUNCTION RUN_FROM_APK_FOR_LAUNCH(launch_id LONG)
+RETURNS BOOL AS
+SELECT EXISTS(
+ SELECT slice_name, startup_id, is_main_thread
+ FROM android_thread_slices_for_all_startups s
+ JOIN slice ON slice.id = s.slice_id
+ LEFT JOIN slice parent ON slice.parent_id = parent.id
+ WHERE
+ startup_id = $launch_id AND is_main_thread AND
+ slice_name GLOB "location=* status=* filter=* reason=*" AND
+ STR_SPLIT(STR_SPLIT(slice_name, " filter=", 1), " reason=", 0)
+ GLOB ("*" || "run-from-apk" || "*") AND
+ (parent.name IS NULL OR
+ parent.name NOT GLOB ("OpenDexFilesFromOat(*split_config*apk)"))
);
-SELECT CREATE_FUNCTION(
- 'SUMMARY_FOR_OPTIMIZATION_STATUS(loc STRING, status STRING, filter STRING, reason STRING)',
- 'STRING',
- '
- SELECT
- CASE
- WHEN
- $loc GLOB "*/base.odex" AND $loc GLOB "*==/*-*"
- THEN STR_SPLIT(STR_SPLIT($loc, "==/", 1), "-", 0) || "/.../"
- ELSE ""
- END ||
- CASE
- WHEN $loc GLOB "*/*"
- THEN REVERSE(STR_SPLIT(REVERSE($loc), "/", 0))
- ELSE $loc
- END ||
- ": " || $status || "/" || $filter || "/" || $reason
- '
-);
+CREATE PERFETTO FUNCTION SUMMARY_FOR_OPTIMIZATION_STATUS(
+ loc STRING,
+ status STRING,
+ filter_str STRING,
+ reason STRING
+)
+RETURNS STRING AS
+SELECT
+CASE
+ WHEN
+ $loc GLOB "*/base.odex" AND $loc GLOB "*==/*-*"
+ THEN STR_SPLIT(STR_SPLIT($loc, "==/", 1), "-", 0) || "/.../"
+ ELSE ""
+END ||
+CASE
+ WHEN $loc GLOB "*/*"
+ THEN REVERSE(STR_SPLIT(REVERSE($loc), "/", 0))
+ ELSE $loc
+END || ": " || $status || "/" || $filter_str || "/" || $reason;
SELECT CREATE_VIEW_FUNCTION(
'BINDER_TRANSACTION_REPLY_SLICES_FOR_LAUNCH(startup_id INT, threshold DOUBLE)',
@@ -188,21 +151,17 @@
);
-- Given a launch id, return if unlock is running by systemui during the launch.
-SELECT CREATE_FUNCTION(
- 'IS_UNLOCK_RUNNING_DURING_LAUNCH(startup_id LONG)',
- 'BOOL',
- '
- SELECT EXISTS(
- SELECT slice.name
- FROM slice, android_startups launches
- JOIN thread_track ON slice.track_id = thread_track.id
- JOIN thread USING(utid)
- JOIN process USING(upid)
- WHERE launches.startup_id = $startup_id
- AND slice.name = "KeyguardUpdateMonitor#onAuthenticationSucceeded"
- AND process.name = "com.android.systemui"
- AND slice.ts >= launches.ts
- AND (slice.ts + slice.dur) <= launches.ts_end
- )
- '
+CREATE PERFETTO FUNCTION IS_UNLOCK_RUNNING_DURING_LAUNCH(startup_id LONG)
+RETURNS BOOL AS
+SELECT EXISTS(
+ SELECT slice.name
+ FROM slice, android_startups launches
+ JOIN thread_track ON slice.track_id = thread_track.id
+ JOIN thread USING(utid)
+ JOIN process USING(upid)
+ WHERE launches.startup_id = $startup_id
+ AND slice.name = "KeyguardUpdateMonitor#onAuthenticationSucceeded"
+ AND process.name = "com.android.systemui"
+ AND slice.ts >= launches.ts
+ AND (slice.ts + slice.dur) <= launches.ts_end
);
diff --git a/src/trace_processor/metrics/sql/android/startup/system_state.sql b/src/trace_processor/metrics/sql/android/startup/system_state.sql
index 5b49ace..214ac3f 100644
--- a/src/trace_processor/metrics/sql/android/startup/system_state.sql
+++ b/src/trace_processor/metrics/sql/android/startup/system_state.sql
@@ -21,40 +21,35 @@
-- Given a launch id and process name glob, returns the sched.dur if a process with
-- that name was running on a CPU concurrent to that launch.
-SELECT CREATE_FUNCTION(
- 'DUR_OF_PROCESS_RUNNING_CONCURRENT_TO_LAUNCH(startup_id INT, process_glob STRING)',
- 'INT',
- '
- SELECT IFNULL(SUM(sched.dur), 0)
- FROM sched
- JOIN thread USING (utid)
- JOIN process USING (upid)
- JOIN (
- SELECT ts, ts_end
- FROM android_startups
- WHERE startup_id = $startup_id
- ) launch
- WHERE
- process.name GLOB $process_glob AND
- sched.ts BETWEEN launch.ts AND launch.ts_end
- '
-);
+CREATE PERFETTO FUNCTION DUR_OF_PROCESS_RUNNING_CONCURRENT_TO_LAUNCH(
+ startup_id INT,
+ process_glob STRING
+)
+RETURNS INT AS
+SELECT IFNULL(SUM(sched.dur), 0)
+FROM sched
+JOIN thread USING (utid)
+JOIN process USING (upid)
+JOIN (
+ SELECT ts, ts_end
+ FROM android_startups
+ WHERE startup_id = $startup_id
+) launch
+WHERE
+ process.name GLOB $process_glob AND
+ sched.ts BETWEEN launch.ts AND launch.ts_end;
-- Given a launch id and slice name glob, returns the number of slices with that
-- name which start concurrent to that launch.
-SELECT CREATE_FUNCTION(
- 'COUNT_SLICES_CONCURRENT_TO_LAUNCH(startup_id INT, slice_glob STRING)',
- 'INT',
- '
- SELECT COUNT(1)
- FROM slice
- JOIN (
- SELECT ts, ts_end
- FROM android_startups
- WHERE startup_id = $startup_id
- ) launch
- WHERE
- slice.name GLOB $slice_glob AND
- slice.ts BETWEEN launch.ts AND launch.ts_end
- '
-);
+CREATE PERFETTO FUNCTION COUNT_SLICES_CONCURRENT_TO_LAUNCH(startup_id INT, slice_glob STRING)
+RETURNS INT AS
+SELECT COUNT(1)
+FROM slice
+JOIN (
+ SELECT ts, ts_end
+ FROM android_startups
+ WHERE startup_id = $startup_id
+) launch
+WHERE
+ slice.name GLOB $slice_glob AND
+ slice.ts BETWEEN launch.ts AND launch.ts_end;
diff --git a/src/trace_processor/metrics/sql/android/startup/thread_state_breakdown.sql b/src/trace_processor/metrics/sql/android/startup/thread_state_breakdown.sql
index 4ef1fc4..0ed863d 100644
--- a/src/trace_processor/metrics/sql/android/startup/thread_state_breakdown.sql
+++ b/src/trace_processor/metrics/sql/android/startup/thread_state_breakdown.sql
@@ -58,51 +58,35 @@
-- Given a launch id and thread state value, returns the aggregate sum
-- of time spent in that state by the main thread of the process being started up.
-SELECT CREATE_FUNCTION(
- 'MAIN_THREAD_TIME_FOR_LAUNCH_AND_STATE(startup_id INT, state STRING)',
- 'INT',
- '
- SELECT SUM(dur)
- FROM launch_thread_state_dur_sum l
- WHERE l.startup_id = $startup_id AND state GLOB $state AND is_main_thread;
- '
-);
+CREATE PERFETTO FUNCTION MAIN_THREAD_TIME_FOR_LAUNCH_AND_STATE(startup_id INT, state STRING)
+RETURNS INT AS
+SELECT SUM(dur)
+FROM launch_thread_state_dur_sum l
+WHERE l.startup_id = $startup_id AND state GLOB $state AND is_main_thread;
-- Given a launch id, returns the aggregate sum of time spent in runnable state
-- by the main thread of the process being started up.
-SELECT CREATE_FUNCTION(
- 'MAIN_THREAD_TIME_FOR_LAUNCH_IN_RUNNABLE_STATE(startup_id INT)',
- 'INT',
- '
- SELECT IFNULL(MAIN_THREAD_TIME_FOR_LAUNCH_AND_STATE($startup_id, "R"), 0)
+CREATE PERFETTO FUNCTION MAIN_THREAD_TIME_FOR_LAUNCH_IN_RUNNABLE_STATE(startup_id INT)
+RETURNS INT AS
+SELECT IFNULL(MAIN_THREAD_TIME_FOR_LAUNCH_AND_STATE($startup_id, "R"), 0)
+ IFNULL(MAIN_THREAD_TIME_FOR_LAUNCH_AND_STATE($startup_id, "R+"), 0);
- '
-);
-- Given a launch id, thread state and io_wait value, returns the aggregate sum
-- of time spent in that state by the main thread of the process being started up.
-SELECT CREATE_FUNCTION(
- 'MAIN_THREAD_TIME_FOR_LAUNCH_STATE_AND_IO_WAIT(startup_id INT, state STRING, io_wait BOOL)',
- 'INT',
- '
- SELECT SUM(dur)
- FROM launch_thread_state_io_wait_dur_sum l
- WHERE l.startup_id = $startup_id AND state GLOB $state
- AND is_main_thread AND l.io_wait = $io_wait;
- '
-);
+CREATE PERFETTO FUNCTION MAIN_THREAD_TIME_FOR_LAUNCH_STATE_AND_IO_WAIT(startup_id INT, state STRING, io_wait BOOL)
+RETURNS INT AS
+SELECT SUM(dur)
+FROM launch_thread_state_io_wait_dur_sum l
+WHERE l.startup_id = $startup_id AND state GLOB $state
+ AND is_main_thread AND l.io_wait = $io_wait;
-- Given a launch id, thread state value and name of a thread, returns the aggregate sum
-- of time spent in that state by that thread. Note: only threads of the processes
-- being started are considered by this function - if a thread from a different name
-- happens to match the name passed, it will *not* be included.
-SELECT CREATE_FUNCTION(
- 'THREAD_TIME_FOR_LAUNCH_STATE_AND_THREAD(startup_id INT, state STRING, thread_name STRING)',
- 'INT',
- '
- SELECT SUM(dur)
- FROM launch_thread_state_dur_sum l
- WHERE l.startup_id = $startup_id AND state GLOB $state AND thread_name = $thread_name;
- '
-);
+CREATE PERFETTO FUNCTION THREAD_TIME_FOR_LAUNCH_STATE_AND_THREAD(startup_id INT, state STRING, thread_name STRING)
+RETURNS INT AS
+SELECT SUM(dur)
+FROM launch_thread_state_dur_sum l
+WHERE l.startup_id = $startup_id AND state GLOB $state AND thread_name = $thread_name;
diff --git a/src/trace_processor/metrics/sql/chrome/chrome_input_to_browser_intervals_base.sql b/src/trace_processor/metrics/sql/chrome/chrome_input_to_browser_intervals_base.sql
index 9d39948..a43903c 100644
--- a/src/trace_processor/metrics/sql/chrome/chrome_input_to_browser_intervals_base.sql
+++ b/src/trace_processor/metrics/sql/chrome/chrome_input_to_browser_intervals_base.sql
@@ -17,44 +17,43 @@
-- active development and the values & meaning might change without
-- notice.
-SELECT CREATE_FUNCTION(
- -- Given a slice id of an event, get timestamp of the most recent flow
- -- event on the Chrome IO thread that preceded this slice.
- -- This helps us identify the last flow event on the IO thread before
- -- letting the browser main thread be aware of input.
- -- We need this for flings (generated by the GPU process) and blocked
- -- touch moves that are forwarded from the renderer.
- '{{function_prefix}}PRECEDING_IO_THREAD_EVENT_FLOW_ID(id LONG)',
- -- Returning the slice id for the flow_out on the chrome IO thread.
- 'LONG',
- 'SELECT MAX(flow.slice_out) AS id
- FROM
- PRECEDING_FLOW(($id)) flow');
+-- Given a slice id of an event, get timestamp of the most recent flow
+-- event on the Chrome IO thread that preceded this slice.
+-- This helps us identify the last flow event on the IO thread before
+-- letting the browser main thread be aware of input.
+-- We need this for flings (generated by the GPU process) and blocked
+-- touch moves that are forwarded from the renderer.
+-- Returning the slice id for the flow_out on the chrome IO thread.
+CREATE PERFETTO FUNCTION {{function_prefix}}PRECEDING_IO_THREAD_EVENT_FLOW_ID(id LONG)
+RETURNS LONG AS
+SELECT MAX(flow.slice_out) AS id
+FROM PRECEDING_FLOW(($id)) flow;
-- Returns a Chrome task which contains the given slice.
-SELECT CREATE_FUNCTION(
- '{{function_prefix}}GET_ENCLOSING_CHROME_TASK_NAME(slice_id LONG)',
- 'STRING',
- 'SELECT
- task.name
- FROM ancestor_slice($slice_id)
- JOIN chrome_tasks task USING (id)
- LIMIT 1
- '
-);
+CREATE PERFETTO FUNCTION {{function_prefix}}GET_ENCLOSING_CHROME_TASK_NAME(
+ slice_id LONG
+)
+RETURNS STRING AS
+SELECT
+ task.name
+FROM ancestor_slice($slice_id)
+JOIN chrome_tasks task USING (id)
+LIMIT 1;
-SELECT CREATE_FUNCTION(
- '{{function_prefix}}GET_SCROLL_TYPE(blocked_gesture BOOL, task_name STRING)',
- 'STRING',
- 'SELECT
- CASE WHEN ($blocked_gesture)
- THEN (SELECT
- CASE WHEN ($task_name) glob "viz.mojom.BeginFrameObserver *"
- THEN "fling"
- WHEN ($task_name) glob "blink.mojom.WidgetInputHandler *"
- THEN "blocking_touch_move"
- ELSE "unknown" END)
- ELSE "regular" END AS delay_type');
+CREATE PERFETTO FUNCTION {{function_prefix}}GET_SCROLL_TYPE(
+ blocked_gesture BOOL,
+ task_name STRING
+)
+RETURNS STRING AS
+SELECT
+ CASE WHEN ($blocked_gesture)
+ THEN (SELECT
+ CASE WHEN ($task_name) glob "viz.mojom.BeginFrameObserver *"
+ THEN "fling"
+ WHEN ($task_name) glob "blink.mojom.WidgetInputHandler *"
+ THEN "blocking_touch_move"
+ ELSE "unknown" END)
+ ELSE "regular" END AS delay_type;
-- Get all InputLatency::GestureScrollUpdate events, to use their
-- flows later on to decide how much time we waited from queueing the event
@@ -161,8 +160,6 @@
WHERE
flow_order = 1;
-
-
-- The decision for processing on the browser main thread for a frame can be
-- instant, or delayed by the renderer in cases where the renderer needs to
-- decide whether the touch move is an ScrollUpdate or not, and in other cases
diff --git a/src/trace_processor/metrics/sql/chrome/chrome_long_tasks.sql b/src/trace_processor/metrics/sql/chrome/chrome_long_tasks.sql
index d1487c1..6557694 100644
--- a/src/trace_processor/metrics/sql/chrome/chrome_long_tasks.sql
+++ b/src/trace_processor/metrics/sql/chrome/chrome_long_tasks.sql
@@ -48,11 +48,9 @@
'
);
-SELECT CREATE_FUNCTION(
- 'IS_LONG_CHOREOGRAPHER_TASK(dur LONG)',
- 'BOOL',
- 'SELECT $dur >= 4 * 1e6'
-);
+CREATE PERFETTO FUNCTION IS_LONG_CHOREOGRAPHER_TASK(dur LONG)
+RETURNS BOOL AS
+SELECT $dur >= 4 * 1e6;
-- Note that not all slices will be mojo slices; filter on interface_name IS
-- NOT NULL for mojo slices specifically.
diff --git a/src/trace_processor/metrics/sql/chrome/chrome_stack_samples_for_task.sql b/src/trace_processor/metrics/sql/chrome/chrome_stack_samples_for_task.sql
index f971cbb..eb04fa2 100644
--- a/src/trace_processor/metrics/sql/chrome/chrome_stack_samples_for_task.sql
+++ b/src/trace_processor/metrics/sql/chrome/chrome_stack_samples_for_task.sql
@@ -23,18 +23,15 @@
-- @task_name: a task name following chrome_tasks.sql naming convention to
-- find stack samples on.
-
SELECT IMPORT('chrome.tasks');
-SELECT CREATE_FUNCTION(
- 'DescribeSymbol(symbol STRING, frame_name STRING)',
- 'STRING',
- 'SELECT COALESCE($symbol,
- CASE WHEN demangle($frame_name) IS NULL
- THEN $frame_name
- ELSE demangle($frame_name)
- END)'
-);
+CREATE PERFETTO FUNCTION DescribeSymbol(symbol STRING, frame_name STRING)
+RETURNS STRING AS
+SELECT COALESCE($symbol,
+ CASE WHEN demangle($frame_name) IS NULL
+ THEN $frame_name
+ ELSE demangle($frame_name)
+ END);
-- Get all Chrome tasks that match a specific name on a specific thread.
-- The timestamps for those tasks are going to be used later on to gather
diff --git a/src/trace_processor/metrics/sql/chrome/event_latency_to_breakdowns.sql b/src/trace_processor/metrics/sql/chrome/event_latency_to_breakdowns.sql
index da02110..2d448e5 100644
--- a/src/trace_processor/metrics/sql/chrome/event_latency_to_breakdowns.sql
+++ b/src/trace_processor/metrics/sql/chrome/event_latency_to_breakdowns.sql
@@ -45,43 +45,41 @@
ON slice.parent_id = event_latency.slice_id;
-- The function takes a breakdown name and checks if the breakdown name is known or not.
-SELECT CREATE_FUNCTION(
- 'InvalidNameOrNull(name STRING)',
- -- Returns the input breakdown name if it's an unknown breakdown, NULL otherwise.
- 'STRING',
- 'SELECT
- CASE
- WHEN
- $name not in (
- "GenerationToBrowserMain", "GenerationToRendererCompositor",
- "BrowserMainToRendererCompositor", "RendererCompositorQueueingDelay",
- "RendererCompositorToMain", "RendererCompositorProcessing",
- "RendererMainProcessing", "EndActivateToSubmitCompositorFrame",
- "SubmitCompositorFrameToPresentationCompositorFrame",
- "ArrivedInRendererCompositorToTermination",
- "RendererCompositorStartedToTermination",
- "RendererMainFinishedToTermination",
- "RendererCompositorFinishedToTermination",
- "RendererMainStartedToTermination",
- "RendererCompositorFinishedToBeginImplFrame",
- "RendererCompositorFinishedToCommit",
- "RendererCompositorFinishedToEndCommit",
- "RendererCompositorFinishedToActivation",
- "RendererCompositorFinishedToEndActivate",
- "RendererCompositorFinishedToSubmitCompositorFrame",
- "RendererMainFinishedToBeginImplFrame",
- "RendererMainFinishedToSendBeginMainFrame",
- "RendererMainFinishedToCommit", "RendererMainFinishedToEndCommit",
- "RendererMainFinishedToActivation", "RendererMainFinishedToEndActivate",
- "RendererMainFinishedToSubmitCompositorFrame",
- "BeginImplFrameToSendBeginMainFrame",
- "RendererCompositorFinishedToSendBeginMainFrame",
- "SendBeginMainFrameToCommit", "Commit",
- "EndCommitToActivation", "Activation")
- THEN $name
- ELSE NULL
- END'
-);
+-- Returns the input breakdown name if it's an unknown breakdown, NULL otherwise.
+CREATE PERFETTO FUNCTION InvalidNameOrNull(name STRING)
+RETURNS STRING AS
+SELECT
+ CASE
+ WHEN
+ $name not in (
+ "GenerationToBrowserMain", "GenerationToRendererCompositor",
+ "BrowserMainToRendererCompositor", "RendererCompositorQueueingDelay",
+ "RendererCompositorToMain", "RendererCompositorProcessing",
+ "RendererMainProcessing", "EndActivateToSubmitCompositorFrame",
+ "SubmitCompositorFrameToPresentationCompositorFrame",
+ "ArrivedInRendererCompositorToTermination",
+ "RendererCompositorStartedToTermination",
+ "RendererMainFinishedToTermination",
+ "RendererCompositorFinishedToTermination",
+ "RendererMainStartedToTermination",
+ "RendererCompositorFinishedToBeginImplFrame",
+ "RendererCompositorFinishedToCommit",
+ "RendererCompositorFinishedToEndCommit",
+ "RendererCompositorFinishedToActivation",
+ "RendererCompositorFinishedToEndActivate",
+ "RendererCompositorFinishedToSubmitCompositorFrame",
+ "RendererMainFinishedToBeginImplFrame",
+ "RendererMainFinishedToSendBeginMainFrame",
+ "RendererMainFinishedToCommit", "RendererMainFinishedToEndCommit",
+ "RendererMainFinishedToActivation", "RendererMainFinishedToEndActivate",
+ "RendererMainFinishedToSubmitCompositorFrame",
+ "BeginImplFrameToSendBeginMainFrame",
+ "RendererCompositorFinishedToSendBeginMainFrame",
+ "SendBeginMainFrameToCommit", "Commit",
+ "EndCommitToActivation", "Activation")
+ THEN $name
+ ELSE NULL
+ END;
-- Creates a view where each row contains information about one EventLatency event. Columns are duration of breakdowns.
-- In the result it will be something like this:
diff --git a/src/trace_processor/metrics/sql/chrome/jank_utilities.sql b/src/trace_processor/metrics/sql/chrome/jank_utilities.sql
index 0d94fad..e1c3a45 100644
--- a/src/trace_processor/metrics/sql/chrome/jank_utilities.sql
+++ b/src/trace_processor/metrics/sql/chrome/jank_utilities.sql
@@ -25,16 +25,19 @@
-- ratio should increase with increments more than minimal value in numerator
-- (1ns) divided by maximum value in denominator, giving 1e-9.
-SELECT CREATE_FUNCTION(
- -- Function : function takes scroll ids of frames to verify it's from
- -- the same scroll, and makes sure the frame ts occured within the scroll
- -- timestamp of the neighbour and computes whether the frame was janky or not.
- 'IsJankyFrame(cur_gesture_id LONG,neighbour_gesture_id LONG,neighbour_ts LONG,'
- || 'cur_gesture_begin_ts LONG,cur_gesture_end_ts LONG,cur_frame_exact FLOAT,'
- || 'neighbour_frame_exact FLOAT)',
- -- Returns true if the frame was janky, false otherwise
- 'BOOL',
- 'SELECT
+-- Function : function takes scroll ids of frames to verify it's from
+-- the same scroll, and makes sure the frame ts occured within the scroll
+-- timestamp of the neighbour and computes whether the frame was janky or not.
+CREATE PERFETTO FUNCTION IsJankyFrame(cur_gesture_id LONG,
+ neighbour_gesture_id LONG,
+ neighbour_ts LONG,
+ cur_gesture_begin_ts LONG,
+ cur_gesture_end_ts LONG,
+ cur_frame_exact FLOAT,
+ neighbour_frame_exact FLOAT)
+-- Returns true if the frame was janky, false otherwise
+RETURNS BOOL AS
+SELECT
CASE WHEN
$cur_gesture_id != $neighbour_gesture_id OR
$neighbour_ts IS NULL OR
@@ -42,42 +45,64 @@
$neighbour_ts > $cur_gesture_end_ts THEN
FALSE ELSE
$cur_frame_exact > $neighbour_frame_exact + 0.5 + 1e-9
- END'
-);
+ END;
-SELECT CREATE_FUNCTION(
- -- Function : function takes the cur_frame_exact, prev_frame_exact and
- -- next_frame_exact and returns the value of the jank budget of the current
- -- frame.
- --
- -- JankBudget is the minimum amount of frames/time we need to reduce the frame
- -- duration by for it to be no longer considered janky.
- 'JankBudget(cur_frame_exact FLOAT, prev_frame_exact FLOAT, '
- || ' next_frame_exact FLOAT)',
- -- Returns the jank budget in percentage (i.e. 0.75) of vsync interval
- -- percentage.
- --
- -- We determine the difference between the frame count of the current frame
- -- and its consecutive frames by subtracting with the frame_exact values. We
- -- null check for cases when the neighbor frame count can be null for the
- -- first and last frames.
- --
- -- Since a frame is considered janky, if the difference in the frame count
- -- with its adjacent frame is greater than 0.5 (half a vsync) which means we
- -- need to reduce the frame count by a value less than 0.5 of maximum
- -- difference in frame count for it to be no longer janky. We subtract 1e-9 as
- -- we want to output minimum amount required.
- 'FLOAT',
- 'SELECT
- COALESCE(
- -- Could be null if next or previous is null.
- MAX(
- ($cur_frame_exact - $prev_frame_exact),
- ($cur_frame_exact - $next_frame_exact)
- ),
- -- If one of them is null output the first non-null.
+-- Function : function takes the cur_frame_exact, prev_frame_exact and
+-- next_frame_exact and returns the value of the jank budget of the current
+-- frame.
+--
+-- JankBudget is the minimum amount of frames/time we need to reduce the frame
+-- duration by for it to be no longer considered janky.
+--
+-- Returns the jank budget in percentage (i.e. 0.75) of vsync interval
+-- percentage.
+CREATE PERFETTO FUNCTION JankBudget(
+ cur_frame_exact FLOAT,
+ prev_frame_exact FLOAT,
+ next_frame_exact FLOAT
+)
+RETURNS FLOAT AS
+-- We determine the difference between the frame count of the current frame
+-- and its consecutive frames by subtracting with the frame_exact values. We
+-- null check for cases when the neighbor frame count can be null for the
+-- first and last frames.
+--
+-- Since a frame is considered janky, if the difference in the frame count
+-- with its adjacent frame is greater than 0.5 (half a vsync) which means we
+-- need to reduce the frame count by a value less than 0.5 of maximum
+-- difference in frame count for it to be no longer janky. We subtract 1e-9 as
+-- we want to output minimum amount required.
+SELECT
+ COALESCE(
+ -- Could be null if next or previous is null.
+ MAX(
($cur_frame_exact - $prev_frame_exact),
($cur_frame_exact - $next_frame_exact)
- -- Otherwise return null
- ) - 0.5 - 1e-9'
-);
\ No newline at end of file
+ ),
+ -- If one of them is null output the first non-null.
+ ($cur_frame_exact - $prev_frame_exact),
+ ($cur_frame_exact - $next_frame_exact)
+ -- Otherwise return null
+ ) - 0.5 - 1e-9;
+
+-- Extract mojo information for the long-task-tracking scenario for specific
+-- names. For example, LongTaskTracker slices may have associated IPC
+-- metadata, or InterestingTask slices for input may have associated IPC to
+-- determine whether the task is fling/etc.
+SELECT CREATE_VIEW_FUNCTION(
+ 'SELECT_LONG_TASK_SLICES(name STRING)',
+ 'interface_name STRING, ipc_hash INT, message_type STRING, id INT',
+ 'SELECT
+ EXTRACT_ARG(s.arg_set_id, "chrome_mojo_event_info.mojo_interface_tag") AS interface_name,
+ EXTRACT_ARG(arg_set_id, "chrome_mojo_event_info.ipc_hash") AS ipc_hash,
+ CASE
+ WHEN EXTRACT_ARG(arg_set_id, "chrome_mojo_event_info.is_reply") THEN "reply"
+ ELSE "message"
+ END AS message_type,
+ s.id
+ FROM slice s
+ WHERE
+ category GLOB "*scheduler.long_tasks*"
+ AND name = $name
+ '
+);
diff --git a/src/trace_processor/metrics/sql/chrome/scroll_jank_cause_get_bitmap.sql b/src/trace_processor/metrics/sql/chrome/scroll_jank_cause_get_bitmap.sql
index fd57296..be66e44 100644
--- a/src/trace_processor/metrics/sql/chrome/scroll_jank_cause_get_bitmap.sql
+++ b/src/trace_processor/metrics/sql/chrome/scroll_jank_cause_get_bitmap.sql
@@ -55,7 +55,7 @@
--------------------------------------------------------------------------------
-- Keeping only the GestureScrollUpdates join the maximum flows on the browser
--- thread.
+-- thread.
DROP VIEW IF EXISTS scroll_with_browser_flows;
CREATE VIEW scroll_with_browser_flows AS
SELECT
diff --git a/src/trace_processor/metrics/sql/chrome/scroll_jank_cause_queuing_delay.sql b/src/trace_processor/metrics/sql/chrome/scroll_jank_cause_queuing_delay.sql
index 1e2ecd2..b683959 100644
--- a/src/trace_processor/metrics/sql/chrome/scroll_jank_cause_queuing_delay.sql
+++ b/src/trace_processor/metrics/sql/chrome/scroll_jank_cause_queuing_delay.sql
@@ -322,127 +322,122 @@
GROUP BY 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20
ORDER BY descendant_cpu_percentage DESC;
-SELECT CREATE_FUNCTION(
- -- Function prototype: takes a '-' separated list of slice names (formed by
- -- the GROUP_CONCAT above) and returns the first slice if any or NULL
- -- otherwise.
- 'GetFirstSliceNameOrNull(name STRING)',
- -- Returns the first slice name or NULL
- 'STRING',
- -- Preforms the actual string modification, takes the either the whole string
- -- if there is no '-' or up to the first '-'. SUBSTR returns NULL if $name is
- -- NULL.
- 'SELECT SUBSTR($name, 0,
- CASE WHEN INSTR($name, "-") = 0 THEN
- LENGTH($name)+1 ELSE
- INSTR($name, "-")
- END)'
-);
+-- Function prototype: takes a - separated list of slice names (formed by
+-- the GROUP_CONCAT above) and returns the first slice if any or NULL
+-- otherwise.
+CREATE PERFETTO FUNCTION GetFirstSliceNameOrNull(name STRING)
+-- Returns the first slice name or NULL
+RETURNS STRING AS
+-- Performs the actual string modification, takes the either the whole string
+-- if there is no - or up to the first '-'. SUBSTR returns NULL if $name is
+-- NULL.
+SELECT SUBSTR($name, 0,
+ CASE WHEN INSTR($name, "-") = 0 THEN
+ LENGTH($name)+1 ELSE
+ INSTR($name, "-")
+ END);
-SELECT CREATE_FUNCTION(
- -- Function prototype: takes a '-' separated list of slice names (formed by
- -- the GROUP_CONCAT above) and checks for certain important view names and
- -- falls back on GetFirstSliceNameOrNull if it can't find one.
- 'GetJavaSliceSummaryOrNull(name STRING)',
- -- Returns the summary of the provided list of java slice names.
- 'STRING',
- -- Performs a bunch of GLOB matches in an order, now there could be multiple
- -- matches (both Toolbar & TabList could be true) so the order matters in
- -- tagging since we don't support multiple tagging of values. Ideally we would
- -- determine which one was the longest duration, but this should be sufficient
- -- for now.
- 'SELECT
- CASE WHEN $name GLOB "*ToolbarControlContainer*" THEN
- "ToolbarControlContainer"
- WHEN $name GLOB "*ToolbarProgressBar*" THEN
- "ToolbarProgressBar"
- WHEN $name GLOB "*TabGroupUiToolbarView*" THEN
- "TabGroupUiToolbarView"
- WHEN $name GLOB "*TabGridThumbnailView*" THEN
- "TabGridThumbnailView"
- WHEN $name GLOB "*TabGridDialogView*" THEN
- "TabGridDialogView"
- WHEN $name GLOB "*BottomContainer*" THEN
- "BottomContainer"
- WHEN $name GLOB "*FeedSwipeRefreshLayout*" THEN
- "FeedSwipeRefreshLayout"
- WHEN $name GLOB "*AutocompleteEditText*" THEN
- "AutocompleteEditText"
- WHEN $name GLOB "*HomeButton*" THEN
- "HomeButton"
- WHEN $name GLOB "*ToggleTabStackButton*" THEN
- "ToggleTabStackButton"
- WHEN $name GLOB "*ListMenuButton*" THEN
- "ListMenuButton"
- WHEN $name GLOB "*ScrimView*" THEN
- "ScrimView"
- WHEN $name GLOB "*ChromeImageView*" THEN
- "ChromeImageView"
- WHEN $name GLOB "*AppCompatImageView*" THEN
- "AppCompatImageView"
- WHEN $name GLOB "*ChromeImageButton*" THEN
- "ChromeImageButton"
- WHEN $name GLOB "*AppCompatImageButton*" THEN
- "AppCompatImageButton"
- WHEN $name GLOB "*TabListRecyclerView*" THEN
- "TabListRecyclerView"
- ELSE
- GetFirstSliceNameOrNull($name)
- END'
-);
+-- Function prototype: takes a - separated list of slice names (formed by
+-- the GROUP_CONCAT above) and checks for certain important view names and
+-- falls back on GetFirstSliceNameOrNull if it can't find one.
+CREATE PERFETTO FUNCTION GetJavaSliceSummaryOrNull(name STRING)
+-- Returns the summary of the provided list of java slice names.
+RETURNS STRING AS
+-- Performs a bunch of GLOB matches in an order, now there could be multiple
+-- matches (both Toolbar & TabList could be true) so the order matters in
+-- tagging since we dont support multiple tagging of values. Ideally we would
+-- determine which one was the longest duration, but this should be sufficient
+-- for now.
+SELECT
+ CASE WHEN $name GLOB "*ToolbarControlContainer*" THEN
+ "ToolbarControlContainer"
+ WHEN $name GLOB "*ToolbarProgressBar*" THEN
+ "ToolbarProgressBar"
+ WHEN $name GLOB "*TabGroupUiToolbarView*" THEN
+ "TabGroupUiToolbarView"
+ WHEN $name GLOB "*TabGridThumbnailView*" THEN
+ "TabGridThumbnailView"
+ WHEN $name GLOB "*TabGridDialogView*" THEN
+ "TabGridDialogView"
+ WHEN $name GLOB "*BottomContainer*" THEN
+ "BottomContainer"
+ WHEN $name GLOB "*FeedSwipeRefreshLayout*" THEN
+ "FeedSwipeRefreshLayout"
+ WHEN $name GLOB "*AutocompleteEditText*" THEN
+ "AutocompleteEditText"
+ WHEN $name GLOB "*HomeButton*" THEN
+ "HomeButton"
+ WHEN $name GLOB "*ToggleTabStackButton*" THEN
+ "ToggleTabStackButton"
+ WHEN $name GLOB "*ListMenuButton*" THEN
+ "ListMenuButton"
+ WHEN $name GLOB "*ScrimView*" THEN
+ "ScrimView"
+ WHEN $name GLOB "*ChromeImageView*" THEN
+ "ChromeImageView"
+ WHEN $name GLOB "*AppCompatImageView*" THEN
+ "AppCompatImageView"
+ WHEN $name GLOB "*ChromeImageButton*" THEN
+ "ChromeImageButton"
+ WHEN $name GLOB "*AppCompatImageButton*" THEN
+ "AppCompatImageButton"
+ WHEN $name GLOB "*TabListRecyclerView*" THEN
+ "TabListRecyclerView"
+ ELSE
+ GetFirstSliceNameOrNull($name)
+ END;
-SELECT CREATE_FUNCTION(
- -- Function prototype: takes slice name, category and descendant_name and
- -- determines if this event should be classified as unknown or not.
- 'UnknownEventOrEmptyString(name STRING, cat STRING, has_descendant STRING)',
- -- Returns either "-UnknownEvent" or "".
- 'STRING',
- -- If our current event has a posted from we consider it already categorized
- -- even if we don't have events underneath it. If its java often we won't have
- -- sub events, and finally if its a single event we just use its name there
- -- isn't anything under to use so just leave it at that.
- 'SELECT
- CASE WHEN
- $name = "ThreadControllerImpl::RunTask" OR
- $cat = "Java" OR
- $has_descendant IS NULL THEN
- "" ELSE
- "-UnknownEvent"
- END'
-);
+-- Function prototype: takes slice name, category and descendant_name and
+-- determines if this event should be classified as unknown or not.
+--
+-- Returns either "-UnknownEvent" or "".
+CREATE PERFETTO FUNCTION UnknownEventOrEmptyString(name STRING,
+ cat STRING,
+ has_descendant STRING)
+RETURNS STRING AS
+-- If our current event has a posted from we consider it already categorized
+-- even if we dont have events underneath it. If its java often we wont have
+-- sub events, and finally if its a single event we just use its name there
+-- isn't anything under to use so just leave it at that.
+SELECT
+ CASE WHEN
+ $name = "ThreadControllerImpl::RunTask" OR
+ $cat = "Java" OR
+ $has_descendant IS NULL THEN
+ "" ELSE
+ "-UnknownEvent"
+ END;
-SELECT CREATE_FUNCTION(
- -- Function prototype: Takes a slice name, function, and file, and determines
- -- if we should use the slice name, or if its a RunTask event uses the
- -- function & file name, however if the RunTask posted from is one of the
- -- simple_watcher paths we collapse them for attributation.
- 'TopLevelName(name STRING, function STRING, file STRING)',
- 'STRING',
- -- The difference for the mojom functions are:
- -- 1) PostDispatchNextMessageFromPipe:
- -- We knew that there is a message in the pipe, didn't try to set up a
- -- SimpleWatcher to monitor when a new one arrives.
- -- 2) ArmOrNotify:
- -- We tried to set up SimpleWatcher, but the setup failed as the
- -- message arrived as we were setting this up, so we posted a task
- -- instead.
- -- 3) Notify:
- -- SimpleWatcher was set up and after a period of monitoring detected
- -- a new message.
- -- For our jank use case this distinction isn't very useful so we group them
- -- together.
- 'SELECT
- CASE WHEN $name = "ThreadControllerImpl::RunTask" THEN
- CASE WHEN $function IN
- ("PostDispatchNextMessageFromPipe", "ArmOrNotify", "Notify") THEN
- "posted-from-mojo-pipe"
- ELSE
- "posted-from-" || $function || "()-in-" || $file
- END
- ELSE
- $name
- END'
-);
+-- Function prototype: Takes a slice name, function, and file, and determines
+-- if we should use the slice name, or if its a RunTask event uses the
+-- function & file name, however if the RunTask posted from is one of the
+-- simple_watcher paths we collapse them for attributation.
+CREATE PERFETTO FUNCTION TopLevelName(name STRING, function STRING, file STRING)
+RETURNS STRING AS
+-- The difference for the mojom functions are:
+-- 1) PostDispatchNextMessageFromPipe:
+-- We knew that there is a message in the pipe, didnt try to set up a
+-- SimpleWatcher to monitor when a new one arrives.
+-- 2) ArmOrNotify:
+-- We tried to set up SimpleWatcher, but the setup failed as the
+-- message arrived as we were setting this up, so we posted a task
+-- instead.
+-- 3) Notify:
+-- SimpleWatcher was set up and after a period of monitoring detected
+-- a new message.
+-- For our jank use case this distinction isnt very useful so we group them
+-- together.
+SELECT
+ CASE WHEN $name = "ThreadControllerImpl::RunTask" THEN
+ CASE WHEN $function IN
+ ("PostDispatchNextMessageFromPipe", "ArmOrNotify", "Notify") THEN
+ "posted-from-mojo-pipe"
+ ELSE
+ "posted-from-" || $function || "()-in-" || $file
+ END
+ ELSE
+ $name
+ END;
-- Create a common name for each "cause" based on the slice stack we found.
DROP VIEW IF EXISTS scroll_jank_cause_queuing_delay_temp;
diff --git a/src/trace_processor/metrics/sql/chrome/scroll_jank_v3.sql b/src/trace_processor/metrics/sql/chrome/scroll_jank_v3.sql
index a126354..72211a3 100644
--- a/src/trace_processor/metrics/sql/chrome/scroll_jank_v3.sql
+++ b/src/trace_processor/metrics/sql/chrome/scroll_jank_v3.sql
@@ -29,17 +29,40 @@
-- respective scroll ids and start/end timestamps.
DROP VIEW IF EXISTS chrome_presented_gesture_scrolls;
CREATE VIEW chrome_presented_gesture_scrolls AS
+WITH
+ chrome_gesture_scrolls AS (
+ SELECT
+ ts AS start_ts,
+ ts + dur AS end_ts,
+ id,
+ -- TODO(b/250089570) Add trace_id to EventLatency and update this script to use it.
+ EXTRACT_ARG(arg_set_id, 'chrome_latency_info.trace_id') AS scroll_update_id,
+ EXTRACT_ARG(arg_set_id, 'chrome_latency_info.gesture_scroll_id') AS scroll_id,
+ EXTRACT_ARG(arg_set_id, 'chrome_latency_info.is_coalesced') AS is_coalesced
+ FROM slice
+ WHERE name = "InputLatency::GestureScrollUpdate"
+ AND dur != -1),
+ updates_with_coalesce_info AS (
+ SELECT
+ chrome_updates.*,
+ (
+ SELECT
+ MAX(id)
+ FROM chrome_gesture_scrolls updates
+ WHERE updates.is_coalesced = false
+ AND updates.start_ts <= chrome_updates.start_ts) AS coalesced_inside_id
+ FROM
+ chrome_gesture_scrolls chrome_updates)
SELECT
- ts AS start_ts,
- ts + dur AS end_ts,
- id,
- -- TODO(b/250089570) Add trace_id to EventLatency and update this script to use it.
- EXTRACT_ARG(arg_set_id, 'chrome_latency_info.trace_id') AS scroll_update_id,
- EXTRACT_ARG(arg_set_id, 'chrome_latency_info.gesture_scroll_id') AS scroll_id
-FROM slice
-WHERE name = "InputLatency::GestureScrollUpdate"
- AND EXTRACT_ARG(arg_set_id, 'chrome_latency_info.is_coalesced') = FALSE
- AND dur != -1;
+ MIN(id) AS id,
+ MIN(start_ts) AS start_ts,
+ MAX(end_ts) AS end_ts,
+ MAX(start_ts) AS last_coalesced_input_ts,
+ scroll_update_id,
+ MIN(scroll_id) AS scroll_id
+FROM updates_with_coalesce_info
+GROUP BY coalesced_inside_id;
+
-- Associate every trace_id with it's perceived delta_y on the screen after
@@ -82,6 +105,7 @@
SELECT
frames.id,
frames.start_ts,
+ frames.last_coalesced_input_ts,
frames.scroll_id,
frames.scroll_update_id,
events.event_latency_id,
@@ -99,6 +123,7 @@
frames.start_ts,
frames.scroll_id,
frames.scroll_update_id,
+ frames.last_coalesced_input_ts,
deltas.delta_y,
frames.event_latency_id,
frames.dur,
@@ -125,7 +150,7 @@
CREATE VIEW chrome_merged_frame_view_with_jank AS
SELECT
id,
- MAX(start_ts) AS max_start_ts,
+ MAX(last_coalesced_input_ts) AS max_start_ts,
MIN(start_ts) AS min_start_ts,
scroll_id,
scroll_update_id,
diff --git a/src/trace_processor/metrics/sql/chrome/vsync_intervals.sql b/src/trace_processor/metrics/sql/chrome/vsync_intervals.sql
index 3434056..c77e387 100644
--- a/src/trace_processor/metrics/sql/chrome/vsync_intervals.sql
+++ b/src/trace_processor/metrics/sql/chrome/vsync_intervals.sql
@@ -15,28 +15,29 @@
WHERE name = "VSync"
ORDER BY track_id, ts;
-SELECT CREATE_FUNCTION(
- -- Function: compute the average Vysnc interval of the
- -- gesture (hopefully this would be either 60 FPS for the whole gesture or 90
- -- FPS but that isn't always the case) on the given time segment.
- -- If the trace doesn't contain the VSync TraceEvent we just fall back on
- -- assuming its 60 FPS (this is the 1.6e+7 in the COALESCE which
- -- corresponds to 16 ms or 60 FPS).
- --
- -- begin_ts: segment start time
- -- end_ts: segment end time
- 'CalculateAvgVsyncInterval(begin_ts LONG, end_ts LONG)',
- -- Returns: the average Vysnc interval on this time segment
- -- or 1.6e+7, if trace doesn't contain the VSync TraceEvent.
- 'FLOAT',
- 'SELECT
- COALESCE((
- SELECT
- CAST(AVG(time_to_next_vsync) AS FLOAT)
- FROM vsync_intervals in_query
- WHERE
- time_to_next_vsync IS NOT NULL AND
- in_query.ts > $begin_ts AND
- in_query.ts < $end_ts
- ), 1e+9 / 60)'
-);
+-- Function: compute the average Vysnc interval of the
+-- gesture (hopefully this would be either 60 FPS for the whole gesture or 90
+-- FPS but that isnt always the case) on the given time segment.
+-- If the trace doesnt contain the VSync TraceEvent we just fall back on
+-- assuming its 60 FPS (this is the 1.6e+7 in the COALESCE which
+-- corresponds to 16 ms or 60 FPS).
+--
+-- begin_ts: segment start time
+-- end_ts: segment end time
+CREATE PERFETTO FUNCTION CalculateAvgVsyncInterval(
+ begin_ts LONG,
+ end_ts LONG
+)
+-- Returns: the average Vysnc interval on this time segment
+-- or 1.6e+7, if trace doesnt contain the VSync TraceEvent.
+RETURNS FLOAT AS
+SELECT
+ COALESCE((
+ SELECT
+ CAST(AVG(time_to_next_vsync) AS FLOAT)
+ FROM vsync_intervals in_query
+ WHERE
+ time_to_next_vsync IS NOT NULL AND
+ in_query.ts > $begin_ts AND
+ in_query.ts < $end_ts
+ ), 1e+9 / 60);
diff --git a/src/trace_processor/perfetto_sql/engine/perfetto_sql_parser.cc b/src/trace_processor/perfetto_sql/engine/perfetto_sql_parser.cc
index 0f51ab1..295a385 100644
--- a/src/trace_processor/perfetto_sql/engine/perfetto_sql_parser.cc
+++ b/src/trace_processor/perfetto_sql/engine/perfetto_sql_parser.cc
@@ -166,6 +166,14 @@
if (tok.token_type == SqliteTokenType::TK_RP) {
break;
}
+ if (tok.token_type == SqliteTokenType::TK_GENERIC_KEYWORD) {
+ base::StackString<1024> err(
+ "Malformed function prototype: %.*s is a SQL keyword so cannot "
+ "appear in a function prototype",
+ static_cast<int>(tok.str.size()), tok.str.data());
+ return ErrorAtToken(tok, err.c_str());
+ }
+
// TODO(lalitm): add a link to create function documentation.
return ErrorAtToken(
tok, "Malformed function prototype: ')', ',', name or type expected");
diff --git a/src/trace_processor/perfetto_sql/stdlib/android/battery_stats.sql b/src/trace_processor/perfetto_sql/stdlib/android/battery_stats.sql
index 30cea54..46ba36d 100644
--- a/src/trace_processor/perfetto_sql/stdlib/android/battery_stats.sql
+++ b/src/trace_processor/perfetto_sql/stdlib/android/battery_stats.sql
@@ -20,104 +20,99 @@
-- @arg track STRING The counter track name (e.g. 'battery_stats.audio').
-- @arg value FLOAT The counter value.
-- @ret STRING The human-readable name for the counter value.
-SELECT CREATE_FUNCTION(
- 'ANDROID_BATTERY_STATS_COUNTER_TO_STRING(track STRING, value FLOAT)',
- 'STRING',
- '
- SELECT
- CASE
- WHEN ($track = "battery_stats.wifi_scan" OR
- $track = "battery_stats.wifi_radio" OR
- $track = "battery_stats.mobile_radio" OR
- $track = "battery_stats.audio" OR
- $track = "battery_stats.video" OR
- $track = "battery_stats.camera" OR
- $track = "battery_stats.power_save" OR
- $track = "battery_stats.phone_in_call")
- THEN
- CASE $value
- WHEN 0 THEN "inactive"
- WHEN 1 THEN "active"
- ELSE "unknown"
- END
- WHEN $track = "battery_stats.wifi"
- THEN
- CASE $value
- WHEN 0 THEN "off"
- WHEN 1 THEN "on"
- ELSE "unknown"
- END
- WHEN $track = "battery_stats.phone_state"
- THEN
- CASE $value
- WHEN 0 THEN "in"
- WHEN 1 THEN "out"
- WHEN 2 THEN "emergency"
- WHEN 3 THEN "off"
- ELSE "unknown"
- END
- WHEN ($track = "battery_stats.phone_signal_strength" OR
- $track = "battery_stats.wifi_signal_strength")
- THEN
- CASE $value
- WHEN 0 THEN "none"
- WHEN 1 THEN "poor"
- WHEN 2 THEN "moderate"
- WHEN 3 THEN "good"
- WHEN 4 THEN "great"
- ELSE "unknown"
- END
- WHEN $track = "battery_stats.wifi_suppl"
- THEN
- CASE $value
- WHEN 0 THEN "invalid"
- WHEN 1 THEN "disconnected"
- WHEN 2 THEN "disabled"
- WHEN 3 THEN "inactive"
- WHEN 4 THEN "scanning"
- WHEN 5 THEN "authenticating"
- WHEN 6 THEN "associating"
- WHEN 7 THEN "associated"
- WHEN 8 THEN "4-way-handshake"
- WHEN 9 THEN "group-handshake"
- WHEN 10 THEN "completed"
- WHEN 11 THEN "dormant"
- WHEN 12 THEN "uninitialized"
- ELSE "unknown"
- END
- WHEN $track = "battery_stats.data_conn"
- THEN
- CASE $value
- WHEN 0 THEN "Out of service"
- WHEN 1 THEN "2.5G (GPRS)"
- WHEN 2 THEN "2.7G (EDGE)"
- WHEN 3 THEN "3G (UMTS)"
- WHEN 4 THEN "3G (CDMA)"
- WHEN 5 THEN "3G (EVDO Rel 0)"
- WHEN 6 THEN "3G (EVDO Rev A)"
- WHEN 7 THEN "3G (LXRTT)"
- WHEN 8 THEN "3.5G (HSDPA)"
- WHEN 9 THEN "3.5G (HSUPA)"
- WHEN 10 THEN "3.5G (HSPA)"
- WHEN 11 THEN "2G (IDEN)"
- WHEN 12 THEN "3G (EVDO Rev B)"
- WHEN 13 THEN "4G (LTE)"
- WHEN 14 THEN "3.5G (eHRPD)"
- WHEN 15 THEN "3.7G (HSPA+)"
- WHEN 16 THEN "2G (GSM)"
- WHEN 17 THEN "3G (TD SCDMA)"
- WHEN 18 THEN "Wifi calling (IWLAN)"
- WHEN 19 THEN "4.5G (LTE CA)"
- WHEN 20 THEN "5G (NR)"
- WHEN 21 THEN "Emergency calls only"
- WHEN 22 THEN "Other"
- ELSE "unknown"
- END
- ELSE CAST($value AS text)
- END
- '
-);
-
+CREATE PERFETTO FUNCTION ANDROID_BATTERY_STATS_COUNTER_TO_STRING(track STRING, value FLOAT)
+RETURNS STRING AS
+SELECT
+ CASE
+ WHEN ($track = "battery_stats.wifi_scan" OR
+ $track = "battery_stats.wifi_radio" OR
+ $track = "battery_stats.mobile_radio" OR
+ $track = "battery_stats.audio" OR
+ $track = "battery_stats.video" OR
+ $track = "battery_stats.camera" OR
+ $track = "battery_stats.power_save" OR
+ $track = "battery_stats.phone_in_call")
+ THEN
+ CASE $value
+ WHEN 0 THEN "inactive"
+ WHEN 1 THEN "active"
+ ELSE "unknown"
+ END
+ WHEN $track = "battery_stats.wifi"
+ THEN
+ CASE $value
+ WHEN 0 THEN "off"
+ WHEN 1 THEN "on"
+ ELSE "unknown"
+ END
+ WHEN $track = "battery_stats.phone_state"
+ THEN
+ CASE $value
+ WHEN 0 THEN "in"
+ WHEN 1 THEN "out"
+ WHEN 2 THEN "emergency"
+ WHEN 3 THEN "off"
+ ELSE "unknown"
+ END
+ WHEN ($track = "battery_stats.phone_signal_strength" OR
+ $track = "battery_stats.wifi_signal_strength")
+ THEN
+ CASE $value
+ WHEN 0 THEN "0/4"
+ WHEN 1 THEN "1/4"
+ WHEN 2 THEN "2/4"
+ WHEN 3 THEN "3/4"
+ WHEN 4 THEN "4/4"
+ ELSE "unknown"
+ END
+ WHEN $track = "battery_stats.wifi_suppl"
+ THEN
+ CASE $value
+ WHEN 0 THEN "invalid"
+ WHEN 1 THEN "disconnected"
+ WHEN 2 THEN "disabled"
+ WHEN 3 THEN "inactive"
+ WHEN 4 THEN "scanning"
+ WHEN 5 THEN "authenticating"
+ WHEN 6 THEN "associating"
+ WHEN 7 THEN "associated"
+ WHEN 8 THEN "4-way-handshake"
+ WHEN 9 THEN "group-handshake"
+ WHEN 10 THEN "completed"
+ WHEN 11 THEN "dormant"
+ WHEN 12 THEN "uninitialized"
+ ELSE "unknown"
+ END
+ WHEN $track = "battery_stats.data_conn"
+ THEN
+ CASE $value
+ WHEN 0 THEN "Out of service"
+ WHEN 1 THEN "2.5G (GPRS)"
+ WHEN 2 THEN "2.7G (EDGE)"
+ WHEN 3 THEN "3G (UMTS)"
+ WHEN 4 THEN "3G (CDMA)"
+ WHEN 5 THEN "3G (EVDO Rel 0)"
+ WHEN 6 THEN "3G (EVDO Rev A)"
+ WHEN 7 THEN "3G (LXRTT)"
+ WHEN 8 THEN "3.5G (HSDPA)"
+ WHEN 9 THEN "3.5G (HSUPA)"
+ WHEN 10 THEN "3.5G (HSPA)"
+ WHEN 11 THEN "2G (IDEN)"
+ WHEN 12 THEN "3G (EVDO Rev B)"
+ WHEN 13 THEN "4G (LTE)"
+ WHEN 14 THEN "3.5G (eHRPD)"
+ WHEN 15 THEN "3.7G (HSPA+)"
+ WHEN 16 THEN "2G (GSM)"
+ WHEN 17 THEN "3G (TD SCDMA)"
+ WHEN 18 THEN "Wifi calling (IWLAN)"
+ WHEN 19 THEN "4.5G (LTE CA)"
+ WHEN 20 THEN "5G (NR)"
+ WHEN 21 THEN "Emergency calls only"
+ WHEN 22 THEN "Other"
+ ELSE "unknown"
+ END
+ ELSE CAST($value AS text)
+ END;
-- View of human readable battery stats counter-based states. These are recorded
-- by BatteryStats as a bitmap where each 'category' has a unique value at any
diff --git a/src/trace_processor/perfetto_sql/stdlib/android/monitor_contention.sql b/src/trace_processor/perfetto_sql/stdlib/android/monitor_contention.sql
index 9fae0c7..284d391 100644
--- a/src/trace_processor/perfetto_sql/stdlib/android/monitor_contention.sql
+++ b/src/trace_processor/perfetto_sql/stdlib/android/monitor_contention.sql
@@ -18,42 +18,33 @@
--
-- @arg slice_name STRING Name of slice
-- @ret STRING Blocking thread
-SELECT
- CREATE_FUNCTION(
- 'ANDROID_EXTRACT_ANDROID_MONITOR_CONTENTION_BLOCKING_THREAD(slice_name STRING)',
- 'STRING',
- '
- SELECT STR_SPLIT(STR_SPLIT($slice_name, "with owner ", 1), " (", 0)
- '
-);
+CREATE PERFETTO FUNCTION ANDROID_EXTRACT_ANDROID_MONITOR_CONTENTION_BLOCKING_THREAD(
+ slice_name STRING
+)
+RETURNS STRING AS
+SELECT STR_SPLIT(STR_SPLIT($slice_name, "with owner ", 1), " (", 0);
-- Extracts the blocking thread tid from a slice name
--
-- @arg slice_name STRING Name of slice
-- @ret INT Blocking thread tid
-SELECT
- CREATE_FUNCTION(
- 'ANDROID_EXTRACT_ANDROID_MONITOR_CONTENTION_BLOCKING_TID(slice_name STRING)',
- 'INT',
- '
- SELECT CAST(STR_SPLIT(STR_SPLIT($slice_name, " (", 1), ")", 0) AS INT)
- '
-);
+CREATE PERFETTO FUNCTION ANDROID_EXTRACT_ANDROID_MONITOR_CONTENTION_BLOCKING_TID(
+ slice_name STRING
+)
+RETURNS INT AS
+SELECT CAST(STR_SPLIT(STR_SPLIT($slice_name, " (", 1), ")", 0) AS INT);
-- Extracts the blocking method from a slice name
--
-- @arg slice_name STRING Name of slice
-- @ret STRING Blocking thread
-SELECT
- CREATE_FUNCTION(
- 'ANDROID_EXTRACT_ANDROID_MONITOR_CONTENTION_BLOCKING_METHOD(slice_name STRING)',
- 'STRING',
- '
- SELECT STR_SPLIT(STR_SPLIT($slice_name, ") at ", 1), "(", 0)
+CREATE PERFETTO FUNCTION ANDROID_EXTRACT_ANDROID_MONITOR_CONTENTION_BLOCKING_METHOD(
+ slice_name STRING
+)
+RETURNS STRING AS
+SELECT STR_SPLIT(STR_SPLIT($slice_name, ") at ", 1), "(", 0)
|| "("
- || STR_SPLIT(STR_SPLIT($slice_name, ") at ", 1), "(", 1)
- '
-);
+ || STR_SPLIT(STR_SPLIT($slice_name, ") at ", 1), "(", 1);
-- Extracts a shortened form of the blocking method name from a slice name.
-- The shortened form discards the parameter and return
@@ -61,30 +52,24 @@
--
-- @arg slice_name STRING Name of slice
-- @ret STRING Blocking thread
+CREATE PERFETTO FUNCTION ANDROID_EXTRACT_ANDROID_MONITOR_CONTENTION_SHORT_BLOCKING_METHOD(
+ slice_name STRING
+)
+RETURNS STRING AS
SELECT
- CREATE_FUNCTION(
- 'ANDROID_EXTRACT_ANDROID_MONITOR_CONTENTION_SHORT_BLOCKING_METHOD(slice_name STRING)',
- 'STRING',
- '
- SELECT
- STR_SPLIT(STR_SPLIT(ANDROID_EXTRACT_ANDROID_MONITOR_CONTENTION_BLOCKING_METHOD($slice_name), " ", 1), "(", 0)
- '
-);
+ STR_SPLIT(STR_SPLIT(ANDROID_EXTRACT_ANDROID_MONITOR_CONTENTION_BLOCKING_METHOD($slice_name), " ", 1), "(", 0);
-- Extracts the monitor contention blocked method from a slice name
--
-- @arg slice_name STRING Name of slice
-- @ret STRING Blocking thread
-SELECT
- CREATE_FUNCTION(
- 'ANDROID_EXTRACT_ANDROID_MONITOR_CONTENTION_BLOCKED_METHOD(slice_name STRING)',
- 'STRING',
- '
- SELECT STR_SPLIT(STR_SPLIT($slice_name, "blocking from ", 1), "(", 0)
+CREATE PERFETTO FUNCTION ANDROID_EXTRACT_ANDROID_MONITOR_CONTENTION_BLOCKED_METHOD(
+ slice_name STRING
+)
+RETURNS STRING AS
+SELECT STR_SPLIT(STR_SPLIT($slice_name, "blocking from ", 1), "(", 0)
|| "("
- || STR_SPLIT(STR_SPLIT($slice_name, "blocking from ", 1), "(", 1)
- '
-);
+ || STR_SPLIT(STR_SPLIT($slice_name, "blocking from ", 1), "(", 1);
-- Extracts a shortened form of the monitor contention blocked method name
-- from a slice name. The shortened form discards the parameter and return
@@ -92,57 +77,44 @@
--
-- @arg slice_name STRING Name of slice
-- @ret STRING Blocking thread
+CREATE PERFETTO FUNCTION ANDROID_EXTRACT_ANDROID_MONITOR_CONTENTION_SHORT_BLOCKED_METHOD(
+ slice_name STRING
+)
+RETURNS STRING AS
SELECT
- CREATE_FUNCTION(
- 'ANDROID_EXTRACT_ANDROID_MONITOR_CONTENTION_SHORT_BLOCKED_METHOD(slice_name STRING)',
- 'STRING',
- '
- SELECT
- STR_SPLIT(STR_SPLIT(ANDROID_EXTRACT_ANDROID_MONITOR_CONTENTION_BLOCKED_METHOD($slice_name), " ", 1), "(", 0)
- '
-);
+ STR_SPLIT(STR_SPLIT(ANDROID_EXTRACT_ANDROID_MONITOR_CONTENTION_BLOCKED_METHOD($slice_name), " ", 1), "(", 0);
-- Extracts the number of waiters on the monitor from a slice name
--
-- @arg slice_name STRING Name of slice
-- @ret INT Count of waiters on the lock
-SELECT
- CREATE_FUNCTION(
- 'ANDROID_EXTRACT_ANDROID_MONITOR_CONTENTION_WAITER_COUNT(slice_name STRING)',
- 'INT',
- '
- SELECT CAST(STR_SPLIT(STR_SPLIT($slice_name, "waiters=", 1), " ", 0) AS INT)
- '
-);
+CREATE PERFETTO FUNCTION ANDROID_EXTRACT_ANDROID_MONITOR_CONTENTION_WAITER_COUNT(
+ slice_name STRING
+)
+RETURNS INT AS
+SELECT CAST(STR_SPLIT(STR_SPLIT($slice_name, "waiters=", 1), " ", 0) AS INT);
-- Extracts the monitor contention blocking source location from a slice name
--
-- @arg slice_name STRING Name of slice
-- @ret STRING Blocking thread
-SELECT
- CREATE_FUNCTION(
- 'ANDROID_EXTRACT_ANDROID_MONITOR_CONTENTION_BLOCKING_SRC(slice_name STRING)',
- 'STRING',
- '
- SELECT STR_SPLIT(STR_SPLIT($slice_name, ")(", 1), ")", 0)
- '
-);
+CREATE PERFETTO FUNCTION ANDROID_EXTRACT_ANDROID_MONITOR_CONTENTION_BLOCKING_SRC(
+ slice_name STRING
+)
+RETURNS STRING AS
+SELECT STR_SPLIT(STR_SPLIT($slice_name, ")(", 1), ")", 0);
-- Extracts the monitor contention blocked source location from a slice name
--
-- @arg slice_name STRING Name of slice
-- @ret STRING Blocking thread
-SELECT
- CREATE_FUNCTION(
- 'ANDROID_EXTRACT_ANDROID_MONITOR_CONTENTION_BLOCKED_SRC(slice_name STRING)',
- 'STRING',
- '
- SELECT STR_SPLIT(STR_SPLIT($slice_name, ")(", 2), ")", 0)
- '
-);
+CREATE PERFETTO FUNCTION ANDROID_EXTRACT_ANDROID_MONITOR_CONTENTION_BLOCKED_SRC(
+ slice_name STRING
+)
+RETURNS STRING AS
+SELECT STR_SPLIT(STR_SPLIT($slice_name, ")(", 2), ")", 0);
-CREATE TABLE internal_broken_android_monitor_contention
-AS
+CREATE TABLE internal_broken_android_monitor_contention AS
SELECT ancestor.parent_id AS id FROM slice
JOIN slice ancestor ON ancestor.id = slice.parent_id
WHERE ancestor.name GLOB 'Lock contention on a monitor lock*'
@@ -247,6 +219,9 @@
LEFT JOIN android_monitor_contention parent ON child.blocked_utid = parent.blocking_utid
AND parent.ts BETWEEN child.ts AND child.ts + child.dur;
+CREATE INDEX internal_android_monitor_contention_chain_idx
+ ON android_monitor_contention_chain (blocking_method, blocking_utid, ts);
+
-- First blocked node on a lock, i.e nodes with |waiter_count| = 0. The |dur| here is adjusted
-- to only account for the time between the first thread waiting and the first thread to acquire
-- the lock. That way, the thread state span joins below only compute the thread states where
@@ -256,7 +231,7 @@
AS
SELECT start.id, start.blocking_utid, start.ts, MIN(end.ts + end.dur) - start.ts AS dur
FROM android_monitor_contention_chain start
-JOIN android_monitor_contention_chain END
+JOIN android_monitor_contention_chain end
ON
start.blocking_utid = end.blocking_utid
AND start.blocking_method = end.blocking_method
diff --git a/src/trace_processor/perfetto_sql/stdlib/android/slices.sql b/src/trace_processor/perfetto_sql/stdlib/android/slices.sql
index 7cd80e7..f0a23bf 100644
--- a/src/trace_processor/perfetto_sql/stdlib/android/slices.sql
+++ b/src/trace_processor/perfetto_sql/stdlib/android/slices.sql
@@ -23,23 +23,20 @@
--
-- @arg name STRING Raw name of the slice
-- @ret STRING Simplified name.
-SELECT CREATE_FUNCTION(
- 'ANDROID_STANDARDIZE_SLICE_NAME(name STRING)',
- 'STRING',
- '
- SELECT
- CASE
- WHEN $name GLOB "Lock contention on*" THEN "Lock contention on <...>"
- WHEN $name GLOB "monitor contention with*" THEN "monitor contention with <...>"
- WHEN $name GLOB "SuspendThreadByThreadId*" THEN "SuspendThreadByThreadId <...>"
- WHEN $name GLOB "LoadApkAssetsFd*" THEN "LoadApkAssetsFd <...>"
- WHEN $name GLOB "relayoutWindow*" THEN "relayoutWindow <...>"
- WHEN $name GLOB "*CancellableContinuationImpl*" THEN "CoroutineContinuation"
- WHEN $name GLOB "Choreographer#doFrame*" THEN "Choreographer#doFrame"
- WHEN $name GLOB "DrawFrames*" THEN "DrawFrames"
- WHEN $name GLOB "/data/app*.apk" THEN "APK load"
- WHEN $name GLOB "OpenDexFilesFromOat*" THEN "OpenDexFilesFromOat"
- WHEN $name GLOB "Open oat file*" THEN "Open oat file"
- ELSE $name
- END
-');
\ No newline at end of file
+CREATE PERFETTO FUNCTION ANDROID_STANDARDIZE_SLICE_NAME(name STRING)
+RETURNS STRING AS
+SELECT
+ CASE
+ WHEN $name GLOB "Lock contention on*" THEN "Lock contention on <...>"
+ WHEN $name GLOB "monitor contention with*" THEN "monitor contention with <...>"
+ WHEN $name GLOB "SuspendThreadByThreadId*" THEN "SuspendThreadByThreadId <...>"
+ WHEN $name GLOB "LoadApkAssetsFd*" THEN "LoadApkAssetsFd <...>"
+ WHEN $name GLOB "relayoutWindow*" THEN "relayoutWindow <...>"
+ WHEN $name GLOB "*CancellableContinuationImpl*" THEN "CoroutineContinuation"
+ WHEN $name GLOB "Choreographer#doFrame*" THEN "Choreographer#doFrame"
+ WHEN $name GLOB "DrawFrames*" THEN "DrawFrames"
+ WHEN $name GLOB "/data/app*.apk" THEN "APK load"
+ WHEN $name GLOB "OpenDexFilesFromOat*" THEN "OpenDexFilesFromOat"
+ WHEN $name GLOB "Open oat file*" THEN "Open oat file"
+ ELSE $name
+ END;
diff --git a/src/trace_processor/perfetto_sql/stdlib/android/startup/startups.sql b/src/trace_processor/perfetto_sql/stdlib/android/startup/startups.sql
index 644d122..73ed192 100644
--- a/src/trace_processor/perfetto_sql/stdlib/android/startup/startups.sql
+++ b/src/trace_processor/perfetto_sql/stdlib/android/startup/startups.sql
@@ -75,20 +75,19 @@
FROM slice
WHERE name IN ('bindApplication', 'activityStart', 'activityResume');
-SELECT CREATE_FUNCTION(
- 'INTERNAL_STARTUP_INDICATOR_SLICE_COUNT(start_ts LONG, end_ts LONG, utid INT, name STRING)',
- 'INT',
- '
- SELECT COUNT(1)
- FROM thread_track t
- JOIN internal_startup_indicator_slices s ON s.track_id = t.id
- WHERE
- t.utid = $utid AND
- s.ts >= $start_ts AND
- s.ts < $end_ts AND
- s.name = $name
- '
-);
+CREATE PERFETTO FUNCTION INTERNAL_STARTUP_INDICATOR_SLICE_COUNT(start_ts LONG,
+ end_ts LONG,
+ utid INT,
+ name STRING)
+RETURNS INT AS
+SELECT COUNT(1)
+FROM thread_track t
+JOIN internal_startup_indicator_slices s ON s.track_id = t.id
+WHERE
+ t.utid = $utid AND
+ s.ts >= $start_ts AND
+ s.ts < $end_ts AND
+ s.name = $name;
-- Maps a startup to the set of processes that handled the activity start.
--
@@ -250,15 +249,11 @@
-- @arg startup_id LONG Startup id.
-- @arg slice_name STRING Slice name.
-- @ret INT Sum of duration.
-SELECT CREATE_FUNCTION(
- 'ANDROID_SUM_DUR_FOR_STARTUP_AND_SLICE(startup_id LONG, slice_name STRING)',
- 'INT',
- '
- SELECT SUM(slice_dur)
- FROM android_thread_slices_for_all_startups
- WHERE startup_id = $startup_id AND slice_name GLOB $slice_name
- '
-);
+CREATE PERFETTO FUNCTION ANDROID_SUM_DUR_FOR_STARTUP_AND_SLICE(startup_id LONG, slice_name STRING)
+RETURNS INT AS
+SELECT SUM(slice_dur)
+FROM android_thread_slices_for_all_startups
+WHERE startup_id = $startup_id AND slice_name GLOB $slice_name;
-- Returns duration of startup for slice name on main thread.
--
@@ -267,12 +262,8 @@
-- @arg startup_id LONG Startup id.
-- @arg slice_name STRING Slice name.
-- @ret INT Sum of duration.
-SELECT CREATE_FUNCTION(
- 'ANDROID_SUM_DUR_ON_MAIN_THREAD_FOR_STARTUP_AND_SLICE(startup_id LONG, slice_name STRING)',
- 'INT',
- '
- SELECT SUM(slice_dur)
- FROM android_thread_slices_for_all_startups
- WHERE startup_id = $startup_id AND slice_name GLOB $slice_name AND is_main_thread
- '
-);
\ No newline at end of file
+CREATE PERFETTO FUNCTION ANDROID_SUM_DUR_ON_MAIN_THREAD_FOR_STARTUP_AND_SLICE(startup_id LONG, slice_name STRING)
+RETURNS INT AS
+SELECT SUM(slice_dur)
+FROM android_thread_slices_for_all_startups
+WHERE startup_id = $startup_id AND slice_name GLOB $slice_name AND is_main_thread;
diff --git a/src/trace_processor/perfetto_sql/stdlib/chrome/metadata.sql b/src/trace_processor/perfetto_sql/stdlib/chrome/metadata.sql
index a4c6376..f0090fd 100644
--- a/src/trace_processor/perfetto_sql/stdlib/chrome/metadata.sql
+++ b/src/trace_processor/perfetto_sql/stdlib/chrome/metadata.sql
@@ -15,12 +15,9 @@
-- Returns hardware class of the device, often use to find device brand
-- and model.
-- @ret STRING Hardware class name.
-SELECT CREATE_FUNCTION(
- 'CHROME_HARDWARE_CLASS()',
- 'STRING',
- 'SELECT
- str_value
- FROM metadata
- WHERE name = "cr-hardware-class"
- '
-);
\ No newline at end of file
+CREATE PERFETTO FUNCTION CHROME_HARDWARE_CLASS()
+RETURNS STRING AS
+SELECT
+ str_value
+ FROM metadata
+WHERE name = "cr-hardware-class";
\ No newline at end of file
diff --git a/src/trace_processor/perfetto_sql/stdlib/chrome/tasks.sql b/src/trace_processor/perfetto_sql/stdlib/chrome/tasks.sql
index 159d6be..272d6d7 100644
--- a/src/trace_processor/perfetto_sql/stdlib/chrome/tasks.sql
+++ b/src/trace_processor/perfetto_sql/stdlib/chrome/tasks.sql
@@ -20,80 +20,59 @@
-- argument of descendant ScopedSetIpcHash slice.
-- This is relevant only for the older Chrome traces, where mojo IPC
-- hash was reported in a separate ScopedSetIpcHash slice.
-SELECT CREATE_FUNCTION(
- 'INTERNAL_EXTRACT_MOJO_IPC_HASH(slice_id INT)',
- 'INT',
- '
- SELECT EXTRACT_ARG(arg_set_id, "chrome_mojo_event_info.ipc_hash")
- FROM descendant_slice($slice_id)
- WHERE name="ScopedSetIpcHash"
- ORDER BY id
- LIMIT 1
- '
-);
+CREATE PERFETTO FUNCTION INTERNAL_EXTRACT_MOJO_IPC_HASH(slice_id INT)
+RETURNS INT AS
+SELECT EXTRACT_ARG(arg_set_id, "chrome_mojo_event_info.ipc_hash")
+FROM descendant_slice($slice_id)
+WHERE name="ScopedSetIpcHash"
+ORDER BY id
+LIMIT 1;
-- Returns the frame type (main frame vs subframe) for key navigation tasks
-- which capture the associated RenderFrameHost in an argument.
-SELECT CREATE_FUNCTION(
- 'INTERNAL_EXTRACT_FRAME_TYPE(slice_id INT)',
- 'INT',
- '
- SELECT EXTRACT_ARG(arg_set_id, "render_frame_host.frame_type")
- FROM descendant_slice($slice_id)
- WHERE name IN ("RenderFrameHostImpl::BeginNavigation",
- "RenderFrameHostImpl::DidCommitProvisionalLoad",
- "RenderFrameHostImpl::DidCommitSameDocumentNavigation",
- "RenderFrameHostImpl::DidStopLoading")
- LIMIT 1
- '
-);
+CREATE PERFETTO FUNCTION INTERNAL_EXTRACT_FRAME_TYPE(slice_id INT)
+RETURNS INT AS
+SELECT EXTRACT_ARG(arg_set_id, "render_frame_host.frame_type")
+FROM descendant_slice($slice_id)
+WHERE name IN (
+ "RenderFrameHostImpl::BeginNavigation",
+ "RenderFrameHostImpl::DidCommitProvisionalLoad",
+ "RenderFrameHostImpl::DidCommitSameDocumentNavigation",
+ "RenderFrameHostImpl::DidStopLoading"
+)
+LIMIT 1;
-- Human-readable aliases for a few key navigation tasks.
-SELECT CREATE_FUNCTION(
- 'INTERNAL_HUMAN_READABLE_NAVIGATION_TASK_NAME(task_name STRING)',
- 'STRING',
- 'SELECT
- CASE
- WHEN $task_name = "content.mojom.FrameHost message (hash=2168461044)"
- THEN "FrameHost::BeginNavigation"
- WHEN $task_name = "content.mojom.FrameHost message (hash=3561497419)"
- THEN "FrameHost::DidCommitProvisionalLoad"
- WHEN $task_name = "content.mojom.FrameHost message (hash=1421450774)"
- THEN "FrameHost::DidCommitSameDocumentNavigation"
- WHEN $task_name = "content.mojom.FrameHost message (hash=368650583)"
- THEN "FrameHost::DidStopLoading"
- END
- '
-);
+CREATE PERFETTO FUNCTION INTERNAL_HUMAN_READABLE_NAVIGATION_TASK_NAME(task_name STRING)
+RETURNS STRING AS
+SELECT
+ CASE
+ WHEN $task_name = "content.mojom.FrameHost message (hash=2168461044)"
+ THEN "FrameHost::BeginNavigation"
+ WHEN $task_name = "content.mojom.FrameHost message (hash=3561497419)"
+ THEN "FrameHost::DidCommitProvisionalLoad"
+ WHEN $task_name = "content.mojom.FrameHost message (hash=1421450774)"
+ THEN "FrameHost::DidCommitSameDocumentNavigation"
+ WHEN $task_name = "content.mojom.FrameHost message (hash=368650583)"
+ THEN "FrameHost::DidStopLoading"
+ END;
-- Takes a task name and formats it correctly for scheduler tasks.
-SELECT CREATE_FUNCTION(
- 'INTERNAL_FORMAT_SCHEDULER_TASK_NAME(task_name STRING)',
- 'STRING',
- 'SELECT
- printf("RunTask(posted_from=%s)", $task_name)
- '
-);
+CREATE PERFETTO FUNCTION INTERNAL_FORMAT_SCHEDULER_TASK_NAME(task_name STRING)
+RETURNS STRING AS
+SELECT printf("RunTask(posted_from=%s)", $task_name);
-- Takes the category and determines whether it is "Java" only, as opposed to
-- "toplevel,Java".
-SELECT CREATE_FUNCTION(
- 'INTERNAL_JAVA_NOT_TOP_LEVEL_CATEGORY(category STRING)',
- 'BOOL',
- 'SELECT
- $category GLOB "*Java*" AND $category not GLOB "*toplevel*"
- '
-);
+CREATE PERFETTO FUNCTION INTERNAL_JAVA_NOT_TOP_LEVEL_CATEGORY(category STRING)
+RETURNS BOOL AS
+SELECT $category GLOB "*Java*" AND $category not GLOB "*toplevel*";
-- Takes the category and determines whether is any valid
-- toplevel category or combination of categories.
-SELECT CREATE_FUNCTION(
- 'INTERNAL_ANY_TOP_LEVEL_CATEGORY(category STRING)',
- 'BOOL',
- 'SELECT
- $category IN ("toplevel", "toplevel,viz", "toplevel,Java")
- '
-);
+CREATE PERFETTO FUNCTION INTERNAL_ANY_TOP_LEVEL_CATEGORY(category STRING)
+RETURNS BOOL AS
+SELECT $category IN ("toplevel", "toplevel,viz", "toplevel,Java");
-- TODO(altimin): the situations with kinds in this file is a bit of a mess.
-- The idea is that it should work as `type` in the `slice` table, pointing to
@@ -103,16 +82,13 @@
-- `create perfetto table`.
-- Get task type for a given task kind.
-SELECT CREATE_FUNCTION(
- 'INTERNAL_GET_JAVA_VIEWS_TASK_TYPE(kind STRING)',
- 'STRING',
- 'SELECT
- (CASE $kind
- WHEN "Choreographer" THEN "choreographer"
- WHEN "SingleThreadProxy::BeginMainFrame" THEN "ui_thread_begin_main_frame"
- END)
- '
-);
+CREATE PERFETTO FUNCTION INTERNAL_GET_JAVA_VIEWS_TASK_TYPE(kind STRING)
+RETURNS STRING AS
+SELECT
+ CASE $kind
+ WHEN "Choreographer" THEN "choreographer"
+ WHEN "SingleThreadProxy::BeginMainFrame" THEN "ui_thread_begin_main_frame"
+ END;
-- All slices corresponding to receiving mojo messages.
-- On the newer Chrome versions, it's just "Receive mojo message" and
@@ -309,21 +285,18 @@
dur,
name
FROM slice
-WHERE
- name GLOB "Looper.dispatch: android.view.Choreographer$FrameHandler*";
+WHERE name GLOB "Looper.dispatch: android.view.Choreographer$FrameHandler*";
-- Extract task's posted_from information from task's arguments.
-SELECT CREATE_FUNCTION('INTERNAL_GET_POSTED_FROM(arg_set_id INT)', 'STRING',
- '
- WITH posted_from as (
- SELECT
- EXTRACT_ARG($arg_set_id, "task.posted_from.file_name") AS file_name,
- EXTRACT_ARG($arg_set_id, "task.posted_from.function_name") AS function_name
- )
+CREATE PERFETTO FUNCTION INTERNAL_GET_POSTED_FROM(arg_set_id INT)
+RETURNS STRING AS
+WITH posted_from as (
SELECT
- file_name || ":" || function_name as posted_from
- FROM posted_from;
- ');
+ EXTRACT_ARG($arg_set_id, "task.posted_from.file_name") AS file_name,
+ EXTRACT_ARG($arg_set_id, "task.posted_from.function_name") AS function_name
+)
+SELECT file_name || ":" || function_name as posted_from
+FROM posted_from;
-- Selects the BeginMainFrame slices (which as posted from ScheduledActionSendBeginMainFrame),
-- used for root-level processing. In top-level/Java based slices, these will correspond to the
@@ -441,26 +414,27 @@
-- Select the slice that might be the descendant mojo slice for the given task
-- slice if it exists.
-SELECT CREATE_FUNCTION('INTERNAL_GET_DESCENDANT_MOJO_SLICE_CANDIDATE(slice_id INT)', 'INT',
- '
- SELECT
- id
- FROM descendant_slice($slice_id)
- WHERE
- -- The tricky case here is dealing with sync mojo IPCs: we do not want to
- -- pick up sync IPCs when we are in a non-IPC task.
- -- So we look at all toplevel events and pick up the first one:
- -- for sync mojo messages, it will be "Send mojo message", which then
- -- will fail.
- -- Some events are excluded as they can legimately appear under "RunTask"
- -- before "Receive mojo message".
- category GLOB "*toplevel*" AND
- name NOT IN (
- "SimpleWatcher::OnHandleReady",
- "MessagePipe peer closed")
- ORDER by depth, ts
- LIMIT 1
- ');
+CREATE PERFETTO FUNCTION INTERNAL_GET_DESCENDANT_MOJO_SLICE_CANDIDATE(
+ slice_id INT
+)
+RETURNS INT AS
+SELECT
+ id
+FROM descendant_slice($slice_id)
+WHERE
+ -- The tricky case here is dealing with sync mojo IPCs: we do not want to
+ -- pick up sync IPCs when we are in a non-IPC task.
+ -- So we look at all toplevel events and pick up the first one:
+ -- for sync mojo messages, it will be "Send mojo message", which then
+ -- will fail.
+ -- Some events are excluded as they can legimately appear under "RunTask"
+ -- before "Receive mojo message".
+ category GLOB "*toplevel*" AND
+ name NOT IN (
+ "SimpleWatcher::OnHandleReady",
+ "MessagePipe peer closed")
+ORDER by depth, ts
+LIMIT 1;
SELECT CREATE_VIEW_FUNCTION('INTERNAL_DESCENDANT_MOJO_SLICE(slice_id INT)',
'task_name STRING',
diff --git a/src/trace_processor/perfetto_sql/stdlib/common/counters.sql b/src/trace_processor/perfetto_sql/stdlib/common/counters.sql
index 22fb72d..cfef984 100644
--- a/src/trace_processor/perfetto_sql/stdlib/common/counters.sql
+++ b/src/trace_processor/perfetto_sql/stdlib/common/counters.sql
@@ -18,13 +18,10 @@
-- Timestamp of first counter value in a counter.
--
-- @arg counter_track_id INT Id of a counter track with a counter.
--- @ret LONG Timestamp of first counter value. Null if doesn't exist.
-SELECT CREATE_FUNCTION(
- 'EARLIEST_TIMESTAMP_FOR_COUNTER_TRACK(counter_track_id INT)',
- 'LONG',
- 'SELECT MIN(ts) FROM counter WHERE counter.track_id = $counter_track_id;'
-);
-
+-- @ret LONG Timestamp of first counter value. Null if doesn't exist.
+CREATE PERFETTO FUNCTION EARLIEST_TIMESTAMP_FOR_COUNTER_TRACK(counter_track_id INT)
+RETURNS LONG AS
+SELECT MIN(ts) FROM counter WHERE counter.track_id = $counter_track_id;
-- Counter values with details of counter track with calculated duration of each counter value.
-- Duration is calculated as time from counter to the next counter.
diff --git a/src/trace_processor/perfetto_sql/stdlib/common/cpus.sql b/src/trace_processor/perfetto_sql/stdlib/common/cpus.sql
index 460c80c..6273116 100644
--- a/src/trace_processor/perfetto_sql/stdlib/common/cpus.sql
+++ b/src/trace_processor/perfetto_sql/stdlib/common/cpus.sql
@@ -47,14 +47,10 @@
--
-- @arg cpu_index INT Index of the CPU whose size we will guess.
-- @ret STRING A descriptive size ('little', 'mid', 'big', etc) or NULL if we have insufficient information.
-SELECT CREATE_FUNCTION(
- 'GUESS_CPU_SIZE(cpu_index INT)',
- 'STRING',
- '
- SELECT
- IIF((SELECT COUNT(DISTINCT n) FROM internal_ranked_cpus) >= 2, size, null) as size
- FROM internal_ranked_cpus
- LEFT JOIN internal_cpu_sizes USING(n)
- WHERE cpu = $cpu_index;
- '
-);
+CREATE PERFETTO FUNCTION GUESS_CPU_SIZE(cpu_index INT)
+RETURNS STRING AS
+SELECT
+ IIF((SELECT COUNT(DISTINCT n) FROM internal_ranked_cpus) >= 2, size, null) as size
+FROM internal_ranked_cpus
+LEFT JOIN internal_cpu_sizes USING(n)
+WHERE cpu = $cpu_index;
diff --git a/src/trace_processor/perfetto_sql/stdlib/common/metadata.sql b/src/trace_processor/perfetto_sql/stdlib/common/metadata.sql
index 117af1e..b43b85b 100644
--- a/src/trace_processor/perfetto_sql/stdlib/common/metadata.sql
+++ b/src/trace_processor/perfetto_sql/stdlib/common/metadata.sql
@@ -17,9 +17,6 @@
--
-- @arg name STRING The name of the metadata entry.
-- @ret LONG int_value for the given name. NULL if there's no such entry.
-SELECT
- CREATE_FUNCTION(
- 'EXTRACT_INT_METADATA(name STRING)',
- 'LONG',
- 'SELECT int_value FROM metadata WHERE name = ($name)'
- );
\ No newline at end of file
+CREATE PERFETTO FUNCTION EXTRACT_INT_METADATA(name STRING)
+RETURNS LONG AS
+SELECT int_value FROM metadata WHERE name = ($name);
\ No newline at end of file
diff --git a/src/trace_processor/perfetto_sql/stdlib/common/percentiles.sql b/src/trace_processor/perfetto_sql/stdlib/common/percentiles.sql
index 74bd271..07e8ce4 100644
--- a/src/trace_processor/perfetto_sql/stdlib/common/percentiles.sql
+++ b/src/trace_processor/perfetto_sql/stdlib/common/percentiles.sql
@@ -92,22 +92,24 @@
-- @arg start_ts LONG Timestamp of start of time range.
-- @arg end_ts LONG Timestamp of end of time range.
-- @ret DOUBLE Value for the percentile.
-SELECT CREATE_FUNCTION(
- 'COUNTER_TRACK_PERCENTILE_FOR_TIME(counter_track_id INT, percentile INT, start_ts LONG, end_ts LONG)',
- 'DOUBLE',
- 'SELECT value
- FROM COUNTER_PERCENTILES_FOR_TIME_RANGE($counter_track_id, $start_ts, $end_ts)
- WHERE percentile = $percentile;'
-);
+CREATE PERFETTO FUNCTION COUNTER_TRACK_PERCENTILE_FOR_TIME(counter_track_id INT,
+ percentile INT,
+ start_ts LONG,
+ end_ts LONG)
+RETURNS DOUBLE AS
+SELECT value
+FROM COUNTER_PERCENTILES_FOR_TIME_RANGE($counter_track_id, $start_ts, $end_ts)
+WHERE percentile = $percentile;
-- Value for specific percentile (range 1-100) for counter track ID.
--
-- @arg counter_track_id INT Id of the counter track.
-- @arg percentile INT Any of the numbers from 1 to 100.
-- @ret DOUBLE Value for the percentile.
-SELECT CREATE_FUNCTION(
- 'COUNTER_TRACK_PERCENTILE(counter_track_id INT, percentile INT)',
- 'DOUBLE',
- 'SELECT COUNTER_TRACK_PERCENTILE_FOR_TIME($counter_track_id, $percentile, TRACE_START(), TRACE_END());'
-);
-
+CREATE PERFETTO FUNCTION COUNTER_TRACK_PERCENTILE(counter_track_id INT,
+ percentile INT)
+RETURNS DOUBLE AS
+SELECT COUNTER_TRACK_PERCENTILE_FOR_TIME($counter_track_id,
+ $percentile,
+ TRACE_START(),
+ TRACE_END());
diff --git a/src/trace_processor/perfetto_sql/stdlib/common/slices.sql b/src/trace_processor/perfetto_sql/stdlib/common/slices.sql
index dbeb23d..4bcab3c 100644
--- a/src/trace_processor/perfetto_sql/stdlib/common/slices.sql
+++ b/src/trace_processor/perfetto_sql/stdlib/common/slices.sql
@@ -106,48 +106,40 @@
-- @arg id INT Id of the slice to check parents of.
-- @arg parent_name STRING Name of potential ancestor slice.
-- @ret BOOL Whether `parent_name` is a name of an ancestor slice.
-SELECT
- CREATE_FUNCTION(
- 'HAS_PARENT_SLICE_WITH_NAME(id INT, parent_name STRING)',
- 'BOOL',
- '
- SELECT EXISTS(
- SELECT 1
- FROM ancestor_slice($id)
- WHERE name = $parent_name
- LIMIT 1
- );
- '
+CREATE PERFETTO FUNCTION HAS_PARENT_SLICE_WITH_NAME(id INT, parent_name STRING)
+RETURNS BOOL AS
+SELECT EXISTS(
+ SELECT 1
+ FROM ancestor_slice($id)
+ WHERE name = $parent_name
+ LIMIT 1
);
-- Checks if slice has a descendant with provided name.
+--
-- @arg id INT Id of the slice to check descendants of.
-- @arg descendant_name STRING Name of potential descendant slice.
--- @ret BOOL Whether `descendant_name` is a name of an descendant slice.
-SELECT
- CREATE_FUNCTION(
- 'HAS_DESCENDANT_SLICE_WITH_NAME(id INT, descendant_name STRING)',
- 'BOOL',
- '
- SELECT EXISTS(
- SELECT 1
- FROM descendant_slice($id)
- WHERE name = $descendant_name
- LIMIT 1
- );
- '
+-- @ret BOOL Whether `descendant_name` is a name of an
+-- descendant slice.
+CREATE PERFETTO FUNCTION HAS_DESCENDANT_SLICE_WITH_NAME(
+ id INT,
+ descendant_name STRING
+)
+RETURNS BOOL AS
+SELECT EXISTS(
+ SELECT 1
+ FROM descendant_slice($id)
+ WHERE name = $descendant_name
+ LIMIT 1
);
-- Count slices with specified name.
--
-- @arg slice_glob STRING Name of the slices to counted.
-- @ret INT Number of slices with the name.
-SELECT CREATE_FUNCTION(
- 'SLICE_COUNT(slice_glob STRING)',
- 'INT',
- 'SELECT COUNT(1) FROM slice WHERE name GLOB $slice_glob;'
-);
-
+CREATE PERFETTO FUNCTION SLICE_COUNT(slice_glob STRING)
+RETURNS INT AS
+SELECT COUNT(1) FROM slice WHERE name GLOB $slice_glob;;
-- Finds the end timestamp for a given slice's descendant with a given name.
-- If there are multiple descendants with a given name, the function will return the
@@ -156,16 +148,16 @@
-- @arg parent_id INT Id of the parent slice.
-- @arg child_name STRING name of the child with the desired end TS.
-- @ret INT end timestamp of the child or NULL if it doesn't exist.
-SELECT CREATE_FUNCTION(
- 'DESCENDANT_SLICE_END(parent_id INT, child_name STRING)',
- 'INT',
- 'SELECT
- CASE WHEN s.dur
- IS NOT -1 THEN s.ts + s.dur
- ELSE NULL
- END
- FROM descendant_slice($parent_id) s
- WHERE s.name = $child_name
- LIMIT 1
- '
-);
+CREATE PERFETTO FUNCTION DESCENDANT_SLICE_END(
+ parent_id INT,
+ child_name STRING
+)
+RETURNS INT AS
+SELECT
+ CASE WHEN s.dur
+ IS NOT -1 THEN s.ts + s.dur
+ ELSE NULL
+ END
+FROM descendant_slice($parent_id) s
+WHERE s.name = $child_name
+LIMIT 1;
diff --git a/src/trace_processor/perfetto_sql/stdlib/common/timestamps.sql b/src/trace_processor/perfetto_sql/stdlib/common/timestamps.sql
index e3958ed..0a5e48c 100644
--- a/src/trace_processor/perfetto_sql/stdlib/common/timestamps.sql
+++ b/src/trace_processor/perfetto_sql/stdlib/common/timestamps.sql
@@ -19,27 +19,21 @@
-- Fetch start of the trace.
-- @ret LONG Start of the trace in nanoseconds.
-SELECT CREATE_FUNCTION(
- 'TRACE_START()',
- 'LONG',
- 'SELECT start_ts FROM trace_bounds;'
-);
+CREATE PERFETTO FUNCTION TRACE_START()
+RETURNS LONG AS
+SELECT start_ts FROM trace_bounds;
-- Fetch end of the trace.
-- @ret LONG End of the trace in nanoseconds.
-SELECT CREATE_FUNCTION(
- 'TRACE_END()',
- 'LONG',
- 'SELECT end_ts FROM trace_bounds;'
-);
+CREATE PERFETTO FUNCTION TRACE_END()
+RETURNS LONG AS
+SELECT end_ts FROM trace_bounds;
-- Fetch duration of the trace.
-- @ret LONG Duration of the trace in nanoseconds.
-SELECT CREATE_FUNCTION(
- 'TRACE_DUR()',
- 'LONG',
- 'SELECT TRACE_END() - TRACE_START();'
-);
+CREATE PERFETTO FUNCTION TRACE_DUR()
+RETURNS LONG AS
+SELECT TRACE_END() - TRACE_START();
-- Checks whether two spans are overlapping.
--
@@ -48,14 +42,10 @@
-- @arg ts2 LONG Start of second span.
-- @arg ts_end2 LONG End of second span.
-- @ret BOOL Whether two spans are overlapping.
-SELECT CREATE_FUNCTION(
- 'IS_SPANS_OVERLAPPING(ts1 LONG, ts_end1 LONG, ts2 LONG, ts_end2 LONG)',
- 'BOOL',
- '
- SELECT (IIF($ts1 < $ts2, $ts2, $ts1)
- < IIF($ts_end1 < $ts_end2, $ts_end1, $ts_end2))
- '
-);
+CREATE PERFETTO FUNCTION IS_SPANS_OVERLAPPING(ts1 LONG, ts_end1 LONG, ts2 LONG, ts_end2 LONG)
+RETURNS BOOL AS
+SELECT (IIF($ts1 < $ts2, $ts2, $ts1)
+ < IIF($ts_end1 < $ts_end2, $ts_end1, $ts_end2));
--Return the overlapping duration between two spans.
--If either duration is less than 0 or there's no intersection, 0 is returned
@@ -65,11 +55,9 @@
-- @arg ts2 LONG Timestamp of second slice start.
-- @arg dur2 LONG Duration of second slice.
-- @ret INT Overlapping duration
-SELECT CREATE_FUNCTION(
- 'SPANS_OVERLAPPING_DUR(ts1 LONG, dur1 LONG, ts2 LONG, dur2 LONG)',
- 'INT',
- '
- SELECT
+CREATE PERFETTO FUNCTION SPANS_OVERLAPPING_DUR(ts1 LONG, dur1 LONG, ts2 LONG, dur2 LONG)
+RETURNS INT AS
+SELECT
CASE
WHEN $dur1 = -1 OR $dur2 = -1 THEN 0
WHEN $ts1 + $dur1 < $ts2 OR $ts2 + $dur2 < $ts1 THEN 0
@@ -77,6 +65,4 @@
WHEN ($ts1 < $ts2) AND ($ts1 + $dur1 < $ts2 + $dur2) THEN $ts1 + $dur1 - $ts2
WHEN ($ts1 > $ts2) AND ($ts1 + $dur1 > $ts2 + $dur2) THEN $ts2 + $dur2 - $ts1
ELSE $dur2
- END
- '
-);
+ END;
diff --git a/src/trace_processor/perfetto_sql/stdlib/experimental/proto_path.sql b/src/trace_processor/perfetto_sql/stdlib/experimental/proto_path.sql
index 2bd8eae..e1cd5fe 100644
--- a/src/trace_processor/perfetto_sql/stdlib/experimental/proto_path.sql
+++ b/src/trace_processor/perfetto_sql/stdlib/experimental/proto_path.sql
@@ -16,12 +16,10 @@
-- Creates a Stack consisting of one frame for a path in the
-- EXPERIMENTAL_PROTO_PATH table.
--
--- @arg path_id INT Id of the path in EXPERIMENTAL_PROTO_PATH
+-- @arg path_id INT LONG of the path in EXPERIMENTAL_PROTO_PATH
-- @ret BYTES Stack with one frame
-SELECT CREATE_FUNCTION(
-"EXPERIMENTAL_PROTO_PATH_TO_FRAME(path_id LONG)",
-"BYTES",
-"
+CREATE PERFETTO FUNCTON EXPERIMENTAL_PROTO_PATH_TO_FRAME(path_id LONG)
+RETURNS BYTES AS
SELECT
CAT_STACKS(
'event.name:' || EXTRACT_ARG(arg_set_id, 'event.name'),
@@ -29,19 +27,16 @@
field_name,
field_type)
FROM EXPERIMENTAL_PROTO_PATH
-WHERE id = $path_id
-");
+WHERE id = $path_id;
-- Creates a Stack following the parent relations in EXPERIMENTAL_PROTO_PATH
-- table starting at the given path_id.
--
--- @arg path_id INT Id of the path in EXPERIMENTAL_PROTO_PATH that will be
+-- @arg path_id LONG Id of the path in EXPERIMENTAL_PROTO_PATH that will be
-- the leaf in the returned stack
-- @ret BYTES Stack
-SELECT CREATE_FUNCTION(
-"EXPERIMENTAL_PROTO_PATH_TO_STACK(path_id LONG)",
-"BYTES",
-"
+CREATE PERFETTO FUNCTION EXPERIMENTAL_PROTO_PATH_TO_STACK(path_id LONG)
+RETURNS BYTES AS
WITH
R AS (
-- Starting at the given path_id generate a stack
@@ -67,5 +62,4 @@
SELECT stack
FROM R
WHERE
- parent_id IS NULL
-");
\ No newline at end of file
+ parent_id IS NULL;
\ No newline at end of file
diff --git a/src/trace_processor/perfetto_sql/stdlib/experimental/thread_executing_span.sql b/src/trace_processor/perfetto_sql/stdlib/experimental/thread_executing_span.sql
index be94e25..b778c64 100644
--- a/src/trace_processor/perfetto_sql/stdlib/experimental/thread_executing_span.sql
+++ b/src/trace_processor/perfetto_sql/stdlib/experimental/thread_executing_span.sql
@@ -497,22 +497,18 @@
--
-- @arg thread_state_id INT Id of the thread_state to get the thread_executing_span id for
-- @ret INT thread_executing_span id
-SELECT
- CREATE_FUNCTION(
-'EXPERIMENTAL_THREAD_EXECUTING_SPAN_ID_FROM_THREAD_STATE_ID(thread_state_id INT)',
-'INT',
-'
-WITH
- t AS (
+CREATE PERFETTO FUNCTION
+EXPERIMENTAL_THREAD_EXECUTING_SPAN_ID_FROM_THREAD_STATE_ID(thread_state_id INT)
+RETURNS INT AS
+WITH t AS (
SELECT
ts,
utid
FROM thread_state
WHERE
id = $thread_state_id
- )
- SELECT
- MAX(start_id) AS thread_executing_span_id
- FROM internal_wakeup w, t
- WHERE t.utid = w.utid AND t.ts >= w.start_ts AND t.ts < w.end_ts;
-');
+)
+SELECT
+ MAX(start_id) AS thread_executing_span_id
+FROM internal_wakeup w, t
+WHERE t.utid = w.utid AND t.ts >= w.start_ts AND t.ts < w.end_ts;
diff --git a/src/tracing/internal/tracing_muxer_impl.cc b/src/tracing/internal/tracing_muxer_impl.cc
index bba6153..e953823 100644
--- a/src/tracing/internal/tracing_muxer_impl.cc
+++ b/src/tracing/internal/tracing_muxer_impl.cc
@@ -1295,9 +1295,9 @@
DataSourceInstanceID>::value,
"data_source_instance_id type mismatch");
internal_state->muxer_id_for_testing = muxer_id_for_testing_;
+ RegisteredProducerBackend& backend = *FindProducerBackendById(backend_id);
if (startup_session_id) {
- RegisteredProducerBackend& backend = *FindProducerBackendById(backend_id);
uint16_t& last_reservation =
backend.producer->last_startup_target_buffer_reservation_;
if (last_reservation == std::numeric_limits<uint16_t>::max()) {
@@ -1349,6 +1349,7 @@
DataSourceBase::SetupArgs setup_args;
setup_args.config = &cfg;
+ setup_args.backend_type = backend.type;
setup_args.internal_instance_index = i;
if (!rds.requires_callbacks_under_lock)
diff --git a/test/cts/Android.bp b/test/cts/Android.bp
index ccd1745..6d58f58 100644
--- a/test/cts/Android.bp
+++ b/test/cts/Android.bp
@@ -39,7 +39,7 @@
],
test_suites: [
"cts",
- "mts",
+ "mts-art",
"vts10",
"general-tests",
],
diff --git a/test/trace_processor/diff_tests/chrome/scroll_jank_v3.out b/test/trace_processor/diff_tests/chrome/scroll_jank_v3.out
index 5f1c097..e539208 100644
--- a/test/trace_processor/diff_tests/chrome/scroll_jank_v3.out
+++ b/test/trace_processor/diff_tests/chrome/scroll_jank_v3.out
@@ -1,3 +1,4 @@
"cause_of_jank","sub_cause_of_jank","delay_since_last_frame","vsync_interval"
+"[NULL]","[NULL]",33.462000,16.368000
"RendererCompositorFinishedToBeginImplFrame","[NULL]",100.274000,16.368000
"RendererCompositorQueueingDelay","[NULL]",33.404000,16.368000
diff --git a/test/trace_processor/diff_tests/chrome/scroll_jank_v3_percentage.out b/test/trace_processor/diff_tests/chrome/scroll_jank_v3_percentage.out
index d3d7bfb..2081e06 100644
--- a/test/trace_processor/diff_tests/chrome/scroll_jank_v3_percentage.out
+++ b/test/trace_processor/diff_tests/chrome/scroll_jank_v3_percentage.out
@@ -1,2 +1,2 @@
"delayed_frame_percentage"
-0.687285
+1.030928
diff --git a/tools/check_sql_metrics.py b/tools/check_sql_metrics.py
index b45edf8..f888d41 100755
--- a/tools/check_sql_metrics.py
+++ b/tools/check_sql_metrics.py
@@ -61,6 +61,17 @@
sys.stderr.write('Offending file: %s\n' % path)
errors += 1
+ # Ban the use of CREATE_FUNCTION.
+ for line in lines:
+ if line.startswith('--'):
+ continue
+
+ if 'create_function' in line.casefold():
+ sys.stderr.write('CREATE_FUNCTION is deprecated in trace processor. '
+ 'Prefer CREATE PERFETTO FUNCTION instead.\n')
+ sys.stderr.write('Offending file: %s\n' % path)
+ errors += 1
+
return errors
diff --git a/tools/check_sql_modules.py b/tools/check_sql_modules.py
index f50fdbd..4fb349e 100755
--- a/tools/check_sql_modules.py
+++ b/tools/check_sql_modules.py
@@ -43,6 +43,28 @@
res = parse_file_to_dict(path, sql)
errors += res if isinstance(res, list) else []
+
+ # Ban the use of LIKE in non-comment lines.
+ lines = [l.strip() for l in sql.split('\n')]
+ for line in lines:
+ if line.startswith('--'):
+ continue
+
+ if 'like' in line.casefold():
+ errors.append('LIKE is banned in trace processor metrics. '
+ 'Prefer GLOB instead.')
+ errors.append('Offending file: %s' % path)
+
+ # Ban the use of CREATE_FUNCTION.
+ for line in lines:
+ if line.startswith('--'):
+ continue
+
+ if 'create_function' in line.casefold():
+ errors.append('CREATE_FUNCTION is deprecated in trace processor. '
+ 'Prefer CREATE PERFETTO FUNCTION instead.')
+ errors.append('Offending file: %s' % path)
+
sys.stderr.write("\n".join(errors))
sys.stderr.write("\n")
return 0 if not errors else 1
diff --git a/tools/gen_ui_imports b/tools/gen_ui_imports
index b644dfe..36b3825 100755
--- a/tools/gen_ui_imports
+++ b/tools/gen_ui_imports
@@ -36,8 +36,7 @@
import os
import argparse
-import subprocess
-import sys
+import re
ROOT_DIR = os.path.dirname(os.path.dirname(os.path.realpath(__file__)))
UI_SRC_DIR = os.path.join(ROOT_DIR, 'ui', 'src')
@@ -45,7 +44,8 @@
def to_camel_case(s):
- first, *rest = s.split('_')
+ # Split string on periods and underscores
+ first, *rest = re.split(r'\.|\_', s)
return first + ''.join(x.title() for x in rest)
@@ -70,7 +70,7 @@
import_text = '\n'.join(imports)
registration_text = '\n'.join(registrations)
- expected = f"{header}\n\n{import_text}\n\n{registration_text}"
+ expected = f"{header}\n\n{import_text}\n\n{registration_text}\n"
with open(output_path, 'w') as f:
f.write(expected)
diff --git a/ui/build.js b/ui/build.js
index 92f793b..f8e2d90 100644
--- a/ui/build.js
+++ b/ui/build.js
@@ -237,6 +237,7 @@
scanDir('buildtools/typefaces');
scanDir('buildtools/catapult_trace_viewer');
generateImports('ui/src/tracks', 'all_tracks.ts');
+ generateImports('ui/src/plugins', 'all_plugins.ts');
compileProtos();
genVersion();
transpileTsProject('ui');
diff --git a/ui/src/common/empty_state.ts b/ui/src/common/empty_state.ts
index af1785f..6044708 100644
--- a/ui/src/common/empty_state.ts
+++ b/ui/src/common/empty_state.ts
@@ -173,5 +173,8 @@
textEntry: '',
hideNonMatching: true,
},
+
+ // Somewhere to store plugins' persistent state.
+ plugins: {},
};
}
diff --git a/ui/src/common/plugin_api.ts b/ui/src/common/plugin_api.ts
index 9ba3a99..53e09a2 100644
--- a/ui/src/common/plugin_api.ts
+++ b/ui/src/common/plugin_api.ts
@@ -16,6 +16,8 @@
import {TrackControllerFactory} from '../controller/track_controller';
import {TrackCreator} from '../frontend/track';
+import {TracePluginFactory} from './plugins';
+
export {EngineProxy} from '../common/engine';
export {
LONG,
@@ -68,6 +70,10 @@
// could be registered in dev.perfetto.CounterTrack - a whole
// different plugin.
registerTrack(track: TrackCreator): void;
+
+ // Register a new plugin factory for a plugin whose lifecycle in linked to
+ // that of the trace.
+ registerTracePluginFactory<T>(pluginFactory: TracePluginFactory<T>): void;
}
export interface PluginInfo {
diff --git a/ui/src/common/plugins.ts b/ui/src/common/plugins.ts
index aa414bc..5a362c7 100644
--- a/ui/src/common/plugins.ts
+++ b/ui/src/common/plugins.ts
@@ -12,21 +12,57 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-import {Engine} from '../common/engine';
+import {Disposable} from 'src/base/disposable';
+
import {
TrackControllerFactory,
trackControllerRegistry,
} from '../controller/track_controller';
+import {Store} from '../frontend/store';
import {TrackCreator} from '../frontend/track';
import {trackRegistry} from '../frontend/track_registry';
+import {Engine} from './engine';
import {
+ EngineProxy,
PluginContext,
PluginInfo,
TrackInfo,
TrackProvider,
} from './plugin_api';
import {Registry} from './registry';
+import {State} from './state';
+
+// All trace plugins must implement this interface.
+export interface TracePlugin extends Disposable {
+ // This is where we would add potential extension points that plugins can
+ // override.
+ // E.g. commands(): Command[];
+ // For now, plugins don't do anything so this interface is empty.
+}
+
+// This interface defines what a plugin factory should look like.
+// This can be defined in the plugin class definition by defining a constructor
+// and the relevant static methods:
+// E.g.
+// class MyPlugin implements TracePlugin<MyState> {
+// static migrate(initialState: unknown): MyState {...}
+// constructor(store: Store<MyState>, engine: EngineProxy) {...}
+// ... methods from the TracePlugin interface go here ...
+// }
+// ... which can then be passed around by class i.e. MyPlugin
+export interface TracePluginFactory<StateT> {
+ // Function to migrate the persistent state. Called before new().
+ migrate(initialState: unknown): StateT;
+
+ // Instantiate the plugin.
+ new(store: Store<StateT>, engine: EngineProxy): TracePlugin;
+}
+
+interface TracePluginContext {
+ plugin: TracePlugin;
+ store: Store<unknown>;
+}
// Every plugin gets its own PluginContext. This is how we keep track
// what each plugin is doing and how we can blame issues on particular
@@ -34,6 +70,8 @@
export class PluginContextImpl implements PluginContext {
readonly pluginId: string;
private trackProviders: TrackProvider[];
+ private tracePluginFactory?: TracePluginFactory<any>;
+ private _tracePluginCtx?: TracePluginContext;
constructor(pluginId: string) {
this.pluginId = pluginId;
@@ -53,6 +91,10 @@
registerTrackProvider(provider: TrackProvider) {
this.trackProviders.push(provider);
}
+
+ registerTracePluginFactory<T>(pluginFactory: TracePluginFactory<T>): void {
+ this.tracePluginFactory = pluginFactory;
+ }
// ==================================================================
// ==================================================================
@@ -62,11 +104,50 @@
return this.trackProviders.map((f) => f(proxy));
}
+ onTraceLoad(store: Store<State>, engine: Engine): void {
+ const TracePluginClass = this.tracePluginFactory;
+ if (TracePluginClass) {
+ // Make an engine proxy for this plugin.
+ const engineProxy = engine.getProxy(this.pluginId);
+
+ // Extract the initial state and pass to the plugin factory for migration.
+ const initialState = store.state.plugins[this.pluginId];
+ const migratedState = TracePluginClass.migrate(initialState);
+
+ // Store the initial state in our root store.
+ store.edit((draft) => {
+ draft.plugins[this.pluginId] = migratedState;
+ });
+
+ // Create a proxy store for our plugin to use.
+ const storeProxy = store.createProxy<unknown>(['plugins', this.pluginId]);
+
+ // Instantiate the plugin.
+ this._tracePluginCtx = {
+ plugin: new TracePluginClass(storeProxy, engineProxy),
+ store: storeProxy,
+ };
+ }
+ }
+
+ onTraceClosed() {
+ if (this._tracePluginCtx) {
+ this._tracePluginCtx.plugin.dispose();
+ this._tracePluginCtx.store.dispose();
+ this._tracePluginCtx = undefined;
+ }
+ }
+
+ get tracePlugin(): TracePlugin|undefined {
+ return this._tracePluginCtx?.plugin;
+ }
+
// Unload the plugin. Ideally no plugin code runs after this point.
// PluginContext should unregister everything.
revoke() {
// TODO(hjd): Remove from trackControllerRegistry, trackRegistry,
// etc.
+ // TODO(stevegolton): Close the trace plugin.
}
// ==================================================================
}
@@ -123,6 +204,18 @@
}
return promises;
}
+
+ onTraceLoad(store: Store<State>, engine: Engine): void {
+ for (const context of this.contexts.values()) {
+ context.onTraceLoad(store, engine);
+ }
+ }
+
+ onTraceClose() {
+ for (const context of this.contexts.values()) {
+ context.onTraceClosed();
+ }
+ }
}
// TODO(hjd): Sort out the story for global singletons like these:
diff --git a/ui/src/common/state.ts b/ui/src/common/state.ts
index dba1158..5f5e1a4 100644
--- a/ui/src/common/state.ts
+++ b/ui/src/common/state.ts
@@ -624,6 +624,9 @@
// Pending deeplink which will happen when we first finish opening a
// trace.
pendingDeeplink?: PendingDeeplinkState;
+
+ // Individual plugin states
+ plugins: {[key: string]: any};
}
export const defaultTraceTime = {
diff --git a/ui/src/controller/trace_controller.ts b/ui/src/controller/trace_controller.ts
index 047f005..d46a6c0 100644
--- a/ui/src/controller/trace_controller.ts
+++ b/ui/src/controller/trace_controller.ts
@@ -30,6 +30,7 @@
getEnabledMetatracingCategories,
isMetatracingEnabled,
} from '../common/metatracing';
+import {pluginManager} from '../common/plugins';
import {
LONG,
NUM,
@@ -45,11 +46,7 @@
PendingDeeplinkState,
ProfileType,
} from '../common/state';
-import {Span} from '../common/time';
-import {
- TPTime,
- TPTimeSpan,
-} from '../common/time';
+import {Span, TPTime, TPTimeSpan} from '../common/time';
import {resetEngineWorker, WasmEngineProxy} from '../common/wasm_engine_proxy';
import {BottomTabList} from '../frontend/bottom_tab';
import {
@@ -342,6 +339,7 @@
}
onDestroy() {
+ pluginManager.onTraceClose();
globals.engines.delete(this.engineId);
}
@@ -556,6 +554,8 @@
}
}
+ pluginManager.onTraceLoad(globals.store, engine);
+
return engineMode;
}
diff --git a/ui/src/frontend/debug.ts b/ui/src/frontend/debug.ts
index 7e9c9e5..64de18a 100644
--- a/ui/src/frontend/debug.ts
+++ b/ui/src/frontend/debug.ts
@@ -16,6 +16,7 @@
import m from 'mithril';
import {Actions} from '../common/actions';
+import {pluginManager} from '../common/plugins';
import {getSchema} from '../common/schema';
import {globals} from './globals';
@@ -28,6 +29,7 @@
globals: typeof globals;
Actions: typeof Actions;
produce: typeof produce;
+ pluginManager: typeof pluginManager
}
}
@@ -37,4 +39,5 @@
window.globals = globals;
window.Actions = Actions;
window.produce = produce;
+ window.pluginManager = pluginManager;
}
diff --git a/ui/src/frontend/index.ts b/ui/src/frontend/index.ts
index 9a8d3a4..22a5122 100644
--- a/ui/src/frontend/index.ts
+++ b/ui/src/frontend/index.ts
@@ -14,6 +14,7 @@
// Keep this import first.
import '../core/static_initializers';
+import '../gen/all_plugins';
import {Draft} from 'immer';
import m from 'mithril';
diff --git a/ui/src/frontend/store.ts b/ui/src/frontend/store.ts
index 170bb97..1f67eed 100644
--- a/ui/src/frontend/store.ts
+++ b/ui/src/frontend/store.ts
@@ -139,16 +139,19 @@
export class ProxyStoreImpl<RootT, T> implements Store<T> {
private subscriptions = new Set<SubscriptionCallback<T>>();
private rootSubscription;
+ private rootStore?: Store<RootT>;
constructor(
- private rootStore: Store<RootT>,
+ rootStore: Store<RootT>,
private path: Path,
) {
+ this.rootStore = rootStore;
this.rootSubscription = rootStore.subscribe(this.rootUpdateHandler);
}
dispose() {
this.rootSubscription.dispose();
+ this.rootStore = undefined;
}
private rootUpdateHandler = (newState: RootT, oldState: RootT) => {
@@ -163,10 +166,15 @@
};
get state(): T {
+ if (!this.rootStore) {
+ throw new StoreError('Proxy store is no longer useable');
+ }
+
const state = lookupPath<T, RootT>(this.rootStore.state, this.path);
if (state === undefined) {
throw new StoreError(`No such subtree: ${this.path}`);
}
+
return state;
}
@@ -179,6 +187,10 @@
}
private applyEdits(edits: Edit<T>[]): void {
+ if (!this.rootStore) {
+ throw new StoreError('Proxy store is no longer useable');
+ }
+
// Transform edits to work on the root store.
const rootEdits = edits.map(
(edit) => (state: Draft<RootT>) => {
@@ -197,6 +209,10 @@
}
createProxy<NewSubStateT>(path: Path): Store<NewSubStateT> {
+ if (!this.rootStore) {
+ throw new StoreError('Proxy store is no longer useable');
+ }
+
const fullPath = [...this.path, ...path];
return new ProxyStoreImpl<RootT, NewSubStateT>(this.rootStore, fullPath);
}
diff --git a/ui/src/frontend/store_unittest.ts b/ui/src/frontend/store_unittest.ts
index 13395a1..01d39d1 100644
--- a/ui/src/frontend/store_unittest.ts
+++ b/ui/src/frontend/store_unittest.ts
@@ -282,4 +282,104 @@
// Ensure proxy callback hasn't been called
expect(callback).not.toHaveBeenCalled();
});
+
+ it('notifies subscribers', () => {
+ const store = createStore(initialState);
+ const fooState = store.createProxy<Foo>(['foo']);
+ const callback = jest.fn();
+
+ fooState.subscribe(callback);
+
+ store.edit((draft) => {
+ draft.foo.counter += 1;
+ });
+
+ expect(callback).toHaveBeenCalledTimes(1);
+ expect(callback).toHaveBeenCalledWith(
+ {
+ ...initialState.foo,
+ counter: 1,
+ },
+ initialState.foo);
+ });
+
+ it('does not notify unsubscribed subscribers', () => {
+ const store = createStore(initialState);
+ const fooState = store.createProxy<Foo>(['foo']);
+ const callback = jest.fn();
+
+ // Subscribe then immediately unsubscribe
+ fooState.subscribe(callback).dispose();
+
+ // Make an arbitrary edit
+ fooState.edit((draft) => {
+ draft.counter += 1;
+ });
+
+ expect(callback).not.toHaveBeenCalled();
+ });
+
+ it('throws on state access when path doesn\'t exist', () => {
+ const store = createStore(initialState);
+
+ // This path is incorrect - baz doesn't exist in State
+ const fooStore = store.createProxy<Foo>(['baz']);
+
+ expect(() => {
+ fooStore.state;
+ }).toThrow(StoreError);
+ });
+
+ it('throws on edit when path doesn\'t exist', () => {
+ const store = createStore(initialState);
+
+ // This path is incorrect - baz doesn't exist in State
+ const fooState = store.createProxy<Foo>(['baz']);
+
+ expect(() => {
+ fooState.edit((draft) => {
+ draft.counter += 1;
+ });
+ }).toThrow(StoreError);
+ });
+
+ it('notifies when relevant edits are made from root store', () => {
+ const store = createStore(initialState);
+ const fooState = store.createProxy<Foo>(['foo']);
+ const callback = jest.fn();
+
+ // Subscribe on the proxy store
+ fooState.subscribe(callback);
+
+ // Edit the root store
+ store.edit((draft) => {
+ draft.foo.counter++;
+ });
+
+ // Expect proxy callback called with correct subtree
+ expect(callback).toHaveBeenCalled();
+ expect(callback).toHaveBeenCalledWith(
+ {
+ ...initialState.foo,
+ counter: 1,
+ },
+ initialState.foo);
+ });
+
+ it('ignores irrrelevant edits from the root store', () => {
+ const store = createStore(initialState);
+ const nestedStore = store.createProxy<NestedState>(['foo', 'nested']);
+ const callback = jest.fn();
+
+ // Subscribe on the proxy store
+ nestedStore.subscribe(callback);
+
+ // Edit an irrelevant subtree on the root store
+ store.edit((draft) => {
+ draft.foo.counter++;
+ });
+
+ // Ensure proxy callback hasn't been called
+ expect(callback).not.toHaveBeenCalled();
+ });
});
diff --git a/ui/src/plugins/dev.perfetto.ExamplePlugin/index.ts b/ui/src/plugins/dev.perfetto.ExamplePlugin/index.ts
new file mode 100644
index 0000000..3305a90
--- /dev/null
+++ b/ui/src/plugins/dev.perfetto.ExamplePlugin/index.ts
@@ -0,0 +1,45 @@
+// 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 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.
+
+import {EngineProxy, PluginContext} from '../../common/plugin_api';
+import {TracePlugin} from '../../common/plugins';
+import {Store} from '../../frontend/store';
+
+interface ExampleState {
+ counter: number;
+}
+
+// This is just an example plugin, used to prove that the plugin system works.
+class ExamplePlugin implements TracePlugin {
+ static migrate(_initialState: unknown): ExampleState {
+ return {counter: 0};
+ }
+
+ constructor(_store: Store<ExampleState>, _engine: EngineProxy) {
+ // No-op
+ }
+
+ dispose(): void {
+ // No-op
+ }
+}
+
+function activate(ctx: PluginContext) {
+ ctx.registerTracePluginFactory(ExamplePlugin);
+}
+
+export const plugin = {
+ pluginId: 'dev.perfetto.ExamplePlugin',
+ activate,
+};
diff --git a/ui/src/tracks/chrome_slices/index.ts b/ui/src/tracks/chrome_slices/index.ts
index 8807b52..d09a552 100644
--- a/ui/src/tracks/chrome_slices/index.ts
+++ b/ui/src/tracks/chrome_slices/index.ts
@@ -221,6 +221,10 @@
tEnd = visibleWindowTime.end.toTPTime('ceil');
}
+ if (!visibleTimeSpan.intersects(tStart, tEnd)) {
+ continue;
+ }
+
const rect = this.getSliceRect(
visibleTimeScale, visibleTimeSpan, windowSpan, tStart, tEnd, depth);
if (!rect || !rect.visible) {