tp: Add cluster label mapping from cluster_id

- Use cluster_id to determine the cluster type of a CPU instead of the previous heuristic which used only maximum frequency.

Change-Id: Iaf0a7b84f28dda2045fce462435f9ebf864af308
diff --git a/Android.bp b/Android.bp
index 2bcbd0e..fa85cc4 100644
--- a/Android.bp
+++ b/Android.bp
@@ -13258,6 +13258,7 @@
         "src/trace_processor/perfetto_sql/stdlib/android/battery_stats.sql",
         "src/trace_processor/perfetto_sql/stdlib/android/binder.sql",
         "src/trace_processor/perfetto_sql/stdlib/android/broadcasts.sql",
+        "src/trace_processor/perfetto_sql/stdlib/android/cpu/cluster_type.sql",
         "src/trace_processor/perfetto_sql/stdlib/android/critical_blocking_calls.sql",
         "src/trace_processor/perfetto_sql/stdlib/android/device.sql",
         "src/trace_processor/perfetto_sql/stdlib/android/dvfs.sql",
diff --git a/BUILD b/BUILD
index 8339af3..fc4db19 100644
--- a/BUILD
+++ b/BUILD
@@ -2543,6 +2543,14 @@
     ],
 )
 
+# GN target: //src/trace_processor/perfetto_sql/stdlib/android/cpu:cpu
+perfetto_filegroup(
+    name = "src_trace_processor_perfetto_sql_stdlib_android_cpu_cpu",
+    srcs = [
+        "src/trace_processor/perfetto_sql/stdlib/android/cpu/cluster_type.sql",
+    ],
+)
+
 # GN target: //src/trace_processor/perfetto_sql/stdlib/android/frames:frames
 perfetto_filegroup(
     name = "src_trace_processor_perfetto_sql_stdlib_android_frames_frames",
@@ -2893,6 +2901,7 @@
     deps = [
         ":src_trace_processor_perfetto_sql_stdlib_android_android",
         ":src_trace_processor_perfetto_sql_stdlib_android_auto_auto",
+        ":src_trace_processor_perfetto_sql_stdlib_android_cpu_cpu",
         ":src_trace_processor_perfetto_sql_stdlib_android_frames_frames",
         ":src_trace_processor_perfetto_sql_stdlib_android_gpu_gpu",
         ":src_trace_processor_perfetto_sql_stdlib_android_memory_heap_graph_heap_graph",
diff --git a/src/trace_processor/perfetto_sql/stdlib/android/BUILD.gn b/src/trace_processor/perfetto_sql/stdlib/android/BUILD.gn
index b655e53..f51ef75 100644
--- a/src/trace_processor/perfetto_sql/stdlib/android/BUILD.gn
+++ b/src/trace_processor/perfetto_sql/stdlib/android/BUILD.gn
@@ -17,6 +17,7 @@
 perfetto_sql_source_set("android") {
   deps = [
     "auto",
+    "cpu",
     "frames",
     "gpu",
     "memory",
diff --git a/src/trace_processor/perfetto_sql/stdlib/android/cpu/BUILD.gn b/src/trace_processor/perfetto_sql/stdlib/android/cpu/BUILD.gn
new file mode 100644
index 0000000..3afe0df
--- /dev/null
+++ b/src/trace_processor/perfetto_sql/stdlib/android/cpu/BUILD.gn
@@ -0,0 +1,19 @@
+# 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 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("../../../../../../gn/perfetto_sql.gni")
+
+perfetto_sql_source_set("cpu") {
+  sources = [ "cluster_type.sql" ]
+}
diff --git a/src/trace_processor/perfetto_sql/stdlib/android/cpu/cluster_type.sql b/src/trace_processor/perfetto_sql/stdlib/android/cpu/cluster_type.sql
new file mode 100644
index 0000000..f15301f
--- /dev/null
+++ b/src/trace_processor/perfetto_sql/stdlib/android/cpu/cluster_type.sql
@@ -0,0 +1,49 @@
+--
+-- 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.
+
+-- Uses cluster_id which has been calculated using the cpu_capacity in order
+-- to determine the cluster type for cpus with 2, 3 or 4 clusters
+-- indicating whether they are "little", "medium" or "big".
+
+CREATE PERFETTO TABLE _cores AS
+WITH data(cluster_id, cluster_type, cluster_count) AS (
+  VALUES
+    (0, 'little', 2), (1, 'big', 2),
+    (0, 'little', 3), (1, 'medium', 3), (2, 'big', 3),
+    (0, 'little', 4), (1, 'medium', 4), (2, 'medium', 4), (3, 'big', 4)
+)
+SELECT * FROM data;
+
+-- Stores the mapping of a cpu to its cluster type - e.g. little, medium, big.
+-- This cluster type is determined by initially using cpu_capacity from sysfs
+-- and grouping clusters with identical capacities, ordered by size.
+-- In the case that capacities are not present, max frequency is used instead.
+-- If nothing is avaiable, NULL is returned.
+CREATE PERFETTO TABLE android_cpu_cluster_mapping (
+  -- Alias of `cpu.ucpu`.
+  ucpu INT,
+  -- Alias of `cpu.cpu`.
+  cpu INT,
+  -- The cluster type of the CPU.
+  cluster_type STRING
+) AS
+SELECT
+  ucpu,
+  cpu,
+  _cores.cluster_type AS cluster_type
+FROM
+  cpu
+LEFT JOIN _cores ON _cores.cluster_id = cpu.cluster_id
+AND _cores.cluster_count = (SELECT COUNT(DISTINCT cluster_id)FROM cpu)
\ 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 1012f80..57705ad 100644
--- a/test/trace_processor/diff_tests/include_index.py
+++ b/test/trace_processor/diff_tests/include_index.py
@@ -100,6 +100,7 @@
 from diff_tests.parser.translated_args.tests import TranslatedArgs
 from diff_tests.parser.ufs.tests import Ufs
 from diff_tests.parser.zip.tests import Zip
+from diff_tests.stdlib.android.cpu_cluster_tests import CpuClusters
 from diff_tests.stdlib.android.frames_tests import Frames
 from diff_tests.stdlib.android.gpu import AndroidGpu
 from diff_tests.stdlib.android.heap_graph_tests import HeapGraph
@@ -279,6 +280,7 @@
       *AndroidMemory(index_path, 'stdlib/android', 'AndroidMemory').fetch(),
       *AndroidGpu(index_path, 'stdlib/android', 'AndroidGpu').fetch(),
       *AndroidStdlib(index_path, 'stdlib/android', 'AndroidStdlib').fetch(),
+      *CpuClusters(index_path, 'stdlib/android', 'CpuClusters').fetch(),
       *LinuxCpu(index_path, 'stdlib/linux/cpu', 'LinuxCpu').fetch(),
       *DominatorTree(index_path, 'stdlib/graphs', 'DominatorTree').fetch(),
       *CriticalPathTests(index_path, 'stdlib/graphs', 'CriticalPath').fetch(),
diff --git a/test/trace_processor/diff_tests/stdlib/android/cpu_cluster_tests.py b/test/trace_processor/diff_tests/stdlib/android/cpu_cluster_tests.py
new file mode 100644
index 0000000..fc1820b
--- /dev/null
+++ b/test/trace_processor/diff_tests/stdlib/android/cpu_cluster_tests.py
@@ -0,0 +1,314 @@
+#!/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 Path
+from python.generators.diff_tests.testing import Csv, TextProto
+from python.generators.diff_tests.testing import DiffTestBlueprint
+from python.generators.diff_tests.testing import TestSuite
+
+
+class CpuClusters(TestSuite):
+
+  def test_android_cpu_cluster_type_one_core(self):
+    return DiffTestBlueprint(
+        trace=TextProto(r"""
+          packet {
+            cpu_info {
+              cpus {
+                processor: "unknown"
+                capacity: 1024
+                frequencies: 100000
+                frequencies: 200000
+              }
+            }
+          }
+          """),
+        query="""
+          INCLUDE PERFETTO MODULE android.cpu.cluster_type;
+
+          SELECT
+            ucpu,
+            cpu,
+            cluster_type
+          FROM
+            android_cpu_cluster_mapping;
+          """,
+        out=Csv("""
+          "ucpu","cpu","cluster_type"
+          0,0,"[NULL]"
+          """))
+
+  def test_android_cpu_cluster_type_two_core(self):
+    return DiffTestBlueprint(
+        trace=TextProto(r"""
+          packet {
+            cpu_info {
+              cpus {
+                processor: "unknown"
+                capacity: 158
+                frequencies: 100000
+                frequencies: 200000
+              }
+              cpus {
+                processor: "unknown"
+                capacity: 1024
+                frequencies: 500000
+                frequencies: 574000
+              }
+            }
+          }
+          """),
+        query="""
+          INCLUDE PERFETTO MODULE android.cpu.cluster_type;
+
+          SELECT
+            ucpu,
+            cpu,
+            cluster_type
+          FROM
+            android_cpu_cluster_mapping;
+          """,
+        out=Csv("""
+          "ucpu","cpu","cluster_type"
+          0,0,"little"
+          1,1,"big"
+          """))
+
+  def test_android_cpu_cluster_type_three_core(self):
+    return DiffTestBlueprint(
+        trace=TextProto(r"""
+        packet {
+          cpu_info {
+            cpus {
+              processor: "unknown"
+              capacity: 158
+              frequencies: 100000
+              frequencies: 200000
+            }
+            cpus {
+              processor: "unknown"
+              capacity: 550
+              frequencies: 300000
+              frequencies: 400000
+            }
+            cpus {
+              processor: "unknown"
+              capacity: 1024
+              frequencies: 500000
+              frequencies: 574000
+            }
+          }
+        }
+        """),
+        query="""
+        INCLUDE PERFETTO MODULE android.cpu.cluster_type;
+
+        SELECT
+          ucpu,
+          cpu,
+          cluster_type
+        FROM
+          android_cpu_cluster_mapping;
+        """,
+        out=Csv("""
+        "ucpu","cpu","cluster_type"
+        0,0,"little"
+        1,1,"medium"
+        2,2,"big"
+        """))
+
+  def test_android_cpu_cluster_type_four_core(self):
+    return DiffTestBlueprint(
+        trace=TextProto(r"""
+        packet {
+          cpu_info {
+            cpus {
+              processor: "unknown"
+              capacity: 158
+              frequencies: 100000
+              frequencies: 200000
+            }
+            cpus {
+              processor: "unknown"
+              capacity: 550
+              frequencies: 300000
+              frequencies: 400000
+            }
+            cpus {
+              processor: "unknown"
+              capacity: 700
+              frequencies: 400000
+              frequencies: 500000
+            }
+            cpus {
+              processor: "unknown"
+              capacity: 1024
+              frequencies: 500000
+              frequencies: 574000
+            }
+          }
+        }
+        """),
+        query="""
+        INCLUDE PERFETTO MODULE android.cpu.cluster_type;
+
+        SELECT
+          ucpu,
+          cpu,
+          cluster_type
+        FROM
+          android_cpu_cluster_mapping;
+        """,
+        out=Csv("""
+        "ucpu","cpu","cluster_type"
+        0,0,"little"
+        1,1,"medium"
+        2,2,"medium"
+        3,3,"big"
+        """))
+
+  def test_android_cpu_cluster_type_five_core(self):
+    return DiffTestBlueprint(
+        trace=TextProto(r"""
+        packet {
+          cpu_info {
+            cpus {
+              processor: "unknown"
+              capacity: 158
+              frequencies: 100000
+              frequencies: 200000
+            }
+            cpus {
+              processor: "unknown"
+              capacity: 550
+              frequencies: 300000
+              frequencies: 400000
+            }
+            cpus {
+              processor: "unknown"
+              capacity: 700
+              frequencies: 400000
+              frequencies: 500000
+            }
+            cpus {
+              processor: "unknown"
+              capacity: 800
+              frequencies: 500000
+              frequencies: 520000
+            }
+            cpus {
+              processor: "unknown"
+              capacity: 1024
+              frequencies: 500000
+              frequencies: 574000
+            }
+          }
+        }
+        """),
+        query="""
+        INCLUDE PERFETTO MODULE android.cpu.cluster_type;
+
+        SELECT
+          ucpu,
+          cpu,
+          cluster_type
+        FROM
+          android_cpu_cluster_mapping;
+        """,
+        out=Csv("""
+        "ucpu","cpu","cluster_type"
+        0,0,"[NULL]"
+        1,1,"[NULL]"
+        2,2,"[NULL]"
+        3,3,"[NULL]"
+        4,4,"[NULL]"
+        """))
+
+  def test_android_cpu_cluster_type_capacity_not_present(self):
+    return DiffTestBlueprint(
+        trace=TextProto(r"""
+        packet {
+          cpu_info {
+            cpus {
+              processor: "unknown"
+              frequencies: 100000
+              frequencies: 200000
+            }
+            cpus {
+              processor: "unknown"
+              frequencies: 300000
+              frequencies: 400000
+            }
+            cpus {
+              processor: "unknown"
+              frequencies: 500000
+              frequencies: 574000
+            }
+          }
+        }
+        """),
+        query="""
+        INCLUDE PERFETTO MODULE android.cpu.cluster_type;
+
+        SELECT
+          ucpu,
+          cpu,
+          cluster_type
+        FROM
+          android_cpu_cluster_mapping;
+        """,
+        out=Csv("""
+        "ucpu","cpu","cluster_type"
+        0,0,"little"
+        1,1,"medium"
+        2,2,"big"
+        """))
+
+  def test_android_cpu_cluster_type_insufficient_data_to_calculate(self):
+    return DiffTestBlueprint(
+        trace=TextProto(r"""
+        packet {
+          cpu_info {
+            cpus {
+              processor: "unknown"
+              frequencies: 10000
+            }
+            cpus {
+              processor: "unknown"
+              frequencies: 10000
+            }
+            cpus {
+              processor: "unknown"
+              frequencies: 10000
+            }
+          }
+        }
+        """),
+        query="""
+        INCLUDE PERFETTO MODULE android.cpu.cluster_type;
+
+        SELECT
+          ucpu,
+          cpu,
+          cluster_type
+        FROM
+          android_cpu_cluster_mapping;
+        """,
+        out=Csv("""
+        "ucpu","cpu","cluster_type"
+        0,0,"[NULL]"
+        1,1,"[NULL]"
+        2,2,"[NULL]"
+        """))