内存管理-80-dma-buf-1-调试-1-文件节点

基于 Linux-6.1


一、文件节点

1. /sys/kernel/dmabuf/buffers

dma-buf-sysfs-stats.c 中有注释: 当启用 CONFIG_DMABUF_SYSFS_STATS 后,/sys/kernel/dma-buf/buffers 接口会暴露出所有 DMA-BUF 的信息。该接口暴露了以下统计项:

/sys/kernel/dmabuf/buffers/<inode_number>/exporter_name
/sys/kernel/dmabuf/buffers/<inode_number>/size

该接口中的信息还可用于推导按每个导出者(exporter)划分的统计数据。可以在发生错误或其他重要事件时收集该接口的数据,以提供 DMA-BUF 使用情况的快照。也可以通过遥测(telemetry)定期收集,以监控各项指标。

有关该接口的详细文档,见 Documentation/ABI/testing/sysfs-kernel-dmabuf-buffers。


1.1 exporter_name

TODO

1.2 size

TODO


1.3 工具脚本-按size降序

#!/system/bin/sh
# dmabuf_top.sh - list /sys/kernel/dmabuf/buffers entries sorted by size desc
#
# Usage (on device):
#   sh /data/local/tmp/dmabuf_top.sh [DIR] [EXPORTER_SUBSTR]
# Defaults:
#   DIR = /sys/kernel/dmabuf/buffers
#   EXPORTER_SUBSTR = (empty, no filter)
#
# Note: directory name is the dma-buf file's inode number, not a pid. size attribute is bytes (kernel: dma_buf->size).

DIR=${1:-/sys/kernel/dmabuf/buffers}
PAT=${2:-}

if [ ! -d "$DIR" ]; then
    echo "no such dir: $DIR" >&2
    exit 1
fi

for d in "$DIR"/*; do
    [ -d "$d" ] || continue
    size=$(cat "$d/size" 2>/dev/null) || continue
    exp=$(cat "$d/exporter_name" 2>/dev/null)
    [ -n "$size" ] || continue
    printf '%s %s %s\n' "$size" "${exp:-<unknown>}" "${d##*/}"
done | sort -rn | awk -v pat="$PAT" '
    pat != "" && index($2, pat) == 0 { next }
    {
        printf "%14s B  %9.2f MiB  %-18s ino=%s\n", $1, $1 / 1048576, $2, $3
        tot += $1
        n++
    }
    END {
        printf "----\n%d buffers, total %.2f MiB (%.0f B)\n", n, tot / 1048576, tot
    }
'

(1) 用法

sh dmabuf_top.sh                                        # 全部
sh dmabuf_top.sh /sys/kernel/dmabuf/buffers qcom_hgsl   # 只看 HGSL,参数大小写敏感
sh dmabuf_top.sh /sys/kernel/dmabuf/buffers qcom        # 所有 qcom 系列

(2) dump出来内容如:

/data/local/tmp # ./dmabuf_top.sh
      75235328 B      71.75 MiB  qcom_hgsl          ino=2110
      26542080 B      25.31 MiB  qcom,system        ino=45
        516096 B       0.49 MiB  qcom,qseecom       ino=33
        131072 B       0.12 MiB  qcom,system-uncached ino=35
        ...
          4096 B       0.00 MiB  msm_hab            ino=118
----
1379 buffers, total 3311.08 MiB (3471921152 B)


1.4 工具脚本-对应到pid

自带的 dmabuf_dump 工具更好用。

(1) 脚本代码

#!/system/bin/sh
# dmabuf_ino_pids.sh - map /sys/kernel/dmabuf/buffers/<ino> to the pids that mmap it
#
# Usage:
#   sh dmabuf_ino_pids.sh [BUFFERS_DIR] [EXPORTER_SUBSTR]
# Defaults:
#   BUFFERS_DIR     = /sys/kernel/dmabuf/buffers
#   EXPORTER_SUBSTR = (empty, no filter)
# Env:
#   PROCFS=/proc            (for local testing)
#   TMPDIR=/data/local/tmp  (needs a writable dir)
#
# The sysfs dir name is the dma-buf file's inode number (dmabuf specific,
# globally unique per boot: drivers/dma-buf/dma-buf.c dma_buf_getfile()).
# A process that mmaps the buffer has the same inode in /proc/<pid>/maps,
# with the pathname starting with "/dmabuf".

DIR=${1:-/sys/kernel/dmabuf/buffers}
PAT=${2:-}
PROC=${PROCFS:-/proc}
TMP=${TMPDIR:-/data/local/tmp}
INO=$TMP/.dmabuf_ino.$$
PSL=$TMP/.dmabuf_ps.$$

