Железо и архитектуры От ламп до кристалла: как физика формировала архитектуру
0%

От ламп до кристалла: как физика формировала архитектуру

От ламп до кристалла: как физика формировала архитектуру

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

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

Где эта глава начинается. Обзорный уровень — что такое вентиль, как устроен процессор, зачем нужна иерархия памяти — уже разобран в треке «Основы Computer Science»: булева логика и вентили, как работает процессор, иерархия памяти и путь от кода к исполнению. Здесь мы не повторяем это, а спрашиваем другое: почему процессор устроен именно так, откуда взялись регистры, кэш, байт, конвейер и почему их не могло быть раньше. Дальше по треку мы разбираем каждый механизм в деталях — конвейер, внеочередное исполнение, подсистему памяти — а эта глава даёт причинную рамку, в которую они укладываются.

Дисциплина обращения с числами

Прежде чем что-либо считать, одно предупреждение, которое действует на весь трек. Числа в железе бессмысленны без указания класса устройства и поколения. «Латентность L1 — 4 такта» верно для десктопных ядер x86 примерно 2015–2025 годов и неверно для микроконтроллера, серверного ядра с большим L1 или GPU. «Тактовая частота 3 ГГц» — это про ядро общего назначения в системе с активным охлаждением, а не про носимую электронику.

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

Карта эпох

Обратите внимание на последнюю строку: это единственная эпоха, где вместо «стало быстрее» написано «стало иначе». Разбор того, почему так вышло, — «Мощность и пределы»; здесь мы доходим до момента перелома и объясняем его физику.

Эпохи не сменяли друг друга щелчком — они перекрывались на годы и десятилетия, и это важно: новая технология сначала была дороже старой и выигрывала только там, где критичны были габариты или надёжность.

Реле: когда бит стоит как деталь машины

Первые универсальные программируемые машины — немецкая Z3 Конрада Цузе (1941) и американская Harvard Mark I (1944) — были построены на электромеханических реле. Реле — это управляемый ключ: ток в катушке притягивает якорь, якорь замыкает контакт. Физика диктует всё остальное: механическое движение занимает порядка единиц миллисекунд, значит такт машины — единицы герц, а контакты изнашиваются механически.

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

  • Состояния минимум. Никаких регистровых файлов: одно-два рабочих места для чисел, всё остальное — в медленной памяти или на носителе.
  • Программа живёт вне машины. У Z3 программа читалась с перфоленты, у Mark I — с бумажной ленты. Машина не могла посмотреть на свою программу как на данные, а значит не могла её менять; условные переходы в Z3 в исходном виде отсутствовали.

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

Лампа: в тысячу раз быстрее и в сто раз капризнее

Электронная лампа переключает поток электронов в вакууме, а не кусок металла: подогретый катод испускает электроны, сетка полем управляет их потоком на анод. Механики нет — есть микросекунды вместо миллисекунд. Такт ламповых машин поднялся до десятков и сотен килогерц (для ENIAC — порядка сотни килогерц).

Цена этого скачка — та самая физика:

  • Катод надо греть. Каждая лампа потребляет несколько ватт постоянно, независимо от того, переключается она или нет. ENIAC (1945) с примерно 17–18 тысячами ламп потреблял порядка 150 кВт и занимал зал.
  • Катод выгорает. При тысячах ламп отказ становится штатным событием. Инженеры ENIAC пошли на приёмы, которые сегодня выглядят как надёжностное программирование в железе: отбор ламп по параметрам, работа при пониженном накале, и главное — не выключать машину, потому что большинство отказов происходило при включении из-за теплового удара.

Четыре поколения переключателя и их следствия в архитектуре

Что лампа сделала с системой команд

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

