--
-- Copyright 2020 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.

-- WebView is embedded in the hosting app's main process, which means it shares some threads
-- with the host app's work. We approximate WebView-related power usage
-- by selecting user slices that belong to WebView and estimating their power use
-- through the CPU time they consume at different core frequencies.
-- This file populates a summary table that can be used to produce metrics in different formats.

SELECT RUN_METRIC('android/android_proxy_power.sql');
SELECT RUN_METRIC('android/cpu_info.sql');

DROP TABLE IF EXISTS top_level_slice;

-- Select topmost slices from the 'toplevel' and 'Java' categories.
-- Filter out Looper events since they are likely to belong to the host app.
-- Slices are only used to calculate the contribution of the browser process,
-- renderer contribution will be calculated as the sum of all renderer processes' usage.
CREATE TABLE top_level_slice AS
SELECT *
FROM slice WHERE
  depth = 0
  AND ((category GLOB '*toplevel*' OR category = 'Java')
    AND name NOT GLOB '*looper*');

DROP TABLE IF EXISTS webview_browser_slices;

-- Match top-level slices to threads and hosting apps.
-- This excludes any renderer slices because renderer processes are counted
-- as a whole separately.
-- Slices from Chrome browser processes are also excluded.
CREATE TABLE webview_browser_slices AS
SELECT
  top_level_slice.ts,
  top_level_slice.dur,
  thread_track.utid,
  process.upid AS upid,
  extract_arg(process.arg_set_id, 'chrome.host_app_package_name') AS app_name
FROM top_level_slice
JOIN thread_track
  ON top_level_slice.track_id = thread_track.id
JOIN process
  ON thread.upid = process.upid
JOIN thread
  ON thread_track.utid = thread.utid
WHERE process.name NOT GLOB '*SandboxedProcessService*'
  AND process.name NOT GLOB '*chrome*'
  AND app_name IS NOT NULL;

DROP TABLE IF EXISTS webview_browser_slices_power;

-- Assign power usage to WebView browser slices.
CREATE VIRTUAL TABLE webview_browser_slices_power
USING SPAN_JOIN(power_per_thread PARTITIONED utid,
                webview_browser_slices PARTITIONED utid);

DROP TABLE IF EXISTS webview_browser_slices_power_summary;

-- Calculate the power usage of all WebView browser slices for each app
-- in milliampere-seconds.
CREATE TABLE webview_browser_slices_power_summary AS
SELECT
  app_name,
  SUM(dur * COALESCE(power_ma, 0) / 1e9) AS power_mas
FROM webview_browser_slices_power
GROUP BY app_name;

DROP TABLE IF EXISTS webview_renderer_threads;

-- All threads of all WebView renderer processes.
CREATE TABLE webview_renderer_threads AS
SELECT
  thread.utid AS utid,
  extract_arg(process.arg_set_id, 'chrome.host_app_package_name') AS app_name
FROM process
JOIN thread
  ON thread.upid = process.upid
WHERE process.name GLOB '*webview*SandboxedProcessService*'
  AND app_name IS NOT NULL;

DROP TABLE IF EXISTS webview_renderer_power_summary;

-- Calculate the power usage of all WebView renderer processes for each app
-- in milliampere-seconds.
CREATE TABLE webview_renderer_power_summary AS
SELECT
  app_name,
  SUM(dur * COALESCE(power_ma, 0) / 1e9) AS power_mas
FROM power_per_thread
JOIN webview_renderer_threads
  ON power_per_thread.utid = webview_renderer_threads.utid
GROUP BY app_name;

DROP TABLE IF EXISTS webview_renderer_power_per_core_type;

-- Calculate the power usage of all WebView renderer processes for each app
-- in milliampere-seconds grouped by core type.
CREATE TABLE webview_renderer_power_per_core_type AS
SELECT
  app_name,
  core_type_per_cpu.core_type AS core_type,
  SUM(dur * COALESCE(power_ma, 0) / 1e9) AS power_mas
FROM power_per_thread
JOIN webview_renderer_threads
  ON power_per_thread.utid = webview_renderer_threads.utid
