Как стать автором
Обновить

Комментарии 26

Снимаю шляпу за качественный контет о Linux! Громадное спасибо за статью.

@dlinyj Спасибо за отзыв.

>>Теперь в процессоре, имея два потока выполнения на каждое ядро, ядро процессора может не простаивать, когда один из потоков спит, а переключится на второй поток,

Что ему мешает сделать это же без HT?

Что ему мешает сделать это же без HT?

В принципе ничего, просто будут дороже переключения контекста. Если взять вытесняющую многозадачность, то там используется таймер, по которому он запускается, т.е. до запуска таймера будет простой процессора. А в случае с кооперативной многозадачности мы должны ждать пока поток сам передаст управление другому потоку. Процессор же может моментально выполнить два потока, когда один поток простаивает и когда конвейер процессора пуст. Вычислительный конвейер

>>до запуска таймера будет простой процессора.

Не будет. Спящий процесс (выполнивший системный yield() или sleep()) гарантированно снимется шедулером с исполнения досрочно, освободив ядро для другого процесса. Вы перепутали это с активным циклом ожидания (spin loop).

Спасибо КЭП за разъяснение! У меня такое чувство, что люди совсем не читали статью и комментарии, сами себе чето-то надумали сами же на свой вопрос ответили…
yield() или sleep() это совсем другой случай, про это мной нигде не было написано. Поток даже может не вызвать yield() или sleep(). Ваши знания как раз видимо и spin loop ограничены…
И вы упустили самый главный момент, что yield() или sleep() займет суммарно значительно больше тактов процессора чем при SMT и HT.

Специально нигде сильно не углублялся, чтобы не усложнять теорию, просто описал основные принципы работы. А если углубиться в тему, то там еще вылезет кучу специфичных вещей для ОС и конкретной версии ядра… Если бы вы внимательно читали статью, то поняли бы, что речь не совсем про планировщик, а про Core Scheduling… Условно вы предлагаете в автошколе учить водителей, тому на какие контакты приходит сигнал зажигания, какая микросхема как работает, как паять контакты, что где-то там должен быть цифровой сигнал определенной формы и тогда автомобиль заведется. Когда можно просто дать ключи, объяснить, как завести, проверить уровень бензина в баке и все. Зачем водителю знать, как устроен двигатель внутреннего сгорания на инженерном уровне? Если ему достаточно знать, что есть бензин, свеча, свеча воспламеняет бензин и толкает поршень.

Мы не будем углубляться в эту тему слишком глубоко, так как это тема отдельной статьи. Но вы всегда можете найти комментарии и пояснения к коду, в файле: include/linux/sched.h, и изучить эту тему самостоятельно. Умение читать исходные коды ядра, является очень важным навыком для каждого разработчика, который хочет углубиться в программирование ядра Linux. Часть полезной информации также можно найти в официальной документации ядра Linux — Scheduler, но всё же лучше смотреть исходные коды ядра.


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

Так откуда простой процессора при уходе задачи в слип? Я уже не про статью пишу, в про ваш комментарий.

Главный вопрос к статье в том, что вы неправильно поставили акцент зачем был сделан HT, как и написали вам снизу - для более полного использования ФУ ядер, а не для экономии на переключении. Экономия на переключении конекста это скорее побочный эффект, и в этом случае делали бы не 2HT а 4 или 8. Только про КНЛь не вспоминайте, там совсем другая история.

>>Условно вы предлагаете в автошколе учить водителей

Нет. ПК пользователям я ничего не предлагаю. А вы, и читатели Хабра - это инженеры, и знать как все устроено это их профессия.

Гранулярность разная. Потоки в операционке засыпают, когда ждут внешних событий: завершения ввода или вывода или других аналогичных событий. В HT под простоем подразумевается, что поток ждёт выполнения долгой инструкции. Обычно это запись или чтение памяти в незакэшированную в L1 память.

Но HT работает не только в этих ситуациях. Допустим, у вас у одного потока много инструкций для FPU блоков процессора, а у другого для ALU, в этом случае процессор тоже может планировать исполнение потоков совместно. Или бывают ситуации, когда в одном потоке длинная цепочка нераспараллеливаемых инструкций (как пример, расчёт факториала последовательным умножением чисел), такая цепочка не грузит все доступные функциональные устройства процессора, и на них можно запускать другой поток.

Какая-то такая картинка.

Последние несколько лет каждая новая версия ядра объявляется "самой многообещающей, значимой, крупной, интересной, и т.д.".

Linux стал большим коммерческим проектом... Со всеми вытекающими последствиями для PR

В этом разработчики RedHat, Gentoo, Suse просто на две головы выше.