Одноадресная (аккумуляторная) машина. Триггер на лампах — это два-три активных элемента на бит. Сорокаразрядный регистр — под сотню ламп плюс обвязка. Регистровый файл из шестнадцати таких регистров физически не помещался в бюджет. Поэтому машины строились вокруг одного аккумулятора: команда указывала один адрес операнда, второй операнд неявно лежал в аккумуляторе, туда же попадал результат. Команды вида ADD addr — не стилистика, а следствие цены триггера. Регистровые архитектуры, к которым мы привыкли (см. «Основы ассемблера»), появились, когда триггер подешевел.

Последовательная обработка бит за битом. EDSAC и EDVAC были bit-serial: сумматор обрабатывал один разряд за такт, а не все сразу. Параллельный сумматор на 40 разрядов стоил бы в десятки раз больше ламп. Идея «сделать в 40 раз медленнее, но в 40 раз дешевле» — прямой предок сегодняшних решений вида «узкий блок, работающий много тактов, вместо широкого за один такт», которые вы встретите в ускорителях и в дешёвых микроконтроллерных ядрах.

Хранимая программа: экономия, а не изящество

ENIAC программировался коммутацией: переключатели и кабели. Смена задачи занимала дни. В отчёте по проекту EDVAC (июнь 1945, авторство приписано Джону фон Нейману, хотя ключевые идеи вырабатывались вместе с Джоном Эккертом и Джоном Мокли) была зафиксирована другая схема: программа хранится в той же памяти, что и данные, и читается той же логикой.

Это часто подают как философский прорыв «код — это данные». Инженерно же это в первую очередь экономия железа: не нужен отдельный дорогой механизм ввода программы, переконфигурация занимает секунды, а не дни, и одна и та же память используется под всё. Первой работающей машиной с хранимой программой стал Manchester Baby (21 июня 1948), затем EDSAC (1949).

Заодно получилась побочка, с которой мы живём до сих пор: раз команда — это данные, её можно перезаписать, а данные можно исполнить. Вся современная работа по безопасности с неисполняемыми страницами, W^X и подписью кода — это попытка задним числом восстановить границу, которую снесли в 1945 году ради экономии ламп.

Память была узким местом с самого начала

Логика ускорилась, а хранить биты было по-прежнему нечем. Ранние виды памяти — ртутные линии задержки (импульс бежит по трубке со ртутью и переизлучается на входе), трубки Уильямса (заряд на люминофоре ЭЛТ), магнитные барабаны — объединяет одно свойство: доступ последовательный. Слово доступно не тогда, когда оно нужно, а тогда, когда оно «подъедет».

Барабан и оптимальное кодирование — предок cache-aware кода

Магнитный барабан вращается с фиксированной скоростью. Головка читает слово, когда оно проходит мимо. Для машины класса IBM 650 (середина 1950-х) порядки такие: скорость вращения — порядка 12 тысяч оборотов в минуту, то есть оборот занимает порядка 5 мс; на дорожке — порядка полусотни слов, значит одно слово проезжает мимо головки за порядка 100 мкс. Средняя задержка случайного обращения — половина оборота, порядка 2–3 мс.

Теперь ключевой момент. Если разместить команды подряд, то к моменту, когда машина закончила выполнять команду, следующее слово уже уехало — и надо ждать почти полный оборот. Поэтому в командах хранили адрес следующей команды, а программисты (а позже — специальные «оптимизирующие ассемблеры») размещали команды на барабане так, чтобы нужное слово подъезжало ровно к моменту готовности.

Посчитаем эффект — модель занимает десяток строк.

"""Модель барабанной памяти: почему в 1950-х расположение команд
значило больше, чем их количество.

Все величины — в 'словных интервалах' (время прохода одного слова мимо головки).
Для машин класса IBM 650, середина 1950-х, словный интервал — порядка 100 мкс.
"""

TRACK_LEN = 50   # слов на дорожке барабана — порядок величины для той эпохи


def program_time(n_instructions: int, exec_time: int, gap: int,
                 track_len: int = TRACK_LEN) -> int:
    """Время выполнения программы из n команд, разложенных с шагом gap.

    exec_time — сколько словных интервалов занимает сама команда.
    Ожидание — сколько ещё интервалов нужно ждать, пока подъедет следующее слово.
    Сложность: O(n) по времени, O(1) по памяти.
    """
    total = 0
    for _ in range(n_instructions):
        wait = (gap - exec_time) % track_len   # барабан не останавливается
        total += exec_time + wait
    return total


