Merge "Perfetto metrics for Multiuser"
diff --git a/Android.bp b/Android.bp
index e030729..bbfb275 100644
--- a/Android.bp
+++ b/Android.bp
@@ -3671,6 +3671,7 @@
     "protos/perfetto/metrics/android/lmk_reason_metric.proto",
     "protos/perfetto/metrics/android/mem_metric.proto",
     "protos/perfetto/metrics/android/mem_unagg_metric.proto",
+    "protos/perfetto/metrics/android/multiuser_metric.proto",
     "protos/perfetto/metrics/android/package_list.proto",
     "protos/perfetto/metrics/android/powrails_metric.proto",
     "protos/perfetto/metrics/android/process_metadata.proto",
@@ -3723,6 +3724,7 @@
     "protos/perfetto/metrics/android/lmk_reason_metric.proto",
     "protos/perfetto/metrics/android/mem_metric.proto",
     "protos/perfetto/metrics/android/mem_unagg_metric.proto",
+    "protos/perfetto/metrics/android/multiuser_metric.proto",
     "protos/perfetto/metrics/android/package_list.proto",
     "protos/perfetto/metrics/android/powrails_metric.proto",
     "protos/perfetto/metrics/android/process_metadata.proto",
@@ -8003,6 +8005,8 @@
     "src/trace_processor/metrics/android/android_lmk_reason.sql",
     "src/trace_processor/metrics/android/android_mem.sql",
     "src/trace_processor/metrics/android/android_mem_unagg.sql",
+    "src/trace_processor/metrics/android/android_multiuser.sql",
+    "src/trace_processor/metrics/android/android_multiuser_populator.sql",
     "src/trace_processor/metrics/android/android_package_list.sql",
     "src/trace_processor/metrics/android/android_powrails.sql",
     "src/trace_processor/metrics/android/android_proxy_power.sql",
diff --git a/BUILD b/BUILD
index b31708e..3124f4b 100644
--- a/BUILD
+++ b/BUILD
@@ -1027,6 +1027,8 @@
         "src/trace_processor/metrics/android/android_lmk_reason.sql",
         "src/trace_processor/metrics/android/android_mem.sql",
         "src/trace_processor/metrics/android/android_mem_unagg.sql",
+        "src/trace_processor/metrics/android/android_multiuser.sql",
+        "src/trace_processor/metrics/android/android_multiuser_populator.sql",
         "src/trace_processor/metrics/android/android_package_list.sql",
         "src/trace_processor/metrics/android/android_powrails.sql",
         "src/trace_processor/metrics/android/android_proxy_power.sql",
@@ -2560,6 +2562,7 @@
         "protos/perfetto/metrics/android/lmk_reason_metric.proto",
         "protos/perfetto/metrics/android/mem_metric.proto",
         "protos/perfetto/metrics/android/mem_unagg_metric.proto",
+        "protos/perfetto/metrics/android/multiuser_metric.proto",
         "protos/perfetto/metrics/android/package_list.proto",
         "protos/perfetto/metrics/android/powrails_metric.proto",
         "protos/perfetto/metrics/android/process_metadata.proto",
diff --git a/protos/perfetto/metrics/android/BUILD.gn b/protos/perfetto/metrics/android/BUILD.gn
index 54a06d6..aa97665 100644
--- a/protos/perfetto/metrics/android/BUILD.gn
+++ b/protos/perfetto/metrics/android/BUILD.gn
@@ -37,6 +37,7 @@
     "lmk_reason_metric.proto",
     "mem_metric.proto",
     "mem_unagg_metric.proto",
+    "multiuser_metric.proto",
     "package_list.proto",
     "powrails_metric.proto",
     "process_metadata.proto",
