Що робить непрацездатний процес процесора?


73

Подивившись на джерело, straceя знайшов використання прапора-клона, CLONE_IDLETASKякий описується як:

#define CLONE_IDLETASK 0x00001000 /* kernel-only flag */

Заглянувши в нього глибше, я виявив, що, хоча цей прапор не висвітлений, man cloneвін фактично використовується ядром під час завантажувального процесу для створення непрацюючих процесів (у всіх яких повинен бути PID 0) для кожного процесора на машині. тобто машина з 8 процесорами матиме щонайменше 7 (див. питання нижче) такі процеси "працюють" (примітки).

Тепер це призводить мене до пари запитань про те, що насправді робить цей "непрацюючий" процес. Моє припущення полягає в тому, що воно виконує операцію NOP постійно, поки не закінчується її часовий проміжок, і ядро ​​призначає реальний процес для запуску або призначення режиму очікування ще раз (якщо ЦП не використовується). І все-таки, це повна здогадка. Тому:

  1. На машині з, скажімо, 8 процесорами буде створено 7 таких непрацюючих процесів? (і один процесор буде утримуватися самим ядром, поки робота з робочим простором користувача не працює?)

  2. Чи справді непрацюючий процес є лише нескінченним потоком операцій NOP? (або цикл, який робить те саме).

  3. Чи використання процесора (скажімо uptime) просто обчислюється тим, наскільки тривалий час роботи в режимі очікування на процесорі та скільки часу його не було протягом певного періоду часу?


PS Цілком ймовірно, що велика частина цього питання пов'язана з тим, що я не повністю розумію, як працює ЦП. тобто я розумію складання, часові рамки та переривання, але я не знаю, як, наприклад, процесор може використовувати більше або менше енергії залежно від того, що він виконує. Буду вдячний, якщо хтось може просвітити і мене.


17
Мені довелося протистояти спокусі просто написати «Нічого», коли побачив заголовок.
Vality

4
Більшість сучасних процесорів динамічно знижуватиме тактову частоту та енергоспоживання під час роботи на холостому ходу або під малим навантаженням ( динамічне масштабування частоти , наприклад, SpeedStep для процесорів Intel). Якщо розігнати центральний процесор, він зазвичай відключає цю поведінку, внаслідок чого процесор підтримуватиме максимальну тактову частоту навіть у режимі очікування.
Нат

2
Дивіться також "Стани живлення ACPI": Є різні способи, за допомогою яких процесор може припинити виконання інструкцій, але все ще залишається неспальним.
pjc50

Відповіді:


85

Завдання в режимі очікування використовується для обліку процесів, а також для зменшення споживання енергії. В Linux створюється одна неробоча задача для кожного процесора і блокується на цьому процесорі; всякий раз, коли на цьому процесорі немає жодного іншого процесу, завдання в режимі очікування планується. Час, витрачений на завдання в режимі очікування, відображається як "час простою" в таких інструментах, як top. (Пробіг обчислюється по-різному.)

