Performance Engineering NEW
Practice writing fast software. Learn to do it right.
400 $/місяць
вт / пт, 18:30 (UTC+3)
старт:
4 серп. 2026 р.
// 31 заняття, 3 місяці
400 $/місяць
вт / пт, 18:30 (UTC+3)

про курс
Більшість проблем перформансу живе не в алгоритмах. Корінь глибше — в тому, як код виконується на реальному CPU та GPU: промахи кешу, невдале розміщення даних у пам'яті, хибні передбачення branch predictor, зайві алокації, перемикання між потоками чи простої в очікуванні ядра ОС. Кожен із цих факторів з'їдає мікросекунди, які складаються у відчутні затримки. Звідси парадокси, що ламають інтуїцію: O(n) програє O(n²), HashMap на мільйони записів поступається sorted array із binary search, а два потоки працюють повільніше за один.
І саме тут починаються по-справжньому цікаві інженерні задачі — особливо зараз, коли частоти процесорів не ростуть, пам'ять відстає від CPU, а залізо більше не пробачає неакуратних рішень. Як прискорити hot loop у 10 разів, не змінюючи алгоритму? Як написати memory allocator, швидший за malloc на вашому workload? Як зрозуміти, що насправді робить ваш код, коли профайлер показує дивне? Цей курс — про розв'язання таких задач: від рівня бітів і байтів до операційних систем, через практику і вимірювання, а не оглядову теорію. Принцип один: не вгадувати — міряти, не «підкручувати» — пояснювати, формувати власну модель того, що відбувається під капотом.
Для middle та senior інженерів, які працюють або хочуть працювати там, де performance — не nice to have, а базова вимога: infrastructure, backend core, databases, machine learning systems, high-frequency trading.
Навчальний план
буде гаряче
ДЛЯ ІНЖЕНЕРІВ
CPU і вартість коду — від аналізу до оптимізацій
Навчимось бачити, де втрачаються наносекунди і як це свідомо виправляти.
• Напишемо власну віртуальну машину: 256 байт памʼяті, 3 регістри, fetch-decode-execute цикл. Після цього JVM, CPython і V8 перестануть бути магією.
• Ієрархія latency операцій і як переписати hot loop з урахуванням цих фактів
• Back-of-envelope estimations: як за 30 секунд на папері сказати, чи встигне алгоритм за секунду. Приклади співбесід у Google та Jane Street
• Техніки, якими інженери Facebook, Twitter і HFT-компаній прискорюють продакшн-код у 100 разів — і як застосувати їх у своєму коді
• Розбір performance-катастроф: regex, що поклав Cloudflare; hash flooding як DoS-вектор проти PHP/Java/Node; Java String у циклі, що робить O(N²)
Cache — чому правильний memory layout важливіший за алгоритм
Два однакові цикли по пам'яті. Перший — у 50 разів швидший. Різниця — в одному рядку.
• Розберемо game engine та прискоримо реальний код у 6–10 разів, не змінюючи алгоритм — тільки через те, як дані лежать у пам'яті
• Cache-friendly алгоритми і структури даних: loop tiling для матриць, B-tree замість red-black tree в базах даних, flat_hash_map замість std::unordered_map
• Інструменти, якими вимірюють cache performance: perf stat на L1-cache-load-misses, cachegrind через valgrind, інтерпретація cg_annotate.
• Кеш операційної системи та вплив на реалізацію File I/O
• Чому ООП з розкиданими полями програє Data-Oriented Design: AoS vs SoA, hot/cold splitting, structure packing
A Bit about Bytes — як дані представлені в памʼяті і чому це має значення
0.1 + 0.2 != 0.3. Це не баг Python — це IEEE 754. Розберемось, чому.
• Variable-length int у Protobuf: як економити 75% байтів на типових даних
• IEEE 754 з нуля: sign, exponent, significand. Зрозуміємо, чому float-и не розподілені рівномірно на числовій осі, і чому фінансові розрахунки ніколи не ведуться у float
• Two's complement: чому -128 і +127 живуть у тому самому байті, і як одне правило «інверт + 1» замінює всю логіку віднімання
• UTF-8 зсередини: закодуємо € у три байти руками, зрозуміємо, чому Twitter рахує grapheme clusters, а не code points
• Розрізняти data / code / stack / heap сегменти просто подивившись на адресу вказівника — і розуміти, звідки береться segfault ще до того, як його кинули
• Bitmap-індекси в БД: як PostgreSQL і ClickHouse відповідають на WHERE gender='M' AND country='UA' швидше за B-tree — і напишемо свій
• Bit hacks, що реально застосовуються в продакшні: popcount для Redis-фільтрів, перевірка степеня двійки без циклів, вирівнювання адрес без умовних переходів
• Endianness на практиці: чому той самий файл, записаний на x86 і прочитаний на ARM, ламається — і як з цим живуть мережеві протоколи
Memory — від malloc до garbage collector
Аллокатор, GC, arena — напишемо все руками. Після цього new і malloc стануть кодом, який ви знаєте зсередини.
• Напишемо власний memory allocator через mmap: header, freelist, first-fit стратегія — і зрозуміємо, чому jemalloc у Facebook і tcmalloc у Google переможуть system malloc на їхніх workload'ах
• Напишемо власний mark & sweep garbage collector
• Stack vs Heap: як працюють push/pop/call/ret на рівні assembly, чому функція не може повернути pointer на локальну змінну, і звідки береться stack overflow на глибокій рекурсії
• Alignment і padding: чому struct { char; int; char; } займає 12 байт замість 6, як правильний порядок полів економить 40% пам'яті, і що процесор робить з unaligned access
Low-level оптимізації — компілятор, асемблер і залізо
Компілятор робить за вас багато. Але іноді він не може — і тоді потрібно розуміти, що відбувається рівнем нижче.
• Instruction-Level Parallelism на практиці: чому процесор може виконувати 4 інструкції за такт
• Як loop unrolling піднімає швидкодію коду
• SIMD через AVX/SSE: як одна інструкція обробляє 8 float-ів замість одного
• Branch prediction зсередини: чому невгадана if-гілка коштує 15–20 циклів, і коли варто переписувати if як branch-free arithmetic
• Reverse engineering: 6 фаз зашифрованого бінарника, які треба розкодувати через gdb і дизасемблер, читаючи x86-64 assembly й розуміючи, що компілятор згенерував з вашого коду
Операційна система — абстракції, за які ви платите
ОС дає зручний інтерфейс: файли, процеси, памʼять. Але кожен syscall — це перемикання контексту. Кожна абстракція — це overhead. Їх розуміння — це різниця між "працює" та "працює швидко".
• Virtual Memory і Page Tables зсередини: як адреса з вашого процесу перетворюється на фізичну через TLB і 4-рівневі таблиці, і чому mov [rax] іноді коштує 100+ циклів
• System calls і context switches: чому один getpid() — це 100 наносекун д, і як vDSO дозволяє обходити ядро для частих викликів
• Page faults як джерело latency spike'ів: чому ваш сервіс раптом даватиме p99 у 10× гірше після запуску GC або після fork(), і як це діагностувати через perf
Процеси — ізоляція, координація, комунікація
Напишемо свій shell з нуля. Після цього ls | grep | wc перестане бути магією командного рядка і стане трьома процесами, трьома pipe, одним парентом.
• Реалізуємо власний shell на C: parsing команд, fork + exec, pipe, redirects
• Fork і exec зсередини: чому саме дві системні функції, а не одна spawn(), і як copy-on-write робить fork() дешевим, поки ви не почнете писати в пам'ять
• IPC на практиці: pipe для потокової передачі, Unix socket для структурованих повідомлень, shared memory для максимальної швидкості — коли вибирати що
Multithreading та Concurrency — від потоків до Event Loop
"Додай потоків" — це не стратегія оптимізації. Це початок нового класу проблем: race conditions, deadlocks, priority inversion, starvation. Конкурентність — це окрема дисципліна, де кожне рішення має trade-off між throughput, latency та correctness.
• Threads vs Processes vs Coroutines: як кожна модель розв'язує одну й ту саму задачу по-різному, і чому Node.js на одному потоці обганяє Apache на тисячі
• False sharing — баг, через який два потоки повільніші за один, хоча не діляться жодною змінною. Як знайти через perf c2c і виправити через alignas(64)
• MESI зсередини: як чотири ядра процесора синхронізують кеш
• Напишемо Thread pool та виправимо багато конкурентних багів
читає
буде гаряче
ДЛЯ ІНЖЕНЕРІВ

Іван Петрушенко
Engineering Lead y @SQUAD, Founder в @CS Osvita.
Former: @Dell Software Engineer, @Fiverr Senior Software Engineer, @Ring Machine Learning Engineer.