내 /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>/maps
GEM/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 objects
600KB만 표시되는 것을 확인했습니다 . mapped
여기서의 의미는 제가 예상했던 것과는 다른 것 같아요 . 비교를 위해 다음 Python 스크립트를 실행하여 사용자 프로세스 주소 공간에 매핑된 i915 개체를 표시하면 총 70MB가 표시됩니다.
내 출력의 줄은 다른 가상 콘솔에서 실행되는 systemd-logind
두 번째 인스턴스를 나타냅니다 . gnome-shell
텍스트 로그인을 실행하는 가상 콘솔로 전환하면 이 파일에는 두 systemd-logind
줄만 표시되지만 아무것도 표시되지 않습니다 gnome-shell
. :-).
/proc/*/fd/
그렇지 않은 경우 최선의 방법은 /proc/*/map_files/
및 (또는)에서 열려 있는 모든 파일을 검색하여 일부 shmem 파일을 찾는 것 입니다 /proc/*/maps
.
올바른 기술을 사용하면 어떤 파일이 숨겨진 shmem 파일 시스템에 속하는지 확실하게 식별하는 것이 가능해 보입니다.
각 공유 메모리 개체는 이름이 있는 파일입니다. 이러한 이름은 파일을 생성한 커널 하위 시스템을 식별하는 데 사용할 수 있습니다.
- SYSV00000000
- i915(예: Intel GPU)
- memfd:gdk-wayland
- 개발/제로("익명" 공유 매핑의 경우)
- ...
문제는 이게 진짜라는 거다.아니요모든 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')