Машина на глиняних ногах
4 / 18

Розділ 3. Стіна на 5 ГГц

Коротка історія одного провалу

У 2000 році Intel запустила архітектуру Netburst. Це була не просто нова лінійка процесорів — це була ставка на майбутнє на десять років уперед. Intel публічно заявила: Pentium 4 спроектований так, щоб дійти до 10 гігагерц до 2010 року.

Головний архітектор Netburst, Патрік Ґелсінгер (той самий, який зараз CEO Intel), пояснював на конференціях: ми зробили “довгий конвеєр” — двадцять, потім тридцять один ступінь — щоб кожна інструкція розбивалася на дуже прості мікрокроки. Тому кожен крок можна виконати дуже швидко. Тому тактова частота може рости майже безмежно.

На папері це звучало геніально.

На практиці — процесор досяг 3.8 ГГц у 2004 році і зупинився. Останній Pentium 4 (Prescott, потім Cedar Mill) так і не пройшов 4 ГГц. Intel анонсувала наступник — “Tejas” — на 4 ГГц. Навесні 2004-го скасувала його повністю. Вдарила об стіну.

У вересні 2005-го Intel офіційно кинула Netburst і повернулася до архітектури старого, непомітного, низькоклокованого Pentium III, розвинутого командою в Ізраїлі. Ця архітектура стала основою Core, Core 2 Duo, і, по прямій лінії спадковості, усіх сучасних процесорів Intel. Усі інновації останніх двадцяти років Intel — це продовження гілки Pentium III, а не Pentium 4.

Чому Netburst не вистрілив? Через три фундаментальні стіни, у які він врізався одночасно.

Стіна перша: потужність

Існує просте фізичне рівняння, яке знає кожен інженер-електронник:

P = C ⋅ V2 ⋅ f

Де: - P — потужність, яку чіп розсіює у вигляді тепла, - C — ємність (майже постійна для даного чіпа), - V — напруга живлення, - f — тактова частота.

Що означає це рівняння практично? Коли ти подвоюєш частоту, ти подвоюєш потужність. Подвоїти ще раз — учетверо.

У 1990-х це не було проблемою, бо одночасно з ростом частоти напругу V знижували (і вона у квадраті!). Від 5 В у 80386 до 1.5 В у Pentium III. Зниження напруги давало змогу нарощувати частоту “безкоштовно” за теплом.

Але нижче 1 В знизити вже неможливо — транзистори перестають розрізняти 0 і 1. Ти просто не можеш мати надійний перемикач, який працює на 0.5 В, бо теплові флуктуації починають робити переключення випадковими.

І як тільки V не може падати далі, рівняння безжально розвертається. Частота росте — потужність росте квадратично швидше за те, що ти отримуєш.

До Pentium 4 типовий настільний процесор розсіював 20-30 Вт. Pentium 4 Prescott розсіював 115 Вт. “Tejas”, за внутрішніми оцінками Intel, мав би розсіювати 150+ Вт на площі в кілька квадратних сантиметрів. Це приблизно як прасувати кремнієвим кристалом — щільність потужності підходила до щільності атомного реактора.

Охолодити це було можливо. Але: - Вентилятори стали гучні як пилосос. - Радіатори виявились більші за сам процесор. - Ноутбуки з такими чіпами обпалювали коліна. - У датацентрах вартість електрики і охолодження почала перевищувати вартість самих серверів.

Це і була стіна потужності (power wall). У певний момент подальше нарощення частоти перестало мати економічний сенс, навіть якби було фізично можливим.

Стіна друга: швидкість світла

Цей аргумент звучить як жарт, але він дуже реальний.

Візьми частоту 5 ГГц. За один період цього такту (0.2 наносекунди) світло у вакуумі пролітає 6 сантиметрів. Електричний сигнал у кремнії — повільніший, приблизно 3 сантиметри.

