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 버퍼의 전체 크기가 표시됩니다. 총계는 루트 사용자로 "drm mm object" 또는 "i915"를 한 번 이상 입력하여 계산할 수 있습니다.

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-logind두 번째 인스턴스를 나타냅니다 . gnome-shell텍스트 로그인을 실행하는 가상 콘솔로 전환하면 이 파일에는 두 systemd-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%/300MB 를 초과할 수 없는 시스템을 보여줍니다 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

로그인한 두 명의 그놈 사용자 중 한 명을 로그아웃하기 전과 후는 다음과 같습니다. 이는 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')

관련 정보