Гибридные процессоры Intel принесли на настольные системы ядра двух типов, которые различаются скоростью и расходом энергии, и планировщику без подсказок железа приходится гадать, куда ставить очередную задачу. Эту работу переложили на сам процессор: в кремний добавлен блок Intel Thread Director, который следит за каждым активным потоком и присваивает ему класс от 0 до 3 по измеренному числу инструкций на такт. Наблюдения стекаются в ядро Linux через интерфейс HFI и превращаются в конкретные подсказки при выборе процессорного ядра для задачи. В статье разобраны устройство таблицы обратной связи, смысл четырех классов потоков, версии ядра с поддержкой и команды, которые дают цифры для осмысленного анализа. Читатель получит готовый набор проверок: от флага hfi в /proc/cpuinfo до замеров частоты и потребления в turbostat.

Аппаратный классификатор потоков внутри гибридного процессора

Первым массовым гибридным чипом стал Alder Lake, двенадцатое поколение Core, выпущенное в 2021 году. Настольный флагман i9-12900K несет восемь производительных ядер Golden Cove с частотой до 5.2 ГГц и восемь экономичных ядер Gracemont до 3.9 ГГц, всего 16 ядер и 24 потока. В мобильном семействе Meteor Lake, вышедшем в 2023 году под именем Core Ultra, схема усложнилась: шесть P-ядер, восемь E-ядер и два маломощных E-ядра на отдельном острове, итого 16 ядер и 22 потока. Разница между типами не ограничивается частотой: у P-ядер шире исполнительные порты, больше кэша L2 и выше пропускная способность на такт, поэтому одна и та же задача ускоряется в полтора-два раза при переносе с E-ядра на P-ядро.

Прежний механизм Intel Turbo Boost Max Technology 3.0 опирался на статический рейтинг ядер, и его хватало только при постоянной нагрузке. Thread Director работает иначе: логика на кристалле непрерывно измеряет для каждого логического процессора отношение выполненных инструкций к тактам и учитывает состав инструкций, включая векторные расширения вроде AVX. Окно наблюдения короткое, порядка миллисекунд, поэтому классификация успевает за сменой фаз работы программы, когда код активно считает, а затем уходит в ожидание ввода-вывода. Решение принимает железо без опроса счетчиков со стороны операционной системы, так что накладные расходы сведены к минимуму.

Таблица HFI и оценки производительности от 0 до 255

Канал связи между классификатором и операционной системой называется Hardware Feedback Interface. Описание интерфейса размещено в разделах 14.6 и 14.9 третьего тома Intel SDM, а его суть умещается в одну таблицу на пакет процессоров. Для каждого логического процессора таблица хранит две безразмерные оценки в диапазоне от 0 до 255: способность к производительности и способность к энергоэффективности, чем выше значение, тем выше соответствующая способность. Оценки независимы, на некоторых моделях их выставляют один раз при старте и больше не трогают, на других обновление приходит каждые несколько десятков миллисекунд.

Цифры 0-255 не привязаны к герцам или ваттам и не переводятся в абсолютные единицы. Это относительные индексы, по которым ядро сравнивает ядра между собой: 180 у одного процессора против 120 у другого означает преимущество первого, но ничего не сообщает о реальных частотах. Обновление таблицы доставляется прерыванием термомонитора: вектор приходит через запись Thermal в локальном APIC, а статус и разрешение лежат в битах регистров IA32_PACKAGE_THERM_STATUS и IA32_PACKAGE_THERM_INTERRUPT. Обнуленная оценка означает прямую рекомендацию железа не ставить задачи на процессор, например при удержании предела TDP или перегреве. Драйвер в ядре разбирает таблицу и передает обновления дальше, ограничивая частоту уведомлений пользовательскому пространству одним событием за джиффи, при CONFIG_HZ=1000 это до тысячи обновлений в секунду. При включенном Thread Director строки таблицы расширяются: для каждого из четырех классов потоков появляются собственные пары значений, и планировщик видит уже не общий рейтинг ядра, а прогноз по конкретному классу нагрузки.

Поддержка канала видна в стандартных местах системы. Флаг hfi в /proc/cpuinfo и строка CONFIG_INTEL_HFI_THERMAL=y в конфиге ядра говорят, что обратная связь собрана и работает:

grep -m1 flags /proc/cpuinfo | grep -ow hfi
grep HFI /boot/config-$(uname -r)
hfi
CONFIG_INTEL_HFI_THERMAL=y

Четыре класса потоков и расчет по числу инструкций на такт