diff --git a/protos/perfetto/metrics/android/multiuser_metric.proto b/protos/perfetto/metrics/android/multiuser_metric.proto
new file mode 100644
index 0000000..eba37d9
--- /dev/null
+++ b/protos/perfetto/metrics/android/multiuser_metric.proto
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2021 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;
+
+// Metrics for Multiuser events, such as switching users.
+message AndroidMultiuserMetric {
+
+  // Holds the data for a Multiuser event.
+  message EventData {
+    // Duration of the event (in milliseconds).
+    optional int32 duration_ms = 1;
+
+    // CPU usage of each process during the event.
+    message CpuUsage {
+      // The userId of the process (e.g. 0 or 10).
+      optional int32 user_id = 1;
+      // The name of the process.
+      optional string process_name = 2;
+      // The number of CPU cycles (in megacycles) spent by that process during the event.
+      optional int32 cpu_mcycles = 3;
+      // The ratio of this process's cycles to the total for all processes, expressed as a percentage.
+      optional float cpu_percentage = 4;
+    }
+    repeated CpuUsage cpu_usage = 2;
+  }
+
+  // Metrics for a user switch.
+  optional EventData user_switch = 1;
+}
\ No newline at end of file
diff --git a/protos/perfetto/metrics/metrics.proto b/protos/perfetto/metrics/metrics.proto
index 499099c..5f2c801 100644
--- a/protos/perfetto/metrics/metrics.proto
+++ b/protos/perfetto/metrics/metrics.proto
@@ -35,6 +35,7 @@
 import "protos/perfetto/metrics/android/lmk_reason_metric.proto";
 import "protos/perfetto/metrics/android/mem_metric.proto";
 import "protos/perfetto/metrics/android/mem_unagg_metric.proto";
+import "protos/perfetto/metrics/android/multiuser_metric.proto";
 import "protos/perfetto/metrics/android/package_list.proto";
 import "protos/perfetto/metrics/android/powrails_metric.proto";
 import "protos/perfetto/metrics/android/profiler_smaps.proto";
@@ -90,7 +91,7 @@
 
 // Root message for all Perfetto-based metrics.
 //
