Linux: ядро (kernel), процессы /proc в ОС и работа с ними (proc, ps, lsof, nice, kill, killall, top, lscpu, interrupts, smp irq affinity, isolcpus, taskset, cpuset/cset shield), утилизация процессора (user/system/idle/iowait/softirq)

  • kernel parameters /proc/cmdline (можно редактировать конфигом GRUB)
  • kernel parameters modification /etc/sysctl.confВ Linux все рассматривается как файлы, включая устройства (/dev) и процессы (/proc).
  • Про перевод процессов в background в Linux подробнее в hotkeys (jobs, fg, bg, ctrl+z)

Процессы запускаются самой системой для функционирования системы, такие процессы называют background/daemon process. Разделение на application и background processes можно увидеть в Windows taskmanager.

Одна программа может инициировать множество процессов (chrome, mediaplayer). При запуске процесс получает Process ID (PID, уникальный идентификатор процесса). Так же каждый процесс запрашивает физические ресурсы у ядра системы – CPU, RAM, HDD/SDD (i/o), NIC. При завершении процесса (автоматически или вручную) ресурсы возвращаются обратно ядру. Особенно удобно потребление ресурсов просмотривать в Мониторинге ресурсов (Windows) или top (Linux).

Процессы в linux построены в древовидной структуре – каждый процесс имеет своего родителя, кроме init (см. ps -auxf или ps -ef) pid 1, который и является порождением других процессов. Справедливо и при использовании pipe – cat 1 | grep 2 – grep будет являться дочерним для cat.

A process is a program or command running on the system. Every process has a unique numeric identifier, known as the process identifier (PID), which is used by the kernel to manage and control the process through its lifecycle. The process with PID 0 is started first at system boot, followed by the process with PID 1, and so on. Processes are organized in a hierarchical fashion.

When a process completes its lifecycle or is terminated, this event is reported back to its parent process, and all the resources provisioned to it are then freed and the PID is removed.

В Linux дочерние процессы не могут работать независимо от родительских, в отличии от Windows (там дочерний процесс связан с родительским только в момент создания – заимствует environment:переменные/настройки). Видно это например при запуске из консоли приложения – если в Windows убить консоль, то с приложением ничего не будет, в отличии от Linux, который дропнет child процесс при отключении родительского (поэтому так полезны в Linux демоны/сервисы/screen).

Each process has a parent process (a.k.a. a calling process) that spawns it. Asingle parent process may have one or many child processes and passes many of its attributes to them at the time of their creation.

Процессам можно передавать сигналы Sig/Signals. Сигналы вообще основном способ взаимодействия между процессами/ядром и процессами, а не только между пользователем и процессом. С точки зрения пользователя Ctrl-c и в Windows и в Linux передает сигнал sigint (signal interrupt), который шлет прерывание процесса от системы процессу. В отличии от Linux, в Windows пользователю сложно отправить произвольный сигнал программе с командной строки (кроме прерывания ctrl-c). В Linux же таких сигналов очень много (смотрим через kill -l) и их можно отправить через kill, начинаются они по названию с приставки SIG (сокращенно от Signal, например sigint).

nice

У процессов есть приоритет исполнения на CPU – задачи с повышенном приоритетом исполняются первыми. В случае с Linux это называется niceness (nice value), значения в range от -20 до +19. Большая часть процессов по умолчанию запускается с значением 0 (в некоторых системах 10), дефолтное значение можно узнать командой nice без аргументов. Чем НИЖЕ значение nice у процесса, тем ВЫШЕ ее приоритет (принцип как в гольфе). Child процесс наследует nice значение у родительского. Посмотреть значение nice можно в top или по ps -efl.

Пример использования nice для повышения приоритета процесса tcpdump. На практике чаще применяется для таких процессов как backup для того, чтобы они не влияли на основные процессы системы во время backup.

# nice --adjustment=-10 tcpdump -s 1514 -i eth2 -w /tmp/ramdisk/ecg_sniffer_eth2_20180321.pcap
A process is spawned at a certain priority, which is established at initiation based on a numeric value called niceness (or a nice value). There are 40 niceness values, with –20 being the highest and +19 the lowest. Most system-started processes use the default niceness of 0. A higher niceness lowers the execution priority of a process and a lower niceness increases it. In other words, a process running at a higher priority gets more CPU scheduler attention. A child process inherits the niceness of its calling process in calculating its priority. Though we normally run programs at the default niceness, we may choose to initiate them at a different niceness to adjust their priority based on urgency and system load.

We can view current process priorities and niceness values with the ps command, the top command, and the system monitor GUI.
Просмотр процессов

ps (в Windows taskmanager ctrl-shift-esc, tasklist/get-process, process explorer) – process show – позволяет посмотреть процессы, запущенные в системе. По умолчанию, ps показывает только принадлежащие вам процессы (freebsd) или только принадлежащие текущему терминалу pts (Linux).

Альтернатива – просмотр папок для PID в /proc/<PID>. Оттуда ps (так же как и другие команды, например top), берет информацию о процессах. В этой папке можно найти всю-всю-всю информацию о конкретном процессе. 

The data located under /proc is referenced by a number of system utilities, including top, ps, uname, and vmstat, for display purposes.

Популярные наборы опций:

~$ ps -ef
~$ ps -auxf
~$ ps -fU redkin_p
~$ ps -fG sudo
~$ ps -efl

Популярные опции:

-a - показывается все пользовательские процессы
-e - показывает все процессы, включая системные
-f/F/l - добавляются разные колонки к стандартному выводу. l добавляет pri/ni колонкие с значением niceness (приоритета процесса)
-U - фильтрация по пользователю
-G - фильтрация по группе

(файлы/процессы) lsof – показывает какие файлы используются какими процессами (включая библиотеки/логи и про). А т.к. в linux все есть файлы – это зачастую очень полезная утилита, полезна, например, для размонтирования флешек, поиска места, куда пишет лог процесс, какие библиотеки использует.

root@spr:~# lsof | grep squ
squid 526 root cwd DIR 8,1 4096 2 /
squid 526 root rtd DIR 8,1 4096 2 /
squid 526 root txt REG 8,1 7076024 144505 /usr/sbin/squid
squid 526 root mem REG 8,1 282752 139004 /usr/lib/x86_64-linux-gnu/libnss_systemd.so.2
squid 526 root mem REG 8,1 55792 131763 /usr/lib/x86_64-linux-gnu/libnss_files-2.28.so
squid 526 root mem REG 8,1 35224 132160 /usr/lib/x86_64-linux-gnu/libffi.so.6.0.4
squid 526 root mem REG 8,1 26616 136067 /usr/lib/x86_64-linux-gnu/libmnl.so.0.2.0
log_file_ 2307 proxy 3w REG 8,1 0 3671227 /var/log/squid/access.log
pinger 2308 proxy cwd DIR 8,1 4096 3672167 /var/spool/squid
pinger 2308 proxy txt REG 8,1 80536 144498 /usr/lib/squid/pinger
pinger 2308 proxy 2u REG 8,1 5928 3672498 /var/log/squid/cache.log
 

