stdlib: Add freq and idle state CPU slices

Adds new files under cpu/freq.sql and cpu/idle.sql that respectively
correspond to every frequency change or every idle state change on every
CPU.

Bug: 329507878
Change-Id: I86571bac470bae31caf770f8d514caf97f92bc1d
Signed-off-by: Samuel Wu <wusamuel@google.com>
diff --git a/Android.bp b/Android.bp
index 3832040..8431325 100644
--- a/Android.bp
+++ b/Android.bp
@@ -12398,6 +12398,8 @@
         "src/trace_processor/perfetto_sql/stdlib/common/timestamps.sql",
         "src/trace_processor/perfetto_sql/stdlib/counters/intervals.sql",
         "src/trace_processor/perfetto_sql/stdlib/cpu/cpus.sql",
+        "src/trace_processor/perfetto_sql/stdlib/cpu/freq.sql",
+        "src/trace_processor/perfetto_sql/stdlib/cpu/idle.sql",
         "src/trace_processor/perfetto_sql/stdlib/cpu/size.sql",
         "src/trace_processor/perfetto_sql/stdlib/deprecated/v42/common/args.sql",
         "src/trace_processor/perfetto_sql/stdlib/deprecated/v42/common/counters.sql",
diff --git a/BUILD b/BUILD
index b5ce58d..b6888b5 100644
--- a/BUILD
+++ b/BUILD
@@ -2466,6 +2466,8 @@
     name = "src_trace_processor_perfetto_sql_stdlib_cpu_cpu",
     srcs = [
         "src/trace_processor/perfetto_sql/stdlib/cpu/cpus.sql",
+        "src/trace_processor/perfetto_sql/stdlib/cpu/freq.sql",
+        "src/trace_processor/perfetto_sql/stdlib/cpu/idle.sql",
         "src/trace_processor/perfetto_sql/stdlib/cpu/size.sql",
     ],
 )
diff --git a/src/trace_processor/perfetto_sql/stdlib/cpu/BUILD.gn b/src/trace_processor/perfetto_sql/stdlib/cpu/BUILD.gn
index e17e6b2..28fc5a0 100644
--- a/src/trace_processor/perfetto_sql/stdlib/cpu/BUILD.gn
+++ b/src/trace_processor/perfetto_sql/stdlib/cpu/BUILD.gn
@@ -17,6 +17,8 @@
 perfetto_sql_source_set("cpu") {
   sources = [
     "cpus.sql",
+    "freq.sql",
+    "idle.sql",
     "size.sql",
   ]
 }
diff --git a/src/trace_processor/perfetto_sql/stdlib/cpu/freq.sql b/src/trace_processor/perfetto_sql/stdlib/cpu/freq.sql
new file mode 100644
index 0000000..c0226bf
--- /dev/null
+++ b/src/trace_processor/perfetto_sql/stdlib/cpu/freq.sql
@@ -0,0 +1,51 @@
+--
+-- 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.
+
+INCLUDE PERFETTO MODULE counters.intervals;
+
+-- Counter information for each frequency change for each CPU. Finds each time
+-- region where a CPU frequency is constant.
+CREATE PERFETTO TABLE cpu_freq_counters(
+  -- Counter id.
+  id INT,
+  -- Joinable with 'counter_track.id'.
+  track_id INT,
+  -- Starting timestamp of the counter
+  ts LONG,
+  -- Duration in which counter is constant and frequency doesn't change.
+  dur INT,
+  -- Frequency in kHz of the CPU that corresponds to this counter. NULL if not
+  -- found or undefined.
+  freq INT,
+  -- CPU that corresponds to this counter.
+  cpu INT
+) AS
+SELECT
+  count_w_dur.id,
+  count_w_dur.track_id,
+  count_w_dur.ts,
+  count_w_dur.dur,
+  count_w_dur.value as freq,
+  cct.cpu
+FROM
+counter_leading_intervals!((
+  SELECT c.*
+  FROM counter c
+  JOIN cpu_counter_track cct
+  ON cct.id = c.track_id AND cct.name = 'cpufreq'
+)) count_w_dur
+JOIN cpu_counter_track cct
+ON track_id = cct.id;
+
diff --git a/src/trace_processor/perfetto_sql/stdlib/cpu/idle.sql b/src/trace_processor/perfetto_sql/stdlib/cpu/idle.sql
new file mode 100644
index 0000000..7f837a2
--- /dev/null
+++ b/src/trace_processor/perfetto_sql/stdlib/cpu/idle.sql
@@ -0,0 +1,53 @@
+--
+-- 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.
+
+INCLUDE PERFETTO MODULE counters.intervals;
+
+-- Counter information for each idle state change for each CPU. Finds each time
+-- region where a CPU idle state is constant.
+CREATE PERFETTO TABLE cpu_idle_counters(
+  -- Counter id.
+  id INT,
+  -- Joinable with 'counter_track.id'.
+  track_id INT,
+  -- Starting timestamp of the counter.
+  ts LONG,
+  -- Duration in which the counter is contant and idle state doesn't change.
+  dur INT,
+  -- Idle state of the CPU that corresponds to this counter. An idle state of -1
+  -- is defined to be active state for the CPU, and the larger the integer, the
+  -- deeper the idle state of the CPU. NULL if not found or undefined.
+  idle INT,
+  -- CPU that corresponds to this counter.
+  cpu INT
+)
+AS
+SELECT
+  count_w_dur.id,
+  count_w_dur.track_id,
+  count_w_dur.ts,
+  count_w_dur.dur,
+  IIF(count_w_dur.value = 4294967295, -1, count_w_dur.value) AS idle,
+  cct.cpu
+FROM
+counter_leading_intervals!((
+  SELECT c.*
+  FROM counter c
+  JOIN cpu_counter_track cct
+  ON cct.id = c.track_id and cct.name = 'cpuidle'
+)) count_w_dur
+JOIN cpu_counter_track cct
+ON track_id = cct.id;
+
diff --git a/test/data/android_cpu_eos.pb.sha256 b/test/data/android_cpu_eos.pb.sha256
new file mode 100644
index 0000000..15f2572
--- /dev/null
+++ b/test/data/android_cpu_eos.pb.sha256
@@ -0,0 +1 @@
+68377df0bb4fc55a26e2da4285aa441b6d1d3c4e99a192a7bc80876834954c2b
\ No newline at end of file
diff --git a/test/trace_processor/diff_tests/include_index.py b/test/trace_processor/diff_tests/include_index.py
index b65f158..5924e04 100644
--- a/test/trace_processor/diff_tests/include_index.py
+++ b/test/trace_processor/diff_tests/include_index.py
@@ -97,6 +97,7 @@
 from diff_tests.stdlib.common.tests import StdlibCommon
 from diff_tests.stdlib.common.tests import StdlibCommon
 from diff_tests.stdlib.counters.tests import StdlibCounterIntervals
