Можете ли вы объяснить, как работают компьютеры, начиная с самого низа?


Чтобы понять компьютеры, вы должны сначала принять физическую реальность. Внутри компьютера нет никакой магии. Только электрические сигналы. Если быть точнее, только высокое и низкое напряжение.

Основной материал для чипов, которые мы используем сегодня, — кремний. Кремний — это полупроводник. Полупроводники обладают физическим свойством: легируя их различными элементами и контролируя напряжение на электроде, можно управлять их проводимостью. Эта крошечная структура, которую можно включать и выключать электричеством, называется транзистором.

Современные процессоры содержат десятки миллиардов транзисторов. Текущий 3-нанометровый техпроцесс TSMC означает, что эти транзисторы изготавливаются настолько невероятно маленькими, что десятки миллиардов помещаются на кусочке кремния размером с ноготь.

Вам нужно запомнить только одну ключевую функцию транзистора. Если подать на его управляющий вывод высокое напряжение, он проводит. Если подать низкое напряжение, он закрывается. Это фундаментальная физическая реальность. Высокое напряжение мы определяем как логическую 1, низкое — как логический 0. Вся информатика построена на этих двух состояниях.

Имея транзисторы, мы можем комбинировать их в логические вентили.

Предположим, мы соединили два транзистора последовательно. Ток может течь от одного конца к другому — выдавая на выходе 1 — только когда на оба управляющих вывода подано высокое напряжение, то есть оба входа равны 1. Если хотя бы один равен 0, ток прерывается и на выходе 0. Эта физическая схема называется вентилем И.

По той же логике, если два транзистора соединены параллельно, ток течет — выдавая на выходе 1 — пока хотя бы один вход равен 1. Только когда оба равны 0, на выходе 0. Это вентиль ИЛИ.

Используя немного другой способ соединения, когда подача 1 дает на выходе 0, а подача 0 дает на выходе 1, мы создаем вентиль НЕ.

С вентилями И, ИЛИ и НЕ физический мир официально входит в математический мир. Я настоятельно рекомендую классический учебник под названием Code Чарльза Петцольда. В этой книге нет воды — она начинается с телеграфа и объясняет, как соединять логические вентили. Она идеально подходит для построения того первого слоя физической интуиции. Прочтите её после этого поста — она просто взорвет вам мозг.

Теперь, когда у нас есть логические вентили, как заставить компьютер складывать?

В двоичной системе 1 плюс 1 равно 10. Это означает, что текущий бит становится 0, и мы переносим 1 в следующий разряд. На самом деле это две логические операции. Первая: определить текущий бит. Если оба входа равны 1, текущий бит равен 0. Если один вход 1, а другой 0, текущий бит равен 1. Эту логику можно реализовать, комбинируя базовые вентили — мы называем это вентилем XOR. Вторая: определить перенос. Перенос происходит только когда оба входа равны 1, что в точности соответствует функции вентиля И.

Соедините вентиль XOR и вентиль И — и вы физически реализовали сложение одного двоичного разряда. Это называется полусумматором. Соедините несколько полусумматоров каскадно, обрабатывая сигнал переноса, и вы получите полный сумматор. Если соединить 64 таких полных сумматора, вы получите физическую схему, способную складывать 64-разрядные двоичные числа.

Когда вы пишете строку кода a = b + c, на самом нижнем уровне происходит следующее: электрические сигналы, представляющие b и c, одновременно устремляются в эту схему сумматора, состоящую из десятков тысяч транзисторов. После чрезвычайно короткой физической задержки на другом конце схемы появляются стабильные высокие и низкие напряжения, представляющие результат.

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

Но умение только складывать бесполезно. Результат — всего лишь набор электрических сигналов: как только питание отключается или входные данные меняются, результат исчезает. Компьютер должен уметь запоминать данные. Это подводит нас к памяти и регистрам.