так может стоило выбрать opensuse, thumbleweed такой же ролинг как и арч, только поштабильнее, а OBS (build.opensuse.org) в разы адекватнее aur и всех рачеспособов доставить пакетов о которых не позаботились мейнтейнеры. А для особо упоротых он позволяет собирать и для рача и для дебиана и так далее.. и не надо болеть головой о том где и как репо содержать

13werwolf13 может и так. Просто у арча самые удобные для чтения скрипты сборки и нравится как сам дистрибутив устроен, но честно раньше я не ожидал, что там мейнтейнеры р*дяи, и тоже в скриптах сборки много грязи. Я им даже патчи на блюдечке преподносил для нескольких пакетов, чтобы они взяли и обновили зависимые пакеты. Все дистрибутивы это сделали, а они там что-то телятся, и многие совсем не умеют читать баги в астриме и писать патчи. Лично перерабатываю каждый скрипт сборки, смотрю багрепорты, оптимизирую код сборки, удаляю костыли времен царя гороха, где-то добавляю свои самопальные патчи, где могу сам решить проблему. Переход для меня не имеет смысл, уже на пути создании своего дистрибутива. В день просматривают не мало багрепортов и по объему написанных патчей RedHat впереди всех, больше всего багов они закрывают, но скрипты сборки тяжелые у них. Насчет универсальной сборки под arch, redhat, debian это не сложно сделать, все собирается в clean chroot просто разный упаковщик пакетов, главная проблема, что везде по разному именуются зависимости, вот это думаю они не смогли решит, иначе пакет будет сразу в себе все зависимости содержать, чтобы не ломать его работу.
Теперь же решение о переключении задач принимает OC по заданному таймеру. Такую многозадачность называют вытесняющая многозадачность или PREEMPT, preemptive multitasking. Простой пример такой очереди, когда в очереди к директору компании стоят сотрудники, но приходит какой-нибудь проверяющий, или какое-то важное лицо, и всех просят подождать, пока директор пообщается с этим более важным человеком.
Тема таймера в примере не раскрыта. Не то чтобы это очень важно, но создается странное впечатление от прочитанного. Наверное можно было бы и без таймера более приоритетную задачу пропускать (по прерыванию от клавиатуры например). Но благодаря таймеру даже менее приоритетный поток может получить управление перед более приоритетным, если тот будет долго выполнятся.
LynXzp у меня не было цели максимально достоверно донести, как работает вытесняющая многозадачность, если углубляться в тему там еще много нюансов. Это тема отдельной статьи. Наоборот цель была передать человеку незнакомому с устройством ОС максимально просто смысл происходящего в ядре ОС. Моя задача не писать сложным языком о сложных вещах, моя задача уменьшить разрыв в знаниях у специалистов и показать, что в реальности все очень просто.
В теоретической части как-то многовато неточностей.
Каждая задача, после того, как выполнила свою работу, должна была явно уведомить планировщик, что задача завершила свою работу и планировщик может переключиться на следующую задачу. Такую очередь называют FIFO — First In First Out первым пришёл, первым ушёл. А такую многозадачность называют совместной или кооперативной многозадачностью.

Не совсем точно. Характер многозадачности (кооперативная или вытесняющая) и политика планировщика (простая очередь — FIFO, приоритетная очередь или ещё как) — это две независмые характеристики. К примеру, в классической системе с кооперативной многозадачностью — MS Windows 3.х — была функция DirectedYield, позволявшая передать управление из текущей задачи указанной задаче.
Чтобы уменьшить накладные расходы переключения задач в ОС, разработчики процессоров придумали простое и элегантное решение, переложили часть функций на процессор. Так были придуманы Intel Hyper-Threading (Intel HT) и AMD Simultaneous Multithreading (AMD SMT).

Причина появления HT — указана не совсем верно, точнее — совсем неверно. HT был введен с целью наиболее полно задействовать все функциональные блоки ядра, которые там есть самые разные — обычные вычисления, вычисления с плавоющей точкой и т.д. Поэтому, кстати, с HT мало толку, когда практически все потоки в системе выполняют одноообразные задачи, а потому задействуют одни и те же функциональные блоки. А потому, для таких систем (например, серверов MS Exchange) включать HT не рекомендуется — выигрыш от задействия разных функциональных блоков не оправдывает потерь на диспетчеризацию для дополнительных ядер.

ЕМНИП 100% + 30% получается, если есть кэш-миссы прямо в память.

Характер многозадачности (кооперативная или вытесняющая) и политика планировщика (простая очередь — FIFO, приоритетная очередь или ещё как) — это две независмые характеристики.

Да так и есть.

К примеру, в классической системе с кооперативной многозадачностью — MS Windows 3.х — была функция DirectedYield, позволявшая передать управление из текущей задачи указанной задаче.

Хоть у меня была 3.11 не знаю, что там было.

HT был введен с целью наиболее полно задействовать все функциональные блоки ядра, которые там есть самые разные — обычные вычисления, вычисления с плавоющей точкой и т.д.

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