+from diff_tests.stdlib.cpu.tests import CpuStdlib
 from diff_tests.stdlib.dynamic_tables.tests import DynamicTables
 from diff_tests.stdlib.graphs.dominator_tree_tests import DominatorTree
 from diff_tests.stdlib.graphs.search_tests import GraphSearchTests
@@ -242,6 +243,7 @@
 
   stdlib_tests = [
       *AndroidStdlib(index_path, 'stdlib/android', 'AndroidStdlib').fetch(),
+      *CpuStdlib(index_path, 'stdlib/cpu', 'CpuStdlib').fetch(),
       *DominatorTree(index_path, 'stdlib/graphs', 'DominatorTree').fetch(),
       *Frames(index_path, 'stdlib/android', 'Frames').fetch(),
       *GraphSearchTests(index_path, 'stdlib/graphs',
diff --git a/test/trace_processor/diff_tests/stdlib/cpu/tests.py b/test/trace_processor/diff_tests/stdlib/cpu/tests.py
new file mode 100644
index 0000000..9b5d75b
--- /dev/null
+++ b/test/trace_processor/diff_tests/stdlib/cpu/tests.py
@@ -0,0 +1,83 @@
+#!/usr/bin/env python3
+# Copyright (C) 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 a
+#
+#      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.
+
+from python.generators.diff_tests.testing import Csv, Path, DataPath
+from python.generators.diff_tests.testing import DiffTestBlueprint
+from python.generators.diff_tests.testing import TestSuite
+
+
+class CpuStdlib(TestSuite):
+  # Test CPU frequency counter grouping.
+  def test_cpu_eos_counters_freq(self):
+    return DiffTestBlueprint(
+        trace=DataPath('android_cpu_eos.pb'),
+        query=("""
+             INCLUDE PERFETTO MODULE cpu.freq;
+             select
+               track_id,
+               freq,
+               cpu,
+               sum(dur) as dur
+             from cpu_freq_counters
+             GROUP BY freq, cpu
+             """),
+        out=Csv("""
+            "track_id","freq","cpu","dur"
+            33,614400,0,4755967239
+            34,614400,1,4755971561
+            35,614400,2,4755968228
+            36,614400,3,4755964320
+            33,864000,0,442371195
+            34,864000,1,442397134
+            35,864000,2,442417916
+            36,864000,3,442434530
+            33,1363200,0,897122398
+            34,1363200,1,897144167
+            35,1363200,2,897180154
+            36,1363200,3,897216772
+            33,1708800,0,2553979530
+            34,1708800,1,2553923073
+            35,1708800,2,2553866772
+            36,1708800,3,2553814688
+            """))
+  # Test CPU idle state counter grouping.
+  def test_cpu_eos_counters_idle(self):
+    return DiffTestBlueprint(
+        trace=DataPath('android_cpu_eos.pb'),
+        query=("""
+             INCLUDE PERFETTO MODULE cpu.idle;
+             select
+               track_id,
+               idle,
+               cpu,
+               sum(dur) as dur
+             from cpu_idle_counters
+             GROUP BY idle, cpu
+             """),
+        out=Csv("""
+             "track_id","idle","cpu","dur"
+             0,-1,0,2839828332
+             37,-1,1,1977033843
+             32,-1,2,1800498713
+             1,-1,3,1884366297
+             0,0,0,1833971336
+             37,0,1,2285260950
+             32,0,2,1348416182
+             1,0,3,1338508968
+             0,1,0,4013820433
+             37,1,1,4386917600
+             32,1,2,5532102915
+             1,1,3,5462026920
+            """))