Как использовать электрические сигналы для запоминания состояния? Инженеры-электронщики изобрели чрезвычайно остроумную схему, называемую триггером. Это схема на логических вентилях с обратной связью. Проще говоря, выходной сигнал подается обратно на вход. Такая конструкция позволяет схеме сохранять текущее состояние высокого или низкого напряжения за счет внутренней обратной связи, даже после удаления исходного входного сигнала.

Когда вы подаете на этот триггер определенный сигнал записи, он обновляет свое внутреннее состояние и фиксирует его. Пока вы не подадите другой сигнал записи, он будет бесконечно долго хранить этот 0 или 1.

Расположите 64 триггера в ряд — и вы сможете хранить 64-разрядное двоичное число. Внутри процессора, прямо рядом с АЛУ, эти сверхбыстрые запоминающие устройства, сделанные из триггеров, называются регистрами. Их физическое расположение находится непосредственно рядом с вычислительной схемой, поэтому электрический сигнал проходит кратчайшее возможное расстояние, что делает их чрезвычайно быстрыми. Конечно, они также чрезвычайно дороги в производстве, поэтому могут быть только очень маленькими.

Здесь я должен настоятельно порекомендовать абсолютно легендарную книгу: Computer Systems: A Programmer’s Perspective, более известную в IT-кругах как CSAPP. Это учебник Университета Карнеги-Меллона. Его невероятность в том, что он устраняет разрыв между языком ассемблера, аппаратной архитектурой и операционными системами. Поняв его, вы будете знать, почему один код выполняется быстро, а другой медленно — потому что вы начнете писать код, мысля на физическом уровне.

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

Более 1 миллиона загрузок по всему интернету — основы информатики, которые мгновенно поднимут ваши навыки.

Продолжим движение наружу. Что если регистров недостаточно? Нам нужно больше памяти. Здесь вступают в дело планки оперативной памяти, вставленные в вашу материнскую плату. Техническое название — динамическая память с произвольным доступом, DRAM.

Физический принцип DRAM полностью отличается от регистров. Вместо триггеров она использует крошечные конденсаторы для хранения электрического заряда. Конденсатор с зарядом — это 1, без заряда — 0. Поскольку структура конденсатора чрезвычайно проста — для хранения одного бита данных нужен только один транзистор и один конденсатор — емкость может быть очень большой. Сегодня десятки или даже сотни гигабайт обычное дело.

Но у конденсаторов есть фатальный недостаток: они теряют заряд. Если их не трогать, заряд, представляющий 1, полностью утекает за несколько миллисекунд, превращаясь в 0. Поэтому на материнской плате должна быть специальная управляющая схема, которая считывает данные из памяти и перезаряжает их через чрезвычайно короткие промежутки времени. Это называется динамическим обновлением. Вот почему, когда вы отключаете компьютер от питания, все в памяти мгновенно исчезает.

Теперь у нас есть АЛУ, которое может выполнять вычисления, и регистры с памятью, которые могут хранить данные. Ключевой вопрос: как эти неодушевленные вещи начинают двигаться? Кто командует им сначала сложить, потом умножить и наконец сохранить результат?

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

На материнской плате есть кварцевый генератор — кристалл кварца, который генерирует импульсный сигнал фиксированной частоты, пока подано питание. Например, если ваш процессор имеет тактовую частоту 4,0 ГГц, это означает, что этот кристалл генерирует 4 миллиарда переходов от высокого к низкому напряжению каждую секунду.

Это сердцебиение компьютера. Все логические вентили и триггеры внутри процессора работают в строгой синхронизации с этим сердцебиением.

Внутри процессора есть очень специальный регистр, называемый счетчиком команд. Он содержит только адрес памяти.

Когда раздается первый удар сердцебиения, процессор делает первое дело: выборку инструкции. Он отправляет адрес, хранящийся в счетчике команд, в память через металлические дорожки на материнской плате. Память отправляет обратно длинную строку из 0 и 1, хранящуюся по этому адресу.

