Introduce dmabuf_allocs to stdlib

With inode-based buffer tracking and allocation re-attribution by
following binders to gralloc.

Bug: 339536476
Change-Id: Ib59348bd248869be74b22f9c4b7e9bc7a699cef8
diff --git a/Android.bp b/Android.bp
index 09c661a..3da4304 100644
--- a/Android.bp
+++ b/Android.bp
@@ -13118,6 +13118,7 @@
         "src/trace_processor/perfetto_sql/stdlib/android/input.sql",
         "src/trace_processor/perfetto_sql/stdlib/android/io.sql",
         "src/trace_processor/perfetto_sql/stdlib/android/job_scheduler.sql",
+        "src/trace_processor/perfetto_sql/stdlib/android/memory/dmabuf.sql",
         "src/trace_processor/perfetto_sql/stdlib/android/memory/heap_graph/dominator_tree.sql",
         "src/trace_processor/perfetto_sql/stdlib/android/memory/process.sql",
         "src/trace_processor/perfetto_sql/stdlib/android/monitor_contention.sql",
diff --git a/BUILD b/BUILD
index d336746..de47252 100644
--- a/BUILD
+++ b/BUILD
@@ -2536,6 +2536,7 @@
 perfetto_filegroup(
     name = "src_trace_processor_perfetto_sql_stdlib_android_memory_memory",
     srcs = [
+        "src/trace_processor/perfetto_sql/stdlib/android/memory/dmabuf.sql",
         "src/trace_processor/perfetto_sql/stdlib/android/memory/process.sql",
     ],
 )
diff --git a/src/trace_processor/perfetto_sql/stdlib/android/memory/BUILD.gn b/src/trace_processor/perfetto_sql/stdlib/android/memory/BUILD.gn
index e6555fc..af2894d 100644
--- a/src/trace_processor/perfetto_sql/stdlib/android/memory/BUILD.gn
+++ b/src/trace_processor/perfetto_sql/stdlib/android/memory/BUILD.gn
@@ -16,5 +16,8 @@
 
 perfetto_sql_source_set("memory") {
   deps = [ "heap_graph" ]
-  sources = [ "process.sql" ]
+  sources = [
+    "dmabuf.sql",
+    "process.sql",
+  ]
 }
