GEMバッファに割り当てられたメモリ量を確認できますか?

GEMバッファに割り当てられたメモリ量を確認できますか?

私の/proc/meminfoプログラムには約500MBが割り当てられていますShmem。より具体的な数字を知りたいです。ここで説明を見つけました。

https://lists.kernelnewbies.org/pipermail/kernelnewbies/2013-July/008628.html

これには、tmpfsメモリ、SysV共有メモリ(ipc / shm.cから)、POSIX共有メモリ(/ dev / shm [tmpfs]の下)、共有匿名マップ(/ dev / zeroのmmapとMAP_SHARED:参照)が含まれます。 drivers/char/mem.c から shmem_zero_setup() 呼び出し: mm/shmem.c を介したページ割り当て。

2->開発者のコ​​メントによると、NR_SHMEMにはtmpfsとGEMページが含まれています。 GEMページとは何ですか?

はい、グラフィカル実行マネージャはshmemを使用してGPUと共有されるオブジェクトを保存します。 drivers/gpu/drm/ で shmem_read_mapping_page*() を使用するをご覧ください。

私は薬です

  • 経由でユーザーに表示されるtmpfsには50MBがありますdf -h -t tmpfs
  • sysvipc共有メモリ内の40MB(10,000ページ、4096バイト)ipcs -mu、。

500MBの用途についてもう少し積極的に説明したい!総GEMクォータを表示する方法はありますか? (または他の可能な貢献者)。

Intelグラフィックハードウェアでグラフィックデスクトップを実行しているので、いくつかのGEMを割り当ててほしいです。私のカーネルバージョンは4.18.16-200.fc28.x86_64(Fedora Workstation 28)です。

答え1

これはフローチャートに次のように表示されます。「drm mmオブジェクト」または「i915」/proc/<pid>/mapsGEM / DRMを使用しているプロセスのPIDを見ると、次のようになります。

awk '/(drm mm object)|i915/ { hypidx = index($1, "-"); from = substr($1, 1, hypidx - 1); to = substr($1, hypidx + 1); sum += strtonum("0x" to) - strtonum("0x" from) } END { print sum }' /proc/${PID}/maps

割り当てられたGEMバッファの合計サイズが表示されます。合計は、rootユーザーとして「drm mm object」または「i915」を1回以上入力することによって計算できます。

find /proc -maxdepth 2 -name maps |
xargs grep -E -l "(drm mm object)|i915" |
xargs awk '/(drm mm object)|i915/ { hypidx = index($1, "-"); sum += strtonum("0x" substr($1, hypidx + 1)) - strtonum("0x" substr($1, 1, hypidx - 1)) } END { print sum }'

-maxdepth 2スレッドマップを見るのを避ける必要があります)。いくつかの追加のinodeベースの重複排除が必要な場合があります。

答え2

編集:カーネルのデバッグ目的にのみ使用されるインターフェイスがあります。アクセスのみ可能rootで不安定です。カーネル開発者でない場合は、上書き、名前変更、または方向が正しく指定されていない可能性があります。 (私が知っているのは欠陥があるかもしれません。)しかし、問題が発生した場合、問題が存在することを知っておくと便利です。

運転i915手が提供した情報は次のとおりです。

$ sudo sh -c 'cat /sys/kernel/debug/dri/*/i915_gem_objects'
643 objects, 205852672 bytes
75 unbound objects, 7811072 bytes
568 bound objects, 198041600 bytes
16 purgeable objects, 5750784 bytes
16 mapped objects, 606208 bytes
13 huge-paged objects (2M, 4K) 123764736 bytes
13 display objects (globally pinned), 14954496 bytes
4294967296 [0x0000000010000000] gtt total
Supported page sizes: 2M, 4K

[k]contexts: 16 objects, 548864 bytes (0 active, 548864 inactive, 548864 global, 0 shared, 0 unbound)
systemd-logind: 324 objects, 97374208 bytes (0 active, 115798016 inactive, 23941120 global, 5246976 shared, 3858432 unbound)
Xwayland: 24 objects, 6995968 bytes (0 active, 12169216 inactive, 5283840 global, 5246976 shared, 110592 unbound)
gnome-shell: 246 objects, 89739264 bytes (26517504 active, 120852480 inactive, 63016960 global, 5242880 shared, 3629056 unbound)
Xwayland: 25 objects, 17309696 bytes (0 active, 22503424 inactive, 5304320 global, 5242880 shared, 90112 unbound)

