![我可以看到分配为 GEM 缓冲区的内存量吗?](https://linux22.com/image/142339/%E6%88%91%E5%8F%AF%E4%BB%A5%E7%9C%8B%E5%88%B0%E5%88%86%E9%85%8D%E4%B8%BA%20GEM%20%E7%BC%93%E5%86%B2%E5%8C%BA%E7%9A%84%E5%86%85%E5%AD%98%E9%87%8F%E5%90%97%EF%BC%9F.png)
我的/proc/meminfo
节目大约 500 MB 被分配为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 分配,因为我在英特尔图形硬件上运行图形桌面。我的内核版本是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
有必要避免查看线程映射)。可能需要一些额外的基于索引节点的重复数据删除。
答案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(即英特尔 GPU)
- memfd:gdk-wayland
- 开发/零(对于任何“匿名”共享映射)
- ...
问题是这确实不是显示所有 DRM/GEM 分配。 DRM 缓冲区可以在不映射的情况下存在,只是作为数字句柄。它们与创建它们时所用的打开的 DRM 文件相关联。当程序崩溃或被杀死时,DRM文件将被关闭,并且其所有DRM句柄将被自动清理。 (除非某些其他软件保持文件描述符的副本打开,就像这个老虫子.)
https://www.systutorials.com/docs/linux/man/7-drm-gem/
您可以在 中找到打开的 DRM 文件/proc/*/fd/
,但它们显示为分配了零块的零大小文件。
例如,下面的输出显示了一个我无法占用超过 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 用户之一的“之前和之后”。如果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')