diff --git a/src/trace_processor/perfetto_sql/stdlib/android/memory/dmabuf.sql b/src/trace_processor/perfetto_sql/stdlib/android/memory/dmabuf.sql
new file mode 100644
index 0000000..1576e9c
--- /dev/null
+++ b/src/trace_processor/perfetto_sql/stdlib/android/memory/dmabuf.sql
@@ -0,0 +1,100 @@
+--
+-- 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 android.binder;
+INCLUDE PERFETTO MODULE slices.with_context;
+
+-- Raw ftrace events
+CREATE PERFETTO TABLE _raw_dmabuf_events AS
+SELECT
+  (SELECT int_value FROM args WHERE arg_set_id = c.arg_set_id AND key = 'inode') AS inode,
+  tt.utid,
+  c.ts,
+  CAST(c.value AS INT) AS buf_size
+FROM thread_counter_track tt
+  JOIN counter c ON c.track_id = tt.id
+WHERE tt.name = 'mem.dma_heap_change';
+
+-- gralloc binder reply slices
+CREATE PERFETTO TABLE _gralloc_binders AS
+SELECT
+  id AS gralloc_binder_reply_id,
+  utid,
+  ts,
+  dur
+FROM thread_slice
+WHERE process_name GLOB '/vendor/bin/hw/android.hardware.graphics.allocator*'
+AND name = 'binder reply';
+
+-- Match gralloc thread allocations to inbound binders
+CREATE PERFETTO TABLE _attributed_dmabufs AS
+SELECT
+  r.inode,
+  r.ts,
+  r.buf_size,
+  IFNULL(b.client_utid, r.utid) AS attr_utid
+FROM _raw_dmabuf_events r
+LEFT JOIN _gralloc_binders gb ON r.utid = gb.utid AND r.ts BETWEEN gb.ts AND gb.ts + gb.dur
+LEFT JOIN android_binder_txns b ON gb.gralloc_binder_reply_id = b.binder_reply_id
+ORDER BY r.inode, r.ts;
+
+CREATE PERFETTO FUNCTION _alloc_source(is_alloc BOOL, inode INT, ts INT)
+RETURNS INT AS
+SELECT attr_utid
+FROM _attributed_dmabufs
+WHERE
+  inode = $inode
+  AND (
+    ($is_alloc AND ts = $ts) OR
+    (NOT $is_alloc AND ts < $ts)
+  )
+ORDER BY ts DESC
+LIMIT 1;
+
+-- Track dmabuf allocations, re-attributing gralloc allocations to their source
+-- (if binder transactions to gralloc are recorded).
+CREATE PERFETTO TABLE android_dmabuf_allocs (
+  -- timestamp of the allocation
+  ts INT,
+  -- allocation size (will be negative for release)
+  buf_size INT,
+  -- dmabuf inode
+  inode INT,
+  -- utid of thread responsible for the allocation
+  -- if a dmabuf is allocated by gralloc we follow the binder transaction
+  -- to the requesting thread (requires binder tracing)
+  utid INT,
+  -- tid of thread responsible for the allocation
+  tid INT,
+  -- thread name
+  thread_name STRING,
+  -- upid of process responsible for the allocation (matches utid)
+  upid INT,
+  -- pid of process responsible for the allocation
+  pid INT,
+  -- process name
+  process_name STRING
+) AS
+WITH _thread_allocs AS (
+  SELECT inode, ts, buf_size, _alloc_source(buf_size > 0, inode, ts) AS utid
+  FROM _attributed_dmabufs
+)
+SELECT ts, buf_size, inode,
+  utid, tid, thread.name AS thread_name,
+  upid, pid, process.name AS process_name
+FROM _thread_allocs allocs
+JOIN thread USING (utid)
+LEFT JOIN process USING (upid)
+ORDER BY ts;
diff --git a/test/trace_processor/diff_tests/stdlib/android/memory.py b/test/trace_processor/diff_tests/stdlib/android/memory.py
index 1da5baf..b62c680 100644
--- a/test/trace_processor/diff_tests/stdlib/android/memory.py
+++ b/test/trace_processor/diff_tests/stdlib/android/memory.py
@@ -46,3 +46,99 @@
         1737069091010,682459310,975,"cached",289,"com.android.packageinstaller",2480,332,1737064421516,29484835,1217,"binder:642_1","processEnd","IActivityManager#1598246212",49364992,52539392,827392,102731776,0,49364992,102731776
         1737069240534,489635,985,"cached",268,"com.android.managedprovisioning",1868,332,1737064421516,29484835,1217,"binder:642_1","processEnd","IActivityManager#1598246212",50683904,53985280,815104,105484288,0,50683904,105484288
          """))
+
+  def test_memory_dmabuf(self):
+    return DiffTestBlueprint(
+        trace=TextProto(r"""
+        packet {
+          ftrace_events {
+            cpu: 0
+            event {
+              timestamp: 1
+              pid: 3000
+              dma_heap_stat {
+                inode: 13583
+                len: 3000
+                total_allocated: 3000
+              }
+            }
+            event {
+              timestamp: 2
+              pid: 3000
+              dma_heap_stat {
+                inode: 13583
+                len: -3000
+                total_allocated: 0
+              }
+            }
+            event {
+              timestamp: 4144791776152
+              pid: 9403
+              binder_transaction {
+                debug_id: 3052940
+                target_node: 256
+                to_proc: 572
+                to_thread: 0
+                reply: 0
+                code: 1
+                flags: 16
+              }
+            }
+            event {
+              timestamp: 4144791793486
+              pid: 591
+              binder_transaction_received {
+                debug_id: 3052940
+              }
+            }
+            event {
+              timestamp: 4144792258492
+              pid: 591
+              dma_heap_stat {
+                inode: 13583
+                len: 10399744
+                total_allocated: 254873600
+              }
+            }
+            event {
+              timestamp: 4144792517566
+              pid: 591
+              binder_transaction {
+                debug_id: 3052950
+                target_node: 0
+                to_proc: 2051
+                to_thread: 9403
+                reply: 1
+                code: 0
+                flags: 0
+              }
+            }
+            event {
+              timestamp: 4144792572498
+              pid: 9403
+              binder_transaction_received {
+                debug_id: 3052950
+              }
+            }
+            event {
+              timestamp: 4145263509021
+              pid: 613
+              dma_heap_stat {
+                inode: 13583
+                len: -10399744
+                total_allocated: 390160384
+              }
+            }
+          }
+        }"""),
+        query="""
+        INCLUDE PERFETTO MODULE android.memory.dmabuf;
+        SELECT * FROM android_dmabuf_allocs;
+        """,
+        out=Csv("""
+        "ts","buf_size","inode","utid","tid","thread_name","upid","pid","process_name"
+        1,3000,13583,1,3000,"[NULL]","[NULL]","[NULL]","[NULL]"
+        2,-3000,13583,1,3000,"[NULL]","[NULL]","[NULL]","[NULL]"
+        4144792258492,10399744,13583,3,591,"[NULL]","[NULL]","[NULL]","[NULL]"
+        4145263509021,-10399744,13583,3,591,"[NULL]","[NULL]","[NULL]","[NULL]"
+         """))
\ No newline at end of file