Почему мой компьютер предпочитает четные ядра?

На моем компьютере установлен Core i7 vPRO 10-го поколения с включенной виртуализацией. 8 ядер + 8 виртуальных ядер. (i7-10875H, Comet Lake)

Каждое физическое ядро ​​разделено на пары, поэтому ядро ​​1 содержит виртуальные ядра 0 и 1, ядро ​​2 содержит виртуальные ядра 2 и 3. Я заметил, что в диспетчере задач первый элемент каждой пары ядер кажется предпочтительным ядром, судя по большему использованию. Я устанавливаю некоторые привязки вручную для некоторых тяжелых программ, но я всегда устанавливаю их группами по 4, либо от 0-3, 4-7, 8-11, 12-15, и никогда не совпадаю с разными логическими процессорами.

Мне интересно, почему происходит такое поведение - приравниваются ли ядра с четными номерами к физическим ядрам, которые могут быть немного быстрее? Если да, получу ли я чуть более высокую тактовую частоту без виртуализации, если я запускаю программы, которые не имеют большого количества потоков?

введите здесь описание изображения введите здесь описание изображения


person 5Diraptor    schedule 02.02.2021    source источник
comment
Все ваши ядра являются логическими ядрами. Пары из них совместно используют физическое ядро, и ваша ОС может предпочесть один из двух братьев и сестер каждой пары, чтобы свести к минимуму количество задач, конкурирующих за одно и то же физическое ядро.   -  person Peter Cordes    schedule 02.02.2021
comment
Ваш ЦП Comet Lake имеет Turbo 3.0, который идентифицирует одно или несколько физических ядер как специальные, способные работать на более высоких тактовых частотах. intel.ca/content/www/ca/en/architecture-and-technology/ Это может быть частью этого для рабочих нагрузок с малым числом потоков, но не объясняет предпочтение одного гиперсестра другому, поскольку это полностью симметричный.   -  person Peter Cordes    schedule 02.02.2021
comment
Кстати, это не вопрос программирования; кажется, принадлежит SuperUser.com. Проголосовал за миграцию (не близко), так как там все понятно и по теме.   -  person Peter Cordes    schedule 02.02.2021
comment
Вы хотите спросить, удваивает ли гиперпоточность мощность процессора? Это не так. Два потока HT в среднем на 30% быстрее, чем один. Поэтому имеет смысл сначала распределить работу между физическими ядрами, а использовать HT в крайнем случае. Также, если мы будем считать от 0, это будут четные ядра.   -  person rustyx    schedule 02.02.2021
comment
@rustyx: Всегда ли Windows перечисляет ядра со смежными гипер-братьями? (Или, может быть, вы просто говорите конкретно о системе ОП). На некоторых материнских платах Linux нумерует ядра 0..n-1 для одного логического ядра каждого физического ядра, а затем n..2n-1 для другого ядра. Например, 0 и 4 являются братьями и сестрами на моем i7-6700k (4c8t). то есть идентификатор ядра в /proc/cpuinfo кодирует 0,1,2,3,0,1,2,3 вместо 0,0,1,1,2,2,3,3. Но, как я уже сказал, именно так ОС выбирает перечисление; Я не уверен, что это соответствует какой-либо жесткой нумерации в BIOS или оборудовании.   -  person Peter Cordes    schedule 02.02.2021
comment
@PeterCordes Кажется, по крайней мере, в моей системе: Core 0: mask 0x3, Core 1: mask 0xc, Core 2: mask 0x30, Core 3: mask 0xc0. К сожалению, godbolt не может запустить win32.   -  person rustyx    schedule 03.02.2021
comment
@rustyx: Linux-системы некоторых других людей сообщают о ядрах в том же порядке, что и вы и OP, например, 0,0, 1,1 и т. д. Так что это может произойти случайно. Было бы необходимо протестировать несколько систем, чтобы показать, что он последовательно делает это (особенно в системах, где Linux действительно перечисляет его так, как это делает моя), или найти некоторую документацию.   -  person Peter Cordes    schedule 03.02.2021
comment
@rustyx Я знаю, что виртуализация не увеличивает емкость. На самом деле мне было интересно, действительно ли это немного замедлит тактовые частоты по сравнению с отсутствием виртуализации. Если мои программы не используют более 8 потоков, мне интересно, есть ли смысл включать виртуализацию.   -  person 5Diraptor    schedule 03.02.2021
comment
Включение или отключение виртуализации ничего не связано с количеством потоков при обычных или пиковых рабочих нагрузках. Это полностью ортогонально гиперпоточности. Например, на нескольких логических ядрах может работать виртуальная гостевая ОС (с подкачкой страниц через аппаратно поддерживаемые таблицы вложенных страниц, с аппаратной обработкой таблиц гостевых страниц и таблиц хост-страниц), в то время как на других логических ядрах выполняется что-то еще. Код в гостевой виртуальной машине будет работать немного медленнее, чем в ОС на «голом железе», из-за более дорогих переходов по страницам и случайных выходов из виртуальной машины для некоторых вещей, но тактовая частота одинакова.   -  person Peter Cordes    schedule 03.02.2021


Ответы (2)


