Параллельное программирование, процессоры и кэши: беседуют Кэйвон и Кунле
Обучаясь на четвёртом курсе в Стэнфорде*, я записался на практикум по параллельному программированию. Разобравшись с алгоритмами, структурами данных и математическим фундаментом нейросетей, я неожиданно осознал, что имею весьма смутное представление о внутреннем устройстве микропроцессоров. Мне захотелось детально погрузиться в компьютерную архитектуру, чтобы лучше понимать принципы работы «железа», на базе которого создаётся современный софт и которым мы пользуемся ежедневно.
Преподавательский состав оказался поистине выдающимся: Кэйвон Фатахалиан — признанный авторитет в сфере графических вычислений и оптимизации производительности, а Кунле Олукотун — легендарный пионер многоядерных процессоров.
Зачем это нужно?
Если говорить кратко — ради максимальной производительности и сокращения издержек, включая финансовые. В эпоху расцвета прикладного искусственного интеллекта вопросы аппаратной архитектуры всё чаще привлекают внимание разработчиков, поскольку именно вычислительные мощности и энергоэффективность сегодня выступают главным узким горлышком (bottleneck).
Предлагаю сначала разобрать более сложные и злободневные темы, а затем вернуться к базису, который держится на трёх китах: 1. специализация аппаратного обеспечения; 2. центральные процессоры (CPU); 3. кэш-память и механизмы обеспечения её когерентности.
1. Специализация железа
С учётом колоссальных инвестиций в индустрию ИИ, даже минимизация энергопотребления и задержек при серверном инференсе (например, при обработке запросов голосовыми помощниками) имеет критическое значение. Поскольку работа нейросети на этапе инференса — это не что иное, как гигантский массив последовательных линейных и нелинейных преобразований (о чём я подробно расскажу в материалах по курсам CS224N об обработке естественного языка и MATH104 по прикладной теории матриц), рынок наводнили специализированные чипы, заточенные именно под ИИ-вычисления.
Закон Деннарда перестал действовать в период с 2005 по 2007 год: простое уплотнение транзисторов в рамках одного процессорного ядра больше не приводит к линейному росту производительности из-за критического перегрева и проблем с теплоотводом. Именно поэтому в игру вступает следующее фундаментальное соотношение:
В условиях жестких физических ограничений по энергопотреблению единственный путь к росту быстродействия (например, ускорению отклика голосовых интерфейсов) лежит через повышение энергоэффективности. В этом и заключается суть аппаратной специализации. Но на чём именно удается сэкономить?
Специализированные процессоры ориентированы на массово-параллельные арифметические вычисления. На обычном CPU теоретически можно как обучать нейросети, так и запускать их инференс, но это сопоставимо с попыткой построить мегаполис с помощью детской пластиковой лопатки — процесс будет катастрофически медленным. (В студенческие годы мне доводилось обучать сетки на CPU, однако тогда речь шла о совсем иных масштабах моделей.)

Приведённая выше схема демонстрирует, что на арифметические инструкции в CPU (которые и составляют основу компьютерных вычислений) уходит всего 6% (!) потребляемой энергии. В специализированных чипах этот показатель существенно выше. Каковы же обратные стороны такого подхода?

Чем уже специализация микросхемы (правая часть графика), тем более ограниченный класс задач она способна эффективно решать. Главная сложность кроется не столько в написании кода, сколько в экономической целесообразности: узкая специализация оправдана лишь при колоссальных объемах однотипных вычислений — например, матричных трансформаций при инференсе нейросетей. Ниже представлен фрагмент кода на Spatial (предметно-ориентированном языке для проектирования аппаратных ускорителей, расположенном на третьем месте слева на графике):

(Кстати, рекомендую познавательный видеоролик о массовом выпуске полупроводников: https://youtu.be/zyr-I9PdIac?si=FF_BIWIVzxUZB_tS.)
Теперь обратимся к универсальным процессорам из левой части схемы.
2. CPU
Современные персональные компьютеры и мобильные гаджеты по-прежнему базируются на центральных процессорах (CPU). Львиная доля программного обеспечения, создаваемого разработчиками на этой платформе, исполняется именно на них. Из каких базовых элементов они состоят?

Базовая архитектура включает три главных компонента: 1. Управляющий блок (Control Unit, выделен оранжевым), координирующий подачу инструкций на арифметическое устройство (для операций сложения, умножения и т.д.); 2. Арифметико-логическое устройство (ALU, жёлтого цвета), выполняющее непосредственные расчёты; 3. Регистры (синие блоки) — сверхбыструю оперативную память для временного хранения обрабатываемых данных и команд. В свою очередь, каждый из этих модулей построен на мириадах микроскопических транзисторов.
Архитектура процессоров бывает весьма вариативной. Например, в параллельных системах вычисления могут распределяться между несколькими ALU одновременно (не путать с программной многопоточностью), при этом результаты записываются в единое адресное пространство и кэши, о которых пойдет речь далее.

3. Кэш-память и протоколы когерентности
Тема кэширования стала одной из самых увлекательных в рамках курса CS149.
Кэш представляет собой буфер для временного хранения данных, занимающий промежуточное положение между регистрами и основной памятью. Будучи элементом аппаратной реализации, он никак не влияет на логическую корректность выполнения программ, однако критически важен для производительности. Подобно специализированным чипам, кэши экономят колоссальные объемы ресурсов: процессорное время, электроэнергию и пропускную способность шины данных.
Напомним классическую иерархию памяти компьютера — от наиболее миниатюрных и быстрых накопителей к объемным и медленным:
Регистры → Кэш-память → Оперативная память → Накопитель (диск)
Типичный микропроцессор оснащен несколькими уровнями кэша. Возникает закономерный вопрос: как предотвратить появление противоречивых данных при параллельной работе с несколькими кэшами?
Эту задачу решают протоколы когерентности, обеспечивающие их синхронизацию. Каждый контроллер кэша реагирует на операции чтения и записи процессора, а также на служебные сообщения от других кэшей согласно определенным правилам. Существует множество подобных протоколов, среди которых классическим примером выступает MESI:

К слову, затронув тему эффективности памяти, нельзя не упомянуть любопытную научную разработку отечественных исследователей из МФТИ: https://mipt.ru/news/mgnovennaya-zagruzka-i-vechnoe-khranenie-v-mfti-sdelali-segnetoelektricheskuyu-pamyat-rekordno-vynos.
Учебный модуль длился десять недель, поэтому уместить весь материал в рамках одной статьи физически невозможно. За кадром остались такие темы, как векторные расширения SIMD, модели ISPC/SPMD, архитектура графических процессоров и CUDA, механизмы примитивов синхронизации и транзакционная память. Каждое из этих направлений заслуживает отдельного глубокого изучения!
* Внесён в перечень иностранных и международных организаций, деятельность которых признана нежелательной на территории РФ.
OpenAI раскрыла новые случаи побега ИИ-агентов после расследования взлома Hugging Face
SpaceX продлит работу спорных газовых турбин на год ради строительства электростанции на 1,2 ГВт
Десять математических прорывов в одном релизе: OpenAI представила возможности новой модели Astra
Samsung прогнозирует нехватку памяти вплоть до 2028 года
Snapdragon 8 Elite превосходит Apple A19 Pro и будущие чипы, но требует башенного кулера
Одиночная планка DDR5 в игровом ПК оказалась лучше связки из двух модулей DDR4
Нейробиологи обнаружили двойной механизм восприятия времени, распределенный по разным зонам мозга
Марсоход Curiosity запечатлел на Марсе 6-метровый останцовый «остров», сформированный миллионами лет эрозии