Add ancestor/descendant_and_self_slice.

Add a helper which returns ancestors/descendants together with the slice
itself.

Change-Id: I80d42c39fa8d1ce8bfc053cb446bc6fe95fe5b2a
diff --git a/Android.bp b/Android.bp
index 7bc9bd8..2d62393 100644
--- a/Android.bp
+++ b/Android.bp
@@ -13187,6 +13187,7 @@
         "src/trace_processor/perfetto_sql/stdlib/sched/time_in_state.sql",
         "src/trace_processor/perfetto_sql/stdlib/slices/cpu_time.sql",
         "src/trace_processor/perfetto_sql/stdlib/slices/flat_slices.sql",
+        "src/trace_processor/perfetto_sql/stdlib/slices/hierarchy.sql",
         "src/trace_processor/perfetto_sql/stdlib/slices/slices.sql",
         "src/trace_processor/perfetto_sql/stdlib/slices/with_context.sql",
         "src/trace_processor/perfetto_sql/stdlib/stack_trace/jit.sql",
diff --git a/BUILD b/BUILD
index ad83cbe..8c8672f 100644
--- a/BUILD
+++ b/BUILD
@@ -2741,6 +2741,7 @@
     srcs = [
         "src/trace_processor/perfetto_sql/stdlib/slices/cpu_time.sql",
         "src/trace_processor/perfetto_sql/stdlib/slices/flat_slices.sql",
+        "src/trace_processor/perfetto_sql/stdlib/slices/hierarchy.sql",
         "src/trace_processor/perfetto_sql/stdlib/slices/slices.sql",
         "src/trace_processor/perfetto_sql/stdlib/slices/with_context.sql",
     ],
diff --git a/src/trace_processor/perfetto_sql/stdlib/slices/BUILD.gn b/src/trace_processor/perfetto_sql/stdlib/slices/BUILD.gn
index f69eafd..e4aba7a 100644
--- a/src/trace_processor/perfetto_sql/stdlib/slices/BUILD.gn
+++ b/src/trace_processor/perfetto_sql/stdlib/slices/BUILD.gn
@@ -18,6 +18,7 @@
   sources = [
     "cpu_time.sql",
     "flat_slices.sql",
+    "hierarchy.sql",
     "slices.sql",
     "with_context.sql",
   ]
diff --git a/src/trace_processor/perfetto_sql/stdlib/slices/hierarchy.sql b/src/trace_processor/perfetto_sql/stdlib/slices/hierarchy.sql
new file mode 100644
index 0000000..dff6475
--- /dev/null
+++ b/src/trace_processor/perfetto_sql/stdlib/slices/hierarchy.sql
@@ -0,0 +1,94 @@
+--
+-- Copyright 2024 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.
+
+-- Similar to `ancestor_slice`, but returns the slice itself in addition to strict ancestors.
+CREATE PERFETTO FUNCTION _slice_ancestor_and_self(
+  -- Id of the slice.
+  slice_id LONG
+)
+RETURNS TABLE(
+  -- Alias of `slice.id`.
+  id LONG,
+  -- Alias of `slice.type`.
+  type STRING,
+  -- Alias of `slice.ts`.
+  ts LONG,
+  -- Alias of `slice.dur`.
+  dur LONG,
+  -- Alias of `slice.track_id`.
+  track_id LONG,
+  -- Alias of `slice.category`.
+  category STRING,
+  -- Alias of `slice.name`.
+  name STRING,
+  -- Alias of `slice.depth`.
+  depth LONG,
+  -- Alias of `slice.parent_id`.
+  parent_id LONG,
+  -- Alias of `slice.arg_set_id`.
+  arg_set_id LONG,
+  -- Alias of `slice.thread_ts`.
+  thread_ts LONG,
+  -- Alias of `slice.thread_dur`.
+  thread_dur LONG
+) AS
+SELECT
+  id, type, ts, dur, track_id, category, name, depth, parent_id, arg_set_id, thread_ts, thread_dur
+FROM slice
+WHERE id = $slice_id
+UNION ALL
+SELECT
+  id, type, ts, dur, track_id, category, name, depth, parent_id, arg_set_id, thread_ts, thread_dur
+FROM ancestor_slice($slice_id);
+
+-- Similar to `descendant_slice`, but returns the slice itself in addition to strict descendants.
+CREATE PERFETTO FUNCTION _slice_descendant_and_self(
+  -- Id of the slice.
+  slice_id LONG
+)
+RETURNS TABLE(
+  -- Alias of `slice.id`.
+  id LONG,
+  -- Alias of `slice.type`.
+  type STRING,
+  -- Alias of `slice.ts`.
+  ts LONG,
+  -- Alias of `slice.dur`.
+  dur LONG,
+  -- Alias of `slice.track_id`.
+  track_id LONG,
+  -- Alias of `slice.category`.
+  category STRING,
+  -- Alias of `slice.name`.
+  name STRING,
+  -- Alias of `slice.depth`.
+  depth LONG,
+  -- Alias of `slice.parent_id`.
+  parent_id LONG,
+  -- Alias of `slice.arg_set_id`.
+  arg_set_id LONG,
+  -- Alias of `slice.thread_ts`.
+  thread_ts LONG,
+  -- Alias of `slice.thread_dur`.
+  thread_dur LONG
+) AS
+SELECT
+  id, type, ts, dur, track_id, category, name, depth, parent_id, arg_set_id, thread_ts, thread_dur
+FROM slice
+WHERE id = $slice_id
+UNION ALL
+SELECT
+  id, type, ts, dur, track_id, category, name, depth, parent_id, arg_set_id, thread_ts, thread_dur
+FROM descendant_slice($slice_id);
\ No newline at end of file
diff --git a/test/trace_processor/diff_tests/stdlib/slices/tests.py b/test/trace_processor/diff_tests/stdlib/slices/tests.py
index 796fcbd..5555c88 100644
--- a/test/trace_processor/diff_tests/stdlib/slices/tests.py
+++ b/test/trace_processor/diff_tests/stdlib/slices/tests.py
@@ -33,7 +33,8 @@
       """,
         out=Csv("""
         "name","ts","dur","depth","thread_name","tid","process_name","pid"
