Samara Portal Technology, Computers

Самарский портал "Технологии, компьютеры"

Галопом по вычислительным Европам. Часть 3. Оптимизация.

Сага о голодных птенцах, или Наличные наше всё

Нет, дедушка еще не сошел с ума, просто состояние ядер современных высокопроизводительных процессоров в отношении данных больше всего напоминает состояние вечно голодных птенцов, а наличные — всего лишь буквальный перевод слова cash (cache). Собственно, о кэшировании я и хочу поговорить. Когда компьютеры только появились — все было хорошо. Процессоры (и микро- и еще до того, как они стали микро) работали на одной частоте с памятью и росли они в быстродействии совершенно параллельно. Пока процессор внутри себя десятки и сотни тактов пережевывал команды (помните про IPC/CPI i8086?) — недорогая динамическая PM/FPM память вполне успевала регенерировать заряд в ячейках и была готова к следующему запросу на чтение или запись.

Проблема (в мире PC) возникла с появлением высокопроизводительного (в 3-6 раз быстрее 8086) процессора i286, с раздельными[1] шинами адреса и данных, частота следования запросов к оперативной памяти от которого выросла пропорционально росту производительности и уже превышала возможности системной памяти к обработке запросов — что привело к тому, что исполнение команд новым мощным процессором вынужденно прерывалось на время доставки затребованных данных и выгрузки результатов. Т.е., у нас появляются простои ядра, обусловленные внешними по отношению к процессору причинами. Процессор же i386 с 32-разрядными операндами нанес следующий удар: еще раз удвоил потребление данных. Что делать? Известное дело: подсмотреть у «старших братьев».

Высокопроизводительные системы давным-давно использовали статическую память, вполне успевавшую работать с процессорами такт-в-такт. Но она была дорогой и горячей (подробнее в следующей главе), поэтому просто заменить DRAM на SRAM не получилось. Решение оказалось, как обычно, посередине: между основным объемом DRAM и процессором поместились несколько микросхем[2] SRAM, работавших в качестве промежуточного буфера, позволявшего мгновенное (в каждом такте) повторное чтение попавших в него данных, а при включении режима обратной (отложенной) записи и такую же моментальную запись результата вычислений. И все бы хорошо, но чисто для понимания: когда типичный объем оперативной памяти на PC был 1 мегабайт — кэш (если он был!) имел размер 64 килобайта, редко 128, для систем с процессором i386DX и 4 мегабайтами ОЗУ — 128-256 KB, и то 256 далеко не всегда. Дешевые же компьютеры часто продавались, вообще, с пустыми панельками под микросхемы кэша.

И это несмотря на то, что эффект от наличия кэша был, в некоторых случаях, огромным. Так, некоторая счетная задача, которая на i386/387DX без кэша тратила около пяти минут на итерацию — после установки 256 KB кэша с обратной записью стала делать итерацию расчета за 20-30 секунд, поначалу вызвав у программистов ощущение аварийного завершения (потому что «так быстро не бывает»).

Следующий шаг системам кэширования пришлось сделать с появлением процессоров i486 и Motorola 68040. Почему? Эти появившиеся практически одновременно конкуренты отличались от своих предшественников и большими частотами, и наличием описанного выше конвейерного исполнения команд. С точки зрения требований к пропускной способности и задержкам памяти это означает резкое увеличение нагрузки. Внешний SRAM-кэш начал вносить заметную задержку (в несколько тактов), не успевая исполнять запросы,  и чтобы избежать простоев ядра — эти процессоры получили внутренний сверхскоростной кэш, работающий рядом с ядром и на частоте ядра (кэширование, таким образом, стало многоуровневым[3] — оставшийся на плате стал кэшем второго уровня (L2), а внутренний — первого (L1)). Первоначально размер L1 и у Intel и у Motorola 68040*[4] составлял 8 KB, по 4 KB для данных и команд, а с появлением умножения частоты у процессоров Intel 486DX/2 и Motorola 68060 — размер накристалльного L1 вырос до 16 KB (по 8 для данных и команд). Одновременно для них ввели и отложенную запись, для ускорения исполнения таких запросов, чтобы не пропускать такт при выгрузке результатов. И все заверте[5]