В общем (для теории планировщика):

  • если вы заботитесь о производительности, по возможности распределяйте задачи по физическим ядрам. Это предотвращает замедление выполнения двух задач, поскольку они совместно используют физическое ядро, в то время как все физическое ядро ​​находится в состоянии простоя.

  • если вам важно энергопотребление, а не производительность, по возможности заставляйте задачи использовать логические процессоры в одном физическом ядре. Это может позволить вам перевести целые ядра/ядра в очень энергоэффективное состояние бездействия.

  • если вы заботитесь о безопасности (а не о производительности или энергопотреблении), вообще не позволяйте несвязанным задачам использовать логические процессоры в одном и том же физическом ядре (поскольку информация, например, какие инструкции используются в данный момент, может просочиться из одного логического процессора). процессора другому логическому процессу в том же физическом ядре). Обратите внимание, что для связанных задач было бы нормально использовать логические процессы в одном физическом ядре (например, 2 потока, принадлежащие одному и тому же процессу, которые доверяют друг другу, но не потоки, принадлежащие разным процессам, которые не доверяют друг другу) .

Конечно, хорошая ОС будет знать предпочтения для каждой задачи (если каждая задача заботится о производительности, энергопотреблении или безопасности) и будет принимать разумные решения для обработки смеси задач с разными предпочтениями. К сожалению, хороших операционных систем не существует — большинство операционных систем и API-интерфейсов были разработаны в 1990-х годах или ранее (когда SMP только зарождалась и все процессоры в любом случае были идентичными) и в них отсутствует информация о задачах, которая была бы необходима для принятия разумных решений; поэтому они предполагают, что производительность — это единственное, что имеет значение для всех задач, что приводит к тому, что задачи распределяются по физическим ядрам, где это возможно, даже если это не идеальное поведение, которое вы видите.

person Brendan    schedule 02.02.2021

Я предполагаю, что это из-за гиперпоточности.

Гиперпоточность не удваивает мощность процессора (по данным Intel, она добавляет в среднем около 30%), поэтому имеет смысл сначала распределить работу между физическими ядрами, а использовать гиперпоточность в крайнем случае, когда общая потребность в процессоре начинает превышать 50%. .

Забавный факт: заявленная 50-процентная общая загрузка ЦП в системе с гиперпоточностью на самом деле составляет около 70 %, а оставшиеся 50 % равны оставшимся ~ 30 %.

Если мы запросим у ОС, как логические процессоры назначены ядрам1, мы увидим такую ​​ситуацию:

Core 0: mask 0x3
Core 1: mask 0xc
Core 2: mask 0x30
Core 3: mask 0xc0
. . .

Это означает, что логические процессоры 0 и 1 находятся на ядре 0, 2 и 3 на ядре 1 и т. д.

Вы можете отключить гиперпоточность в BIOS. Но поскольку это повышает производительность, приятно иметь эту функцию. Просто нужно быть осторожным, чтобы не закрепить работу так, чтобы она конкурировала за одно и то же ядро.


1 Чтобы проверить назначение ядра, я использую небольшую программу на C, приведенную ниже. Информация также может быть доступна через WMIC.

#include <stdio.h>
#include <stdlib.h>
#undef _WIN32_WINNT
#define _WIN32_WINNT 0x601
#include <Windows.h>

int main() {
    DWORD len = 65536;
    char *buf = (char*)malloc(len);
    if (!GetLogicalProcessorInformationEx(RelationProcessorCore, (PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX)buf, &len)) {
        return GetLastError();
    }
    union {
        PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX info;
        PBYTE infob;
    };
    info = (PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX)buf;
    for (size_t i = 0, n = 0; n < len; i++, n += info->Size, infob += info->Size) {
        switch (info->Relationship) {
        case RelationProcessorCore:
            printf("Core %zd:", i);
            for (int j = 0; j < info->Processor.GroupCount; j++)
                printf(" mask 0x%llx", info->Processor.GroupMask[j].Mask);
            printf("\n");
            break;
        }
    }
    return 0;
}
person rustyx    schedule 03.02.2021
comment
Попытка интерпретировать нагрузку 50 % (с одним ядром на каждом физическом ядре) как 70 % очень схематична. Это действительно зависит от фактической рабочей нагрузки, сколько дополнительной работы может выполнять каждое ядро. Код с высокой пропускной способностью (инструкций за такт), специально настроенный для кэш-памяти L1, например, BLAS matmul, может столкнуться с отрицательным масштабированием при гиперпоточности. то есть лучшая общая пропускная способность с отключенным HT или с одним потоком на физическое ядро. Очень разветвленный код, как, возможно, некоторые алгоритмы сжатия, может лучше масштабироваться. (OTOH, некоторые высокопроизводительные коды, такие как x264/x265, немного масштабируются, например, на 15-20%). - person Peter Cordes; 04.02.2021
comment
Должен признаться, я еще не видел отрицательного масштабирования с HT. Просто говорю из опыта. Мы провели некоторые измерения различных типов (серверных) рабочих нагрузок на различных поколениях процессоров Xeon и Core i7/i9, и разница между первыми 50 % и последними 50 % заявленной и фактической производительности процессора всегда составляла от 70/30 до 80/20. Кроме того, я наблюдал значительную долю массовых простоев, вызванных тем, что люди полагали, что на сервере, загруженном на 50%, имеется достаточно свободной емкости. - person rustyx; 04.02.2021
comment
Большинство рабочих нагрузок масштабируются положительно, но я думаю, что это не редкость для тщательно настроенного кода высокопроизводительных вычислений, особенно для обработки чисел с плавающей запятой. Или, возможно, раньше это было более распространено, когда пропускная способность памяти была ниже, поэтому частота попаданий в кэш была еще более ценной, а размеры окон выполнения OoO (ROB и RS) были меньше, поэтому разделение или конкурентное совместное использование также уменьшало доступный ILP в каждом потоке. Особенно до появления Haswell, когда был только один модуль SIMD mul и один модуль add, а не два модуля FMA, поэтому насыщение было не таким сложным. например Zen очень широк и имеет много внутренних ресурсов пропускной способности. - person Peter Cordes; 04.02.2021