Thread Director делит все потоки на четыре класса с номерами от 0 до 3. Класс 0 получают ветки с наибольшим отношением инструкций к тактам, им скорость нужнее всего, класс 3 достается самым медленным потокам с длинными паузами. Классификатор сравнивает измеренный IPC с эталоном для типа ядра и корректирует оценку с учетом характера инструкций, поэтому поток с плотным векторным кодом и поток, ждущий данные из памяти, попадают в разные классы даже при равной доле процессорного времени. Класс пересматривается на каждом окне наблюдения, и один процесс в разные минуты жизни может побывать и в классе 0, и в классе 2: архиватор, распаковывающий сжатый лог, сначала считает интенсивно, а затем уходит в ожидание диска и теряет класс.

Расширение таблицы по классам дает планировщику материал для точных сравнений. В типичной картине P-ядро опережает E-ядро на классе 0 примерно вдвое, а на классе 3 преимущество сжимается до десятков процентов, поэтому дорогая миграция оправдана только для вычислительных веток. Класс конкретного потока наружу не отдается: классификация живет внутри процессора, и вовне уходят лишь агрегированные оценки из таблицы HFI. Приближенный анализ выполняется утилитой perf, которая считает те же инструкции и такты:

perf stat -e instructions,cycles -p 3124 -- sleep 10
Performance counter stats for process id '3124':

    18,442,109,002      instructions              #    1.64  insn per cycle
    11,236,904,517      cycles                    #    3.912  GHz
          10.012341100 seconds time elapsed

Деление дает 18 442 109 002 / 11 236 904 517 = 1.64 инструкции на такт, и это значение того же порядка, что закладывает в класс сам классификатор. Потоки с показателем в районе 2 и выше типично попадают в старшие классы, а значения ниже 0.5 характерны для классов 2 и 3, когда программа большую часть времени проводит в ожидании.

Поддержка Thread Director в ядре 5.18 и ее условия

Драйвер HFI, принимающий термальные прерывания и разбирающий таблицу, вошел в ядро 5.17. Через один релиз, в 5.18, добавили распознавание типов ядер по листу CPUID.1AH и учет классов потоков при планировании, и эта пара стала минимальной базой для гибридных чипов Alder Lake. Чтобы механизм заработал, нужны три условия: процессор с флагом гибридности, свежий микрокод с таблицами классификатора и активный интерфейс HFI в прошивке. Версию микрокода показывает /proc/cpuinfo:

grep -m1 -E 'model name|microcode' /proc/cpuinfo
model name	: 12th Gen Intel(R) Core(TM) i9-12900K
microcode	: 0x12c

Тип ядра процессор отдает через лист CPUID.1AH: значение 0x40 означает ядро Atom, значение 0x80 соответствует ядру Core, а с версии 5.18 эти числа дублируются в sysfs в атрибуте core_type внутри каталога topology каждого логического процессора. Типы ядер удобно сопоставить с диапазонами частот через lscpu и заодно проверить спаривание потоков:

lscpu -e=CPU,CORE,MAXMHZ | sed -n '1,4p;18p'
cat /sys/devices/system/cpu/cpu0/topology/thread_siblings_list
cat /sys/devices/system/cpu/cpu16/topology/thread_siblings_list
CPU CORE MAXMHZ
0   0    5200.0000
1   1    5200.0000
2   2    5200.0000
16  8    3900.0000
0,8
16

Первые шестнадцать логических процессоров сидят на восьми P-ядрах с Hyper-Threading: у ядра 0 два потока с номерами 0 и 8, а процессор 16 принадлежит E-ядру 8 и соседей не имеет. Эта карта понадобится при точечном закреплении задач через taskset.

Замеры частоты и энергопотребления в turbostat

Утилита turbostat из состава исходников ядра читает MSR-регистры напрямую и печатает фактические частоты, температуры и потребление по каждому ядру, показывая, как классификатор и планировщик распорядились ресурсами. Чтение MSR недоступно обычному пользователю, нужны права root:

sudo turbostat --quiet --interval 5 --num_iterations 3 --show Core,CPU,Bzy_MHz,PkgTmp,PkgWatt,CorWatt
Core	CPU	Bzy_MHz	PkgTmp	PkgWatt	CorWatt
-	-	4537	74	138.62	-
0	0	5089	74	138.62	16.87
8	16	3902	74	138.62	5.94

