Как планировщик Windows 10 справляется с Hyper Threading, поскольку Core CPU по умолчанию отключена для процессоров Intel?

2422
manuel

Я использую Windows 10 (1607) на процессоре Intel Xeon E3-1231v3 (Haswell, 4 физических ядра, 8 логических ядер ).

Когда я впервые установил Windows 7 на эту машину, я заметил, что четыре из восьми логических ядер были припаркованы, пока приложению не потребовалось более 4 потоков. С помощью монитора ресурсов Windows можно проверить, припаркованы ли ядра или нет ( пример ). Насколько я понимаю, это важная техника для поддержания баланса потоков между физическими ядрами, как объясняется на веб-сайте Microsoft : « Алгоритм и инфраструктура парковки ядра также используются для балансировки производительности процессора между логическими процессорами в клиентских системах Windows 7 с помощью процессоры с технологией Intel Hyper-Threading ».

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

Но мне интересно, почему? Какова была причина этого? Есть ли замена и если да, то как это выглядит? Разработала ли Microsoft новую стратегию планировщика, которая сделала парковку ядра устаревшей?


Приложение:

Вот пример того, как базовая парковка, представленная в Windows 7, может повысить производительность (по сравнению с Vista, у которой пока нет базовой парковки). Вы можете видеть, что в Vista HT (Hyper Threading) снижает производительность, а в Windows 7 - нет:

enter image description here

enter image description here

( источник )

Я попытался включить Core Parking, как упоминалось здесь, но я заметил, что алгоритм Core Parking больше не поддерживает технологию Hyper Threading. Он припарковал ядра 4,5,6,7, в то время как он должен был припарковать ядра 1,3,5,7, чтобы избежать назначения потоков одному и тому же физическому ядру. Windows перечисляет ядра таким образом, что два последовательных индекса принадлежат одному физическому ядру. Очень странно. Кажется, Microsoft все испортила в корне. И никто не заметил ...

Кроме того, я сделал несколько тестов процессора, используя ровно 4 потока.

Сродство к процессору установлено для всех ядер (Windows defualt):

Среднее время работы: 17.094498, стандартное отклонение: 2.472625

Привязка к ЦП устанавливается на каждое другое ядро ​​(чтобы оно работало на разных физических ядрах, наилучшее планирование):

Среднее время работы: 15.014045, стандартное отклонение: 1.302473

Привязка ЦП установлена ​​на худшее из возможных расписаний (четыре логических ядра на двух физических ядрах):

Среднее время работы: 20.811493, стандартное отклонение: 1.405621

Так что есть разница в производительности. И вы можете видеть, что планирование по умолчанию в Windows ранжируется между лучшим и наихудшим возможным планированием, как мы ожидаем, что это произойдет с планировщиком, не поддерживающим гиперпоточность. Однако, как указано в комментариях, могут быть и другие причины, такие как меньшее количество переключений контекста, логический вывод приложений и т. Д. Таким образом, мы до сих пор не имеем однозначного ответа.

Исходный код для моего теста:

#include <stdlib.h> #include <Windows.h> #include <math.h>  double runBenchmark(int num_cores) { int size = 1000; double** source = new double*[size]; for (int x = 0; x < size; x++) { source[x] = new double[size]; } double** target = new double*[size * 2]; for (int x = 0; x < size * 2; x++) { target[x] = new double[size * 2]; } #pragma omp parallel for num_threads(num_cores) for (int x = 0; x < size; x++) { for (int y = 0; y < size; y++) { source[y][x] = rand(); } } #pragma omp parallel for num_threads(num_cores) for (int x = 0; x < size-1; x++) { for (int y = 0; y < size-1; y++) { target[x * 2][y * 2] = 0.25 * (source[x][y] + source[x + 1][y] + source[x][y + 1] + source[x + 1][y + 1]); } } double result = target[rand() % size][rand() % size]; for (int x = 0; x < size * 2; x++) delete[] target[x]; for (int x = 0; x < size; x++) delete[] source[x]; delete[] target; delete[] source; return result; }  int main(int argc, char** argv) { int num_cores = 4; system("pause"); // So we can set cpu affinity before the benchmark starts  const int iters = 1000; double avgElapsedTime = 0.0; double elapsedTimes[iters]; for (int i = 0; i < iters; i++) { LARGE_INTEGER frequency; LARGE_INTEGER t1, t2; QueryPerformanceFrequency(&frequency); QueryPerformanceCounter(&t1); runBenchmark(num_cores); QueryPerformanceCounter(&t2); elapsedTimes[i] = (t2.QuadPart - t1.QuadPart) * 1000.0 / frequency.QuadPart; avgElapsedTime += elapsedTimes[i]; } avgElapsedTime = avgElapsedTime / iters; double variance = 0; for (int i = 0; i < iters; i++) { variance += (elapsedTimes[i] - avgElapsedTime) * (elapsedTimes[i] - avgElapsedTime); } variance = sqrt(variance / iters); printf("Average running time: %f, standard deviation: %f", avgElapsedTime, variance); return 0; } 
6
Держись, "четыре из восьми ядер"? Вы только что упомянули, что ваш процессор имеет только 4 ядра и 8 _threads_. Действительно ли здесь применима «базовая парковка»? grawity 7 лет назад 1
@grawity Теоретически парковка ядра означала позволить процессору парковать половину гиперпоточного ядра. Насколько я понимаю, кэш-память на ядро ​​была разделена между двумя логическими (гиперпоточными) ядрами, и с одним припаркованным он мог быть освобожден и, по существу, позволил бы одному ядру получить доступ к полному кешу, который был к нему подключен. Это может обеспечить небольшой прирост для задач с низким числом потоков, при этом сохраняя способность восстанавливать гиперпоточность и полностью использовать ядро ​​в многопоточных задачах. Mokubai 7 лет назад 1
@ Grawity: Извините за путаницу. Я имел в виду восемь «логических ядер», то есть это только виртуальное ядро. manuel 7 лет назад 0
@mokubai Процессоры Intel могут запускать два потока на одном ядре процессора, что приводит к увеличению производительности примерно на 30%. Однако теперь предположим, что у вас есть приложение с двумя активными потоками. Теперь вы хотите, чтобы они работали на двух разных физических ядрах, что идеально удваивает производительность по сравнению с одним потоком. Но если они работают на одном физическом ядре с гиперпоточностью, они работают только на 30% быстрее, чем один поток. Вот где основная парковка приходит и избегает последней ситуации. manuel 7 лет назад 0
Процессоры AMD Zen имеют аналогичную проблему, но AMD недавно выпустила заявление, в котором в основном указывалось, что проблема заключалась в том, что утилита выполняла проверки производительности, а не саму Windows на основе всех проведенных исследований. Поэтому, прежде чем винить Microsoft за что-либо, убедитесь, что инструменты не виноваты .. Ramhound 7 лет назад 0
@ Мануэль, я знаю. Но парковка ядра также освобождает некоторый кэш и может стать дополнительным бонусом по сравнению с гипер поточным ядром с разделенным кешем. Mokubai 7 лет назад 0
@Ramhound: я только что проверил свою гипотезу с эталоном. manuel 7 лет назад 0
Базовая парковка относится ко всему физическому _core_, а не к отдельным логическим процессорам. (С включенным HT у вас есть два LP на ядро; с отключенным HT у вас есть только один.) Следует избегать таких терминов, как «виртуальное ядро» и «логическое ядро», поскольку они вводят в заблуждение. Базовая парковка возможна только в том случае, если _both_ LP в ядре неактивны в течение определенного периода времени. Jamie Hanrahan 7 лет назад 0
@ Джейми Ханрахан: неправильно. Прочитайте [это] (https://msdn.microsoft.com/en-us/library/windows/hardware/dn613899 (v = vs.85) .aspx), где написано: _ Алгоритм базовой парковки и инфраструктура также используются для сбалансировать производительность процессора между логическими процессорами в клиентских системах Windows 7 с процессорами, использующими технологию Intel Hyper-Threading._ manuel 7 лет назад 0
Это не так, как это реализовано в планировщике. См. Описание в _Windows Internals_ Соломона, Руссиновича и Ионеску. «Базовая парковка» означает буквальное отключение ядра. Вы не можете сделать это на уровне LP. Jamie Hanrahan 7 лет назад 0
все еще верно, что планировщик предпочитает использовать LP так, что для каждого ядра используется только один LP. Однако планирование потоков чрезвычайно динамично, и ваше тестовое приложение вряд ли будет единственным, что нужно запустить в любой момент. Таким образом, тот факт, что в вашем тестовом приложении есть только потоки _nCores_, но вы иногда видите два LP в ядре, оба из которых выполняют потоки вашего приложения, не означает, что это не работает. Также помните, что для запуска диспетчера задач или почти любой другой программы мониторинга требуется запуск хотя бы одного потока! Просто взгляд на систему меняет то, что она делает. Jamie Hanrahan 7 лет назад 0
@JamieHanrahan: Извините, но ваше заявление о базовой парковке все еще неверно. Я посмотрел его (шестое издание Windows Internals, 2-я часть, стр. 108), где говорится: «Основные политики парковки [...] и, что самое важное, всегда оставляет один поток в пакете SMT непаркованным, другими словами, он отвечает за существенное отключение функции Hyper-Threading, присутствующей в процессорах Intel, до тех пор, пока нагрузка этого не потребует ». _ manuel 7 лет назад 0
Вы слишком много читаете об этом. Да, код, который делает это, переплетается с кодом «парковки ядра», но попытка использовать только один LP в ядре не является «парковкой ядра». Вы категорически не можете «припарковать» один LP из ядра. LP не является физически отдельным набором логики, которая может быть припаркована; это 99% абстракция, представленная микроархитектурой. Обратите внимание, что, согласно статье MSy _you_ связанный, парковка ядра не происходит в Windows 7, только в Server 2008 ... но в Windows 7 происходит одноразовая запись за раз. Поэтому при использовании только одного LP на ядро в то время это не «основная парковка». Это просто не с использованием LP. Jamie Hanrahan 7 лет назад 0
Ну, это просто техничность. И это не объясняет, почему я мог _видеть> функцию, подобную парковке ядра, работающую в Windows 7 через диспетчер задач, монитор ресурсов и т. Д., В отличие от Windows 10, где изменилось планирование процессов и это ядро, дружественное к гиперпоточности парковка, как планирование, больше не используется. Возможно, нам придется подождать, пока не будет выпущена седьмая редакция Windows Inside, но мне действительно любопытно посмотреть, что именно изменила Microsoft _или_, если это действительно так, что старое планирование Vista вернуло назад производительность для приложений с потоком <= 4 , manuel 7 лет назад 0
@manuel Были значительные улучшения между Windows 7 и Windows 10 Ramhound 7 лет назад 0
Я не знаю, что вы видите, @manuel, но я вижу, что под Windows 10 все время происходит один LP-на-ядро. Я думаю, что ваша система просто загружена больше, чем вы думаете, поэтому у планировщика мало выбора но использовать более одного LP в некоторых ядрах. Если вы действительно ненавидите такое поведение, просто отключите гиперпоточность в настройках прошивки. Jamie Hanrahan 7 лет назад 0
@JamieHanrahan Но это не то, что я вижу. И это подтверждается различными отчетами в Интернете (см., Например, [это] (https://social.technet.microsoft.com/Forums/en-US/8d6085d8-2c26-426c-87ac-2ba189b77aa5/core-parking-not -working-after-upgrade? forum = win10itprohardware)) Может быть, у вас есть процессор AMD, потому что в этом случае Windows 10 по-прежнему использует Core Parking. manuel 7 лет назад 0
Нет, это Intel. Я повторяю: вы не можете идти по тому, что вы видите в диспетчере задач. Я считаю, что в Windows 10 произошло то, что планировщик не задерживается так долго, пока не запустит поток в ядре, в котором уже запущен поток. Jamie Hanrahan 7 лет назад 0
Я считаю, что то, что вы видите, является оптическим обманом. Я проверил ситуацию на 8-ядерном компьютере с Hyper Threading (16 логических ядер), и мне очень трудно сказать, сколько ядер припарковано и какие. Кажется, что планировщик Windows 10 паркует и распаковывает ядра с высокой скоростью, поэтому в Resource Monitor я вижу состояние «Запарковано», устойчивое на одних ядрах, но часто мерцающее на других. Честно говоря, я не могу сказать, сколько припаркованных ядер у меня есть в любой момент времени, и я также сомневаюсь, что отображение Resource Monitor может справиться с этим. harrymc 7 лет назад 0
@harrymc Я не вижу "припаркованной" метки в мониторе ресурсов. Не все. Даже если процессор полностью простаивает с использованием <5%. Так что я не думаю, что ваша теория верна, в противном случае планировщик должен быть настолько глуп, что он часто отключает ядра, даже если мой компьютер находится в состоянии полной простоя, что также было бы ошибочным поведением. manuel 7 лет назад 0
@manuel: «некорректное поведение», но за этим может быть какая-то логика. Например, разделив нагрузку между ядрами, чтобы не перегружать одно ядро. Разработчики ядра Windows, безусловно, знают аппаратное обеспечение Intel лучше, чем вы или я. Проверка: в ключе реестра `HKEY_LOCAL_MACHINE \ SYSTEM \ CurrentControlSet \ Control \ Power \ PowerSettings \ 54533251-82be-4824-96c1-47b60b740d00 \ 0cc5b647-c1df-4637-891a-dec35c318583`, установите значение в 100MM и значение в 100MM = 0 '. Перезагрузитесь, если что-то измените. harrymc 7 лет назад 0
Это не отвечает на ваш вопрос, но я держу пари, что Microsoft не заботится о чем-то столь же "устаревшем", как технология Haswell. Skylake от Intel представила технологию Speed ​​Shift, которая, помимо прочего, делает парковку ядра под управлением ОС избыточной. Последняя сборка Windows 10 очень хорошо поддерживает Speed ​​Shift. Ни Intel, ни Microsoft не дают много технических подробностей, но я думаю, что можно с уверенностью предположить, что Microsoft отключила парковку ядра в Win 10, потому что архитектура ядра и его оптимизация в пользу новых процессоров сделали его несовместимым с унаследованной в настоящее время парадигмой парковки ядра. misha256 7 лет назад 0
Может быть, вы можете включить его? ... http: //www.thewindowsclub.com/enable-disable-core-parking-windows Moab 6 лет назад 0

1 ответ на вопрос

0
ZXX

Да, я мог бы рассказать вам историю, но вы будете ненавидеть это, и я буду ненавидеть писать это :-)

Короткая версия - Win10 испортил все, что мог, и находится в постоянном состоянии голодающих ядер из-за системной проблемы, известной как переподписка процессора (слишком много потоков, никто не может их обслуживать, что-то задыхается в любой точке, навсегда). Вот почему они отчаянно нуждаются в этих поддельных процессорах, сокращают базовый таймер планировщика до 1 мс и не могут позволить вам парковаться. Это просто опалило бы систему. Откройте Process Explorer и добавьте количество потоков, теперь сделайте математику :-)

API CPU Sets был введен для того, чтобы дать хоть какой-то шанс для борьбы тем, кто знает и имеет время написать код для борьбы со зверем. Вы можете де-факто парковать поддельные процессоры, помещая их в набор процессоров, который вы никому не дадите, и создав набор по умолчанию для передачи его пираньям. Но вы не можете сделать это на клиентских sku-s (технически это может быть просто невозможно), так как ядро ​​перейдет в состояние паники и либо полностью проигнорирует наборы процессоров, либо некоторые другие вещи начнут падать. Он должен защищать целостность системы любой ценой.

Все положение вещей в целом является табу, так как для этого потребуются серьезные переписки, и каждый выберет несерьезные темы и признает, что они все испортили. Гиперпотоки на самом деле должны быть постоянно отключены (они нагревают ядра при реальной нагрузке, ухудшают производительность и дестабилизируют HTM - основная причина, по которой он никогда не стал массовым). Большие магазины SQL Server делают это в качестве первого шага установки, как и Azure. Нет, они запускают серверы с де-факто настройкой клиента, так как им нужно было бы гораздо больше ядер, чтобы осмелиться переключиться. Проблема просочилась в Server 2016.

SQL Server является единственным реальным пользователем наборов ЦП (как обычно :-), 99% продвинутых возможностей Win всегда выполнялись только для SQL Server, начиная с суперэффективной обработки файлов с отображением в памяти, которая убивает людей, пришедших из Linux с тех пор они предполагают различную семантику).