Эта длинная строка из 0 и 1 и есть инструкция. Когда инструкция возвращается в процессор, она поступает в устройство управления. Устройство управления — это тоже просто набор жестко соединенных логических вентилей, его задача — декодирование. Например, когда оно видит, что первые несколько цифр поступивших 0 и 1 равны 1011, его внутренняя структура соединений определяет, что эти высокие и низкие напряжения активируют именно переключатель, ведущий к схеме сложения в АЛУ. В то же время остальная часть инструкции указывает, в каких регистрах находятся два значения данных для сложения.

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

На следующем ударе результат записывается обратно в указанный регистр.

Наконец, счетчик команд автоматически увеличивается на единицу, указывая на следующую инструкцию в памяти. Затем цикл повторяется. Миллиарды раз в секунду.

Это вся правда о том, как работает компьютер на самом нижнем уровне. Нет никакого продвинутого интеллекта — только кварцевый генератор, слепо отбивающий такты, счетчик команд, механически увеличивающий адреса, устройство управления, роботизированно переключающее пути сигналов в соответствии с прочитанными 0 и 1, и АЛУ, пассивно преобразующее входящие уровни напряжения в новые уровни напряжения.

Код Python или Java, который вы пишете в своей повседневной работе, в конечном итоге транслируется программой, называемой компилятором, в длинную, утомительную последовательность машинных инструкций, специфичных для архитектуры процессора — чистые 0 и 1.

На этом этапе вы на самом деле прошли всю цепочку от песка (кремния) до программы. Многие люди чувствуют, что поняли на этом этапе, но в реальной индустриальной среде сегодня простое понимание традиционных принципов работы процессора не дотягивает даже до проходного балла.

Учитывая текущую горячую тему больших моделей ИИ, я должен расширить ваш кругозор. Давайте посмотрим, как на самом деле выглядит ландшафт вычислительных мощностей сегодня.

Любая команда, работающая сегодня с большими моделями, будь то обучение или инференс, абсолютно не может использовать CPU для вычислений. Почему?

Потому что CPU спроектированы для обработки сложного логического управления. Посмотрите на процессор: большая часть его площади отведена под предсказание ветвлений, управление кэшем и устройство управления. Часть, фактически используемая для чистых числовых вычислений — АЛУ — не так велика. Это как если бы CPU был высокообразованным интеллектуалом, преуспевающим в сложных управленческих процессах. Попросите его вычислить 1+1, он сможет, и даже, возможно, проанализирует, нет ли ошибки — но он может обрабатывать только несколько за раз.

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

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

Чтобы действительно понять, что на самом деле вычисляют большие модели, если ваша математическая интуиция все еще основана на заученных формулах, я настоятельно рекомендую вам посмотреть “Суть линейной алгебры” от 3Blue1Brown. Для облегчения повторения и вывода вы можете использовать этот сборник заметок 3Blue1Brown на китайском и английском языках. Он действительно достигает интуитивной визуализации продвинутого умножения матриц и линейных преобразований. После просмотра у вас появится реальная физическая мысленная картина операций умножения-накопления для тысяч и тысяч параметров.

Заметки по линейной алгебре от 3Blue1Brown: Возможно, лучший китайско-английский сборник в интернете

Природа этих массивных матричных вычислений породила GPU, графический процессор — который теперь следует называть универсальным параллельным вычислительным блоком.

Философия дизайна GPU полностью противоположна CPU. Она отсекает большую часть сложных управляющих схем и больших кэшей, заполняя каждый бит освободившегося физического пространства простейшими АЛУ. Текущий чип NVIDIA H100 содержит десятки тысяч вычислительных ядер. Хотя каждое ядро может работать на более низкой частоте, чем ядро CPU, и имеет слабую логику управления, все они могут работать одновременно.

Представьте себе GPU как строй из 100 000 школьников, умеющих только складывать и умножать. Вы даете им чрезвычайно простую команду: умножьте число слева от вас на число справа от вас. Все 100 000 школьников одновременно вычисляют результат на одном такте. Для массово параллельных матричных операций, необходимых для больших моделей, GPU в сотни и тысячи раз эффективнее CPU.