n, exec_time = 1000, 5

naive = program_time(n, exec_time, gap=1)          # команды подряд
optimal = program_time(n, exec_time, gap=exec_time)  # шаг равен времени выполнения

print(f"наивное размещение: {naive} интервалов")    # 51000
print(f"оптимальное:        {optimal} интервалов")  # 5000
print(f"выигрыш:            {naive / optimal:.1f}x")  # 10.2x

Десятикратная разница на одном и том же коде — только от раскладки в памяти. Ничего не напоминает? Это буквально тот же самый механизм, что и в современном коде, чувствительном к кэшу и к предвыборке: сама арифметика бесплатна, платите вы за то, что данные не подъехали вовремя. Разница только в единицах: тогда — миллисекунды оборота, сейчас — сотни тактов до оперативной памяти на десктопных ядрах 2020-х. Практическая сторона разобрана в «Кэш и локальность», а устройство самой иерархии — в «Подсистеме памяти».

Ферритовые сердечники: появляется понятие «оперативная»

Память на магнитных сердечниках (промышленно — с начала 1950-х, машина Whirlwind как ранний носитель идеи) впервые дала произвольный доступ: любое слово за одно и то же время, порядка единиц микросекунд для машин той эпохи. Сердечники были энергонезависимы и достаточно надёжны, чтобы память перестала быть главной болью.

Три следа этого решения:

  1. Слово «core» в core dump — это буквально «сброс содержимого ферритовой памяти».
  2. Разделение «быстрая небольшая память рядом с процессором» и «медленная большая память дальше» стало возможным именно тогда, когда появилась быстрая память с произвольным доступом. До этого делить было нечего.
  3. Чтение сердечника было разрушающим — после чтения значение приходилось записывать обратно. Первая в истории массовая «скрытая работа контроллера памяти», которая полностью повторится в динамической памяти с её регенерацией.

Транзистор: то же самое, но без накала

В декабре 1947 года в Bell Labs Джон Бардин и Уолтер Браттейн получили усиление на точечно-контактном приборе; в 1948 Уильям Шокли описал биполярный плоскостной транзистор (Нобелевская премия — 1956). Физика принципиально другая: управление током идёт в твёрдом теле, а не в вакууме. Отсюда:

  • нет накала — статическое потребление падает на порядки;
  • нет выгорающего катода — время наработки на отказ вырастает на порядки;
  • размер — миллиметры вместо сантиметров.

Второе поколение машин (IBM 7090, PDP-1, BESM-6, CDC 6600 — конец 1950-х и первая половина 1960-х) — это транзисторы, распаянные на платах. Такт поднялся до сотен килогерц и единиц мегагерц, а бюджет элементов вырос с тысяч до десятков тысяч.

Как только элементов стало хватать, архитектура немедленно потратила их на то, чего не могла себе позволить раньше:

Что появилось Какое ограничение отпустило Где это сегодня
Несколько регистров, индексные регистры триггер перестал стоить как деталь машины регистровый файл любого современного ядра
Аппаратная плавающая точка умножитель стал по карману блоки FPU и SIMD (глава 10)
Прерывания стало дёшево хранить и восстанавливать состояние вся модель ввода-вывода и планирования в ОС
Каналы ввода-вывода (автономные процессоры обмена) лишние элементы можно отдать периферии DMA, IOMMU, умные контроллеры
Несколько исполнительных устройств и учёт зависимостей (CDC 6600, 1964) элементов хватило на дублирование арифметики суперскалярность (глава 07)
Виртуальная память (Atlas, 1962) появился запас на трансляцию адресов MMU, TLB, страничная память
Кэш (IBM System/360 Model 85, 1968) разрыв «логика быстрее памяти» стал болезненным вся иерархия кэшей

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