Чтобы безопасно играть с этим, вам понадобится минимум 16 ядер для клиентского компьютера, 32 для сервера (что на самом деле делает что-то реальное :-) Вы должны установить как минимум 4 ядра по умолчанию, чтобы ядро ​​и системные службы едва дышали. но это все равно только двухъядерный эквивалент ноутбука (у вас все еще есть постоянный удушье), что означает 6-8, чтобы позволить системе дышать правильно.

Win10 нужно 4 ядра и 16 ГБ, чтобы едва дышать. Ноутбуки обходятся без 2-х ядерных и 2-х фальшивых «процессоров», если не нужно ничего делать, так как их обычное распределение работы таково, что всегда есть достаточно вещей, которые все равно нужно ждать (длинная очередь на memaloc «очень помогает» :-) ,

Это все равно не поможет вам с OpenMP (или каким-либо автоматическим распараллеливанием), если у вас нет способа явно указать ему использовать ваш набор ЦП (отдельные потоки должны быть назначены для набора ЦП) и ничего больше. Вам все еще нужно установить соответствие процессов, это предварительное условие для наборов процессоров.

Сервер 2k8 был последним хорошим (да, это также означает и Win7 :-). Люди массово загружали ТБ за 10 минут им и SQL Server. Теперь люди хвастаются, что могут загрузить его за один час - под Linux :-) Так что, скорее всего, положение "не там" тоже намного лучше. У Linux были CPU Sets задолго до Win.

Похожие вопросы