init – первый процесс стартуемый в системе linux. Имеет pid 1. Стартует другие процессы необходимые для работы системы. 

~$ ps -aux | grep init
root 1 0.0 0.0 33700 1960 ? Ss янв.11 0:04 /sbin/init

Поля:

Each process is in one state at any given time. These states are running, sleeping, waiting, stopped, and zombie, and are explained below:
Running
: the process is being executed by the system CPU.
Stopped: the process is currently halted and will not run even when its turn comes, unless a signal is sent to it to change its behavior.
Sleeping: the process is waiting for input from a user or another process.
Waiting: the process has received the input it was waiting for and is now ready to run as soon as its turn arrives.
Zombie: the process is dead. A zombie process exists in the process table alongside other process entries, but it takes up no resources!!!!. Its entry is retained until the parent process permits it to die. Azombie process is also called a defunct process
  • STIME/START – когда запущен процесс
  • TIME – время которое CPU обрабатывает процесс (совокупное)
TIME - Aggregated execution time for the process, including time spent in both userland and kernel space.
  • COMMAND – исполняемая команда/процесс. При использовании флага -f совместно с -aux (-auxf) показывается дерево зависимостей процесса. Это может быть полезно для отслеживания приложения-источника, например zombie/defunct процессов (можно отследить и по ps -ef).
~$ ps -auxf
redkin_p 11293 0.0 0.0 27560 1928 ? Ss февр.02 0:00 SCREEN -S tp_daemon
redkin_p 11294 0.0 0.1 23664 2468 pts/2 Ss+ февр.02 0:00 \_ /bin/bash
redkin_p 6511 0.0 0.1 23692 2912 pts/4 Ss марта11 0:00 \_ /bin/bash
redkin_p 4098 0.0 0.1 107076 2304 pts/4 S+ марта11 0:00 \_ python3 bin/tp_snmp_proxy.py
root 9507 0.0 0.2 392396 4880 ? Ss февр.19 1:10 /usr/sbin/apache2 -k graceful
www-data 19494 0.0 0.2 392964 4692 ? S марта10 0:00 \_ /usr/sbin/apache2 -k graceful
www-data 19495 0.0 0.2 393208 4668 ? S марта10 0:00 \_ /usr/sbin/apache2 -k graceful
www-data 19496 0.0 0.2 393208 4840 ? S марта10 0:00 \_ /usr/sbin/apache2 -k graceful
redkin_p 29897 1.5 3.9 1171484 81616 ? Sl 03:00 9:54 ruby /home/redkin_p/bin/sms.rb
redkin_p 31681 0.0 0.0 0 0 ? Z 10:49 0:00 \_ [sh] <defunct>
redkin_p 936 0.0 0.0 0 0 ? Z 10:49 0:00 \_ [sh] <defunct>
redkin_p 9125 0.0 0.0 0 0 ? Z 10:50 0:00 \_ [sh] <defunct>
redkin_p 9446 0.0 0.0 0 0 ? Z 10:50 0:00 \_ [sh] <defunct>

~$ ps -ef | head
UID PID PPID C STIME TTY TIME CMD
root 1 0 0 янв.11 ? 00:00:04 /sbin/init
root 2 0 0 янв.11 ? 00:00:00 [kthreadd]
root 3 2 0 янв.11 ? 00:22:33 [ksoftirqd/0]
root 5 2 0 янв.11 ? 00:00:00 [kworker/0:0H]
root 7 2 0 янв.11 ? 01:04:51 [rcu_sched]

~$ ls -l /proc/ | head
total 0
dr-xr-xr-x 9 root root 0 янв. 30 00:30 1
dr-xr-xr-x 9 root root 0 янв. 30 00:30 10
dr-xr-xr-x 9 redkin_p redkin_p 0 марта 12 10:51 10700
dr-xr-xr-x 9 root root 0 янв. 30 00:30 1089
dr-xr-xr-x 9 root root 0 янв. 30 00:30 11
dr-xr-xr-x 9 root root 0 янв. 30 00:30 1114
dr-xr-xr-x 9 root root 0 янв. 30 00:30 1118
dr-xr-xr-x 9 root root 0 янв. 30 00:30 1124
dr-xr-xr-x 9 root root 0 янв. 30 00:30 1126


~$ ls -l /proc/10700/ | head
dr-xr-xr-x 2 redkin_p redkin_p 0 марта 12 14:07 attr
-rw-r--r-- 1 root root 0 марта 12 14:07 autogroup
-r-------- 1 root root 0 марта 12 14:07 auxv
-r--r--r-- 1 root root 0 марта 12 14:07 cgroup
--w------- 1 root root 0 марта 12 14:07 clear_refs
-r--r--r-- 1 root root 0 марта 12 10:51 cmdline
-rw-r--r-- 1 root root 0 марта 12 14:07 comm
-rw-r--r-- 1 root root 0 марта 12 14:07 coredump_filter
-r--r--r-- 1 root root 0 марта 12 14:07 cpuset

~$ cat /proc/10700/status
Name: sh
State: Z (zombie)
Tgid: 10700
Ngid: 0
Pid: 10700
PPid: 29897
TracerPid: 0
Uid: 1000 1000 1000 1000
Gid: 1000 1000 1000 1000
FDSize: 0
Groups: 4 24 27 30 46 110 111 1000 1003
NStgid: 10700
NSpid: 10700
NSpgid: 29896
NSsid: 29896
Threads: 1
SigQ: 0/7891
SigPnd: 0000000000000000
ShdPnd: 0000000000000000
SigBlk: 0000000000000000
SigIgn: 0000000000000000
SigCgt: 0000000000010002
CapInh: 0000000000000000
CapPrm: 0000000000000000
CapEff: 0000000000000000
CapBnd: 0000003fffffffff
CapAmb: 0000000000000000
Seccomp: 0
Speculation_Store_Bypass: vulnerable
Cpus_allowed: 3
Cpus_allowed_list: 0-1
Mems_allowed: 00000000,00000001
Mems_allowed_list: 0
voluntary_ctxt_switches: 2
nonvoluntary_ctxt_switches: 1
# Показать PID процесса и дочерних процессов
# pidof показывает в одну строку

~$ pidof systemd
1
~$ pidof crond
441

# pgrep показывает в разные строки (+ поддерживает разные опции и regexp)
~$ pgrep systemd
1
327
337
427
~$ pgrep crond
441
~$ pgrep --oldest postgres # показать только родительский postgres
8434