System/360: изобретение слова «архитектура»

1964 год, IBM System/360. С инженерной точки зрения это самое важное событие в списке, и оно не про физику, а про то, как физику упаковать в контракт.

До S/360 каждая новая модель компьютера была новой машиной со своим набором команд: программы переписывались. IBM (команда Джина Амдала, Джералда Блау и Фреда Брукса) сделала ход, который сегодня кажется очевидным: отделила систему команд от способа её реализации. Одна и та же система команд была реализована в дешёвых моделях медленной и простой аппаратурой, а в дорогих — быстрой и сложной. Слово «архитектура» в нашем смысле — из этой работы.

Это и есть та самая идея контракта, которую подробно разбирает «Система команд»: программа видит абстрактную машину, а как эта абстракция реализована — свобода производителя. Без такого разделения не существовало бы ни конвейеров, ни внеочередного исполнения: обе техники меняют способ выполнения, сохраняя видимое поведение.

Микрокод: как дёшево реализовать сложную систему команд

Чтобы одна система команд работала на разном по мощности железе, IBM массово применила микрокод — идею Мориса Уилкса (1951). Вместо того чтобы строить управляющий автомат из случайной логики под каждую команду, в машину ставится небольшая быстрая память (control store), в которой каждая команда разложена в последовательность элементарных шагов.

Экономика микрокода в 1960-х была бесспорной: ПЗУ дешевле и компактнее случайной логики, а сложную команду выгоднее «прошить», чем развести проводами. Именно поэтому эпоха 1960–1970-х дала богатые, сложные системы команд: дороговизна памяти делала плотный код ценным, а микрокод делал сложные команды дешёвыми в реализации. Когда оба этих условия перестали выполняться, маятник качнулся в другую сторону — об этом ниже и подробно в «RISC и CISC».

Байт побеждает: почему именно 8 бит

До S/360 разрядность слова была вопросом вкуса и задачи:

Машина (эпоха) Слово Почему так
IBM 701, 704 (1950-е) 36 бит точность научных расчётов; 6-битные символы укладываются ровно
PDP-8 (1965) 12 бит минимизация стоимости, машина для лаборатории
CDC 6600 (1964) 60 бит максимум точности для суперкомпьютера
IBM System/360 (1964) 32 бита, адресуемый байт 8 бит компромисс между текстом и числами

Восьмибитный байт победил по совокупности причин, и все они инженерные: шесть бит не вмещали строчные буквы вместе с прописными и служебными символами; восемь — степень двойки, что упрощает адресацию и сдвиги; байт делится на две шестнадцатеричные цифры и удобно ложится на десятичную арифметику с упаковкой. Сегодня 8 бит выглядит законом природы, но это выбор 1964 года под текстовые и коммерческие задачи.

Интегральная схема: тирания чисел

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

Решение: делать элементы и соединения сразу вместе, в одном куске материала. Джек Килби (Texas Instruments, 1958) показал работающую схему на одном кристалле германия с навесными перемычками; Роберт Нойс (Fairchild, 1959) на основе планарного процесса Жана Эрни сделал вариант с металлизацией прямо на кристалле — то есть технологически воспроизводимый.

Ранний массовый потребитель ИС — бортовой компьютер Apollo (Apollo Guidance Computer, 1960-е). Его строили на тысячах экземпляров одной-единственной микросхемы — трёхвходового элемента ИЛИ-НЕ. Это чистая иллюстрация принципа: когда критичны масса, объём и надёжность, вы готовы строить всю машину из одного примитива, даже если это неоптимально по числу элементов.

Принцип, который не изменился с тех пор: провода дороже вычислений

Интегральная схема сместила соотношение стоимостей окончательно: транзистор дешевеет быстрее, чем связь между транзисторами. Локальное соединение внутри кристалла почти бесплатно, соединение через весь кристалл — дорого по задержке и энергии, выход за пределы корпуса — дорого во всех смыслах сразу (выводы корпуса, ёмкость, мощность драйверов).

