[metrics] adding chrome_stack_samples_for_task.sql
Given a chrome task name resulting from chrome_tasks.sql, this script
finds and aggregates all stack samples that happened during this task
and returns them.
Bug:235062961
Change-Id: Ibe55e3941c5113ca5c1b58ba68d9aa6a84f6613d
diff --git a/Android.bp b/Android.bp
index 8bc5ce4..15f2d5c 100644
--- a/Android.bp
+++ b/Android.bp
@@ -8916,6 +8916,7 @@
"src/trace_processor/metrics/sql/chrome/chrome_performance_mark_hashes.sql",
"src/trace_processor/metrics/sql/chrome/chrome_processes.sql",
"src/trace_processor/metrics/sql/chrome/chrome_slice_names.sql",
+ "src/trace_processor/metrics/sql/chrome/chrome_stack_samples_for_task.sql",
"src/trace_processor/metrics/sql/chrome/chrome_tasks.sql",
"src/trace_processor/metrics/sql/chrome/chrome_thread_slice.sql",
"src/trace_processor/metrics/sql/chrome/chrome_unsymbolized_args.sql",
diff --git a/BUILD b/BUILD
index f61b2c3..52a9f84 100644
--- a/BUILD
+++ b/BUILD
@@ -1215,6 +1215,7 @@
"src/trace_processor/metrics/sql/chrome/chrome_performance_mark_hashes.sql",
"src/trace_processor/metrics/sql/chrome/chrome_processes.sql",
"src/trace_processor/metrics/sql/chrome/chrome_slice_names.sql",
+ "src/trace_processor/metrics/sql/chrome/chrome_stack_samples_for_task.sql",
"src/trace_processor/metrics/sql/chrome/chrome_tasks.sql",
"src/trace_processor/metrics/sql/chrome/chrome_thread_slice.sql",
"src/trace_processor/metrics/sql/chrome/chrome_unsymbolized_args.sql",
diff --git a/src/trace_processor/metrics/sql/BUILD.gn b/src/trace_processor/metrics/sql/BUILD.gn
index f00ad8c..80eaf60 100644
--- a/src/trace_processor/metrics/sql/BUILD.gn
+++ b/src/trace_processor/metrics/sql/BUILD.gn
@@ -95,6 +95,7 @@
"chrome/chrome_performance_mark_hashes.sql",
"chrome/chrome_processes.sql",
"chrome/chrome_slice_names.sql",
+ "chrome/chrome_stack_samples_for_task.sql",
"chrome/chrome_unsymbolized_args.sql",
"chrome/chrome_tasks.sql",
"chrome/chrome_thread_slice.sql",
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
new file mode 100644
index 0000000..a0523f3
--- /dev/null
+++ b/src/trace_processor/metrics/sql/chrome/chrome_stack_samples_for_task.sql
@@ -0,0 +1,165 @@
+--
+-- Copyright 2022 The Android Open Source Project
+--
+-- Licensed under the Apache License, Version 2.0 (the "License");
+-- you may not use this file except in compliance with the License.
+-- You may obtain a copy of the License at
+--
+-- https://www.apache.org/licenses/LICENSE-2.0
+--
+-- Unless required by applicable law or agreed to in writing, software
+-- distributed under the License is distributed on an "AS IS" BASIS,
+-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+-- See the License for the specific language governing permissions and
+-- limitations under the License.
+--
+
+-- Params:
+-- @target_duration_ms: find stack samples on tasks that are longer than
+-- this value
+
+-- @thread_name: thread name to look for stack samples on
+
+-- @task_name: a task name following chrome_tasks.sql naming convention to
+-- find stack samples on.
+
+
+SELECT RUN_METRIC('chrome/chrome_tasks.sql');
+
+
+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)'
+);
+
+-- 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
+-- information about stack traces that were collected during running them.
+DROP VIEW IF EXISTS chrome_targeted_task;
+CREATE VIEW chrome_targeted_task AS
+SELECT
+ chrome_tasks.full_name AS full_name,
+ chrome_tasks.dur AS dur,
+ chrome_tasks.ts AS ts,
+ chrome_tasks.id AS id,
+ utid AS utid
+FROM
+ chrome_tasks
+WHERE
+ chrome_tasks.dur >= {{target_duration_ms}} * 1e6
+ AND chrome_tasks.thread_name = {{thread_name}}
+ AND chrome_tasks.full_name = {{task_name}};
+
+
+-- Get all frames attached to callsite ids, as frames can be
+-- reused between stack frames, callsite ids are unique per
+-- stack sample.
+DROP VIEW IF EXISTS chrome_non_symbolized_frames;
+CREATE VIEW chrome_non_symbolized_frames AS
+SELECT
+ frames.name as frame_name,
+ callsite.id as callsite_id,
+ *
+FROM
+ stack_profile_frame frames
+ JOIN stack_profile_callsite callsite
+ ON callsite.frame_id = frames.id;
+
+-- Only lowest child frames are join-able with chrome_non_symbolized_frames
+-- which we need for the time at which the callstack was taken.
+DROP VIEW IF EXISTS chrome_symbolized_child_frames;
+CREATE VIEW chrome_symbolized_child_frames AS
+SELECT
+ thread.name as thread_name,
+ sample.utid AS sample_utid,
+ *
+FROM
+ chrome_non_symbolized_frames frames
+ JOIN cpu_profile_stack_sample sample USING(callsite_id)
+ JOIN thread USING(utid)
+ JOIN process USING(upid);
+
+-- Not all frames are symbolized, in cases where those frames
+-- are not symbolized, use the file name as it is usually descriptive
+-- of the function.
+DROP VIEW IF EXISTS chrome_thread_symbolized_child_frames;
+CREATE VIEW chrome_thread_symbolized_child_frames AS
+SELECT
+ DescribeSymbol(symbol.name, frame_name) AS description,
+ depth,
+ ts,
+ callsite_id,
+ sample_utid
+FROM chrome_symbolized_child_frames
+ LEFT JOIN stack_profile_symbol symbol USING(symbol_set_id)
+WHERE thread_name = {{thread_name}} ORDER BY ts DESC;
+
+-- Since only leaf stack frames have a timestamp, let's export this
+-- timestamp to all it's ancestor frames to use it later on for
+-- filtering frames within specific windows
+DROP VIEW IF EXISTS chrome_non_symbolized_frames_timed;
+CREATE VIEW chrome_non_symbolized_frames_timed AS
+ SELECT
+ chrome_non_symbolized_frames.frame_name,
+ chrome_non_symbolized_frames.depth,
+ chrome_thread_symbolized_child_frames.ts,
+ chrome_thread_symbolized_child_frames.sample_utid,
+ chrome_non_symbolized_frames.callsite_id,
+ symbol_set_id,
+ chrome_non_symbolized_frames.frame_id
+FROM chrome_thread_symbolized_child_frames
+ JOIN experimental_ancestor_stack_profile_callsite(
+ chrome_thread_symbolized_child_frames.callsite_id) child
+ JOIN chrome_non_symbolized_frames
+ ON chrome_non_symbolized_frames.callsite_id = child.id;
+
+DROP VIEW IF EXISTS chrome_frames_timed_and_symbolized;
+CREATE VIEW chrome_frames_timed_and_symbolized AS
+ SELECT
+ DescribeSymbol(symbol.name, frame_name) AS description,
+ ts,
+ depth,
+ callsite_id,
+ sample_utid
+FROM chrome_non_symbolized_frames_timed
+ LEFT JOIN stack_profile_symbol symbol
+ USING(symbol_set_id)
+ORDER BY DEPTH ASC;
+
+-- Union leaf stack frames with all stack frames after the timestamp
+-- is attached to get a view of all frames timestamped.
+DROP VIEW IF EXISTS all_frames;
+CREATE VIEW all_frames AS
+SELECT
+ *
+FROM
+ (SELECT
+ * FROM
+ chrome_frames_timed_and_symbolized
+ UNION
+ SELECT
+ description,
+ ts,
+ depth,
+ callsite_id,
+ sample_utid
+ FROM chrome_thread_symbolized_child_frames)
+ORDER BY depth ASC;
+
+-- Filter stack samples that happened only during the specified
+-- task on the specified thread.
+DROP VIEW IF EXISTS chrome_stack_samples_for_task;
+CREATE VIEW chrome_stack_samples_for_task AS
+SELECT
+ all_frames.*
+FROM
+ all_frames JOIN
+ chrome_targeted_task ON
+ all_frames.sample_utid = chrome_targeted_task.utid
+ AND all_frames.ts >= chrome_targeted_task.ts
+ AND all_frames.ts <= chrome_targeted_task.ts + chrome_targeted_task.dur;
\ No newline at end of file
diff --git a/test/data/chrome_stack_traces_symbolized_trace.pftrace.sha256 b/test/data/chrome_stack_traces_symbolized_trace.pftrace.sha256
new file mode 100644
index 0000000..76156d4
--- /dev/null
+++ b/test/data/chrome_stack_traces_symbolized_trace.pftrace.sha256
@@ -0,0 +1 @@
+a3cb32a2faaef29b0b16c0f8242073beffdc6d0454e7a07a5e5466349f3c3125
\ No newline at end of file
diff --git a/test/trace_processor/chrome/chrome_stack_samples_for_task_test.out b/test/trace_processor/chrome/chrome_stack_samples_for_task_test.out
new file mode 100644
index 0000000..6e63af3
--- /dev/null
+++ b/test/trace_processor/chrome/chrome_stack_samples_for_task_test.out
@@ -0,0 +1,11 @@
+
+"description","ts","depth"
+"Scanned",696373965111470,0
+"tracing::TraceEventDataSource::OnAddLegacyTraceEvent(base::trace_event::TraceEvent*, bool, base::trace_event::TraceEventHandle*)",696373965111470,1
+"base::trace_event::TraceLog::AddTraceEventWithThreadIdAndTimestamps(char, unsigned char const*, char const*, char const*, unsigned long long, unsigned long long, int, base::TimeTicks const&, base::ThreadTicks const&, base::trace_event::TraceArguments*, unsigned int)",696373965111470,2
+"base::subtle::TimeTicksNowIgnoringOverride()",696373965111470,3
+"base::tracing::AutoThreadLocalBoolean::~AutoThreadLocalBoolean()",696373965111470,4
+"tracing::TraceEventDataSource::OnUpdateDuration(unsigned char const*, char const*, base::trace_event::TraceEventHandle, int, bool, base::TimeTicks const&, base::ThreadTicks const&, base::trace_event::ThreadInstructionCount)",696373965111470,5
+"content::ServiceWorkerRegistry::StoreUserData(long long, blink::StorageKey const&, std::__1::vector<std::__1::pair<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >, std::__1::allocator<std::__1::pair<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > > > const&, base::OnceCallback<void (blink::ServiceWorkerStatusCode)>)",696373965111470,6
+"base::trace_event::TraceLog::UpdateTraceEventDuration(unsigned char const*, char const*, base::trace_event::TraceEventHandle)",696373965111470,7
+"XML_ParseBuffer",696373965111470,8
diff --git a/test/trace_processor/chrome/chrome_stack_samples_for_task_test.sql b/test/trace_processor/chrome/chrome_stack_samples_for_task_test.sql
new file mode 100644
index 0000000..3b33d47
--- /dev/null
+++ b/test/trace_processor/chrome/chrome_stack_samples_for_task_test.sql
@@ -0,0 +1,34 @@
+--
+-- Copyright 2022 The Android Open Source Project
+--
+-- Licensed under the Apache License, Version 2.0 (the "License");
+-- you may not use this file except in compliance with the License.
+-- You may obtain a copy of the License at
+--
+-- https://www.apache.org/licenses/LICENSE-2.0
+--
+-- Unless required by applicable law or agreed to in writing, software
+-- distributed under the License is distributed on an "AS IS" BASIS,
+-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+-- See the License for the specific language governing permissions and
+-- limitations under the License.
+
+SELECT RUN_METRIC('chrome/chrome_stack_samples_for_task.sql',
+ 'target_duration_ms', '0.000001',
+ 'thread_name', '"CrBrowserMain"',
+ 'task_name', '"sendTouchEvent"') AS suppress_query_output;
+
+SELECT
+ sample.description,
+ sample.ts,
+ sample.depth
+FROM chrome_stack_samples_for_task sample
+JOIN (
+ SELECT
+ ts,
+ dur
+ FROM slice
+ WHERE ts = 696373965001470
+) test_slice
+ ON sample.ts >= test_slice.ts
+ AND sample.ts <= test_slice.ts + test_slice.dur;
\ No newline at end of file
diff --git a/test/trace_processor/chrome/index b/test/trace_processor/chrome/index
index ee0ac6f..e5d8395 100644
--- a/test/trace_processor/chrome/index
+++ b/test/trace_processor/chrome/index
@@ -70,5 +70,8 @@
# Chrome tasks.
../../data/chrome_page_load_all_categories_not_extended.pftrace.gz chrome_tasks_test.sql chrome_tasks.out
+# Chrome stack samples.
+../../data/chrome_stack_traces_symbolized_trace.pftrace chrome_stack_samples_for_task_test.sql chrome_stack_samples_for_task_test.out
+
# Unsymbolized args.
unsymbolized_args.textproto chrome_unsymbolized_args unsymbolized_args.out