Утилита isolcpus для изолирования ядер процессора в Linux

В данной статье я расскажу, как на Linux изолировать ядро процессора с помощью утилиты isolcpus.

В результате изоляции планировщик ОС Linux не будет размещать на указанных ядрах никакие пользовательские процессы. Запустить нужный процесс на изолированном ядре возможно будет только с помощью утилиты taskset. В результате изоляции на выделенных ядрах будут работать потоки только вашего процесса, планировщик не будет пытаться перенести их на другие ядра, а также не будет пытаться запустить на указанных ядрах другие процессы, которые бы вытесняли и прерывали потоки исполнения вашего процесса.

Эксперимент проводился на виртуальной машине VirtualBox, на которой была запущена инсталляция CentOS 8 с помощью Vagrant. Для виртуальной машины я выделил 3 ядра на своем дестопном 4-хядерном процессоре.

Утилита lscpu покажет всю информацию о процессорах в том числе количество имеющихся ядер на каждом из процессоров.

Architecture:        x86_64
CPU op-mode(s):      32-bit, 64-bit
Byte Order:          Little Endian
CPU(s):              3
On-line CPU(s) list: 0-2
Thread(s) per core:  1
Core(s) per socket:  3
Socket(s):           1
NUMA node(s):        1
Vendor ID:           GenuineIntel
CPU family:          6
Model:               94
Model name:          Intel(R) Core(TM) i5-6400T CPU @ 2.20GHz
Stepping:            3
CPU MHz:             2208.002
BogoMIPS:            4416.00
Hypervisor vendor:   KVM
Virtualization type: full
L1d cache:           32K
L1i cache:           32K
L2 cache:            256K
L3 cache:            6144K
NUMA node0 CPU(s):   0-2
Flags:               fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush mmx fxsr sse sse2 ht syscall nx rdtscp lm constant_tsc rep_good nopl xtopology nonstop_tsc cpuid tsc_known_freq pni pclmulqdq ssse3 cx16 pcid sse4_1 sse4_2 x2apic movbe popcnt aes xsave avx rdrand hypervisor lahf_lm abm 3dnowprefetch invpcid_single pti fsgsbase avx2 invpcid rdseed clflushopt md_clear flush_l1d

Как и ожидалось у меня 1 процессор, на котором выделено три ядра CPU0, CPU1, CPU2. Нумерация ядер начинается 0. Для наглядности я изолирую ядро CPU1, т.е. второе из трех имеющихся.

Утилита isolcpus запускается при старте ядра Linux. Для этого необходимо внести изменения в параметры старта ядра. На сайте RedHat есть пошаговая инструкция, как это сделать. Для внесения изменений надо работать под root или использовать sudo.

Для начала надо сделать страховые копии конфигурации GRUB

# cp /etc/default/grub /etc/default/grub-backup
# cp /boot/grub2/grub.cfg /boot/grub2/grub.cfg-backup

Потом открыть файл для редактирования в vi:

# vi /etc/default/grub

Найти строку GRUB_CMDLINE_LINUX и добавить в конце строки isolcpus=1. Для того, чтобы изолировать два ядра (например, СPU0 и CPU2), укажите в GRUB_CMDLINE_LINUX isolcpus=0,2.

GRUB_CMDLINE_LINUX="resume=UUID=89eb8bd0-55b8-4925-be59-b98c8a4e23cc rhgb quiet isolcpus=1"

Сохранить файл. И потом обновить конфигурацию GRUB:

# grub2-mkconfig -o /boot/grub2/grub.cfg

После этого надо перезагрузить Linux. Если все было сделано правильно, Linux успешно перезагрузится после чего можно проверить, как все сработало. Для примера я собрал Spring Boot проект и запустил его командой:

# mvn spring-boot:run &

С помощью утилиты jps я определил pid моего процесса:

# jps
3296 Jps
2933 DemoApplication
2908 Launcher

Затем с помощью утилиты pidstat я смотрю на каких CPU работает мое приложение:

# pidstat -t -p 2933
CPU  Command
  2  java
  2  |__java
  0  |__java
  0  |__VM Thread
  2  |__Reference Handl
  2  |__Finalizer
  2  |__Signal Dispatch
  0  |__Service Thread
  0  |__Monitor Deflati
  0  |__C1 CompilerThre
  2  |__Sweeper thread
  2  |__Notification Th
  0  |__VM Periodic Tas
  2  |__Common-Cleaner
  2  |__Catalina-utilit
  2  |__Catalina-utilit
  2  |__container-0
  2  |__http-nio-8080-e
  2  |__http-nio-8080-e
  0  |__http-nio-8080-e
  2  |__http-nio-8080-e
  2  |__http-nio-8080-e
  0  |__http-nio-8080-e
  2  |__http-nio-8080-e
  0  |__http-nio-8080-e
  2  |__http-nio-8080-e
  2  |__http-nio-8080-e
  0  |__http-nio-8080-P
  2  |__http-nio-8080-A

Как видите, все потоки процесса разбросаны планировщиком по CPU0 и CPU2, а CPU1 отсутствует в списке. Можно посмотреть свойства процесса, где можно увидеть, что для данного процесса доступны только CPU0 и CPU2:

# cat /proc/2933/status | grep Cpus_allowed_list
Cpus_allowed_list:      0,2

«Убъем» процесс и попробуем запустить его на изолированном ядре CPU1 с помощью утилиты taskset:

# taskset -c 1 mvn spring-boot:run &

Утилита pidstat покажет, что все потоки запущенного процесса работают только на CPU0:

# pidstat -t -p 3357
CPU  Command
  1  java
  1  |__java
  1  |__java
  1  |__VM Thread
  1  |__Reference Handl
  1  |__Finalizer
  1  |__Signal Dispatch
  1  |__Service Thread
  1  |__Monitor Deflati
  1  |__C1 CompilerThre
  1  |__Sweeper thread
  1  |__Notification Th
  1  |__VM Periodic Tas
  1  |__Common-Cleaner
  1  |__Catalina-utilit
  1  |__Catalina-utilit
  1  |__container-0
  1  |__http-nio-8080-e
  1  |__http-nio-8080-e
  1  |__http-nio-8080-e
  1  |__http-nio-8080-e
  1  |__http-nio-8080-e
  1  |__http-nio-8080-e
  1  |__http-nio-8080-e
  1  |__http-nio-8080-e
  1  |__http-nio-8080-e
  1  |__http-nio-8080-e
  1  |__http-nio-8080-P
  1  |__http-nio-8080-A

Примечательно, что с помощью утилиты numactl мы не сможем запустить процесс на CPU1. Numactl выдает ошибку, что данное ядро недоступно для запуска приложения.

# numactl --physcpubind=1 mvn spring-boot:run
libnuma: Warning: cpu argument 1 is out of range

Это связано с тонкостями логики кода утилиты numactl. Утилита taskset в этом отношении действует «грубее» и, может быть, — «правильнее».

Ссылки

Добавить комментарий

Заполните поля или щелкните по значку, чтобы оставить свой комментарий:

Логотип WordPress.com

Для комментария используется ваша учётная запись WordPress.com. Выход /  Изменить )

Фотография Twitter

Для комментария используется ваша учётная запись Twitter. Выход /  Изменить )

Фотография Facebook

Для комментария используется ваша учётная запись Facebook. Выход /  Изменить )

Connecting to %s