もう一度注意して進めてください。mapped objects600KBのみ表示されることを確認しました。mappedここでの意味は、私が予想したものとは異なるようです。比較のために、次のPythonスクリプトを実行してユーザープロセスのアドレス空間にマップされたi915オブジェクトを表示すると、合計70MBが表示されます。

私の出力の行は、別の仮想コンソールで実行されているsystemd-logind2番目のインスタンスを表します。gnome-shellテキストログインを実行している仮想コンソールに切り替えると、このファイルには2systemd-logind行しか表示されませんが、何も表示されませんgnome-shell。 :-).


/proc/*/fd/そうでない場合の最善の方法は、および/proc/*/map_files/(または)で開いているすべてのファイルを検索していくつかのshmemファイルを見つけることです/proc/*/maps

正しい技術を使用すると、どのファイルが隠されたshmemファイルシステムに属しているかを確実に識別することが可能になります。

各共有メモリオブジェクトは名前のファイルです。これらの名前は、ファイルを生成したカーネルサブシステムを識別するために使用できます。

問題はこれが本当だということだ。いいえすべてのDRM / GEM割り当てを表示します。 DRMバッファは、デジタルハンドルのようにマッピングなしで存在できます。これは、作成時に使用されたオープンDRMファイルに関連付けられます。プログラムがクラッシュまたはシャットダウンすると、DRMファイルが閉じられ、すべてのDRMハンドルが自動的にクリーンアップされます。 (他のソフトウェアがファイル記述子のコピーを開いていない限り、この古いバグのように.)

https://www.systutorials.com/docs/linux/man/7-drm-gem/

で開いたDRMファイルが見つかりますが、/proc/*/fd/ブロックが割り当てられていないサイズが0のファイルとして表示されます。

たとえば、次の出力は50%/ 300 MBを超えることができないシステムを示していますShmem

$ grep Shmem: /proc/meminfo
Shmem:            612732 kB

$ df -h -t tmpfs
Filesystem      Size  Used Avail Use% Mounted on
tmpfs           3.9G   59M  3.8G   2% /dev/shm
tmpfs           3.9G  2.5M  3.9G   1% /run
tmpfs           3.9G     0  3.9G   0% /sys/fs/cgroup
tmpfs           3.9G  9.0M  3.9G   1% /tmp
tmpfs           786M   20K  786M   1% /run/user/42
tmpfs           786M  8.0M  778M   2% /run/user/1000
tmpfs           786M  5.7M  781M   1% /run/user/1001

$ sudo ipcs -mu

------ Shared Memory Status --------
segments allocated 20
pages allocated 4226
pages resident  3990
pages swapped   0
Swap performance: 0 attempts     0 successes  

shmem ファイルシステムで開いているすべてのファイルを非表示にします。

$ sudo python3 ~/shm -s
15960   /SYSV*
79140   /i915
7912    /memfd:gdk-wayland
1164    /memfd:pulseaudio
104176

ログインした2人のGNOMEユーザーの1人をログアウトする前と後は、次のようになります。これはgnome-shell、マップされていないDRMバッファが100MBを超えると発生する可能性があります。

$ grep Shmem: /proc/meminfo
Shmem:            478780 kB
$ df -t tmpfs -h
Filesystem      Size  Used Avail Use% Mounted on
tmpfs           3.9G  4.0K  3.9G   1% /dev/shm
tmpfs           3.9G  2.5M  3.9G   1% /run
tmpfs           3.9G     0  3.9G   0% /sys/fs/cgroup
tmpfs           3.9G  276K  3.9G   1% /tmp
tmpfs           786M   20K  786M   1% /run/user/42
tmpfs           786M  8.0M  778M   2% /run/user/1000
tmpfs           786M  5.7M  781M   1% /run/user/1001
$ sudo ./shm -s
80  /SYSV*
114716  /i915
1692    /memfd:gdk-wayland
1156    /memfd:pulseaudio
117644