На самом деле ИИ — как и сумматор в CPU — вовсе не так таинственен. Это все еще просто слой за слоем логики и матриц. Если вы хотите с нуля построить свое понимание глубокого обучения, я рекомендую книгу, которую многие в Twitter хвалят за полное развенчание магии ИИ: Deep Learning with Python. Когда вы сами разберетесь в тензорных вычислениях прямого и обратного распространения, вы поймете, что внутри больших моделей тоже нет никакой магии.

После прочтения этой книги я полностью разочаровался в магии ИИ!

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

Потому что АЛУ вычисляет очень быстро. Как упоминалось ранее, модули памяти хранят данные, заряжая и разряжая конденсаторы, и они находятся на некотором физическом расстоянии от CPU или GPU — электрическим сигналам требуется время, чтобы пройти по материнской плате. Самая большая проблема, с которой сталкиваются сегодня чипы ИИ, — это то, что в научных кругах называют фоннеймановским узким местом.

То есть: тысячи вычислительных ядер за долю секунды обрабатывают имеющиеся данные, а затем им остается только простаивать в ожидании, пока новые данные будут перенесены из медленной памяти. Даже если вы сделаете вычислительные схемы на чипе быстрее, если вы не сможете подавать данные достаточно быстро, вычислительная мощность будет потрачена впустую.

Чтобы решить эту проблему, инженеры по аппаратному обеспечению были доведены до крайности. Поскольку обычные модули памяти слишком далеки и медленны, почему бы не упаковать память и чип GPU непосредственно на одной подложке? Чтобы увеличить ширину канала для передачи данных, вместо традиционных проводов они используют технологию, называемую кремниевыми интерпозерами — сверлят тысячи микроскопических проводящих отверстий внутри кремния для прямого соединения памяти и вычислительных ядер. Это то, что разрекламировали до небес как высокопропускную память, HBM.

Если эта часть вас глубоко увлекает и вы хотите получить незаменимую высокооплачиваемую должность архитектора или низкоуровневого разработчика в грядущую эпоху ИИ, я настоятельно рекомендую вам взяться за Computer Architecture: A Quantitative Approach. Эта книга написана двумя лауреатами премии Тьюринга, и почти каждый аппаратный инженер в Кремниевой долине имеет ее экземпляр. Она использует огромное количество реальных данных и формул, чтобы объяснить, почему чипы должны проектироваться с определенными архитектурами кэша и где именно находятся узкие места в многоядерном параллелизме. Хотя ее невероятно сухо читать, и некоторые главы очень трудны, это необходимый путь для преодоления когнитивного разрыва в низкоуровневом понимании.

Вернемся к вашему первоначальному вопросу. Почему вы все еще чувствуете замешательство после изучения всех этих терминов? Потому что традиционное обучение разрывает живую связь между физическими объектами и логическими абстракциями.

Когда вы рассматриваете CPU как волшебный черный ящик, эти термины кажутся непостижимыми определениями. Но если вы проследите за физическими законами снизу вверх:

  • Поскольку высокое и низкое напряжение могут образовывать логические вентили, мы получили арифметические устройства, которые могут выполнять вычисления.
  • Поскольку схемы с обратной связью могут фиксировать состояния напряжения, мы получили регистры, которые могут хранить данные.
  • Поскольку нам нужно было ритмично управлять потоком электрических сигналов, мы получили кварцевые генераторы и устройства управления.
  • Поскольку эта система слишком сложна для прямого ввода уровней напряжения человеком, мы изобрели наборы инструкций, упаковав 0 и 1 в язык ассемблера, а затем в C и Python.

Как практик, прошедший через окопы этой индустрии, я могу ответственно заявить: в нашу эпоху фронтенд-фреймворки приходят и уходят, бэкенд-микросервисные архитектуры процветают несколько лет, и даже архитектуры больших ИИ-моделей итерируются с головокружительной скоростью. Многие высокоуровневые техники разработки приложений, которые вы учите сегодня, могут устареть в следующем году. Фактически, большие модели уже могут выполнять многие базовые задачи кодирования лучше, чем средний программист.

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

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