[stdlib]: Add an android.oom_adjuster module
android_oom_adj_states contains a row per oom_adj transition in all
processes. The transition is augmented with metadata about the last
oom_adj update in the system_server. Furthermore, we also expose
a generic oom_adjuster translation function.
Test: tools/diff_test_trace_processor.py out/android/trace_processor_shell --name-filter '.*oom_adjuster.*'
Change-Id: I338e40ba2feaae2de8981e774db82a7a4cabe3ba
diff --git a/Android.bp b/Android.bp
index 73487c9..58e5e2d 100644
--- a/Android.bp
+++ b/Android.bp
@@ -11986,6 +11986,7 @@
"src/trace_processor/perfetto_sql/stdlib/android/job_scheduler.sql",
"src/trace_processor/perfetto_sql/stdlib/android/monitor_contention.sql",
"src/trace_processor/perfetto_sql/stdlib/android/network_packets.sql",
+ "src/trace_processor/perfetto_sql/stdlib/android/oom_adjuster.sql",
"src/trace_processor/perfetto_sql/stdlib/android/process_metadata.sql",
"src/trace_processor/perfetto_sql/stdlib/android/screenshots.sql",
"src/trace_processor/perfetto_sql/stdlib/android/services.sql",
diff --git a/BUILD b/BUILD
index a60811a..50532d6 100644
--- a/BUILD
+++ b/BUILD
@@ -2374,6 +2374,7 @@
"src/trace_processor/perfetto_sql/stdlib/android/job_scheduler.sql",
"src/trace_processor/perfetto_sql/stdlib/android/monitor_contention.sql",
"src/trace_processor/perfetto_sql/stdlib/android/network_packets.sql",
+ "src/trace_processor/perfetto_sql/stdlib/android/oom_adjuster.sql",
"src/trace_processor/perfetto_sql/stdlib/android/process_metadata.sql",
"src/trace_processor/perfetto_sql/stdlib/android/screenshots.sql",
"src/trace_processor/perfetto_sql/stdlib/android/services.sql",
diff --git a/src/trace_processor/perfetto_sql/stdlib/android/BUILD.gn b/src/trace_processor/perfetto_sql/stdlib/android/BUILD.gn
index be50773..29c4b89 100644
--- a/src/trace_processor/perfetto_sql/stdlib/android/BUILD.gn
+++ b/src/trace_processor/perfetto_sql/stdlib/android/BUILD.gn
@@ -31,6 +31,7 @@
"job_scheduler.sql",
"monitor_contention.sql",
"network_packets.sql",
+ "oom_adjuster.sql",
"process_metadata.sql",
"screenshots.sql",
"services.sql",
diff --git a/src/trace_processor/perfetto_sql/stdlib/android/oom_adjuster.sql b/src/trace_processor/perfetto_sql/stdlib/android/oom_adjuster.sql
new file mode 100644
index 0000000..9c184e5
--- /dev/null
+++ b/src/trace_processor/perfetto_sql/stdlib/android/oom_adjuster.sql
@@ -0,0 +1,129 @@
+--
+-- 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.
+--
+
+INCLUDE PERFETTO MODULE common.slices;
+INCLUDE PERFETTO MODULE counters.intervals;
+
+-- Converts an oom_adj score Integer to String bucket name.
+CREATE PERFETTO FUNCTION android_oom_adj_score_to_bucket_name(
+ -- oom_adj score.
+ value INT,
+ -- android_app id of the process.
+ android_appid INT)
+-- Returns the oom_adj bucket.
+RETURNS STRING
+AS
+SELECT
+ CASE
+ WHEN $value = -1000 THEN 'native'
+ WHEN $value = -900 THEN 'system'
+ WHEN $value = -800 THEN 'persistent'
+ WHEN $value = -700 THEN 'persistent'
+ WHEN $value = -600 THEN 'logcat'
+ WHEN $value = 0 THEN 'foreground_app'
+ WHEN $value = 50 THEN 'perceptible_foreground_app'
+ WHEN $value BETWEEN 100 AND 199 THEN 'visible_app'
+ WHEN $value BETWEEN 200 AND 224 THEN 'perceptible_app'
+ WHEN $value BETWEEN 225 AND 249 THEN 'perceptible_medium_app'
+ WHEN $value BETWEEN 250 AND 299 THEN 'perceptible_low_app'
+ WHEN $value BETWEEN 300 AND 399 THEN 'backup'
+ WHEN $value BETWEEN 400 AND 499 THEN 'heavy_weight_app'
+ WHEN $value BETWEEN 500 AND 599 THEN 'service'
+ WHEN $value BETWEEN 600 AND 699 THEN 'home_app'
+ WHEN $value BETWEEN 700 AND 799 THEN 'previous_app'
+ WHEN $value BETWEEN 800 AND 899 THEN 'service_b'
+ WHEN $value BETWEEN 900 AND 949 THEN 'cached_app'
+ WHEN $value >= 950 THEN 'cached_app_lmk_first'
+ WHEN $android_appid IS NULL THEN 'unknown'
+ WHEN $android_appid < 10000 THEN 'unknown_native'
+ ELSE 'unknown_app'
+ END;
+
+-- All oom adj state intervals across all processes along with the reason for the state update.
+CREATE PERFETTO TABLE android_oom_adj_intervals (
+ -- Timestamp the oom_adj score of the process changed
+ ts INT,
+ -- Duration until the next oom_adj score change of the process.
+ dur INT,
+ -- oom_adj score of the process.
+ score INT,
+ -- oom_adj bucket of the process.
+ bucket STRING,
+ -- Upid of the process having an oom_adj update.
+ upid INT,
+ -- Name of the process having an oom_adj update.
+ process_name STRING,
+ -- Slice id of the latest oom_adj update in the system_server.
+ oom_adj_id INT,
+ -- Timestamp of the latest oom_adj update in the system_server.
+ oom_adj_ts INT,
+ -- Duration of the latest oom_adj update in the system_server.
+ oom_adj_dur INT,
+ -- Track id of the latest oom_adj update in the system_server
+ oom_adj_track_id INT,
+ -- Thread name of the latest oom_adj update in the system_server.
+ oom_adj_thread_name STRING,
+ -- Reason for the latest oom_adj update in the system_server.
+ oom_adj_reason STRING,
+ -- Trigger for the latest oom_adj update in the system_server.
+ oom_adj_trigger STRING
+ ) AS
+WITH
+ reason AS (
+ SELECT
+ thread_slice.id AS oom_adj_id,
+ thread_slice.ts AS oom_adj_ts,
+ thread_slice.dur AS oom_adj_dur,
+ thread_slice.track_id AS oom_adj_track_id,
+ thread_name AS oom_adj_thread_name,
+ str_split(thread_slice.name, '_', 1) AS oom_adj_reason,
+ slice.name AS oom_adj_trigger,
+ LEAD(thread_slice.ts) OVER (ORDER BY thread_slice.ts) AS oom_adj_next_ts
+ FROM thread_slice
+ JOIN slice ON slice.id = thread_slice.parent_id
+ WHERE thread_slice.name GLOB 'updateOomAdj_*' AND process_name = 'system_server'
+ )
+SELECT
+ ts,
+ dur,
+ value AS score,
+ android_oom_adj_score_to_bucket_name(value, android_appid) AS bucket,
+ process.upid,
+ process.name AS process_name,
+ reason.oom_adj_id,
+ reason.oom_adj_ts,
+ reason.oom_adj_dur,
+ reason.oom_adj_track_id,
+ reason.oom_adj_thread_name,
+ reason.oom_adj_reason,
+ reason.oom_adj_trigger
+FROM
+ counter_leading_intervals
+ !(
+ (
+ SELECT counter.*
+ FROM counter
+ JOIN counter_track track
+ ON track.id = counter.track_id AND track.name = 'oom_score_adj'
+ ))
+ counter
+JOIN process_counter_track track
+ ON counter.track_id = track.id
+JOIN process
+ USING (upid)
+LEFT JOIN reason
+ ON counter.ts BETWEEN oom_adj_ts AND COALESCE(oom_adj_next_ts, trace_end())
+WHERE track.name = 'oom_score_adj';
diff --git a/test/trace_processor/diff_tests/stdlib/android/tests.py b/test/trace_processor/diff_tests/stdlib/android/tests.py
index ad4a5ed..927394f 100644
--- a/test/trace_processor/diff_tests/stdlib/android/tests.py
+++ b/test/trace_processor/diff_tests/stdlib/android/tests.py
@@ -1213,3 +1213,38 @@
0,"com.android.bluetooth","droid.bluetooth",7639,7639,571248973750,9874358,-700,"com.android.bluetooth","binder:7639_2",7672,7639,571871169647,6460322,"android.os.BinderProxy@7482132","android.bluetooth.IBluetooth","com.android.bluetooth/.btservice.AdapterService","[NULL]",4
-700,"com.android.bluetooth","droid.bluetooth",7639,7639,572342110044,4874276,-700,"com.android.bluetooth","binder:7639_2",7672,7639,572466393291,1404185,"android.os.BinderProxy@ce5a6fc","android.media.browse.MediaBrowserService","com.android.bluetooth/.avrcpcontroller.BluetoothMediaBrowserService","[NULL]",10
"""))
+
+ def test_oom_adjuster_transitions(self):
+ return DiffTestBlueprint(
+ trace=DataPath('sched_wakeup_trace.atr'),
+ query="""
+ INCLUDE PERFETTO MODULE android.oom_adjuster;
+ SELECT
+ ts,
+ dur,
+ score,
+ bucket,
+ process_name,
+ oom_adj_ts,
+ oom_adj_dur,
+ oom_adj_thread_name,
+ oom_adj_reason,
+ oom_adj_trigger
+ FROM android_oom_adj_intervals
+ WHERE oom_adj_reason IS NOT NULL
+ ORDER BY ts
+ LIMIT 10
+ """,
+ out=Csv("""
+ "ts","dur","score","bucket","process_name","oom_adj_ts","oom_adj_dur","oom_adj_thread_name","oom_adj_reason","oom_adj_trigger"
+ 1737065264829,701108081,925,"cached_app","com.android.providers.calendar",1737064421516,29484835,"binder:642_1","processEnd","IActivityManager#1598246212"
+ 1737066678827,3470211742,935,"cached_app","com.android.imsserviceentitlement",1737064421516,29484835,"binder:642_1","processEnd","IActivityManager#1598246212"
+ 1737066873002,3470017567,945,"cached_app","com.android.carrierconfig",1737064421516,29484835,"binder:642_1","processEnd","IActivityManager#1598246212"
+ 1737067058812,3469831757,955,"cached_app_lmk_first","com.android.messaging",1737064421516,29484835,"binder:642_1","processEnd","IActivityManager#1598246212"
+ 1737067246975,699224817,955,"cached_app_lmk_first","android.process.acore",1737064421516,29484835,"binder:642_1","processEnd","IActivityManager#1598246212"
+ 1737068421919,3468468650,965,"cached_app_lmk_first","com.android.shell",1737064421516,29484835,"binder:642_1","processEnd","IActivityManager#1598246212"
+ 1737068599673,697908135,965,"cached_app_lmk_first","android.process.media",1737064421516,29484835,"binder:642_1","processEnd","IActivityManager#1598246212"
+ 1737068933602,3467956967,975,"cached_app_lmk_first","com.android.gallery3d",1737064421516,29484835,"binder:642_1","processEnd","IActivityManager#1598246212"
+ 1737069091010,3467799559,975,"cached_app_lmk_first","com.android.packageinstaller",1737064421516,29484835,"binder:642_1","processEnd","IActivityManager#1598246212"
+ 1737069240534,3467650035,985,"cached_app_lmk_first","com.android.managedprovisioning",1737064421516,29484835,"binder:642_1","processEnd","IActivityManager#1598246212"
+ """))