Нет, серьезно, после появления даже того, крохотного по нынешним меркам, накристалльного кэша производительность ядра процессоров стала независимой от остальных систем настолько[6], что стало понятно: найден абсолютно верный путь, позволяющий строить все более и более быстрые процессоры, почти не замечая гири DRAM на ноге. С тех пор кэши на кристаллах только росли.

На самом деле, тут есть фундаментальный конфликт интересов. С одной стороны, чем больше кэш — тем вероятнее найти в нем нужные данные, но с другой стороны — чем он больше, тем медленнее[7] поиск в нем. Конечно, у разных компаний разные успехи в этом (Intel умеет делать очень быстрые, но относительно небольшие кэши, а вот AMD берет объемом, увеличивая процент попаданий), но в целом такое соотношение сохраняется.

Возникла, правда, проблема: чем больше кэш — тем дольше в нем поиск, но с другой стороны — выше вероятность попадания. Пока размеры в 1-4 килобайта это не в счет, а когда уже 16+16 и более — то над дальнейшим увеличением уже надо подумать, что важнее: темп доступа или вероятность попадания/промаха? Потому что поиск-то в кэшах выполняется последовательно, от меньших кэшей к большим. Сначала происходит проверка наименьшего и наибыстрейшего кэша первого уровня (L1), в случае попадания процессор продолжает работу на высокой скорости. Если меньший кэш дал промах (в нем нет нужных данных), проверяется следующий, чуть больший и более медленный кэш второго уровня (L2), и так далее, пока — потерпев две, три, а иногда и четыре неудачи последовательно не будет сформировано запроса к основной памяти.

По мере роста производительности процессоров росли и кэши. В эпоху i486 у PC[8] размер L2 варьировался от 128 KB у дешевых моделей до 512 KB у продвинутых рабочих станций, процессоры Pentium поддерживались уже кэшами размером 256-1024 KB (как правило[9], 512 KB), но время шло, и по мере увеличения коэффициента умножения, L2 работающий на частоте внешней шины справляться перестал (а у высокопроизводительных RISC станций и серверов проблема обозначилась еще раньше[10]). Потребовалось пересматривать всю системную архитектуру. Варианты были разные[11], но победил Intel.

Да, самым красивым стало решение Pentium PRO от Intel. В дополнение к 8+8 KB L1 в корпусе процессора разместился и кристалл с L2, работавший по отдельной шине на полной скорости ядра (соответственно, от 150 до 200 MHz) размер этого L2 варьировался от 256 до 1024 KB, а эффект от увеличения его скорости до частоты ядра был потрясающим: Pentium PRO 166 с полноскоростным L2 на 512 KB обгонял обычный Pentium 166 с 1024 KB внешнего L2 на частоте 66 MHz как стоячего. Чуть лучше выглядел Pentium 166 MMX (L1 у него был 16+16), но тоже[12] — не то! Pentium PRO же с частотой 200 MHz и 1024 KB полноскоростного L2 рвал всех[13]. И, в особенности, кошельки покупателей. На момент выпуска он стоил около 3000 еще тех, тяжелых, долларов за штуку. И с ростом частоты цена вопроса обещала расти уже совершенно непристойно. Надо было как-то выходить из положения.

Галопом по вычислительным Европам. Часть 4. Как накормить процессор. Статья Ильи Вайцмана. 25.01.2023 г.

И ответы тут разные компании нашли разные. Так компания Intel в своих процессорах Pentium II остановилась на варианте 16+16 L1, но быстро (+512 KB на плате процессора и на половинной частоте), а вот AMD в своих первых Athlon предпочла пожертвовать скоростью L1, увеличив вероятность попадания за счет размера 64+64 и эксклюзивности[14] L1 по отношению к L2 (L2 в серии Argon/Pluto/Orion так же, как у Intel был внешним, 512 KB и на половинной скорости ядра). Впоследствии, по мере развития технологических процессов оказалось, что вместо сборки из самого процессора и микросхем кэша на корпусе процессора (Pentium PRO) или на процессорной плате (Pentium II с разъемом Slot 1 и первые Athlon на Slot A) все можно разместить на самом кристалле. Получается хотя (на тот момент) и меньше — 256 KB против 512[15], но более чем вдвое быстрее. С тех пор прошло много лет, и после того, как на кристалл стал помещаться не только L2, но и несколько ядер возникла новая проблема: организация взаимодействия между различными потоками команд. И это было непросто…

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