for d in "$DIR"/*; do
    [ -d "$d" ] || continue
    printf '%s %s %s\n' "${d##*/}" "$(cat "$d/size" 2>/dev/null)" \
        "$(cat "$d/exporter_name" 2>/dev/null)"
done > "$INO"

ps -A -o PID,NAME > "$PSL" 2>/dev/null

awk -v pat="$PAT" '
function hx(h,  i, c, v) {
    v = 0
    for (i = 1; i <= length(h); i++) {
        c = tolower(substr(h, i, 1))
        v = v * 16 + index("0123456789abcdef", c) - 1
    }
    return v
}
FILENAME == ARGV[1] { sz[$1] = $2; ex[$1] = $3; next }
FILENAME == ARGV[2] { comm[$1] = $2; next }
$6 ~ /^\/dmabuf/ && ($5 in sz) {
    if (pat != "" && index(ex[$5], pat) == 0) next
    n = split(FILENAME, p, "/")
    pid = p[n - 1]
    r = $1
    i = index(r, "-")
    kb = (hx(substr(r, i + 1)) - hx(substr(r, 1, i - 1))) / 1024
    k = $5 SUBSEP pid
    if (!(k in mkb)) pk[$5] = pk[$5] " " k
    mkb[k] += kb
    nmap[k]++
}
END {
    cnt = 0
    for (d in sz) if (pat == "" || index(ex[d], pat)) ord[++cnt] = d
    for (i = 2; i <= cnt; i++) {
        v = ord[i]; j = i - 1
        while (j >= 1 && sz[ord[j]] + 0 < sz[v] + 0) { ord[j + 1] = ord[j]; j-- }
        ord[j + 1] = v
    }
    print "== mapped (ino -> pids) =="
    for (i = 1; i <= cnt; i++) {
        d = ord[i]
        if (!(d in pk)) continue
        printf "ino=%-8s %10.2f MiB  %-14s\n", d, sz[d] / 1048576, ex[d]
        n = split(pk[d], ks, " ")
        for (j = 1; j <= n; j++) {
            split(ks[j], a, SUBSEP)
            printf "    pid=%-6s %-18s %d VMA  %.2f MiB\n", a[2],
                   (a[2] in comm ? comm[a[2]] : "?"), nmap[ks[j]], mkb[ks[j]] / 1024
        }
    }
    print "== no mapping found (fd-only, or already freed) =="
    for (i = 1; i <= cnt; i++) {
        d = ord[i]
        if (d in pk) continue
        printf "ino=%-8s %10.2f MiB  %-14s\n", d, sz[d] / 1048576, ex[d]
    }
}
' "$INO" "$PSL" "$PROC"/[0-9]*/maps 2>/dev/null

rm -f "$INO" "$PSL"

(2) 执行结果

/data/local/tmp # sh dmabuf_ino_pids.sh
== mapped (ino -> pids) ==
ino=2110          71.75 MiB  qcom_hgsl
    pid=3837   com.sam.Unity 1 VMA  71.75 MiB
...
ino=2204           0.03 MiB  qcom,system //共享的
    pid=1034   vendor.display.composer-service 1 VMA  0.03 MiB 
    pid=1085   surfaceflinger     1 VMA  0.03 MiB
    pid=3511   com.sam.island 1 VMA  0.03 MiB
...
== no mapping found (fd-only, or already freed) ==
ino=36            25.31 MiB  qcom,system


2. /sys/kernel/debug/dma_buf/bufinfo

提供了系统中所有 DMA-BUF 的概览。但是,由于在生产环境中挂载 debugfs 并不安全,因此可以使用 procfs 和 sysfs 来在生产系统上收集 DMA-BUF 的统计信息。

/sys/kernel/debug/dma_buf # cat bufinfo

Dma-buf Objects:
size            flags           mode            count           exp_name        ino             name
00028672        00000002        00080007        00000003        qcom,system     00002528        qcom,system
        Attached Devices:
Total 0 devices attached

00491520        00000002        00080007        00000004        qcom,system     00002527        qcom,system
        Attached Devices:
        hab-ogles
Total 1 devices attached

00028672        00000002        00080007        00000003        qcom,system     00002526        qcom,system
        Attached Devices:
...
...
00032768        00000002        00080007        00000001        msm_hab 00000001        <none>
        Attached Devices:
Total 0 devices attached


3. /sys/kernel/debug/dma_pools

/sys/kernel/debug/dma_pools # ls -l
-r-------- 1 root root 0 1970-01-01 01:00 pool_size_dma     //cat 0
-r-------- 1 root root 0 1970-01-01 01:00 pool_size_dma32   //cat 2097152
-r-------- 1 root root 0 1970-01-01 01:00 pool_size_kernel  //cat 2097152