-// Next id: 36
+// Next id: 37
 message TraceMetrics {
   reserved 4, 10, 13, 14, 16, 19;
 
@@ -180,6 +181,9 @@
   // Profiler smaps
   optional ProfilerSmaps profiler_smaps = 35;
 
+  // Multiuser - metrics for switching users.
+  optional AndroidMultiuserMetric android_multiuser = 36;
+
   // 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 743a2e7..15a119f 100644
--- a/protos/perfetto/metrics/perfetto_merged_metrics.proto
+++ b/protos/perfetto/metrics/perfetto_merged_metrics.proto
@@ -702,6 +702,35 @@
 
 // End of protos/perfetto/metrics/android/mem_unagg_metric.proto
 
+// Begin of protos/perfetto/metrics/android/multiuser_metric.proto
+
+// Metrics for Multiuser events, such as switching users.
+message AndroidMultiuserMetric {
+
+  // Holds the data for a Multiuser event.
+  message EventData {
+    // Duration of the event (in milliseconds).
+    optional int32 duration_ms = 1;
+
+    // CPU usage of each process during the event.
+    message CpuUsage {
+      // The userId of the process (e.g. 0 or 10).
+      optional int32 user_id = 1;
+      // The name of the process.
+      optional string process_name = 2;
+      // The number of CPU cycles (in megacycles) spent by that process during the event.
+      optional int32 cpu_mcycles = 3;
+      // The ratio of this process's cycles to the total for all processes, expressed as a percentage.
+      optional float cpu_percentage = 4;
+    }
+    repeated CpuUsage cpu_usage = 2;
+  }
+
+  // Metrics for a user switch.
+  optional EventData user_switch = 1;
+}
+// End of protos/perfetto/metrics/android/multiuser_metric.proto
+
 // Begin of protos/perfetto/metrics/android/package_list.proto
 
 message AndroidPackageList {
@@ -1168,7 +1197,7 @@
 
 // Root message for all Perfetto-based metrics.
 //
-// Next id: 36
+// Next id: 37
 message TraceMetrics {
   reserved 4, 10, 13, 14, 16, 19;
 
@@ -1258,6 +1287,9 @@
   // Profiler smaps
   optional ProfilerSmaps profiler_smaps = 35;
 
+  // Multiuser - metrics for switching users.
+  optional AndroidMultiuserMetric android_multiuser = 36;
+
   // Demo extensions.
   extensions 450 to 499;
 
diff --git a/src/trace_processor/metrics/BUILD.gn b/src/trace_processor/metrics/BUILD.gn
index 84b211b..8311cde 100644
--- a/src/trace_processor/metrics/BUILD.gn
+++ b/src/trace_processor/metrics/BUILD.gn
@@ -61,6 +61,8 @@
   "android/process_oom_score.sql",
   "android/profiler_smaps.sql",
   "android/mem_stats_priority_breakdown.sql",
+  "android/android_multiuser.sql",
+  "android/android_multiuser_populator.sql",
   "android/span_view_stats.sql",
   "android/android_sysui_cuj.sql",
   "android/android_sysui_cuj_jank_query.sql",
diff --git a/src/trace_processor/metrics/android/android_multiuser.sql b/src/trace_processor/metrics/android/android_multiuser.sql
new file mode 100644
index 0000000..0b94f89
--- /dev/null
+++ b/src/trace_processor/metrics/android/android_multiuser.sql
@@ -0,0 +1,25 @@
+--
+-- Copyright 2021 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_multiuser_populator.sql',
+    'output_table_name', 'event_user_switch',
+    'start_event', 'user_start',
+    'end_event', 'launcher_end');
+
+CREATE VIEW android_multiuser_output AS
+SELECT AndroidMultiuserMetric(
+  'user_switch', (SELECT * FROM event_user_switch)
+);
\ No newline at end of file
diff --git a/src/trace_processor/metrics/android/android_multiuser_populator.sql b/src/trace_processor/metrics/android/android_multiuser_populator.sql
new file mode 100644
index 0000000..b4d73b6
--- /dev/null
+++ b/src/trace_processor/metrics/android/android_multiuser_populator.sql
@@ -0,0 +1,116 @@
+--
+-- Copyright 2021 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.
+--
+
+-- Collect the important timestamps for Multiuser events.
+DROP VIEW IF EXISTS multiuser_events;
+CREATE VIEW multiuser_events AS
+SELECT
+      {{start_event}}_time_ns AS event_start_time_ns,
+      {{end_event}}_time_ns AS event_end_time_ns
+FROM
+  (
+    SELECT slice.ts AS user_start_time_ns
+    FROM slice
+    WHERE (slice.name LIKE "onBeforeStartUser%")
+    -- TODO: Use a signal based on SysUi so that it covers all switching, not just starting.
+  ),
+  (
+    SELECT slice.ts + slice.dur AS launcher_end_time_ns
+    FROM slice
+    WHERE (slice.name = "launching: com.google.android.apps.nexuslauncher")
+  );
+
+-- Calculation of the duration of the Multiuser event of interest.
+DROP VIEW IF EXISTS multiuser_timing;
+CREATE VIEW multiuser_timing AS
+SELECT
+      CAST((event_end_time_ns - event_start_time_ns) / 1e6 + 0.5 AS INT) AS duration_ms
+FROM
+  multiuser_events;
+
+
+-- Calculate CPU usage during the Multiuser event of interest.
+
+-- Get all the scheduling slices.
+DROP VIEW IF EXISTS sp_sched;
+CREATE VIEW sp_sched AS
+SELECT ts, dur, cpu, utid
+FROM sched;
+-- Get all the cpu frequency slices.
+DROP VIEW IF EXISTS sp_frequency;
+CREATE VIEW sp_frequency AS
+SELECT
+  ts,
+  lead(ts) OVER (PARTITION BY track_id ORDER BY ts) - ts as dur,
+  cpu,
+  value as freq_khz
+FROM counter
+JOIN cpu_counter_track ON counter.track_id = cpu_counter_track.id;
+-- Create the span joined table which combines cpu frequency with scheduling slices.
+DROP TABLE IF EXISTS sched_with_frequency;
+CREATE VIRTUAL TABLE sched_with_frequency
+USING SPAN_JOIN(sp_sched PARTITIONED cpu, sp_frequency PARTITIONED cpu);
+
+-- Calculate the CPU cycles spent per process during the duration.
+DROP VIEW IF EXISTS cpu_usage_all;
+CREATE VIEW cpu_usage_all AS
+SELECT
+    process.uid / 100000 AS user_id,
+    process.name AS process_name,
+    SUM(dur * freq_khz) / 1e9 AS cpu_kcycles
+FROM
+    sched_with_frequency
+    JOIN thread USING (utid)
+    JOIN process USING (upid)
+WHERE
+    ts >= (SELECT event_start_time_ns FROM multiuser_events)
+    AND
+    ts <= (SELECT event_end_time_ns FROM multiuser_events)
+GROUP BY upid, process.name
+ORDER BY cpu_kcycles DESC;
+
+-- Get the data from cpu_usage_all, but also with the percentage.
+DROP VIEW IF EXISTS cpu_usage;
+CREATE VIEW cpu_usage AS
+SELECT
+    user_id,
+    process_name,
+    CAST(cpu_kcycles / 1e3 AS INT) AS cpu_mcycles,
+    cpu_kcycles / (SELECT SUM(cpu_kcycles) FROM cpu_usage_all) * 100 AS cpu_percentage
+FROM
+    cpu_usage_all
+ORDER BY cpu_mcycles DESC LIMIT 6;
+
+
+-- Record the output for populating the proto.
+CREATE VIEW {{output_table_name}} AS
+SELECT AndroidMultiuserMetric_EventData(
+  'duration_ms', (
+    SELECT duration_ms
+    FROM multiuser_timing
+  ),
+  'cpu_usage', (
+    SELECT RepeatedField(
+      AndroidMultiuserMetric_EventData_CpuUsage(
+        'user_id', user_id,
+        'process_name', process_name,
+        'cpu_mcycles', cpu_mcycles,
+        'cpu_percentage', cpu_percentage
+      )
+    )
+    FROM cpu_usage
+  )
+);
\ No newline at end of file
diff --git a/src/trace_processor/python/perfetto/trace_processor/metrics.descriptor b/src/trace_processor/python/perfetto/trace_processor/metrics.descriptor
index 93c8e9b..c909308 100644
--- a/src/trace_processor/python/perfetto/trace_processor/metrics.descriptor
+++ b/src/trace_processor/python/perfetto/trace_processor/metrics.descriptor
Binary files differ
diff --git a/src/trace_processor/python/perfetto/trace_processor/metrics.descriptor.sha1 b/src/trace_processor/python/perfetto/trace_processor/metrics.descriptor.sha1
index 6a2cd2a..8f474c4 100644
--- a/src/trace_processor/python/perfetto/trace_processor/metrics.descriptor.sha1
+++ b/src/trace_processor/python/perfetto/trace_processor/metrics.descriptor.sha1
@@ -2,5 +2,5 @@
 // SHA1(tools/gen_binary_descriptors)
 // 9fc6d77de57ec76a80b76aa282f4c7cf5ce55eec
 // SHA1(protos/perfetto/metrics/metrics.proto)
-// 3729737822b6b641906d9873e02b6a2b252972d0
+// d861d7b0dd079940872852cbb4a4dfc3d67ac672
   
\ No newline at end of file
diff --git a/test/trace_processor/parsing/android_multiuser_switch.out b/test/trace_processor/parsing/android_multiuser_switch.out
new file mode 100644
index 0000000..a49f9e3
--- /dev/null
+++ b/test/trace_processor/parsing/android_multiuser_switch.out
@@ -0,0 +1,5 @@
+android_multiuser: {
+  user_switch: {
+    duration_ms: 4900
+  }
+}
\ No newline at end of file
diff --git a/test/trace_processor/parsing/android_multiuser_switch.textproto b/test/trace_processor/parsing/android_multiuser_switch.textproto
new file mode 100644
index 0000000..223ddb6
--- /dev/null
+++ b/test/trace_processor/parsing/android_multiuser_switch.textproto
@@ -0,0 +1,48 @@
+packet {
+  ftrace_events {
+    cpu: 3
+    event {
+      timestamp: 3000000000 # 3e9
+      pid: 4064
+      print {
+        buf: "S|1204|onBeforeStartUser-10|0\n"
+      }
+    }
+  }
+}
+packet {
+  ftrace_events {
+    cpu: 3
+    event {
+      timestamp: 3100000000
+      pid: 4064
+      print {
+        buf: "F|1204|onBeforeStartUser-10|0\n"
+      }
+    }
+  }
+}
+packet {
+  ftrace_events {
+    cpu: 2
+    event {
+      timestamp: 5200000000
+      pid: 4065
+      print {
+        buf: "S|1204|launching: com.google.android.apps.nexuslauncher|0\n"
+      }
+    }
+  }
+}
+packet {
+  ftrace_events {
+    cpu: 2
+    event {
+      timestamp: 7900000000 # 7.9e9
+      pid: 4065
+      print {
+        buf: "F|1204|launching: com.google.android.apps.nexuslauncher|0\n"
+      }
+    }
+  }
+}
\ No newline at end of file
diff --git a/test/trace_processor/parsing/index b/test/trace_processor/parsing/index
index f1ff4c6..b586e28 100644
--- a/test/trace_processor/parsing/index
+++ b/test/trace_processor/parsing/index
@@ -160,3 +160,6 @@
 
 # Regression test for b/193721088 (infra prepending " done\n" to atrace)
 ../../data/atrace_b_193721088.atr sched_smoke.sql sched_smoke_trailing_empty.out
+
+# Multiuser
+android_multiuser_switch.textproto android_multiuser android_multiuser_switch.out