Тепер подивись на сучасний процесор. Його кристал — 10×10 міліметрів, або навіть 20×30 міліметрів для серверних монстрів. Це означає, що сигнал не встигає пройти з одного кінця чіпа в інший за один такт. Він потребує двох, трьох, навіть десяти тактів, щоб дійти.

Це фундаментальне обмеження, яке не можна обійти. Ейнштейн поставив його у 1905-му. Швидкість передачі інформації не може перевищувати швидкість світла.

Практичні наслідки: - Процесор не може бути великим. Уже сьогодні архітектори мусять робити чіпи “територіально розподіленими” — блоки, які спілкуються асинхронно, бо синхронно не встигають. - Тактову частоту не можна сильно підвищити, бо тоді сигналу треба буде ще більше тактів на проходження. - Кеші на чіпі мусять бути ближче до ядра — звідси L1, L2, L3, ієрархія, про яку ми поговоримо у наступному розділі.

Уявімо, що ми хочемо процесор на 20 ГГц. За один такт сигнал пройде 1.5 см. Щоб цей процесор мав сенс, його ядро має міститись в цих 1.5 см, а це означає мікроскопічне ядро з крихітним кешем. На практиці — непрактично.

Коротко: швидкість світла поставила стелю, в яку ми вперлися. Десь на ~6-8 ГГц ми будемо, мабуть, назавжди.

Стіна третя: паралелізм у серійному коді

Третя стіна — найтонша, найконцептуальніша, і найважливіша для програміста.

У 1990-х процесори навчилися хитрої штуки: виконувати інструкції не за порядком (out-of-order execution). Якщо ти написав:

A = B + C
D = E + F
G = A + D

Процесор бачить: перші дві інструкції незалежні, їх можна виконати паралельно. Третя залежить від обох. Отже, він виконує першу і другу одночасно, а потім третю.

Це називається паралелізм на рівні інструкцій (ILP — Instruction Level Parallelism). Pentium Pro у 1995-му був першим чіпом Intel, який робив це серйозно. Наступні двадцять років процесори вчилися виконувати все більше і більше інструкцій паралельно. Сучасний Apple M3 може виконувати до восьми інструкцій одночасно в одному ядрі.

Але.

Є фундаментальна межа. Середній серійний код (той, що ти пишеш у C, Python, Java) містить приблизно три-чотири незалежні інструкції на кожну серію залежних. Процесор може видобути з нього 3-4× прискорення через ILP — і все. Більше там немає. Код занадто послідовний.

Це стіна не фізична, а інформаційна. Вона закладена в мові програмування, у стилі мислення, у звичках. Ти пишеш step1(); step2(); step3(); — а потім дивуєшся, чому 100-ядерний сервер не робить це у сто разів швидше.

Єдиний спосіб обійти цю стіну — явно писати паралельний код. Розбивати задачу на частини, які можуть виконуватись одночасно на різних ядрах. І тут уже вступає в дію інший закон, такий самий невблаганний, як закон світла.

Закон Амдала

Ґене Амдал — інженер IBM, архітектор System/360, один з основоположників комп’ютерної архітектури. У 1967 році він сформулював простий, але жорстокий принцип:

Якщо частина програми серійна (не може бути розпаралелена) і становить долю s, то максимальне прискорення, яке ти можеш отримати від будь-якої кількості процесорів, дорівнює 1/s.

Тобто: - Якщо 10% твого коду серійні — максимум прискорення 10 разів. Навіть на мільйоні процесорів. - Якщо 1% серійний — максимум 100 разів. - Якщо 0.1% серійний — максимум 1000 разів.

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

А це надзвичайно важко. Людина думає послідовно. Програміст за природою пише послідовний код. Паралельний код — це не просто “інший синтаксис”, це інший спосіб думати про задачу. І він повний пасток: deadlock (два процеси чекають один на одного вічно), race condition (два процеси змінюють те саме і результат залежить від того, хто першим встиг), false sharing (два процеси працюють із “різними” змінними, які випадково лежать в одному кеш-рядку, і тому постійно б’ються), тощо.