4. /sys/kernel/debug/dmaengine/summary

/sys/kernel/debug/dmaengine # ls -l
-r--r--r-- 1 root root 0 1970-01-01 01:00 summary

只读,cat出来是空。


5. /proc/<pid>/maps

包含已 mmap 的 dma_buf 信息:/proc/<pid>/maps 第 5 列就是 inode,第 6 列路径以 /dmabuf 开头(dma-buf.c:166-180);dumpsys 的 DMA-BUF mapped 正是扫这里(android_os_Debug.cpp:745-773)。


6. /proc/<pid>/fdinfo/<fd>

这里面有 size/count/exp_name(dma-buf.c:1188-1200),如:

# for F in `ls`; do echo --------F=$F---------; cat $F; done
...
--------F=411---------
pos:    0
flags:  02000002
mnt_id: 8
ino:    2332
size:   28672
count:  9
exp_name:       qcom,system
name:   qcom,system
...


6.1 工具脚本

反查某进程持有的 dma-buf fd,打印 ino / 大小 / exporter / fd / refs。

(1) 脚本内容

PID=${1:?usage: $0 PID}
P=${PROCFS:-/proc}/$PID

if [ ! -d "$P" ]; then
    echo "no such pid: $PID" >&2
    exit 1
fi

seen=" "
total=0
nbuf=0
nfds=0

for f in "$P"/fd/*; do
    fd=${f##*/}
    info="$P/fdinfo/$fd"
    [ -r "$info" ] || continue
    exp=$(sed -n 's/^exp_name:[[:space:]]*//p' "$info" 2>/dev/null)
    [ -n "$exp" ] || continue
    size=$(sed -n 's/^size:[[:space:]]*//p' "$info" 2>/dev/null)
    refs=$(sed -n 's/^count:[[:space:]]*//p' "$info" 2>/dev/null)
    ino=$(stat -L -c '%i' "$f" 2>/dev/null)
    size=${size:-0}
    key=${ino:-fd:$fd}

    mb=$(( size / 1048576 ))
    frac=$(( size % 1048576 * 100 / 1048576 ))
    printf 'ino=%-8s %d.%02d MiB  %-14s fd=%-4s refs=%-4s %s\n' \
        "${ino:-?}" "$mb" "$frac" "$exp" "$fd" "${refs:-?}" "$(readlink "$f")"

    case "$seen" in
        *" $key "*) ;;
        *) seen="$seen$key "
           total=$(( total + size ))
           nbuf=$(( nbuf + 1 )) ;;
    esac
    nfds=$(( nfds + 1 ))
done

echo "----"
tmb=$(( total / 1048576 ))
tfrac=$(( total % 1048576 * 100 / 1048576 ))
printf 'pid=%s: %d bufs / %d fds, total %d.%02d MiB (%s B)\n' "$PID" "$nbuf" "$nfds" "$tmb" "$tfrac" "$total"

(2) 执行结果

/data/local/tmp # sh dmabuf_pid_fds.sh 2645
ino=1603     0.17 MiB  qcom,system    fd=226  refs=2    /dmabuf:qcom,system
ino=1604     0.02 MiB  qcom,system    fd=227  refs=3    /dmabuf:qcom,system
ino=1605     0.17 MiB  qcom,system    fd=228  refs=2    /dmabuf:qcom,system
ino=1606     0.02 MiB  qcom,system    fd=229  refs=3    /dmabuf:qcom,system
ino=1603     0.17 MiB  qcom,system    fd=230  refs=2    /dmabuf:qcom,system
ino=1604     0.02 MiB  qcom,system    fd=231  refs=3    /dmabuf:qcom,system
ino=1607     0.17 MiB  qcom,system    fd=233  refs=2    /dmabuf:qcom,system
ino=1608     0.02 MiB  qcom,system    fd=234  refs=3    /dmabuf:qcom,system
ino=1605     0.17 MiB  qcom,system    fd=236  refs=2    /dmabuf:qcom,system
ino=1606     0.02 MiB  qcom,system    fd=237  refs=3    /dmabuf:qcom,system
ino=1607     0.17 MiB  qcom,system    fd=241  refs=2    /dmabuf:qcom,system
ino=1608     0.02 MiB  qcom,system    fd=242  refs=3    /dmabuf:qcom,system
----
pid=2645: 6 bufs / 12 fds, total 0.62 MiB (651264 B)

 

posted on 2026-10-28 15:07  Hello-World3  阅读(2)  评论(0)    收藏  举报

导航