А потому, для таких систем (например, серверов MS Exchange) включать HT не рекомендуется — выигрыш от задействия разных функциональных блоков не оправдывает потерь на диспетчеризацию для дополнительных ядер.

Это уже особенность Windows c его более микроядерной архитектурой. В Linux же используется монолитное ядро.
Они без этого все задействованы.
Нет. Например, если происходит кэш-промах при обращении к данным, то процессору приходится обращаться к памяти, а это — достаточно долгая операция (сотни тактов), за время выполнения которой все выбранные с опережением независимые от инструкции, обращающейся к памяти, инструкции успевают исполниться и исполнительные устройства процессора в результате простаивают. Планировщик ОС при этом не получает никакого уведомления: все это происходит для него прозрачно (да и не сможет он на это эффективно среагировать).
А вот наличие второго потока выполнения для другого логического процессора в физическом процессоре с поддержкой HT позволяет в данном примере загрузить эти простаивающие исполнительные устройства физического процессора (если, конечно, этому потоку тоже не понадобится вскоре обратиться в память за содержимым, которое остутствует в кэше).
Как раз дело в шедулере, что переключения через OC затрагивают суммарно больше времени и процессорных тактов.
Строго говоря, HT сама по себе в переключении потоков операционной системы в планировщике не участвует. Она просто представляет планировщику ОС физический процессор как два логических процессора, на каждый из которых ОС назначет по одному потоку выполнения. Огрубленно ( если не обращать внимание на детали, что современные ОС знают о логических процессорах и принимают меры, чтобы не снизить производительность их неправильным использованием), ОС работает с логическим процессом HT так же как с физическим ядром.
Это уже особенность Windows c его более микроядерной архитектурой. В Linux же используется монолитное ядро.
Вся эта работа по представлению физического процессора как двух логических происходит при выполнении пользовательской программы в пользовательском режиме работы логического процессора, безо всякого вмешательства ОС. Поэтому рост или потеря производительности от ядра ОС никак не зависит: это — интимное дело процессора и программы пользовательского режима.
Нет. Например, если происходит кэш-промах при обращении к данным, то процессору приходится обращаться к памяти, а это — достаточно долгая операция (сотни тактов), за время выполнения которой все выбранные с опережением независимые от инструкции, обращающейся к памяти, инструкции успевают исполниться и исполнительные устройства процессора в результате простаивают. Планировщик ОС при этом не получает никакого уведомления: все это происходит для него прозрачно (да и не сможет он на это эффективно среагировать).
А вот наличие второго потока выполнения для другого логического процессора в физическом процессоре с поддержкой HT позволяет в данном примере загрузить эти простаивающие исполнительные устройства физического процессора (если, конечно, этому потоку тоже не понадобится вскоре обратиться в память за содержимым, которое остутствует в кэше).

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

Мною про это было написано. Вы сами же что-то надумали, и сами же ответили себе…
Ну, если вы изначально думали именно так, то дальше смысла вести дискуссию нет.
А если бы вы ещё и написали так, чтобы вас не могли понять неправильно — было бы совсем здорово.

>> Чтобы уменьшить накладные расходы переключения задач в ОС, разработчики процессоров придумали простое и элегантное решение, переложили часть функций на процессор. Так были придуманы Intel Hyper-Threading (Intel HT) и AMD Simultaneous Multithreading (AMD SMT).

В первый раз вижу такую странную интерпретацию причины появление Hyper Threading.
Возможно у вас будет ссылка?

Wiki, например, пишет, что целью было "увеличить параллелизм".
А разъясняющие статьи - объясняют, что процессорное ядро имеет общий бэкэнд (ALU и наборы регистров) для двух логических потоков исполнения.
И если основной поток "простаивает", например на длительных операциях (с точки зрения Out Of Order исполнения: не осталось полностью готовых (микро-)операций в основном потоке исполнения) - начинают исполняются операции второго потока исполения.

WASD1 ссылок нет, вполне логичная интерпретация. Выше уже был дан ответ, почему накладные расходы на переключение выше при использовании средств ОС. И в статье есть картинка иллюстрирующая это, похожие картинки есть в интернете по запросам Hyper-Threading, Intel HT, Simultaneous Multithreading, AMD SMT. Можно добавить еще, что в случае вытесняющей многозадачностью с таймером происходит прерывание, а все прерывания, как нас раньше учили самые дорогие операции для процессора. А в случае кооперативной многозадачности, мы можем не дождаться, что поток нам даст управление т.к. он должен делать это вручную, и при этом может простаивать. В случае с HT и SMT работает простой принцип если конвеер процессора простаивает происходит автоматические переключение на симметричный поток. Для понимания его принципа работы 99% людей этого более чем достаточно. Это все есть на картинке, где показан принцип работы. Могу предположить, что еще предсказание переходов лучше работает при HT и SMT, и отсюда тоже чуть лучше будет производительность. Если человек не занимается слишком низкоуровневым программирование, и низкоуровневой оптимизацией кода или производством процессоров, глубже нет смысла углубляться.