$ grep Shmem: /proc/meminfo
Shmem:            313008 kB
$ df -t tmpfs -h
Filesystem      Size  Used Avail Use% Mounted on
tmpfs           3.9G  4.0K  3.9G   1% /dev/shm
tmpfs           3.9G  2.1M  3.9G   1% /run
tmpfs           3.9G     0  3.9G   0% /sys/fs/cgroup
tmpfs           3.9G  204K  3.9G   1% /tmp
tmpfs           786M   20K  786M   1% /run/user/42
tmpfs           786M  6.8M  780M   1% /run/user/1000
$ sudo ./shm -s
40  /SYSV*
88496   /i915
1692    /memfd:gdk-wayland
624 /memfd:pulseaudio
90852

上記の出力を生成するために使用されたPythonスクリプト:

#!/bin/python3
# Reads Linux /proc.  No str, all bytes.

import sys
import os
import stat
import glob
import collections
import math

# File.
# 'name' is first name encountered, we don't track hardlinks.
Inode = collections.namedtuple('Inode', ['name', 'bytes', 'pids'])

# inode number -> Inode object
inodes = dict()
# pid -> program name
pids = dict()
# filename -> list() of Inodes
filenames = dict()

def add_file(pid, proclink):
    try:
        vfs = os.statvfs(proclink)

        # The tmpfs which reports 0 blocks is an internal shm mount
        # python doesn't admit f_fsid ...
        if vfs.f_blocks != 0:
            return
        filename = os.readlink(proclink)
        # ... but all the shm files are deleted (hack :)
        if not filename.endswith(b' (deleted)'):
            return
        filename = filename[:-10]
        # I tried a consistency check that all our st_dev are the same
        # but actually there can be more than one internal shm mount!
        # i915 added a dedicated "gemfs" so they could control mount options.

        st = os.stat(proclink)

        # hack the second: ignore deleted character devices from devpts
        if stat.S_ISCHR(st.st_mode):
            return

        # Read process name succesfully,
        # before we record file owned by process.
        if pid not in pids:
            pids[pid] = open(b'/proc/' + pid + b'/comm', 'rb').read()[:-1]

        if st.st_ino not in inodes:
            inode_pids = set()
            inode_pids.add(pid)

            inode = Inode(name=filename,
                          bytes=st.st_blocks * 512,
                          pids=inode_pids)
            inodes[st.st_ino] = inode
        else:
            inode = inodes[st.st_ino]
            inode.pids.add(pid)

        # Group SYSV shared memory objects.
        # There could be many, and the rest of the name is just a numeric ID
        if filename.startswith(b'/SYSV'):
            filename = b'/SYSV*'

        filename_inodes = filenames.setdefault(filename, set())
        filename_inodes.add(st.st_ino)

    except FileNotFoundError:
        # File disappeared (race condition).
        # Don't bother to distinguish "file closed" from "process exited".
        pass

summary = False
if sys.argv[1:]:
    if sys.argv[1:] == ['-s']:
        summary = True
    else:
        print("Usage: {0} [-s]".format(sys.argv[0]))
        sys.exit(2)

os.chdir(b'/proc')
for pid in glob.iglob(b'[0-9]*'):
    for f in glob.iglob(pid + b'/fd/*'):
        add_file(pid, f)
    for f in glob.iglob(pid + b'/map_files/*'):
        add_file(pid, f)

def pid_name(pid):
    return pid + b'/' + pids[pid]

def kB(b):
    return str(math.ceil(b / 1024)).encode('US-ASCII')

out = sys.stdout.buffer

total = 0
for (filename, filename_inodes) in sorted(filenames.items(), key=lambda p: p[0]):
    filename_bytes = 0
    for ino in filename_inodes:
        inode = inodes[ino]
        filename_bytes += inode.bytes
        if not summary:
            out.write(kB(inode.bytes))
            out.write(b'\t')
            #out.write(str(ino).encode('US-ASCII'))
            #out.write(b'\t')            
            out.write(inode.name)
            out.write(b'\t')
            out.write(b' '.join(map(pid_name, inode.pids)))
            out.write(b'\n')
    total += filename_bytes
    out.write(kB(filename_bytes))
    out.write(b'\t')
    out.write(filename)
    out.write(b'\n')
out.write(kB(total))
out.write(b'\n')

関連情報