Posso ver a quantidade de memória alocada como buffers GEM?

1

Meu /proc/meminfo mostra que cerca de 500 MB estão alocados como Shmem . Eu quero obter números mais específicos. Eu encontrei uma explicação aqui:

link

It includes tmpfs memory, SysV shared memory (from ipc/shm.c), POSIX shared memory (under /dev/shm [which is a tmpfs]), and shared anonymous mappings (from mmap of /dev/zero with MAP_SHARED: see call to shmem_zero_setup() from drivers/char/mem.c): whatever allocates pages through mm/shmem.c.

2-> as per the developer comments NR_SHMEM included tmpfs and GEM pages whct is Gem pages

     

Ah sim, e o Gerenciador de Execução de Imagens usa shmem para objetos compartilhados   com a GPU: veja o uso de shmem_read_mapping_page * () em drivers / gpu / drm /.

Eu tenho sobre

  • 50 MB em tmpfs visíveis ao usuário, encontrados com df -h -t tmpfs .
  • 40MB (10.000 páginas de 4096 bytes) na memória compartilhada sysvipc, encontrada com ipcs -mu .

Eu gostaria de obter uma contabilização mais positiva, para o que usa os 500MB! Existe uma maneira de mostrar as alocações totais do GEM? (Ou qualquer outro contribuinte provável).

Espero ter algumas alocações do GEM, já que estou executando uma área de trabalho gráfica no hardware de hardware da Intel. Minha versão do kernel é 4.18.16-200.fc28.x86_64 (Fedora Workstation 28).

    
por sourcejedi 19.11.2018 / 17:15

2 respostas

0

Você pode encontrar alguns dos arquivos shmem procurando por todos os arquivos abertos, em /proc/*/fd/ e /proc/*/map_files/ (ou /proc/*/maps ).

Com os hacks certos, parece ser possível identificar com segurança quais arquivos pertencem ao (s) sistema (s) de arquivos shmem oculto.

Cada objeto de memória compartilhada é um arquivo com um nome. E os nomes podem ser usados para identificar qual subsistema de kernel criou o arquivo.

No entanto, isso não mostra todas as alocações de DRM / GEM. Os buffers de DRM podem existir sem serem mapeados, simplesmente como um identificador numérico. Estes estão ligados ao arquivo DRM aberto em que foram criados. Quando o programa falha ou é eliminado, o arquivo DRM será fechado e todas as suas alças de DRM serão limpas automaticamente. (A menos que algum outro software mantenha uma cópia do descritor de arquivo aberto, como este bug antigo .

link

Você pode encontrar arquivos DRM abertos em /proc/*/fd/ , mas eles são exibidos como um arquivo de tamanho zero com blocos zero alocados.

Por exemplo, no momento, ainda não consigo contabilizar mais de 50% / 300 MB do meu 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  

Todos os arquivos abertos no (s) sistema (s) de arquivos shmem oculto:

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

Aqui está um "antes e depois", desconectando um dos meus dois usuários registrados do GNOME. Pode ser explicado se gnome-shell tinha mais de 100 MB de buffers DRM não mapeados.

$ 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

Script Python para gerar a saída acima:

#!/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')
    
por 20.11.2018 / 17:34
1

Eles aparecem em mapas de processo como " objeto drm mm ” ou " i915 ”. Você pode ver isso em /proc/<pid>/maps ; dado o PID de um processo usando GEM / DRM:

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

mostrará o tamanho total dos buffers GEM alocados. O cálculo do total pode ser feito alimentando-se em todos os mapas que contenham pelo menos uma ocorrência de “objeto drm mm” ou “i915”; como root:

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 é necessário para evitar a visualização de mapas de encadeamentos). Alguma desduplicação adicional baseada em inode pode ser necessária.

    
por 19.11.2018 / 17:52