Статистика: у середньому, помилок у паралельному коді в десять-двадцять разів більше, ніж у послідовному. І вони в десять разів важче відтворюються у налагодженні.

“Вільний обід закінчився”

Герб Саттер написав у березні 2005 року статтю з пророчою назвою: “The Free Lunch Is Over: A Fundamental Turn Toward Concurrency in Software”.

Він писав: “Протягом тридцяти років програмісти насолоджувались безкоштовним обідом. Щороку ми писали той самий код, і щороку він ставав швидшим, бо процесори ставали швидшими. Цей час скінчився. Відтепер ти або навчишся писати паралельний код, або залишишся на 2005-му році продуктивності назавжди”.

Стаття стала маніфестом. За наступні п’ятнадцять років індустрія намагалася відповісти на неї: - Нові мови програмування, де паралелізм вбудований у ядро — Go з горутинами, Rust з моделлю володіння, Erlang зі своїми акторами (існував із 1980-х, але раптом став модним). - Бібліотеки паралельного виконання — OpenMP, Intel TBB, Microsoft PPL. - GPU-обчислення — коли з’ясувалось, що графічні прискорювачі, спроектовані для паралельної обробки пікселів, чудово підходять і для інших задач. CUDA (2006) дала змогу писати для GPU як для звичайного процесора. Через п’ятнадцять років CUDA стала платформою, на якій виросли всі сучасні LLM. - Функціональне програмування повернулося з академії на продакшн — Scala, Clojure, Elixir, частини Haskell — бо в них паралелізм простіший і безпечніший.

Але фундаментально проблема не розв’язана. Більшість коду, написаного сьогодні, досі послідовна. Більшість програмістів паралельно програмувати не вміють. Ми живемо у двох шарах: залізо масово паралельне (100 ядер в сервері, тисячі в GPU), а код масово послідовний. Розрив між ними — 20 років, і він не скорочується.

Де ми зараз

Нинішній найкращий настільний процесор AMD Ryzen 9 7950X3D працює на базовій частоті 4.2 ГГц, turbo — 5.7 ГГц. Apple M3 Max — базова ~4 ГГц. Серверні Xeon Platinum — 2.5-3.5 ГГц на базі (турбо вище). За 20 років частота майже не змінилася.

Що змінилося? Кількість ядер. 2005 — 2 ядра. 2010 — 4. 2015 — 8. 2020 — 16. 2024 — 96 ядер у одному серверному чіпі AMD EPYC, 192 у двох сокетах. Apple Silicon з Ultra-варіантами має 24-32 ядра. А от GPU: NVIDIA H100 має 18 432 “CUDA cores” (спрощено — маленьких паралельних обчислювачів).

Ми живемо у світі, де обчислювальна потужність росте тільки вшир, тільки через паралелізм. Годинник зупинено назавжди.

Що з цього винести

  1. У 2004 році Intel вдарилася у стіну потужності. Формула P = CV²f не пробачила.
  2. Швидкість світла ставить другу стіну. Сигнал не встигає пройти чіп за один такт, коли частота занадто висока.
  3. Закон Амдала ставить третю: 10% серійного коду — і мільйон ядер тобі не допоможуть.
  4. Програмісти досі живуть у до-2005-му світі. Пишуть серійний код і дивуються, що він не стає швидшим. Вільний обід справді скінчився.
  5. Прогрес тепер йде через паралелізм (більше ядер, GPU), спеціалізацію (AI-прискорювачі), і економію пам’яті (наступна стіна).

Яка ж вона, ця наступна стіна? Вона теж велика. Вона пов’язана з тим, що не тільки процесор зупинився — пам’ять теж не встигає. І коли процесор усе менше чекає на свою інструкцію, але все більше чекає на дані — у гру вступає той самий привид, якого ми зустрінемо у наступному розділі.

Він народився у 1945 році. Він був блискучим. Його звали Джон фон Нейман.