JOIN core_type_per_cpu
  ON power_per_thread.cpu = core_type_per_cpu.cpu
GROUP BY app_name, core_type_per_cpu.core_type;

DROP TABLE IF EXISTS host_app_threads;

-- All threads of hosting apps (this is a superset of webview_browser_slices).
-- 1) select all threads that had any WebView browser slices associated with them;
-- 2) get all threads for processes matching threads from 1).
-- For example, only some of app's threads wrote any slices, but we are selecting
-- all threads for this app's process.
-- Excludes all renderer processes and Chrome browser processes.
CREATE TABLE host_app_threads AS
SELECT
  thread.utid AS utid,
  thread.name AS name,
  extract_arg(process.arg_set_id, 'chrome.host_app_package_name') AS app_name
FROM thread
JOIN process ON thread.upid = process.upid
WHERE thread.upid IN
  (SELECT DISTINCT(webview_browser_slices.upid) FROM webview_browser_slices)
  AND process.name NOT GLOB '*SandboxedProcessService*'
  AND process.name NOT GLOB '*chrome*'
  AND app_name IS NOT NULL;

DROP TABLE IF EXISTS host_app_power_summary;

-- Calculate the power usage of all WebView (host app+browser) processes for each app
-- in milliampere-seconds.
CREATE TABLE host_app_power_summary AS
SELECT
  app_name,
  SUM(dur * COALESCE(power_ma, 0) / 1e9) AS power_mas
FROM power_per_thread
JOIN host_app_threads
  ON power_per_thread.utid = host_app_threads.utid
GROUP BY app_name;

DROP TABLE IF EXISTS host_app_power_per_core_type;

-- Calculate the power usage of all WebView (host app+browser) processes for each app
-- in milliampere-seconds grouped by core type.
CREATE TABLE host_app_power_per_core_type AS
SELECT
  app_name,
  core_type_per_cpu.core_type AS core_type,
  SUM(dur * COALESCE(power_ma, 0) / 1e9) AS power_mas
FROM power_per_thread
JOIN host_app_threads
  ON power_per_thread.utid = host_app_threads.utid
JOIN core_type_per_cpu
  ON power_per_thread.cpu = core_type_per_cpu.cpu
GROUP BY app_name, core_type_per_cpu.core_type;

DROP TABLE IF EXISTS webview_only_threads;

-- A subset of the host app threads that are WebView-specific.
CREATE TABLE webview_only_threads AS
SELECT *
FROM host_app_threads
WHERE name GLOB 'Chrome*' OR name GLOB 'CookieMonster*'
  OR name GLOB 'CompositorTileWorker*' OR name GLOB 'ThreadPool*ground*'
  OR NAME GLOB 'ThreadPoolService*' OR name GLOB 'VizCompositorThread*'
  OR name IN ('AudioThread', 'DedicatedWorker thread', 'GpuMemoryThread',
    'JavaBridge', 'LevelDBEnv.IDB', 'MemoryInfra', 'NetworkService', 'VizWebView');

DROP TABLE IF EXISTS webview_only_power_summary;

-- Calculate the power usage of all WebView-specific host app threads
-- (browser + in-process renderers) for each app in milliampere-seconds.
CREATE TABLE webview_only_power_summary AS
SELECT
  app_name,
  SUM(dur * COALESCE(power_ma, 0) / 1e9) AS power_mas
FROM power_per_thread
JOIN webview_only_threads
  ON power_per_thread.utid = webview_only_threads.utid
GROUP BY app_name;

DROP TABLE IF EXISTS webview_only_power_per_core_type;

-- Calculate the power usage of all WebView-specific host app threads
-- for each app in milliampere-seconds grouped by core type.
CREATE TABLE webview_only_power_per_core_type AS
SELECT app_name,
  core_type_per_cpu.core_type AS core_type,
  SUM(dur * COALESCE(power_ma, 0) / 1e9) AS power_mas
FROM power_per_thread
JOIN webview_only_threads
  ON power_per_thread.utid = webview_only_threads.utid
JOIN core_type_per_cpu
  ON power_per_thread.cpu = core_type_per_cpu.cpu