Из одного этого факта выводится половина современного железа:

Запомните этот вывод: он объясняет и SIMD, и ускорители, и то, почему оптимизация памяти даёт больше, чем оптимизация арифметики.

Два закона, которые постоянно путают

Гордон Мур в статье 1965 года (Cramming more components onto integrated circuits, журнал Electronics, текст доступен в архиве IEEE) заметил: число элементов на кристалле при минимальной стоимости на элемент удваивается примерно ежегодно; в 1975 он скорректировал период до примерно двух лет. Это экономическое наблюдение, а не закон физики: оно про то, сколько выгодно поместить на кристалл, и оно всегда включало в себя ожидания рынка и объёмы инвестиций.

Совсем другое утверждение — масштабирование Деннарда (Роберт Деннард и соавторы, 1974, статья о проектировании MOSFET с малыми размерами). Оно гласит: если уменьшить все геометрические размеры транзистора в k раз и одновременно снизить напряжение питания в k раз, то напряжённость поля останется прежней, задержка уменьшится в k раз, а плотность мощности останется постоянной.

Вот отсюда и брался «бесплатный обед» 1975–2004 годов. Динамическая мощность переключения примерно равна

P_dyn ≈ α · C · V² · f

где α — доля переключающихся элементов за такт, C — ёмкость, V — напряжение питания, f — частота. При масштабировании C падает, V падает, f растёт — и произведение остаётся примерно тем же на единицу площади. Каждое новое поколение техпроцесса давало и больше транзисторов, и выше частоту, и то же тепловыделение.

"""Почему до ~2004 частота росла бесплатно, а потом перестала.
Модель качественная: показывает соотношения, а не абсолютные ватты."""


def dyn_power(cap: float, volt: float, freq: float, alpha: float = 0.15) -> float:
    """Динамическая мощность переключения в условных единицах."""
    return alpha * cap * volt ** 2 * freq


# Эпоха масштабирования Деннарда: размеры и напряжение падают вместе.
# Возьмём шаг уменьшения размеров k ≈ 1.43 (транзисторов на площади становится вдвое больше).
base = dyn_power(cap=1.0, volt=5.0, freq=1.0)
scaled = dyn_power(cap=0.7, volt=3.5, freq=1.43)     # C и V вниз, f вверх
print(f"мощность одного транзистора: {scaled / base:.2f} от прежней")  # ~0.49

# Транзисторов на той же площади стало вдвое больше — значит мощность
# на квадратный миллиметр осталась прежней. Это и есть 'бесплатный обед'.
print(f"плотность мощности: {2 * scaled / base:.2f} от прежней")       # ~0.98

# После ~2004: напряжение упёрлось (порог открытия транзистора не масштабируется),
# поднять частоту можно только подняв напряжение — а оно входит в квадрате
stuck_v = dyn_power(cap=0.7, volt=1.0, freq=3.0)
push_f = dyn_power(cap=0.7, volt=1.2, freq=4.0)     # +33% частоты
print(f"рост мощности за +33% частоты: {push_f / stuck_v:.2f}x")  # ~1.92x

Почему напряжение перестало снижаться — это уже чистая физика полупроводника. Транзистор открывается, когда напряжение на затворе превышает пороговое. Крутизна перехода из закрытого состояния в открытое ограничена термодинамикой: при комнатной температуре подпороговый наклон не может быть лучше примерно 60 мВ на декаду тока. Значит, снижая пороговое напряжение, вы экспоненциально увеличиваете ток утечки закрытого транзистора — и то, что вы сэкономили на переключениях, вытекает статически. К середине 2000-х утечки стали сопоставимы с динамической мощностью, и снижать напряжение стало нельзя.

Что перестало расти около 2005 года и что выросло вместо этого

