Merge "ui: add plugin for cpuidle time in state" into main
diff --git a/ui/src/plugins/dev.perfetto.CpuidleTimeInState/OWNERS b/ui/src/plugins/dev.perfetto.CpuidleTimeInState/OWNERS
new file mode 100644
index 0000000..4dd7964
--- /dev/null
+++ b/ui/src/plugins/dev.perfetto.CpuidleTimeInState/OWNERS
@@ -0,0 +1 @@
+zhaon@google.com
\ No newline at end of file
diff --git a/ui/src/plugins/dev.perfetto.CpuidleTimeInState/index.ts b/ui/src/plugins/dev.perfetto.CpuidleTimeInState/index.ts
new file mode 100644
index 0000000..b599e01
--- /dev/null
+++ b/ui/src/plugins/dev.perfetto.CpuidleTimeInState/index.ts
@@ -0,0 +1,88 @@
+// 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 {Trace} from '../../public/trace';
+import {PerfettoPlugin, PluginDescriptor} from '../../public/plugin';
+import {CounterOptions} from '../../frontend/base_counter_track';
+import {TrackNode} from '../../public/workspace';
+import {
+  SimpleCounterTrack,
+  SimpleCounterTrackConfig,
+} from '../../frontend/simple_counter_track';
+
+class CpuidleTimeInState implements PerfettoPlugin {
+  private addCounterTrack(
+    ctx: Trace,
+    name: string,
+    query: string,
+    group?: TrackNode,
+    options?: Partial<CounterOptions>,
+  ): void {
+    const config: SimpleCounterTrackConfig = {
+      data: {
+        sqlSource: query,
+        columns: ['ts', 'value'],
+      },
+      columns: {ts: 'ts', value: 'value'},
+      options,
+    };
+
+    const uri = `/cpuidle_time_in_state_${name}`;
+    ctx.tracks.registerTrack({
+      uri,
+      title: name,
+      track: new SimpleCounterTrack(ctx, {trackUri: uri}, config),
+    });
+    const track = new TrackNode({uri, title: name});
+
+    if (group) {
+      group.addChildInOrder(track);
+    }
+  }
+
+  async onTraceLoad(ctx: Trace): Promise<void> {
+    const group = new TrackNode({
+      title: 'Cpuidle Time In State',
+      isSummary: true,
+    });
+
+    const e = ctx.engine;
+    await e.query(`INCLUDE PERFETTO MODULE linux.cpu.idle_time_in_state;`);
+    const result = await e.query(
+      `select distinct state_name from cpu_idle_time_in_state_counters`,
+    );
+    const it = result.iter({state_name: 'str'});
+    for (; it.valid(); it.next()) {
+      this.addCounterTrack(
+        ctx,
+        it.state_name,
+        `select
+            ts,
+            idle_percentage as value
+        from cpu_idle_time_in_state_counters
+        where state_name='${it.state_name}'`,
+        group,
+        {unit: 'percent'},
+      );
+    }
+    if (group.hasChildren) {
+      ctx.workspace.addChildInOrder(group);
+    }
+  }
+}
+
+export const plugin: PluginDescriptor = {
+  pluginId: 'dev.perfetto.CpuidleTimeInState',
+  plugin: CpuidleTimeInState,
+};