/proc и /sys — окно в kernel state
Если top, vmstat, iostat — это утилиты, которые показывают вам kernel state в красивом виде, то /proc и /sys — источник, откуда они эту информацию берут. Это виртуальные файловые системы: на диске их нет, kernel создаёт их inodes “на лету” и наполняет содержимым по запросу. Открыть файл из /proc — это спросить kernel “какое у тебя текущее состояние”.
В этом уроке: что такое pseudo-FS, как читать главные файлы (/proc/loadavg, /proc/meminfo, /proc/cpuinfo, /proc/[pid]/, /sys/class/net/), и как через echo в /proc/sys/ менять runtime kernel parameters без перекомпиляции.
Что это такое: virtual filesystem
/proc и /sys — не настоящие ФС. Они virtual: kernel создаёт inode и file_operations динамически. Когда вы делаете cat /proc/cpuinfo, происходит:
open("/proc/cpuinfo")— VFS видит, что это /proc, делегирует procfs.- procfs создаёт inode для файла.
read()— procfs вызывает callback, который формирует строки на лету (читая kernel state).close()— inode уничтожается.
Поэтому ls -l /proc/cpuinfo показывает размер 0:
$ ls -l /proc/cpuinfo
-r--r--r-- 1 root root 0 May 18 09:12 /proc/cpuinfo
$ wc -l /proc/cpuinfo
145 /proc/cpuinfo
Файл якобы 0 байт, но в нём 145 строк! Это потому что kernel генерирует содержимое в момент read, а stat показывает stored size (которого нет).
/proc — что тут
Главные категории файлов:
Общие kernel info:
$ ls /proc/ | head -30
1 # PID 1 -- systemd
123 # другие PID
...
buddyinfo # buddy allocator
cgroups
cmdline # kernel cmdline (как был загружен)
config.gz # config с которым собрана kernel (если включено)
cpuinfo # CPU info
crypto
devices # registered char/block drivers (видели в уроке 12.1)
diskstats # raw disk stats (iostat использует)
filesystems # supported FS
fs/ # FS internals (inotify, etc.)
interrupts # IRQ stats
iomem # memory map (физические адреса устройств)
ioports # ports map
kallsyms # kernel symbols (нужны root для отладки)
kmsg # kernel ring buffer (dmesg использует)
loadavg # load average + tasks
mdstat # md/RAID status
meminfo # memory breakdown
modules # loaded kernel modules (lsmod использует)
mounts # active mounts
net/ # сетевая info
partitions
schedstat
self -> /proc/<current pid> # symlink на свой PID
slabinfo # kernel slab allocator stats
stat # system stats (boot time, irq totals)
swaps # swap usage
sys/ # tunable kernel parameters
sysrq-trigger # сейчас не записал ли кто sysrq
sysvipc/ # SysV IPC (sem, msg, shm)
thread-self -> ...
tty/
uptime # uptime in seconds (cf top)
version # kernel version
vmstat # vm stats (vmstat -s использует)
zoneinfo # NUMA zones
Самые полезные /proc файлы
# Load average:
$ cat /proc/loadavg
1.42 1.05 0.87 1/287 12345
# Format: load1 load5 load15 runnable/total last-pid
# Память:
$ cat /proc/meminfo | head -15
MemTotal: 32985856 kB
MemFree: 3145728 kB
MemAvailable: 12345678 kB
Buffers: 124356 kB
Cached: 9821456 kB
...
# Uptime в секундах + idle time:
$ cat /proc/uptime
1234567.89 4521879.11
# uptime, sum of idle time per CPU
# Kernel cmdline:
$ cat /proc/cmdline
BOOT_IMAGE=/boot/vmlinuz-6.5.0-21 root=UUID=5d3e... ro quiet splash
# CPU info:
$ cat /proc/cpuinfo | grep 'model name' | head -1
model name : Intel(R) Core(TM) i7-9750H CPU @ 2.60GHz
# Active mounts:
$ cat /proc/mounts | head -5
sysfs /sys sysfs rw,nosuid,nodev,noexec,relatime 0 0
proc /proc proc rw,nosuid,nodev,noexec,relatime 0 0
devtmpfs /dev devtmpfs rw,nosuid,relatime,size=4015868k,nr_inodes=1003967,mode=755 0 0
tmpfs /run tmpfs rw,nosuid,nodev,noexec,relatime,size=1607672k,mode=755 0 0
/dev/nvme0n1p2 / ext4 rw,relatime,errors=remount-ro 0 0
# Interrupts breakdown:
$ cat /proc/interrupts | head
CPU0 CPU1 CPU2 CPU3
0: 33 0 0 0 IO-APIC 2-edge timer
1: 9 0 0 0 IO-APIC 1-edge i8042
8: 0 0 0 0 IO-APIC 8-edge rtc0
9: 1234567 234 456 789 IO-APIC 9-fasteoi acpi
16: 345678 123456 234567 345678 IO-APIC 16-fasteoi ehci_hcd:usb1
...
/proc/[pid] — per-process data
Каждый процесс имеет директорию в /proc по своему PID:
$ ls /proc/$$ # $$ -- PID текущей shell
attr/
auxv
cgroup
clear_refs
cmdline
comm
cwd -> /home/lev # symlink на cwd
environ # env vars
exe -> /usr/bin/bash # symlink на executable
fd/ # open file descriptors
fdinfo/
io # IO stats
limits # rlimits
maps # memory map
mountinfo
mounts
mountstats
net/
ns/ # namespaces
oom_adj
oom_score
oom_score_adj
root -> /
stat # main stats (ps использует)
status # human-readable status
syscall # текущий syscall (если в нём)
task/ # threads
wchan # waiting on what
Часто используемые:
# PID текущей shell:
echo $$
2345
# Command-line:
$ tr '\0' ' ' < /proc/2345/cmdline
bash
# Текущий cwd:
$ readlink /proc/2345/cwd
/home/lev
# Open fds:
$ ls -l /proc/2345/fd/
total 0
lrwx------ 1 lev lev 64 May 18 09:12 0 -> /dev/pts/0
lrwx------ 1 lev lev 64 May 18 09:12 1 -> /dev/pts/0
lrwx------ 1 lev lev 64 May 18 09:12 2 -> /dev/pts/0
lrwx------ 1 lev lev 64 May 18 09:12 255 -> /dev/pts/0
# Memory map:
$ cat /proc/2345/maps | head
55b234567000-55b234568000 r--p 00000000 fd:01 1234567 /usr/bin/bash
55b234568000-55b234678000 r-xp 00001000 fd:01 1234567 /usr/bin/bash
55b234678000-55b234712000 r--p 00111000 fd:01 1234567 /usr/bin/bash
...
7f8c12345000-7f8c12346000 r-xp 00000000 fd:01 7654321 /usr/lib/libc.so.6
[heap] ...
[stack] ...
# Status (более user-friendly):
$ cat /proc/2345/status | head -20
Name: bash
Umask: 0022
State: S (sleeping)
Tgid: 2345
Pid: 2345
PPid: 2344
TracerPid: 0
Uid: 1000 1000 1000 1000
Gid: 1000 1000 1000 1000
FDSize: 256
Groups: 4 24 27 30 46 116 1000
VmPeak: 14156 kB
VmSize: 14156 kB
VmRSS: 6789 kB <-- resident memory
VmData: 2345 kB
VmStk: 132 kB
VmExe: 968 kB
VmLib: 2345 kB
# IO stats:
$ cat /proc/2345/io
rchar: 12345678
wchar: 234567
syscr: 4567
syscw: 234
read_bytes: 1234567
write_bytes: 89012
cancelled_write_bytes: 0
Это огромное окно в каждый процесс. Multiple tools (lsof, gdb, strace) под капотом используют /proc.
/sys — структурированный hierarchy
/sys (sysfs) появилась позже /proc и более структурированная. Делится на:
$ ls /sys/
block/ # block devices: sda, nvme0n1
bus/ # buses: pci, usb, scsi
class/ # классы устройств: net, block, tty, input
dev/ # major:minor lookup
devices/ # физическая иерархия устройств
firmware/ # firmware info (efi)
fs/ # FS-specific (ext4 attrs, etc.)
hypervisor/ # if running in VM
kernel/ # kernel parameters
module/ # loaded modules
power/ # power management
Главные категории:
# Все сетевые интерфейсы:
ls /sys/class/net/
eth0 lo wlan0
# Информация про eth0:
ls /sys/class/net/eth0/
address # MAC
speed # текущая скорость в Mbps
duplex # full/half
operstate # up/down
mtu
rx_bytes # total
tx_bytes
statistics/ # детальная статистика
# Конкретные значения:
cat /sys/class/net/eth0/address
e0:d5:5e:12:34:56
cat /sys/class/net/eth0/speed
1000
cat /sys/class/net/eth0/statistics/rx_bytes
12345678901
# Block devices:
ls /sys/block/
nvme0n1 sda sdb
# Информация про nvme0n1:
cat /sys/block/nvme0n1/size
4000797360
# (число секторов 512 байт; * 512 = размер в байтах)
cat /sys/block/nvme0n1/queue/scheduler
[none] mq-deadline kyber bfq
# Текущий scheduler в [скобках]. Поменять:
echo mq-deadline > /sys/block/nvme0n1/queue/scheduler
# Per-CPU info:
ls /sys/devices/system/cpu/
cpu0 cpu1 cpu2 cpu3 cpufreq/ ...
cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_cur_freq
2600000 # текущая частота в кГц
/proc/sys — runtime kernel tuning через sysctl
/proc/sys — особенный subdir. В нём kernel parameters, которые можно менять записью:
# Текущее значение swappiness:
$ cat /proc/sys/vm/swappiness
60
# Поменять:
$ echo 10 | sudo tee /proc/sys/vm/swappiness
10
# Через sysctl:
$ sudo sysctl vm.swappiness=10
vm.swappiness = 10
# Все настройки сейчас:
$ sysctl -a | head -20
abi.vsyscall32 = 1
crypto.fips_enabled = 0
dev.cdrom.autoclose = 1
...
# Чтобы сохранить навсегда -- /etc/sysctl.d/:
$ sudo tee /etc/sysctl.d/99-myconf.conf <<EOF
vm.swappiness = 10
net.ipv4.tcp_keepalive_time = 600
kernel.sysrq = 1
EOF
# Применить:
$ sudo sysctl -p /etc/sysctl.d/99-myconf.conf
Полезные tunables:
# Memory:
vm.swappiness # 0-100, как агрессивно swap-ить (default 60, server обычно 10)
vm.dirty_ratio # % памяти для dirty pages until forced flush
vm.dirty_background_ratio # % для async flush
vm.overcommit_memory # 0/1/2 -- политика overcommit
vm.min_free_kbytes # минимум, который kernel держит свободным
# Network:
net.ipv4.tcp_keepalive_time
net.ipv4.tcp_max_syn_backlog
net.core.somaxconn # макс backlog для listen()
net.ipv4.ip_local_port_range # эфемерные порты
# Filesystem:
fs.file-max # макс открытых файлов всего
fs.inotify.max_user_watches
# Process / IPC:
kernel.pid_max # макс PID
kernel.sysrq # включить SysRq key
# Security:
kernel.unprivileged_userns_clone
kernel.kptr_restrict
sysctl tuning — мощный tool, но может разрушить систему. Test на dev-машине сначала. И знайте, что нужно: tuning vm.swappiness=0 на production иногда хорошо, иногда плохо — зависит от workload. Не копировать настройки слепо из stack overflow.
Live writing в /proc и /sys (примеры)
# Drop page cache (полезно для benchmark):
sudo sync # сначала flush dirty
sudo bash -c "echo 3 > /proc/sys/vm/drop_caches" # потом drop
# 1 = pagecache, 2 = dentries/inodes, 3 = both
# Force kernel panic (для тестирования high availability):
echo c | sudo tee /proc/sysrq-trigger # CAREFUL!
# Поменять disk scheduler:
echo mq-deadline | sudo tee /sys/block/sda/queue/scheduler
# Включить hotplug rescan SCSI:
echo '- - -' | sudo tee /sys/class/scsi_host/host0/scan
# Поменять MTU сетевой:
echo 9000 | sudo tee /sys/class/net/eth0/mtu
# Force re-detect mouse:
echo 'mouse_event' | sudo tee /sys/class/input/input2/uevent
/proc/diskstats — raw data для iostat
iostat использует /proc/diskstats:
$ cat /proc/diskstats | head
8 0 sda 1234567 23456 89012345 234567 234567 89012 78901234 567890 0 234567 802457
8 1 sda1 234567 1234 1234567 23456 12345 567 1234567 23456 0 23456 46912
259 0 nvme0n1 1234567890 234567 12345678901 2345678 345678901 23456 89012345678 12345678 0 1234567 13991346
15 колонок per partition. Самые важные: 1-2: major, minor. 3: имя. 4: reads completed. 6: reads merged. 7: sectors read. 8: time spent reading (ms). 9-13: writes (то же самое). 14: IOs currently in progress. 15: time spent doing IOs (ms) — для %util.
iostat вычисляет дельты двух snapshot’ов /proc/diskstats и делит на интервал.
/proc/interrupts — IRQ activity
$ cat /proc/interrupts | head -10
CPU0 CPU1 CPU2 CPU3
0: 33 0 0 0 IO-APIC 2-edge timer
1: 654 12 5 7 IO-APIC 1-edge i8042
8: 0 0 0 0 IO-APIC 8-edge rtc0
9: 1234567 234 456 789 IO-APIC 9-fasteoi acpi
16: 345678 123456 234567 345678 IO-APIC 16-fasteoi ehci_hcd:usb1
17: 1234567 1345678 2345678 1234567 IO-APIC 17-fasteoi nvme0q1, eth0
Колонки — per-CPU counts. Последний столбец — описание (источник IRQ).
Что искать:
- IRQ концентрируется на одном CPU — IRQ affinity issue. Попробуйте
irqbalanceили вручную:echo 0xf | sudo tee /proc/irq/16/smp_affinity # все 4 CPU могут принимать IRQ 16 - Слишком много interrupts от network — может помочь polling mode (NAPI, RPS), interrupt coalescing.
Попробуй сам
# 1. Прочитать главное:
cat /proc/loadavg
cat /proc/uptime
cat /proc/version
cat /proc/cmdline
# 2. Per-process:
echo $$
cat /proc/$$/status | head -20
ls /proc/$$/fd/
cat /proc/$$/cmdline | tr '\0' ' '; echo
# 3. Memory deep dive:
cat /proc/meminfo | grep -i 'swap\|anon\|file\|slab' | head -10
# 4. CPU info:
grep 'model name' /proc/cpuinfo | head -1
grep -c '^processor' /proc/cpuinfo
# 5. Сетевые интерфейсы через /sys:
for iface in /sys/class/net/*/; do
name=$(basename $iface)
state=$(cat $iface/operstate 2>/dev/null)
mac=$(cat $iface/address 2>/dev/null)
echo "$name: $state, $mac"
done
# 6. Поменять swappiness (требует root):
sudo sysctl vm.swappiness
sudo sysctl vm.swappiness=10 # временно
# 7. Drop page cache и наблюдать:
free -h # перед
sync; echo 3 | sudo tee /proc/sys/vm/drop_caches # drop
free -h # после: cache меньше
# 8. Конкретные kernel params:
sudo sysctl -a | grep tcp_keepalive
# 9. IRQ topology:
cat /proc/interrupts | head -10