И тут снова, разные компании подошли к вопросу по-разному. Компания Intel сначала (в процессорах архитектуры Core 2) увеличили L1, до размера 32I+32D и начали делать общий на два ядра кэш L2 (доведя его размер до 2, 3, 4 и даже 6 MB на два ядра и, соответственно, 4, 6, 8 и 12[16] MB на сборку из двух чиплетов, известную как Core 2 Quad). Но, как и ожидалось, большие кэши не позволяли производить быстрый поиск, ограничивая потенциал ускорения самих ядер, поэтому впоследствии, (в процессорах Core I[3...9], с заметно выросшим IPC) Intel решила использовать небольшой L2 (по 256 KB на ядро), а для межъядерного обмена и буферизации работы с основной памятью создать разделяемый между ядрами кэш третьего уровня.

Их же конкуренты из AMD предпочли оставить кэши отдельными, ограничившись L2, но довели их размер с 256 до 1024 KB на ядро. В принципе, индивидуальные кэши у AMD получались эффективнее, потому что больше (в одно и то же время между собой конкурировали процессоры Intel с двумя ядрами с кешем 256 KB на ядро и 2-3 мегабайтами общего L3 и четырехядерные процессоры AMD с организацией L2 4 x 1 MB), что для суммы однопоточных приложений выходило неплохо, но вот межпроцессный обмен получался хуже. Итог был, прямо скажем, неоднозначным.

Если рассмотреть процессоры AMD семейств Llano и Trinity, то можно увидеть, что при тех же четырех ядрах у Liano L2[17] организован как 4x1 MB, а у Trinity — 2x2 MB. Что частично решило проблему взаимодействия процессов (как у Core 2 Quad). Стало гораздо лучше, хотя бы два потока получили возможность для быстрого обмена данными. Однако, передача данных между потоками из разных «полупроцессоров» требовала (как и у процессоров Intel) оборота данных через оперативную память.

Компания AMD урок усвоила, и следующие поколения многоядерных процессоров AMD получили разделяемый (и доступный для встроенной графики, если она есть) кэш третьего уровня. И даже в тех случаях, когда по технологическим причинам этот кэш приходится разделять на части — то на каждый сегмент кэша третьего уровня приходится не меньше трех ядер (6 потоков), чего в большинстве случаев достаточно для приемлемой эффективности обмена (помните главу «Количество против качества»?). С тех пор трехуровневая модель кэширования — быстрый маленький L1, среднего размера L2 и большой разделяемый между ядрами L3 – стала, в целом, общепринятой.

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

Продолжение следует…

[1]У процессоров 8086/88 адрес и данные выставлялись на общую шину поочередно, а 286 мог делать это в одном такте, по раздельным шинам адреса (24 разряда) и данных (16 разрядов).

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

[3]Внутренний кэш появился впервые даже чуть раньше, в 1985 году в процессоре MIPS R2000, и сразу 64I+32D, но у него не было внешнего кэша, так что это было такое неоднозначное с точки зрения производительности решение. В R3000 положение исправилось, но на рынки он уже реально вышел позже, чем i486.

[4]Неконвейерный процессор Motorola 68030 имел по 256 байт неуправляемого кэша команд и данных, которые можно считать, скорее, буферами предвыборки, а не полноценными кэшами. Такие же 256 байт кэша имел и микропроцессор Zilog Z280, например.