>> ссылок нет, вполне логичная интерпретация.
@nullc0de жаль, только Intel о "логичности этой интерпретации" не знает.

А не знает об этом Intel потому, что она неправильная (тем более, в ситуации, сервера, когда потоков больше, чем доступных процессорных ядер - у нас же ведь больше, иначе вы бы статью не писали, а просто Hyper Threading отключили бы).

Если у вас 1 аппаратный поток исполниния, на 1 процессорное ядро и каждый thread работает по 100мс, то на этом процессорном ядре 10 раз в секунду будет сниматься thread и планироваться следующий.

Если у вас 2 аппаратных потока исполнения, на 1 процессорное ядро (Hyper Threading) - и каждый процесс работает по 100мс, то на каждом из двух аппаратных потоках 10 раз в секунду будет сниматсья логический thread и планироваться новый.

Те же самые результаты (одинаковое время работы логических thread до снятия с процессора) вы получите, если у вас будет 10 аппаратных потоков, 20 аппаратных потоков, если каждый thread в среднем будет работать 50мс, 20мс......

Среднее время работы логического thread до снятия с процессора не зависит от наличия heper threading (разумеется в предположении, что логических thread у нас больше, чем потоков исполнения предоставленных железом).

Поэтому да инженерная чаксть у вас вполне крутая, но по теоретической - поправьте пожалуйста и не вводите людей в заблуждение.

WASD1 спасибо за ваше гениальное разъяснение претендующее на нобелевскую премию. Процессор не работает в категориях миллисекунд, он работает в категории тактов и инструкций процессора. Вы еще пытаетесь переложить ситуацию со 100% загрузкой процессора, на задачи, когда один поток уснул и работает другой поток. При 100% загрузке нет никакого преимущества и RT задачах тоже. И вы читали статью не внимательно, мною было сделано замечание на эту тему в статье. Читайте на здоровье www.cs.unc.edu/~anderson/papers/ecrts19d.pdf

>> Процессор не работает в категориях миллисекунд, он работает в категории тактов и инструкций процессора.
Процитируйте где я написал, что процессор работает в категориях миллисекунд (или опять "ссылки нет, но интерпретация логичная").
И да в ситуации с HT/без HT "число инструкций за 1 квант времени" - изменяется очень сильно. Если вы об этом не знаете, или не понимаете, что измерять надо в сравнимых величинах - спросили бы, я бы вам объяснил (Intel давал цифру +30% производительности per Core при включении HT).


>> Вы еще пытаетесь переложить ситуацию со 100% загрузкой процессора, на задачи, когда один поток уснул и работает другой поток. При 100% загрузке нет никакого преимущества и RT задачах тоже.
Когда один поток уснул, то он снимется с процессора и произойдёт переключение контекста. Что при включении HT, что без включения HT.

Есть эффекты второго порядка (почему число переключений контекста может быть ниже или выше на любую разумную метрику).
Но для начала неплохо бы разобраться с основным эффектом: почему в gorss-подсчёте число переключений контекста (на поток исполнения процессора) не снижается.

По HT выше куча объяснений — и все неправильные :).
Ну то есть на очень высоком уровне все верно — HT нужен чтобы улучшить использование функциональных блоков CPU за счет паралеллизма. Но реализация работает не за счет того что «один поток использует fpu а другой alu».

Идей там на самом деле две. Первая — это то что память работает намного медленнее чем CPU. Если процесс полез в память а с кэшем нам не повезло, то он может довольно долго ждать пока эти данные подгрузятся в кэш. Соответственно пока один поток ждет данные из памяти — второй может гонять вычисления на CPU.

Вторая идея — это понятие зависимостей по данным. В этом случае исходных данных для запуска команды нет просто потому что их еще не вычислили. Например наивное суммирование массива: sum = sum + x[i]. Чтобы добавить в эту сумму i-е число надо вначале вычислить сумму с i-1м. Даже если это делать за такт (а в реальных CPU это зачастую занимает дольше) то мы будем по 1 числу за такт добавлять в сумму, а ALU у нас штуки 3. Зависимости по данным мешают полностью загружать исполнительные блоки процессора, тут-то на сцену и выходит HT который позволяет эти «незагруженные» ALU нагрузить вычислениями из второго потока.

Современные видеокарты, кстати, работают по родственным принципам, только там не пара потоков в HT а сразу пара сотен. Выкидываем из процессора все сложные фишки типа out-of-order execution и ставим кучу ALU, после чего используем HT в громадных масштабах.
Зарегистрируйтесь на Хабре, чтобы оставить комментарий