Здається, Unix завжди мав певний цикл холостого ходу (але це не обов'язково фактичне завдання в режимі очікування, див . Відповідь Гілла ), і навіть у V1 він використовував WAITінструкцію, яка зупиняла процесор, поки не відбулося переривання (воно позначало "зачекайте на перервати »). Деякі інші операційні системи, зокрема, використовували цикли зайнятості, DOS, OS / 2 та ранні версії Windows. Вже досить давно центральні процесори використовували таку інструкцію "чекати", щоб зменшити споживання енергії та теплопродукції. Ви можете бачити різні реалізації непрацюючих завдань, наприклад, в arch/x86/kernel/process.cядрі Linux: основна лише викликаєHLT, Який зупиняє процесор , поки не відбудеться переривання (і дозволяє C1 режим економії енергії), інші реалізації обробки різних помилок або неефективності ( наприклад , використовуючи MWAITзамість того , HLTна деяких процесорах).

Все це повністю відокремлено від режимів очікування в процесах, коли вони чекають події (введення / виведення тощо).


3
Хе, я бачу це зараз, дякую. play_dead()це дуже приємна мнемонічна назва для виконання HALT. Чи не було б ризику надіслати HALT до кожного процесора і, отже, повісити? (тобто досягти цієї ситуації. HALT кожен процесор буде помилкою в ядрі правильно?)
grochmal

30
Процесор прокидається від HALT через переривання.
Йохан Мірен

1
@ JohanMyréen - Класно, це має сенс. У такому випадку навіть переривання IRQ від пристрою введення викликає резервне копіювання. Дякую.
грочмал

15
Або, більш надійно, таймер перериває ... (Без галочки - це ще один чайник риби.)
Стівен Кітт

3
@EJP дійсно, це досить поширена інструкція, хоча вона має різні назви в різних архітектурах.
immibis

50

У дизайні підручника планувальника процесів, якщо у планувальника немає жодного процесу для планування (тобто якщо всі процеси заблоковані, очікуючи на введення), тоді планувальник чекає перерви процесора. Переривання може вказувати на вхід з периферійного пристрою (дія користувача, мережевий пакет, завершене зчитування з диска тощо) або може бути переривом таймера, який запускає таймер у процесі.

Планувальник Linux не має спеціального коду для випадків, коли нічого не потрібно робити. Натомість він кодує справу, що нічого не робиться, як особливий процес, неробочий процес. Процес простою планується лише тоді, коли жоден інший процес не планується (він фактично має нескінченно низький пріоритет). Процес очікування насправді є частиною ядра: це нитка ядра, тобто потік, який виконує код у ядрі, а не код у процесі. (Точніше, є одна така нитка для кожного процесора.) Коли запущений процес запуску, він виконує операцію очікування на переривання.

Як працює режим очікування на перерву, залежить від можливостей процесора. З найпростішим дизайном процесора, це просто зайнятий цикл -

nothing:
    goto nothing

Процесор постійно продовжує виконувати інструкцію гілки, яка нічого не досягає. Більшість сучасних ОС не роблять цього, якщо вони не працюють на процесорі, де немає нічого кращого, а більшість процесорів мають щось краще. Замість того, щоб витрачати енергію, не роблячи нічого, крім обігріву приміщення, в ідеалі процесор слід вимкнути. Таким чином, ядро ​​запускає код, який наказує процесору самому вимикатися або принаймні вимикати більшу частину процесора. Повинно бути принаймні одна невелика частина, яка залишається включеною, контролер переривання. Коли периферія викликає перерву, контролер переривання надсилає сигнал пробудження до основної (частини) процесора.

На практиці сучасні процесори, такі як Intel / AMD і ARM, мають безліч складних налаштувань управління потужністю. ОС може оцінити, скільки часу процесор буде перебувати в режимі очікування і вибере різні режими низької потужності залежно від цього. Режими пропонують різні компроміси між енергоспоживанням у режимі очікування та часом, необхідним для входу та виходу з режиму очікування. У деяких процесорах ОС також може знизити тактову частоту процесора, коли виявить, що процеси не вимагають багато процесорного часу.


5
Зауважте, що навіть самі основні вбудовані процесори, такі як мікроконтролери на основі AVR, мають інструкцію WFI (Wait For Interrupt), хоча ця інструкція може бути еквівалентною NOP залежно від конкретної моделі.
Йонас Шефер

@JonasWielicki Я думав, що ти зазвичай просто перейдеш у тугий цикл, якщо нічого робити не можеш, або ти можеш перейти в стан з низькою потужністю і чекати, коли перерва тебе виб'є з нього (стан низької потужності зазвичай вимагає більше " метал "перебиває".
Нік Т

1
@JonasWielicki Архітектури, розроблені для вбудованих систем, дбають про управління енергією, тому WFI тут важливий. У багатьох старих архітектурах такого немає. Оригінальна архітектура 8086 не зробила AFAIR. У 68k є WFI? Це стандартна функція на MIPS? Моє знайомство з програмуванням низького рівня здебільшого стосується ARM, де низьке споживання енергії - це звичайно, а WFI - лише вершина айсберга управління потужністю.
Жиль

1
@Gilles 8086 мав інструкцію щодо зупинки. Дивіться en.m.wikipedia.org/wiki/HLT_(x86_instruction) Інструкція включала функціональність енергозбереження лише з 80486 DX4. Повернувшись до історії, HLT вже був у 8080 р. Та похідними (як Z80).
pabouk

1
@pabouk HLTможе вимкнути варіанти SL 386 та 486, перш ніж вийшов DX4 (стаття у Вікіпедії невірна).
Стівен Кітт

0

Ні, незадіяне завдання не витрачає цикли процесора. Планувальник просто не вибирає непрацюючий процес для виконання. Процес очікування очікує, що відбудеться якась подія, щоб вона могла продовжуватися. Наприклад, він може чекати введення в read()системний виклик.

До речі, ядро ​​- це не окремий процес. Код ядра завжди виконується в контексті процесу (ну, за винятком спеціального випадку потоку ядра), тому сказати "невірно", і одне ЦП буде утримуватися самим ядром, поки робота з простором користувача не виконуватиметься ".


3
Гммм ... я не думаю, що це такий процес простою, який створюється CLONE_IDLETASK. Якби це тоді, його взагалі не потрібно було б створювати, тобто, якщо планувальник ігнорував процеси ядра в режимі очікування на процесорах, він не потребував би створювати для них жодних процесів під час завантаження. (DW не моя :))
grochmal

Трохи гугл виявляє, що CLONE_IDLETASK - внутрішній прапор, який був введений навколо ядра версії 2.5.14 у 2002 році та пізніше видалений у 2004 році.
Йохан Мірен

«ЕН» простоює процес , але не « » простоює процес.
іммібіс
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.