Android codec_metrics and tests to perfetto
Bug: 286081370
Change-Id: I153dead30ea86501699b010634a20c35140571bf
diff --git a/Android.bp b/Android.bp
index c2f0ee7..756ff91 100644
--- a/Android.bp
+++ b/Android.bp
@@ -4393,6 +4393,7 @@
"protos/perfetto/metrics/android/binder_metric.proto",
"protos/perfetto/metrics/android/camera_metric.proto",
"protos/perfetto/metrics/android/camera_unagg_metric.proto",
+ "protos/perfetto/metrics/android/codec_metrics.proto",
"protos/perfetto/metrics/android/cpu_metric.proto",
"protos/perfetto/metrics/android/display_metrics.proto",
"protos/perfetto/metrics/android/dma_heap_metric.proto",
@@ -4469,6 +4470,7 @@
"protos/perfetto/metrics/android/binder_metric.proto",
"protos/perfetto/metrics/android/camera_metric.proto",
"protos/perfetto/metrics/android/camera_unagg_metric.proto",
+ "protos/perfetto/metrics/android/codec_metrics.proto",
"protos/perfetto/metrics/android/cpu_metric.proto",
"protos/perfetto/metrics/android/display_metrics.proto",
"protos/perfetto/metrics/android/dma_heap_metric.proto",
@@ -4527,6 +4529,7 @@
"protos/perfetto/metrics/android/binder_metric.proto",
"protos/perfetto/metrics/android/camera_metric.proto",
"protos/perfetto/metrics/android/camera_unagg_metric.proto",
+ "protos/perfetto/metrics/android/codec_metrics.proto",
"protos/perfetto/metrics/android/cpu_metric.proto",
"protos/perfetto/metrics/android/display_metrics.proto",
"protos/perfetto/metrics/android/dma_heap_metric.proto",
@@ -10187,6 +10190,7 @@
"src/trace_processor/metrics/sql/android/android_task_names.sql",
"src/trace_processor/metrics/sql/android/android_trace_quality.sql",
"src/trace_processor/metrics/sql/android/android_trusty_workqueues.sql",
+ "src/trace_processor/metrics/sql/android/codec_metrics.sql",
"src/trace_processor/metrics/sql/android/composer_execution.sql",
"src/trace_processor/metrics/sql/android/composition_layers.sql",
"src/trace_processor/metrics/sql/android/counter_span_view_merged.sql",
diff --git a/BUILD b/BUILD
index 28c8e18..ae675d7 100644
--- a/BUILD
+++ b/BUILD
@@ -1842,6 +1842,7 @@
"src/trace_processor/metrics/sql/android/android_task_names.sql",
"src/trace_processor/metrics/sql/android/android_trace_quality.sql",
"src/trace_processor/metrics/sql/android/android_trusty_workqueues.sql",
+ "src/trace_processor/metrics/sql/android/codec_metrics.sql",
"src/trace_processor/metrics/sql/android/composer_execution.sql",
"src/trace_processor/metrics/sql/android/composition_layers.sql",
"src/trace_processor/metrics/sql/android/counter_span_view_merged.sql",
@@ -4016,6 +4017,7 @@
"protos/perfetto/metrics/android/binder_metric.proto",
"protos/perfetto/metrics/android/camera_metric.proto",
"protos/perfetto/metrics/android/camera_unagg_metric.proto",
+ "protos/perfetto/metrics/android/codec_metrics.proto",
"protos/perfetto/metrics/android/cpu_metric.proto",
"protos/perfetto/metrics/android/display_metrics.proto",
"protos/perfetto/metrics/android/dma_heap_metric.proto",
diff --git a/protos/perfetto/metrics/android/BUILD.gn b/protos/perfetto/metrics/android/BUILD.gn
index 90ca5af..a9e9d2c 100644
--- a/protos/perfetto/metrics/android/BUILD.gn
+++ b/protos/perfetto/metrics/android/BUILD.gn
@@ -29,6 +29,7 @@
"binder_metric.proto",
"camera_metric.proto",
"camera_unagg_metric.proto",
+ "codec_metrics.proto",
"cpu_metric.proto",
"display_metrics.proto",
"dma_heap_metric.proto",
diff --git a/protos/perfetto/metrics/android/codec_metrics.proto b/protos/perfetto/metrics/android/codec_metrics.proto
new file mode 100644
index 0000000..d752b19
--- /dev/null
+++ b/protos/perfetto/metrics/android/codec_metrics.proto
@@ -0,0 +1,71 @@
+/*
+ * 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.
+ */
+
+syntax = "proto2";
+
+package perfetto.protos;
+
+import "protos/perfetto/metrics/android/cpu_metric.proto";
+
+// These metrices collects various function and thread
+// usage within androd's codec framework. This can give an
+// idea about performance and cpu usage when using codec
+// framework
+message AndroidCodecMetrics {
+
+ // profile details in messages
+ message Detail {
+ // function thread
+ optional string thread_name = 1;
+ // total time
+ optional int64 total_cpu_ns = 2;
+ // CPU time ( time 'Running' on cpu)
+ optional int64 running_cpu_ns = 3;
+ }
+
+ // These are traces and could indicate framework queue latency
+ // buffer-packing, buffer-preprocess, buffer post-process
+ // latency etc. These metrics are monitored to track quality.
+ // Same message can come from different
+ // processes.
+ message CodecFunction {
+ // codec string
+ optional string codec_string = 1;
+ // process_name
+ optional string process_name = 2;
+ // details
+ optional Detail detail = 3;
+ }
+
+ // This message can indicate overall cpu
+ // utilization of codec framework threads.
+ message CpuUsage {
+ // name of process using codec framework
+ optional string process_name = 1;
+ // name of the codec thread
+ optional string thread_name = 2;
+ // total cpu usage of the codec thread
+ optional int64 thread_cpu_us = 3;
+ // can be number of codec framework thread
+ optional uint32 num_threads = 4;
+ // core type data info used by codec thread
+ repeated AndroidCpuMetric.CoreTypeData core_data = 5;
+ }
+
+ repeated CpuUsage cpu_usage = 1;
+ repeated CodecFunction codec_function = 2;
+
+}
\ No newline at end of file
diff --git a/protos/perfetto/metrics/metrics.proto b/protos/perfetto/metrics/metrics.proto
index 1beec18..6e7ef02 100644
--- a/protos/perfetto/metrics/metrics.proto
+++ b/protos/perfetto/metrics/metrics.proto
@@ -22,6 +22,7 @@
import "protos/perfetto/metrics/android/batt_metric.proto";
import "protos/perfetto/metrics/android/android_sysui_notifications_blocking_calls_metric.proto";
import "protos/perfetto/metrics/android/android_blocking_calls_cuj_metric.proto";
+import "protos/perfetto/metrics/android/codec_metrics.proto";
import "protos/perfetto/metrics/android/cpu_metric.proto";
import "protos/perfetto/metrics/android/camera_metric.proto";
import "protos/perfetto/metrics/android/camera_unagg_metric.proto";
@@ -242,6 +243,9 @@
optional AndroidSysUINotificationsBlockingCallsMetric android_sysui_notifications_blocking_calls_metric = 51;
+ // Metrics to track codec framework.
+ optional AndroidCodecMetrics codec_metrics = 52;
+
// Demo extensions.
extensions 450 to 499;
diff --git a/protos/perfetto/metrics/perfetto_merged_metrics.proto b/protos/perfetto/metrics/perfetto_merged_metrics.proto
index 5428e13..3f983bc 100644
--- a/protos/perfetto/metrics/perfetto_merged_metrics.proto
+++ b/protos/perfetto/metrics/perfetto_merged_metrics.proto
@@ -419,6 +419,59 @@
// End of protos/perfetto/metrics/android/cpu_metric.proto
+// Begin of protos/perfetto/metrics/android/codec_metrics.proto
+
+// These metrices collects various function and thread
+// usage within androd's codec framework. This can give an
+// idea about performance and cpu usage when using codec
+// framework
+message AndroidCodecMetrics {
+
+ // profile details in messages
+ message Detail {
+ // function thread
+ optional string thread_name = 1;
+ // total time
+ optional int64 total_cpu_ns = 2;
+ // CPU time ( time 'Running' on cpu)
+ optional int64 running_cpu_ns = 3;
+ }
+
+ // These are traces and could indicate framework queue latency
+ // buffer-packing, buffer-preprocess, buffer post-process
+ // latency etc. These metrics are monitored to track quality.
+ // Same message can come from different
+ // processes.
+ message CodecFunction {
+ // codec string
+ optional string codec_string = 1;
+ // process_name
+ optional string process_name = 2;
+ // details
+ optional Detail detail = 3;
+ }
+
+ // This message can indicate overall cpu
+ // utilization of codec framework threads.
+ message CpuUsage {
+ // name of process using codec framework
+ optional string process_name = 1;
+ // name of the codec thread
+ optional string thread_name = 2;
+ // total cpu usage of the codec thread
+ optional int64 thread_cpu_us = 3;
+ // can be number of codec framework thread
+ optional uint32 num_threads = 4;
+ // core type data info used by codec thread
+ repeated AndroidCpuMetric.CoreTypeData core_data = 5;
+ }
+
+ repeated CpuUsage cpu_usage = 1;
+ repeated CodecFunction codec_function = 2;
+
+}
+// End of protos/perfetto/metrics/android/codec_metrics.proto
+
// Begin of protos/perfetto/metrics/android/display_metrics.proto
message AndroidDisplayMetrics {
@@ -2247,6 +2300,9 @@
optional AndroidSysUINotificationsBlockingCallsMetric android_sysui_notifications_blocking_calls_metric = 51;
+ // Metrics to track codec framework.
+ optional AndroidCodecMetrics codec_metrics = 52;
+
// Demo extensions.
extensions 450 to 499;
diff --git a/python/perfetto/trace_processor/metrics.descriptor b/python/perfetto/trace_processor/metrics.descriptor
index cfe58ff..c8673ba 100644
--- a/python/perfetto/trace_processor/metrics.descriptor
+++ b/python/perfetto/trace_processor/metrics.descriptor
Binary files differ
diff --git a/src/trace_processor/metrics/sql/android/BUILD.gn b/src/trace_processor/metrics/sql/android/BUILD.gn
index 8884dd8..147b688 100644
--- a/src/trace_processor/metrics/sql/android/BUILD.gn
+++ b/src/trace_processor/metrics/sql/android/BUILD.gn
@@ -62,6 +62,7 @@
"composition_layers.sql",
"counter_span_view_merged.sql",
"cpu_info.sql",
+ "codec_metrics.sql",
"display_metrics.sql",
"frame_missed.sql",
"g2d.sql",
diff --git a/src/trace_processor/metrics/sql/android/codec_metrics.sql b/src/trace_processor/metrics/sql/android/codec_metrics.sql
new file mode 100644
index 0000000..831cd8e
--- /dev/null
+++ b/src/trace_processor/metrics/sql/android/codec_metrics.sql
@@ -0,0 +1,197 @@
+--
+-- Copyright 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
+--
+-- 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('android/android_cpu.sql');
+
+-- Attaching thread proto with media thread name
+DROP VIEW IF EXISTS core_type_proto_per_thread_name;
+CREATE VIEW core_type_proto_per_thread_name AS
+SELECT
+thread.name as thread_name,
+core_type_proto_per_thread.proto AS proto
+FROM core_type_proto_per_thread
+JOIN thread using(utid)
+WHERE thread.name = 'MediaCodec_loop' OR
+ thread.name = 'CodecLooper'
+GROUP BY thread.name;
+
+-- aggregate all cpu the codec threads
+DROP VIEW IF EXISTS codec_per_thread_cpu_use;
+CREATE VIEW codec_per_thread_cpu_use AS
+SELECT
+ upid,
+ process.name AS process_name,
+ thread.name AS thread_name,
+ CAST(SUM(sched.dur) / 1e3 as INT64) AS cpu_time_us,
+ COUNT(DISTINCT utid) AS num_threads
+FROM sched
+JOIN thread USING(utid)
+JOIN process USING(upid)
+WHERE thread.name = 'MediaCodec_loop' OR
+ thread.name = 'CodecLooper'
+GROUP BY process.name, thread.name;
+
+-- All process that has codec thread
+DROP VIEW IF EXISTS android_codec_process;
+CREATE VIEW android_codec_process AS
+SELECT
+ upid,
+ process.name as process_name
+FROM sched
+JOIN thread using(utid)
+JOIN process using(upid)
+WHERE thread.name = 'MediaCodec_loop' OR
+ thread.name = 'CodecLooper'
+GROUP BY process_name;
+
+-- Total cpu for a process
+DROP VIEW IF EXISTS codec_total_per_process_cpu_use;
+CREATE VIEW codec_total_per_process_cpu_use AS
+SELECT
+ upid,
+ process_name,
+ CAST(SUM(sched.dur) / 1e3 as INT64) AS media_process_cpu_time_us
+FROM sched
+JOIN thread using(utid)
+JOIN android_codec_process using(upid)
+GROUP BY process_name;
+
+-- Joining total process with media thread table
+DROP VIEW IF EXISTS codec_per_process_thread_cpu_use;
+CREATE VIEW codec_per_process_thread_cpu_use AS
+SELECT
+ *
+FROM codec_total_per_process_cpu_use
+JOIN codec_per_thread_cpu_use using(process_name);
+
+-- Traces are collected using specific traits in codec framework. These traits
+-- are mapped to actual names of slices and then combined with other tables to
+-- give out the total_cpu and cpu_running time.
+
+-- Utility functions to trim codec trace string
+SELECT CREATE_FUNCTION(
+ -- extract the string demilited by the limiter
+ 'EXTRACT_CODEC_STRING(slice_name STRING, limiter STRING)',
+ -- output the result string
+ 'STRING',
+ -- delimit with the first occurrence
+ 'select case when instr($slice_name, $limiter) > 0 then
+ substr($slice_name, 1, instr($slice_name, $limiter) - 1) else
+ $slice_name end'
+);
+
+-- traits strings from codec framework
+DROP TABLE IF EXISTS trace_trait_table;
+CREATE TABLE trace_trait_table(
+ trace_trait varchar(100));
+insert into trace_trait_table (trace_trait) values
+ ('MediaCodec'),
+ ('CCodec'),
+ ('C2PooledBlockPool'),
+ ('C2BufferQueueBlockPool'),
+ ('Codec2'),
+ ('ACodec'),
+ ('FrameDecoder');
+
+-- Maps traits to slice strings. Any string with '@' is considered to indicate
+-- the same trace with different information.Hence those strings are delimited
+-- using '@' and considered as part of single trace.
+DROP VIEW IF EXISTS codec_slices;
+CREATE VIEW codec_slices AS
+SELECT
+ DISTINCT EXTRACT_CODEC_STRING(slice.name, '@') as codec_slice_string
+FROM slice
+JOIN trace_trait_table ON slice.name glob '*' || trace_trait || '*';
+
+-- combine slice and thread info
+DROP VIEW IF EXISTS slice_with_utid;
+CREATE VIEW slice_with_utid AS
+SELECT
+ EXTRACT_CODEC_STRING(slice.name, '@') as codec_string,
+ ts,
+ dur,
+ upid,
+ slice.name as slice_name,
+ slice.id as slice_id, utid,
+ thread.name as thread_name
+FROM slice
+JOIN thread_track ON thread_track.id = slice.track_id
+JOIN thread USING (utid);
+
+-- Combine with thread_state info
+DROP TABLE IF EXISTS slice_thread_state_breakdown;
+CREATE VIRTUAL TABLE slice_thread_state_breakdown
+USING SPAN_LEFT_JOIN(
+ slice_with_utid PARTITIONED utid,
+ thread_state PARTITIONED utid
+);
+
+-- Get cpu_running_time for all the slices of interest
+DROP VIEW IF EXISTS slice_cpu_running;
+CREATE VIEW slice_cpu_running AS
+SELECT
+ codec_string,
+ sum(dur) as cpu_time,
+ sum(case when state = 'Running' then dur else 0 end) as cpu_run_ns,
+ thread_name,
+ process.name as process_name,
+ slice_id,
+ slice_name
+FROM slice_thread_state_breakdown
+LEFT JOIN process using(upid)
+where codec_string in (select codec_slice_string from codec_slices)
+GROUP BY codec_string, thread_name, process_name;
+
+
+-- Generate proto for the trace
+DROP VIEW IF EXISTS metrics_per_slice_type;
+CREATE VIEW metrics_per_slice_type AS
+SELECT
+ process_name,
+ codec_string,
+ AndroidCodecMetrics_Detail(
+ 'thread_name', thread_name,
+ 'total_cpu_ns', CAST(cpu_time as INT64),
+ 'running_cpu_ns', CAST(cpu_run_ns as INT64)
+ ) AS proto
+FROM slice_cpu_running;
+
+-- Generating codec framework cpu metric
+DROP VIEW IF EXISTS codec_metrics_output;
+CREATE VIEW codec_metrics_output AS
+SELECT AndroidCodecMetrics(
+ 'cpu_usage', (
+ SELECT RepeatedField(
+ AndroidCodecMetrics_CpuUsage(
+ 'process_name', process_name,
+ 'thread_name', thread_name,
+ 'thread_cpu_us', CAST((cpu_time_us) as INT64),
+ 'num_threads', num_threads,
+ 'core_data', core_type_proto_per_thread_name.proto
+ )
+ ) FROM codec_per_process_thread_cpu_use
+ JOIN core_type_proto_per_thread_name using(thread_name)
+ ),
+ 'codec_function', (
+ SELECT RepeatedField (
+ AndroidCodecMetrics_CodecFunction(
+ 'codec_string', codec_string,
+ 'process_name', process_name,
+ 'detail', metrics_per_slice_type.proto
+ )
+ ) FROM metrics_per_slice_type
+ )
+);
\ No newline at end of file
diff --git a/test/data/codec-framedecoder-trace.pftrace.sha256 b/test/data/codec-framedecoder-trace.pftrace.sha256
new file mode 100644
index 0000000..9f6d046
--- /dev/null
+++ b/test/data/codec-framedecoder-trace.pftrace.sha256
@@ -0,0 +1 @@
+4b5b272aee9527e57c7cc369e0471eff8616ad2c8e40ce30f870f697640b0be2
\ No newline at end of file
diff --git a/test/trace_processor/diff_tests/codecs/codec-framedecoder-trace.out b/test/trace_processor/diff_tests/codecs/codec-framedecoder-trace.out
new file mode 100644
index 0000000..77b814d
--- /dev/null
+++ b/test/trace_processor/diff_tests/codecs/codec-framedecoder-trace.out
@@ -0,0 +1,91 @@
+codec_metrics {
+ cpu_usage {
+ process_name: "/system/bin/mediaserver"
+ thread_name: "CodecLooper"
+ thread_cpu_us: 40782
+ num_threads: 1
+ core_data {
+ type: "bigger"
+ metrics {
+ mcycles: 14
+ runtime_ns: 6151247
+ min_freq_khz: 1996800
+ max_freq_khz: 2400000
+ avg_freq_khz: 2399000
+ }
+ }
+ core_data {
+ type: "little"
+ metrics {
+ mcycles: 60
+ runtime_ns: 34631513
+ min_freq_khz: 1804800
+ max_freq_khz: 1804800
+ avg_freq_khz: 1804000
+ }
+ }
+ }
+ codec_function {
+ codec_string: "C2PooledBlockPool::fetchLinearBlock"
+ process_name: "/system/bin/mediaserver"
+ detail {
+ thread_name: "CodecLooper"
+ total_cpu_ns: 6505730
+ running_cpu_ns: 6224689
+ }
+ }
+ codec_function {
+ codec_string: "C2PooledBlockPool::fetchLinearBlock"
+ process_name: "/system/bin/mediaserver"
+ detail {
+ thread_name: "HwBinder:1465_4"
+ total_cpu_ns: 805417
+ running_cpu_ns: 805417
+ }
+ }
+ codec_function {
+ codec_string: "CCodecBufferChannel::onWorkDone(c2.android.hevc.decoder#264"
+ process_name: "/system/bin/mediaserver"
+ detail {
+ thread_name: "CodecLooper"
+ total_cpu_ns: 34476253
+ running_cpu_ns: 19314740
+ }
+ }
+ codec_function {
+ codec_string: "CCodecBufferChannel::queue(c2.android.hevc.decoder#264"
+ process_name: "/system/bin/mediaserver"
+ detail {
+ thread_name: "ALooper"
+ total_cpu_ns: 6599844
+ running_cpu_ns: 2656718
+ }
+ }
+ codec_function {
+ codec_string: "FrameDecoder::ColorConverter"
+ process_name: "/system/bin/mediaserver"
+ detail {
+ thread_name: "binder:1465_4"
+ total_cpu_ns: 18414272
+ running_cpu_ns: 10807813
+ }
+ }
+ codec_function {
+ codec_string: "FrameDecoder::ExtractFrame"
+ process_name: "/system/bin/mediaserver"
+ detail {
+ thread_name: "binder:1465_4"
+ total_cpu_ns: 226664606
+ running_cpu_ns: 17917404
+ }
+ }
+ codec_function {
+ codec_string: "FrameDecoderBenchmark#frameDecoderBenchmarkTest"
+ process_name: "android.platform.test.scenario"
+ detail {
+ thread_name: "roidJUnitRunner"
+ total_cpu_ns: -1
+ running_cpu_ns: -1
+ }
+ }
+}
diff --git a/test/trace_processor/diff_tests/codecs/tests.py b/test/trace_processor/diff_tests/codecs/tests.py
new file mode 100644
index 0000000..a475b34
--- /dev/null
+++ b/test/trace_processor/diff_tests/codecs/tests.py
@@ -0,0 +1,28 @@
+#!/usr/bin/env python3
+# 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 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, DataPath, Metric
+from python.generators.diff_tests.testing import Csv, Json, TextProto
+from python.generators.diff_tests.testing import DiffTestBlueprint
+from python.generators.diff_tests.testing import TestSuite
+
+
+class Codecs(TestSuite):
+
+ def test_codecs_framedecoder_metric(self):
+ return DiffTestBlueprint(
+ trace=DataPath('codec-framedecoder-trace.pftrace'),
+ query=Metric('codec_metrics'),
+ out=Path('codec-framedecoder-trace.out'))
diff --git a/test/trace_processor/diff_tests/include_index.py b/test/trace_processor/diff_tests/include_index.py
index 3e51524..b4d7ded 100644
--- a/test/trace_processor/diff_tests/include_index.py
+++ b/test/trace_processor/diff_tests/include_index.py
@@ -40,6 +40,7 @@
from diff_tests.chrome.tests_rail_modes import ChromeRailModes
from diff_tests.chrome.tests_scroll_jank import ChromeScrollJank
from diff_tests.chrome.tests_touch_gesture import ChromeTouchGesture
+from diff_tests.codecs.tests import Codecs
from diff_tests.cros.tests import Cros
from diff_tests.dynamic.tests import Dynamic
from diff_tests.fs.tests import Fs
@@ -111,6 +112,7 @@
*ChromeProcesses(index_path, 'chrome', 'ChromeProcesses').fetch(),
*ChromeArgs(index_path, 'chrome', 'ChromeArgs').fetch(),
*Chrome(index_path, 'chrome', 'Chrome').fetch(),
+ *Codecs(index_path, 'codecs', 'Codecs').fetch(),
*Cros(index_path, 'cros', 'Cros').fetch(),
*Dynamic(index_path, 'dynamic', 'Dynamic').fetch(),
*EntityStateResidency(index_path, 'power',