GROUP BY app_name, core_type_per_cpu.core_type;

-- Create views for output.

DROP TABLE IF EXISTS total_app_power_output;

CREATE TABLE total_app_power_output AS
SELECT
  host_app_power_summary.app_name AS app_name,
  host_app_power_summary.power_mas AS total_mas,
  host_app_power_little_cores_mas.power_mas AS little_cores_mas,
  host_app_power_big_cores_mas.power_mas AS big_cores_mas,
  host_app_power_bigger_cores_mas.power_mas AS bigger_cores_mas
FROM host_app_power_summary LEFT JOIN host_app_power_per_core_type AS host_app_power_little_cores_mas
  ON host_app_power_summary.app_name = host_app_power_little_cores_mas.app_name
    AND host_app_power_little_cores_mas.core_type = 'little'
LEFT JOIN host_app_power_per_core_type AS host_app_power_big_cores_mas
  ON host_app_power_summary.app_name = host_app_power_big_cores_mas.app_name
    AND host_app_power_big_cores_mas.core_type = 'big'
LEFT JOIN host_app_power_per_core_type AS host_app_power_bigger_cores_mas
  ON host_app_power_summary.app_name = host_app_power_bigger_cores_mas.app_name
    AND host_app_power_bigger_cores_mas.core_type = 'bigger';

DROP TABLE IF EXISTS webview_renderer_power_output;

CREATE TABLE webview_renderer_power_output AS
SELECT
  webview_renderer_power_summary.app_name AS app_name,
  webview_renderer_power_summary.power_mas AS total_mas,
  webview_renderer_little_power.power_mas AS little_cores_mas,
  webview_renderer_big_power.power_mas AS big_cores_mas,
  webview_renderer_bigger_power.power_mas AS bigger_cores_mas
FROM webview_renderer_power_summary LEFT JOIN webview_renderer_power_per_core_type AS webview_renderer_little_power
  ON webview_renderer_power_summary.app_name = webview_renderer_little_power.app_name
    AND webview_renderer_little_power.core_type = 'little'
LEFT JOIN webview_renderer_power_per_core_type AS webview_renderer_big_power
  ON webview_renderer_power_summary.app_name = webview_renderer_big_power.app_name
    AND webview_renderer_big_power.core_type = 'big'
LEFT JOIN webview_renderer_power_per_core_type AS webview_renderer_bigger_power
  ON webview_renderer_power_summary.app_name = webview_renderer_bigger_power.app_name
    AND webview_renderer_bigger_power.core_type = 'bigger';

DROP TABLE IF EXISTS webview_only_power_output;

CREATE TABLE webview_only_power_output AS
SELECT
  webview_only_power_summary.app_name AS app_name,
  webview_only_power_summary.power_mas AS total_mas,
  webview_only_power_little_cores_mas.power_mas AS little_cores_mas,
  webview_only_power_big_cores_mas.power_mas AS big_cores_mas,
  webview_only_power_bigger_cores_mas.power_mas AS bigger_cores_mas
FROM webview_only_power_summary LEFT JOIN webview_only_power_per_core_type AS webview_only_power_little_cores_mas
  ON webview_only_power_summary.app_name = webview_only_power_little_cores_mas.app_name
    AND webview_only_power_little_cores_mas.core_type = 'little'
LEFT JOIN webview_only_power_per_core_type AS webview_only_power_big_cores_mas
  ON webview_only_power_summary.app_name = webview_only_power_big_cores_mas.app_name
    AND webview_only_power_big_cores_mas.core_type = 'big'
LEFT JOIN webview_only_power_per_core_type AS webview_only_power_bigger_cores_mas
  ON webview_only_power_summary.app_name = webview_only_power_bigger_cores_mas.app_name
    AND webview_only_power_bigger_cores_mas.core_type = 'bigger';

DROP TABLE IF EXISTS total_device_power;

-- Calculate the power usage of the device in milliampere-seconds.
CREATE TABLE total_device_power AS
SELECT SUM(dur * COALESCE(power_ma, 0) / 1e9) AS power_mas
FROM power_per_thread;