Аналог ps из мира Windows Powershell – довольно удобно с pipe:sort, select на основе столбцов в выводе.

PS C:\WINDOWS\system32> Get-Process| Sort CPU -descending | Select -first 3 -property ID, ProcessName, CPU

Id ProcessName CPU
-- ----------- ---
8392 start 1231,53125
11484 chrome 749,71875
3912 avp 676,078125
Мониторинг всей системы

top/htop – мониторинг системных ресурсов и процессов в Linux. Показывает сводку по всей системе (сводка из команды uptime:uptime, user count, load average; tasks, CPU usage, Mem usage) и те процессы, которые потребляют больше всего ресурсов. Для начала в общем случае смотрится загрузка CPU/MEM, затем остальное.

load average (LA) – безразмерная метрика, показывает среднюю загрузку системы за период времени для всей системы (100% значения = ~60% загрузка за 1/5/15 минутный интервалы + ~40% загрузка со старта системы – подробнее ниже).

    1. `Из практики могу сказать, что LA это индикатор средней загрузки всей системы и лучше смотреть загрузку по конкретным ядрам, потому что
      1. низкий LA это не показатель низкой загрузки конкретного ядра и в случае если приложение/worker однопоточное, оно может работать “в полке” (добавлять к общему LA единицу) и создавать проблемы (длительный отклик/потеря транзакций/проч), при этом общий LA за счет большого кол-ва CPU/cores будет низкий т.к. другие ядра простаивают.
      2. высокий LA нужно сопоставлять с количеством вычислительных ресурсов (CPU/Core), подробнее ниже.
    2. На практике сталкивался с высоким load average на gentoo после нагрузки на cpu/HDD (сжатие/архивирование файлов, системное обновление), причем load average уже после самой причины загрузки “не уходил” в течении ~часа – видимо это шлейф 37%. 

    3. Чтобы получить понимание загружена ли система по load average, значение load average нужно поделить на количество CPU (ядер CPU). Конечно это далеко не всегда справедливо, потому что только в идеальных условиях, процессоры/ядра загружаются равномерно. Далее полученное значение сравнить с единицей. В результате Load average в значении 1.73 при разном количестве CPU/ядер говорит о разном:

        • на системе c 8 CPU – система “отдыхает”
        • на в системе с 2 CPU – система недозагружена на 0.27%
        • на в системе с 1 CPU – система в полке на 0.73%
In UNIX computing, the system load is a measure of the amount of computational work that a computer system performs. The load average represents the average system load over a period of time. It conventionally appears in the form of three numbers which represent the system load during the last one-, five-, and fifteen-minute periods.

An idle computer has a load number of 0 (the idle process isn't counted). Each process using or waiting for CPU (the ready queue or run queue) increments the load number by 1. Each process that terminates decrements it by 1. Most UNIX systems count only processes in the running (on CPU) or runnable (waiting for CPU) states. However, Linux also includes processes in uninterruptible sleep states (usually waiting for disk activity), which can lead to markedly different results if many processes remain blocked in I/O due to a busy or stalled I/O system.[1] This, for example, includes processes blocking due to an NFS server failure or too slow media (e.g., USB 1.x storage devices). Such circumstances can result in an elevated load average which does not reflect an actual increase in CPU use (but still gives an idea of how long users have to wait).

~$ uptime
18:00:38 up 59 days, 18:18, 4 users, load average: 3,74, 4,29, 3,94

~$ cat /proc/loadavg
3.74 4.29 3.94 3/287 14030

В примере ниже с реальных серверов – сервер с 2 CPU очень нагружен (6.43/2), а сервера с 8 (3.65/8) и 16 (0.03/16) недозагружены.

~$ cat /proc/cpuinfo | grep processor | wc -l
2
~$ cat /proc/loadavg
6.43 5.56 5.04 3/379 347

$ cat /proc/cpuinfo | grep processor | wc -l
8
$ cat /proc/loadavg
3.65 4.73 4.96 3/248 30671

$ cat /proc/cpuinfo | grep processor | wc -l
16
$ cat /proc/loadavg
0.03 0.05 0.05 1/782 27791
For example, one can interpret a load average of "1.73 0.60 7.98" on a single-CPU system as:
- during the last minute, the system was overloaded by 73% on average (1.73 runnable processes, so that 0.73 processes had to wait for a turn for a single CPU system on average).
- during the last 5 minutes, the CPU was idling 40% of the time on average.
- during the last 15 minutes, the system was overloaded 698% on average (7.98 runnable processes, so that 6.98 processes had to wait for a turn for a single CPU system on average).
This means that this system (CPU, disk, memory, etc.) could have handled all of the work scheduled for the last minute if it were 1.73 times as fast.

In a system with four CPUs, a load average of 3.73 would indicate that there were, on average, 3.73 processes ready to run, and each one could be scheduled into a CPU.

Общий принцип работы LA – по умолчанию загрузка считается нулевой, каждый процесс, который ждет своей очереди для обработки CPU или Drive (HDD/SSD) добавляет значение в 1 к load average, каждый процесс, который прерывается, наоборот, уменьшает значение на 1. Сама метрика получается из файла /proc/loadavg. С точки зрения математики значение load average состоит из:

    • 63% от значения берется из предыдущего минуты/5минут/15 минут
    • 37% берется от загрузки с начала старта системы
Mathematically speaking, all three values always average all the system load since the system started up. They all decay exponentially, but they decay at different speeds: they decay exponentially by e after 1, 5, and 15 minutes respectively. Hence, the 1-minute load average consists of 63% (more precisely: 1 - 1/e) of the load from the last minute and 37% (1/e) of the average load since start up, excluding the last minute. For the 5- and 15-minute load averages, the same 63%/37% ratio is computed over 5 minutes and 15 minutes respectively. Therefore, it is not technically accurate that the 1-minute load average only includes the last 60 seconds of activity, as it includes 37% of the activity from the past, but it is correct to state that it includes mostly the last minute.

lsof – показать открытые процессами файлами. Сопоставление какой файл открыт каким процессом. Может быть полезно при размонтировке носителей (напр. ошибка “device or resource busy” при попытке eject USB). Чтобы посмотреть все процессы нужно запускать из под sudo.

~$ sudo lsof | wc
6175 58986 749350
~$ lsof | wc
2163 20393 250710
Изменение процессов

kill (в Windows taskmanager ctrl-shift-esc, taskkill, process explorer can restart/pause processes) – позволяет остановить (частный случай для Linux kill) процесс/процессы по ID процесса (PID), процессы определенного пользователя и проч.

kill -9 # принудительная остановка процесса (SIGKILL)
kill -9 -1 # принудительная остановка всех процессов пользователя (SIGKILL)
kill -9 $(pgrep -f 'top') # принудительная остановка всех процессов top
kill -1 # сигнализируем процессу, что ему нужно перечитать свою конфигурацию (может быть проигнорировано приложением) (SIGHUP)
kill -2 или ctrl-c # сигнализируем процессу, что ему нужно прерывать исполнение (SIGINT)
kill -15 # софт-остановка процесса (может быть проигнорирована приложением) (SIGTERM)
kill -20 или ctrl-z # приостановить процесс (suspended state, SIGTSTP)
kill -18 или ctrl-z # возобновить процесс (SIGCONT)

kill позволяет отсылать большое количество сигналов процессам. По умолчанию используется непринудительная остановка процесса kill -15 (SIGTERM), которая позволяет приложению высвободить ресурсы и приостановить отключение, в случае если оно считает что отключение прямо сейчас опасно (например, для завершения подпроцессов/сохранения файлов в постоянную память/корректного высвобождения памяти или просто прописан exception не умирать никогда). Поэтому рекомендуется использование именно его для завершения процессов, а не kill -9 (SIGKIL), который может привести к разным проблемам – осиротевшим процессам/zombie/проблемам в application логике (напр. не до конца выполненные операции). kill -l позволяет показать все возможные сигналы, которые можно отослать процессу (64 штуки!).

Наиболее часто используемые:
1 SIGHUP (reload) Hang up signal causes a process to disconnect itself from a closed terminal that it was tied to. Also used to instruct a running daemon to re-read its configuration.
2 SIGINT The ^c signal issued on the controlling terminal to interrupt the execution of a process.
9 SIGKILL (kill abruptly) Kills a process abruptly. Some processes ignore signal 15 as they might be waiting for an input to continue processing. Such processes may be terminated forcefully using signal 9.
15 SIGTERM (stop execution by process) Sends a soft termination signal to stop a process in an orderly fashion. This signal may be ignored by a process. This is the default signal.

~$ kill -l
 1) SIGHUP 2) SIGINT 3) SIGQUIT 4) SIGILL 5) SIGTRAP
 6) SIGABRT 7) SIGBUS 8) SIGFPE 9) SIGKILL 10) SIGUSR1
11) SIGSEGV 12) SIGUSR2 13) SIGPIPE 14) SIGALRM 15) SIGTERM
16) SIGSTKFLT 17) SIGCHLD 18) SIGCONT 19) SIGSTOP 20) SIGTSTP
21) SIGTTIN 22) SIGTTOU 23) SIGURG 24) SIGXCPU 25) SIGXFSZ
26) SIGVTALRM 27) SIGPROF 28) SIGWINCH 29) SIGIO 30) SIGPWR
31) SIGSYS 34) SIGRTMIN 35) SIGRTMIN+1 36) SIGRTMIN+2 37) SIGRTMIN+3
38) SIGRTMIN+4 39) SIGRTMIN+5 40) SIGRTMIN+6 41) SIGRTMIN+7 42) SIGRTMIN+8
43) SIGRTMIN+9 44) SIGRTMIN+10 45) SIGRTMIN+11 46) SIGRTMIN+12 47) SIGRTMIN+13
48) SIGRTMIN+14 49) SIGRTMIN+15 50) SIGRTMAX-14 51) SIGRTMAX-13 52) SIGRTMAX-12
53) SIGRTMAX-11 54) SIGRTMAX-10 55) SIGRTMAX-9 56) SIGRTMAX-8 57) SIGRTMAX-7
58) SIGRTMAX-6 59) SIGRTMAX-5 60) SIGRTMAX-4 61) SIGRTMAX-3 62) SIGRTMAX-2
63) SIGRTMAX-1 64) SIGRTMAX
# Дочерние
pkill <name>
- оперирует названием процесса (по сути kill`pidof <process_name`)
pkill t-rex-64 - убиваем процесс t-rex-64
# apt-get install psmisc # для работы killall
killall <name> - убить все процессы (если больше одного)
killall -9 python - убиваем принудительно все процессы python

nice – позволяет запускать приложения с заданным приоритетом nice value. Например, долгие неважные процессы (backup, обновление системы/приложений, скан сети) можно сделать с nice 15-20, а важные с -15 – -20.

renice нужен для изменения приоритета уже работающего процесса.

sudo nice -n -20 <command> или nice --20 - запускаем команду с приоритетом -20
sudo renice -n 7 18153 - выставляем активному процессу 18153 приоритет 7
sudo renice -n -20 -u admin - делаем приоритет -20 для всех процессов пользователя admin
sudo renice -n 20 -g customers - делаем приоритет 20 для всех процессов группы customers

~$ sudo renice -n -18 29897
29897 (process ID) old priority 0, new priority -18

 

классика жанра (ничего нового) – affinity, isolated, polling

 
Core (logical/physical) numbers

Количество процессинг-юнитов (физических CPU). Может не совпадать с top (добавляются логические CPU,  как в примерах ниже).

$ nproc
4
 nproc - print the number of processing units available.

Понятнее всего количество физических и логических ядер посмотреть в выводе lscpu

    • логические (общее количество на систему) в виде CPU(s). Отображаются все CPU, включая созданные hyperthreading –  в данном выводе 2 процессора E5-2620 v3 с 6 физическими ядрами на борту и 12 потокама (12 * 2 = 24).
    • физические (количество на сокет) в виде Core(s) per socket
# E5-2620 v3
lscpu
Architecture: x86_64
CPU op-mode(s): 32-bit, 64-bit
Byte Order: Little Endian
CPU(s): 24
On-line CPU(s) list: 0-23
Thread(s) per core: 2
Core(s) per socket: 6
Socket(s): 2
NUMA node(s): 2
Vendor ID: GenuineIntel
CPU family: 6
Model: 63
Model name: Intel(R) Xeon(R) CPU E5-2620 v3 @ 2.40GHz

top
%Cpu0 : 0.0 us, 0.0 sy, 0.0 ni,100.0 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
%Cpu1 : 2.1 us, 2.1 sy, 0.0 ni, 95.7 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
%Cpu2 : 0.0 us, 0.0 sy, 0.0 ni,100.0 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
%Cpu3 : 0.0 us, 0.0 sy, 0.0 ni,100.0 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
%Cpu4 : 0.0 us, 0.0 sy, 0.0 ni,100.0 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
%Cpu5 : 0.0 us, 0.0 sy, 0.0 ni,100.0 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
%Cpu6 : 0.0 us, 0.0 sy, 0.0 ni,100.0 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
%Cpu7 : 0.0 us, 0.0 sy, 0.0 ni,100.0 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
%Cpu8 : 0.0 us, 0.0 sy, 0.0 ni,100.0 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
%Cpu9 : 0.0 us, 0.0 sy, 0.0 ni,100.0 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
%Cpu10 : 0.0 us, 0.0 sy, 0.0 ni,100.0 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
%Cpu11 : 0.0 us, 0.0 sy, 0.0 ni,100.0 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
%Cpu12 : 0.0 us, 0.0 sy, 0.0 ni,100.0 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
%Cpu13 : 0.0 us, 0.0 sy, 0.0 ni,100.0 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
%Cpu14 : 0.0 us, 0.0 sy, 0.0 ni,100.0 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
%Cpu15 : 0.0 us, 0.0 sy, 0.0 ni,100.0 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
%Cpu16 : 0.0 us, 0.0 sy, 0.0 ni,100.0 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
%Cpu17 : 0.0 us, 0.0 sy, 0.0 ni,100.0 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
%Cpu18 : 0.0 us, 0.0 sy, 0.0 ni,100.0 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
%Cpu19 : 0.0 us, 0.0 sy, 0.0 ni,100.0 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
%Cpu20 : 0.0 us, 0.0 sy, 0.0 ni,100.0 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
%Cpu21 : 0.0 us, 0.0 sy, 0.0 ni,100.0 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
%Cpu22 : 0.0 us, 0.0 sy, 0.0 ni,100.0 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
%Cpu23 : 0.0 us, 0.0 sy, 0.0 ni,100.0 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
# i3-4360
lscpu
Architecture: x86_64
CPU op-mode(s): 32-bit, 64-bit
Byte Order: Little Endian
CPU(s): 4
On-line CPU(s) list: 0-3
Thread(s) per core: 2
Core(s) per socket: 2
Socket(s): 1
NUMA node(s): 1
Vendor ID: GenuineIntel
CPU family: 6
Model: 60
Model name: Intel(R) Core(TM) i3-4360 CPU @ 3.70GHz

top
%Cpu0 : 0.4 us, 0.0 sy, 0.0 ni, 99.6 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
%Cpu1 : 0.4 us, 0.4 sy, 0.0 ni, 99.1 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
%Cpu2 : 0.0 us, 0.0 sy, 0.0 ni,100.0 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
%Cpu3 : 0.0 us, 0.0 sy, 0.0 ni,100.0 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st

 

isolcpus
  • Isolcpus deprecated функционал. У isolcpus есть два существенных недостатка, которых нет у ниже описанного cpuset shield (cset shield):
    • для ядер CPU, которые находятся в изоляции не работает scheduler операционной системы и нагрузка одного приложения не будет распределяться по нескольким CPU, даже если так настроен taskset
    • isolcpus можно настроить только с перезагрузкой (изменение grub)
Since isolated CPUs are excluded from SMP balancing and the scheduler algorithm, it's not desirable to use them in situations where you want a process balanced across multiple CPUs. In such cases, shielding is more desirable (see the man page for cset-shield):
- Normally, when I have isolcpus, starting a process with taskset -c 2-32 means all threads end up on core 2 as isolcpus "removes cores from scheduler" as I was told so there is no load balancing.
-  Similar to taskset, it's possible to define more than one CPU in a cpuset, however, due to the nature of isolated CPUs, only the first defined CPU will be effective.
- Cgroup cpuset is not balancing tasks on CPUs isolated via isolcpus kernel parameter Automated load balancing of a process/task across multiple isolated CPUs is not possible.

Изоляция CPU позволяет “вынести” CPU из общих ресурсов и в последующем прибиндить его к конкретной app, которая потенциально будет работать более стабильно/производительно в такой конфигурации за счет отсутствия переключения контекста и кеша. По факту, пишут, что преимущества изоляции сейчас минимальны и многие приложения прекрасно масштабируются/балансируются на CPU без присвоения им конкретных ядер обработки (запуск нескольких instance приложения без присвоения каждому конкретных ядер).

Since isolated CPUs are excluded from SMP balancing and the scheduler algorithm, it's not desirable to use them in situations where you want a process balanced across multiple CPUs. In such cases, shielding is more desirable (see the man page for cset-shield). 

The isolcpus option can be used to isolate cores from the Linux scheduler. The isolated cores can then be used to dedicatedly run HPC applications or threads. This helps in better application performance due to zero context switching and minimal cache thrashing. It has been verified that core isolation has minimal advantage due to mature Linux scheduler in some circumstances.

Пример настройки – 1) выводим из системы 7 ядер из 8 или 2) с 1 по 19. Нулевое ядро в обоих случаях оставляем системе в GRUB cmdline.

vim.tiny /etc/default/grub
   GRUB_CMDLINE_LINUX="isolcpus=1,2,3,4,5,6,7"
   GRUB_CMDLINE_LINUX="isolcpus=1-19"
sudo update-grub
Проверка isolcpus. Основной работающий способ – по первому процессу (в моем случае c 3.2.0-4-amd64 только этот способ работал).
You can also use taskset pointed to PID 1. As PID 1 is the standard PID for the first task launched by the kernel, we can take as a pretty good indication that it will reflect whether we have isolcpus working. As in:

$taskset -cp 1
pid 1's current affinity list: 0,1

$lscpu | grep CPU.s
CPU(s): 4
On-line CPU(s) list: 0-3
NUMA node0 CPU(s): 0-3

As it can be seen, lscpu is showing 4 CPU/cores, while taskset is only showing 0,1, so this shows isolcpus is working here.

Так же можно посмотреть с каким CMDLINE была загружена система.

# cat /proc/cmdline
BOOT_IMAGE=/boot/vmlinuz-3.2.0-4-amd64 root=UUID=fcd249ff-8e89-408d-bc51-e8868dc14748 ro isolcpus=1 quiet

 

cpuset shield (cset shield)
  • (CPUSET/CSET SHIELD, ISOLCPUS, AFFINITY, IxChariot) Конфигурация системы (нагрузчик IxChariot Endpoint) которую я настраивал для создания высокой нагрузки (более 10 gbps TCP трафиком), всего 4 ядра CPU в системе:
    • использовал cpuset с shield (cset shield) для ядер CPU 2-3, на которых запускается endpoint процесс с балансировкой нагрузки между ядрами
    • использовал isolated CPU для ядра 1 (isolcpus), прерывания очередей нагрузочных интерфейсов (сетевой карты 10G) переведены на отдельное изолированное ядро 1 (smp_affinity) – периодически были всплески на CPU1 до 80%, но редко (для отлова чаще всего нужно использовать top с настройками обновления чаще 1 раз в 3с) в отличии от конфигураций shield 1-3 или default конфигурации
    • системные процессы работали на оставшемся ядре 0 – конфиги ниже однозначно проявили себя хуже
      • если все держать в общем пуле (linux + endpoint + прерывания) – система (SSH) не тормозит, но производительность упирается в прерывания на нулевом ядре
      • если на CPU 0 обрабатывать как прерывания (только на нем), так и системные задачи (linux + прерывания) – система явно упирается в прерывания на нулевом ядре и даже SSH начинает тормозить, результаты ухудшаются
      • если выделять два ядра CPU0 + CPU1 под общие задачи прерывания и системные задачи (linux + прерывания), а приложение держать на отдельных двух – все ок и с системой и с результатами тестирования производительности приложения, но потенциально вариант с разделением прерываний на отдельный CPU более стабилен и я остановился на нем

Включает в себя достоинства isolcpus и при этом в этом функционале отсутствуют недостатки isolcpus – одно приложение в группе cset shield балансируется между выделенными в shield ядрами, настройка cset shield возможна без перезагрузок системы.

# INSTALL CPUSET/CSET
apt-get install cpuset

# CHECK THAT SHIELD OFF
taskset -cp 1
  pid 1's current affinity list: 0-3

# CREATE SHIELD
cset shield --cpu 2-3 --kthread on

# RUN APP IN SHIELD
cset shield --exec /usr/local/some_application
# ALTERNATE
set shield --shield --pid 3237

# DELETE APP FROM SHIELD
cset shield --unshield --pid 3237

# CHECK
taskset -cp 1  # check system pid
  pid 1's current affinity list: 0-1
taskset -cp 19  # check app pid
  pid 19's current affinity list: 2-3
cset shield -s  # show shield load
  cset: "user" cpuset of CPUSPEC(2-3) with 13 tasks running
  cset: done

Если нужно, чтобы cset настраивался сразу при запуске системы – это легко сделать добавив те же команды настройки cset в автостарт системы (напр. /etc/rc.local или systemctl). Единственная особенность – запуск приложения в shield и cset нужно разносить каким-то ожиданием или sleep (на практике достаточно 5 секунд) или проверкой создания, иначе приложение не запустится т.к. cset shield еще не будет создан.

maxcpus

Изменять количество активных CPU в сторону понижения надежнее всего через maxcpus.

I have got some interesting experience with 
> switching on/off the CPU cores. First, I did the on/off switching of 
> the i-th CPU core by writing 1/0 values into the 
> /sys/devices/system/cpu/cpu$i/onlinefile of the working Linux kernel 
> [2]. Whereas it seemed to work well, when the query rates were 
> moderate (a few times ten thousand queries per second), it caused 
> problems in the second case, when I used up to 3 million queries per 
> second query rates, and thus I rather set the number of active CPU 
> cores at the DUT by using the maxcpus=nkernel parameter.
interrupts, SMP IRQ affinitY

Linux kernels have the ability to balance hardware interrupt requests across multiple CPUs or CPU cores. The feature is referred to as SMP IRQ Affinity and results in better system performance as well as better CPU utilization.

CPU ID Binary Hexadecimal
CPU 0 0001 1
CPU 1 0010 2
CPU 2 0100 4
CPU 3 1000 8
    • прерывания – это триггер, сгенерированный девайсом (сетевой картой, дисковым контроллером), получив этот триггер CPU должен его обработать (в том числе остановив текущую задачу)
When a hardware component (such as a disk controller or an Ethernet NIC) needs to interrupt the work of the CPU, it triggers an interrupt. The interrupt notifies the CPU that an event occurred and the CPU should suspend its current work to deal with the event.
    • во многих случаях несмотря на низкую совокупную утилизацию CPU производительность низка из-за высокой загрузки ядра (или ядер) CPU, обрабатывающего прерывания – к примеру без SMP IRQ affinity все прерывания всех сетевых карт распределены на нулевое ядро CPU0, что, очевидно, может быть bottleneck
In many cases, when overall CPU usage is low but performance is poor, it is usually the CPU core specified to handle interrupts is fully occupied. Let's take NIC interrupts as an example. Without the SMP IRQ affinity, all NIC interrupts are associated with CPU 0. As a result, CPU 0 is overloaded and cannot efficiently process network packets, causing a bottleneck in performance.
    • распределение прерываний на специальные CPU/группы CPU (лучше группы) в виде SMP IRQ affinity появилось еще в Linux ядре 2.4, к примеру можно переводить полностью NIC на определенные ядра или более стандартно – переводить определенные очереди каждой NIC на отдельные ядра (используя RSS или Soft RSS RPS/RFS). Нежелательно использовать CPU0 для прерываний RPS.
Balancing network interrupts among multiple CPUs increases the performance of network-based operations.

In kernel 2.4 and later, Linux improves the capability of assigning specific interrupts to the specified processors (or processor groups). This is called the SMP IRQ affinity, which controls how the system responds to various hardware events. You can limit or redistribute the server workload so that the server can work more efficiently. After you configure the SMP IRQ affinity, multiple NIC interrupts are allocated to multiple CPUs to distribute the CPU workload and speed up data processing. The SMP IRQ affinity requires NICs to support multiple queues. A NIC supporting multiple queues has multiple interrupt numbers, which can be evenly allocated to different CPUs. In the following example, interrupt 27 is allocated to CPU 0 for processing. Generally, you are recommended to leave CPU 0 unused.
    • ((с другой стороны в Linux по умолчанию работает NAPI)) по идее задачу динамически должен и решает IRQbalance, но по факту
      • он часто выключен по умолчанию
      • зачастую даже при включении все равно более правильным решением является настройкам вручную прерываний и отключение IRQbalance (лаг на адаптацию при спайках нагрузки, высокий уровень context switch, глюки)
      • возможным (не тестил) промежуточным вариантом является вынесение части ядер из irq balance: IRQBALANCE_BANNED_CPULIST=5-12
Most Linux installations are not configured to balance network interrupts. The default network interrupt behavior uses a single processor (typically CPU0) to handle all network interrupts and can become a serious performance bottleneck with high volumes of network traffic. Balancing network interrupts among multiple CPUs increases the performance of network-based operations.

IRQbalance is applicable to most scenarios. However, in scenarios requiring high network performance, you are recommended to bind interrupts manually. IRQbalance can cause some issues during operation:
(a) The calculated value is sometimes inappropriate, failing to achieve load balancing among CPUs.
(b) When the system is idle and IRQs are in power-save mode, IRQbalance distributes all interrupts to the first CPU, to make other idle CPUs sleep and reduce energy consumption. When the load suddenly rises, performance may be degraded due to the lag in adjustment.
(c) The CPU specified to handle interrupts frequently changes, resulting in more context switches.
(d) IRQbalance is enabled but does not take effect, that is, does not specify a CPU for handling interrupts.
  • IRQbalance помогает в средних сценариях, но по факту:
    • Он иногда не работает (у меня так же было) и это приводит к деградации производительности/росту задержек и потерь
    • С высокой прозводительностью зачастую лучше настроить прерывания вручную – IRQbalance is applicable to most scenarios. However, in scenarios requiring high network performance, you are recommended to bind interrupts manually.

Настройка affinity позволяет:

    1. привязать процесс к конкретному ядру (конкретным) CPU
    2. привязать очередь прерываний к конкретному ядру,  например, очередь прерываний с сетевой карты биндится к конкретному ядру процессора (напр. так реализовано в TRex)

Часто используется в задачах генерации/обработки большой нагрузки. Привязка приводит к повышению стабильности производительности и росту данной производительности (пример описан в ESXi). Affinity работает зачастую в связке c распределением потоков на базе расчета hash для передаваемых потоков:

Технология RSS позволяет аппаратно раскидывать приходящие на сетевую карту пакеты на несколько процессоров, где они обрабатываются различными потоками. При этом выполнять все операции с пакетом непосредственно на том процессоре, куда пакет аппаратно попал, нецелесообразно, обычно делают так: несколько процессорных ядер выделяется под RSS, где потоки выгребают пакеты из сетевой карты и раскидывают по нескольким очередям, а затем другие потоки-воркеры, работающие на других процессорных ядрах, забирают пакеты из очередей и обрабатывают.

Количество очередей RSS обычно делается равным количеству процессов, на которые трафик распределяется.

 

Пример моей настройки прерываний на отдельное ядро на практике (работало)

  • Распределение прерываний в smp_affinity появляется сразу после UP интерфейса, независимо от того, есть ли линк или нет. Если интерфейс не в UP – прерывания распределить не получится.
/proc/interrupts до настройки smp_affinity.
while true; do echo; echo; grep -w "CPU0\|Rescheduling\|eth8\|eth9" /proc/interrupts | sort -n; sleep 1; done
CPU0 CPU1 CPU2 CPU3
RES: 84049 43750986 110517787 110615940 Rescheduling interrupts
166: 82474083 0 0 0 IR-PCI-MSI-edge eth8-TxRx-0
167: 24042806 0 0 0 IR-PCI-MSI-edge eth8-TxRx-1
168: 59272802 0 0 0 IR-PCI-MSI-edge eth8-TxRx-2
169: 59361007 0 0 0 IR-PCI-MSI-edge eth8-TxRx-3
170: 4 0 0 0 IR-PCI-MSI-edge eth8
180: 82616626 0 0 0 IR-PCI-MSI-edge eth9-TxRx-0
181: 24207180 0 0 0 IR-PCI-MSI-edge eth9-TxRx-1
182: 59306623 0 0 0 IR-PCI-MSI-edge eth9-TxRx-2
183: 59334616 0 0 0 IR-PCI-MSI-edge eth9-TxRx-3
184: 2 0 0 0 IR-PCI-MSI-edge eth9
Настройка распределения прерываний на отдельное ядро (второе).
echo 000002 > /proc/irq/166/smp_affinity
echo 000002 > /proc/irq/167/smp_affinity
echo 000002 > /proc/irq/168/smp_affinity
echo 000002 > /proc/irq/169/smp_affinity
echo 000002 > /proc/irq/170/smp_affinity
echo 000002 > /proc/irq/180/smp_affinity
echo 000002 > /proc/irq/181/smp_affinity
echo 000002 > /proc/irq/182/smp_affinity
echo 000002 > /proc/irq/183/smp_affinity
echo 000002 > /proc/irq/184/smp_affinity
/proc/interrupts после настройки smp_affinity (CPU0 более не инкрементировался).
while true; do echo; echo; grep -w "CPU0\|Rescheduling\|eth8\|eth9" /proc/interrupts | sort -n; sleep 1; done
CPU0 CPU1 CPU2 CPU3
RES: 38502 44083017 180343133 172478449 Rescheduling interrupts
166: 83784996 680 0 0 IR-PCI-MSI-edge eth8-TxRx-0
167: 24543343 42381024 0 0 IR-PCI-MSI-edge eth8-TxRx-1
168: 60286755 35225747 0 0 IR-PCI-MSI-edge eth8-TxRx-2
169: 59985599 34032738 0 0 IR-PCI-MSI-edge eth8-TxRx-3
170: 2 0 0 0 IR-PCI-MSI-edge eth8
180: 83957687 682 0 0 IR-PCI-MSI-edge eth9-TxRx-0
181: 24894775 42820948 0 0 IR-PCI-MSI-edge eth9-TxRx-1
182: 60905927 35291571 0 0 IR-PCI-MSI-edge eth9-TxRx-2
183: 59187673 34322303 0 0 IR-PCI-MSI-edge eth9-TxRx-3
184: 4 0 0 0 IR-PCI-MSI-edge eth9

Настройка распределения прерываний на все ядра.

echo 00000f > /proc/irq/65/smp_affinity # eth0-tx-0
echo 00000f > /proc/irq/66/smp_affinity # eth0-tx-1
echo 00000f > /proc/irq/67/smp_affinity # eth0-tx-2
echo 00000f > /proc/irq/68/smp_affinity # eth0-tx-3
echo 00000f > /proc/irq/69/smp_affinity # eth0-rx-0
echo 00000f > /proc/irq/70/smp_affinity # eth0-rx-1
echo 00000f > /proc/irq/71/smp_affinity # eth0-rx-2
echo 00000f > /proc/irq/72/smp_affinity # eth0-rx-3

Посмотреть привязку процесса к CPU

Посмотреть привязку PID к CPUI можно множеством способов. Первый способ с taskset считаю самый простой и надежный, пользовался им при работе с isolcpus, cset shield (выше).

# С помощью самого taskset
~$ taskset -p 6099
pid 6099's current affinity mask: 3

# С помощью ps (столбец PSR)
sh-4.4# ps -eo pid,tid,class,rtprio,ni,pri,psr,pcpu,stat,wchan:14,comm | grep softirq
PID TID CLS RTPRIO NI PRI PSR %CPU STAT WCHAN COMMAND
9 9 TS - 0 19 0 5.7 S - ksoftirqd/0
16 16 TS - 0 19 1 0.0 S - ksoftirqd/1
21 21 TS - 0 19 2 0.0 S - ksoftirqd/2
26 26 TS - 0 19 3 0.0 S - ksoftirqd/3
31 31 TS - 0 19 4 0.0 S - ksoftirqd/4
36 36 TS - 0 19 5 0.0 S - ksoftirqd/5
41 41 TS - 0 19 6 0.0 S - ksoftirqd/6
46 46 TS - 0 19 7 0.0 S - ksoftirqd/7

# С помощью top (столбец P)
> Hit f to get into the Fields Management window
> Select P (Last Used Cpu) ((выбирается backspace))
> Esc
scroll coordinates: y = 1/195 (tasks), x = 1/13 (fields)
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND P
713 root 20 0 36760 27652 3656 S 0,0 0,3 165:04.34 collectl 1
335 root 20 0 60180 24396 7080 S 0,0 0,3 10:56.09 systemd-journal 0
1 root 20 0 107272 10412 7732 S 0,0 0,1 16:26.84 systemd 0
18601 www-data 20 0 1934252 10156 2472 S 0,0 0,1 0:00.00 apache2 1

# Можно даже сделать простой скрипт, который рассчитает количество процессов на ядро - в примере наиболее загруженны по количеству процессов ядра 0 и 1
root@us:~# ps -eo pid,tid,class,rtprio,ni,pri,psr,pcpu,stat,wchan:14,comm | awk '{print $7}' | sort | uniq -c | sort -n
1 PSR
7 10
7 11
7 3
7 4
7 5
7 7
7 8
7 9
8 2
9 6
55 1
73 0

 

 

Taskset

Привязать PID к CPU удобнее всего с помощью taskset. Так же можно использовать cset/cpuset без shield (с shield описано выше).

# Можно напрямую указать конкретный CPU (affinity), range или list (man taskset --cpu-list 0-2,6)
taskset --cpu-list 1 /root/redkin/tcpreplay-master/src/tcpreplay -i enp3s0f1 --topspeed --loop=1000000000000 --duration=600 --preload-pcap /root/redkin/test.pcap &
taskset --cpu-list 2 /root/redkin/tcpreplay-master/src/tcpreplay -i enp3s0f1 --topspeed --loop=1000000000000 --duration=600 --preload-pcap /root/redkin/test.pcap &

# Можно оперировать coremask, но это чаще всего менее удобно
taskset 0xFFFFFFFF /root/redkin/tcpreplay-master/src/tcpreplay -i enp3s0f1 --topspeed --loop=1000000000000 --duration=600 --preload-pcap /root/redkin/test.pcap &

# HEX
~$ taskset -p 0x00000001 6099
pid 6099's current affinity mask: 3
pid 6099's new affinity mask: 1
~$ taskset -p 0x00000002 6099
pid 6099's current affinity mask: 1
pid 6099's new affinity mask: 2

# DECIMAL
 >sudo taskset -pc 7 17551
pid 17551's current affinity list: 7
pid 17551's new affinity list: 7

Могут быть проблемы с привязкой для kernel threads, по идее они решаются только персборкой ядра с отключением флага PF_NO_SETAFFINITY для kernel процессов, но не факт (не изучил до конца этот вопрос – сомнения на основе статьи).

 >ps -p 828
PID TTY TIME CMD
828 ? 00:00:00 nfsiod
>sudo taskset -pc 7 828
pid 828's current affinity list: 0-11
taskset: failed to set pid 828's affinity: Invalid argument

Many kernel threads set the flag PF_NO_SETAFFINITY:
To change the affinity, you would have to change the kernel.
https://stackoverflow.com/questions/25359565/how-one-can-set-affinity-for-kernel-threads
https://stackoverflow.com/questions/60100719/check-value-of-pf-no-setaffinity

 

Пример привязки на сетевом оборудовании

Прерывание на сетевой карте привязываем к ядру CPU. Из /proc/interrupts можно извлечь распределение прерываний по очередям.

Помещает очередь прерываний первого интерфейса (по умолчанию 60, если в качестве интерфейса захвата eth1) на ЦПУ 0.
cat 1 > /proc/irq/60/smp_affinity 

Если задействован второй интерфейс необходимо определить его очередь прерываний. Для этого выполнить команду:
grep <наименование интерфейса> /proc/interrupts 
В полученном списке необходимо найти очередь для RX. Для установки свободного процессора необходимо использовать следующую формулу: 2 в степени номер свободного процессора в шеснадцатиричной форме. Например 8 свободный процессор (2^7) = 128. В шестнадцатиричной форме равно 80.
cat 80 > /proc/irq/69/smp_affinity
Number cores: 8
pgrep <proc> | xargs -I PID_PROC taskset -p PID_PROC
pid 23116's current affinity mask: 2
pid 23117's current affinity mask: 4
pid 23118's current affinity mask: 8
pid 23119's current affinity mask: 10
pid 23120's current affinity mask: 20
pid 23121's current affinity mask: 40
pid 23122's current affinity mask: 80
pid 23123's current affinity mask: 100

 /interfaces |tr ',' '
> '| xargs -I ETH grep ETH /proc/interrupts | cut -d: -f1 | xargs -I IRQ_NUMBER head -v /proc/irq/IRQ_NUMBER/smp_affinity
==> /proc/irq/133/smp_affinity <==
0002
==> /proc/irq/134/smp_affinity <==
0004
==> /proc/irq/135/smp_affinity <==
0008
==> /proc/irq/136/smp_affinity <==
0010
==> /proc/irq/137/smp_affinity <==
0020
==> /proc/irq/138/smp_affinity <==
...

CheckPoint рекомендует IRQ между сетевыми картами рекомендует делать такими, чтобы они не пересекались (IRQ swizzling). Рекомендуют отключать Hyper-Threading.

https://downloads.checkpoint.com/fileserver/SOURCE/direct/ID/7555/FILE/Performance_tests_methodology.pdf 
Hardware Configuration for Open Server
Interfaces that are constantly used should not share the same IRQ.
To prevent the use of the same IRQ in such a situation perform the following:
1. Upgrade BIOS to enable IRQ swizzling (for platforms that support this option).
IRQ swizzling is designed to enable PCI-E based NICs to have different IRQ pools. For
example, two PCI-E dual cards are put in two separate busses, they will both receive the same
IRQs (16 & 17 for example).
Upgrading the BIOS to include support for IRQ swizzling will enable the second NIC to have
different IRQs (18, 19 for example).
2. Select the ports that do not share the same IRQ for the heavily used network interfaces.
For example, configure the internal/external/sync subnets so that they will not share IRQ
interfaces.
3. Use gigabit based equipment (NICs, switches, cables)
4. Disable hyper-threading

 

УТИЛИЗАЦИЯ процессора
  • idle – наилучший показатель фактической загруженности ядра CPU, потому что если ядро чем то занято, то idle отличен от нулевого, а занято ядро может быть любыми задачами – user/system/idle/iowait/softirq.
  • iowait – задача ядра процессора, которая говорит об ожидании ядром диска HDD/SSD (выполнения дисковых операций). Обычно загрузка этой задачей ядром нулевое в сетевой обработке, а когда на практике фиксировал всплески утилизации ядер CPU iowait до 70-100% то это было с влиянием на сетевой трафик (потери).
11:36:02 INFO: cpu cores :12
11:36:02 INFO: cpu speed :3655.329MHz
11:36:02 INFO: user :0.07%
11:36:02 INFO: system :1.58%
11:36:02 INFO: idle :85.85%
11:36:02 INFO: iowait :0.04%
11:36:02 INFO: softirq :12.46%
11:36:02 INFO: cycles/byte :5.24

Leave a Reply