Итог перелома: закон Мура ещё некоторое время продолжал работать (транзисторов на кристалле становилось больше), а масштабирование Деннарда закончилось. Транзисторы есть, но запитать их все одновременно нельзя — это явление называют «тёмным кремнием». Дальше архитектуре осталось три хода, и все три мы разбираем в этом треке: больше ядер (глава 11), шире данные на одну команду (глава 10), специализированные блоки под конкретные задачи (глава 12).

Микропроцессор: как корпус на 16 выводов определил систему команд

Intel 4004 (1971) обычно вспоминают как «первый микропроцессор». Для нашего разговора он интереснее другим — это самый наглядный пример того, как упаковка формирует архитектуру.

Порядки величин: около 2300 транзисторов, технология порядка 10 мкм, рабочая частота — сотни килогерц. Разрядность — 4 бита. Почему четыре? Не потому, что кому-то нравились полубайты, а потому, что чип должен был поместиться в корпус на 16 выводов — стандартный и дешёвый на тот момент. Шестнадцати ножек не хватает на отдельные шины адреса и данных, поэтому шина сделана мультиплексированной: по одним и тем же четырём линиям в разные такты передаётся то адрес, то данные, то команда.

Схема причинности здесь абсолютно прямая:

  • дешёвый корпус → мало выводов;
  • мало выводов → узкая мультиплексированная шина;
  • узкая шина → многотактный доступ к памяти;
  • многотактный доступ → система команд, экономящая обращения к памяти.

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

8086 и сегменты: обход ограничения, ставший наследием

Intel 8086 (1978) — 16-разрядная машина, которой нужно было адресовать больше 64 КБ. Решение: адрес формируется как сегмент, сдвинутый на 4 бита, плюс смещение — получается 20-битный физический адрес при 16-битных регистрах. Это был разумный обход ограничения своего времени.

Дальше произошло то, что происходит с любым удачным обходом: он стал обязательным для совместимости. Сегментные регистры пережили десятилетия, реальный режим до сих пор существует в x86-совместимых процессорах, и до сих пор процессор, включаясь, оказывается в режиме, в котором он умеет притворяться машиной 1978 года — прежде чем загрузчик переведёт его в защищённый и затем в длинный режим (подробности со стороны системного ПО — в «Процессе загрузки»).

Это универсальное свойство систем команд: они накапливают историю, потому что стоимость несовместимости платит не тот, кто проектирует железо. Сравнение моделей x86, ARM и RISC-V с этой точки зрения — тема пятой главы; там же обсуждается, что означает возможность строить систему команд без наследственного балласта.

Скорость света становится архитектурным фактором

Есть ограничение, которое не смягчается никаким техпроцессом. За одну наносекунду свет проходит около 30 см в вакууме, а сигнал в проводнике на плате — порядка 15–20 см. Пока такт машины — микросекунды, это неважно. Когда такт становится наносекундой (частота 1 ГГц), это становится главным.

Следствия, которые видны в железе:

  • В суперкомпьютерах 1970-х (машины линии Cray) провода подрезали по длине, а корпус делали компактным именно для сокращения задержек распространения. Знаменитая «С-образная» компоновка — не дизайн, а укорачивание проводов.
  • На современных ядрах при частоте единиц гигагерц сигнал за такт успевает пройти лишь несколько сантиметров, а с учётом ёмкости проводников на кристалле — существенно меньше. Пересечь большой кристалл за один такт невозможно, поэтому в конвейере появляются такты, потраченные только на передачу данных между удалёнными блоками.
  • Отсюда же архитектурная норма: большие структуры (кэш последнего уровня, межъядерная сеть) проектируются как распределённые с несколькими тактами задержки, а не как один быстрый блок.

Именно это ограничение делает бессмысленной идею «сделать одно очень большое и очень быстрое ядро»: за его размер придётся платить задержками внутри самого ядра.

2004: точка, где кончилась одна эпоха и началась текущая

К началу 2000-х отрасль шла по инерции «выше частота — выше производительность». Проекты сверхглубоких конвейеров с прицелом на очень высокие частоты столкнулись с двумя стенами одновременно: тепловой (плотность мощности перестала быть постоянной) и конвейерной (при глубоком конвейере цена ошибки предсказания перехода растёт, см. главу 08). Около 2004–2005 годов планы на дальнейший рост частоты в массовых процессорах были свёрнуты, и вся отрасль развернулась к многоядерности.