Первая строка со знаками дефиса усредняет весь пакет, дальше идут отдельные ядра. Разрыв частот виден сразу: производительное ядро держит 5089 МГц, экономичное 3902 МГц, и это согласуется с паспортными максимумами 5.2 и 3.9 ГГц. Температура пакета 74 градуса при Tjmax 100 означает запас до троттлинга, а потребление 138.62 Вт лежит между заводскими пределами PL1 и PL2 для i9-12900K, которые равны 125 и 241 Вт. При выходе на PL2 и прогреве способности ядер в таблице HFI снижаются, и планировщик получает сигнал смещать потоки к энергоэффективным ядрам. Ноль отсчета удобно снять на простое: средняя частота в районе 800-1000 МГц и потребление пакета порядка 20-30 Вт дают базу, с которой сравниваются все дальнейшие замеры.

Влияние на планировщик Linux и проверка закреплением

Планировщик использует рекомендации классификатора в двух местах: при выборе ядра для пробужденной задачи и при решении о миграции. Механизм Intel Turbo Boost Max Technology 3.0 задает ядрам приоритеты, и на гибридных системах эти приоритеты опираются на оценки способности к производительности, поступающие из таблицы HFI. Потоки старших классов смещаются на P-ядра, поток с низким IPC планировщик спокойно оставляет на E-ядре, освобождая быстрые ядра для тех, кому они действительно нужны.

Проверить выгоды легко на одном и том же однопоточном тесте, закрепленном то на P-ядре, то на E-ядре:

taskset -c 0 openssl speed -seconds 10 rsa2048 2>/dev/null | tail -2
taskset -c 16 openssl speed -seconds 10 rsa2048 2>/dev/null | tail -2
                 sign    verify    sign/s verify/s
rsa 2048 bits 0.000239s 0.000014s   4182.3  71428.6
                 sign    verify    sign/s verify/s
rsa 2048 bits 0.000406s 0.000023s   2463.1  43478.3

Расшифровка проста: 4182.3 подписи в секунду на P-ядре против 2463.1 на E-ядре, а расчет прибавки выглядит так: (4182.3 - 2463.1) / 2463.1 * 100 = 69.8 процента. Отношение 1.7 близко к произведению отношения частот 5.2 / 3.9 = 1.33 на разницу в эффективности на такт между Golden Cove и Gracemont.

Теперь стоит оставить задаче свободу и посмотреть, куда ее поставит планировщик с включенным Thread Director:

openssl speed -seconds 10 rsa2048 >/dev/null 2>&1 &
pid=$!
sleep 3
ps -o pid,psr,comm -p $pid
wait $pid
  PID PSR COMM
 8421   4 openssl

Столбец PSR показывает текущий процессор: значение 4 относится к группе P-ядер, значит высококлассовый поток планировщик унес на быстрое ядро сам, без указаний извне. Номер процессора хранится и в тридцать девятом поле файла /proc/PID/stat, что удобно для коротких скриптов.

Ограничения анализа и порядок проверки на реальной машине

У механизма есть границы, о которых стоит помнить при интерпретации цифр. В виртуальной машине HFI обычно не пробрасывается гостю, поэтому классификация не работает, хотя типы ядер через CPUID.1AH могут быть видны. На ядрах до 5.18 гибридная топология известна системе, но подсказки классификатора планировщик игнорирует, и задачи распределяются без учета IPC. Класс конкретного потока наружу не отдается, так что выводы строятся на косвенных признаках: частотах, размещении по ядрам и собственном расчете IPC. Порядок анализа на реальной машине сводится к нескольким шагам:

  1. проверить флаг hfi в /proc/cpuinfo и строку CONFIG_INTEL_HFI_THERMAL в конфиге ядра;
  2. сопоставить типы ядер через атрибут core_type в sysfs и вывод lscpu;
  3. снять базовые частоты, температуру и потребление в turbostat на простое и под нагрузкой;
  4. прогнать один и тот же однопоточный тест на P-ядре и на E-ядре через taskset и сравнить пропускную способность;
  5. вычислить IPC через perf stat и соотнести его с тем, на каких ядрах планировщик оставляет поток.

Когда анализ показывает, что вычислительный поток месяцами висит на E-ядрах, у администратора есть рычаги: точечное закрепление через taskset, ограничение множества ядер для группы процессов через cpuset в cgroup версии 2 или смена профиля governor в sysfs. Цифры из turbostat и perf превращают спор о гибридных процессорах в измеряемую задачу: видно, где классификатор прав, а где планировщик ошибается и отдает быстрые ядра тем, кому они не нужны. Thread Director не заменяет понимание нагрузки, но дает ядру Linux данные, которых раньше не было вовсе, и проверка этих данных руками занимает меньше десяти минут.