[5]Существовали забавные мутанты: процессоры Cyrix/Ti 486SLC/DLC, по сути i386SX/DX но с 1 KB кэша L1, предназначенные для модернизации старых компьютеров. Сколько людей было обмануто жуликами, продававшими им такие системы за цену полноценных i486DX!! Нет, они были существенно быстрее i386, особенно в сочетании с Cyrix FasMath 83D87, но… А еще были 486SRX2 и 486DRX2, де-факто i386 SX и DX с частотой 66 MHz. Ощущение от работы на 486DRX2 было странным. Вроде бы, иногда даже почти как 486, но как с гирей на ноге. А вот смысла в 486SRX2 я совсем не понял. Все упиралось в 16-разрядную внешнюю шину.

[6]Не на 100%, конечно, но внутренние кэши в достаточно большой степени развязали руки разработчикам CPU.

[7]Чисто для примера: в процессоре Phenom II x6 1055T, имеющего размеры кэша первого, второго и третьего уровня в 64I+64D, 512 и 6144 килобайта — задержка выборки составляет 3, 13 и 48 тактов соответственно.

[8]В мире дорогих серверов и рабочих станций (MIPS или PA-RISC, например) размеры кэша на материнских платах уже в середине-конце 80 достигали 4-16 мегабайт. Но по таким ценам, я вам скажу…

[9]Чипсеты VIA Apollo поддерживали до 2048 KB L2, что иногда оказывалось полезным. Но, в целом, для того периода такая величина кэша была избыточной.

[10]Серверы на процессорах Alpha 21064 получили до 16(!) MB внешнего кэша L2, но помогало это тоже частично.

[11]Процессоры HP PA-RISC, например, оснащались огромным кэшем L1 (до 4 MB (2D+2I) на плате процессора), что позволяло им добиться высокой производительности на некоторых алгоритмах. Но — не на всех. Это решение оказалось не универсальным.

[12]На платах ASUSTEK можно было вместо шины 66,6 и коэффициента умножения 2,5 сделать 83х2 — и в таком случае (если все работало) Pentium 166 MMX с 1024 L2 обретал почти крылья. Потому что ускорялось не только ядро, но и L2 с оперативной памятью. Получалось быстрее, чем стандартный (3х66,6) Pentium 200 MMX.

[13]В чуть более поздние времена было на практике доказано, что серверная система из двух PPro 200 с полноскоростным L2 в 1024 KB даже со старой EDO памятью, уверенно опережала на ряде задач сервер на двух Pentium II 300 с более совершенной SDRAM — но с кэшами по 512 KB половинной скорости..

[14]Адресное пространство кэшей, как правило, инклюзивно — содержимое и адресное пространство кэша является частью кэша следующего уровня, но эксклюзивные кэши процессоров AMD того поколения не дублировались, а складывались, поэтому объем кэшей у них получался 128+512=640 KB.

[15]Соответственно, у Intel общий объем кэшей на кристалле вышел 256 KB, а у AMD целых 384. Но медленнее.

[16]Процессор Q9650, к примеру, с четырьмя ядрами частотой 3 GHz и 12 MB (2x6) кэша L2 — очень достойный по производительности экземпляр. На материнских платах с DDR3 он вполне актуален даже сегодня. Не то что круть неимоверная (как 15 лет назад), но вполне для работы годно.

[17]У семейства Trinity очень странная организация L1. Кэш инструкций по 16 KB индивидуальный для каждого ядра, а L1D (кэш данных) размером 64 KB — разделяемый, на два ядра. Решение интересное, но спорное.

----

Логистика 2023: вызовы и решения

Логистика 2023: вызовы и решения. Статья Владислава Боярова. 04.04.2023 г.

Галопом по вычислительным Европам. Часть 6. Спецпроцессоры.

Галопом по вычислительным Европам. Часть 6. Спецпроцессоры. Часть 5. Память. Статья Ильи Вайцмана. 15.03.2023 г.

«Домашний компьютер». Конкурс в Самаре.

«Домашний компьютер». Конкурс в Самаре.

Blood, Sweat & Tears, или Кровь, пот и слёзы – часть третья, объединительная

ИТ-Перестройка-2023 от OCS

ИТ-Перестройка-2023 от OCS. Статья Владислава Боярова. 10.03.2023 г.