Отключение/Подключение всех ядер процессора, кроме загрузочного, под linux

Оставим за рамками, зачем может понадобиться отключать ядра процессора. Обычно этого совсем не требуется даже в случае оптимизации энергозатрат и снижения нагрева. По часть экономии энергии процессор сам знает когда и что лучше приглушить, да отключить. А для оверклокерства ядра процессора обычно отключают через BIOS. Однако у процессоров существуют специальные защищённые режимы, и для перехода в них процессору требуется чтобы осталось только одно загрузочное ядро. К примеру, для выполнения инструкции skinit на процессорах AMD с поддержкой технологии виртуализации SVM. Но речь сейчас не об этом.

Для того чтобы отключить функционирование всех ядер процессора, кроме загрузочного, (такие ядра называются AP ядрами) можно либо вызвать в ядре функцию disable_nonboot_cpus (отключить все разом), либо в цикле вызвать функцию cpu_down. И я покажу как это можно сделать в другом посте. Сложность там заключается в том, что нельзя стандартным образом узнать адрес этих функции чтобы их вызвать. Драйвера с ними так просто не слинковать.

Однако, ядро Linux предоставляет удобный способ управления оборудованием через интерфейс псевдо-файловой системы sys. И здесь всё достаточно просто. Ядро под номером 0 - загрузочное. Все остальные можно отключать. В папке /sys/devices/system/cpu/ расположены номерные директории с именем cpu[0-9]*, где номер соответствует номеру ядра. В каждой такой папке расположен файл online. Если в него записать 0, то ядро будет отключено. Если в него записать 1, то ядро будет включено. Для доступа на запись к этому файлу требуются права суперпользователя. Посмотреть какие ядра сейчас включены можно прочитав файл /sys/devices/system/cpu/online, какие отключены прочитав файл /sys/devices/system/cpu/offline. Также можно просмотреть лог ядра dmesg.

Пример:

#!/bin/bash

regexp='[0-9]*'

# Disable all APs
for i in /sys/devices/system/cpu/cpu*
do
   cpu=${i##*/}
   cpu_num="${cpu#cpu}"
   if expr match "$cpu_num" "\($regexp\)" > /dev/null
   then
       if [ $cpu_num -eq 0 ]
       then
           continue
       fi
     
       echo 0 > $i/online && echo $i disabled
   fi
done

cat /sys/devices/system/cpu/online
cat /sys/devices/system/cpu/offline

# Reenable all APs
for i in /sys/devices/system/cpu/cpu*
do
   cpu=${i##*/}
   cpu_num="${cpu#cpu}"
   if expr match "$cpu_num" "\($regexp\)" > /dev/null
   then
       if [ $cpu_num -eq 0 ]
       then
           continue
       fi
     
       echo 1 > $i/online && echo $i enabled
   fi
done

cat /sys/devices/system/cpu/online
cat /sys/devices/system/cpu/offline

Результат выполнения:

$ sudo ./disable_ap.sh
/sys/devices/system/cpu/cpu1 disabled
/sys/devices/system/cpu/cpu2 disabled
/sys/devices/system/cpu/cpu3 disabled
/sys/devices/system/cpu/cpu4 disabled
/sys/devices/system/cpu/cpu5 disabled
/sys/devices/system/cpu/cpu6 disabled
/sys/devices/system/cpu/cpu7 disabled
0
1-7
/sys/devices/system/cpu/cpu1 enabled
/sys/devices/system/cpu/cpu2 enabled
/sys/devices/system/cpu/cpu3 enabled
/sys/devices/system/cpu/cpu4 enabled
/sys/devices/system/cpu/cpu5 enabled
/sys/devices/system/cpu/cpu6 enabled
/sys/devices/system/cpu/cpu7 enabled
0-7

Лог ядра:

[20080.935736] smpboot: CPU 1 is now offline
[20080.975822] smpboot: CPU 2 is now offline
[20081.025735] Broke affinity for irq 26
[20081.026770] smpboot: CPU 3 is now offline
[20081.071753] Broke affinity for irq 26
[20081.072861] smpboot: CPU 4 is now offline
[20081.108642] Broke affinity for irq 18
[20081.108646] Broke affinity for irq 26
[20081.109673] smpboot: CPU 5 is now offline
[20081.149577] Broke affinity for irq 18
[20081.149579] Broke affinity for irq 23
[20081.149581] Broke affinity for irq 26
[20081.149583] Broke affinity for irq 27
[20081.150609] smpboot: CPU 6 is now offline
[20081.169563] Broke affinity for irq 18
[20081.169566] Broke affinity for irq 23
[20081.169567] Broke affinity for irq 26
[20081.169569] Broke affinity for irq 27
[20081.169572] Broke affinity for irq 29
[20081.170605] smpboot: CPU 7 is now offline
[20081.177538] x86: Booting SMP configuration:
[20081.177540] smpboot: Booting Node 0 Processor 1 APIC 0x2
[20081.184957] smpboot: Booting Node 0 Processor 2 APIC 0x4
[20081.189939] smpboot: Booting Node 0 Processor 3 APIC 0x6
[20081.194996] smpboot: Booting Node 0 Processor 4 APIC 0x1
[20081.199836] smpboot: Booting Node 0 Processor 5 APIC 0x3
[20081.204537] smpboot: Booting Node 0 Processor 6 APIC 0x5
[20081.208958] smpboot: Booting Node 0 Processor 7 APIC 0x7

Пост перенесён из старого блога.

Comments

comments powered by Disqus