Что это означало для программиста — переход, который до сих пор не закончился: производительность перестала расти сама. Однопоточный код, который в 1995–2004 годах ускорялся просто оттого, что вы купили новую машину, с середины 2000-х перестал ускоряться существенно. Отсюда весь современный интерес к параллелизму, к моделям памяти (глава 11) и к аккуратной работе с кэшем.

Полезно видеть все три ограничения вместе, потому что архитектура сегодня — это балансирование между ними:

Стена В чём суть Архитектурный ответ
Стена памяти логика ускорялась быстрее памяти с 1960-х иерархия кэшей, предвыборка, много потоков для сокрытия задержки
Стена мощности плотность мощности перестала быть постоянной (~2005) ограничение частоты, управление питанием, гетерогенные ядра
Стена параллелизма параллелизм на уровне команд в одном потоке ограничен явный параллелизм: потоки, векторы, ускорители

Открытая система команд как продолжение той же логики

История, изложенная выше, объясняет и то, почему в 2010-х появился RISC-V. Когда система команд — это контракт (идея S/360), а реализация — свобода производителя, возникает вопрос: кому принадлежит контракт? Полвека ответ был «компании, которая его придумала», и это означало, что построить процессор можно, только договорившись с владельцем.

Проект RISC-V начался в Калифорнийском университете в Беркли около 2010 года именно как попытка сделать контракт общедоступным и, что не менее важно, модульным: небольшое обязательное ядро набора команд плюс независимые расширения. Насколько это меняет расстановку сил, где такой подход реально работает, а где пока нет, и чем модель RISC-V отличается от моделей ARM и x86 — разбирается в «RISC-V: открытая система команд». Здесь важно только зафиксировать причинную связь: открытая система команд стала осмысленной ровно тогда, когда проектирование кристалла подешевело относительно проектирования системы команд и её экосистемы.

Окаменелости, которые видны на вашей машине прямо сейчас

История в железе — не абстракция. Её можно посмотреть командами.

# Разрядность, порядок байт, размеры кэшей — контракт, унаследованный из 1960-1980-х
lscpu | grep -Ei 'architecture|byte order|cpu\(s\)|mhz|l1d|l1i|l2|l3'

# Микрокод — идея Уилкса 1951 года, живая и обновляемая на лету
grep -m1 microcode /proc/cpuinfo
dmesg 2>/dev/null | grep -i 'microcode' | head -3

# Расширения системы команд как археологические слои:
# mmx (1997) -> sse (1999) -> avx (2011) -> avx512 (2010-е) — каждое поколение
# добавляло ширину, не ломая совместимость
grep -m1 -o 'flags.*' /proc/cpuinfo | tr ' ' '\n' | grep -E '^(mmx|sse|sse2|avx|avx2|avx512f)$'

# Топология: сколько физических ядер и сколько потоков на ядро.
# Само существование этой строки — прямое следствие остановки роста частоты
lscpu | grep -Ei 'thread|core|socket'

# На машине с RISC-V вывод будет riscv64, и это уже другая ветка истории
uname -m

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

Со стороны системного ПО те же окаменелости видны как режимы процессора при загрузке и как модель памяти ядра — это разбирается в треке про операционные системы (память, загрузка). Со стороны микроконтроллеров — как крайне консервативные архитектуры, живущие под теми же ограничениями, что и мейнфреймы 1960-х, только по другой причине (цена и энергия, а не технология): см. «Основы железа» в треке embedded.

Типичные заблуждения

«Лампы были медленные». Наоборот: лампа переключается за микросекунды, это в тысячу раз быстрее реле. Медленными ламповые машины делала не лампа, а память и последовательная (побитовая) обработка, выбранная ради экономии ламп.