-        "ThreadSlice",5,6,0,"Thread",5,"Process",3
+        "ThreadSlice",5,8,0,"Thread",5,"Process",3
+        "NestedThreadSlice",6,1,1,"Thread",5,"Process",3
       """))
 
   def test_process_slice(self):
@@ -63,7 +64,44 @@
         "name","ts","dur","depth","thread_name","tid","process_name","pid"
         "AsyncSlice",1,2,0,"[NULL]","[NULL]","[NULL]","[NULL]"
         "ProcessSlice",3,4,0,"[NULL]","[NULL]","Process",3
-        "ThreadSlice",5,6,0,"Thread",5,"Process",3
+        "ThreadSlice",5,8,0,"Thread",5,"Process",3
+        "NestedThreadSlice",6,1,1,"Thread",5,"Process",3
+      """))
+
+  # Ancestor / descendant wrappers.
+
+  def test_slice_ancestor_and_self(self):
+    return DiffTestBlueprint(
+        trace=Path('trace.py'),
+        query="""
+        INCLUDE PERFETTO MODULE slices.hierarchy;
+
+        SELECT name, ts, dur, depth
+        FROM _slice_ancestor_and_self(
+          (SELECT id FROM slice WHERE name = 'NestedThreadSlice')
+        );
+      """,
+        out=Csv("""
+        "name","ts","dur","depth"
+        "NestedThreadSlice",6,1,1
+        "ThreadSlice",5,8,0
+      """))
+
+  def test_slice_descendant_and_self(self):
+    return DiffTestBlueprint(
+        trace=Path('trace.py'),
+        query="""
+        INCLUDE PERFETTO MODULE slices.hierarchy;
+
+        SELECT name, ts, dur, depth
+        FROM _slice_descendant_and_self(
+          (SELECT id FROM slice WHERE name = 'ThreadSlice')
+        );
+      """,
+        out=Csv("""
+        "name","ts","dur","depth"
+        "ThreadSlice",5,8,0
+        "NestedThreadSlice",6,1,1
       """))
 
   # Common functions
@@ -118,4 +156,4 @@
         7,33333
         8,46926
         9,17865
-        """))
+        """))
\ No newline at end of file
diff --git a/test/trace_processor/diff_tests/stdlib/slices/trace.py b/test/trace_processor/diff_tests/stdlib/slices/trace.py
index 395051c..79991d1 100644
--- a/test/trace_processor/diff_tests/stdlib/slices/trace.py
+++ b/test/trace_processor/diff_tests/stdlib/slices/trace.py
@@ -36,6 +36,8 @@
 
 trace.add_track_event_slice("AsyncSlice", ts=1, dur=2, track=async_track_id)
 trace.add_track_event_slice("ProcessSlice", ts=3, dur=4, track=process_track)
-trace.add_track_event_slice("ThreadSlice", ts=5, dur=6, track=thread_track)
+trace.add_track_event_slice("ThreadSlice", ts=5, dur=8, track=thread_track)
+trace.add_track_event_slice(
+    "NestedThreadSlice", ts=6, dur=1, track=thread_track)
 
 sys.stdout.buffer.write(trace.trace.SerializeToString())