«Закон Мура — закон физики». Это наблюдение об экономике производства. Оно не гарантировало ни роста частоты, ни роста производительности — только рост числа элементов на кристалле при минимальной стоимости элемента. Рост частоты давало масштабирование Деннарда, и оно закончилось на десятилетие раньше.

«Частота — мера производительности». Частота — это темп тактов, а не работы. Работа за такт зависит от того, сколько команд ядро выпускает за такт, сколько времени оно стоит в ожидании памяти и насколько удачно предсказаны переходы. Сравнивать процессоры по частоте можно только внутри одной микроархитектуры, и даже там с оговорками — подробнее в «Выборе железа под задачу».

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

«RISC победил CISC» или наоборот. Ни то ни другое: изменилась экономика, и обе линии сдвинулись навстречу. Что именно сдвинулось — тема четвёртой главы.

«Историческое наследие можно просто выбросить». Совместимость — это не сентиментальность, а экономика: стоимость переписывания софта обычно превышает выигрыш от чистой архитектуры. Наследие уходит только вместе с рынком, на котором оно было нужно.

Мини-итог

  • Архитектура на каждом этапе оптимизировалась под соотношение стоимостей: цена переключателя, его энергия, его скорость и надёжность связей между переключателями.
  • Реле дали двоичность (двухпозиционный элемент), лампы — аккумуляторную одноадресную модель и побитовую обработку (элементов мало), транзисторы — регистры, прерывания и параллельные блоки (элементов много).
  • Хранимая программа была в первую очередь способом сэкономить железо; её побочный эффект — стирание границы между кодом и данными — мы до сих пор чиним средствами защиты памяти.
  • Последовательный доступ ранней памяти породил оптимизацию раскладки под задержку. Ровно эта же дисциплина сегодня называется работой с кэшем.
  • System/360 отделила систему команд от реализации. Без этого контракта не было бы ни конвейеров, ни внеочередного исполнения, ни возможности выпускать разные по мощности процессоры с одной системой команд.
  • Интегральная схема закрепила главный современный принцип: вычислять дёшево, перемещать данные дорого.
  • Закон Мура и масштабирование Деннарда — разные утверждения. Второе кончилось около 2004–2006 годов, и именно поэтому частота больше не растёт, а производительность берут параллелизмом и специализацией.
  • Каждое число в железе имеет смысл только с указанием класса устройства и поколения.

Источники

  • Nathan Ensmenger, Thomas Haigh, Paul Ceruzzi. A New History of Modern Computing. MIT Press — современная академическая история отрасли без мифологии.
  • John Hennessy, David Patterson. Computer Architecture: A Quantitative Approach — приложения к книге содержат исторический разбор каждого механизма и ссылки на первоисточники.
  • Gordon Moore. Cramming more components onto integrated circuits, Electronics, 1965 — скан оригинала в Computer History Museum.
  • Robert Dennard et al. Design of Ion-Implanted MOSFET’s with Very Small Physical Dimensions, IEEE JSSC, 1974 — страница статьи в IEEE Xplore.
  • Gene Amdahl, Gerrit Blaauw, Frederick Brooks. Architecture of the IBM System/360, IBM Journal of R&D, 1964 — текст на сайте IBM Research.
  • Maurice Wilkes. The Best Way to Design an Automatic Calculating Machine, 1951 — первоисточник идеи микрокода.
  • Computer History Museum — коллекция материалов по ранним машинам, включая документацию ENIAC, EDSAC и IBM 650.
  • Архив документации DEC и IBM на bitsavers.org — оригинальные руководства, где видно, как формулировались архитектурные контракты своего времени.

Что дальше

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

Транзистор и вентиль: что происходит под булевой логикой

Нашли неточность? Выделите фрагмент текста — рядом появится жучок.

Нужен разбор именно вашей ситуации?

Статья описывает общий случай. Если у вас частный — можно разобрать его отдельно, платно. А если не хватает целого материала, предложите тему: её оплачивают вскладчину, и она выходит открытой для всех.

Доска запросов