Процессоры Intel Sandy Bridge — все секреты

Процессоры Intel Sandy Bridge все секреты

Читатель наверняка знаком с кратким описанием микроархитектуры Sandy Bridge и помнит, что для той статьи мы использовали лишь иллюстрации из презентаций Intel, снабдив их нашими комментариями. Очевидно, они рассказывают не всю историю, поэтому нужна детальная статья, где история рассказывается вся и уже из независимого источника. ;) Кроме того, т. к. в своё время мы не делали подробного описания предыдущей микроархитектуры Nehalem, восполним это тем, что детально опишем не только ныне добавленные и изменившиеся элементы, но и старые (притом, что они не обязательно появились в Nehalem — некоторые цифры и факты куда древнее). Также мы испытаем нововведение: специфические термины и сокращения будут особо выделены, а при наведении на них курсора покажется всплывающая подсказка-расшифровка со ссылкой на нашу «Энциклопедию процессорных терминов» (которая, кстати, обновляется перед выходом каждой статьи).

«Крутой и холодный»

Прежде всего, какой ЦП был нужен Intel после 2008 г., когда микроархитектурное превосходство первых Core i (Nehalem и, в 2009 г., Westmere) над ЦП соперника стало окончательным? Ситуация немного напоминает первый год после выхода Pentium II: почивая на лаврах и получая рекордную прибыль, хорошо бы сделать продолжение удачной архитектуры, не сильно изменив её название, добавив новые команды, использование которых значительно улучшит производительность, не забыв и о других новшествах, ускоряющих сегодняшние версии программ. Правда, в отличие от ситуации 10-летней давности, надо обратить внимание и на модную ныне тему энергоэффективности, обыгранную двусмысленным прилагательным Cool — «крутой» и «холодный», — и не менее модное стремление встроить в процессор всё, что пока ещё существует как отдельные микросхемы. Вот под таким соусом и подана новинка.


«Позавчера», «вчера» и «сегодня» процессоров Intel.

Интегрированный в кристалл ЦП графический процессор ( ГП) мы детально рассмотрим в отдельной статье. Тут же исследуем результат работы израильского отделения Intel (Israel Development Center), которому в очередной раз поручили сделать ещё более экономную модификацию текущей (на 2008 г.) универсальной серверно-настольно-мобильной архитектуры (назовём её просто Nehalem). Правда, изначальное кодовое имя Gesher («мост» на иврите) по «политическим» причинам (была в Израиле такая партия, да сплыла…) пришлось изменить на Sandy Bridge — «песчаный мост» (сократим его до SB). Причина задержки не совсем ясна: следуя своей обычной практике выпуска каждый нечётный год нового техпроцесса («тик»), а каждый чётный — микроархитектуры («так»), SB должен был выйти в 2010 г. — тем более, что половина якобы новых добавленных в него идей уже были в предыдущих ЦП Intel. Тем не менее, учитывая состояние ЦП конкурента, нельзя сказать, что SB опоздал. Конечно, инженерам Intel надо бы поглядывать в сторону новых архитектур AMD, которые в ближайшем будущем (и опоздав гораздо больше, чем на год), кажется, чем-то грозят…

Технически задача стояла примерно так: на той же площади кристалла (т. е. при той же себестоимости) и том же 32 нм техпроцессе сделать ЦП, который на старых программах имел бы +10% скорости и −20% потребления одновременно, а на новых (где используются добавленные команды) — аж +100% пиковой скорости при том же TDP. Возможно, цифры были чуть другие, но почти так это выглядит по результатам. А вот какими методами — проще всего узнать, сравнивая SB с Nehalem (это относится к многочисленным прилагательным «больше», «быстрее», «экономней» и пр. далее в тексте). Напрашивается сравнение и с выходящей в середине 2011 г. архитектурой AMD Bulldozer, но оно будет после детального обзора её самой. Intel постепенно заместит архитектуру почти всех своих выпускаемых сегодня x86-ЦП (кроме Atom) с Nehalem на SB. Позиционирование против ЦП AMD пока точно не ясно, но один гол в ворота соперника уже забит: SB уже успела нещадно побить сегодняшние «Феномы», а обновлённые соперники выйдут на несколько месяцев позже — и не факт, что возьмут реванш.

Фронт конвейера


Фронт конвейера. Цвета показывают разные виды информации и обрабатывающих или хранящих её блоков.

Предсказание переходов

Начнём с заявления Intel о полностью переработанном предсказателе переходов (BPU). Как и в Nehalem, он каждый такт (и наперёд реального исполнения) предсказывает адрес следующей 32-байтовой порции кода в зависимости от предполагаемого поведения команд перехода в только что предсказанной порции — причём, судя по всему, вне всякой зависимости от числа и типа переходов. Точнее, если в текущей порции есть предположительно срабатывающий переход, выдаются его собственный и целевой адреса́, иначе — переход к следующей подряд порции. Сами предсказания стали ещё точней за счёт удвоения буфера целевых адресов (BTB), удлинения регистра глобальной истории переходов (GBHR) и оптимизации хэш-функции доступа к таблице шаблонов поведения (BHT). Правда, фактические тесты показали, что в некоторых случаях эффективность предсказания всё же чуть хуже, чем в Nehalem. Может быть, увеличение производительности с уменьшением потребления не совместимо с качественным предсказанием переходов? Попробуем разобраться.

В Nehalem (как и других современных архитектурах) BTB присутствует в виде двухуровневой иерархии — малый-«быстрый» L1 и большой-«медленный» L2. Происходит это по той же причине, почему существуют несколько уровней кэша: одноуровневое решение окажется слишком компромиссным по всем параметрам (размер, скорость срабатывания, потребление и пр.). Но в SB архитекторы решили поставить один уровень, причём размером вдвое больше, чем L2 BTB у Nehalem, т. е. наверняка не менее 4096 ячеек — именно столько их в Atom (а размер обслуживаемого кэша L1I совпадает у всех ЦП Intel с первых Pentium M). По идее, при этом увеличится занимаемая им площадь, а т. к. общую площадь ядра менять не рекомендуется (таков один из начальных постулатов архитектуры) — у какой-то другой структуры что-то придётся забрать. Но остаётся ещё и скорость. Учитывая, что SB должен быть рассчитан на чуть большую скорость при том же техпроцессе, можно ожидать, что эта крупная структура будет бутылочным горлышком всего конвейера — если только не конвейеризировать и её (двух стадий уже хватит). Правда, общее число срабатывающих за такт транзисторов в BTB при этом удвоится, что совсем не способствует энергоэкономии. Опять тупик? На это Intel отвечает, что новый BTB хранит адреса в некоем сжатом состоянии, что позволяет иметь вдвое больше ячеек при похожих площади и потреблении. Но проверить это пока невозможно.

Смотрим с другой стороны. SB получил не новые алгоритмы предсказания, а оптимизированные старые: общий, для косвенных переходов, циклов и возвратов. Nehalem имеет 18-битный GBHR и BHT неизвестного размера. Впрочем, можно гарантировать, что число ячеек в таблице меньше, чем 218, иначе она бы заняла бо́льшую часть ядра. Поэтому существует специальная хэш-функция, сворачивающая 18 бит истории всех переходов и биты адреса команды в индекс меньшей длины. Причём, скорее всего, хэшей как минимум два — для всех битов GBHR и для тех, что отражают срабатывание наиболее трудных переходов. И вот эффективность хаотичного распределения индексами различных шаблонов поведения по номерам ячеек BHT определяет успешность предсказателя общего вида. Хотя явно это не сказано, но Intel наверняка улучшила хэши, что позволило использовать GBHR бо́льшей длины с не меньшей эффективностью заполнения. А вот о размере BHT по прежнему можно гадать — как и о том, как на самом деле изменилось потребление энергии предсказателем в целом… Что касается буфера адресов возвратов (RSB), он по-прежнему 16-адресный, но введено новое ограничение на сами вызовы — не более четырёх на 16 байт кода.

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

Декодирование и IDQ

Предсказанные наперёд адреса исполняемых команд (попеременно для каждого потока — при включенной технологии Hyper-Threading) выдаются для проверки их наличия в кэшах команд (L1I) и мопов (L0m), но о последнем умолчим — опишем пока остальную часть фронта. Как ни странно, Intel сохранила размер считываемой из L1I порции команд в 16 байт (тут слово «порция» понимается согласно нашему определению). До сих пор это было препятствием для векторного кода, средний размер команд которого перерос 4 байта, а потому 4 команды, желательные для исполнения за такт, уже не уместятся в 16 байт. AMD решила эту проблему в архитектуре K10, расширив порцию команд до 32 байт — хотя её ЦП пока имеют не более чем 3- путный конвейер. В SB неравенство размеров приводит к побочному эффекту: предсказатель выдаёт очередной адрес выровненного 32-байтового блока, и если обнаружится (предположительно) срабатывающий переход в его первой половине, то считывать и декодировать вторую не надо — однако это будет сделано.

Из L1I порция попадает в буфер предекодера, а оттуда — в сам предекодер-длиномер ( ILD), обрабатывающий до 7 или 6 команд/такт (с и без макрослияния, но всё равно на 1 больше, чем в Nehalem) в зависимости от их совокупной длины и сложности. Сразу после перехода обработка начинается с команды по целевому адресу, иначе — с того байта, перед которым предекодер остановился тактом ранее. Аналогично с финальной точкой: либо это (вероятно) срабатывающий переход, адрес последнего байта которого поступил от BTB, либо последний байт само́й порции — если только не достигнут предел в 7 команд/такт, или не встретилась «неудобная» команда. Скорее всего, буфер длиномера имеет всего 2–4 ячейки, однако длиномер может получить из него любые 16 подряд идущих байт. Например, если в начале порции опознаны 7 двухбайтовых команд, то в следующем такте можно обработать ещё 16 байт, начиная с 15-го.

Длиномер, помимо прочего, занимается обнаружением пар макросливаемых команд. О самих парах поговорим чуть позже, а пока заметим, что, как и в Nehalem, каждый такт может быть обнаружено не более одной такой пары, хотя максимум их можно было бы разметить 3 (и ещё одну одиночную команду). Однако измерение длин команд — процесс частично последовательный, так что определить несколько макросливаемых пар не удалось бы в течение такта.

Размеченные команды попадают в одну из двух очередей команд (IQ: instruction queue) — по одной на поток, на 20 команд каждая (что на 2 больше, чем у Nehalem). Декодер попеременно читает команды из очередей и переводит их в мопы. В нём есть 4 простых транслятора (переводят 1 команду в 1 моп, а с макрослиянием — 2 команды в 1 моп), сложный транслятор (1 команда в 2–4 мопа) и микросеквенсер для самых сложных команд, требующих 5 и более мопов из микрокода. Причём ПЗУ микрокода хранит только «хвосты» каждой последовательности, начиная с 5-го мопа, потому что первые 4 выдаются сложным транслятором. При этом если число мопов в микропрограмме не делится нацело на 4, то их последняя четвёрка будет неполной, но вставить ещё 1–3 мопа от трансляторов в этом же такте не получится. Результат декодирования поступает в кэш мопов и два буфера мопов (по одному на поток). Последние (официально именуемые IDQ — instruction decode queue, очередь декодированных команд) по-прежнему имеют по 28 мопов и возможность блокировки цикла, если его исполняемая часть там уместится.

Всё это (кроме кэша мопов) уже было в Nehalem. А в чём же различия? Прежде всего, что очевидно, декодер научили обрабатывать новые команды поднабора AVX. Поддержка наборов SSE со всеми цифрами уже никого не удивляет, а ускорение шифрования командами AES-NI (включая PCLMULQDQ) было добавлено в Westmere (32 нм версия Nehalem). В микрослияние подложили подводный камень: эта функция не срабатывает для команд, имеющих и константу, и RIP-относительную адресацию (RIP-relative, адрес относительно регистра-указателя команды — обычный способ обращения к данным в 64-битном коде). Такие команды требуют 2 мопа (отдельно загрузка и операция), а значит — декодер их обработает не более одной за такт, используя лишь сложный транслятор. Intel утверждает, что эти жертвы сделаны для экономии энергии, только не ясно, на чём: двухкратные размещение, исполнение и отставка мопов явно займут больше ресурсов, а значит — и потребят энергии, чем один.

Макрослияние оптимизировано — ранее в качестве первой сливаемой команды могло быть лишь арифметическое или логическое сравнение (CMP или TEST), теперь же допустимы простые арифметические команды сложения и вычитания (ADD, SUB, INC, DEC) и логического «И» (AND), также меняющие флаги для условного перехода (вторая команда пары). Это позволяет почти в любом цикле сократить последние 2 команды до 1 мопа. Разумеется, ограничения на сливаемые команды остались, но они некритичны, т. к. перечисленные ситуации для пары команд почти всегда исполняются:

  • первый операнд первой команды должен быть регистром;
  • если второй операнд первой команды находится в памяти, RIP-относительная адресация недопустима;
  • вторая команда не может находиться в начале строки кэша или пересекать границу строк.

Правила для самого́ перехода такие:

  • только TEST и AND совместимы с любым условием;
  • сравнения на (не) равно и любые знаковые совместимы с любой разрешённой первой командой;
  • сравнения на (не) перенос и любые беззнаковые не совместимы с INC и DEC;
  • остальные сравнения (знак, переполнение, чётность и их отрицания) допустимы лишь для TEST и AND.

Главное изменение в очередях мопов — слитые мопы типа load-ex, обращение в память в которых требует чтения индексного регистра, (и ещё несколько редких видов) при записи в IDQ разделяются на пары. Даже если таких мопов попадётся 4, то в IDQ запишутся все 8 итоговых. Делается это потому, что в очередях мопов (IDQ), диспетчера (ROB) и резервации теперь применяется сокращённый формат мопа без 6-битного поля индекса (разумеется, для экономии при перемещении мопов). Предполагается, что такие случаи будут редки, а потому на скорость сильно влиять не будут.

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

  • мопы цикла должны порождаться не более чем 8-ю 32-байтовыми порциями исходного кода;
  • эти порции должны быть закэшированы в L0m (в Nehalem, разумеется, — в L1I);
  • допускается до 8 безусловных переходов, предсказанных как срабатывающие (включая финальный);
  • вызовы и возвраты недопустимы;
  • недопустимы непарные обращения в стек (чаще всего при неравном числе команд PUSH и POP) — об этом ниже.

Стековый движок

Есть ещё один механизм, работу которого мы в прошлых статьях не рассматривали — стековый движок (stack pointer tracker, «следитель за указателем (на вершину) стека»), расположенный перед IDQ. Он появился ещё в Pentium M и до сих пор не изменился. Суть его в том, что модификация указателя стека (регистра ESP/RSP для 32/64-битного режима) командами для работы с ним (PUSH, POP, CALL и RET) делается отдельным сумматором, результат хранится в специальном регистре и возвращается в моп как константа — вместо того, чтобы модифицировать указатель в АЛУ после каждой команды, как это требует программная архитектура и как было в ЦП Intel до Pentium M.

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

Внимательный Читатель (добрый день!) заметит связь: при зацикливании очереди мопов непарные обращения в стек недопустимы именно по причине того, что стековый движок в конвейере находится до IDQ — если после очередной итерации значение теневого указателя окажется ненулевым, в новой потребуется вставить синхромоп, а в циклическом режиме это невозможно (мопы только читаются из IDQ). Более того, стековый движок вообще при этом выключен для экономии энергии, как и все остальные части фронта.

Тайная жизнь нопов

Ещё одно изменение коснулось длиномера, но этот случай несколько выделяется. Сначала вспомним, что такое нопы и зачем они нужны. Когда-то в архитектуре x86 ноп был лишь 1-байтовый. Когда требовалось сместить код более чем на 1 байт или заменить команды длиной более 1-го байта, ноп просто вставляли несколько раз. Но несмотря на то, что эта команда ничего не делает, время на её декодирование всё-таки тратится, причём пропорционально числу нопов. Чтобы производительность «пропатченной» программы не просела, ноп можно удлинить префиксами. Однако в ЦП 90-х годов темп декодирования команд с числом префиксов выше определённой величины (которая куда меньше максимально допустимой длины x86-команды в 15 байт) резко падал. Кроме того, конкретно для нопа префикс применяется, как правило, одного вида, но многократно повторенный, что допускается лишь как нежелательное исключение, усложняющие длиномер.

Для разрешения указанных проблем начиная с Pentium Pro и Athlon процессоры понимают «длинный ноп» с байтом modR/M для «официального» удлинения команды с помощью регистров и адресного смещения. Естественно, никаких операций с памятью и регистрами не происходит, но при определении длины используются те же блоки длиномера, что и для обычных многобайтовых команд. Теперь использование длинных нопов официально рекомендуется учебниками по низкоуровневой программной оптимизации и от Intel, и от AMD. Кстати, предекодер SB вдвое (с 6 до 3 тактов) уменьшил штраф за префиксы 66 и 67, меняющие длину константы и адресного смещения — но, как и в Nehalem, штраф не накладывается на команды, где эти префиксы фактически не меняют длину (например, если префикс 66 применён к команде без непосредственного операнда) или являются частью списка переключателей опкодов (что сплошь и рядом используется в векторном коде).

Максимальная длина верно оформленного длинного нопа не превышает 9 байт для Intel и 11 для AMD. А потому для выравнивания на 16 или 32 байта нопов всё-таки может быть несколько. Однако т. к. команда эта простая, её декодирование и «исполнение» займёт ресурсов никак не больше обработки самых простых действующих команд. Поэтому уже много лет тестирование длинными нопами является стандартным методом определения параметров фронта конвейера, в частности — пропускной способности длиномера и декодера. И вот тут Sandy Bridge преподнёс очень странный сюрприз: тестирование производительности обычных программ не выявило никаких задержек и замедлений, а вот дежурная синтетическая проверка параметров декодера неожиданно показала, что его производительность равна одной команде за такт! При этом никаких официальных оповещений о таких радикальных изменениях в декодере Intel не давала.

Процедура замера отлично работала ещё на Nehalem и показывала верные 4 IPC. Можно свалить вину на новый и «чрезмерно» активный Turbo Boost 2.0, портящий замеряемые показатели тактов, но для тестов он был отключен. Перегрев с замедляющим частоту тротлингом тоже исключён. А когда, наконец, причина обнаружилась — стало ещё страннее: оказывается, длинные нопы на SB обрабатываются только первым простым транслятором, хотя 1-байтовые нопы с любым числом префиксов и аналогичные «по бездействию» команды (например, копирование регистра в себя) запросто принимаются всеми четыремя. Зачем так было делать — не ясно, однако как минимум один недостаток такого технического решения уже себя явно показал: на выяснение причин загадочной медлительности декодера нашей исследовательской командой было угрохано дней десять… В отместку просим яростных фанатов Противоположного Лагеря придумать какую-нибудь конспирологическую теорию о коварных планах некой компании I. по запутыванию наивных доблестных исследователей процессоров. :)

Кстати, как оказалось, «более равным» среди прочих транслятор №1 уже был. В Nehalem команды циклической прокрутки (ROL и ROR) с явным операндом-константой тоже декодировались только в первом трансляторе, причём в этом же такте отключался четвёртый, так что величина IPC падала до 3-х. Казалось бы — зачем приводить тут такой редкий пример? Но именно из-за этого подвоха, чтобы добиться пиковой скорости на алгоритмах хэширования вроде SHA-1, нужна была очень точная планировка команд, с которой компиляторы не справлялись. В SB же такие команды просто стали 2-мопными, так что, занимая сложный транслятор (который и так один), они ведут себя почти неотличимо для ЦП, но более предсказуемо для человека и компилятора. С нопами же получилось всё наоборот.

Кэш мопов

Цели и предшественники

Мы не зря отделили эту главу от остального описания фронта — добавление кэша мопов наглядно демонстрирует, какой путь выбрала Intel для всех своих процессоров, начиная с Core 2. В последний впервые (для Intel) был добавлен блок, который одновременно достигал две, казалось бы, противоречивые цели: увеличение скорости и экономия энергии. Речь идёт об очереди команд (IQ) между предекодером и декодером, хранившей тогда до 18 команд длиной до 64 байт в сумме. Если бы она только сглаживала разницу темпов подготовки и декодирования команд (как обычный буфер) — выгода была бы небольшая. Но в Intel догадались приделать к IQ небольшой блок LSD (вряд ли парни что-то «приняли», просто у них юмор такой) — Loop Stream Detector, «детектор циклического потока». При обнаружении цикла, умещающегося в 18 команд, LSD отключает все предыдущие стадии (предсказатель, кэш L1I и предекодер) и поставляет из очереди в декодер команды цикла, пока тот не завершится, либо пока не будет сделан переход за его пределы (вызовы и возвраты не допустимы). Таким образом экономится энергия за счёт отключения временно простаивающих блоков и увеличивается производительность за счёт гарантированного потока в 4 команды/такт для декодера, даже если они были «снабжены» самыми неудобными префиксами.

Intel явно понравилась эта идея, так что для Nehalem схема была оптимизирована: IQ продублирована (для двух потоков), а между декодером и диспетчером (т. е. аккурат на границе фронта и тыла) были поставлены две очереди IDQ на 28 мопов каждая, и блок LSD перенесли к ним. Теперь при блокировке цикла отключается ещё и декодер, а производительность поднялась в т. ч. за счёт гарантированного притока уже не 4-х команд, а 4-х мопов за такт, даже если их генерация производилась с минимальным (для Core 2/i) темпом в 2 мопа/такт. Яростные фанаты Противоположного Лагеря, на секунду оторвавшись от любимого занятия, тут же вставят шпильку: если LSD такая хорошая штука, почему же его не встроили в Atom? И шпилька справедлива — имея 32-моповую очередь после декодера, Atom не умеет блокировать в ней цикл, что как раз очень бы пригодилось для экономии драгоценных милливатт. Тем не менее, Intel не собиралась бросать идею и для новых ЦП подготовила обновление, да ещё какое!

Официальное внутреннее название кэша мопов — DSB (decode stream buffer: буфер потока декодирования), хотя он не так точно отражает суть, как рекомендуемый термин DIC (decoded instruction cache: кэш декодированных команд). Как ни странно, он не подменяет, а дополняет очереди IDQ, которые теперь соединяются с декодером или с кэшем мопов. При очередном предсказании перехода целевой адрес одновременно проверяется в кэшах команд и мопов. Если сработает последний — то далее считывание идёт из него, а остальной фронт отключается. Вот почему кэш мопов является кэшем нулевого уровня для мопов, т. е. L0m.

Интересно, что продолжить эту мысль можно, назвав IDQ кэшами «минус первого» уровня. :) Но не является ли такая сложная иерархия в рамках даже не всего ядра, а одного только фронта избыточной? Пускай Intel в качестве исключения не пожалела площадь, но принесёт ли пара IDQ существенную дополнительную экономию, учитывая, что при их работе теперь отключается лишь кэш мопов, т. к. остальной фронт (кроме предсказателя) и так спит? И ведь особой прибавки к скорости тоже не получишь, т. к. кэш мопов также настроен на генерацию 4 мопов/такт. Видимо, инженеры Intel решили, что 3-уровневая игра стоит милливаттовых свеч.

Кроме экономии, кэш мопов ускоряет производительность в т. ч. сокращением штрафа при фальш-предсказании перехода: в Nehalem при нахождении верного кода в L1I штраф был 17 тактов, в SB — 19, но если код нашёлся в L0m — то только 14. Причём это максимальные цифры: при внеочерёдном исполнении ложно предсказанного перехода планировщику надо ещё запустить и завершить предыдущие в программном порядке мопы, а за это время L0m может успеть подкачать верные мопы, чтобы планировщик успел их запустить сразу после отставки команд до перехода. В Nehalem такой приём работал с IDQ и фронтом, но в первом случае вероятность того, что верный целевой адрес тоже будет внутри 28-мопового цикла, весьма мал, а во втором медлительность фронта в большинстве случаев не позволяла снизить задержку до нуля. У SB такой шанс больше.

Устройство

Топологически L0m состоит из 32 наборов по 8 строк (8- путная ассоциативность). В каждой строке хранится 6 мопов (во всём кэше — 1536, т. е. «полтора киломопа»), причём за такт кэш может записать и считать по одной строке. Предсказатель выдаёт адреса 32-байтовых блоков, и именно этот размер является рабочим для L0m, поэтому далее под термином «порция» будем понимать выровненный и предсказанный как исполняющийся 32-байтовый блок кода (а не 16-байтовый, как для декодера). При декодировании контроллер L0m ждёт обработки порции до конца или до первого срабатывающего в ней перехода (разумеется, предположительно — тут и далее полагаем предсказания всегда верными), накапливая мопы одновременно с их отправкой в тыл. Затем он фиксирует точки входа в порцию и выхода из неё, согласно поведению переходов. Обычно точкой входа оказывается целевой адрес срабатывающего в предыдущей порции перехода (точнее, младшие 5 бит адреса), а точкой выхода — собственный адрес срабатывающего перехода в этой порции. В крайнем случае, если ни в предыдущей, ни в текущей порциях не сработает ни один переход (т. е. порции не только исполняются, но и хранятся подряд), то обе выполнятся целиком — вход в них будет на нулевом мопе и байте, а выход — на последнем мопе и начальном байте его команды.

Если в порции оказалось более 18 мопов — она не кэшируется. Это задаёт минимум среднего (в пределах порции) размера команды в 1,8 байта, что не будет серьёзным ограничением в большинстве программ. Можно вспомнить второй пункт ограничений IDQ — если цикл уместится в порции, но займёт от 19 до 28 мопов, его не зафиксируют ни кэш L0m, ни очередь IDQ, хотя по размеру он бы везде уместился. Впрочем, в этом случае средняя длина команд должна быть 1,1–1,7 байта, что для двух десятков команд подряд крайне маловероятно.

Скорее всего, мопы порции одновременно записываются в кэш, занимая 1–3 строки одного набора, так что для L0m нарушается один из главных принципов работы наборно-ассоциативного кэша: при кэш-попадании обычно срабатывает одна строка набора. Тут же теги до трёх строк могут получить адрес одной и той же порции, отличаясь лишь порядковыми номерами. При попадании предсказанного адреса в L0m считывание происходит аналогично — срабатывают 1, 2 или 3 пути нужного набора. Правда, такая схема таит в себе недостаток.

Если исполняемая программа во всех порциях декодируется в 13–18 мопов, что займёт по 3 строки L0m для всех порций, обнаружится следующее: если текущий набор уже занят двумя 3-строчными порциями, и в него пытается записаться третья (которой не хватит одной строки), придётся вытеснить одну из старых, а с учётом её связности — все 3 старых. Таким образом больше двух порций «мелко-командного» кода в наборе не должно уместиться. При проверке этого предположения на практике получилось вот что: порции с крупными командами, требующие менее 7 мопов, упаковались в L0m числом в 255 (ещё одну занять почему-то не получилось), уместив почти 8 КБ кода. Средние порции (7–12 мопов) заняли все 128 возможных позиций (по 2 строки каждая), закэшировав ровно 4 КБ. Ну а мелкие команды уместились в 66-и порциях, что на две больше ожидаемого значения (2112 байт против 2048), что, видимо, объясняется граничными эффектами нашего тестового кода. Недостача на лицо — если бы 256 6-моповых строк могли быть заполнены полностью, их бы хватило на 85 полных троек с общим размером кода 2720 байт.

Возможно, Intel не рассчитывает, что в каком-то коде будет так много коротких и простых команд, что более 2/3 его придётся на 3-строчные порции, которые станут вытеснять друг друга из L0m раньше необходимого. А даже если такой код и встретится — учитывая простоту его декодирования, остальные блоки фронта запросто справятся с задачей поставки необходимых тылу 4 мопов/такт (правда, без обещанной экономии ватт и тактов штрафа при фальш-предсказании). Любопытно, что имей L0m 6 путей, проблемы бы не возникло. Intel же решила, что иметь размер кэша на треть больше именно за счёт ассоциативности — важнее…

Размеры

Вспомним, что идея кэшировать большое количество мопов вместо команд x86, не нова. Впервые она появилась в Pentium 4 в виде кэша моп-трасс — последовательностей мопов после развёртки циклов. Причём кэш трасс не дополнял, а заменял отсутствующий L1I — команды для декодера читались сразу из L2. Не смотря на забвение архитектуры NetBurst, разумно предположить, что инженеры Intel использовали прошлый опыт, хоть и без развёртки циклов и выделенного для кэша предсказателя. Сравним старое и новое решения (новые ЦП тут названы Core i 2, потому что номера почти всех моделей с архитектурой SB начинаются с двойки):

Pentium 4
(Willamette,
Northwood)
Pentium 4
(Prescott)
Core i 2
(Sandy Bridge)
Объём, Кмопов 12 12 1,5
Организация, наборов⋅путей 256⋅8 256⋅8 32⋅8
Число мопов в строке 6 6 6
ПС, мопов/такт 3 3 4
Полный размер мопа, бит* 119 138 139–147
Сжатый размер мопа, бит* 53 64 85
Эквивалентный объём, КБ* 80 96 16

* — предположительно

Тут нужны пояснения. Во-первых, пропускная способность для L0m указана с учётом общего ограничения ширины конвейера в 4 мопа. Выше мы предположили, что за такт L0m может прочесть и записать по 18 мопов. Однако при чтении все 18 (если их получилось именно столько при декодировании оригинальной порции) не могут быть отправлены за такт, и отправка происходит за несколько тактов.

Далее, размер мопа в битах вообще относится к очень деликатной информации, которую производители либо вообще не выдают, либо только при припирании к стенке (дескать, вы и так уже всё вычислили, так и быть — подтвердим). Для ЦП Intel последняя достоверно известная цифра — 118 бит для Pentium Pro. Ясно, что с тех пор размер увеличился, но с этого места начинаются догадки. 118 бит для 32-битного x86-ЦП может получиться, если в мопе есть поля для адреса породившей его команды (32 бита), непосредственного операнда (32 бита), адресного смещения (32 бита), регистровых операндов (3 по 3 бита + 2 бита на масштаб для индексного регистра) и опкода (11 бит, в которых закодирован конкретный вариант x86-команды с учётом префиксов). После добавления MMX, SSE и SSE2 поле опкода наверняка выросло на 1 бит, откуда и получена цифра 119.

После перехода на x86-64 (Prescott и далее), по идее, все 32-битные поля должны возрасти до 64-х бит. Но тут есть тонкости: 64-битные константы в x86-64 допускаются только по одной (т. е. более 8 байт обе константы в команде точно не займут), а виртуальная адресация и тогда, и сейчас пока обходится 48 битами. Так что увеличить размер мопа требуется всего на 16 бит адреса и 3 дополнительных бита номеров регистров (коих стало 16) — получаем (примерно) 138 бит. Ну а в SB моп, видимо, вырос ещё на 1 бит за счёт добавления очередных нескольких сотен команд со времён последних P4, и ещё на 8 — за счёт увеличения максимального числа явно указанных регистров в команде до 5 (при использовании AVX). Последнее, впрочем, сомнительно: со времён, представьте себе, аж i386 в архитектуру x86 не была добавлена ни одна новая команда, требующая хотя бы 4 байта константы (с единственным недавним и крайне незаметным исключением в SSE4.a от AMD, о котором даже большинство программистов не знает). А т. к. Intel AVX и AMD XOP обновили кодировку лишь векторных команд, биты номеров дополнительных регистров уместятся в старшей половине частично неиспользуемого (для этих команд) 32-битного поля непосредственного операнда. Тем более, что и в само́й x86-команде 4-й или 5-й регистр кодируется как раз четыремя битами константы.

Очевидно, что хранить и пересылать таких «монстров» в сколько-нибудь большом количестве — сильно затратно. Поэтому ещё для P4 Intel придумала сокращённый вариант мопа, в котором лишь одно поле для обеих констант, причём если они там не умещаются, то недостающие биты размещаются в этом же поле соседнего мопа. Однако если он уже хранит там свои константы, то в качестве соседа приходится вставлять ноп как донор-носитель дополнительных бит. Преемственность такой схемы наблюдается и в SB: лишние нопы не вставляются, но команды с 8-байтовыми константами (или с суммой размеров константы и адресного смещения в 5–8 байт) имеют в L0m двойной размер. Впрочем, учитывая длину таких команд, больше 4-х их в порции не уместится, так что ограничение по занимаемым мопам явно некритично. Тем не менее, констатируем: SB, в отличие от предыдущих ЦП, имеет аж 3 формата мопов — декодируемый (самый полный), хранимый в кэше мопов (с сокращением констант) и основной (без поля регистра индекса), используемый далее в конвейере. Впрочем, большинство мопов проходят нетронутыми от декодирования до отставки.

Ограничения

«Правила пользования кэшем» на спецформате мопов не заканчиваются. Очевидно, столь удобный блок как L0m никак не мог оказаться совсем без ограничений той или иной степени серьёзности, о которых нам не рассказали в рекламных материалах. :) Начнём с того, что все мопы транслируемой команды должны уместиться в одной строке, иначе они переносятся в следующую. Это объяснимо тем, что адреса мопов строки хранятся отдельно (для экономии 48 бит в каждом мопе), а все порождаемые командой мопы должны соответствовать адресу её первого байта, хранимому в теге только одной строки. Для восстановления оригинальных адресов в тегах хранятся длины породивших мопы команд. «Непереносимость» мопов несколько портит эффективность использования L0m, т. к. изредка встречающиеся команды, генерирующие несколько мопов, имеют существенный шанс не уместиться в очередной строке.

Более того, мопы самых сложных команд по-прежнему хранятся в ПЗУ с микрокодом, а в L0m попадают лишь первые 4 мопа последовательности, плюс ссылка на продолжение, так что всё вместе занимает целую строку. Из этого следует, что в порции могут встретиться не более трёх микрокодовых команд, а учитывая средний размер команды более вероятным пределом будут две. В реальности, впрочем, они попадаются куда реже.

Ещё один важный момент — L0m не имеет своего TLB. Вроде бы, это должно ускорять проверку адресов (которые тут только виртуальные) и уменьшить потребление энергии. Но всё гораздо интересней — не зря все современные кэши имеют физическую адресацию. Виртуальные адресные пространства исполняемых в ОС программ могут пересекаться, поэтому при переключении контекста задачи, чтобы по тем же адресам не считать старые данные или код, виртуально адресуемый кэш должен сбрасываться (именно так было с кэшем трасс у P4). Разумеется, его эффективность при этом будет низкой. В некоторых архитектурах применяются т. н. ASID (address space identifier, идентификатор адресного пространства) — уникальные числа, присваиваемые ОС каждому потоку. Однако x86 не поддерживает ASID за ненадобностью — учитывая наличие физических тегов для всех кэшей. Но вот пришёл L0m и нарушил картину. Более того, вспомним, что кэш мопов, как и большинство ресурсов ядра, разделяется между двумя потоками, так что в нём окажутся мопы разных программ. А если добавить переключение между виртуальными ОС в соответствующем режиме, то мопы двух программ могут совпасть по адресам. Что же делать?

Проблема с потоками решается просто — L0m просто делится пополам по наборам, так что номер потока даёт старший бит номера набора. Кроме того, L1I имеет включающую политику хранения относительно L0m. Поэтому при вытеснении кода из L1I происходит и удаление его мопов из L0m, что требует проверки двух смежных порций (размер строки всех кэшей современных ЦП, не считая самого́ L0m — 64 байта). Таким образом виртуальный адрес из тэгов закэшированных мопов всегда можно проверить в тегах L1I, используя его TLB. Выходит, что хоть L0m и имеет виртуальную адресацию, но заимствует физические теги для кода из L1I. Тем не менее, есть ситуация, при которой L0m целиком сбрасывается — промах и замещение в L1I TLB, а также его полный сброс (в т. ч. при переключении режимов работы ЦП). Кроме того, L0m совсем отключается, если базовый адрес селектора кода (CS) не равен нулю (что крайне маловероятно в современных ОС).

Работа

Главный секрет кэша мопов — алгоритм, подменяющий чтениями из L0m работу фронта по переработке команд в мопы. Начинается он с того, что при очередном переходе для выбора набора L0m использует биты 5–9 адреса цели перехода (или биты 5–8 плюс номер потока — при 2-поточности). В тегах набора указаны точка входа в порцию, мопы которой записаны в соответствующей тегу строке, и порядковый номер этой строки в пределах порции. Совпасть могут 1–3 строки, которые (скорее всего) одновременно считываются в 18-моповый буфер. Оттуда мопы четвёрками посылаются в IDQ, пока не будет достигнута точка выхода — и всё повторяется сначала. Причём когда в порции остаются неотправленными 1–3 последних мопа, они высылаются с 3–1 первыми мопами новой порции, в сумме составив обычную четвёрку. Т. е. с точки зрения принимающей мопы очереди IDQ все переходы сглажены в равномерный поток кода — как в P4, но без кэша трасс.

А теперь любопытный момент — в строке допускается не более двух переходов, причём если один из них — безусловный, то он окажется последним для строки. Наш Внимательный Читатель сообразит, что на всю порцию допустимо иметь до 6 условных переходов (каждый из которых может сработать, не будучи при этом точкой выхода), либо 5 условных и 1 безусловный, который будет последней командой порции. Предсказатель переходов в ЦП Intel устроен так, что он не замечает условный переход, пока он хотя бы раз не сработает, и только после этого его поведение будет предсказываться. Но даже «вечносрабатывающие» переходы тоже подпадают под ограничение. Фактически это значит, что завершить исполнение мопов порции допустимо и до точки её выхода.

А вот аналогичный трюк со множественным входом не пройдёт — если происходит переход в уже закэшированную порцию, но по другому смещению в ней (например, когда там более одного безусловного перехода), то L0m фиксирует промах, включает фронт и запишет поступившие мопы в новую порцию. Т. е. в кэше допустимы копии для порций с разными входами и одинаковым, точно известным выходом (помимо ещё нескольких возможных). А при вытеснении кода из L1I в L0m удаляются все строки, точки входа которых попадают в любой из 64-х байт двух порций. Кстати, в кэше трасс P4 тоже были возможны копии, причём они существенно уменьшали эффективность хранения кода…

Такие ограничения уменьшают доступность пространства L0m. Попробуем подсчитать, сколько же его остаётся для фактического использования. Средний размер команды x86-64 — 4 байта. Среднее число мопов на команду — 1,1. Т. е. на порцию скорее всего придётся 8–10 мопов, что составляет 2 строки. Как было ранее подсчитано, L0m сможет сохранить 128 таких пар, чего хватит на 4 КБ кода. Однако с учётом неидеального использования строк реальное число будет, видимо, 3–3,5 КБ. Интересно, как это вписывается в общий баланс объёмов кэшевой подсистемы?

  • 1 банк L3 (фактически часть L3, в среднем приходящаяся на ядро) — 2 МБ;
  • L2 — 256 КБ, в 8 раз меньше;
  • оба L1 — по 32 КБ, в 8 раз меньше;
  • кэшируемый объём в L0m — примерно в 10 раз меньше.

Любопытно, что если найти в ядре ещё одну структуру, хранящую много команд или мопов, то ей окажется очередь ROB диспетчера, в которой умещается 168 мопов, генерируемые примерно 650–700 байтами кода, что в 5 раз меньше эффективного эквивалентного объёма L0m (3–3,5 КБ) и в 9 раз меньше полного (6 КБ). Таким образом, кэш мопов дополняет стройную иерархию различных хранилищ кода с разными, но хорошо сбалансированными параметрами. Intel утверждает, что в среднем 80% обращений попадают в L0m. Это значительно ниже цифры в 98–99% для кэша L1I на 32 КБ, но всё равно — в четырёх случаях из пяти кэш мопов оправдывает своё присутствие.

Диспетчер и планировщик

Переименование и размещение

Переходим к тыловой части. Первое крупное изменение — новые диспетчер и планировщик. Как и любой представитель этой стадии, диспетчер выполняет переименование регистров, размещение мопов в очереди ROB и резервации, приём завершённых мопов и их отставку. Каждый такт диспетчер принимает до 4 мопов от IDQ, прописывает физические регистры, помещает мопы в ROB (тоже до 4), разделяет слитые мопы на простые и отправляет их (до 6) в резервацию, связав каждый с нужным портом запуска (которых тоже 6). Очевидно, что в четвёрке принимаемых мопов допустимо не более трёх микро- или макрослитых, чтобы после разделения их можно было обработать за такт. Мопам обмена с памятью также выделяют ячейки в очереди загрузки или сохранения в LSU.

Некоторые мопы сразу после (или даже вместо) переименования указываются как незапускаемые:

  • любые нопы (до 4 за такт) — потому что они ничего не делают;
  • FXCH (обмен местами регистров x87-стека, до 2 за такт) — их «исполнение» заключается в переименовании пары регистров (в предыдущих ЦП только эта команда удалялась при размещении);
  • VZEROUPPER (1 за такт, потому что генерируются 4 неисполняемых мопа) — для обнуления старших половин всех регистров ymm (об этом позже);
  • классы обнуляющих и единичных идиом (zeroing idioms, ones idioms; 4 и 2 за такт).

К обнуляющим относятся команды, действие которых при указанных операндах всегда сводится к обнулению регистра-приёмника, хотя сами они специально для этого не предназначены. К таким SB относит все виды команд *XOR* (исключающее ИЛИ), *SUB* (вычитание) и PCMPGT* (векторная целая проверка на «больше»), все аргументы которых являются одним регистром (звёздочками заменены переменные части мнемоник разных версий команд). Поскольку результат предопределён, то считается, что никаких источников команде читать не надо, а потому она эквивалентна простому помещению константы 0 в целевой регистр. Явное обнуление в x86 не используется из-за особенностей ISA: для РОНов такая команда окажется длиннее идиомы, а для векторных регистров этого варианта нет вообще.

Само обнуление происходит за счёт того, что архитектурный регистр-приёмник перенумеруется на свободный физический регистр, помечаемый как содержащий нули (хотя реально там наверняка что-то другое). Потому «исполнять» такие мопы можно по 4 за такт, тогда как обычные *XOR*, *SUB* и PCMPGT* запускаются максимум тройками. Как-бы-нулевой регистр не читается из РФ, а в ФУ просто посылается сигнал, что этот аргумент — константа 0. Правда, анализа на 0 результатов вычислений в ФУ и загрузок из кэша не происходит (хотя флаг Z после большинства операций в АЛУ показывает именно это), так что 0 в регистре может оказаться и после необнуляющих команд с последующим штатным чтением — диспетчер о нём просто не узнает.

К обнуляющим также относится команда CLC, сбрасывающая флаг переноса. Поскольку 4 основных флага (перенос, переполнение, ноль и знак) также переименовываются, CLC по нашим тестам также может «исполняться» 4 раза за такт, хоть это и бессмысленно. Впрочем, представитель Intel заявил, что к CLC заочное обнуление не относится… Ещё одна группа команд, сокращающаяся подобным образом — единичная идиома PCMPEQ* (векторная целая проверка на «равно»). По аналогии с обнуляющими, при одинаковых аргументах она всегда устанавливает все биты приёмника в «1». Однако, в отличие от «обнулятелей», такому мопу всё же надо исполниться в любом из двух портов, куда обычно попадают эти команды — удалённо отметить регистр как содержащий единицы диспетчер не может, их надо записать явно.

Новый старый стиль

Прежде чем рассказать о само́м планировщике, вспомним основные различия между ними в нашей Энциклопедии. Точнее, нас интересует «хранящий» вариант с несколькими РФ и «ссылочный» с одним (физическим). Первый более привычен, т. к. применялся во всех x86-ЦП с внеочерёдным исполнением, за исключением всех P4. А второй был в P4 — и вот сейчас вернулся в SB. Может быть, Intel что-то перепутала, внедрив в новую экономную архитектуру блок из старой Netburst, представители которой «прославились» тепловыделением? (Также его применяют во всех серверных ЦП IBM POWER, которые ещё выше по частоте и ещё жарче.) Однако планировщик к этому точно не был причастен, а очень даже наоборот — именно вариант с физическим регистровым файлом (ФРФ), как ни странно, оказывается самым экономным.

До сих пор все основные процессы в планировщике (от размещения до отставки) требовали перемещения мопов вместе с накопленными в них данными, что требовало довольно много энергии (вспомните длину мопа и добавьте биты регистров-операндов). Вариант с ФРФ копирует или меняет не сами значения, а только 8-битные (в данном случае) ссылки на тот регистр в ФРФ, где они хранятся. Ещё одно преимущество такой схемы в снятии ограничения на число чтений из РФ. Дело в том, что в старой схеме основным РФ в исполнительном тракте был спекулятивный (СРФ), а вторичным — архитектурный (АРФ). Размер СРФ должен быть достаточен, чтобы держать аргументы и результаты всех хранящихся в резервации(ях) мопов, а размер АРФ, разумеется, будет совпадать с числом регистров данного типа согласно ISA.

Проблема была в том, что у АРФ лишь 3 порта чтения (а в Pentium II и III — 2), и при переименовании регистров 3–4 размещаемых мопа могут за такт прочесть (и скопировать в свою ячейку ROB) лишь небольшое число регистров, которые достаточно давно не менялись, чтобы их значения уже успели попасть из СРФ в АРФ при отставке. Учитывая, что у каждой целочисленной и AVX-команды число читаемых регистров может достигать трёх, разместитель не справился бы за такт со сбором всех нужных данных для четвёрки мопов. При использовании единственного РФ число его портов достаточно большое (по нашим тестам, в SB — 10 чтений и 5 записей), чтобы за такт прочесть и записать всё необходимое.

Поскольку каждый моп теперь не накапливает содержимое регистров, обе очереди тыла (ROB для диспетчера и резервация для планировщика) могут при той же площади хранить большее число мопов: 128 и 36 ячеек в ROB и RS Nehalem подросли до 168 и 54 в SB. Это значит, что планировщик теперь может отслеживать зависимости команд в более длинном куске кода, получая возможность одновременно запустить даже далёкие друг от друга команды. Это особенно пригождается при исполнении двух потоков, делящих между собой большинство ресурсов, включая обе этих очереди (опишем потом, как именно). Размеры же ФРФ такие — 160 64-битных РОНов и 144 256-битных векторных регистра. Правда, на самом деле векторных РФ два, каждый из которых хранит 128-битные половины. Почему так?

Исполнительная стадия

Тракты данных

Для ответа на вопрос выше снова сделаем исторический экскурс. Давным-давно, в далёкой-далёкой… гм, эпохе 70-х и 80-х гг. процессоры обрабатывали лишь целые числа, а потому исполнительный тракт у них был один, на 8/16/32 бита. Затем добавился вещественный тракт на 64/80 бит (архитектуре x86 в этом смысле пришлось труднее, потому что расширенную 80-битную точность больше нигде не внедрили). Далее, рассматривая только ЦП Intel, последовал набор MMX, который архитектурно хоть и использовал стек x87, но физически имел не только отдельные ФУ, но и регистры. Потом добавлен SSE — хотя для программиста регистры xmm 128-битные, векторные РФ и ФУ до Core 2 были 64-битными и тоже отдельными. Правда, когда SSE2 расширил целочисленную обработку до 128 бит, для этих ФУ нового РФ не создали, а просто переделали блок MMX, чтобы его РФ и ФУ могли хранить и обрабатывать и половинки 128-битных регистров.

В Core 2 структура исполнительного блока окончательно приобрела нынешние очертания. 64-битный целочисленный тракт работает с командами общего назначения, первый 128-битный — с целочисленными векторами, а второй 128-битный — с вещественными векторами и скалярами (включая x87). Вспомним, что при исполнении SSE-кода переключаться между целым и вещественным режимом не надо (в отличие от режимов MMX и х87), и каждый регистр xmm может хранить и целые, и вещественные значения. Но т. к. физически они хранятся и обрабатываются в разных РФ и доменах, возникает вопрос о доступности нужных данных нужному ФУ, если они находятся в соседнем тракте. Чтобы перемещений между векторными трактами было как можно меньше, в каждом их них есть блоки для наиболее частых команд — в частности, логических и некоторых перестановок. Но т. к. ФУ отдельные, то и команды для них Intel тоже решила сделать отдельными — и вот в x86 появилась такая химера, как «вещественная логика». Как-нибудь мы поговорим об этом звере, а пока договоримся обозначать такие ФУ как FLOG. Аналогично, ФУ для «целочисленной логики» назовём ILOG.

Пересылки данных между векторными трактами весьма редки благодаря наличию большинства нужных ФУ на каждом из них. Схема исполнительной стадии в Nehalem (не считая ФУ, используемых некоторыми редкими командами) выглядит так:

Тракт→ 64 бита,
целый1
128 бит №1,
целый
128 бит №2,
вещественный
Порт 0 АЛУ2
Сдвигатель
АЛУ
Перестановщик
F MOV (x87)
F MUL
F DIV
Порт 1 АЛУ
IMUL
AGU3
MOV
ILOG
IMUL
Сдвигатель
F ADD
Конвертер4
Порт 5 АЛУ
Сдвигатель
АЛУ
Перестановщик
FMOV (SSE)5
FLOG
Перестановщик

Не указаны порты: №2 для вычисления адреса чтения и самого чтения из памяти, №3 для вычисления адреса записи и №4 для самой записи.
1 — Не указан скалярный целочисленный делитель: он получает мопы со всех трёх портов при любом виде деления.
2 — Напомним, что АЛУ работают только с целыми числами и, помимо арифметики и логики, выполняют также копирования (MOV).
3 — Это ФУ исполняет только команду LEA: вычисление адреса как для операции чтения, но с помещением в приёмник самого́ адреса (иногда используется как замена некоторых арифметических команд). Аналогичный блок в порту 2 вычисляет адреса для «настоящих» чтений, выполняя дополнительные неарифметические операции.
4 — Преобразователь арифметических форматов (между двумя вещественными или вещественным и целым). Для некоторых команд использует один из вспомогательных ФУ, получающих мопы с других портов.
5 — «Вещественные копирования», ещё одна химера, когда речь идёт о векторном регистре целиком.

И тут на сцену выходит набор AVX и его 256-битные регистры ymm. Как их обрабатывать? Основных вариантов три:

  • Не менять ФУ, обрабатывая регистры половинками, как это было с xmm до Core 2;
  • Поставить отдельный тракт или расширить один из имеющихся, снабдив его необходимыми и «полноширными» ФУ;
  • Снабдить недостающими ФУ оба нынешних тракта, чтобы они могли работать над регистром ymm одновременно.

Нетрудно догадаться, какой вариант был выбран, учитывая, что процессору надо и скорость вычислений поднять, и энергию (обязательно) с площадью (желательно) сэкономить. Правда, по причинам, описанным далее в главе об AVX, добавлен только вещественный домен в бывший целочисленный тракт, который мы теперь назовём смешанным. После добавки и перетасовки ФУ в SB получилось вот что:


От центра вверх — 3 исполнительных тракта SB (в порядке, указанном в таблице). 5 структур ниже центра — 64-битные РФ (4 из них попарно объединены). Внизу — диспетчер и планировщик.
Тракт→ 64 бита,
целый1
128 бит №1,
смешанный
128 бит №2,
вещественный
Порт 0 АЛУ
Сдвигатель
MOV
ILOG

IMUL+FMUL1
Сдвигатель
FMOV (x87, AVX)
FMUL
IDIV+FDIV2
Порт 1 АЛУ
IMUL
Сложное AGU
АЛУ
FADD
Конвертер

Перестановщик
FADD
Конвертер
Порт 5 АЛУ
Сдвигатель
АЛУ3
Сдвигатель
Перестановщик
FMOV (SSE, AVX)
FLOG
Перестановщик

Не указаны порты: №2 и №3 для вычисления адресов и чтения из памяти и №4 для записи. Жирным указаны добавленные ФУ, курсивом — перемещённые, подчёркнутым — спариваемые.
1 — Универсальный умножитель для векторных целых и всех вещественных.
2 — Универсальный делитель для скалярных целых и всех вещественных. (Деления векторных целых в x86 нет.)
3 — Спариваются блоки копирования и логики.

Обратим внимание, что в Nehalem до полноценного АЛУ порту 1 не хватало лишь сумматора — логика и копирование там и так исполнялись. В SB целочисленные блоки портов 0 и 1 целиком поменяли местами, потеряв только отдельный умножитель, но почему-то не добавив на его место сумматор. Также нужно пояснить, почему, начиная с Pentium Pro, мопы записи разбиваются отдельно на вычисление адреса и саму запись. Во-первых, в элементарном мопе (в отличие от слитого) нет места и для данных, и для компонент адреса. Во-вторых — это часто позволяет заранее вычислить адрес, что поможет как можно раньше определить возможные адресные конфликты с чтениями (подробней об этом — далее).

Конфликты завершения

Теперь на секунду вернёмся к планировщику. Иногда встречается такая ситуация: некая команда после запуска исполняется в течение X тактов, но через Y тактов (Y

Теперь каждый из трёх вычислительных портов может за такт принять завершение до трёх мопов с разных трактов (правда, в сумме со всех портов — вряд ли больше 6). До сих пор такими параметрами могла похвастать лишь AMD, у которой раздельные 3-портовые планировщики для целочисленного и векторно-вещественного трактов запускают и принимают на пару 6 мопов/такт. Однако даже там не удалось обойти проблему переменной задержки некоторых команд — прежде всего это деление и вся трансцендентная арифметика. Время исполнения этих операций зависит от содержимого аргумента(ов) — например, для скалярного вещественного деления и извлечения корня в SB это 10–24 такта. В этих случаях в старых ЦП резервация просто блокировала порт с медлительным делителем, пока он не завершал работу. Затем ЦП обеих компаний научились принимать стоп-сигналы от всех ФУ (а не только от делителя-извлекателя), но только один за такт (если завершаемых мопов в данном порту больше — они становятся в очередь). И вот SB удалил возможную задержку, принимая 3 завершения за такт (очередь возможна лишь среди ФУ, совпадающих и по номеру порта, и по тракту). Правда, для этого ему пришлось приделать к некоторым командам временны́е балласты, но об этом — позже.

Межтрактные шлюзы

Пересылка данных между трактами обычно занимает заметное время (на Nehalem в большинстве случаев — 2 такта). Как с этим в SB? Оказывается, декодер для ряда команд вставляет специальные мопы, использующие некоторые ФУ как межтрактные шлюзы: с 64-битного тракта в любой 128-битный — через порт 0, обратно — через 5-й, а между 128-битными работают оба. «Настоящие» шлюзы, как и ранее, иногда вызывают задержку в 1 такт при переходе между целыми и вещественными SSE-операциями, хотя теперь они являются доменами одного тракта. Зато задержек в 2 такта уже почти нет. Судя по нашим тестам, передача между трактами обычно занимает 1 такт, но для шлюза в порту 0 может быть и бесплатна — возможно, он физически находится ближе к «своим» ФУ и успевает срабатывать вместе с ними.

Вспомним, что для AVX-кода доступен 256-битный перестановщик. Если исполняется команда, не требующая пересылки элементов между трактами, то её задержка такая же, как и для SSE-версии, т. к. использует 2 ФУ для половинок ymm. В противном случае используется полнодуплексный межтрактный перестановщик на 256 бит, причём его задержка в 1 такт присутствует, даже если фактически данные между трактами не передавались. Все шлюзы являются частью исполнительного конвейера — т. е. одновременно допускается использование ФУ и межтрактных пересылок.

Вещественные денормалы

Стандарт IEEE-754, который используют почти все современные процессоры для представления вещественных чисел, имеет такую особенность: когда экспонента E установлена в 0, а содержимое мантиссы M ненулевое, число интерпретируется не в нормальном виде (1,M⋅2E), а «денормальном» (0,M⋅2Emin, где Emin — минимальная «нормальная» экспонента). Обработка таких чисел (а также бесконечности и неопределённости) на ЦП Intel всегда была замедлена на сотни (!) тактов из-за микропрограммного получения результата. (Яростные фанаты Противоположного Лагеря могут гордиться своим кумиром — у AMD как минимум начиная с первых Athlon денормалы почти не замедляли вычисления, а бесконечности и неопределённости даже ускоряли.)

Проблема настолько велика, что для векторных вещественных вычислений Intel ввела в x86 специальный «облегчённый» режим DAZ ([assume] denormals are zero — считать денормалы нулями), идущий ради производительности несколько вразрез с мировым стандартом. В SB большинство подобных ситуаций разрешаются аппаратными механизмами, что кардинально повысило скорость обработки денормалов (и серьёзно уменьшило размер микрокода). Теперь лишь умножение изредка может вызвать небольшую дополнительную задержку. Это может значительно ускорить код, работающий с очень близкими к нулю числами — например, при вычислении знаменателей суммы ряда, что требуется для большинства трансцендентных функций.

Частичный доступ к регистрам

Очередная сложность, возникающая при разработке процессора — архитектурное допущение читать и менять часть какого-либо регистра. В x86 это применимо к РОНам, xmm и ymm — причём последний случай настолько особый, что этому посвящена целая глава. Тут же опишем проблему в целом на примере 64-битного РОНа.

Архитектурно программист может использовать регистр целиком, младшие 4 байта, младшие 2 байта и младший 1 байт. Для первых 4 РОНов есть ещё доступ ко второму байту, но для всех x86-ЦП уже давно рекомендуется настоятельно забыть эту возможность — трудностей хватает и без этого. При очередном архитектурном удвоении разрядности регистров у инженеров есть несколько вариантов реализации доступа к новым и старым регистрам как полностью, так и частично:

  1. Сделать отдельные архитектурные РФ для регистров нужной разрядности — как при переходе от 64-битных регистров mm (для MMX) к 128-битным xmm (которые, правда, не сразу можно было использовать для целых чисел, так что ФУ у них поначалу были разные). Выгода — нет зависимостей по данным (как если бы каждый xmm содержал бы в своей младшей половине mm с тем же номером). Минусов больше — требуются спецкоманды для перемещения данных между старым РФ и новым, а архитектурное состояние для сохранения вырастает не на 64, а на 128 байт (тогда регистров было ещё 8). Сегодня же, когда x87 и MMX уже устарели, их содержимое всё ещё надо сохранять (кроме случая с применением новой команды, как будет описано ниже).
  2. Сделать отдельные физические РФ для младших частей регистров — как во всех ЦП Intel от PPro до PM включительно (кроме P4). Правда, из-за дополнительных затрат это применяется лишь к младшим байтам РОНов — остальные части используют другие методы. Как и в случае выше, зависимостей нет — переименованный 8-битный регистр N хранится отдельно от 32-битного с тем же номером. Однако есть штраф, когда части регистра должны объединиться, чтобы быть обработанными другой командой.

    Пример: команда-1 обработала младший байт 32-битного РОНа, а следующая команда-2 читает его целиком. Вроде бы всё решается просто — команда-1 записывает изменённый байт не в «байтовый», а в основной (полноразрядный) РФ, а затем этот регистр читается весь. Но при внеочерёдном исполнении состояние старших трёх байт читаемого архитектурного регистра достоверно известно лишь при отставке, когда спекулятивый РФ записывает в архитектурный результаты готовых мопов. А значит при частичном доступе команда-2 вынуждена ждать 5–7 тактов до отставки команды-1.

  3. То же, что и выше, но части регистра могут объединяться в шлюзе при ФУ — это используется для РОНов в ЦП Intel с Core (первых) по Nehalem. При этом разместитель диспетчера автоматически вставляет дополнительный синхромоп, встраивающий только что записанный байт из «байтового РФ» в младший байт соответствующего ему регистра «полного РФ». Штраф в такой ситуации — 2–3 такта, т. к. достаточно дождаться завершения (не отставки) лишь последней команды, пишущей в данный регистр.
  4. Хранить регистры в цельном РФ, но получать доступ отдельными частями: для 64-битного РОНа — 1+1+2+4 байта, для xmm — 4+4+8 (напомним, что в наборах SSE есть скалярные вещественные команды, обрабатывающие только младший SP- или DP-элемент вектора). Применяется в Intel Core (2) и Nehalem — только для xmm, а в ЦП AMD и Intel Pentium 4 — и для РОНов, и для xmm. Никаких штрафов при использовании и даже слиянии регистров нет (т. к. синхромопы не используются), но существует ложная зависимость, когда запись в часть архитектурного регистра всегда считается зависящей от предыдущих записей в этот регистр — частичных и даже полных, когда он целиком перезаписывается.

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

  5. Как выше, но во избежание ложных зависимостей запись в часть регистра сбрасывает в 0 остальную часть — это применяется при 32-битных операциях с 64-битными РОНами на всех ЦП (чтобы не ставить отдельный РФ для 8-байтовых версий регистров в дополнение к 4- и 1-байтовым), а также (как мы увидим ниже) при 128-битных командах AVX с регистрами xmm, т. е. младшими половинами ymm. Оба решения, очевидно, являются архитектурными.
  6. Программист или компилятор явно удаляет зависимость частей регистра, обнуляя его целиком или частично до использования как приёмник. Этот способ также используется в AVX, причём с немалым подвохом.

Теперь, когда все варианты перечислены, — на чём же остановились авторы SB? Для РОНов теперь используется метод №4, как и для xmm/ymm — в Nehalem же при частичной обработке РОНов надо было ждать лишние 3 такта. Исключение составляют «старшие» байтовые регистры (от AH до DH), которые всё же могут отдельно переименовываться. Но, как подсказывает Внимательный Читатель, есть ещё один ресурс, который и переименовывается, и читается-пишется (причём частично — куда чаще, чем полностью): 4–6 самых используемых флагов.

До сих пор ЦП использовали к ним подход №2, но SB перешёл на модифицированный вариант №3: флаг переноса (C) переименовывается отдельно, а для остальных имеется сливающий моп. Что это даёт? Вот типичная ситуация: в конце цикла команда INC или DEC меняет его параметр, записывая флаги нуля и знака в поле флагов физического регистра (имеется только для РОНов). Затем условный переход проверяет флаг нуля или знака — никаких проблем, они только что изменились. Но если условный переход читает флаг переполнения, либо попалась команда сохранения всех флагов в стек — придётся ждать, пока команды, менявшие оставшиеся 2 флага, уйдут в отставку, чтобы выделить нужный бит или их все. И вот SB сократил этот штраф примерно вдвое. Если же читается флаг переноса — то штрафа нет вообще.

Т. к. остальные флаги всё ещё держатся вместе, это создаёт любопытные эффекты — например, для команд сдвига. Дело в том, что согласно ISA вытесняемые биты должны попадать во флаг переноса, причём если параметр сдвига более 1, то попадёт только последний бит. Так вот этот вариант до сих пор вызывал парадоксальную зависимость флага переноса от своего же старого значения — после такой команды чтение только что изменённого флага всё равно приводило к штрафу. В SB такого штрафа нет, зато синхромопы для слияния флагов теперь всегда вставляются после многобитных вращений. В результате задержка получения результата вращения в регистре-приёмнике — 1 такт, а во флагах — 2–3.

AVX

Реализация

Главным новшеством в исполнительной стадии является добавление недостававших ФУ, чтобы вкупе с уже имеющимися суметь исполнить любую операцию с региcтрами ymm (кроме деления и извлечения корня) в полноконвейерном варианте и одновременно над всем вектором. Но как же получается, что несколько ФУ, которые надо задействовать для исполнения операции, находятся в одном порту? Ведь, как мы знаем, каждый порт может за такт запустить 1 моп… И тут на помощь приходит второе новшество, без которого первое не имело бы смысла — впервые среди процессоров (именно процессоров вообще) запускаемый через порт резервации моп может активировать более одного ФУ: в данном случае — пару одинаковых, потому в таблице выше они и названы спариваемыми. Таким образом за такт можно исполнить 3 256-битные AVX-операции, активировав 6 ФУ!

Но где восклицание — там и половник дёгтя: т. к. AVX-моп один, использовать два ФУ из пары отдельно не получится. Запустить 128-битные SSE-команды (да и 128-битные AVX) тоже можно лишь 3 за такт, так что на имеющемся коде, не знающем ни про какой AVX, почти половина векторных ФУ нового ЦП будет простаивать (разумеется, в выключенном состоянии для экономии), не принеся никакого ускорения. Очевидно, Intel делает большую ставку на активное использование AVX в обновлённых версиях ПО. Но и тут безоблачного будущего не предвидится — и не только потому, что внедрение нового часто происходит медленно…

Подножка

Как мы помним из исторического экскурса выше, иногда содержимое xmm-регистров перемещается через шлюзы в соседний векторный тракт, где местное ФУ производит с ним некую операцию. Результат при этом почти всегда записывается в местный же РФ, так что если следующая операция, которую требовалось исполнить над этим вектором, снова должна использовать местное ФУ — данные уже на месте. А теперь представим себе, что в SSE-код программист-оптимизатор добавляет вручную написанную процедуру с использованием команд AVX и регистров ymm, младшие половины которых, как мы помним, совпадают с регистрами xmm с тем же номером. Поскольку при исполнении AVX-команд 1-й («смешанный») векторный тракт работает только с младшей половиной ymm, а 2-й — только со старшей, это может потребовать обмена местами неверно расположенных половин регистра, для чего перед каждой операцией придётся проверять, где они расположены. Intel решила проблему иначе.

Для SB схема использования двух трактов изменилась: теперь на 1-й тракт попадают всё регистры mm, xmm и младшие половины ymm, а на 2-й — стек х87 и старшие части ymm (причём в регистрах с теми же номерами, что и для младших половин). Таким образом все векторные команды, кроме 256-битных AVX, используют 1-й векторный РФ для хранения всех операндов и устройства 1-го тракта для исполнения (опять же, без делителя-извлекателя — это ФУ, видимо, просто не уместилось). При работе с командами MMX, SSE и 128-битных версий AVX 2-й РФ не используется, а только хранит своё содержимое. И вот с SSE есть сложность.

Команда SSE, записывающая в некий регистр xmm, сохраняет содержимое старшей половины соответствующего ему регистра ymm, а вот аналог этой команды из набора AVX, работающий с этим же регистром xmm, согласно ISA обнулит старшую часть своего ymm. Ситуация бы упростилась, если бы все программы использовали только 128-битные векторы или только 256-битные. Но всё хуже: 2-й РФ не просто хранит старшие половины ymm — он лишь отслеживает положение соответствующих им младших половин в 1-м РФ, но свои половины синхронно не перемещает. Пример: команда SSE «ADDPD xmm1, xmm2» складывает пару вещественных DP-элементов регистра xmm2 с аналогичной парой из xmm1 и записывает на место последнего результат. После переименования регистров моп команды приобретёт неразрушающий формат операндов и будет выглядеть, например, так: «ADDPD xmm78, xmm34, xmm56» — т. е. до его исполнения архитектурному регистру xmm1 соответствовал физический xmm34, xmm2 — xmm56, а после отставки xmm1 будет назначен на xmm78. А теперь вопрос на засыпку — что будет со старшей половиной регистра ymm1?

Решение

Если бы команда была «VADDPD xmm1, xmm2» (префикс V- используется во всех командах AVX, включая работающие с xmm), то ответ ясен — старшую половину архитектурного xmm1 надо обнулить, что делается разместителем даже без доступа в РФ. А вот для SSE-версии её надо сохранить, что для 2-го РФ означает копирование физического регистра №34 в №78. И это только для одной команды, а всего их может быть до 5 за такт (3 вычислительные и 2 загрузочные). Intel могла бы оснастить старший РФ 5-полосным шлюзом с портов чтения на порты записи, а переименователь — возможностью слежения за половинами ymm отдельно. Но для упрощения и/или экономии инженеры вместо этого внедрили небольшой «теневой» АРФ, хранящий 16 старших половин регистров ymm, когда они не используются SSE-кодом. (Возможно, поэтому для РОНов физических регистров 160, а для xmm/ymm — 144, хотя планировщик общий…) Причём, АРФ должно быть даже два — по одному на поток.

Теперь, допустим, надо исполнить 256-битную операцию с регистром ymm1. Вероятно, планировщик должен подать векторным РФ номера обеих половинок (старшую — из АРФ), считав их содержимое в пару ФУ… Но оказывается, что напрямую из АРФ читать мопам нельзя. Поэтому не будет SB исполнять 256-битную команду AVX сразу после SSE. Вместо этого грянет аж 70-тактовый штраф, в течение которого сначала должны исполниться уже запущенные в резервацию команды (сериализация конвейера), а затем специальная микропрограмма восстановит все 16 старших половин ymm. Более того, и 128-битную AVX-команду тоже ждёт штраф — в АРФ нельзя даже обнулить регистр без выгрузки в основной РФ. Тот же штраф будет при при обратном переходе — когда после AVX-кода встретится любая команда SSE, и старшие половины потребуется сохранить обратно в АРФ. Но если штраф будет происходит часто, программисты хором пошлют AVX на всякие другие буквы, возопив «Как жить дальше?!»

Ответ Intel — «надо чаще обнуляться». В составе набора AVX есть команда VZEROUPPER, сбрасывающая старшие половины всех регистров ymm всего за 1 такт. После этого все связи между половинами можно считать исправленными, т. к. для любого регистра xmmN старшая часть ymmN содержит 0. Переходы между 128-битным и 256-битным векторными кодами не вызовут штраф, т. к. в старших частях точно нули. На физическом уровне АРФ не сбрасывается, а помечается как целиком нулевой, так что его уже не надо грузить в основной РФ. Но произвести сериализацию всё же придётся…

Вспоминая программиста-оптимизатора, во избежании штрафа он должен поставить VZEROUPPER перед вызовом оптимизированной AVX-процедуры и после него. Если процедура находится в библиотеке, вызывать которую может как программа с кодом SSE, так и с AVX, то VZEROUPPER должна быть и в прологе, и в эпилоге каждой функции. Тут может быть полезна ещё одна команда VZEROALL, обнуляющая все регистры ymm целиком. Тем не менее, можно предсказать, что программисты наверняка часто будут забывать вставить команды VZERO* в свой ассемблерный код. Выловить же эти ошибки трудно, т. к. программа всё ещё будет работать, хоть и медленнее, но мало ли на то причин…

Кстати: само существование 128-битных команд AVX в дополнение к таким же, но 256-битным — тоже своего рода костыль. Только на этот раз не для нахождения очередного компромисса внутри процессора между сложностью, скоростью и площадью. Дело в довольно большом объёме кода драйверов и даже компонентов ядер разных ОС, которые используют xmm и точно не будут скоро переписаны под AVX. А значит и общаться с ними надо на «128-битном языке». Но т. к. соблазны AVX-кодировки велики (представитель Intel даже как-то сказал, что неразрушающий формат и компактизация кода в сумме дадут не меньший эффект, чем удлинение векторов), компания решила дать программистам шанс ускорить и 128-битный код, чтобы не переключаться каждый раз со штрафами между SSE и полноразрядным AVX. Впрочем, за счёт своей многочисленности сообщество программистов ядра Linux вполне быстро бы перевело эту ОС на новый формат (будь он обязательным). Поэтому можно сделать вывод, что в сложностях устройства AVX виновата … Microsoft! :)

Сохранение состояния

После удвоения разрядности векторных регистров размер полного описания архитектурного состояния ЦП стал больше на 256 байт — теперь в нём все регистры общего и специального назначений, стек x87 и набор ymm занимают 832 байта. При прерывании и переключении контекста задачи всё это надо как можно скорее записать в специальную область памяти, а при возврате восстановить. А т. к. задержка (особенно для прерываний) должна быть минимальной, объём пересылаемых данных оказывается тому препятствием. В SB регистры общего и специального назначений записываются всегда (впрочем, они и меняются всегда), но есть специальный блок, отслеживающий 3 остальных РФ — стек x87 с регистрами mm для MMX, и старшую и младшую половины регистров ymm для SSE и AVX. Сохраняться и восстанавливаться будут только РФ, модифицированные за текущий сеанс работы с задачей. Например, программа, работавшая лишь с РОНами, сохранит в статусе всего около 100 байт. Однако это произойдёт не автоматически, а при использовании добавленной команды XSAVEOPT, поддержка которой обозначается отдельным битом в CPUID.

Динамические тайминги

При тестировании задержек и пропусков команд (о чём мы детально поговорим далее) мы обнаружили у AVX-кода некую странность, которой «не может быть никогда». Точнее, речь идёт о векторном вещественном сложении (вычитании) и умножении. В идеале, они, как и почти все остальные команды, должны иметь фиксированные тайминги — однако в наших тестах (если, конечно, всё было замерено точно) получилось совсем не так. Судя по всему, в случае долгого неисполнения вещественного кода блоки FADD и FMUL переходят в некое «полувекторное» состояние, когда 256-битные команды обрабатываются каждый 2-й такт, а задержки — на 2 такта больше нормы. Через несколько сот исполненных вещественных команд задержка уменьшается на 1 такт, а ещё через несколько сот, вместе с пропуском, наконец, становится номинальной. 128-битные операции также затронуты — задержка изначально на такт больше, но хоть пропуск не страдает.

Сразу скажем, что представитель Intel заверил нас, что это ошибка в наших тестах. Да и здравый смысл подсказывает, что ничего подобного в ЦП быть не должно. Т. к. требуется экономить энергию, отключая неиспользуемые подолгу блоки (что используется ещё со времён Pentium-M), инженеры наверняка оптимизировали время их включения до 1–2 тактов. А то, что планировщику оказывается куда трудней управлять потоком мопов в «полусонные» ФУ — и вовсе удаляет последние остатки здравого смысла. С другой стороны — никаких ошибок в нашей методике совместными усилиями мы так и не нашли. Тем более, что по такой же схеме были получены и остальные сотни цифр, которые по большей части подтверждены. Однако, если бы мы стали перепроверять все версии, статья бы вышла лет через пять. Тем не менее, проверка будет, пока же при дальнейших обсуждениях таймингов проигнорируем этот странный момент…

Новые и отсутствующие команды

В AVX 1-й версии входят 256-битные команды вещественной арифметики, логики и перестановок, но целочисленную арифметику и сдвиги почему-то оставили 128-битными — до выхода AVX2. Пока что для обработки регистра ymm с целочисленными значениями надо сначала сохранить его старшую половину в младшей половине другого регистра, затем обработать младшие половины обоих (старшие при этом обнулятся) и снова собрать в 32-байтовый вектор. Зачем так сделано, официального объяснения нет, а неофициальное примерно такое — вещественной арифметике большие векторы сегодня нужней, а целочисленной их добавят «потом», и пока выгодней обходиться командами AVX с регистрами xmm. Но ещё раз посмотрим на таблицу ФУ в SB — дополнив 2-й тракт сумматором и подключив его к порту 5, где уже есть блок логики и копирований, мы получили бы в нём полноценное 128-битное АЛУ, которое могло бы работать со своим «собратом по порту» из 1-го тракта. Зачем же добавлять 32-байтовые целочисленные векторы лишь через два года в AVX2, если почти всё уже готово?…

В ГП разных компаний и экспериментальном процессоре Intel Larrabee есть команды с векторными адресами — scatter и gather (разброс и сбор): запись и чтение вектора по индивидуальным адресам или смещениям его элементов, составляющим другой вектор. AVX же эти полезные во многих алгоритмах команды получит лишь во 2-й версии, т. к. для эффективного (т. е. параллельного, а не поэлементного) исполнения требуется серьёзное дооснащение кэша сложными коммутаторами в буфере строки (всей 64-байтовой строки, а не 16-байтового порта кэша). Пока это малосовместимо с требованиями поднять скорость без ущерба для площади и экономии, а потому откладывается до следующей микроархитектуры Haswell.

Но и у 1-го AVX есть, чем заполнить лакуну — команды чтения и записи с байтовой маской. Тут интересно, что замаскированные байты не только не считываются или записываются, но даже и не проверяются на возможность доступа. Например, невыровненное чтение, пересекающее границу страницы памяти, может вызвать кучу неприятностей (промах в кэше или TLB, запрет доступа и пр.), однако если все байты «на той стороне» оказываются с нулями в маске, никаких проблем не будет, т. к. фактический доступ и все проверки для них будут отменены. В отличие от команд разброса и сбора, дополнительных аппаратных блоков тут вводить не нужно, по крайней мере для Intel — уже в Nehalem кэши обладали почти всем нужным для такого функционала, просто теперь он программно управляем. Ещё одна новинка — команда «широковещания» (broadcast), копирующая элемент во все позиции вектора-приёмника (почему-то только из памяти в регистр).

Тайминги команд

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

Итак, к имеющимся командным группам добавлена ещё одна — для вещественных 256-битных команд AVX. За вре́менным неимением конкурентов (до выхода AMD Bulldozer) помечать синим эти клетки не будем. :) Сравнение SB по остальным командам прежде всего показывает увеличение общего IPC в каждой группе до рекордных 4, т. к. учитывались обнуляющие директивы, работающие в каждом домене (кроме x87, где вместо них — обмены регистров).

Если посмотреть на отдельные команды, то главные изменения по сравнению с Core i — умножения. Скалярное целочисленное стало полноконвейерным даже при получении полноразрядного результата, однако тут есть нюанс: указанные 3 такта (справедливые и для умножения 64⋅64=128 бит) это задержка перед получением младшей половины результата, отправляемой в регистр EAX (RAX); старшая, для регистра EDX (RDX), будет готова тактом позже. Это происходит потому, что целочисленный умножитель уникален наличием второго командного порта — основной (принимающий моп для записи EAX/RAX) подключен к 1-му порту резервации, а второй — сразу к двум остальным (0-му и 5-му), откуда он получает моп для записи старшей половины. Выходит, что умножитель как бы находится сразу на всех вычислительных портах. При этом приём мопов возможен парами каждый такт, так что в итоге умножение оказывается полноконвейерным.

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

Дело в том, что в погоне за упрощением (в т. ч. и по причинам экономии) производители ЦП часто делают таблицу таймингов в резервации общей для целой группы команд, даже если нужные ФУ могут обработать некоторые команды быстрее. Например, все основные вещественные команды в архитектурах AMD K7–10 исполняются за 4 такта: скалярные и векторные, одинарной и двойной (не для K7) точности, сложения-вычитания и умножения — во всех восьми комбинациях, хотя в каждой паре второй вариант явно сложнее. Но планировщику проще считать, что все такие команды исполняются за одинаковое время.

Intel такой подход до сих пор использовала только в Pentium II/III/M для команд SSE, что также видно по таблице: для 64-битных ФУ векторные команды должны быть не только полуконвейерными (т. е. с пропуском 2), но и с на единицу большей задержкой, чего как раз нет. Планировщик в Core 2/i стал более разборчивым и даёт отдельные задержки для сложений и умножений, причём для последних — в зависимости от точности. SB же вернул «округлённые вверх» упрощения для всех умножений.

Вообще-то такая стандартизация задержек началась ещё в Nehalem. Его резервация устроена так, что порт 0 выпускает мопы с задержками либо 1 такт, либо 4 и больше, порт 1 — 1 или 3 такта, а порт 5 — только 1. Правда, есть 2-тактовые мопы, запускаемые через все 3 порта, но один такт из пары тратится на межтрактный шлюз. Порты 2, 3 и 4 монопольно используются операциями с памятью и адресами аж с Pentium Pro. В SB изменился лишь порт 0, который теперь выпускает мопы с задержками либо 1 такт, либо 5 и больше (мопов на 4 такта, кажется, уже нет).

Стандартизация задержек повлияла и на команду LEA. В таблице ФУ для SB блок AGU указан как сложный. Это потому, что в сложные зачислены команды LEA, у которых адрес или RIP-относительный, или 3-компонентный (плюс ещё два редких случая), остальные (простые) считаются в АЛУ других двух портов за такт. «Сложное AGU» считает свои адреса аж за 3 такта, хотя AGU в Nehalem справлялось со всеми видами операндов за такт. Возможная причина кроется в том, что никакого AGU в тракте нет, а сложные операции делаются в АЛУ порта 1, но с дополнительным функционалом. Этого бы хватило, чтобы вычислить адрес за 2 такта, но «ленивый» планировщик не поймёт такой моп, так что его задержка «для совместимости» с портом 1 искусственно увеличена до 3 тактов.

Впрочем, нашлись исключения и из стандартов. Оказывается, не все векторные умножения исполняются в порту 0 — несколько целочисленных перенесены в порт 1, но при этом они сохранили задержку в 5 тактов. Причём сами эти команды мало чем отличаются от других векторных целочисленных умножений, так что неясна причина выделения им отдельного специализированного умножителя, который затем расположили в соседнем порту… Ещё страннее ситуация с командами сравнения векторов с целыми элементами: для каждой из 4 разрядностей элемента (от 1 до 8 байт) есть сравнения на «равно» и на «больше». Так вот из этих 8 команд 7 исполняются за 1 такт в любом из двух векторных целочисленных АЛУ (как и ожидалось, ведь сравнение по сути есть вычитание). Но вот отдельно взятая PCMPGTQ (сравнение 8-байтовых элементов на «больше») исполняется только в порту 0 и за 5 (конвейерных) тактов, хотя сложность операции точно такая же. Есть исключения и среди команд преобразования форматов, задержки многих из которых стали на 2 такта больше… В общем, если именно таким образом обновлённый планировщик экономит энергию, на всякий случай напомним: иная простота — хуже. ;)

Из других изменений следует выделить улучшенные тайминги некоторых видов команд скалярного сдвига и вращения. Утверждается, что это сделано специально для ускорения криптоалгоритмов, которым спецкоманды AES-NI не подходят, т. к. они заточены конкретно под шифр AES. Всё бы хорошо, если бы другие виды тех же самых команд, не используемые в криптокоде, в результате не замедлились. Например, двойные сдвиги в Nehalem исполнялись за 4 конвейерных такта. Теперь те из них, что имеют фактор сдвига в виде константы, готовы уже через 1 такт, причём сразу в двух ФУ, зато те, у кого этот операнд — регистр, стали полуконвейерными. Такие же тайминги оказались и у обычных сдвигов (хотя они проще), видимо снова ради стандартизации. Таким образом, почти на каждое улучшение в пропуске или задержке «популярной» команды найдётся ухудшение в исполнении команд менее популярных.

Кэши

В скобках указаны значения для Nehalem (если есть отличие).

Кэш L0m (новый) L1I L1D L2 L3
Размер 1536 мопов 32 КБ 256 КБ 1–20 (2–30) МБ
Ассоциативность 8 8 (4) 8 8 8, 12, 16, 20 (12, 16, 24)
Размер строки 6 мопов 64 байта
Задержка, тактов 3? 4 4–7 (4) 11–12 (10) ≈26–31 (≈35–40)
Число портов 2 1 3 (2) 1 1 на банк, 2–8 банков
(2 на кэш, 1–10 банков)
Разрядность портов 4 мопа 16 байт 64 байта 64? (32) байта
Частота
(f — частота ядра)
f f/2 Максимум всех f
(2,13–2,66 ГГц)
Политика работы Включающая Включающая
Свободная
Только чтение Отложенная запись
Общий для … Потоков ядра Всех ядер, включая ГП

L1D

Сразу скажем, что кэши L1I и L2 почти не изменились — у первого ассоциативность снова (как и до Nehalem) стала 8, а у второго чуть увеличилась задержка. Самое главное изменение в ядрах, касаемое кэшей, кроется в доступе к L1D, который теперь стал 3-портовым: к раздельным портам чтения и записи добавили ещё один для чтения. Кроме того, как уже было указано, в планировщике Nehalem 2-й порт вычисляет адрес чтения и исполняет само чтение, 3-й вычисляет адрес записи (только), а 4-й — исполняет саму запись. В SB же порты 2 и 3 могут и вычислить любой адрес, и исполнить чтение.

Внимательный Читатель сразу найдёт подвох: портов L1D — 3, а адресных генераторов — 2. При не более чем 16-байтовых обменах их устоявшийся максимальный темп составит 32 байта/такт (либо два чтения, либо чтение и запись). 32-байтовые операции каждым портом обслуживаются за два такта, причём вычисление адреса для конкретной команды происходит в течение первого из них. Так что для двух чтений и одной записи требуется три адреса в течение двух тактов — тогда при потоковых обменах один из трёх нужных адресов можно вычислить заранее в течение второго такта предыдущей 32-байтовой операции. Только так мы получим искомый максимум в 48 байт/такт.

Возникает довольно странный компромисс: три 16-байтовые операции за такт в потоке сделать нельзя. С другой стороны, за такт можно вычислить адреса для двух 32-байтовых обменов, но даже одно 32-байтовое чтение за такт не запустишь, потому что порты чтения не объединяются. Т. е. либо нам не будет хватать числа AGU (тех, что в портах 2 и 3), либо ширины портов, либо возможности их объединения.

Как мы знаем из теории, многопортовость в кэшах чаще всего делается не явная, а мнимая, с помощью многобанковости. Однако Nehalem нарушил это правило, внедрив 8-транзисторные битовые ячейки для всех кэшей ядра. Помимо большей экономии (об этом подробно рассказывалось в статье о микроархитектуре Intel Atom, который тоже применяет такую схему), это также даёт возможность получить истинную 2-портовость (чтение + запись), что и было использовано в L1D — никаких конфликтов по адресам в имеющихся 8 банках не было. В SB банков по-прежнему 8, а портов уже 3. Очевидно, конфликты неизбежны, но только среди адресов портов чтения.

Каждый банк L1D имеет ширину в 8 байт, вместе составляя строку, поэтому каждый из 16-байтовых портов использует 1–2 банка при выровненном доступе и 2–3 при невыровненном. Например, 8-байтовое чтение, пересекающее 8-байтовую границу, использует 2 банка, как и выровненное 16-байтовое. В SB конфликт происходит, если хоть один из банков, нужных одному чтению, также нужен и второму, причём для доступа к другой строке. Последнее означает, что если оба чтения требуют не только одинаковый(ые) банк(и), но и одинаковые номера строк в нём (них), то конфликта не будет, т. к. фактический доступ произойдёт один, и он обслужит оба обращения. В Nehalem, с его единственным чтением за такт, такого, очевидно, быть не могло.

Упомянув о невыровненном доступе, скажем и о более «грешных» делах — пересечении строки кэша, что обойдётся 5-тактным штрафом, и границы страницы виртуальной памяти (чаще всего — 4 КБ), что наказывается в среднем 24 тактами (ситуация требует сериализации конвейера). Причём последняя цифра малообъяснима, т. к. TLB, как мы увидим ниже, способны на одновременную обработку обеих смежных страниц — но даже при последовательном доступе двухзначной цифры получиться не может…

LSU

Изменений в LSU (контроллере L1D, который Intel упорно называет MOB) не меньше, чем в само́м кэше. Начнём с того, что очередь чтения удлинилась с 48 до 64 ячеек, а записи — с 32 до 36. Каждая ячейка привязана к одному мопу, а очередь записи хранит ещё и 32 байта данных (было 16). Очередь чтения хранит все команды считываний, но в каждый момент не более 32 могут обрабатываться на разных стадиях. Фактически, это отдельные диспетчер и планировщик, «ROB» которых хранит 64 мопа, а «резервация» — 32. Когда чтение завершено, моп удаляется из этой резервации, но остаётся в очереди чтения до отставки. Очередь записи хранит информацию до отставки предыдущих команд, когда ясно, что адрес, данные и сам факт исполнения команды верны, а значит её можно попытаться записать в кэш. Если попытка успешна — моп записи уходит в отставку, освобождая место и в очереди, и в ROB. При промахе или других проблемах запись задержится.

Как и все современные кэши, L1D является неблокирующим — после промаха он может принимать дальнейшие запросы одновременно с заполнением себя подгруженными данными. Кэш может выдержать даже 3 промаха/такт. Одновременно удерживается столько промахов, сколько имеется буферов заполнения. В SB, как и в его предшественнике, у L1D таковых 10, а у L2 — 16. Политика отложенной записи в L1D и L2 означает, что модифицированная строка остаётся в кэше до вытеснения, однако информация о факте её модификации (если до этого данные были «свежие») отправляется в теги соответствующей строки в L3.

Внеочерёдный доступ

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

Однако предсказатель оперирует только выровненными на 16 байт чтениями размером до 16 байт, а также выровненными 32-байтовыми — остальные будут ждать вычисления адресов всех предыдущих записей. Ещё одна проблема нового движка в том, что он предсказывает лишь младшие 12 бит адресов: если у записи и чтения они равны (даже если они не предсказаны, а точно известны), то чтение считается зависимым от записи. Т. е. фактически предсказывается лишь 8 бит адреса — с 5-го по 12-й. Возможно, ложная зависимость обусловлена тем, что в ячейках таблицы счётчиков нет поля, хранящего старшую часть адреса.

STLF

…серьёзно улучшен. Описывать громоздкие старые правила для Nehalem мы не будем, укажем сразу новые:

  • байты для чтения должны полностью содержаться в записи, вне зависимости от выровненности адресов и размеров операций; это эквивалентно следующему: W-байтовая запись по адресу A перенаправляется в R-байтовое чтение по адресу B, если A≤B и A+W≥B+R; далее указаны исключения:
  • если запись 16- или 32-байтовая — 4- и 8-байтовые чтения обрабатываются в пределах её 8-байтовых порций;
  • если запись 32-байтовая — все чтения, кроме 32-байтовых, обрабатываются в пределах её 16-байтовых половин;

Ясно, что STLF не может работать одновременно с внеочерёдной загрузкой: адреса записей должны быть известны точно, а не только 8 битами.

Задержки чтения

Видя такое благолепие, яростные фанаты Противоположного Лагеря немедленно требуют какого-нибудь негатива. К сожалению, и он нашёлся: во-первых, обещанные 11 тактов задержки при чтении L2 в наших тестах никак не получались меньше 12; аналогично с L3. Во-вторых (и это гораздо хуже), идеальные 4 такта задержки при чтении L1D доступны не всегда, потому что теперь надо смотреть не только в какой исполнительный домен загрузить данные, но и как вычисляется адрес. Напомним, что в x86 адрес обращения в память состоит из трёх компонент: регистр базы, регистр индекса (возможно, умноженный на масштаб 2, 4 или 8) и адресное смещение (явно указанное в команде). Сочетаться (сложением) они могут в любой комбинации. Как мы помним, в SB можно вычислить аж 3 команды LEA за такт (сложную и две простых), что втрое больше, чем ранее. :) А вот те адреса, что вычисляются в «правильных» AGU (в портах 2 и 3), дают уже втрое больше проблем, которых хватит аж на целую таблицу задержек чтения/записи (тут учтены и все межтрактные задержки на передачу данных):

↓ Свойства адреса \ Тип приёмника → РОН (x)mm x87 ymm
Смещение≥2048 ИЛИ есть индекс 5 6 7 7
Смещение<2048 И нет индекса 4 5 6 7

Учитывая такое безобразие, удивительно, как SB не только не провалил ни один из наших тестов, но даже нигде не оказался медленнее, чем Nehalem с его почти честным 4-тактным L1D. Можно аккуратно предположить, что AGU в портах 2 и 3 настолько просты, что могут за такт сделать лишь одно сложение, да и то с неполной разрядностью одного из слагаемых — иначе оно затянется на второй такт, как и 3-компонентное. Если бы речь шла о 10-гигагерцовом ЦП с конвейером на сотню стадий, это ещё было бы простительно, но тут… Впрочем, есть другой вариант.

Сначала поясним, почему, вопреки тенденции, для ymm-пересылки цифры не указаны как 8 и 7. В одном из патентов Intel указан такой способ переноса «больших» данных из кэша в тракты: учитывая, что межтрактовая задержка в шлюзах равна 1 такту (для смежных трактов), надо в начале считать старшие 16 байт, которые уйдут на самый дальний тракт (2-й векторный), а через такт — младшие, которым надо на один тракт (и такт) ближе — тогда обе половины окажутся на местах синхронно. Вычисление адреса делается «впритык» к самому чтению (если ему ничего не мешает, например занятость портов или незавершённость записи по «подозрительному» адресу). Для этого AGU автоматически прибавляет к смещению 16, а возможно — вычисляет адреса обеих половин одновременно, что может объяснить медлительность при «сложной» адресации. В простом случае 32-байтовое чтение больше ничем не будет отличаться от 16-байтового, но если слово пересекает границу строки кэша, то теги читаются для двух строк, а если и границу страницы памяти — то и в TLB делается второе обращение. Тот же подход используется и при ymm-записях.

TLB

В скобках указаны значения для Nehalem (если есть отличие).

Параметр TLB L1I TLB L1D TLB L2
Размер страницы 4 КБ 2/4 МБ 4 КБ 2/4 МБ 1 ГБ 4 КБ
Размер 128 8+8 (7+7) 64 32 4 (0) 512
Ассоциативность 4 8 (7) 4 4 4 (–) 4
Задержка, тактов 1, учтена в задержке к кэшу 7
Число портов 1 2 1
Политика работы Скорее всего, включающая (для 4 КБ)
Общий для потоков? Да Нет Да

Изменения в подсистеме TLB небольшие: DTLB (так Intel называет TLB L1D) обзавёлся «честной» секцией для «сверхбольших» страниц по 1 ГБ. Впервые их поддержка появилась в AMD K10, а у Intel — в Westmere, однако в последнем они разбивались на множество «просто больших» страниц по 2 МБ и хранились в соответствующей секции TLB. ITLB (TLB L1I) получил две дополнительные ячейки для больших страниц, а STLB («shared TLB», т. е. разделяемый TLB L2) не изменился. Кстати, последний в Nehalem назывался UTLB (unified, единый), а вот для SB кэш L3 на большинстве слайдов переименовали в LLC (last level cache — кэш последнего уровня)… Кажется, кто-то в Intel обожает плодить сущности без необходимости. И кого ж они запутать хотят? :)

Суть странной записи «8+8» вместо «16» раскроется в главе о Hyper-Threading, а вот вопросы «Являются ли все или некоторые TLB неблокирующими?» и «Сколько промахов они могут удержать?» пока и вовсе останутся лишь с догадками «нет» и «нисколько». Зато известно, что при промахе в TLB L2 происходит обращение в адресный транслятор (PMH), на что уходит около 10 тактов. Это подозрительно мало, т. к. трансляция 64-битного виртуального адреса в физический (транслируются, правда, только биты с 13-го по 48-й) требует до 4 чтений из памяти или кэша. Столь быстрая реакция возможна, только если у PMH есть свой кэш. Его параметры и детали работы определить крайне трудно (уж очень тщательно скрыты задержки), но по известным примерам в предыдущих ЦП Intel предположим, что 32 ячейки наверняка найдутся. Точно известно только, что PMH может читать дескрипторы страниц откуда угодно — от L1D до памяти.


Жёлтая структура слева — L1D, внизу-слева — TLB L2, остальное пространство — LSU. В центре видны два почти одинаковых вертикально вытянутых блока — видимо, это TLB L1D.

Таблица выше является настоящим испытанием для Внимательного Читателя. Но подвох обнаруживается быстро — кэш L1D стал 3-портовым (надо полагать, вместе с тегами), а вот его TLB — почему-то нет, хотя было бы естественно. Ошибка? Нет, на фотографии ядра видно, что TLB (очевидно, 1-портовых) осталось 2, как у Nehalem. Видимо, причина в том, что на 2 AGU больше двух обменов/такт не получится, а при использовании команд AVX для достижения пика при потоковых операциях в среднем потребуется и вовсе 1,5 адреса/такт. Видимо, Intel посчитала, что ради экономии места третьи TLB и AGU пока лишние.

В Nehalem к битам TLB было добавлено поле VPID (идентификатор виртуального процесса), сравнение содержимого которого с текущим VPID позволяло определить, относится ли адрес в TLB в адресному пространству этой виртуальной машины или остался после переключения с соседней. Архитектура Westmere преобразовала это поле в более общий формат PCID (идентификатор контекста процесса), что позволило сохранять содержимое TLB не только при переключении виртуальных машин, но и при смене адресации в пределах одной ОС. Что к этому добавлено в SB (и добавлено ли…) — не известно.

Кстати, о виртуализации (раз уж мы пока нигде её не упомянули) — Westmere отличался от Nehalem в т. ч. наличием небольшого кэша на 3 так называемых VMCS (virtual machine control structure, структура управления виртуальной машиной), содержащих архитектурное состояние виртуальной ОС. Кэшировать их полезно для ускорения переключения между ОС. Надо полагать, в SB этот кэш как минимум сохранился, а то и увеличился.

Аппаратная предзагрузка

Для L1D предзагрузчик поддерживает до 4 явно заданных спецкомандами загрузок, но это не так интересно, как автозагрузки. Блок следит за числом ожидающих промахов в L1D, и когда оно мало, а ядро не исполняет потоковую операцию (типа загрузки или сохранения контекста или операций со «строками») — происходит загрузка по одному из предсказанных адресов. Обращения в TLB не нужны, т. к. физический адрес недавно сделанного чтения на некоторое время остаётся и в предзагрузчике, а предсказания никогда не пересекают границу в 4 КБ.

Используются два алгоритма. Первый (простой или потоковый) основан на возрастающих адресах читаемых всеми командами данных — убывающие адреса не обрабатываются, т. к. для этого алгоритма они редки. Второй (сложный или шаговый) имеет буфер предположительно на 256 ячеек — в каждой хранится собственный адрес недавней команды чтения (по его младшему байту ячейка индексируется, когда в очередь чтения LSU поступает новый моп), прошлый адрес её загрузки и шаг последовательности (полагая, что он регулярный и не превосходит ±2048). При каждом исполнении этого чтения предзагрузчик проверяет регулярность шага, и, при положительном исходе, загружает в кэш следующую порцию. Предзагрузка в L1I, как уже описывалось, основана на предсказаниях переходов.

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

Интересно, что сложный алгоритм для L2 (а, возможно, и для L1D) имеет 2-битный насыщаемый счётчик, следящий за востребованностью данных: предположительно, если хотя бы 2 раза подряд предзагруженные данные были полезны, то даже если далее каждое третье обращение будет по «чужому» адресу, алгоритм не собьётся с найденного шага потока.

А теперь сюрприз — всё вышеописанное относится и к Nehalem. В SB же изменился только сложный алгоритм для L2, зато основательно:

  • Теперь он может запустить уже две предзагрузки на каждое чтение этого потока, уходя вперёд максимум на 20 шагов;
  • Вышеописанная функция работает только при достаточном простое L2: при его средней загрузке в него наперёд читается по одной строке, а при сильной — и вовсе ноль (точнее одна, но только в L3);
  • Если шаг большой, то загрузка в L2 также отменяется (близкая локальность обеспечивается простым алгоритмом);
  • Слежение производится за 32 потоками запросов: для каждой из 16 отслеживаемых страниц по 4 КБ допусти́м 1 восходящий и 1 нисходящий поток. Ранее было 12 восходящих потоков и 4 нисходящих, по одному на страницу.

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

Hyper-Threading

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

  • Дублируются: TLB L1I для стр. по 2 МБ, IQ, RSB, IDQ, архитектурное состояние ядра, АРФ для старших половин ymm;
  • Делятся пополам: TLB L1I для стр. по 4 КБ, L0m, ROB, обе очереди в LSU, буфер простого предзагрузчика в L1 (?);
  • Делятся динамически: BTB, резервация, все ФУ, вся подсистема памяти (кроме её блоков, указанных выше);
  • Чередуются по тактам (кроме случаев срыва одного из потоков): все стадии фронта, переименование, размещение мопов в планировщике и отставка.

Поясним, что такое «делятся динамически»: это значит, что блок не знает о существовании двух потоков и никак бы не изменился, если бы в ЦП не было многопоточности. Это особенно наглядно в случае диспетчера: ROB делится между потоками, т. к. надо соблюдать очерёдность размещений и отставок соответственно адресам каждого потока. Но когда мопы попадают в резервацию, адресов в них уже нет, а есть номера ячеек в ROB и ФРФ. Учитывая, что некий регистр-приёмник N при переименовании получит в одном потоке физический регистр X, а в другом — Y (что равносильно двум записям в N в одном потоке), то резервации всё равно, чьи мопы одновременно запускать, а для ФУ всё равно, чьи исполнять.

Наличие дублируемых и статически делящихся пополам ресурсов и чередование потоков по всей поочерёдной части конвейера говорит о том, что лучше всего Nehalem и SB чувствуют себя при исполнении пары почти одинаковых по объёму кода потоков. Причём если это 2 одинаковых потока, то обеспечить загрузку разных ФУ и прочих динамически разделяемых блоков будет трудно — общий алгоритм будет спотыкаться примерно в тех же местах, даже работая с разными данными. А подобрать две разные программы с примерно одинаковом темпом использования кода может оказаться ещё труднее — тем более, что это всецело зависит от ядра ОС, которая почти ничего не знает о внутренних событиях ЦП и загрузке его блоков.

Возможно, Intel не использовала динамическое разделение в TLB L1I (как в остальных TLB, особенно, учитывая, что сам кэш L1I разделяется так же), потому что его нет и у кэша мопов, а эти две структуры при вытеснении срабатывают одновременно. Впрочем, глядя на список пункта «Делятся пополам» (а в этих блоках, напомним, 3 цифры размеров из 4 в SB увеличились), можно сделать вывод, что ускорение от включения HT если не увеличится, то хотя бы с меньшей вероятностью станет отрицательным, что изредка бывало у Nehalem. Проверить это можно будущими тестами.

Внеядро

Кэш L3

Физически, кэш L3 не очень изменился: он по-прежнему разделён на банки по числу x86-ядер. В Nehalem была возможность сделать запись и чтение в/из L3 за такт, если они попадали в разные банки, т. к. использовался общий коммутатор и контроллер на весь кэш. Теперь организация банков другая: можно сделать запись или чтение, но в каждом банке по отдельности. А т. к. число банков почти всегда равно числу ядер (исключения до сих пор встречались только у 6–10-ядерных серверных Xeon, где в некоторых моделях банков на 1 больше или меньше числа ядер), то это фактически линейно увеличивает пропускную способность L3. Учитывая, что она разделяется между всеми ядрами (включая ГП), это очень полезно, т. к. пропуск, приходящийся на каждое ядро, до сих пор был главной проблемой любого разделяемого кэша.

Как и предшественник, ядра SB активней используют КМОП-логику по сравнению с динамической, что отразилось на частоте возникновения ошибок при работе. Это потребовало внедрить более мощные алгоритмы и коды обнаружения и коррекции ошибок (ECC) в кэшах ядер, способные в каждом байте обнаружить и исправить 2-битные ошибки и обнаружить (но не исправить) 3-битные. До сих пор ЦП умели обнаруживать до двух неверных бит и исправлять один, требуя в среднем 1 бит ECC на каждый защищаемый байт. Новый код, видимо, требует не менее 1,5 бит/байт — чуть позже мы сможем это проверить.

Главное изменение в L3 — он стал работать на полной частоте ядра. Точнее, x86-ядер. Точнее, работающего(их) из них в данный момент, т. к. часть ядер могут спать. Помимо увеличения пропускной способности это ещё и уменьшает задержки, которые, разумеется, меряются тактами ядер на их частоте. И вот (см. таблицу с параметрами кэша) в SB они уменьшились на 30%. Это при том, что сама частота кэша вовсе не подросла на 30%. Причина в том, что когда поток данных пересекает силовые (по величине логических «0» и «1» в вольтах) и, особенно, частотные домены, происходит задержка в несколько тактов для преобразования уровней и совпадения фронтов тактовых сигналов. В SB такой проблемы нет, т. к. L3 работает на том же напряжении, что и работающие x86-ядра (не отключенные силовыми ключами), а частота у всех активно загруженных ядер всегда одинакова (включая применение технологии Turbo Boost) — и именно на неё и настроится частота L3.

Правда, всё может оказаться интересней. Внимательный Читатель успел заметить, что кэш L2 работает на половинной частоте, а потому, имея 64-байтовый порт, теряет половину ПС. Такое решение, видимо, связано с разумной достаточностью и 32 байт/такт, а потому можно применить более экономные транзисторы, которые, к тому же, будут работать при меньшей частоте. Про L3 такое достоверно не известно, но резонно предположить, что там ситуация та же: на высокой частоте работают только контроллеры портов кольцевой шины, обрабатывая по 32 байта/такт в каждом порту (детальней об этом ниже), а вот сам кэш работает целыми 64-байтовыми строками раз в 2 такта.

Как и в Nehalem, каждый банк L3 разделён на блоки по 512 КБ и 4 пути. В большинстве ЦП серий Core i в каждом банке таких блоков 3 или 4. Серверные ЦП Xeon с архитектурой Beckton и Westmere-EX имеют 6, 8 или 10 ядер и банков L3, но последние увеличены как по размеру (до 3 МБ), так и по ассоциативности (до 24), что в самых дорогих ЦП даёт аж 30 МБ. Для SB же пока обещаны «лишь» 8-ядерные Xeon с 20-путным L3 на 20 МБ.

Для любителей кунсткамеры добавим, что единственный представитель архитектуры Nehalem с одним работающим ядром (и одним банком L3 на 2 МБ) — это, как ни странно, не какой-то тихой сапой выпущенный сверхбюджетный Celeron, а Xeon LC3518, физически представляющий собой обычный 4-ядерный Nehalem с тремя (!) отключенными ядрами и их банками. Авторы SB также приготовили такие диковинки — это модели Celeron B и Pentium B, где на 2 ядра и ГП приходится не 4, не 3, а 2 МБ кэша с уполовиненной до 8 путей ассоциативностью.

Кольцевая шина




Вверху — слайд 2009 г. о кольцевой шине Nehalem-EX. Внизу — свежий о ней же в Sandy Bridge-EX.

Не только наш Внимательный Читатель догадался, как надо связать L3 и ядра, чтобы ПС кэша росла пропорционально числу банков (а значит — и ядер). Однако эта кольцевая шина, вопреки утверждению Intel, в SB появилась не впервые. Если не считать различных специализированных процессоров (в частности, некоторых ГП), среди ЦП вообще она появилась в 9-ядерных Sony/IBM Cell BE (2007 г.). У ЦП Intel кольцевая шина была внедрена в 8-ядерных серверных Xeon серий Nehalem-EX (2010 г.), откуда с небольшими изменениями она попала SB. Её имеют и только что вышедшие серверные Westmere-EX (Xeon E7).

В каждом направлении протянуто 4 шины: запросов, подтверждений, снупов (для поддержки когерентности) и собственно данных (шириной 32 байта) — разумеется, всё защищено битами ECC. Протокол обмена является чуть переделанной и дополненной версией шины QPI, которую мы привыкли видеть как межпроцессорную шину типа «точка-точка», аналогичную HyperTransport в ЦП AMD. Внутри процессора связываемые «точки» являются агентами, каждый из которых имеет две пары шинных портов (приёмный и передающий в каждую сторону) и пару клиентских. К шинным подключены звенья шины, связывающие соседние агенты. К клиентским обычно подключены локальное x86-ядро и локальный банк L3. Однако в 2/4-ядерных SB один из крайних агентов подключен только к ГП, а второй — только к «системному агенту»; шинные порты также используются наполовину, т. к. в этих местах шина разворачивается на 180°, соединяя противонаправленные звенья. В 8-ядерном серверном SB будет 8 обычных агентов и 4 концевых, каждый из которых разворачивает направление обеих шин на 90°, задействуя все шинные порты, и обслуживает по одному клиенту-контроллеру: по 2 для памяти и для внешних шин (QPI и PCIe).


Агенты кольцевой шины показаны красным.

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

Таким образом, пиковая ПС шины равна полупроизведению числа используемых шинных портов всех агентов, 32 байт и частоты. «Полу-» — потому что требуется 2 порта для каждого звена. Учитывая, что кольцо, как и L3, работает на максимуме частот ядер, абсолютный максимум его ПС получается очень большим: для 4-ядерного ЦП на 3 ГГц — 960 млрд. байт/с (по «славной» традиции производителей винчестеров назовём это 960 ГБ/с :). Для сравнения — в Cell BE ко́льца также передают по 32 байта в каждую сторону, но на одну передачу требуется 2 такта, поэтому этот 9-ядерный ЦП наберёт на 3 ГГц примерно те же 960 ГБ/с.

Физически звенья шины проложены дорожками на самом высоком уровне, доступном для передачи сигналов — 7-м и 8-м слоях металлизации. Вышележащие слои используются только для питания и контактных площадок. Причём дорожки проходят поверх банков L3 и отдельного места не занимают. Такое устройство позволяет масштабировать шину простым копированием агентов и звеньев, что гораздо проще добавления дополнительных портов к центральному коммутатору. Впрочем, у последнего есть и преимущество — задержка прямой коммутации куда меньше, чем транзитной. Однако из-за более высокой частоты кэш L3 в SB оказался всё же с меньшей задержкой, чем в Nehalem.

Поддержка аппаратной отладки

Говоря о кольцевой шине, стоит упомянуть новую отладочную функцию — Generic Debug eXternal Connection (GDXC). Она позволяет мониторить трафик и синхрокоманды шины, перенаправляя их во внешний логический анализатор, подключаемый к спецпорту процессора. Ранее такие тонкие инструменты были доступны разве что производителям системных плат (разумеется, при полной секретности), да самим разработчикам. Но GDXC доступна и системным программистам, что, по идее, должно способствовать вылавливанию ошибок и оптимизации видеодрайверов. Что касается «обычных программистов», им наверняка пригодится увеличение (с 6 до 8) числа счётчиков производительности и событий в каждом ядре.

Когерентность и «поддержка» OpenCL

Nehalem был первым ЦП Intel со времён Pentium 4, в котором кэш последнего (т. е. 3-го) уровня стал включающим относительно остальных. Это означает, что в многопроцессорной системе процессорам будет проще отслеживать копии данных, раскиданных по разным кэшам, что требуется для поддержки их когерентности. Для этого теги каждой строки в L3 среди прочего хранят набор битов, обозначающих я́дра этого ЦП, в кэши которых эта строка была скопирована, а также номера других ЦП, в кэшах которых также есть её копия. Для Westmere-EX число таких битов наверняка не меньше 17 (10 ядер + 7 «остальных» ЦП). Кроме того, тогда же стандартный протокол когерентности MESI обновился до MESIF, включив в себя 5-е состояние Forward, разрешающее ответ на снуп-запрос от другого ЦП (в MESI ответить мог каждый ЦП, что увеличивало снуп-трафик). Соображением минимизации снуп-трафика руководствовалась и AMD, добавив для своих Opteron 5-е состояние Owned и получив протокол MOESI.

Когда при доступе в L3 из какого-либо ядра оказывается, что искомая строка закэширована другим ядром (для простоты предположим, что одним) и может быть им модифицирована, происходит обращение к его кэшам L1D и L2 для проверки её актуального состояния. Проверка называется «чистой», если данные оказались нетронутыми, и «грязной», если они модифицированы и требуют копирования в запрашивающее ядро и L3. В SB первый случай вызывает задержку в 43 такта, а второй — в 60. Эти указанные в документации цифры почему-то являются константами, хотя должны зависеть от топологического расстояния между ядрами на кольцевой шине. Да и разница в 17 тактов куда больше, чем положенные 2 для передачи 64 байт…

Новинкой в SB по части включающей политики L3 является то, что биты присутствия копий данных в кэшах ядер учитывают и ГП. Т. е. с точки зрения программы ГП можно использовать как векторный сопроцессор, работающий с общими данными в общем адресном пространстве. По идее, поддержка OpenCL 1.1 в ГП этому должна способствовать, что успел заявить Thomas Piazza, глава отдела графических архитектур Intel. Однако некоторые аналитики упорно писали, что OpenCL в SB не поддерживается. Ещё один детектив? Да, и он распутан.

Согласно заявлению другого представителя компании, поддержка физически есть, но из-за неготовности драйвера при его активации по-прежнему будут использоваться лишь ресурсы x86-ядер. Когда появится обновление, где всё заработает, — сказано не было. По менее официальным каналам получен намёк, что и до этого ГП как-то можно будет использовать в качестве сопроцессора. Но только после доделки нужного SDK (инструментального пакета для программистов) ГП будет доступен не «как-то», а по-человечески. :)

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

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

Системный агент и ИКП

Системный агент — это та часть «внеядра», которая получается после вычета кэша L3 и ГП. Остаётся вот что:

  • арбитр со своим портом кольцевой шины — коммутирует потоки данных между остальными частями агента;
  • порт отладочной шины GDXC;
  • контроллер шин QPI (1–2 соединения на 25,6, 28,8 или 32 ГБ/с) — очевидно, присутствует только в серверных моделях;
  • контроллер шин PCIe 2.0 (на 1 ГП/с) или 3.0 (2 ГП/с, только для Xeon) — в зависимости от модели может быть 16-, 20-, 24- и 40-полосным и допускает различные схемы соединений по числу полос: для наиболее распространённых 20-полосных моделей это x16+x4 (для большинства мобильных SB доступен только этот вариант), x8+x8+x4 и x8+x4+x4+x4 (только для младших Xeon);
  • контроллер шины DMI 2.0 — для соединения с PCH (чипсетом): фактически немного преобразованный 4-полосный канал PCIe, по сравнению с v1.0 (в Nehalem и Atom) удвоил ПС до 4 ГБ/с (сумма в оба направления);
  • «гибкое межсоединение экранов» (Flexible Display Interconnect, FDI) — порт для соединения с контроллером физических интерфейсов экранов в составе чипсета, также переработанный из PCIe;
  • ускоритель (де)кодирования видео;
  • контроллер памяти;
  • программируемый силовой контроллер (Power control unit, PCU) с собственной прошивкой.

Наиболее интересными тут оказываются 3 последних пункта. Однако видеоускоритель оставим для обзора графической части, тут же расскажем об ИКП. Он поддерживает 2–4 канала памяти вплоть до DDR3-1600 (с ПСП 12,8 ГБ/с на канал), но для настольных и мобильных ЦП — только 2 канала DDR3-1333. Каждый канал имеет отдельные ресурсы и независимо обслуживает запросы. ИКП имеет внеочерёдный планировщик операций (!), максимизирующий ПСП с минимизацией задержек. Кроме того, ещё в версиях Nehalem для Xeon появилась технология SMI (Scalable Memory Interconnect, масштабируемое межсоединение памяти) с использованием подключаемых SMB (масштабируемый буфер памяти, аналог буфера AMB из FB-DIMM, но находящийся не на модуле, а на системной плате). Буфер подключается скоростной последовательной шиной к каналу ИКП процессора и позволяет подключить к себе большее суммарное число модулей, чем напрямую к ЦП. Правда, от этого ухудшаются и задержки, и частота работы памяти.

В каждом канале есть 32-строковый буфер записи, причём запись считается завершённой, как только данные попадут в буфер. Как ни странно, слиянием записи этот буфер не занимается, в результате чего частичные записи (когда обновляется не вся строка) обрабатываются неэффективно, т. к. требуют чтения старой копии строки. Это странно, учитывая, что современные микросхемы памяти учитывают битовую маску записи не только для отдельных 8-байтовых слов (которых 8 на строку), но и байт в словах, потому комбинация неизменной и обновлённой частей строки производится внутри чипа памяти, а не в ИКП. Впрочем, в SB ИКП (как и кэши) может включать продвинутые методы ECC, и для этого даже частично обновляемую строку для пересчёта ECC надо начала считать целиком. Причём это правило работает даже при применении обычной памяти, а также в большинстве мобильных моделей, где ECC-память вовсе не поддерживается.

Turbo Boost 2.0

Силовой контроллер системного агента отвечает сразу за 3 функции — защита от перегрева, сохранение энергии и авторазгон (именно в таком порядке они добавлялись с эволюцией ЦП x86). Последний пункт в процессорах Intel известен как технология Turbo Boost (TB). Её обновлённая версия является одним из главных «гвоздей программы», т. к. для слабопараллелизуемых программ она может дать ускорение не меньшее, чем все архитектурные улучшения в ядрах.

Напомним, что TB следит за текущими частотами, напряжениями питания, силами тока и температурами разных частей кристалла, чтобы определить, можно ли повысить работающим ядрам частоту на очередной шаг множителя (отдельно для x86-ядер и ГП). При этом учитываются пределы по всем вышеуказанным параметрам. Главной новинкой 2-й версии TB является дополнительное повышение частот, происходящее сразу после периода простоя всех или большей части ядер и обусловленное температурной инерцией системы «ЦП + радиатор». Очевидно, что при включении нагрузки и всплеске выделения тепла температура кристалла достигнет некоего значения не мгновенно, а плавно и с замедлением. Так вот если текущая температура пока ещё не критическая, и по остальным параметрам также есть запас, то контроллер ещё чуть поднимет множитель, ещё чуть увеличив потребление и выделение энергии и ещё чуть увеличив скорость роста температуры. Кстати, Intel продемонстрировала стабильную работу 4-ядерного SB на частоте 4,9 ГГц с воздушным охлаждением…


Зелёным пунктиром обозначена частота, а красным — температура. Во врезке — типичная нагрузка на ЦП домашнего ПК.

В зависимости от качества кулера и политики BIOS по регулировке оборотов вентилятора при разной температуре, первые 10–25 секунд после относительно длительного простоя процессор будет потреблять больше величины TDP, а занятые ядра теоретически должны работать на бо́льших частотах, чем у ЦП Westmere в тех же обстоятельствах. Как только температура поднимается до критической отметки, частота снизится к обычному «турбированному» значению — это снизит и выделение тепла до TDP, а температура расти перестанет. Выигрыш в том, что в течение нескольких секунд система будет работать чуть быстрее, чем с Turbo Boost 1.0. Т. е. вторая версия технологии является «турбонаддувом турбобуста». Отсюда ясно, на какие сценарии это рассчитано — периодический запуск малооптимизированных под многопоточность программ, быстро решающих свою задачу и снова погружающих систему в простой на несколько минут. При домашней и офисной работе — типичная ситуация.

Не стоит забывать, что теперь каждый шаг множителя для x86-ядер равен 100 МГц, а не 133, поэтому напрямую сравнивать «турбо-формулы» SB и Nehalem не получится. Для ГП шаг равен 50 МГц, а для ИКП — 266 (максимум — 2166, автоматически не разгоняется). Частота шины DMI принимается как базовая, от которой отталкиваются остальные часто́ты всей системы. Впрочем, ровно по этой причине её как раз надо оставить на стандартных 100 МГц, и если уж заниматься разгоном, то только через множители. Кстати, отдельный тактовый генератор теперь не обязателен и будет присутствовать лишь на дорогих «оверклокерских» платах, а остальные станут чуть дешевле и проще.


Обычно тактовый генератор южного моста подключен к нескольким делителям в самом мосту, а через шину DMI — и к ЦП с его разнообразными умножителями…


…Но в дорогих платах внешний генератор тактирует всё.

Экономия

Методы достижения энергоэффективности в архитектуре Nehalem почти совпадают с оными в ЦП Atom, что описано во 2-й части его детального обзора на нашем сайте (правда, поддержка состояния глубокого сна C6 и низковольтной памяти LV-DDR3 появилась только в Westmere). А что появилось в SB?

Во-первых — второй тип термодатчиков. Привычный термодиод, показания которого «видят» BIOS и утилиты, измеряет температуру для регулировки оборотов вентиляторов и защиты от перегрева (частотным троттлингом и, если не поможет, аварийным отключением ЦП). Однако его площадь весьма велика, потому их всего по одному в каждом ядре (включая ГП) и в системном агенте. К ним в каждом крупном блоке добавлено по нескольку компактных аналоговых МОП-схем с термотранзисторами. У них меньший рабочий диапазон измерений (80–100 °C), но они нужны для уточнения данных термодиода и построения точной карты нагрева кристалла, без чего нереализуемы новые функции TB 2.0. Более того, силовой контроллер может использовать даже внешний датчик, если производитель системной платы разместит и подключит его — хотя не совсем ясно, чем он поможет.

Добавлена функция перенумерации C-состояний, для чего отслеживается история переходов между ними для каждого ядра. Переход занимает время тем большее, чем больше «номер сна», в который ядро входит или из которого выходит. Контроллер определяет, имеет ли смысл усыплять ядро с учётом вероятности его «пробудки». Если таковая ожидается скоро, то вместо затребованного ОС состояния C6 или C3 ядро будет переведено в C3 или C1, соответственно, т. е. в более активное состояние, быстрее выходящее в рабочее. Как ни странно, несмотря на большее потребление энергии в таком сне, общая экономия может не пострадать, т. к. сокращаются оба переходных периода, в течение которых процессор совсем не спит.

Для мобильных моделей перевод всех ядер в C6 вызывает сброс и отключение кэша L3 общими для банков силовыми ключами. Это ещё сильнее снизит потребление при простое, но чревато дополнительной задержкой при пробуждении, т. к. ядрам придётся несколько сотен или тысяч раз промахнуться в L3, пока туда подкачаются нужные данные и код. Очевидно, в совокупности с предыдущей функцией это произойдёт, лишь если контроллер точно уверен, что ЦП засыпает надолго (по меркам процессорного времени).

Core i3/i5 прошлого поколения являлись своеобразными рекордсменами по требованиям к сложности системы питания ЦП на системной плате, требуя аж 6 напряжений — точнее, все 6 были и ранее, но не все вели в процессор. В SB силовые шины изменились не числом, а использованием:

  • x86-ядра и L3 — 0,65–1,05 В (в Nehalem L3 отделён);
  • ГП — аналогично (в Nehalem почти весь северный мост, который, напомним, являлся там вторым кристаллом ЦП, питается общей шиной);
  • системный агент, у которого частота фиксирована, а напряжение — постоянное 0,8, 0,9 или 0,925 В (первые два варианта — для мобильных моделей), либо динамически регулируемое 0,879–0,971 В;
  • умножители частоты — постоянное 1,8 В или регулируемое 1,71–1,89 В;
  • драйвер шины памяти — 1,5 В или 1,425–1,575 В;
  • драйвер PCIe — 1,05 В.

Регулируемые версии силовых шин используются в разблокированных видах SB с буквой K. В настольных моделях частота простоя x86-ядер повышена с 1,3 до 1,6 ГГц, судя по всему, без ущерба для экономии. При этом 4-ядерный ЦП при полном простое потребляет 3,5–4 Вт. Мобильные версии простаивают на 800 МГц и просят ещё меньше.

Модели и чипсеты


Серверные и настольные варианты SB для разных разъёмов. Обратите внимание на разную частоту работы ИКП в зависимости от числа подключенных модулей и их типа. Иллюстрация с pc.watch.impress.co.jp.

Очередную смену разъёма для настольных линеек (с LGA1156 на LGA1155) обсуждать не будем — эта тема уже избита. :) По традиции укажем на список моделей в Википедии, хотя на момент сдачи этой статьи туда ещё не внесли несколько недавно анонсированных ЦП.

Традиционный для обоих производителей x86-ЦП модельный бардак начинается с самого мощного, «серверного» вида (без ГП, с 4-канальным ИКП и 40 полосами PCIe 3.0), также известного как SB-E — он попадёт и в десктопы под именем Core i7 Extreme и даже просто Core i7, «потеряв» 2–4 ядра, 8 полос PCIe и, возможно, 1 канал ИКП и снизив объём L3 с 20 МБ до 10–15. TDP «экстремалов», как и прежде, останется на 130 ваттах. Остальные анонсированные модели i7 — это «просто мощные» настольные ЦП, как и полагается. Среди i5 тоже есть исключения — они могут быть и 2-ядерными (с половинным размером L3). Среди i3 исключений нет, и на том спасибо.

Всё ещё живые Pentium и в очередной раз воскресшие Celeron лишены поддержки HT, AVX, AES-NI и TB для x86-ядер. Обе марки имеют три вида, обозначаемых буквой у номера модели — настольные G***, мобильные B*** или *** (только цифры) и встроенные ***E (с поддержкой ECC). Встроенные и часть мобильных ЦП используют корпус BGA1023, остальные мобильные — под разъём Socket G2. Celeron G440, B710, 787 и 827E — 1-ядерники, причём последний лишён даже ускорения 3D в ГП. Кэш L3 сократили до 1,5 МБ у 827E и 1 МБ (!) у B710 и 787. Pentium G имеют 3 МБ L3, а все остальные версии Pentium и Celeron — 2.

Мобильный ряд прежде всего удивляет моделью Core i7 Extreme 2920XM за $1096. Видимо, дверью ошиблась — это к модным нынче экономным серверам (где разблокированный множитель не пригодится), а не для портативных приборов с автономным питанием и слабеньким кулером. У мобильного i7 может быть разным размер L3 и число ядер (с буквой Q или X их 4, иначе — 2). i5 в этом отношении более стабильны, а у единственного пока i3 Turbo Boost работает только для ГП. Мобильные Core получат «старшую» графику (о различиях между ними — ниже), а вот Pentium и Celeron (даже настольные) помимо половины 3D-блоков лишены и технологий Clear Video HD (улучшение видеопотока «на лету») и QuickSync (аппаратный перекодировщик видео).

Номера моделей мало что скажут. Core i теперь 4-значные и начинаются с двойки; Pentium, наоборот, одну цифру потеряли (причём разница между 600-ми и 800-ми моделями — только в частоте и (не)поддержке памяти DDR3-1333). Если у настольной модели последняя цифра — 5, то у неё старший ГП, а если 0 — то младший. Однако для 2600K и 2500K это не работает: полноценная графика (вдобавок к разблокированному множителю) есть именно у них, а не у несуществующих 2605K и 2505K. У мобильных ЦП эта же пятёрка означает поддержку ECC-памяти и развилки шины PCIe. Ещё последней цифрой может быть 2, что означает включение этой модели в программу Processor Performance Upgrade — о ней мы расскажем в ближайшей статье.

Вдобавок, Внимательный Читатель нам напомнит, что с января 2011 г. выпускаются мобильные Celeron 763 и 925 на ядре Penryn 4-летней давности для пред-предыдущей архитектуры. А теперь сравним их (1 ядро, 1 МБ L2 и, разумеется, никакого ГП и L3) с готовящимися к выпуску мобильными же Celeron 787 и 857: 787 — 1-ядерник с 1 МБ L3, а 857 — 2-ядерник с 2 МБ; у 857 по сравнению с 787 базовая частота x86-ядер — меньше, базовая частота ГП — та же, а турбо-частота ГП — больше. А теперь попробуйте определить хотя бы что-то из этого только по номерам моделей…

Буквы S и T после номера означают «средне» и «очень» экономные модели, но сравнивать их частоты не получится: например, модель Core i5-2500 быстрее и прожорливей, чем 2500S, которая быстрее и прожорливей, чем 2500T, но вот насколько именно в каждом случае — без таблицы не ясно. Вдобавок, «очень» экономные Xeon обозначаются буквой L, а не T, а ещё есть не менее экономная встроенная модель i3-2340UE. Также известно, что настольные Pentium и Celeron моделей GxxxT дополнительно лишатся ускорения 3D в ГП, но вот Celeron G440 с тем же TDP в 35 Вт буквы T не имеет. У «просто» экономных мобильных и встроенных ЦП номера заканчиваются на 9, а у «самых» — на 7.

Удивительно, как Intel сама себе делает подножку: на сайте компании есть официальная и постоянно обновляемая база данных процессоров с почти полным списком характеристик старых и текущих моделей. В ней с удивлением можно обнаружить, что новый Pentium 957, оказывается, не имеет виртуализации, хотя все остальные источники (включая заявления самой Intel) говорят, что ни один ЦП новой архитектуры не лишится поддержки VT и x86-64.

Короче, бардак полный и, судя по всему, намеренный. Но один намёк на порядок всё же есть: если расположить модельные ряды как «Celeron-Pentium-i3-i5-i7», то в каждой линейке все ЦП окажутся дороже самого дорогого из предыдущей и дешевле самого дешёвого из следующей. Впрочем, уже сейчас (для текущих цен и пока анонсированных моделей) это работает лишь по отдельности для настольных и мобильных процессоров, ибо мобильный Celeron B810 сто́ит, как самый быстрый настольный Pentium. Но даже с этой поправкой нельзя твёрдо сказать, что Intel именует ЦП не по производительности, а по цене, ибо откуда тогда берутся сами цены? :)

      
Чипсеты-близнецы H67 и P67.

Некоторые странности до сих пор имелись и среди чипсетов: долгое время можно было купить системную плату либо с поддержкой разгона (на чипсете P67), либо встроенного ГП (на H67). Пользователи, которые хотели и того, и другого, недоумевали, почему их поставили перед выбором «или-или». Ответ прост: чипсет Z68 с поддержкой «всего» вышел лишь в мае, на 4 месяца позже старта платформы. Причём физически это всё тот же P67/H67 (который суть один и тот же кристалл), только со всеми разблокированными функциями.


Чипсет Z68.

Помимо этого, для «бизнес-сектора» (малопонятный автору термин маркетологов) выпущены настольные Q67, Q65 и B65 — это H67 с поддержкой PCI; у последних двух только 1 (из 6) порт SATA — версии 3.0 (а не 2 из 6, как в остальных чипсетах), т. е. поддерживает скорость 6 Гбит/с, а у B65 нет RAID. Наиболее дешёвая модификация — H61, без PCI, RAID и SATA 3.0. Мобильных чипсетов набирается пять: стандартные QM67, QS67 и HM67 (с TDP около 3,9 Вт и размером микросхемы 25×25 мм) и экономные UM67 и HM65 (3,4 Вт и 22×22 мм). QM67 и QS67 допускают полный ручной разгон всех ядер (являясь по этой части мобильным аналогом P67); а ещё вся пятёрка имеет разную поддержку RAID — от никакой в HM65 и UM67 до уровней 0, 1, 5 и 10 в QM67 и HM67. Судя по всему, этот же южный мост применяется и в чипсетах C202, C204 и C206 для младших Xeon серий E3 (которые суть обычный 4-ядерный SB).

Проблему с поддерживаемыми функциями Intel уже продемонстрировала ошибкой в контроллере SATA во всех выпущенных в начале года чипсетах. Исправление и перевыпуск, как известно, влетели в миллиардную «копеечку», а репутационные издержки и вовсе трудновыразимы.

Кристалл

Техпроцесс

Физически техпроцесс 32 нм для SB мало отличается от такового для Westmere. Главное улучшение — в компенсации разброса параметров транзисторов, прежде всего утечки тока. Например, в Westmere в разных кристаллах на 300-миллиметровой пластине утечка могла иметь 4-кратную разницу, что особенно влияет на надёжность записи в кэши и РФ. Компенсация этого разброса для SB позволит достичь большего выхода годных кристаллов, лучшей экономии и более высоких частот. Как именно? В каждую линию шин записи в РФ и кэшах добавили программируемую «подтяжку» из трёх транзисторов разного размера, стабилизирующую уровень логической «1» в зависимости от утечки. Во время заводского тестирования утечка замеряется в разных местах кристалла, после чего «подтяжки» программируются на наиболее точную комбинацию транзисторов (из 8 возможных) для улучшения надёжности записи.

По некоторым данным, в кэшах Westmere использовалось не менее трёх видов ячеек СОЗУ. Для основных матриц L3 — средневольтная высокоплотная (площадью 0,171 квадратных микрон на бит), для тегов L3 — низковольтная скоростная (0,199 мк²/бит), а для L2 и L1 (включая теги) — 8-транзисторая ультранизковольтная скоростная (0,256 мк²/бит, но для L1 удельная площадь кэша примерно вчетверо больше за счёт многопортовости и встроенной в матрицу логики). Разнообразие видов СОЗУ показывает, что инженеры в каждом случае нашли свой баланс между скоростью срабатывания, площадью, потреблением и надёжностью хранения и работы. В частности, имея в L2 8-транзисторные ячейки, можно было устроить «бесплатный» порт записи — однако этот кэш не сделали 2-портовым, видимо, по причине усложнения управляющей логики, непропорционального получаемому ускорению.

Судя по всё ещё актуальной проблеме разброса параметров, для SB техпроцесс значительно оптимизировать не удалось. Тем не менее планки по частоте и экономии подняты — в частности, т. к. L3 теперь запитывается той же силовой шиной, что и x86-ядра, он должен быть рассчитан на работу при 0,65 В (при низкой нагрузке), что ниже минимального вольтажа для L3 в Westmere (0,8 В). Уменьшенного потребления удалось достичь без увеличения площади хранения бита, но со штрафом для надёжности — доля моделей SB с полным (не заблокированным частично) кэшем L3 пока оказывается меньше, чем у Nehalem и Westmere.

Виды кристаллов

4 вида кристалла для SB имеют такие физические показатели (для 8-ядерных — предполагаемые):

Модели Core i5/i3,
Pentium,
Celeron
Core i3,
Core-М°
i7/i5/i3
Xeon,
Core i7/i5
Xeon,
Core i7
Extreme
Число ядер x86 и ФУ ГП* 2 + 6 2 + 12 4 + 12 8 + 0
Объём кэша L3, МБ 3 4 8 20
Число транзисторов, млн. 504 624 995 ≈2200
Площадь кристалла, мм² 131 149 219 ≈400
Размер кристалла (Ш×В), мм 13,803×9,507 14,554×10,256 21,078×10,256 ≈20×20

° — мобильные варианты
* — под графическим ФУ понимается конечный исполнительный блок, иерархически эквивалентный «потоковому процессору» (SP) AMD и «CUDA-ядру» NVidia.

Помимо этих цифр также обнародовано, что старший 12-блочный ГП типа HD Graphics 3000 имеет 114 млн. транзисторов (обозначим эту меру как Мтр.), а 1 ядро x86 — 55 Мтр. (включая кэш L2). Из этих цифр можно подсчитать, что банк L3 на 2 MБ имеет 130,5 Мтр., а младший 6-блочный HD Graphics 2000 — 59 Мтр.


Кристалл 4-ядерного SB (по ссылке — очень детальное фото).

Посмотрим на кристалл — на примере 4-ядерного, фото которого — единственное доступное на сегодня. Как и в предыдущей архитектуре, Intel использовала модульную схему, позволяющую относительно легко получать новые модификации простым изменением числа блоков. В данном случае видны 4 модуля «ядро x86 и локальный банк L3», ГП (большой блок слева), системный агент со всеми контроллерами (справа) и физические интерфейсы (драйверы) шин: PCIe (вдоль правого края), FDI (в нижнем правом углу), памяти (внизу), GDXC (в нижнем левом углу) и DMI (в верхнем левом углу). Области с монотонным цветом общей площадью ≈12 мм² — пустые.

Устройство ГП


Блок-схема ГП в Sandy Bridge. Иллюстрация с pc.watch.impress.co.jp.

Первое, что любопытно — его младшая версия получена не просто путём отсечения половины ФУ у старшей, но и последующим уменьшением размеров кристалла и по ширине, и по высоте. Этот факт мы исследуем позже, а тут обратимся ко второму моменту — если 59 Мтр. для HD Graphics 2000 верны, то всё, что остаётся после вычитания всех ФУ, занимает всего 3,4 Мтр. А ведь в ГП, помимо исполнительных блоков, есть много общих и не менее сложных ресурсов (площадь и сложность которых видна в центральной части ГП, а их количество — на блок-схеме): планировщик и кэш кода, процессор вершин, растеризатор, текстурный сэмплер и прочее.

Учитывая, что одно из рекламируемых преимуществ нового ГП Intel — это не только удвоенная (до 128 бит) разрядность ФУ (за счёт чего вся 3D-графика ускорилась «вдвое»), но и большее число аппаратных блоков — скорее всего общие части займут не намного меньше транзисторов, чем ФУ. Из чего надо сделать вывод, что цифра в 59 Мтр. занижена, а значит — из сокращённого 2-ядерного кристалла убрали что-то ещё, помимо половины ФУ в ГП. А т. к. все ядра и банки L3 мы уже посчитали, подозрения падают на системный агент — тем более, что именно в нём находится аппаратный перекодировщик QuickSync, отключенный в самых младших моделях, ГП которых из-за этого зовётся HD 1000. Чуть позже у нас окажется способ это проверить. Пока же заметим, что 4-ядерные модели с младшим ГП получены стандартным отключением 6 ФУ.

Устройство банка L3

В таблице не зря указаны именно физические параметры кэша L3 — фактически доступные размер и ассоциативность зависят от конкретной модели, ведь при заводском тестировании что-то могут отключить. А вот плотность в 7,8 транзистора/бит — общая для всех. Напомним, что стандартная ячейка применяемого в кэшах статического ОЗУ имеет 6 транзисторов, а экономная — 8 (с ущербом для площади, поэтому её размещают только в ядре, кэши которого относительно малы). Если из 130,5 Мтр. (для банка L3 на 2 МБ) вычесть положенные 100,7 Мтр. (при 6-транзисторных ячейках только для данных), останется 29,8 Мтр. Этого должно хватить на биты ECC (1 на байт) и теги (предположим, что это 50 бит на строку, включая свои биты ECC). Тогда контроллеру банка и агенту кольцевой шины останется 7,4 Мтр., что вполне вероятно.


Банк кэша L3 на 2 МБ. Вверху — агент кольцевой шины. В центре — контроллер банка. Справа от них — теги и ECC (вертикальный ряд). Остальные блоки — массивы данных. Нижние 4 пути могут отсутствовать.

Т. к. продвинутые методы ECC внедрены для защиты наиболее уязвимых, ультранизковольтных ячеек, в L3 они не применяются, поэтому выше мы посчитали число битов ECC как стандартный 1 на байт. Теперь посмотрим на фото банка. Видно, что каждый блок тегов состоит из двух матриц (бордового цвета). Размер большей из них составляет 10% от размера обслуживаемых матриц с данными (в которые, видимо, встроены и биты ECC), но с учётом меньшей плотности тут хранится примерно 8,5% информации от объёма строки и её ECC (576 бит) — и это почти соответствует вычисленному нами значению в 50 бит на строку. А вот что хранят малые матрицы тегов — сказать трудно…

2-ядерные кристаллы

Если кто думает, что в высокоинтеллектуальной аналитике процессорных архитектур нет места легкомысленным «фотожабам» — наслаждайтесь: попытаемся представить, как выглядят остальные два выпущенных кристалла для 2-ядерных моделей (возможно, Intel опубликует и их изображения, так что можно будет проверить). Со старшим вариантом проблем нет — удалив «лишние» 2 x86-ядра, сместим вправо ГП, водрузив его над левой третью ИКП.


Почти так должен выглядеть 2-ядерный SB с 4 МБ L3 и старшим ГП.

А вот с младшей версией всё интереснее. Сначала обратим внимание, что каждый банк L3 не зря имеет пусто́ты в нижней четверти — в некоторых 4-ядерных моделях отключена одна 4-путная четвертинка каждого банка, а в младшем 2-ядерном кристалле нижние четверти в обоих банках и вовсе физически отсутствуют. Управляющих цепей там нет, поэтому после урезания каждого банка сместим ИКП и ГП вверх.

Однако чтобы эта версия кристалла оказалась меньше и по высоте, ГП также придётся обрезать. Обратим внимание на его верхнюю часть с массивом блоков в 3 ряда и 4 колонки — это и есть 12 ФУ. Для образования необходимого сдвига достаточно отсечь верхний ряд, оставив 8 ФУ, из которых 2 будут выключены. Правда, при этом отсекается и верхний край драйвера шины DMI, а ниже (на место GDXC) его не переставить — слишком высокий.

Допустим, мы всё же как-то смогли сместить ГП вверх. Но тут нас ждёт ещё один сюрприз — локальный агент шины и контроллер L3 окажутся не на одной линии с остальными. Если в этом месте шине придётся сделать 2 поворота на 90°, это ограничит её максимальную частоту работы, а т. к. она должна совпадать с частотой x86-ядер — то и их. Значит, такое решение применяется только в недорогих ЦП, которым высокая частота не очень важна — но этот вывод нарушает наличие модели Core i5 2390T, которая имеет штатную частоту 2,7 ГГц, а авторазогнанную — до 3,5 ГГц. Правда, можно также предположить, что агент остался на месте, но небольшой кусочек логики «под» ним (в правом нижнем углу ГП) перемещён в положение «над». Но это замедлит уже сам ГП, а его скорость у вышеуказанной модели — до 1,1 ГГц (почти как в топовых моделях).

На этом трудности не заканчиваются — нам ещё придётся где-то «откусить» те же 3/4 миллиметра и по ширине. Хорошо бы подошёл контроллер PCIe, но лишать процессор со слабым встроенным ГП возможности подключения мощного внешнего — кощунство (хотя это очень удобно бы объяснило «подозреваемые на пропажу» транзисторы в системном агенте). А ещё справа расположен не менее важный контроллер FDI. Драйвер DMI слева также некуда девать, к тому же между ним и драйвером GDXC есть часть графической логики…

Всё это намекает на такой итог: у инженеров графического отдела было достаточно времени, чтобы подготовить сразу две версии раскладки блоков ГП — полную (на 12 ФУ) и компактную (на 6). Причём во второй версии некоторые общие блоки удалены (!), а остальные заметно переставлены, за счёт чего и нашлось место для сокращения и по длине, и по ширине. Таким образом, «обвинения» в пропаже транзисторов могут быть предъявлены не только системному агенту (где удалена как минимум мало кому нужная GDXC, а возможно — и блок QuickSync), но и ГП.

Проверить гипотезу можно двумя способами: дождавшись фото этого кристалла и/или детально исследовав, чем отличаются версии ГП в 2-ядерных моделях, помимо числа ФУ. С «гаданиями по чипу» на сегодня закончим, но заметим, что Intel вряд ли пошла бы на такие сложности, если бы не было очень серьёзного повода для экономии этих несчастных 18 мм² (всего 12% от площади старшего 2-ядерного кристалла), при том, что 12 мм² в 4-ядернике пропадают зря. Возможно, этот повод — минимизация стоимости наиболее популярных моделей, в т. ч. и для лучшего продвижения в мобильном сегменте. Посмотрим, как это отразится на ценах…


Ядро Westmere по сравнению с синтезированной моделью ядра SB (на 2010 г.). Как видно, разработчики уместили все новшества почти на той же площади. Иллюстрация с chip-architect.com.

Производительность

Что эта глава делает в теоретическом обзоре микроархитектуры? А то, что есть один общепризнанный тест, уже 20 лет (в разных версиях) использующийся для оценки не теоретической, а программно достижимой скорости компьютеров — SPEC CPU. Он может комплексно оценить производительность процессора, причём в наилучшем для него случае — когда исходный код тестов скомпилирован и оптимизирован для тестируемой системы (т. е. походя проверяется ещё и компилятор с библиотеками). Таким образом, полезные программы окажутся быстрее лишь с написанными вручную вставками на ассемблере, на что сегодня идут редкие смельчаки-программисты с большим запасом времени. SPEC можно отнести к полусинтетическим тестам, т. к. он и ничего полезного не вычисляет, и никаких конкретных цифр не даёт (IPC, флопсы, тайминги и пр.) — «попугаи» одного ЦП нужны только для сравнения с другими.

Обычно Intel предоставляет результаты для своих ЦП почти одновременно с их выпуском. Но с SB произошла непонятная 3-месячная задержка, а полученные в марте цифры всё ещё предварительны. Что именно их задерживает — неясно, однако это всё равно лучше, чем ситуация с AMD, вообще не выпустившей официальных результатов своих последних ЦП. Нижеуказанные цифры для Opteron даны производителями серверов, использовавшими компилятор Intel, так что эти результаты могут быть недооптимизированы: что программный инструментарий Intel может сделать с кодом, исполняемым на «чужом» ЦП, мы уже знаем. ;)


Сравнение систем в тестах SPEC CPU2006. Таблица составлена Дэвидом Кантером с realworldtech.com по данным на март'2011.

В сравнении с предыдущими ЦП SB показывает превосходные (в прямом смысле) результаты в абсолюте и вовсе рекордные на каждое ядро и гигагерц. Включение HT и добавление 2 МБ к L3 даёт +3% к вещественной скорости и +15% к целой. Однако самую высокую удельную скорость имеет 2-ядерная модель, и в этом — поучительное наблюдение: очевидно, Intel задействовала AVX, но т. к. целочисленного прироста пока получить нельзя, то можно ожидать резкое ускорение лишь вещественных показателей. Но и для них никакого скачка нет, что показывает сравнение 4-ядерных моделей — а результаты для i3-2120 раскрывают причину: имея те же 2 канала ИКП, каждое ядро получает вдвое бо́льшую ПСП, что отражается 34-процентным приростом удельной вещественной скорости. Видимо, кэш L3 на 6–8 МБ слишком мал, и масштабирование его собственной ПС за счёт кольцевой шины уже не спасает. Теперь ясно, зачем Intel планирует оснастить серверные Xeon 3- и даже 4-канальными ИКП. Только вот тамошним 8 ядрам уже и их не хватит, чтобы развернуться по полной…

Дополнение: В базе SPEC появились финальные результаты SB — цифры (ожидаемо) чуть подросли, но качественные выводы те же.

Перспективы и итоги

О выходящем весной 2012 г. 22-нанометровом преемнике Sandy Bridge под названием Ivy Bridge («плющевый мост») уже многое известно. Ядра общего назначения будут поддерживать чуть обновлённый поднабор AES-NI; вполне возможно и «бесплатное» копирование регистров на стадии переименования. Улучшений в Turbo Boost не предвидится, зато ГП (который, кстати, заработает на всех версиях чипсета) нарастит максимальное число ФУ до 16, станет поддерживать подключение не двух, а трёх экранов, наконец-то обретёт нормальную поддержку OpenCL 1.1 (вместе с DirectX 11 и OpenGL 3.1) и улучшит возможности по аппаратной обработке видео. Скорее всего, уже и в настольных и мобильных моделях ИКП станет поддерживать частоту 1600 МГц, а контроллер PCIe — версию шины 3.0. Главное технологическое новшество — в кэше L3 будут использоваться (впервые в массовом микроэлектронном производстве!) транзисторы с вертикально расположенным многосторонним затвором-ребром (FinFET), имеющие радикально улучшенные электрические характеристики (детали — в одной из ближайших статей). Ходят слухи, что версии с ГП снова станут многочиповыми, только на этот раз к процессору добавят один или несколько кристаллов быстрой видеопамяти.

Ivy Bridge будет подключаться к новым чипсетам (т. е. южным мостам) 70-й серии: Z77, Z75 и H77 для дома (заменят Z68/P67/H67) и Q77, Q75 и B75 для офиса (вместо Q67/Q65/B65). Она (т. е. физическая микросхема под разными именами) по-прежнему будет иметь не более двух портов SATA 3.0, а поддержка USB 3.0 наконец-то появится, но на год позже, чем у конкурента. Встроенная поддержка PCI исчезнет (после 19 лет шине пора на покой), зато контроллер дисковой подсистемы в Z77 и Q77 получит технологию Smart Response для увеличения производительности кэшированием дисков с помощью SSD. Впрочем, наиболее волнительная новость заключается в том, что несмотря на старую добрую традицию, настольные версии Ivy Bridge не просто будут размещаться в том же разъёме LGA1155, что и SB, но и будут обратно совместимы с ними — т. е. современные платы подойдут и новому ЦП.

Ну а для энтузиастов уже в 4-м квартале этого года будет готов куда более мощный чипсет X79 (к 4–8-ядерным SB-E для «серверно-экстремального» разъёма LGA2011). Он пока не будет иметь USB 3.0, зато портов SATA 3.0 будет уже 10 из 14 (плюс поддержка 4 видов RAID), а 4 из 8 полос PCIe могут соединяться с ЦП параллельно с DMI, удваивая ПС связи «ЦП—чипсет». К сожалению, X79 не подойдёт к 8-ядерным Ivy Bridge.

В качестве исключения (а может быть, и нового правила) список того, что бы хотелось улучшить и исправить в Sandy Bridge, приводить не будем. Уже очевидно, что любое изменение является сложным компромиссом — строго по закону сохранения вещества (в формулировке Ломоносова): если где-то что-то прибыло, то где-то столько же и убудет. Если бы Intel кидалась в каждой новой архитектуре исправлять ошибки старой, то число наломанных дров и полетевших щепок могло бы превысить выгоду от полученного. Поэтому вместо крайностей и недостижимого идеала экономически выгодней искать баланс между постоянно меняющимися и подчас противоположными требованиями.

Несмотря на некоторые пятна, новая архитектура должна не только ярко засветить (что, судя по тестам, она и делает), но и затмить все предыдущие — как свои, так и соперника. Объявленные цели по производительности и экономности достигнуты, за исключением оптимизации под набор AVX, которая вот-вот должна проявиться в новых версиях популярных программ. И тогда Гордон Мур ещё раз удивится своей прозорливости. Судя по всему, Intel во всеоружии подходит к Эпической Битве между архитектурами, которую мы увидим в этом году.

Источник Процессоры Intel Sandy Bridge - все секреты


RSS лента ВСЕГО блога с комментариями RSS лента ВСЕГО блога БЕЗ комментариев RSS лента этой КАТЕГОРИИ с комментариями RSS лента этой КАТЕГОРИИ и БЕЗ комментариев RSS лента ЭТОГО ПОСТА с комментариями к нему

Процессоры Intel Sandy Bridge - все секреты

Процессоры Intel Sandy Bridge все секреты

Читатель наверняка знаком с кратким описанием микроархитектуры Sandy Bridge и помнит, что для той статьи мы использовали лишь иллюстрации из презентаций Intel, снабдив их нашими комментариями. Очевидно, они рассказывают не всю историю, поэтому нужна детальная статья, где история рассказывается вся и уже из независимого источника. ;) Кроме того, т. к. в своё время мы не делали подробного описания предыдущей микроархитектуры Nehalem, восполним это тем, что детально опишем не только ныне добавленные и изменившиеся элементы, но и старые (притом, что они не обязательно появились в Nehalem — некоторые цифры и факты куда древнее). Также мы испытаем нововведение: специфические термины и сокращения будут особо выделены, а при наведении на них курсора покажется всплывающая подсказка-расшифровка со ссылкой на нашу «Энциклопедию процессорных терминов» (которая, кстати, обновляется перед выходом каждой статьи).

«Крутой и холодный»

Прежде всего, какой ЦП был нужен Intel после 2008 г., когда микроархитектурное превосходство первых Core i (Nehalem и, в 2009 г., Westmere) над ЦП соперника стало окончательным? Ситуация немного напоминает первый год после выхода Pentium II: почивая на лаврах и получая рекордную прибыль, хорошо бы сделать продолжение удачной архитектуры, не сильно изменив её название, добавив новые команды, использование которых значительно улучшит производительность, не забыв и о других новшествах, ускоряющих сегодняшние версии программ. Правда, в отличие от ситуации 10-летней давности, надо обратить внимание и на модную ныне тему энергоэффективности, обыгранную двусмысленным прилагательным Cool — «крутой» и «холодный», — и не менее модное стремление встроить в процессор всё, что пока ещё существует как отдельные микросхемы. Вот под таким соусом и подана новинка.


«Позавчера», «вчера» и «сегодня» процессоров Intel.

Интегрированный в кристалл ЦП графический процессор ( ГП) мы детально рассмотрим в отдельной статье. Тут же исследуем результат работы израильского отделения Intel (Israel Development Center), которому в очередной раз поручили сделать ещё более экономную модификацию текущей (на 2008 г.) универсальной серверно-настольно-мобильной архитектуры (назовём её просто Nehalem). Правда, изначальное кодовое имя Gesher («мост» на иврите) по «политическим» причинам (была в Израиле такая партия, да сплыла…) пришлось изменить на Sandy Bridge — «песчаный мост» (сократим его до SB). Причина задержки не совсем ясна: следуя своей обычной практике выпуска каждый нечётный год нового техпроцесса («тик»), а каждый чётный — микроархитектуры («так»), SB должен был выйти в 2010 г. — тем более, что половина якобы новых добавленных в него идей уже были в предыдущих ЦП Intel. Тем не менее, учитывая состояние ЦП конкурента, нельзя сказать, что SB опоздал. Конечно, инженерам Intel надо бы поглядывать в сторону новых архитектур AMD, которые в ближайшем будущем (и опоздав гораздо больше, чем на год), кажется, чем-то грозят…

Технически задача стояла примерно так: на той же площади кристалла (т. е. при той же себестоимости) и том же 32 нм техпроцессе сделать ЦП, который на старых программах имел бы +10% скорости и −20% потребления одновременно, а на новых (где используются добавленные команды) — аж +100% пиковой скорости при том же TDP. Возможно, цифры были чуть другие, но почти так это выглядит по результатам. А вот какими методами — проще всего узнать, сравнивая SB с Nehalem (это относится к многочисленным прилагательным «больше», «быстрее», «экономней» и пр. далее в тексте). Напрашивается сравнение и с выходящей в середине 2011 г. архитектурой AMD Bulldozer, но оно будет после детального обзора её самой. Intel постепенно заместит архитектуру почти всех своих выпускаемых сегодня x86-ЦП (кроме Atom) с Nehalem на SB. Позиционирование против ЦП AMD пока точно не ясно, но один гол в ворота соперника уже забит: SB уже успела нещадно побить сегодняшние «Феномы», а обновлённые соперники выйдут на несколько месяцев позже — и не факт, что возьмут реванш.

Фронт конвейера


Фронт конвейера. Цвета показывают разные виды информации и обрабатывающих или хранящих её блоков.

Предсказание переходов

Начнём с заявления Intel о полностью переработанном предсказателе переходов (BPU). Как и в Nehalem, он каждый такт (и наперёд реального исполнения) предсказывает адрес следующей 32-байтовой порции кода в зависимости от предполагаемого поведения команд перехода в только что предсказанной порции — причём, судя по всему, вне всякой зависимости от числа и типа переходов. Точнее, если в текущей порции есть предположительно срабатывающий переход, выдаются его собственный и целевой адреса́, иначе — переход к следующей подряд порции. Сами предсказания стали ещё точней за счёт удвоения буфера целевых адресов (BTB), удлинения регистра глобальной истории переходов (GBHR) и оптимизации хэш-функции доступа к таблице шаблонов поведения (BHT). Правда, фактические тесты показали, что в некоторых случаях эффективность предсказания всё же чуть хуже, чем в Nehalem. Может быть, увеличение производительности с уменьшением потребления не совместимо с качественным предсказанием переходов? Попробуем разобраться.

В Nehalem (как и других современных архитектурах) BTB присутствует в виде двухуровневой иерархии — малый-«быстрый» L1 и большой-«медленный» L2. Происходит это по той же причине, почему существуют несколько уровней кэша: одноуровневое решение окажется слишком компромиссным по всем параметрам (размер, скорость срабатывания, потребление и пр.). Но в SB архитекторы решили поставить один уровень, причём размером вдвое больше, чем L2 BTB у Nehalem, т. е. наверняка не менее 4096 ячеек — именно столько их в Atom (а размер обслуживаемого кэша L1I совпадает у всех ЦП Intel с первых Pentium M). По идее, при этом увеличится занимаемая им площадь, а т. к. общую площадь ядра менять не рекомендуется (таков один из начальных постулатов архитектуры) — у какой-то другой структуры что-то придётся забрать. Но остаётся ещё и скорость. Учитывая, что SB должен быть рассчитан на чуть большую скорость при том же техпроцессе, можно ожидать, что эта крупная структура будет бутылочным горлышком всего конвейера — если только не конвейеризировать и её (двух стадий уже хватит). Правда, общее число срабатывающих за такт транзисторов в BTB при этом удвоится, что совсем не способствует энергоэкономии. Опять тупик? На это Intel отвечает, что новый BTB хранит адреса в некоем сжатом состоянии, что позволяет иметь вдвое больше ячеек при похожих площади и потреблении. Но проверить это пока невозможно.

Смотрим с другой стороны. SB получил не новые алгоритмы предсказания, а оптимизированные старые: общий, для косвенных переходов, циклов и возвратов. Nehalem имеет 18-битный GBHR и BHT неизвестного размера. Впрочем, можно гарантировать, что число ячеек в таблице меньше, чем 218, иначе она бы заняла бо́льшую часть ядра. Поэтому существует специальная хэш-функция, сворачивающая 18 бит истории всех переходов и биты адреса команды в индекс меньшей длины. Причём, скорее всего, хэшей как минимум два — для всех битов GBHR и для тех, что отражают срабатывание наиболее трудных переходов. И вот эффективность хаотичного распределения индексами различных шаблонов поведения по номерам ячеек BHT определяет успешность предсказателя общего вида. Хотя явно это не сказано, но Intel наверняка улучшила хэши, что позволило использовать GBHR бо́льшей длины с не меньшей эффективностью заполнения. А вот о размере BHT по прежнему можно гадать — как и о том, как на самом деле изменилось потребление энергии предсказателем в целом… Что касается буфера адресов возвратов (RSB), он по-прежнему 16-адресный, но введено новое ограничение на сами вызовы — не более четырёх на 16 байт кода.

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

Декодирование и IDQ

Предсказанные наперёд адреса исполняемых команд (попеременно для каждого потока — при включенной технологии Hyper-Threading) выдаются для проверки их наличия в кэшах команд (L1I) и мопов (L0m), но о последнем умолчим — опишем пока остальную часть фронта. Как ни странно, Intel сохранила размер считываемой из L1I порции команд в 16 байт (тут слово «порция» понимается согласно нашему определению). До сих пор это было препятствием для векторного кода, средний размер команд которого перерос 4 байта, а потому 4 команды, желательные для исполнения за такт, уже не уместятся в 16 байт. AMD решила эту проблему в архитектуре K10, расширив порцию команд до 32 байт — хотя её ЦП пока имеют не более чем 3- путный конвейер. В SB неравенство размеров приводит к побочному эффекту: предсказатель выдаёт очередной адрес выровненного 32-байтового блока, и если обнаружится (предположительно) срабатывающий переход в его первой половине, то считывать и декодировать вторую не надо — однако это будет сделано.

Из L1I порция попадает в буфер предекодера, а оттуда — в сам предекодер-длиномер ( ILD), обрабатывающий до 7 или 6 команд/такт (с и без макрослияния, но всё равно на 1 больше, чем в Nehalem) в зависимости от их совокупной длины и сложности. Сразу после перехода обработка начинается с команды по целевому адресу, иначе — с того байта, перед которым предекодер остановился тактом ранее. Аналогично с финальной точкой: либо это (вероятно) срабатывающий переход, адрес последнего байта которого поступил от BTB, либо последний байт само́й порции — если только не достигнут предел в 7 команд/такт, или не встретилась «неудобная» команда. Скорее всего, буфер длиномера имеет всего 2–4 ячейки, однако длиномер может получить из него любые 16 подряд идущих байт. Например, если в начале порции опознаны 7 двухбайтовых команд, то в следующем такте можно обработать ещё 16 байт, начиная с 15-го.

Длиномер, помимо прочего, занимается обнаружением пар макросливаемых команд. О самих парах поговорим чуть позже, а пока заметим, что, как и в Nehalem, каждый такт может быть обнаружено не более одной такой пары, хотя максимум их можно было бы разметить 3 (и ещё одну одиночную команду). Однако измерение длин команд — процесс частично последовательный, так что определить несколько макросливаемых пар не удалось бы в течение такта.

Размеченные команды попадают в одну из двух очередей декодера (IQ, по одной на поток, на 18 ячеек каждая). Декодер читает команды из очереди и переводит их в мопы. В нём есть 4 простых транслятора (переводят 1 команду в 1 моп, а с макрослиянием — 2 команды в 1 моп), сложный транслятор (1 команда в 2–4 мопа) и микросеквенсер для самых сложных команд, требующих 5 и более мопов из микрокода. Причём ПЗУ микрокода хранит только «хвосты» каждой последовательности, начиная с 5-го мопа, потому что первые 4 выдаются сложным транслятором. При этом если число мопов в микропрограмме не делится нацело на 4, то их последняя четвёрка будет неполной, но вставить ещё 1–3 мопа от трансляторов в этом же такте не получится. Результат декодирования поступает в кэш мопов и два буфера мопов (по одному на поток). Последние (официально именуемые IDQ — instruction decode queue, очередь декодированных команд) по-прежнему имеют по 28 мопов и возможность блокировки цикла, если его исполняемая часть там уместится.

Всё это (кроме кэша мопов) уже было в Nehalem. А в чём же различия? Прежде всего, что очевидно, декодер научили обрабатывать новые команды поднабора AVX. Поддержка наборов SSE со всеми цифрами уже никого не удивляет, а ускорение шифрования командами AES-NI (включая PCLMULQDQ) было добавлено в Westmere (32 нм версия Nehalem). В микрослияние подложили подводный камень: эта функция не срабатывает для команд, имеющих и константу, и RIP-относительную адресацию (RIP-relative, адрес относительно регистра-указателя команды — обычный способ обращения к данным в 64-битном коде). Такие команды требуют 2 мопа (отдельно загрузка и операция), а значит — декодер их обработает не более одной за такт, используя лишь сложный транслятор. Intel утверждает, что эти жертвы сделаны для экономии энергии, только не ясно, на чём: двухкратные размещение, исполнение и отставка мопов явно займут больше ресурсов, а значит — и потребят энергии, чем один.

Макрослияние оптимизировано — ранее в качестве первой сливаемой команды могло быть лишь арифметическое или логическое сравнение (CMP или TEST), теперь же допустимы простые арифметические команды сложения и вычитания (ADD, SUB, INC, DEC) и логического «И» (AND), также меняющие флаги для условного перехода (вторая команда пары). Это позволяет почти в любом цикле сократить последние 2 команды до 1 мопа. Разумеется, ограничения на сливаемые команды остались, но они некритичны, т. к. перечисленные ситуации для пары команд почти всегда исполняются:

  • первый операнд первой команды должен быть регистром;
  • если второй операнд первой команды находится в памяти, RIP-относительная адресация недопустима;
  • вторая команда не может находиться в начале строки кэша или пересекать границу строк.

Правила для самого́ перехода такие:

  • только TEST и AND совместимы с любым условием;
  • сравнения на (не) равно и любые знаковые совместимы с любой разрешённой первой командой;
  • сравнения на (не) перенос и любые беззнаковые не совместимы с INC и DEC;
  • остальные сравнения (знак, переполнение, чётность и их отрицания) допустимы лишь для TEST и AND.

Главное изменение в очередях мопов — слитые мопы типа load-ex, обращение в память в которых требует чтения индексного регистра, (и ещё несколько редких видов) при записи в IDQ разделяются на пары. Даже если таких мопов попадётся 4, то в IDQ запишутся все 8 итоговых. Делается это потому, что в очередях мопов (IDQ), диспетчера (ROB) и резервации теперь применяется сокращённый формат мопа без 6-битного поля индекса (разумеется, для экономии при перемещении мопов). Предполагается, что такие случаи будут редки, а потому на скорость сильно влиять не будут.

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

  • мопы цикла должны порождаться не более чем 8-ю 32-байтовыми блоками исходного кода;
  • все эти порции должны быть закэшированы в L0m (в Nehalem, разумеется, — в L1I);
  • не допускается более 8-и безусловных переходов (предсказанных как срабатывающие), включая финальный;
  • вызовы и возвраты недопустимы;
  • недопустимы непарные обращения в стек (чаще всего при неравном числе команд PUSH и POP) — об этом ниже.

Стековый движок

Есть ещё один механизм, работу которого мы в прошлых статьях не рассматривали — стековый движок (stack pointer tracker, «следитель за указателем (на вершину) стека»), расположенный перед IDQ. Он появился ещё в Pentium M и до сих пор не изменился. Суть его в том, что модификация указателя стека (регистра ESP/RSP для 32/64-битного режима) командами для работы с ним (PUSH, POP, CALL и RET) делается отдельным сумматором, результат хранится в специальном регистре и возвращается в моп как константа — вместо того, чтобы модифицировать указатель в АЛУ после каждой команды, как это требует программная архитектура и как было в ЦП Intel до Pentium M.

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

Внимательный Читатель (добрый день!) заметит связь: при зацикливании очереди мопов непарные обращения в стек недопустимы именно по причине того, что стековый движок в конвейере находится до IDQ — если после очередной итерации значение теневого указателя окажется ненулевым, в новой потребуется вставить синхромоп, а в циклическом режиме это невозможно (мопы только читаются из IDQ). Более того, стековый движок вообще при этом выключен для экономии энергии, как и все остальные части фронта.

Тайная жизнь нопов

Ещё одно изменение коснулось длиномера, но этот случай несколько выделяется. Сначала вспомним, что такое нопы и зачем они нужны. Когда-то в архитектуре x86 ноп был лишь 1-байтовый. Когда требовалось сместить код более чем на 1 байт или заменить команды длиной более 1-го байта, ноп просто вставляли несколько раз. Но несмотря на то, что эта команда ничего не делает, время на её декодирование всё-таки тратится, причём пропорционально числу нопов. Чтобы производительность «пропатченной» программы не просела, ноп можно удлинить префиксами. Однако в ЦП 90-х годов темп декодирования команд с числом префиксов выше определённой величины (которая куда меньше максимально допустимой длины x86-команды в 15 байт) резко падал. Кроме того, конкретно для нопа префикс применяется, как правило, одного вида, но многократно повторенный, что допускается лишь как нежелательное исключение, усложняющие длиномер.

Для разрешения указанных проблем начиная с Pentium Pro и Athlon процессоры понимают «длинный ноп» с байтом modR/M для «официального» удлинения команды с помощью регистров и адресного смещения. Естественно, никаких операций с памятью и регистрами не происходит, но при определении длины используются те же блоки длиномера, что и для обычных многобайтовых команд. Теперь использование длинных нопов официально рекомендуется учебниками по низкоуровневой программной оптимизации и от Intel, и от AMD. Кстати, предекодер SB вдвое (с 6 до 3 тактов) уменьшил штраф за префиксы 66 и 67, меняющие длину константы и адресного смещения — но, как и в Nehalem, штраф не накладывается на команды, где эти префиксы фактически не меняют длину (например, если префикс 66 применён к команде без непосредственного операнда) или являются частью списка переключателей опкодов (что сплошь и рядом используется в векторном коде).

Максимальная длина верно оформленного длинного нопа не превышает 9 байт для Intel и 11 для AMD. А потому для выравнивания на 16 или 32 байта нопов всё-таки может быть несколько. Однако т. к. команда эта простая, её декодирование и «исполнение» займёт ресурсов никак не больше обработки самых простых действующих команд. Поэтому уже много лет тестирование длинными нопами является стандартным методом определения параметров фронта конвейера, в частности — пропускной способности длиномера и декодера. И вот тут Sandy Bridge преподнёс очень странный сюрприз: тестирование производительности обычных программ не выявило никаких задержек и замедлений, а вот дежурная синтетическая проверка параметров декодера неожиданно показала, что его производительность равна одной команде за такт! При этом никаких официальных оповещений о таких радикальных изменениях в декодере Intel не давала.

Процедура замера отлично работала ещё на Nehalem и показывала верные 4 IPC. Можно свалить вину на новый и «чрезмерно» активный Turbo Boost 2.0, портящий замеряемые показатели тактов, но для тестов он был отключен. Перегрев с замедляющим частоту тротлингом тоже исключён. А когда, наконец, причина обнаружилась — стало ещё страннее: оказывается, длинные нопы на SB обрабатываются только первым простым транслятором, хотя 1-байтовые нопы с любым числом префиксов и аналогичные «по бездействию» команды (например, копирование регистра в себя) запросто принимаются всеми четыремя. Зачем так было делать — не ясно, однако как минимум один недостаток такого технического решения уже себя явно показал: на выяснение причин загадочной медлительности декодера нашей исследовательской командой было угрохано дней десять… В отместку просим яростных фанатов Противоположного Лагеря придумать какую-нибудь конспирологическую теорию о коварных планах некой компании I. по запутыванию наивных доблестных исследователей процессоров. :)

Кстати, как оказалось, «более равным» среди прочих транслятор №1 уже был. В Nehalem команды циклической прокрутки (ROL и ROR) с явным операндом-константой тоже декодировались только в первом трансляторе, причём в этом же такте отключался четвёртый, так что величина IPC падала до 3-х. Казалось бы — зачем приводить тут такой редкий пример? Но именно из-за этого подвоха, чтобы добиться пиковой скорости на алгоритмах хэширования вроде SHA-1, нужна была очень точная планировка команд, с которой компиляторы не справлялись. В SB же такие команды просто стали 2-мопными, так что, занимая сложный транслятор (который и так один), они ведут себя почти неотличимо для ЦП, но более предсказуемо для человека и компилятора. С нопами же получилось всё наоборот.

Кэш мопов

Цели и предшественники

Мы не зря отделили эту главу от остального описания фронта — добавление кэша мопов наглядно демонстрирует, какой путь выбрала Intel для всех своих процессоров, начиная с Core 2. В последний впервые (для Intel) был добавлен блок, который одновременно достигал две, казалось бы, противоречивые цели: увеличение скорости и экономия энергии. Речь идёт о той самой очереди команд (IQ) между предекодером и декодером, хранившей до 18 команд длиной до 64 байт в сумме. Если бы она только сглаживала разницу темпов подготовки и декодирования команд (как обычный буфер) — выгода была бы небольшая. Но в Intel догадались приделать к IQ небольшой блок LSD (вряд ли парни что-то «приняли», просто у них юмор такой) — Loop Stream Detector, «детектор циклического потока». При обнаружении цикла, умещающегося в 18 команд, LSD отключает кэш L1I и предекодер и поставляет из очереди в декодер команды цикла, пока тот не завершится, либо пока не будет сделан переход за его пределы (вызовы и возвраты не допустимы). Таким образом, экономится энергия за счёт отключения временно простаивающих блоков и увеличивается производительность за счёт гарантированного потока в 4 команды/такт для декодера, даже если они были «снабжены» самыми неудобными префиксами.

Intel явно понравилась эта идея, так что для Nehalem схема была оптимизирована: IQ продублирована (для двух потоков), а между декодером и диспетчером (т. е. аккурат на границе фронта и тыла) были поставлены две очереди IDQ на 28 мопов каждая, и блок LSD перенесли в них. Теперь при блокировке цикла отключается ещё и декодер, а производительность поднялась в т. ч. за счёт гарантированного притока уже не 4-х команд, а 4-х мопов за такт, даже если их генерация производилась с минимальным (для Core 2/i) темпом в 2 мопа/такт. Яростные фанаты Противоположного Лагеря, на секунду оторвавшись от любимого занятия, тут же вставят шпильку: если LSD такая хорошая штука, почему же его не встроили в Atom? И шпилька справедлива — имея 32-моповую очередь после декодера, Atom не умеет блокировать в ней цикл, что как раз очень бы пригодилось для экономии драгоценных милливатт. Тем не менее, Intel не собиралась бросать идею и для новых ЦП подготовила обновление, да ещё какое!

Официальное название кэша мопов — DSB, decode stream buffer (буфер потока декодирования), хотя это неточно отражает суть. Как ни странно, он не подменяет, а дополняет очереди IDQ, которые теперь соединяются с декодером или с кэшем мопов. При очередном предсказании перехода целевой адрес одновременно проверяется в кэшах команд и мопов. Если сработает последний — то далее считывание идёт из него, а остальной фронт отключается. Вот почему кэш мопов является кэшем нулевого уровня, т. е. L0m. Интересно, что продолжить эту мысль можно, назвав IDQ кэшами «минус первого» уровня. :) Но не является ли такая сложная иерархия в рамках даже не всего ядра, а одного только фронта избыточной? Пускай Intel в качестве исключения не пожалела площадь, но принесёт ли пара IDQ существенную дополнительную экономию, учитывая, что при их работе теперь отключается лишь кэш мопов, т. к. остальной фронт (кроме предсказателя) и так спит? И ведь особой прибавки к скорости тоже не получишь, т. к. кэш мопов также настроен на генерацию 4 мопов/такт. Видимо, инженеры Intel решили, что 3-уровневая игра стоит милливаттовых свеч.

Кроме экономии, кэш мопов ускоряет производительность в т. ч. сокращением штрафа при фальш-предсказании перехода: в Nehalem при нахождении верного кода в L1I штраф был 17 тактов, в SB — 19, но если код нашёлся в L0m — то только 14. Причём это максимальные цифры: при внеочерёдном исполнении ложно предсказанного перехода планировщику надо ещё запустить и завершить предыдущие в программном порядке мопы, а за это время L0m может успеть подкачать верные мопы, чтобы планировщик успел их запустить сразу после отставки команд до перехода. В Nehalem такой приём работал с IDQ и фронтом, но в первом случае вероятность того, что верный целевой адрес тоже будет внутри 28-мопового цикла, весьма мал, а во втором медлительность фронта в большинстве случаев не позволяла снизить задержку до нуля. У SB такой шанс больше.

Устройство

Топологически L0m состоит из 32 наборов по 8 строк (8- путная ассоциативность). В каждой строке хранится 6 мопов (во всём кэше — 1536, т. е. «полтора киломопа»), причём за такт кэш может записать и считать по одной строке. Предсказатель выдаёт адреса 32-байтовых блоков, и именно этот размер является рабочим для L0m, поэтому далее под термином «порция» будем понимать выровненный и предсказанный как исполняющийся 32-байтовый блок кода (а не 16-байтовый, как для декодера). При декодировании контроллер L0m ждёт обработки порции до конца или до первого срабатывающего в ней перехода (разумеется, предположительно — тут и далее полагаем предсказания всегда верными), накапливая мопы одновременно с их отправкой в тыл. Затем он фиксирует точки входа в порцию и выхода из неё, согласно поведению переходов. Обычно точкой входа оказывается целевой адрес срабатывающего в предыдущей порции перехода (точнее, младшие 5 бит адреса), а точкой выхода — собственный адрес срабатывающего перехода в этой порции. В крайнем случае, если ни в предыдущей, ни в текущей порциях не сработает ни один переход (т. е. порции не только исполняются, но и хранятся подряд), то обе выполнятся целиком — вход в них будет на нулевом мопе и байте, а выход — на последнем мопе и начальном байте его команды.

Если в порции оказалось более 18 мопов — она не кэшируется. Это задаёт минимум среднего (в пределах порции) размера команды в 1,8 байта, что не будет серьёзным ограничением в большинстве программ. Можно вспомнить второй пункт ограничений IDQ — если цикл уместится в порции, но займёт от 19 до 28 мопов, его не зафиксируют ни кэш L0m, ни очередь IDQ, хотя по размеру он бы везде уместился. Впрочем, в этом случае средняя длина команд должна быть 1,1–1,7 байта, что для двух десятков команд подряд крайне маловероятно.

Скорее всего, мопы порции одновременно записываются в кэш, занимая 1–3 строки одного набора, так что для L0m нарушается один из главных принципов работы наборно-ассоциативного кэша: при кэш-попадании обычно срабатывает одна строка набора. Тут же теги до трёх строк могут получить адрес одной и той же порции, отличаясь лишь порядковыми номерами. При попадании предсказанного адреса в L0m считывание происходит аналогично — срабатывают 1, 2 или 3 пути нужного набора. Правда, такая схема таит в себе недостаток.

Если исполняемая программа во всех порциях декодируется в 13–18 мопов, что займёт по 3 строки L0m для всех порций, обнаружится следующее: если текущий набор уже занят двумя 3-строчными порциями, и в него пытается записаться третья (которой не хватит одной строки), придётся вытеснить одну из старых, а с учётом её связности — все 3 старых. Таким образом больше двух порций «мелко-командного» кода в наборе не должно уместиться. При проверке этого предположения на практике получилось вот что: порции с крупными командами, требующие менее 7 мопов, упаковались в L0m числом в 255 (ещё одну занять почему-то не получилось), уместив почти 8 КБ кода. Средние порции (7–12 мопов) заняли все 128 возможных позиций (по 2 строки каждая), закэшировав ровно 4 КБ. Ну а мелкие команды уместились в 66-и порциях, что на две больше ожидаемого значения (2112 байт против 2048), что, видимо, объясняется граничными эффектами нашего тестового кода. Недостача на лицо — если бы 256 6-моповых строк могли быть заполнены полностью, их бы хватило на 85 полных троек с общим размером кода 2720 байт.

Возможно, Intel не рассчитывает, что в каком-то коде будет так много коротких и простых команд, что более 2/3 его придётся на 3-строчные порции, которые станут вытеснять друг друга из L0m раньше необходимого. А даже если такой код и встретится — учитывая простоту его декодирования, остальные блоки фронта запросто справятся с задачей поставки необходимых тылу 4 мопов/такт (правда, без обещанной экономии ватт и тактов штрафа при фальш-предсказании). Любопытно, что имей L0m 6 путей, проблемы бы не возникло. Intel же решила, что иметь размер кэша на треть больше именно за счёт ассоциативности — важнее…

Размеры

Вспомним, что идея кэшировать большое количество мопов вместо команд x86, не нова. Впервые она появилась в Pentium 4 в виде кэша моп-трасс — последовательностей мопов после развёртки циклов. Причём кэш трасс не дополнял, а заменял отсутствующий L1I — команды для декодера читались сразу из L2. Не смотря на забвение архитектуры NetBurst, разумно предположить, что инженеры Intel использовали прошлый опыт, хоть и без развёртки циклов и выделенного для кэша предсказателя. Сравним старое и новое решения (новые ЦП тут названы Core i 2, потому что номера почти всех моделей с архитектурой SB начинаются с двойки):

Pentium 4
(Willamette,
Northwood)
Pentium 4
(Prescott)
Core i 2
(Sandy Bridge)
Объём, Кмопов 12 12 1,5
Организация, наборов⋅путей 256⋅8 256⋅8 32⋅8
Число мопов в строке 6 6 6
ПС, мопов/такт 3 3 4
Полный размер мопа, бит* 119 138 139–147
Сжатый размер мопа, бит* 53 64 85
Эквивалентный объём, КБ* 80 96 16

* — предположительно

Тут нужны пояснения. Во-первых, пропускная способность для L0m указана с учётом общего ограничения ширины конвейера в 4 мопа. Выше мы предположили, что за такт L0m может прочесть и записать по 18 мопов. Однако при чтении все 18 (если их получилось именно столько при декодировании оригинальной порции) не могут быть отправлены за такт, и отправка происходит за несколько тактов.

Далее, размер мопа в битах вообще относится к очень деликатной информации, которую производители либо вообще не выдают, либо только при припирании к стенке (дескать, вы и так уже всё вычислили, так и быть — подтвердим). Для ЦП Intel последняя достоверно известная цифра — 118 бит для Pentium Pro. Ясно, что с тех пор размер увеличился, но с этого места начинаются догадки. 118 бит для 32-битного x86-ЦП может получиться, если в мопе есть поля для адреса породившей его команды (32 бита), непосредственного операнда (32 бита), адресного смещения (32 бита), регистровых операндов (3 по 3 бита + 2 бита на масштаб для индексного регистра) и опкода (11 бит, в которых закодирован конкретный вариант x86-команды с учётом префиксов). После добавления MMX, SSE и SSE2 поле опкода наверняка выросло на 1 бит, откуда и получена цифра 119.

После перехода на x86-64 (Prescott и далее), по идее, все 32-битные поля должны возрасти до 64-х бит. Но тут есть тонкости: 64-битные константы в x86-64 допускаются только по одной (т. е. более 8 байт обе константы в команде точно не займут), а виртуальная адресация и тогда, и сейчас пока обходится 48 битами. Так что увеличить размер мопа требуется всего на 16 бит адреса и 3 дополнительных бита номеров регистров (коих стало 16) — получаем (примерно) 138 бит. Ну а в SB моп, видимо, вырос ещё на 1 бит за счёт добавления очередных нескольких сотен команд со времён последних P4, и ещё на 8 — за счёт увеличения максимального числа явно указанных регистров в команде до 5 (при использовании AVX). Последнее, впрочем, сомнительно: со времён, представьте себе, аж i386 в архитектуру x86 не была добавлена ни одна новая команда, требующая хотя бы 4 байта константы (с единственным недавним и крайне незаметным исключением в SSE4.a от AMD, о котором даже большинство программистов не знает). А т. к. Intel AVX и AMD XOP обновили кодировку лишь векторных команд, биты номеров дополнительных регистров уместятся в старшей половине частично неиспользуемого (для этих команд) 32-битного поля непосредственного операнда. Тем более, что и в само́й x86-команде 4-й или 5-й регистр кодируется как раз четыремя битами константы.

Очевидно, что хранить и пересылать таких «монстров» в сколько-нибудь большом количестве — сильно затратно. Поэтому ещё для P4 Intel придумала сокращённый вариант мопа, в котором лишь одно поле для обеих констант, причём если они там не умещаются, то недостающие биты размещаются в этом же поле соседнего мопа. Однако если он уже хранит там свои константы, то в качестве соседа приходится вставлять ноп как донор-носитель дополнительных бит. Преемственность такой схемы наблюдается и в SB: лишние нопы не вставляются, но команды с 8-байтовыми константами (или с суммой размеров константы и адресного смещения в 5–8 байт) имеют в L0m двойной размер. Впрочем, учитывая длину таких команд, больше 4-х их в порции не уместится, так что ограничение по занимаемым мопам явно некритично. Тем не менее, констатируем: SB, в отличие от предыдущих ЦП, имеет аж 3 формата мопов — декодируемый (самый полный), хранимый в кэше мопов (с сокращением констант) и основной (без поля регистра индекса), используемый далее в конвейере. Впрочем, большинство мопов проходят нетронутыми от декодирования до отставки.

Ограничения

«Правила пользования кэшем» на спецформате мопов не заканчиваются. Очевидно, столь удобный блок как L0m никак не мог оказаться совсем без ограничений той или иной степени серьёзности, о которых нам не рассказали в рекламных материалах. :) Начнём с того, что все мопы транслируемой команды должны уместиться в одной строке, иначе они переносятся в следующую. Это объяснимо тем, что адреса мопов строки хранятся отдельно (для экономии 48 бит в каждом мопе), а все порождаемые командой мопы должны соответствовать адресу её первого байта, хранимому в теге только одной строки. Для восстановления оригинальных адресов в тегах хранятся длины породивших мопы команд. «Непереносимость» мопов несколько портит эффективность использования L0m, т. к. изредка встречающиеся команды, генерирующие несколько мопов, имеют существенный шанс не уместиться в очередной строке.

Более того, мопы самых сложных команд по-прежнему хранятся в ПЗУ с микрокодом, а в L0m попадают лишь первые 4 мопа последовательности, плюс ссылка на продолжение, так что всё вместе занимает целую строку. Из этого следует, что в порции могут встретиться не более трёх микрокодовых команд, а учитывая средний размер команды более вероятным пределом будут две. В реальности, впрочем, они попадаются куда реже.

Ещё один важный момент — L0m не имеет своего TLB. Вроде бы, это должно ускорять проверку адресов (которые тут только виртуальные) и уменьшить потребление энергии. Но всё гораздо интересней — не зря все современные кэши имеют физическую адресацию. Виртуальные адресные пространства исполняемых в ОС программ могут пересекаться, поэтому при переключении контекста задачи, чтобы по тем же адресам не считать старые данные или код, виртуально адресуемый кэш должен сбрасываться (именно так было с кэшем трасс у P4). Разумеется, его эффективность при этом будет низкой. В некоторых архитектурах применяются т. н. ASID (address space identifier, идентификатор адресного пространства) — уникальные числа, присваиваемые ОС каждому потоку. Однако x86 не поддерживает ASID за ненадобностью — учитывая наличие физических тегов для всех кэшей. Но вот пришёл L0m и нарушил картину. Более того, вспомним, что кэш мопов, как и большинство ресурсов ядра, разделяется между двумя потоками, так что в нём окажутся мопы разных программ. А если добавить переключение между виртуальными ОС в соответствующем режиме, то мопы двух программ могут совпасть по адресам. Что же делать?

Проблема с потоками решается просто — L0m просто делится пополам по наборам, так что номер потока даёт старший бит номера набора. Кроме того, L1I имеет включающую политику хранения относительно L0m. Поэтому при вытеснении кода из L1I происходит и удаление его мопов из L0m, что требует проверки двух смежных порций (размер строки всех кэшей современных ЦП, не считая самого́ L0m — 64 байта). Таким образом виртуальный адрес из тэгов закэшированных мопов всегда можно проверить в тегах L1I, используя его TLB. Выходит, что хоть L0m и имеет виртуальную адресацию, но заимствует физические теги для кода из L1I. Тем не менее, есть ситуация, при которой L0m целиком сбрасывается — промах и замещение в L1I TLB, а также его полный сброс (в т. ч. при переключении режимов работы ЦП). Кроме того, L0m совсем отключается, если базовый адрес селектора кода (CS) не равен нулю (что крайне маловероятно в современных ОС).

Работа

Главный секрет кэша мопов — алгоритм, подменяющий чтениями из L0m работу фронта по переработке команд в мопы. Начинается он с того, что при очередном переходе для выбора набора L0m использует биты 5–9 адреса цели перехода (или биты 5–8 плюс номер потока — при 2-поточности). В тегах набора указаны точка входа в порцию, мопы которой записаны в соответствующей тегу строке, и порядковый номер этой строки в пределах порции. Совпасть могут 1–3 строки, которые (скорее всего) одновременно считываются в 18-моповый буфер. Оттуда мопы четвёрками посылаются в IDQ, пока не будет достигнута точка выхода — и всё повторяется сначала. Причём когда в порции остаются неотправленными 1–3 последних мопа, они высылаются с 3–1 первыми мопами новой порции, в сумме составив обычную четвёрку. Т. е. с точки зрения принимающей мопы очереди IDQ все переходы сглажены в равномерный поток кода — как в P4, но без кэша трасс.

А теперь любопытный момент — в строке допускается не более двух переходов, причём если один из них — безусловный, то он окажется последним для строки. Наш Внимательный Читатель сообразит, что на всю порцию допустимо иметь до 6 условных переходов (каждый из которых может сработать, не будучи при этом точкой выхода), либо 5 условных и 1 безусловный, который будет последней командой порции. Предсказатель переходов в ЦП Intel устроен так, что он не замечает условный переход, пока он хотя бы раз не сработает, и только после этого его поведение будет предсказываться. Но даже «вечносрабатывающие» переходы тоже подпадают под ограничение. Фактически это значит, что завершить исполнение мопов порции допустимо и до точки её выхода.

А вот аналогичный трюк со множественным входом не пройдёт — если происходит переход в уже закэшированную порцию, но по другому смещению в ней (например, когда там более одного безусловного перехода), то L0m фиксирует промах, включает фронт и запишет поступившие мопы в новую порцию. Т. е. в кэше допустимы копии для порций с разными входами и одинаковым, точно известным выходом (помимо ещё нескольких возможных). А при вытеснении кода из L1I в L0m удаляются все строки, точки входа которых попадают в любой из 64-х байт двух порций. Кстати, в кэше трасс P4 тоже были возможны копии, причём они существенно уменьшали эффективность хранения кода…

Такие ограничения уменьшают доступность пространства L0m. Попробуем подсчитать, сколько же его остаётся для фактического использования. Средний размер команды x86-64 — 4 байта. Среднее число мопов на команду — 1,1. Т. е. на порцию скорее всего придётся 8–10 мопов, что составляет 2 строки. Как было ранее подсчитано, L0m сможет сохранить 128 таких пар, чего хватит на 4 КБ кода. Однако с учётом неидеального использования строк реальное число будет, видимо, 3–3,5 КБ. Интересно, как это вписывается в общий баланс объёмов кэшевой подсистемы?

  • 1 банк L3 (фактически часть L3, в среднем приходящаяся на ядро) — 2 МБ;
  • L2 — 256 КБ, в 8 раз меньше;
  • оба L1 — по 32 КБ, в 8 раз меньше;
  • кэшируемый объём в L0m — примерно в 10 раз меньше.

Любопытно, что если найти в ядре ещё одну структуру, хранящую много команд или мопов, то ей окажется очередь ROB диспетчера, в которой умещается 168 мопов, генерируемые примерно 650–700 байтами кода, что в 5 раз меньше эффективного эквивалентного объёма L0m (3–3,5 КБ) и в 9 раз меньше полного (6 КБ). Таким образом, кэш мопов дополняет стройную иерархию различных хранилищ кода с разными, но хорошо сбалансированными параметрами. Intel утверждает, что в среднем 80% обращений попадают в L0m. Это значительно ниже цифры в 98–99% для кэша L1I на 32 КБ, но всё равно — в четырёх случаях из пяти кэш мопов оправдывает своё присутствие.

Диспетчер и планировщик

Переименование и размещение

Переходим к тыловой части. Первое крупное изменение — новые диспетчер и планировщик. Как и любой представитель этой стадии, диспетчер выполняет переименование регистров, размещение мопов в очереди ROB и резервации, приём завершённых мопов и их отставку. Каждый такт диспетчер принимает до 4 мопов от IDQ, прописывает физические регистры, помещает мопы в ROB (тоже до 4), разделяет слитые мопы на простые и отправляет их (до 6) в резервацию, связав каждый с нужным портом запуска (которых тоже 6). Очевидно, что в четвёрке принимаемых мопов допустимо не более трёх микро- или макрослитых, чтобы после разделения их можно было обработать за такт. Мопам обмена с памятью также выделяют ячейки в очереди загрузки или сохранения в LSU.

Некоторые мопы сразу после (или даже вместо) переименования указываются как незапускаемые:

  • любые нопы (до 4 за такт) — потому что они ничего не делают;
  • FXCH (обмен местами регистров x87-стека, до 2 за такт) — их «исполнение» заключается в переименовании пары регистров (в предыдущих ЦП только эта команда удалялась при размещении);
  • VZEROUPPER (1 за такт, потому что генерируются 4 неисполняемых мопа) — для обнуления старших половин всех регистров ymm (об этом позже);
  • классы обнуляющих и единичных идиом (zeroing idioms, ones idioms; 4 и 2 за такт).

К обнуляющим относятся команды, действие которых при указанных операндах всегда сводится к обнулению регистра-приёмника, хотя сами они специально для этого не предназначены. К таким SB относит все виды команд *XOR* (исключающее ИЛИ), *SUB* (вычитание) и PCMPGT* (векторная целая проверка на «больше»), все аргументы которых являются одним регистром (звёздочками заменены переменные части мнемоник разных версий команд). Поскольку результат предопределён, то считается, что никаких источников команде читать не надо, а потому она эквивалентна простому помещению константы 0 в целевой регистр. Явное обнуление в x86 не используется из-за особенностей ISA: для РОНов такая команда окажется длиннее идиомы, а для векторных регистров этого варианта нет вообще.

Само обнуление происходит за счёт того, что архитектурный регистр-приёмник перенумеруется на свободный физический регистр, помечаемый как содержащий нули (хотя реально там наверняка что-то другое). Потому «исполнять» такие мопы можно по 4 за такт, тогда как обычные *XOR*, *SUB* и PCMPGT* запускаются максимум тройками. Как-бы-нулевой регистр не читается из РФ, а в ФУ просто посылается сигнал, что этот аргумент — константа 0. Правда, анализа на 0 результатов вычислений в ФУ и загрузок из кэша не происходит (хотя флаг Z после большинства операций в АЛУ показывает именно это), так что 0 в регистре может оказаться и после необнуляющих команд с последующим штатным чтением — диспетчер о нём просто не узнает.

К обнуляющим также относится команда CLC, сбрасывающая флаг переноса. Поскольку 4 основных флага (перенос, переполнение, ноль и знак) также переименовываются, CLC по нашим тестам также может «исполняться» 4 раза за такт, хоть это и бессмысленно. Впрочем, представитель Intel заявил, что к CLC заочное обнуление не относится… Ещё одна группа команд, сокращающаяся подобным образом — единичная идиома PCMPEQ* (векторная целая проверка на «равно»). По аналогии с обнуляющими, при одинаковых аргументах она всегда устанавливает все биты приёмника в «1». Однако, в отличие от «обнулятелей», такому мопу всё же надо исполниться в любом из двух портов, куда обычно попадают эти команды — удалённо отметить регистр как содержащий единицы диспетчер не может, их надо записать явно.

Новый старый стиль

Прежде чем рассказать о само́м планировщике, вспомним основные различия между ними в нашей Энциклопедии. Точнее, нас интересует «хранящий» вариант с несколькими РФ и «ссылочный» с одним (физическим). Первый более привычен, т. к. применялся во всех x86-ЦП с внеочерёдным исполнением, за исключением всех P4. А второй был в P4 — и вот сейчас вернулся в SB. Может быть, Intel что-то перепутала, внедрив в новую экономную архитектуру блок из старой Netburst, представители которой «прославились» тепловыделением? (Также его применяют во всех серверных ЦП IBM POWER, которые ещё выше по частоте и ещё жарче.) Однако планировщик к этому точно не был причастен, а очень даже наоборот — именно вариант с физическим регистровым файлом (ФРФ), как ни странно, оказывается самым экономным.

До сих пор все основные процессы в планировщике (от размещения до отставки) требовали перемещения мопов вместе с накопленными в них данными, что требовало довольно много энергии (вспомните длину мопа и добавьте биты регистров-операндов). Вариант с ФРФ копирует или меняет не сами значения, а только 8-битные (в данном случае) ссылки на тот регистр в ФРФ, где они хранятся. Ещё одно преимущество такой схемы в снятии ограничения на число чтений из РФ. Дело в том, что в старой схеме основным РФ в исполнительном тракте был спекулятивный (СРФ), а вторичным — архитектурный (АРФ). Размер СРФ должен быть достаточен, чтобы держать аргументы и результаты всех хранящихся в резервации(ях) мопов, а размер АРФ, разумеется, будет совпадать с числом регистров данного типа согласно ISA.

Проблема была в том, что у АРФ лишь 3 порта чтения (а в Pentium II и III — 2), и при переименовании регистров 3–4 размещаемых мопа могут за такт прочесть (и скопировать в свою ячейку ROB) лишь небольшое число регистров, которые достаточно давно не менялись, чтобы их значения уже успели попасть из СРФ в АРФ при отставке. Учитывая, что у каждой целочисленной и AVX-команды число читаемых регистров может достигать трёх, разместитель не справился бы за такт со сбором всех нужных данных для четвёрки мопов. При использовании единственного РФ число его портов достаточно большое (по нашим тестам, в SB — 10 чтений и 5 записей), чтобы за такт прочесть и записать всё необходимое.

Поскольку каждый моп теперь не накапливает содержимое регистров, обе очереди тыла (ROB для диспетчера и резервация для планировщика) могут при той же площади хранить большее число мопов: 128 и 36 ячеек в ROB и RS Nehalem подросли до 168 и 54 в SB. Это значит, что планировщик теперь может отслеживать зависимости команд в более длинном куске кода, получая возможность одновременно запустить даже далёкие друг от друга команды. Это особенно пригождается при исполнении двух потоков, делящих между собой большинство ресурсов, включая обе этих очереди (опишем потом, как именно). Размеры же ФРФ такие — 160 64-битных РОНов и 144 256-битных векторных регистра. Правда, на самом деле векторных РФ два, каждый из которых хранит 128-битные половины. Почему так?

Исполнительная стадия

Тракты данных

Для ответа на вопрос выше снова сделаем исторический экскурс. Давным-давно, в далёкой-далёкой… гм, эпохе 70-х и 80-х гг. процессоры обрабатывали лишь целые числа, а потому исполнительный тракт у них был один, на 8/16/32 бита. Затем добавился вещественный тракт на 64/80 бит (архитектуре x86 в этом смысле пришлось труднее, потому что расширенную 80-битную точность больше нигде не внедрили). Далее, рассматривая только ЦП Intel, последовал набор MMX, который архитектурно хоть и использовал стек x87, но физически имел не только отдельные ФУ, но и регистры. Потом добавлен SSE — хотя для программиста регистры xmm 128-битные, векторные РФ и ФУ до Core 2 были 64-битными и тоже отдельными. Правда, когда SSE2 расширил целочисленную обработку до 128 бит, для этих ФУ нового РФ не создали, а просто переделали блок MMX, чтобы его РФ и ФУ могли хранить и обрабатывать и половинки 128-битных регистров.

В Core 2 структура исполнительного блока окончательно приобрела нынешние очертания. 64-битный целочисленный тракт работает с командами общего назначения, первый 128-битный — с целочисленными векторами, а второй 128-битный — с вещественными векторами и скалярами (включая x87). Вспомним, что при исполнении SSE-кода переключаться между целым и вещественным режимом не надо (в отличие от режимов MMX и х87), и каждый регистр xmm может хранить и целые, и вещественные значения. Но т. к. физически они хранятся и обрабатываются в разных РФ и доменах, возникает вопрос о доступности нужных данных нужному ФУ, если они находятся в соседнем тракте. Чтобы перемещений между векторными трактами было как можно меньше, в каждом их них есть блоки для наиболее частых команд — в частности, логических и некоторых перестановок. Но т. к. ФУ отдельные, то и команды для них Intel тоже решила сделать отдельными — и вот в x86 появилась такая химера, как «вещественная логика». Как-нибудь мы поговорим об этом звере, а пока договоримся обозначать такие ФУ как FLOG. Аналогично, ФУ для «целочисленной логики» назовём ILOG.

Пересылки данных между векторными трактами весьма редки благодаря наличию большинства нужных ФУ на каждом из них. Схема исполнительной стадии в Nehalem (не считая ФУ, используемых некоторыми редкими командами) выглядит так:

Тракт→ 64 бита,
целый1
128 бит №1,
целый
128 бит №2,
вещественный
Порт 0 АЛУ2
Сдвигатель
АЛУ
Перестановщик
F MOV (x87)
F MUL
F DIV
Порт 1 АЛУ
IMUL
AGU3
MOV
ILOG
IMUL
Сдвигатель
F ADD
Конвертер4
Порт 5 АЛУ
Сдвигатель
АЛУ
Перестановщик
FMOV (SSE)5
FLOG
Перестановщик

Не указаны порты: №2 для вычисления адреса чтения и самого чтения из памяти, №3 для вычисления адреса записи и №4 для самой записи.
1 — Не указан скалярный целочисленный делитель: он получает мопы со всех трёх портов при любом виде деления.
2 — Напомним, что АЛУ работают только с целыми числами и, помимо арифметики и логики, выполняют также копирования (MOV).
3 — Это ФУ исполняет только команду LEA: вычисление адреса как для операции чтения, но с помещением в приёмник самого́ адреса (иногда используется как замена некоторых арифметических команд). Аналогичный блок в порту 2 вычисляет адреса для «настоящих» чтений, выполняя дополнительные неарифметические операции.
4 — Преобразователь арифметических форматов (между двумя вещественными или вещественным и целым). Для некоторых команд использует один из вспомогательных ФУ, получающих мопы с других портов.
5 — «Вещественные копирования», ещё одна химера, когда речь идёт о векторном регистре целиком.

И тут на сцену выходит набор AVX и его 256-битные регистры ymm. Как их обрабатывать? Основных вариантов три:

  • Не менять ФУ, обрабатывая регистры половинками, как это было с xmm до Core 2;
  • Поставить отдельный тракт или расширить один из имеющихся, снабдив его необходимыми и «полноширными» ФУ;
  • Снабдить недостающими ФУ оба нынешних тракта, чтобы они могли работать над регистром ymm одновременно.

Нетрудно догадаться, какой вариант был выбран, учитывая, что процессору надо и скорость вычислений поднять, и энергию (обязательно) с площадью (желательно) сэкономить. Правда, по причинам, описанным далее в главе об AVX, добавлен только вещественный домен в бывший целочисленный тракт, который мы теперь назовём смешанным. После добавки и перетасовки ФУ в SB получилось вот что:


От центра вверх — 3 исполнительных тракта SB (в порядке, указанном в таблице). 5 структур ниже центра — 64-битные РФ (4 из них попарно объединены). Внизу — диспетчер и планировщик.
Тракт→ 64 бита,
целый1
128 бит №1,
смешанный
128 бит №2,
вещественный
Порт 0 АЛУ
Сдвигатель
MOV
ILOG

IMUL+FMUL1
Сдвигатель
FMOV (x87, AVX)
FMUL
IDIV+FDIV2
Порт 1 АЛУ
IMUL
Сложное AGU
АЛУ
FADD
Конвертер

Перестановщик
FADD
Конвертер
Порт 5 АЛУ
Сдвигатель
АЛУ3
Сдвигатель
Перестановщик
FMOV (SSE, AVX)
FLOG
Перестановщик

Не указаны порты: №2 и №3 для вычисления адресов и чтения из памяти и №4 для записи. Жирным указаны добавленные ФУ, курсивом — перемещённые, подчёркнутым — спариваемые.
1 — Универсальный умножитель для векторных целых и всех вещественных.
2 — Универсальный делитель для скалярных целых и всех вещественных. (Деления векторных целых в x86 нет.)
3 — Спариваются блоки копирования и логики.

Обратим внимание, что в Nehalem до полноценного АЛУ порту 1 не хватало лишь сумматора — логика и копирование там и так исполнялись. В SB целочисленные блоки портов 0 и 1 целиком поменяли местами, потеряв только отдельный умножитель, но почему-то не добавив на его место сумматор. Также нужно пояснить, почему, начиная с Pentium Pro, мопы записи разбиваются отдельно на вычисление адреса и саму запись. Во-первых, в элементарном мопе (в отличие от слитого) нет места и для данных, и для компонент адреса. Во-вторых — это часто позволяет заранее вычислить адрес, что поможет как можно раньше определить возможные адресные конфликты с чтениями (подробней об этом — далее).

Конфликты завершения

Теперь на секунду вернёмся к планировщику. Иногда встречается такая ситуация: некая команда после запуска исполняется в течение X тактов, но через Y тактов (Y

Теперь каждый из трёх вычислительных портов может за такт принять завершение до трёх мопов с разных трактов (правда, в сумме со всех портов — вряд ли больше 6). До сих пор такими параметрами могла похвастать лишь AMD, у которой раздельные 3-портовые планировщики для целочисленного и векторно-вещественного трактов запускают и принимают на пару 6 мопов/такт. Однако даже там не удалось обойти проблему переменной задержки некоторых команд — прежде всего это деление и вся трансцендентная арифметика. Время исполнения этих операций зависит от содержимого аргумента(ов) — например, для скалярного вещественного деления и извлечения корня в SB это 10–24 такта. В этих случаях в старых ЦП резервация просто блокировала порт с медлительным делителем, пока он не завершал работу. Затем ЦП обеих компаний научились принимать стоп-сигналы от всех ФУ (а не только от делителя-извлекателя), но только один за такт (если завершаемых мопов в данном порту больше — они становятся в очередь). И вот SB удалил возможную задержку, принимая 3 завершения за такт (очередь возможна лишь среди ФУ, совпадающих и по номеру порта, и по тракту). Правда, для этого ему пришлось приделать к некоторым командам временны́е балласты, но об этом — позже.

Межтрактные шлюзы

Пересылка данных между трактами обычно занимает заметное время (на Nehalem в большинстве случаев — 2 такта). Как с этим в SB? Оказывается, декодер для ряда команд вставляет специальные мопы, использующие некоторые ФУ как межтрактные шлюзы: с 64-битного тракта в любой 128-битный — через порт 0, обратно — через 5-й, а между 128-битными работают оба. «Настоящие» шлюзы, как и ранее, иногда вызывают задержку в 1 такт при переходе между целыми и вещественными SSE-операциями, хотя теперь они являются доменами одного тракта. Зато задержек в 2 такта уже почти нет. Судя по нашим тестам, передача между трактами обычно занимает 1 такт, но для шлюза в порту 0 может быть и бесплатна — возможно, он физически находится ближе к «своим» ФУ и успевает срабатывать вместе с ними.

Вспомним, что для AVX-кода доступен 256-битный перестановщик. Если исполняется команда, не требующая пересылки элементов между трактами, то её задержка такая же, как и для SSE-версии, т. к. использует 2 ФУ для половинок ymm. В противном случае используется полнодуплексный межтрактный перестановщик на 256 бит, причём его задержка в 1 такт присутствует, даже если фактически данные между трактами не передавались. Все шлюзы являются частью исполнительного конвейера — т. е. одновременно допускается использование ФУ и межтрактных пересылок.

Вещественные денормалы

Стандарт IEEE-754, который используют почти все современные процессоры для представления вещественных чисел, имеет такую особенность: когда экспонента E установлена в 0, а содержимое мантиссы M ненулевое, число интерпретируется не в нормальном виде (1,M⋅2E), а «денормальном» (0,M⋅2Emin, где Emin — минимальная «нормальная» экспонента). Обработка таких чисел (а также бесконечности и неопределённости) на ЦП Intel всегда была замедлена на сотни (!) тактов из-за микропрограммного получения результата. (Яростные фанаты Противоположного Лагеря могут гордиться своим кумиром — у AMD как минимум начиная с первых Athlon денормалы почти не замедляли вычисления, а бесконечности и неопределённости даже ускоряли.)

Проблема настолько велика, что для векторных вещественных вычислений Intel ввела в x86 специальный «облегчённый» режим DAZ ([assume] denormals are zero — считать денормалы нулями), идущий ради производительности несколько вразрез с мировым стандартом. В SB большинство подобных ситуаций разрешаются аппаратными механизмами, что кардинально повысило скорость обработки денормалов (и серьёзно уменьшило размер микрокода). Теперь лишь умножение изредка может вызвать небольшую дополнительную задержку. Это может значительно ускорить код, работающий с очень близкими к нулю числами — например, при вычислении знаменателей суммы ряда, что требуется для большинства трансцендентных функций.

Частичный доступ к регистрам

Очередная сложность, возникающая при разработке процессора — архитектурное допущение читать и менять часть какого-либо регистра. В x86 это применимо к РОНам, xmm и ymm — причём последний случай настолько особый, что этому посвящена целая глава. Тут же опишем проблему в целом на примере 64-битного РОНа.

Архитектурно программист может использовать регистр целиком, младшие 4 байта, младшие 2 байта и младший 1 байт. Для первых 4 РОНов есть ещё доступ ко второму байту, но для всех x86-ЦП уже давно рекомендуется настоятельно забыть эту возможность — трудностей хватает и без этого. При очередном архитектурном удвоении разрядности регистров у инженеров есть несколько вариантов реализации доступа к новым и старым регистрам как полностью, так и частично:

  1. Сделать отдельные архитектурные РФ для регистров нужной разрядности — как при переходе от 64-битных регистров mm (для MMX) к 128-битным xmm (которые, правда, не сразу можно было использовать для целых чисел, так что ФУ у них поначалу были разные). Выгода — нет зависимостей по данным (как если бы каждый xmm содержал бы в своей младшей половине mm с тем же номером). Минусов больше — требуются спецкоманды для перемещения данных между старым РФ и новым, а архитектурное состояние для сохранения вырастает не на 64, а на 128 байт (тогда регистров было ещё 8). Сегодня же, когда x87 и MMX уже устарели, их содержимое всё ещё надо сохранять (кроме случая с применением новой команды, как будет описано ниже).
  2. Сделать отдельные физические РФ для младших частей регистров — как во всех ЦП Intel от PPro до PM включительно (кроме P4). Правда, из-за дополнительных затрат это применяется лишь к младшим байтам РОНов — остальные части используют другие методы. Как и в случае выше, зависимостей нет — переименованный 8-битный регистр N хранится отдельно от 32-битного с тем же номером. Однако есть штраф, когда части регистра должны объединиться, чтобы быть обработанными другой командой.

    Пример: команда-1 обработала младший байт 32-битного РОНа, а следующая команда-2 читает его целиком. Вроде бы всё решается просто — команда-1 записывает изменённый байт не в «байтовый», а в основной (полноразрядный) РФ, а затем этот регистр читается весь. Но при внеочерёдном исполнении состояние старших трёх байт читаемого архитектурного регистра достоверно известно лишь при отставке, когда спекулятивый РФ записывает в архитектурный результаты готовых мопов. А значит при частичном доступе команда-2 вынуждена ждать 5–7 тактов до отставки команды-1.

  3. То же, что и выше, но части регистра могут объединяться в шлюзе при ФУ — это используется для РОНов в ЦП Intel с Core (первых) по Nehalem. При этом разместитель диспетчера автоматически вставляет дополнительный синхромоп, встраивающий только что записанный байт из «байтового РФ» в младший байт соответствующего ему регистра «полного РФ». Штраф в такой ситуации — 2–3 такта, т. к. достаточно дождаться завершения (не отставки) лишь последней команды, пишущей в данный регистр.
  4. Хранить регистры в цельном РФ, но получать доступ отдельными частями: для 64-битного РОНа — 1+1+2+4 байта, для xmm — 4+4+8 (напомним, что в наборах SSE есть скалярные вещественные команды, обрабатывающие только младший SP- или DP-элемент вектора). Применяется в Intel Core (2) и Nehalem — только для xmm, а в ЦП AMD и Intel Pentium 4 — и для РОНов, и для xmm. Никаких штрафов при использовании и даже слиянии регистров нет (т. к. синхромопы не используются), но существует ложная зависимость, когда запись в часть архитектурного регистра всегда считается зависящей от предыдущих записей в этот регистр — частичных и даже полных, когда он целиком перезаписывается.

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

  5. Как выше, но во избежание ложных зависимостей запись в часть регистра сбрасывает в 0 остальную часть — это применяется при 32-битных операциях с 64-битными РОНами на всех ЦП (чтобы не ставить отдельный РФ для 8-байтовых версий регистров в дополнение к 4- и 1-байтовым), а также (как мы увидим ниже) при 128-битных командах AVX с регистрами xmm, т. е. младшими половинами ymm. Оба решения, очевидно, являются архитектурными.
  6. Программист или компилятор явно удаляет зависимость частей регистра, обнуляя его целиком или частично до использования как приёмник. Этот способ также используется в AVX, причём с немалым подвохом.

Теперь, когда все варианты перечислены, — на чём же остановились авторы SB? Для РОНов теперь используется метод №4, как и для xmm/ymm — в Nehalem же при частичной обработке РОНов надо было ждать лишние 3 такта. Исключение составляют «старшие» байтовые регистры (от AH до DH), которые всё же могут отдельно переименовываться. Но, как подсказывает Внимательный Читатель, есть ещё один ресурс, который и переименовывается, и читается-пишется (причём частично — куда чаще, чем полностью): 4–6 самых используемых флагов.

До сих пор ЦП использовали к ним подход №2, но SB перешёл на модифицированный вариант №3: флаг переноса (C) переименовывается отдельно, а для остальных имеется сливающий моп. Что это даёт? Вот типичная ситуация: в конце цикла команда INC или DEC меняет его параметр, записывая флаги нуля и знака в поле флагов физического регистра (имеется только для РОНов). Затем условный переход проверяет флаг нуля или знака — никаких проблем, они только что изменились. Но если условный переход читает флаг переполнения, либо попалась команда сохранения всех флагов в стек — придётся ждать, пока команды, менявшие оставшиеся 2 флага, уйдут в отставку, чтобы выделить нужный бит или их все. И вот SB сократил этот штраф примерно вдвое. Если же читается флаг переноса — то штрафа нет вообще.

Т. к. остальные флаги всё ещё держатся вместе, это создаёт любопытные эффекты — например, для команд сдвига. Дело в том, что согласно ISA вытесняемые биты должны попадать во флаг переноса, причём если параметр сдвига более 1, то попадёт только последний бит. Так вот этот вариант до сих пор вызывал парадоксальную зависимость флага переноса от своего же старого значения — после такой команды чтение только что изменённого флага всё равно приведёт к штрафу. В SB такого штрафа нет, зато синхромопы для слияния флагов теперь всегда вставляются после многобитных вращений. В результате задержка получения результата команды сдвига в регистре-приёмнике — 1 такт, а во флагах — 2–3.

AVX

Реализация

Главным новшеством в исполнительной стадии является добавление недостававших ФУ, чтобы вкупе с уже имеющимися суметь исполнить любую операцию с региcтрами ymm (кроме деления и извлечения корня) в полноконвейерном варианте и одновременно над всем вектором. Но как же получается, что несколько ФУ, которые надо задействовать для исполнения операции, находятся в одном порту? Ведь, как мы знаем, каждый порт может за такт запустить 1 моп… И тут на помощь приходит второе новшество, без которого первое не имело бы смысла — впервые среди процессоров (именно процессоров вообще) запускаемый через порт резервации моп может активировать более одного ФУ: в данном случае — пару одинаковых, потому в таблице выше они и названы спариваемыми. Таким образом за такт можно исполнить 3 256-битные AVX-операции, активировав 6 ФУ!

Но где восклицание — там и половник дёгтя: т. к. AVX-моп один, использовать два ФУ из пары отдельно не получится. Запустить 128-битные SSE-команды (да и 128-битные AVX) тоже можно лишь 3 за такт, так что на имеющемся коде, не знающем ни про какой AVX, почти половина векторных ФУ нового ЦП будет простаивать (разумеется, в выключенном состоянии для экономии), не принеся никакого ускорения. Очевидно, Intel делает большую ставку на активное использование AVX в обновлённых версиях ПО. Но и тут безоблачного будущего не предвидится — и не только потому, что внедрение нового часто происходит медленно…

Подножка

Как мы помним из исторического экскурса выше, иногда содержимое xmm-регистров перемещается через шлюзы в соседний векторный тракт, где местное ФУ производит с ним некую операцию. Результат при этом почти всегда записывается в местный же РФ, так что если следующая операция, которую требовалось исполнить над этим вектором, снова должна использовать местное ФУ — данные уже на месте. А теперь представим себе, что в SSE-код программист-оптимизатор добавляет вручную написанную процедуру с использованием команд AVX и регистров ymm, младшие половины которых, как мы помним, совпадают с регистрами xmm с тем же номером. Поскольку при исполнении AVX-команд 1-й («смешанный») векторный тракт работает только с младшей половиной ymm, а 2-й — только со старшей, это может потребовать обмена местами неверно расположенных половин регистра, для чего перед каждой операцией придётся проверять, где они расположены. Intel решила проблему иначе.

Для SB схема использования двух трактов изменилась: теперь на 1-й тракт попадают всё регистры mm, xmm и младшие половины ymm, а на 2-й — стек х87 и старшие части ymm (причём в регистрах с теми же номерами, что и для младших половин). Таким образом все векторные команды, кроме 256-битных AVX, используют 1-й векторный РФ для хранения всех операндов и устройства 1-го тракта для исполнения (опять же, без делителя-извлекателя — это ФУ, видимо, просто не уместилось). При работе с командами MMX, SSE и 128-битных версий AVX 2-й РФ не используется, а только хранит своё содержимое. И вот с SSE есть сложность.

Команда SSE, записывающая в некий регистр xmm, сохраняет содержимое старшей половины соответствующего ему регистра ymm, а вот аналог этой команды из набора AVX, работающий с этим же регистром xmm, согласно ISA обнулит старшую часть своего ymm. Ситуация бы упростилась, если бы все программы использовали только 128-битные векторы или только 256-битные. Но всё хуже: 2-й РФ не просто хранит старшие половины ymm — он лишь отслеживает положение соответствующих им младших половин в 1-м РФ, но свои половины синхронно не перемещает. Пример: команда SSE «ADDPD xmm1, xmm2» складывает пару вещественных DP-элементов регистра xmm2 с аналогичной парой из xmm1 и записывает на место последнего результат. После переименования регистров моп команды приобретёт неразрушающий формат операндов и будет выглядеть, например, так: «ADDPD xmm78, xmm34, xmm56» — т. е. до его исполнения архитектурному регистру xmm1 соответствовал физический xmm34, xmm2 — xmm56, а после отставки xmm1 будет назначен на xmm78. А теперь вопрос на засыпку — что будет со старшей половиной регистра ymm1?

Решение

Если бы команда была «VADDPD xmm1, xmm2» (префикс V- используется во всех командах AVX, включая работающие с xmm), то ответ ясен — старшую половину архитектурного xmm1 надо обнулить, что делается разместителем даже без доступа в РФ. А вот для SSE-версии её надо сохранить, что для 2-го РФ означает копирование физического регистра №34 в №78. И это только для одной команды, а всего их может быть до 5 за такт (3 вычислительные и 2 загрузочные). Intel могла бы оснастить старший РФ 5-полосным шлюзом с портов чтения на порты записи, а переименователь — возможностью слежения за половинами ymm отдельно. Но для упрощения и/или экономии инженеры вместо этого внедрили небольшой «теневой» АРФ, хранящий 16 старших половин регистров ymm, когда они не используются SSE-кодом. (Возможно, поэтому для РОНов физических регистров 160, а для xmm/ymm — 144, хотя планировщик общий…) Причём, АРФ должно быть даже два — по одному на поток.

Теперь, допустим, надо исполнить 256-битную операцию с регистром ymm1. Вероятно, планировщик должен подать векторным РФ номера обеих половинок (старшую — из АРФ), считав их содержимое в пару ФУ… Но оказывается, что напрямую из АРФ читать мопам нельзя. Поэтому не будет SB исполнять 256-битную команду AVX сразу после SSE. Вместо этого грянет аж 70-тактовый штраф, в течение которого сначала должны исполниться уже запущенные в резервацию команды (сериализация конвейера), а затем специальная микропрограмма восстановит все 16 старших половин ymm. Более того, и 128-битную AVX-команду тоже ждёт штраф — в АРФ нельзя даже обнулить регистр без выгрузки в основной РФ. Тот же штраф будет при при обратном переходе — когда после AVX-кода встретится любая команда SSE, и старшие половины потребуется сохранить обратно в АРФ. Но если штраф будет происходит часто, программисты хором пошлют AVX на всякие другие буквы, возопив «Как жить дальше?!»

Ответ Intel — «надо чаще обнуляться». В составе набора AVX есть команда VZEROUPPER, сбрасывающая старшие половины всех регистров ymm всего за 1 такт. После этого все связи между половинами можно считать исправленными, т. к. для любого регистра xmmN старшая часть ymmN содержит 0. Переходы между 128-битным и 256-битным векторными кодами не вызовут штраф, т. к. в старших частях точно нули. На физическом уровне АРФ не сбрасывается, а помечается как целиком нулевой, так что его уже не надо грузить в основной РФ. Но произвести сериализацию всё же придётся…

Вспоминая программиста-оптимизатора, во избежании штрафа он должен поставить VZEROUPPER перед вызовом оптимизированной AVX-процедуры и после него. Если процедура находится в библиотеке, вызывать которую может как программа с кодом SSE, так и с AVX, то VZEROUPPER должна быть и в прологе, и в эпилоге каждой функции. Тут может быть полезна ещё одна команда VZEROALL, обнуляющая все регистры ymm целиком. Тем не менее, можно предсказать, что программисты наверняка часто будут забывать вставить команды VZERO* в свой ассемблерный код. Выловить же эти ошибки трудно, т. к. программа всё ещё будет работать, хоть и медленнее, но мало ли на то причин…

Кстати: само существование 128-битных команд AVX в дополнение к таким же, но 256-битным — тоже своего рода костыль. Только на этот раз не для нахождения очередного компромисса внутри процессора между сложностью, скоростью и площадью. Дело в довольно большом объёме кода драйверов и даже компонентов ядер разных ОС, которые используют xmm и точно не будут скоро переписаны под AVX. А значит и общаться с ними надо на «128-битном языке». Но т. к. соблазны AVX-кодировки велики (представитель Intel даже как-то сказал, что неразрушающий формат и компактизация кода в сумме дадут не меньший эффект, чем удлинение векторов), компания решила дать программистам шанс ускорить и 128-битный код, чтобы не переключаться каждый раз со штрафами между SSE и полноразрядным AVX. Впрочем, за счёт своей многочисленности сообщество программистов ядра Linux вполне быстро бы перевело эту ОС на новый формат (будь он обязательным). Поэтому можно сделать вывод, что в сложностях устройства AVX виновата … Microsoft! :)

Сохранение состояния

После удвоения разрядности векторных регистров размер полного описания архитектурного состояния ЦП стал больше на 256 байт — теперь в нём все регистры общего и специального назначений, стек x87 и набор ymm занимают 832 байта. При прерывании и переключении контекста задачи всё это надо как можно скорее записать в специальную область памяти, а при возврате восстановить. А т. к. задержка (особенно для прерываний) должна быть минимальной, объём пересылаемых данных оказывается тому препятствием. В SB регистры общего и специального назначений записываются всегда (впрочем, они и меняются всегда), но есть специальный блок, отслеживающий 3 остальных РФ — стек x87 с регистрами mm для MMX, и старшую и младшую половины регистров ymm для SSE и AVX. Сохраняться и восстанавливаться будут только РФ, модифицированные за текущий сеанс работы с задачей. Например, программа, работавшая лишь с РОНами, сохранит в статусе всего около 100 байт. Однако это произойдёт не автоматически, а при использовании добавленной команды XSAVEOPT, поддержка которой обозначается отдельным битом в CPUID.

Динамические тайминги

При тестировании задержек и пропусков команд (о чём мы детально поговорим далее) мы обнаружили у AVX-кода некую странность, которой «не может быть никогда». Точнее, речь идёт о векторном вещественном сложении (вычитании) и умножении. В идеале, они, как и почти все остальные команды, должны иметь фиксированные тайминги — однако в наших тестах (если, конечно, всё было замерено точно) получилось совсем не так. Судя по всему, в случае долгого неисполнения вещественного кода блоки FADD и FMUL переходят в некое «полувекторное» состояние, когда 256-битные команды обрабатываются каждый 2-й такт, а задержки — на 2 такта больше нормы. Через несколько сот исполненных вещественных команд задержка уменьшается на 1 такт, а ещё через несколько сот, вместе с пропуском, наконец, становится номинальной. 128-битные операции также затронуты — задержка изначально на такт больше, но хоть пропуск не страдает.

Сразу скажем, что представитель Intel заверил нас, что это ошибка в наших тестах. Да и здравый смысл подсказывает, что ничего подобного в ЦП быть не должно. Т. к. требуется экономить энергию, отключая неиспользуемые подолгу блоки (что используется ещё со времён Pentium-M), инженеры наверняка оптимизировали время их включения до 1–2 тактов. А то, что планировщику оказывается куда трудней управлять потоком мопов в «полусонные» ФУ — и вовсе удаляет последние остатки здравого смысла. С другой стороны — никаких ошибок в нашей методике совместными усилиями мы так и не нашли. Тем более, что по такой же схеме были получены и остальные сотни цифр, которые по большей части подтверждены. Однако, если бы мы стали перепроверять все версии, статья бы вышла лет через пять. Тем не менее, проверка будет, пока же при дальнейших обсуждениях таймингов проигнорируем этот странный момент…

Новые и отсутствующие команды

В AVX 1-й версии входят 256-битные команды вещественной арифметики, логики и перестановок, но целочисленную арифметику и сдвиги почему-то оставили 128-битными — до выхода AVX2. Пока что для обработки регистра ymm с целочисленными значениями надо сначала сохранить его старшую половину в младшей половине другого регистра, затем обработать младшие половины обоих (старшие при этом обнулятся) и снова собрать в 32-байтовый вектор. Зачем так сделано, официального объяснения нет, а неофициальное примерно такое — вещественной арифметике большие векторы сегодня нужней, а целочисленной их добавят «потом», и пока выгодней обходиться командами AVX с регистрами xmm. Но ещё раз посмотрим на таблицу ФУ в SB — дополнив 2-й тракт сумматором и подключив его к порту 5, где уже есть блок логики и копирований, мы получили бы в нём полноценное 128-битное АЛУ, которое могло бы работать со своим «собратом по порту» из 1-го тракта. Зачем же добавлять 32-байтовые целочисленные векторы лишь через два года в AVX2, если почти всё уже готово?…

В ГП разных компаний и экспериментальном процессоре Intel Larrabee есть команды с векторными адресами — scatter и gather (разброс и сбор): запись и чтение вектора по индивидуальным адресам или смещениям его элементов, составляющим другой вектор. AVX же эти полезные во многих алгоритмах команды получит лишь во 2-й версии, т. к. для эффективного (т. е. параллельного, а не поэлементного) исполнения требуется серьёзное дооснащение кэша сложными коммутаторами в буфере строки (всей 64-байтовой строки, а не 16-байтового порта кэша). Пока это малосовместимо с требованиями поднять скорость без ущерба для площади и экономии, а потому откладывается до следующей микроархитектуры Haswell.

Но и у 1-го AVX есть, чем заполнить лакуну — команды чтения и записи с байтовой маской. Тут интересно, что замаскированные байты не только не считываются или записываются, но даже и не проверяются на возможность доступа. Например, невыровненное чтение, пересекающее границу страницы памяти, может вызвать кучу неприятностей (промах в кэше или TLB, запрет доступа и пр.), однако если все байты «на той стороне» оказываются с нулями в маске, никаких проблем не будет, т. к. фактический доступ и все проверки для них будут отменены. В отличие от команд разброса и сбора, дополнительных аппаратных блоков тут вводить не нужно, по крайней мере для Intel — уже в Nehalem кэши обладали почти всем нужным для такого функционала, просто теперь он программно управляем. Ещё одна новинка — команда «широковещания» (broadcast), копирующая элемент во все позиции вектора-приёмника (почему-то только из памяти в регистр).

Тайминги команд

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

Итак, к имеющимся командным группам добавлена ещё одна — для вещественных 256-битных команд AVX. За вре́менным неимением конкурентов (до выхода AMD Bulldozer) помечать синим эти клетки не будем. :) Сравнение SB по остальным командам прежде всего показывает увеличение общего IPC в каждой группе до рекордных 4, т. к. учитывались обнуляющие директивы, работающие в каждом домене (кроме x87, где вместо них — обмены регистров).

Если посмотреть на отдельные команды, то главные изменения по сравнению с Core i — умножения. Скалярное целочисленное стало полноконвейерным даже при получении полноразрядного результата, однако тут есть нюанс: указанные 3 такта (справедливые и для умножения 64⋅64=128 бит) это задержка перед получением младшей половины результата, отправляемой в регистр EAX (RAX); старшая, для регистра EDX (RDX), будет готова тактом позже. Это происходит потому, что целочисленный умножитель уникален наличием второго командного порта — основной (принимающий моп для записи EAX/RAX) подключен к 1-му порту резервации, а второй — сразу к двум остальным (0-му и 5-му), откуда он получает моп для записи старшей половины. Выходит, что умножитель как бы находится сразу на всех вычислительных портах. При этом приём мопов возможен парами каждый такт, так что в итоге умножение оказывается полноконвейерным.

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

Дело в том, что в погоне за упрощением (в т. ч. и по причинам экономии) производители ЦП часто делают таблицу таймингов в резервации общей для целой группы команд, даже если нужные ФУ могут обработать некоторые команды быстрее. Например, все основные вещественные команды в архитектурах AMD K7–10 исполняются за 4 такта: скалярные и векторные, одинарной и двойной (не для K7) точности, сложения-вычитания и умножения — во всех восьми комбинациях, хотя в каждой паре второй вариант явно сложнее. Но планировщику проще считать, что все такие команды исполняются за одинаковое время.

Intel такой подход до сих пор использовала только в Pentium II/III/M для команд SSE, что также видно по таблице: для 64-битных ФУ векторные команды должны быть не только полуконвейерными (т. е. с пропуском 2), но и с на единицу большей задержкой, чего как раз нет. Планировщик в Core 2/i стал более разборчивым и даёт отдельные задержки для сложений и умножений, причём для последних — в зависимости от точности. SB же вернул «округлённые вверх» упрощения для всех умножений.

Вообще-то такая стандартизация задержек началась ещё в Nehalem. Его резервация устроена так, что порт 0 выпускает мопы с задержками либо 1 такт, либо 4 и больше, порт 1 — 1 или 3 такта, а порт 5 — только 1. Правда, есть 2-тактовые мопы, запускаемые через все 3 порта, но один такт из пары тратится на межтрактный шлюз. Порты 2, 3 и 4 монопольно используются операциями с памятью и адресами аж с Pentium Pro. В SB изменился лишь порт 0, который теперь выпускает мопы с задержками либо 1 такт, либо 5 и больше (мопов на 4 такта, кажется, уже нет).

Стандартизация задержек повлияла и на команду LEA. В таблице ФУ для SB блок AGU указан как сложный. Это потому, что в сложные зачислены команды LEA, у которых адрес или RIP-относительный, или 3-компонентный (плюс ещё два редких случая), остальные (простые) считаются в АЛУ других двух портов за такт. «Сложное AGU» считает свои адреса аж за 3 такта, хотя AGU в Nehalem справлялось со всеми видами операндов за такт. Возможная причина кроется в том, что никакого AGU в тракте нет, а сложные операции делаются в АЛУ порта 1, но с дополнительным функционалом. Этого бы хватило, чтобы вычислить адрес за 2 такта, но «ленивый» планировщик не поймёт такой моп, так что его задержка «для совместимости» с портом 1 искусственно увеличена до 3 тактов.

Впрочем, нашлись исключения и из стандартов. Оказывается, не все векторные умножения исполняются в порту 0 — несколько целочисленных перенесены в порт 1, но при этом они сохранили задержку в 5 тактов. Причём сами эти команды мало чем отличаются от других векторных целочисленных умножений, так что неясна причина выделения им отдельного специализированного умножителя, который затем расположили в соседнем порту… Ещё страннее ситуация с командами сравнения векторов с целыми элементами: для каждой из 4 разрядностей элемента (от 1 до 8 байт) есть сравнения на «равно» и на «больше». Так вот из этих 8 команд 7 исполняются за 1 такт в любом из двух векторных целочисленных АЛУ (как и ожидалось, ведь сравнение по сути есть вычитание). Но вот отдельно взятая PCMPGTQ (сравнение 8-байтовых элементов на «больше») исполняется только в порту 0 и за 5 (конвейерных) тактов, хотя сложность операции точно такая же. Есть исключения и среди команд преобразования форматов, задержки многих из которых стали на 2 такта больше… В общем, если именно таким образом обновлённый планировщик экономит энергию, на всякий случай напомним: иная простота — хуже. ;)

Из других изменений следует выделить улучшенные тайминги некоторых видов команд скалярного сдвига и вращения. Утверждается, что это сделано специально для ускорения криптоалгоритмов, которым спецкоманды AES-NI не подходят, т. к. они заточены конкретно под шифр AES. Всё бы хорошо, если бы другие виды тех же самых команд, не используемые в криптокоде, в результате не замедлились. Например, двойные сдвиги в Nehalem исполнялись за 4 конвейерных такта. Теперь те из них, что имеют фактор сдвига в виде константы, готовы уже через 1 такт, причём сразу в двух ФУ, зато те, у кого этот операнд — регистр, стали полуконвейерными. Такие же тайминги оказались и у обычных сдвигов (хотя они проще), видимо снова ради стандартизации. Таким образом, почти на каждое улучшение в пропуске или задержке «популярной» команды найдётся ухудшение в исполнении команд менее популярных.

Кэши

В скобках указаны значения для Nehalem (если есть отличие).

Кэш L0m (новый) L1I L1D L2 L3
Размер 1536 мопов 32 КБ 256 КБ 1–20 (2–30) МБ
Ассоциативность 8 8 (4) 8 8 8, 12, 16, 20 (12, 16, 24)
Размер строки 6 мопов 64 байта
Задержка, тактов 3? 4 4–7 (4) 11–12 (10) ≈26–31 (≈35–40)
Число портов 2 1 3 (2) 1 1 на банк, 2–8 банков
(2 на кэш, 1–10 банков)
Разрядность портов 4 мопа 64 байта 64? (32) байта
Частота
(f — частота ядра)
f f/2 Максимум всех f
(2,13–2,66 ГГц)
Политика работы Включающая Включающая
Свободная
Только чтение Отложенная запись
Общий для … Потоков ядра Всех ядер, включая ГП

L1D

Сразу скажем, что кэши L1I и L2 почти не изменились — у первого ассоциативность снова (как и до Nehalem) стала 8, а у второго чуть увеличилась задержка. Самое главное изменение в ядрах, касаемое кэшей, кроется в доступе к L1D, который теперь стал 3-портовым: к раздельным портам чтения и записи добавили ещё один для чтения. Кроме того, как уже было указано, в планировщике Nehalem 2-й порт вычисляет адрес чтения и исполняет само чтение, 3-й вычисляет адрес записи (только), а 4-й — исполняет саму запись. В SB же порты 2 и 3 могут и вычислить любой адрес, и исполнить чтение.

Внимательный Читатель сразу найдёт подвох: портов L1D — 3, а адресных генераторов — 2. При не более чем 16-байтовых обменах их устоявшийся максимальный темп составит 32 байта/такт (либо два чтения, либо чтение и запись). 32-байтовые операции каждым портом обслуживаются за два такта, причём вычисление адреса для конкретной команды происходит в течение первого из них. Так что для двух чтений и одной записи требуется три адреса в течение двух тактов — тогда при потоковых обменах один из трёх нужных адресов можно вычислить заранее в течение второго такта предыдущей 32-байтовой операции. Только так мы получим искомый максимум в 48 байт/такт.

Возникает довольно странный компромисс: три 16-байтовые операции за такт в потоке сделать нельзя. С другой стороны, за такт можно вычислить адреса для двух 32-байтовых обменов, но даже одно 32-байтовое чтение за такт не запустишь, потому что порты чтения не объединяются. Т. е. либо нам не будет хватать числа AGU (тех, что в портах 2 и 3), либо ширины портов, либо возможности их объединения.

Как мы знаем из теории, многопортовость в кэшах чаще всего делается не явная, а мнимая, с помощью многобанковости. Однако Nehalem нарушил это правило, внедрив 8-транзисторные битовые ячейки для всех кэшей ядра. Помимо большей экономии (об этом подробно рассказывалось в статье о микроархитектуре Intel Atom, который тоже применяет такую схему), это также даёт возможность получить истинную 2-портовость (чтение + запись), что и было использовано в L1D — никаких конфликтов по адресам в имеющихся 8 банках не было. В SB банков по-прежнему 8, а портов уже 3. Очевидно, конфликты неизбежны, но только среди адресов портов чтения.

Каждый банк L1D имеет ширину в 8 байт, вместе составляя строку, поэтому каждый из 16-байтовых портов использует 1–2 банка при выровненном доступе и 2–3 при невыровненном. Например, 8-байтовое чтение, пересекающее 8-байтовую границу, использует 2 банка, как и выровненное 16-байтовое. В SB конфликт происходит, если хоть один из банков, нужных одному чтению, также нужен и второму, причём для доступа к другой строке. Последнее означает, что если оба чтения требуют не только одинаковый(ые) банк(и), но и одинаковые номера строк в нём (них), то конфликта не будет, т. к. фактический доступ произойдёт один, и он обслужит оба обращения. В Nehalem, с его единственным чтением за такт, такого, очевидно, быть не могло.

Упомянув о невыровненном доступе, скажем и о более «грешных» делах — пересечении строки кэша, что обойдётся 5-тактным штрафом, и границы страницы виртуальной памяти (чаще всего — 4 КБ), что наказывается в среднем 24 тактами (ситуация требует сериализации конвейера). Причём последняя цифра малообъяснима, т. к. TLB, как мы увидим ниже, способны на одновременную обработку обеих смежных страниц — но даже при последовательном доступе двухзначной цифры получиться не может…

LSU

Изменений в LSU (контроллере L1D, который Intel упорно называет MOB) не меньше, чем в само́м кэше. Начнём с того, что очередь чтения удлинилась с 48 до 64 ячеек, а записи — с 32 до 36. Каждая ячейка привязана к одному мопу, а очередь записи хранит ещё и 32 байта данных (было 16). Очередь чтения хранит все команды считываний, но в каждый момент не более 32 могут обрабатываться на разных стадиях. Фактически, это отдельные диспетчер и планировщик, «ROB» которых хранит 64 мопа, а «резервация» — 32. Когда чтение завершено, моп удаляется из этой резервации, но остаётся в очереди чтения до отставки. Очередь записи хранит информацию до отставки предыдущих команд, когда ясно, что адрес, данные и сам факт исполнения команды верны, а значит её можно попытаться записать в кэш. Если попытка успешна — моп записи уходит в отставку, освобождая место и в очереди, и в ROB. При промахе или других проблемах запись задержится.

Как и все современные кэши, L1D является неблокирующим — после промаха он может принимать дальнейшие запросы одновременно с заполнением себя подгруженными данными. Кэш может выдержать даже 3 промаха/такт. Одновременно удерживается столько промахов, сколько имеется буферов заполнения. В SB, как и в его предшественнике, у L1D таковых 10, а у L2 — 16. Политика отложенной записи в L1D и L2 означает, что модифицированная строка остаётся в кэше до вытеснения, однако информация о факте её модификации (если до этого данные были «свежие») отправляется в теги соответствующей строки в L3.

Внеочерёдный доступ

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

Однако предсказатель оперирует только выровненными на 16 байт чтениями размером до 16 байт, а также выровненными 32-байтовыми — остальные будут ждать вычисления адресов всех предыдущих записей. Ещё одна проблема нового движка в том, что он предсказывает лишь младшие 12 бит адресов: если у записи и чтения они равны (даже если они не предсказаны, а точно известны), то чтение считается зависимым от записи. Т. е. фактически предсказывается лишь 8 бит адреса — с 5-го по 12-й. Возможно, ложная зависимость обусловлена тем, что в ячейках таблицы счётчиков нет поля, хранящего старшую часть адреса.

STLF

…серьёзно улучшен. Описывать громоздкие старые правила для Nehalem мы не будем, укажем сразу новые:

  • байты для чтения должны полностью содержаться в записи, вне зависимости от выровненности адресов и размеров операций; это эквивалентно следующему: W-байтовая запись по адресу A перенаправляется в R-байтовое чтение по адресу B, если A≤B и A+W≥B+R; далее указаны исключения:
  • если запись 16- или 32-байтовая — 4- и 8-байтовые чтения обрабатываются в пределах её 8-байтовых порций;
  • если запись 32-байтовая — все чтения, кроме 32-байтовых, обрабатываются в пределах её 16-байтовых половин;

Ясно, что STLF не может работать одновременно с внеочерёдной загрузкой: адреса записей должны быть известны точно, а не только 8 битами.

Задержки чтения

Видя такое благолепие, яростные фанаты Противоположного Лагеря немедленно требуют какого-нибудь негатива. К сожалению, и он нашёлся: во-первых, обещанные 11 тактов задержки при чтении L2 в наших тестах никак не получались меньше 12; аналогично с L3. Во-вторых (и это гораздо хуже), идеальные 4 такта задержки при чтении L1D доступны не всегда, потому что теперь надо смотреть не только в какой исполнительный домен загрузить данные, но и как вычисляется адрес. Напомним, что в x86 адрес обращения в память состоит из трёх компонент: регистр базы, регистр индекса (возможно, умноженный на масштаб 2, 4 или 8) и адресное смещение (явно указанное в команде). Сочетаться (сложением) они могут в любой комбинации. Как мы помним, в SB можно вычислить аж 3 команды LEA за такт (сложную и две простых), что втрое больше, чем ранее. :) А вот те адреса, что вычисляются в «правильных» AGU (в портах 2 и 3), дают уже втрое больше проблем, которых хватит аж на целую таблицу задержек чтения/записи (тут учтены и все межтрактные задержки на передачу данных):

↓ Свойства адреса \ Тип приёмника → РОН (x)mm x87 ymm
Смещение≥2048 ИЛИ есть индекс 5 6 7 7
Смещение<2048 И нет индекса 4 5 6 7

Учитывая такое безобразие, удивительно, как SB не только не провалил ни один из наших тестов, но даже нигде не оказался медленнее, чем Nehalem с его почти честным 4-тактным L1D. Можно аккуратно предположить, что AGU в портах 2 и 3 настолько просты, что могут за такт сделать лишь одно сложение, да и то с неполной разрядностью одного из слагаемых — иначе оно затянется на второй такт, как и 3-компонентное. Если бы речь шла о 10-гигагерцовом ЦП с конвейером на сотню стадий, это ещё было бы простительно, но тут… Впрочем, есть другой вариант.

Сначала поясним, почему, вопреки тенденции, для ymm-пересылки цифры не указаны как 8 и 7. В одном из патентов Intel указан такой способ переноса «больших» данных из кэша в тракты: учитывая, что межтрактовая задержка в шлюзах равна 1 такту (для смежных трактов), надо в начале считать старшие 16 байт, которые уйдут на самый дальний тракт (2-й векторный), а через такт — младшие, которым надо на один тракт (и такт) ближе — тогда обе половины окажутся на местах синхронно. Вычисление адреса делается «впритык» к самому чтению (если ему ничего не мешает, например занятость портов или незавершённость записи по «подозрительному» адресу). Для этого AGU автоматически прибавляет к смещению 16, а возможно — вычисляет адреса обеих половин одновременно, что может объяснить медлительность при «сложной» адресации. В простом случае 32-байтовое чтение больше ничем не будет отличаться от 16-байтового, но если слово пересекает границу строки кэша, то теги читаются для двух строк, а если и границу страницы памяти — то и в TLB делается второе обращение. Тот же подход используется и при ymm-записях.

TLB

В скобках указаны значения для Nehalem (если есть отличие).

Параметр TLB L1I TLB L1D TLB L2
Размер страницы 4 КБ 2/4 МБ 4 КБ 2/4 МБ 1 ГБ 4 КБ
Размер 128 8+8 (7+7) 64 32 4 (0) 512
Ассоциативность 4 8 (7) 4 4 4 (–) 4
Задержка, тактов 1, учтена в задержке к кэшу 7
Число портов 1 2 1
Политика работы Скорее всего, включающая (для 4 КБ)
Общий для потоков? Да Нет Да

Изменения в подсистеме TLB небольшие: DTLB (так Intel называет TLB L1D) обзавёлся «честной» секцией для «сверхбольших» страниц по 1 ГБ. Впервые их поддержка появилась в AMD K10, а у Intel — в Westmere, однако в последнем они разбивались на множество «просто больших» страниц по 2 МБ и хранились в соответствующей секции TLB. ITLB (TLB L1I) получил две дополнительные ячейки для больших страниц, а STLB («shared TLB», т. е. разделяемый TLB L2) не изменился. Кстати, последний в Nehalem назывался UTLB (unified, единый), а вот для SB кэш L3 на большинстве слайдов переименовали в LLC (last level cache — кэш последнего уровня)… Кажется, кто-то в Intel обожает плодить сущности без необходимости. И кого ж они запутать хотят? :)

Суть странной записи «8+8» вместо «16» раскроется в главе о Hyper-Threading, а вот вопросы «Являются ли все или некоторые TLB неблокирующими?» и «Сколько промахов они могут удержать?» пока и вовсе останутся лишь с догадками «нет» и «нисколько». Зато известно, что при промахе в TLB L2 происходит обращение в адресный транслятор (PMH), на что уходит около 10 тактов. Это подозрительно мало, т. к. трансляция 64-битного виртуального адреса в физический (транслируются, правда, только биты с 13-го по 48-й) требует до 4 чтений из памяти или кэша. Столь быстрая реакция возможна, только если у PMH есть свой кэш. Его параметры и детали работы определить крайне трудно (уж очень тщательно скрыты задержки), но по известным примерам в предыдущих ЦП Intel предположим, что 32 ячейки наверняка найдутся. Точно известно только, что PMH может читать дескрипторы страниц откуда угодно — от L1D до памяти.


Жёлтая структура слева — L1D, внизу-слева — TLB L2, остальное пространство — LSU. В центре видны два почти одинаковых вертикально вытянутых блока — видимо, это TLB L1D.

Таблица выше является настоящим испытанием для Внимательного Читателя. Но подвох обнаруживается быстро — кэш L1D стал 3-портовым (надо полагать, вместе с тегами), а вот его TLB — почему-то нет, хотя было бы естественно. Ошибка? Нет, на фотографии ядра видно, что TLB (очевидно, 1-портовых) осталось 2, как у Nehalem. Видимо, причина в том, что на 2 AGU больше двух обменов/такт не получится, а при использовании команд AVX для достижения пика при потоковых операциях в среднем потребуется и вовсе 1,5 адреса/такт. Видимо, Intel посчитала, что ради экономии места третьи TLB и AGU пока лишние.

В Nehalem к битам TLB было добавлено поле VPID (идентификатор виртуального процесса), сравнение содержимого которого с текущим VPID позволяло определить, относится ли адрес в TLB в адресному пространству этой виртуальной машины или остался после переключения с соседней. Архитектура Westmere преобразовала это поле в более общий формат PCID (идентификатор контекста процесса), что позволило сохранять содержимое TLB не только при переключении виртуальных машин, но и при смене адресации в пределах одной ОС. Что к этому добавлено в SB (и добавлено ли…) — не известно.

Кстати, о виртуализации (раз уж мы пока нигде её не упомянули) — Westmere отличался от Nehalem в т. ч. наличием небольшого кэша на 3 так называемых VMCS (virtual machine control structure, структура управления виртуальной машиной), содержащих архитектурное состояние виртуальной ОС. Кэшировать их полезно для ускорения переключения между ОС. Надо полагать, в SB этот кэш как минимум сохранился, а то и увеличился.

Аппаратная предзагрузка

Для L1D предзагрузчик поддерживает до 4 явно заданных спецкомандами загрузок, но это не так интересно, как автозагрузки. Блок следит за числом ожидающих промахов в L1D, и когда оно мало, а ядро не исполняет потоковую операцию (типа загрузки или сохранения контекста или операций со «строками») — происходит загрузка по одному из предсказанных адресов. Обращения в TLB не нужны, т. к. физический адрес недавно сделанного чтения на некоторое время остаётся и в предзагрузчике, а предсказания никогда не пересекают границу в 4 КБ.

Используются два алгоритма. Первый (простой или потоковый) основан на возрастающих адресах читаемых всеми командами данных — убывающие адреса не обрабатываются, т. к. для этого алгоритма они редки. Второй (сложный или шаговый) имеет буфер предположительно на 256 ячеек — в каждой хранится собственный адрес недавней команды чтения (по его младшему байту ячейка индексируется, когда в очередь чтения LSU поступает новый моп), прошлый адрес её загрузки и шаг последовательности (полагая, что он регулярный и не превосходит ±2048). При каждом исполнении этого чтения предзагрузчик проверяет регулярность шага, и, при положительном исходе, загружает в кэш следующую порцию. Предзагрузка в L1I, как уже описывалось, основана на предсказаниях переходов.

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

Интересно, что сложный алгоритм для L2 (а, возможно, и для L1D) имеет 2-битный насыщаемый счётчик, следящий за востребованностью данных: предположительно, если хотя бы 2 раза подряд предзагруженные данные были полезны, то даже если далее каждое третье обращение будет по «чужому» адресу, алгоритм не собьётся с найденного шага потока.

А теперь сюрприз — всё вышеописанное относится и к Nehalem. В SB же изменился только сложный алгоритм для L2, зато основательно:

  • Теперь он может запустить уже две предзагрузки на каждое чтение этого потока, уходя вперёд максимум на 20 шагов;
  • Вышеописанная функция работает только при достаточном простое L2: при его средней загрузке в него наперёд читается по одной строке, а при сильной — и вовсе ноль (точнее одна, но только в L3);
  • Если шаг большой, то загрузка в L2 также отменяется (близкая локальность обеспечивается простым алгоритмом);
  • Слежение производится за 32 потоками запросов: для каждой из 16 отслеживаемых страниц по 4 КБ допусти́м 1 восходящий и 1 нисходящий поток. Ранее было 12 восходящих потоков и 4 нисходящих, по одному на страницу.

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

Hyper-Threading

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

  • Дублируются: TLB L1I для стр. по 2 МБ, IQ, RSB, IDQ, архитектурное состояние ядра, АРФ для старших половин ymm;
  • Делятся пополам: TLB L1I для стр. по 4 КБ, L0m, ROB, обе очереди в LSU, буфер простого предзагрузчика в L1 (?);
  • Делятся динамически: BTB, резервация, все ФУ, вся подсистема памяти (кроме её блоков, указанных выше);
  • Чередуются по тактам (кроме случаев срыва одного из потоков): все стадии фронта, переименование, размещение мопов в планировщике и отставка.

Поясним, что такое «делятся динамически»: это значит, что блок не знает о существовании двух потоков и никак бы не изменился, если бы в ЦП не было многопоточности. Это особенно наглядно в случае диспетчера: ROB делится между потоками, т. к. надо соблюдать очерёдность размещений и отставок соответственно адресам каждого потока. Но когда мопы попадают в резервацию, адресов в них уже нет, а есть номера ячеек в ROB и ФРФ. Учитывая, что некий регистр-приёмник N при переименовании получит в одном потоке физический регистр X, а в другом — Y (что равносильно двум записям в N в одном потоке), то резервации всё равно, чьи мопы одновременно запускать, а для ФУ всё равно, чьи исполнять.

Наличие дублируемых и статически делящихся пополам ресурсов и чередование потоков по всей поочерёдной части конвейера говорит о том, что лучше всего Nehalem и SB чувствуют себя при исполнении пары почти одинаковых по объёму кода потоков. Причём если это 2 одинаковых потока, то обеспечить загрузку разных ФУ и прочих динамически разделяемых блоков будет трудно — общий алгоритм будет спотыкаться примерно в тех же местах, даже работая с разными данными. А подобрать две разные программы с примерно одинаковом темпом использования кода может оказаться ещё труднее — тем более, что это всецело зависит от ядра ОС, которая почти ничего не знает о внутренних событиях ЦП и загрузке его блоков.

Возможно, Intel не использовала динамическое разделение в TLB L1I (как в остальных TLB, особенно, учитывая, что сам кэш L1I разделяется так же), потому что его нет и у кэша мопов, а эти две структуры при вытеснении срабатывают одновременно. Впрочем, глядя на список пункта «Делятся пополам» (а в этих блоках, напомним, 3 цифры размеров из 4 в SB увеличились), можно сделать вывод, что ускорение от включения HT если не увеличится, то хотя бы с меньшей вероятностью станет отрицательным, что изредка бывало у Nehalem. Проверить это можно будущими тестами.

Внеядро

Кэш L3

Физически, кэш L3 не очень изменился: он по-прежнему разделён на банки по числу x86-ядер. В Nehalem была возможность сделать запись и чтение в/из L3 за такт, если они попадали в разные банки, т. к. использовался общий коммутатор и контроллер на весь кэш. Теперь организация банков другая: можно сделать запись или чтение, но в каждом банке по отдельности. А т. к. число банков почти всегда равно числу ядер (исключения до сих пор встречались только у 6–10-ядерных серверных Xeon, где в некоторых моделях банков на 1 больше или меньше числа ядер), то это фактически линейно увеличивает пропускную способность L3. Учитывая, что она разделяется между всеми ядрами (включая ГП), это очень полезно, т. к. пропуск, приходящийся на каждое ядро, до сих пор был главной проблемой любого разделяемого кэша.

Как и предшественник, ядра SB активней используют КМОП-логику по сравнению с динамической, что отразилось на частоте возникновения ошибок при работе. Это потребовало внедрить более мощные алгоритмы и коды обнаружения и коррекции ошибок (ECC) в кэшах ядер, способные в каждом байте обнаружить и исправить 2-битные ошибки и обнаружить (но не исправить) 3-битные. До сих пор ЦП умели обнаруживать до двух неверных бит и исправлять один, требуя в среднем 1 бит ECC на каждый защищаемый байт. Новый код, видимо, требует не менее 1,5 бит/байт — чуть позже мы сможем это проверить.

Главное изменение в L3 — он стал работать на полной частоте ядра. Точнее, x86-ядер. Точнее, работающего(их) из них в данный момент, т. к. часть ядер могут спать. Помимо увеличения пропускной способности это ещё и уменьшает задержки, которые, разумеется, меряются тактами ядер на их частоте. И вот (см. таблицу с параметрами кэша) в SB они уменьшились на 30%. Это при том, что сама частота кэша вовсе не подросла на 30%. Причина в том, что когда поток данных пересекает силовые (по величине логических «0» и «1» в вольтах) и, особенно, частотные домены, происходит задержка в несколько тактов для преобразования уровней и совпадения фронтов тактовых сигналов. В SB такой проблемы нет, т. к. L3 работает на том же напряжении, что и работающие x86-ядра (не отключенные силовыми ключами), а частота у всех активно загруженных ядер всегда одинакова (включая применение технологии Turbo Boost) — и именно на неё и настроится частота L3.

Правда, всё может оказаться интересней. Внимательный Читатель успел заметить, что кэш L2 работает на половинной частоте, а потому, имея 64-байтовый порт, теряет половину ПС. Такое решение, видимо, связано с разумной достаточностью и 32 байт/такт, а потому можно применить более экономные транзисторы, которые, к тому же, будут работать при меньшей частоте. Про L3 такое достоверно не известно, но резонно предположить, что там ситуация та же: на высокой частоте работают только контроллеры портов кольцевой шины, обрабатывая по 32 байта/такт в каждом порту (детальней об этом ниже), а вот сам кэш работает целыми 64-байтовыми строками раз в 2 такта.

Как и в Nehalem, каждый банк L3 разделён на блоки по 512 КБ и 4 пути. В большинстве ЦП серий Core i в каждом банке таких блоков 3 или 4. Серверные ЦП Xeon с архитектурой Beckton и Westmere-EX имеют 6, 8 или 10 ядер и банков L3, но последние увеличены как по размеру (до 3 МБ), так и по ассоциативности (до 24), что в самых дорогих ЦП даёт аж 30 МБ. Для SB же пока обещаны «лишь» 8-ядерные Xeon с 20-путным L3 на 20 МБ.

Для любителей кунсткамеры добавим, что единственный представитель архитектуры Nehalem с одним работающим ядром (и одним банком L3 на 2 МБ) — это, как ни странно, не какой-то тихой сапой выпущенный сверхбюджетный Celeron, а Xeon LC3518, физически представляющий собой обычный 4-ядерный Nehalem с тремя (!) отключенными ядрами и их банками. Авторы SB также приготовили такие диковинки — это модели Celeron B и Pentium B, где на 2 ядра и ГП приходится не 4, не 3, а 2 МБ кэша с уполовиненной до 8 путей ассоциативностью.

Кольцевая шина




Вверху — слайд 2009 г. о кольцевой шине Nehalem-EX. Внизу — свежий о ней же в Sandy Bridge-EX.

Не только наш Внимательный Читатель догадался, как надо связать L3 и ядра, чтобы ПС кэша росла пропорционально числу банков (а значит — и ядер). Однако эта кольцевая шина, вопреки утверждению Intel, в SB появилась не впервые. Если не считать различных специализированных процессоров (в частности, некоторых ГП), среди ЦП вообще она появилась в 9-ядерных Sony/IBM Cell BE (2007 г.). У ЦП Intel кольцевая шина была внедрена в 8-ядерных серверных Xeon серий Nehalem-EX (2010 г.), откуда с небольшими изменениями она попала SB. Её имеют и только что вышедшие серверные Westmere-EX (Xeon E7).

В каждом направлении протянуто 4 шины: запросов, подтверждений, снупов (для поддержки когерентности) и собственно данных (шириной 32 байта) — разумеется, всё защищено битами ECC. Протокол обмена является чуть переделанной и дополненной версией шины QPI, которую мы привыкли видеть как межпроцессорную шину типа «точка-точка», аналогичную HyperTransport в ЦП AMD. Внутри процессора связываемые «точки» являются агентами, каждый из которых имеет две пары шинных портов (приёмный и передающий в каждую сторону) и пару клиентских. К шинным подключены звенья шины, связывающие соседние агенты. К клиентским обычно подключены локальное x86-ядро и локальный банк L3. Однако в 2/4-ядерных SB один из крайних агентов подключен только к ГП, а второй — только к «системному агенту»; шинные порты также используются наполовину, т. к. в этих местах шина разворачивается на 180°, соединяя противонаправленные звенья. В 8-ядерном серверном SB будет 8 обычных агентов и 4 концевых, каждый из которых разворачивает направление обеих шин на 90°, задействуя все шинные порты, и обслуживает по одному клиенту-контроллеру: по 2 для памяти и для внешних шин (QPI и PCIe).


Агенты кольцевой шины показаны красным.

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

Таким образом, пиковая ПС шины равна полупроизведению числа используемых шинных портов всех агентов, 32 байт и частоты. «Полу-» — потому что требуется 2 порта для каждого звена. Учитывая, что кольцо, как и L3, работает на максимуме частот ядер, абсолютный максимум его ПС получается очень большим: для 4-ядерного ЦП на 3 ГГц — 960 млрд. байт/с (по «славной» традиции производителей винчестеров назовём это 960 ГБ/с :). Для сравнения — в Cell BE ко́льца также передают по 32 байта в каждую сторону, но на одну передачу требуется 2 такта, поэтому этот 9-ядерный ЦП наберёт на 3 ГГц примерно те же 960 ГБ/с.

Физически звенья шины проложены дорожками на самом высоком уровне, доступном для передачи сигналов — 7-м и 8-м слоях металлизации. Вышележащие слои используются только для питания и контактных площадок. Причём дорожки проходят поверх банков L3 и отдельного места не занимают. Такое устройство позволяет масштабировать шину простым копированием агентов и звеньев, что гораздо проще добавления дополнительных портов к центральному коммутатору. Впрочем, у последнего есть и преимущество — задержка прямой коммутации куда меньше, чем транзитной. Однако из-за более высокой частоты кэш L3 в SB оказался всё же с меньшей задержкой, чем в Nehalem.

Поддержка аппаратной отладки

Говоря о кольцевой шине, стоит упомянуть новую отладочную функцию — Generic Debug eXternal Connection (GDXC). Она позволяет мониторить трафик и синхрокоманды шины, перенаправляя их во внешний логический анализатор, подключаемый к спецпорту процессора. Ранее такие тонкие инструменты были доступны разве что производителям системных плат (разумеется, при полной секретности), да самим разработчикам. Но GDXC доступна и системным программистам, что, по идее, должно способствовать вылавливанию ошибок и оптимизации видеодрайверов. Что касается «обычных программистов», им наверняка пригодится увеличение (с 6 до 8) числа счётчиков производительности и событий в каждом ядре.

Когерентность и «поддержка» OpenCL

Nehalem был первым ЦП Intel со времён Pentium 4, в котором кэш последнего (т. е. 3-го) уровня стал включающим относительно остальных. Это означает, что в многопроцессорной системе процессорам будет проще отслеживать копии данных, раскиданных по разным кэшам, что требуется для поддержки их когерентности. Для этого теги каждой строки в L3 среди прочего хранят набор битов, обозначающих я́дра этого ЦП, в кэши которых эта строка была скопирована, а также номера других ЦП, в кэшах которых также есть её копия. Для Westmere-EX число таких битов наверняка не меньше 17 (10 ядер + 7 «остальных» ЦП). Кроме того, тогда же стандартный протокол когерентности MESI обновился до MESIF, включив в себя 5-е состояние Forward, разрешающее ответ на снуп-запрос от другого ЦП (в MESI ответить мог каждый ЦП, что увеличивало снуп-трафик). Соображением минимизации снуп-трафика руководствовалась и AMD, добавив для своих Opteron 5-е состояние Owned и получив протокол MOESI.

Когда при доступе в L3 из какого-либо ядра оказывается, что искомая строка закэширована другим ядром (для простоты предположим, что одним) и может быть им модифицирована, происходит обращение к его кэшам L1D и L2 для проверки её актуального состояния. Проверка называется «чистой», если данные оказались нетронутыми, и «грязной», если они модифицированы и требуют копирования в запрашивающее ядро и L3. В SB первый случай вызывает задержку в 43 такта, а второй — в 60. Эти указанные в документации цифры почему-то являются константами, хотя должны зависеть от топологического расстояния между ядрами на кольцевой шине. Да и разница в 17 тактов куда больше, чем положенные 2 для передачи 64 байт…

Новинкой в SB по части включающей политики L3 является то, что биты присутствия копий данных в кэшах ядер учитывают и ГП. Т. е. с точки зрения программы ГП можно использовать как векторный сопроцессор, работающий с общими данными в общем адресном пространстве. По идее, поддержка OpenCL 1.1 в ГП этому должна способствовать, что успел заявить Thomas Piazza, глава отдела графических архитектур Intel. Однако некоторые аналитики упорно писали, что OpenCL в SB не поддерживается. Ещё один детектив? Да, и он распутан.

Согласно заявлению другого представителя компании, поддержка физически есть, но из-за неготовности драйвера при его активации по-прежнему будут использоваться лишь ресурсы x86-ядер. Когда появится обновление, где всё заработает, — сказано не было. По менее официальным каналам получен намёк, что и до этого ГП как-то можно будет использовать в качестве сопроцессора. Но только после доделки нужного SDK (инструментального пакета для программистов) ГП будет доступен не «как-то», а по-человечески. :)

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

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

Системный агент и ИКП

Системный агент — это та часть «внеядра», которая получается после вычета кэша L3 и ГП. Остаётся вот что:

  • арбитр со своим портом кольцевой шины — коммутирует потоки данных между остальными частями агента;
  • порт отладочной шины GDXC;
  • контроллер шин QPI (1–2 соединения на 25,6, 28,8 или 32 ГБ/с) — очевидно, присутствует только в серверных моделях;
  • контроллер шин PCIe 2.0 (на 1 ГП/с) или 3.0 (2 ГП/с, только для Xeon) — в зависимости от модели может быть 16-, 20-, 24- и 40-полосным и допускает различные схемы соединений по числу полос: для наиболее распространённых 20-полосных моделей это x16+x4 (для большинства мобильных SB доступен только этот вариант), x8+x8+x4 и x8+x4+x4+x4 (только для младших Xeon);
  • контроллер шины DMI 2.0 — для соединения с PCH (чипсетом): фактически немного преобразованный 4-полосный канал PCIe, по сравнению с v1.0 (в Nehalem и Atom) удвоил ПС до 4 ГБ/с (сумма в оба направления);
  • «гибкое межсоединение экранов» (Flexible Display Interconnect, FDI) — порт для соединения с контроллером физических интерфейсов экранов в составе чипсета, также переработанный из PCIe;
  • ускоритель (де)кодирования видео;
  • контроллер памяти;
  • программируемый силовой контроллер (Power control unit, PCU) с собственной прошивкой.

Наиболее интересными тут оказываются 3 последних пункта. Однако видеоускоритель оставим для обзора графической части, тут же расскажем об ИКП. Он поддерживает 2–4 канала памяти вплоть до DDR3-1600 (с ПСП 12,8 ГБ/с на канал), но для настольных и мобильных ЦП — только 2 канала DDR3-1333. Каждый канал имеет отдельные ресурсы и независимо обслуживает запросы. ИКП имеет внеочерёдный планировщик операций (!), максимизирующий ПСП с минимизацией задержек. Кроме того, ещё в версиях Nehalem для Xeon появилась технология SMI (Scalable Memory Interconnect, масштабируемое межсоединение памяти) с использованием подключаемых SMB (масштабируемый буфер памяти, аналог буфера AMB из FB-DIMM, но находящийся не на модуле, а на системной плате). Буфер подключается скоростной последовательной шиной к каналу ИКП процессора и позволяет подключить к себе большее суммарное число модулей, чем напрямую к ЦП. Правда, от этого ухудшаются и задержки, и частота работы памяти.

В каждом канале есть 32-строковый буфер записи, причём запись считается завершённой, как только данные попадут в буфер. Как ни странно, слиянием записи этот буфер не занимается, в результате чего частичные записи (когда обновляется не вся строка) обрабатываются неэффективно, т. к. требуют чтения старой копии строки. Это странно, учитывая, что современные микросхемы памяти учитывают битовую маску записи не только для отдельных 8-байтовых слов (которых 8 на строку), но и байт в словах, потому комбинация неизменной и обновлённой частей строки производится внутри чипа памяти, а не в ИКП. Впрочем, в SB ИКП (как и кэши) может включать продвинутые методы ECC, и для этого даже частично обновляемую строку для пересчёта ECC надо начала считать целиком. Причём это правило работает даже при применении обычной памяти, а также в большинстве мобильных моделей, где ECC-память вовсе не поддерживается.

Turbo Boost 2.0

Силовой контроллер системного агента отвечает сразу за 3 функции — защита от перегрева, сохранение энергии и авторазгон (именно в таком порядке они добавлялись с эволюцией ЦП x86). Последний пункт в процессорах Intel известен как технология Turbo Boost (TB). Её обновлённая версия является одним из главных «гвоздей программы», т. к. для слабопараллелизуемых программ она может дать ускорение не меньшее, чем все архитектурные улучшения в ядрах.

Напомним, что TB следит за текущими частотами, напряжениями питания, силами тока и температурами разных частей кристалла, чтобы определить, можно ли повысить работающим ядрам частоту на очередной шаг множителя (отдельно для x86-ядер и ГП). При этом учитываются пределы по всем вышеуказанным параметрам. Главной новинкой 2-й версии TB является дополнительное повышение частот, происходящее сразу после периода простоя всех или большей части ядер и обусловленное температурной инерцией системы «ЦП + радиатор». Очевидно, что при включении нагрузки и всплеске выделения тепла температура кристалла достигнет некоего значения не мгновенно, а плавно и с замедлением. Так вот если текущая температура пока ещё не критическая, и по остальным параметрам также есть запас, то контроллер ещё чуть поднимет множитель, ещё чуть увеличив потребление и выделение энергии и ещё чуть увеличив скорость роста температуры. Кстати, Intel продемонстрировала стабильную работу 4-ядерного SB на частоте 4,9 ГГц с воздушным охлаждением…


Зелёным пунктиром обозначена частота, а красным — температура. Во врезке — типичная нагрузка на ЦП домашнего ПК.

В зависимости от качества кулера и политики BIOS по регулировке оборотов вентилятора при разной температуре, первые 10–25 секунд после относительно длительного простоя процессор будет потреблять больше величины TDP, а занятые ядра теоретически должны работать на бо́льших частотах, чем у ЦП Westmere в тех же обстоятельствах. Как только температура поднимается до критической отметки, частота снизится к обычному «турбированному» значению — это снизит и выделение тепла до TDP, а температура расти перестанет. Выигрыш в том, что в течение нескольких секунд система будет работать чуть быстрее, чем с Turbo Boost 1.0. Т. е. вторая версия технологии является «турбонаддувом турбобуста». Отсюда ясно, на какие сценарии это рассчитано — периодический запуск малооптимизированных под многопоточность программ, быстро решающих свою задачу и снова погружающих систему в простой на несколько минут. При домашней и офисной работе — типичная ситуация.

Не стоит забывать, что теперь каждый шаг множителя для x86-ядер равен 100 МГц, а не 133, поэтому напрямую сравнивать «турбо-формулы» SB и Nehalem не получится. Для ГП шаг равен 50 МГц, а для ИКП — 266 (максимум — 2166, автоматически не разгоняется). Частота шины DMI принимается как базовая, от которой отталкиваются остальные часто́ты всей системы. Впрочем, ровно по этой причине её как раз надо оставить на стандартных 100 МГц, и если уж заниматься разгоном, то только через множители. Кстати, отдельный тактовый генератор теперь не обязателен и будет присутствовать лишь на дорогих «оверклокерских» платах, а остальные станут чуть дешевле и проще.


Обычно тактовый генератор южного моста подключен к нескольким делителям в самом мосту, а через шину DMI — и к ЦП с его разнообразными умножителями…


…Но в дорогих платах внешний генератор тактирует всё.

Экономия

Методы достижения энергоэффективности в архитектуре Nehalem почти совпадают с оными в ЦП Atom, что описано во 2-й части его детального обзора на нашем сайте (правда, поддержка состояния глубокого сна C6 и низковольтной памяти LV-DDR3 появилась только в Westmere). А что появилось в SB?

Во-первых — второй тип термодатчиков. Привычный термодиод, показания которого «видят» BIOS и утилиты, измеряет температуру для регулировки оборотов вентиляторов и защиты от перегрева (частотным троттлингом и, если не поможет, аварийным отключением ЦП). Однако его площадь весьма велика, потому их всего по одному в каждом ядре (включая ГП) и в системном агенте. К ним в каждом крупном блоке добавлено по нескольку компактных аналоговых МОП-схем с термотранзисторами. У них меньший рабочий диапазон измерений (80–100 °C), но они нужны для уточнения данных термодиода и построения точной карты нагрева кристалла, без чего нереализуемы новые функции TB 2.0. Более того, силовой контроллер может использовать даже внешний датчик, если производитель системной платы разместит и подключит его — хотя не совсем ясно, чем он поможет.

Добавлена функция перенумерации C-состояний, для чего отслеживается история переходов между ними для каждого ядра. Переход занимает время тем большее, чем больше «номер сна», в который ядро входит или из которого выходит. Контроллер определяет, имеет ли смысл усыплять ядро с учётом вероятности его «пробудки». Если таковая ожидается скоро, то вместо затребованного ОС состояния C6 или C3 ядро будет переведено в C3 или C1, соответственно, т. е. в более активное состояние, быстрее выходящее в рабочее. Как ни странно, несмотря на большее потребление энергии в таком сне, общая экономия может не пострадать, т. к. сокращаются оба переходных периода, в течение которых процессор совсем не спит.

Для мобильных моделей перевод всех ядер в C6 вызывает сброс и отключение кэша L3 общими для банков силовыми ключами. Это ещё сильнее снизит потребление при простое, но чревато дополнительной задержкой при пробуждении, т. к. ядрам придётся несколько сотен или тысяч раз промахнуться в L3, пока туда подкачаются нужные данные и код. Очевидно, в совокупности с предыдущей функцией это произойдёт, лишь если контроллер точно уверен, что ЦП засыпает надолго (по меркам процессорного времени).

Core i3/i5 прошлого поколения являлись своеобразными рекордсменами по требованиям к сложности системы питания ЦП на системной плате, требуя аж 6 напряжений — точнее, все 6 были и ранее, но не все вели в процессор. В SB силовые шины изменились не числом, а использованием:

  • x86-ядра и L3 — 0,65–1,05 В (в Nehalem L3 отделён);
  • ГП — аналогично (в Nehalem почти весь северный мост, который, напомним, являлся там вторым кристаллом ЦП, питается общей шиной);
  • системный агент, у которого частота фиксирована, а напряжение — постоянное 0,8, 0,9 или 0,925 В (первые два варианта — для мобильных моделей), либо динамически регулируемое 0,879–0,971 В;
  • умножители частоты — постоянное 1,8 В или регулируемое 1,71–1,89 В;
  • драйвер шины памяти — 1,5 В или 1,425–1,575 В;
  • драйвер PCIe — 1,05 В.

Регулируемые версии силовых шин используются в разблокированных видах SB с буквой K. В настольных моделях частота простоя x86-ядер повышена с 1,3 до 1,6 ГГц, судя по всему, без ущерба для экономии. При этом 4-ядерный ЦП при полном простое потребляет 3,5–4 Вт. Мобильные версии простаивают на 800 МГц и просят ещё меньше.

Модели и чипсеты


Серверные и настольные варианты SB для разных разъёмов. Обратите внимание на разную частоту работы ИКП в зависимости от числа подключенных модулей и их типа. Иллюстрация с pc.watch.impress.co.jp.

Очередную смену разъёма для настольных линеек (с LGA1156 на LGA1155) обсуждать не будем — эта тема уже избита. :) По традиции укажем на список моделей в Википедии, хотя на момент сдачи этой статьи туда ещё не внесли несколько недавно анонсированных ЦП.

Традиционный для обоих производителей x86-ЦП модельный бардак начинается с самого мощного, «серверного» вида (без ГП, с 4-канальным ИКП и 40 полосами PCIe 3.0), также известного как SB-E — он попадёт и в десктопы под именем Core i7 Extreme и даже просто Core i7, «потеряв» 2–4 ядра, 8 полос PCIe и, возможно, 1 канал ИКП и снизив объём L3 с 20 МБ до 10–15. TDP «экстремалов», как и прежде, останется на 130 ваттах. Остальные анонсированные модели i7 — это «просто мощные» настольные ЦП, как и полагается. Среди i5 тоже есть исключения — они могут быть и 2-ядерными (с половинным размером L3). Среди i3 исключений нет, и на том спасибо.

Всё ещё живые Pentium и в очередной раз воскресшие Celeron лишены поддержки HT, AVX, AES-NI и TB для x86-ядер. Обе марки имеют три вида, обозначаемых буквой у номера модели — настольные G***, мобильные B*** или *** (только цифры) и встроенные ***E (с поддержкой ECC). Встроенные и часть мобильных ЦП используют корпус BGA1023, остальные мобильные — под разъём Socket G2. Celeron G440, B710, 787 и 827E — 1-ядерники, причём последний лишён даже ускорения 3D в ГП. Кэш L3 сократили до 1,5 МБ у 827E и 1 МБ (!) у B710 и 787. Pentium G имеют 3 МБ L3, а все остальные версии Pentium и Celeron — 2.

Мобильный ряд прежде всего удивляет моделью Core i7 Extreme 2920XM за $1096. Видимо, дверью ошиблась — это к модным нынче экономным серверам (где разблокированный множитель не пригодится), а не для портативных приборов с автономным питанием и слабеньким кулером. У мобильного i7 может быть разным размер L3 и число ядер (с буквой Q или X их 4, иначе — 2). i5 в этом отношении более стабильны, а у единственного пока i3 Turbo Boost работает только для ГП. Мобильные Core получат «старшую» графику (о различиях между ними — ниже), а вот Pentium и Celeron (даже настольные) помимо половины 3D-блоков лишены и технологий Clear Video HD (улучшение видеопотока «на лету») и QuickSync (аппаратный перекодировщик видео).

Номера моделей мало что скажут. Core i теперь 4-значные и начинаются с двойки; Pentium, наоборот, одну цифру потеряли (причём разница между 600-ми и 800-ми моделями — только в частоте и (не)поддержке памяти DDR3-1333). Если у настольной модели последняя цифра — 5, то у неё старший ГП, а если 0 — то младший. Однако для 2600K и 2500K это не работает: полноценная графика (вдобавок к разблокированному множителю) есть именно у них, а не у несуществующих 2605K и 2505K. У мобильных ЦП эта же пятёрка означает поддержку ECC-памяти и развилки шины PCIe. Ещё последней цифрой может быть 2, что означает включение этой модели в программу Processor Performance Upgrade — о ней мы расскажем в ближайшей статье.

Вдобавок, Внимательный Читатель нам напомнит, что с января 2011 г. выпускаются мобильные Celeron 763 и 925 на ядре Penryn 4-летней давности для пред-предыдущей архитектуры. А теперь сравним их (1 ядро, 1 МБ L2 и, разумеется, никакого ГП и L3) с готовящимися к выпуску мобильными же Celeron 787 и 857: 787 — 1-ядерник с 1 МБ L3, а 857 — 2-ядерник с 2 МБ; у 857 по сравнению с 787 базовая частота x86-ядер — меньше, базовая частота ГП — та же, а турбо-частота ГП — больше. А теперь попробуйте определить хотя бы что-то из этого только по номерам моделей…

Буквы S и T после номера означают «средне» и «очень» экономные модели, но сравнивать их частоты не получится: например, модель Core i5-2500 быстрее и прожорливей, чем 2500S, которая быстрее и прожорливей, чем 2500T, но вот насколько именно в каждом случае — без таблицы не ясно. Вдобавок, «очень» экономные Xeon обозначаются буквой L, а не T, а ещё есть не менее экономная встроенная модель i3-2340UE. Также известно, что настольные Pentium и Celeron моделей GxxxT дополнительно лишатся ускорения 3D в ГП, но вот Celeron G440 с тем же TDP в 35 Вт буквы T не имеет. У «просто» экономных мобильных и встроенных ЦП номера заканчиваются на 9, а у «самых» — на 7.

Удивительно, как Intel сама себе делает подножку: на сайте компании есть официальная и постоянно обновляемая база данных процессоров с почти полным списком характеристик старых и текущих моделей. В ней с удивлением можно обнаружить, что новый Pentium 957, оказывается, не имеет виртуализации, хотя все остальные источники (включая заявления самой Intel) говорят, что ни один ЦП новой архитектуры не лишится поддержки VT и x86-64.

Короче, бардак полный и, судя по всему, намеренный. Но один намёк на порядок всё же есть: если расположить модельные ряды как «Celeron-Pentium-i3-i5-i7», то в каждой линейке все ЦП окажутся дороже самого дорогого из предыдущей и дешевле самого дешёвого из следующей. Впрочем, уже сейчас (для текущих цен и пока анонсированных моделей) это работает лишь по отдельности для настольных и мобильных процессоров, ибо мобильный Celeron B810 сто́ит, как самый быстрый настольный Pentium. Но даже с этой поправкой нельзя твёрдо сказать, что Intel именует ЦП не по производительности, а по цене, ибо откуда тогда берутся сами цены? :)

      
Чипсеты-близнецы H67 и P67.

Некоторые странности до сих пор имелись и среди чипсетов: долгое время можно было купить системную плату либо с поддержкой разгона (на чипсете P67), либо встроенного ГП (на H67). Пользователи, которые хотели и того, и другого, недоумевали, почему их поставили перед выбором «или-или». Ответ прост: чипсет Z68 с поддержкой «всего» вышел лишь в мае, на 4 месяца позже старта платформы. Причём физически это всё тот же P67/H67 (который суть один и тот же кристалл), только со всеми разблокированными функциями.


Чипсет Z68.

Помимо этого, для «бизнес-сектора» (малопонятный автору термин маркетологов) выпущены настольные Q67, Q65 и B65 — это H67 с поддержкой PCI; у последних двух только 1 (из 6) порт SATA — версии 3.0 (а не 2 из 6, как в остальных чипсетах), т. е. поддерживает скорость 6 Гбит/с, а у B65 нет RAID. Наиболее дешёвая модификация — H61, без PCI, RAID и SATA 3.0. Мобильных чипсетов набирается пять: стандартные QM67, QS67 и HM67 (с TDP около 3,9 Вт и размером микросхемы 25×25 мм) и экономные UM67 и HM65 (3,4 Вт и 22×22 мм). QM67 и QS67 допускают полный ручной разгон всех ядер (являясь по этой части мобильным аналогом P67); а ещё вся пятёрка имеет разную поддержку RAID — от никакой в HM65 и UM67 до уровней 0, 1, 5 и 10 в QM67 и HM67. Судя по всему, этот же южный мост применяется и в чипсетах C202, C204 и C206 для младших Xeon серий E3 (которые суть обычный 4-ядерный SB).

Проблему с поддерживаемыми функциями Intel уже продемонстрировала ошибкой в контроллере SATA во всех выпущенных в начале года чипсетах. Исправление и перевыпуск, как известно, влетели в миллиардную «копеечку», а репутационные издержки и вовсе трудновыразимы.

Кристалл

Техпроцесс

Физически техпроцесс 32 нм для SB мало отличается от такового для Westmere. Главное улучшение — в компенсации разброса параметров транзисторов, прежде всего утечки тока. Например, в Westmere в разных кристаллах на 300-миллиметровой пластине утечка могла иметь 4-кратную разницу, что особенно влияет на надёжность записи в кэши и РФ. Компенсация этого разброса для SB позволит достичь большего выхода годных кристаллов, лучшей экономии и более высоких частот. Как именно? В каждую линию шин записи в РФ и кэшах добавили программируемую «подтяжку» из трёх транзисторов разного размера, стабилизирующую уровень логической «1» в зависимости от утечки. Во время заводского тестирования утечка замеряется в разных местах кристалла, после чего «подтяжки» программируются на наиболее точную комбинацию транзисторов (из 8 возможных) для улучшения надёжности записи.

По некоторым данным, в кэшах Westmere использовалось не менее трёх видов ячеек СОЗУ. Для основных матриц L3 — средневольтная высокоплотная (площадью 0,171 квадратных микрон на бит), для тегов L3 — низковольтная скоростная (0,199 мк²/бит), а для L2 и L1 (включая теги) — 8-транзисторая ультранизковольтная скоростная (0,256 мк²/бит, но для L1 удельная площадь кэша примерно вчетверо больше за счёт многопортовости и встроенной в матрицу логики). Разнообразие видов СОЗУ показывает, что инженеры в каждом случае нашли свой баланс между скоростью срабатывания, площадью, потреблением и надёжностью хранения и работы. В частности, имея в L2 8-транзисторные ячейки, можно было устроить «бесплатный» порт записи — однако этот кэш не сделали 2-портовым, видимо, по причине усложнения управляющей логики, непропорционального получаемому ускорению.

Судя по всё ещё актуальной проблеме разброса параметров, для SB техпроцесс значительно оптимизировать не удалось. Тем не менее планки по частоте и экономии подняты — в частности, т. к. L3 теперь запитывается той же силовой шиной, что и x86-ядра, он должен быть рассчитан на работу при 0,65 В (при низкой нагрузке), что ниже минимального вольтажа для L3 в Westmere (0,8 В). Уменьшенного потребления удалось достичь без увеличения площади хранения бита, но со штрафом для надёжности — доля моделей SB с полным (не заблокированным частично) кэшем L3 пока оказывается меньше, чем у Nehalem и Westmere.

Виды кристаллов

4 вида кристалла для SB имеют такие физические показатели (для 8-ядерных — предполагаемые):

Модели Core i5/i3,
Pentium,
Celeron
Core i3,
Core-М°
i7/i5/i3
Xeon,
Core i7/i5
Xeon,
Core i7
Extreme
Число ядер x86 и ФУ ГП* 2 + 6 2 + 12 4 + 12 8 + 0
Объём кэша L3, МБ 3 4 8 20
Число транзисторов, млн. 504 624 995 ≈2200
Площадь кристалла, мм² 131 149 219 ≈400
Размер кристалла (Ш×В), мм 13,803×9,507 14,554×10,256 21,078×10,256 ≈20×20

° — мобильные варианты
* — под графическим ФУ понимается конечный исполнительный блок, иерархически эквивалентный «потоковому процессору» (SP) AMD и «CUDA-ядру» NVidia.

Помимо этих цифр также обнародовано, что старший 12-блочный ГП типа HD Graphics 3000 имеет 114 млн. транзисторов (обозначим эту меру как Мтр.), а 1 ядро x86 — 55 Мтр. (включая кэш L2). Из этих цифр можно подсчитать, что банк L3 на 2 MБ имеет 130,5 Мтр., а младший 6-блочный HD Graphics 2000 — 59 Мтр.


Кристалл 4-ядерного SB (по ссылке — очень детальное фото).

Посмотрим на кристалл — на примере 4-ядерного, фото которого — единственное доступное на сегодня. Как и в предыдущей архитектуре, Intel использовала модульную схему, позволяющую относительно легко получать новые модификации простым изменением числа блоков. В данном случае видны 4 модуля «ядро x86 и локальный банк L3», ГП (большой блок слева), системный агент со всеми контроллерами (справа) и физические интерфейсы (драйверы) шин: PCIe (вдоль правого края), FDI (в нижнем правом углу), памяти (внизу), GDXC (в нижнем левом углу) и DMI (в верхнем левом углу). Области с монотонным цветом общей площадью ≈12 мм² — пустые.

Устройство ГП


Блок-схема ГП в Sandy Bridge. Иллюстрация с pc.watch.impress.co.jp.

Первое, что любопытно — его младшая версия получена не просто путём отсечения половины ФУ у старшей, но и последующим уменьшением размеров кристалла и по ширине, и по высоте. Этот факт мы исследуем позже, а тут обратимся ко второму моменту — если 59 Мтр. для HD Graphics 2000 верны, то всё, что остаётся после вычитания всех ФУ, занимает всего 3,4 Мтр. А ведь в ГП, помимо исполнительных блоков, есть много общих и не менее сложных ресурсов (площадь и сложность которых видна в центральной части ГП, а их количество — на блок-схеме): планировщик и кэш кода, процессор вершин, растеризатор, текстурный сэмплер и прочее.

Учитывая, что одно из рекламируемых преимуществ нового ГП Intel — это не только удвоенная (до 128 бит) разрядность ФУ (за счёт чего вся 3D-графика ускорилась «вдвое»), но и большее число аппаратных блоков — скорее всего общие части займут не намного меньше транзисторов, чем ФУ. Из чего надо сделать вывод, что цифра в 59 Мтр. занижена, а значит — из сокращённого 2-ядерного кристалла убрали что-то ещё, помимо половины ФУ в ГП. А т. к. все ядра и банки L3 мы уже посчитали, подозрения падают на системный агент — тем более, что именно в нём находится аппаратный перекодировщик QuickSync, отключенный в самых младших моделях, ГП которых из-за этого зовётся HD 1000. Чуть позже у нас окажется способ это проверить. Пока же заметим, что 4-ядерные модели с младшим ГП получены стандартным отключением 6 ФУ.

Устройство банка L3

В таблице не зря указаны именно физические параметры кэша L3 — фактически доступные размер и ассоциативность зависят от конкретной модели, ведь при заводском тестировании что-то могут отключить. А вот плотность в 7,8 транзистора/бит — общая для всех. Напомним, что стандартная ячейка применяемого в кэшах статического ОЗУ имеет 6 транзисторов, а экономная — 8 (с ущербом для площади, поэтому её размещают только в ядре, кэши которого относительно малы). Если из 130,5 Мтр. (для банка L3 на 2 МБ) вычесть положенные 100,7 Мтр. (при 6-транзисторных ячейках только для данных), останется 29,8 Мтр. Этого должно хватить на биты ECC (1 на байт) и теги (предположим, что это 50 бит на строку, включая свои биты ECC). Тогда контроллеру банка и агенту кольцевой шины останется 7,4 Мтр., что вполне вероятно.


Банк кэша L3 на 2 МБ. Вверху — агент кольцевой шины. В центре — контроллер банка. Справа от них — теги и ECC (вертикальный ряд). Остальные блоки — массивы данных. Нижние 4 пути могут отсутствовать.

Т. к. продвинутые методы ECC внедрены для защиты наиболее уязвимых, ультранизковольтных ячеек, в L3 они не применяются, поэтому выше мы посчитали число битов ECC как стандартный 1 на байт. Теперь посмотрим на фото банка. Видно, что каждый блок тегов состоит из двух матриц (бордового цвета). Размер большей из них составляет 10% от размера обслуживаемых матриц с данными (в которые, видимо, встроены и биты ECC), но с учётом меньшей плотности тут хранится примерно 8,5% информации от объёма строки и её ECC (576 бит) — и это почти соответствует вычисленному нами значению в 50 бит на строку. А вот что хранят малые матрицы тегов — сказать трудно…

2-ядерные кристаллы

Если кто думает, что в высокоинтеллектуальной аналитике процессорных архитектур нет места легкомысленным «фотожабам» — наслаждайтесь: попытаемся представить, как выглядят остальные два выпущенных кристалла для 2-ядерных моделей (возможно, Intel опубликует и их изображения, так что можно будет проверить). Со старшим вариантом проблем нет — удалив «лишние» 2 x86-ядра, сместим вправо ГП, водрузив его над левой третью ИКП.


Почти так должен выглядеть 2-ядерный SB с 4 МБ L3 и старшим ГП.

А вот с младшей версией всё интереснее. Сначала обратим внимание, что каждый банк L3 не зря имеет пусто́ты в нижней четверти — в некоторых 4-ядерных моделях отключена одна 4-путная четвертинка каждого банка, а в младшем 2-ядерном кристалле нижние четверти в обоих банках и вовсе физически отсутствуют. Управляющих цепей там нет, поэтому после урезания каждого банка сместим ИКП и ГП вверх.

Однако чтобы эта версия кристалла оказалась меньше и по высоте, ГП также придётся обрезать. Обратим внимание на его верхнюю часть с массивом блоков в 3 ряда и 4 колонки — это и есть 12 ФУ. Для образования необходимого сдвига достаточно отсечь верхний ряд, оставив 8 ФУ, из которых 2 будут выключены. Правда, при этом отсекается и верхний край драйвера шины DMI, а ниже (на место GDXC) его не переставить — слишком высокий.

Допустим, мы всё же как-то смогли сместить ГП вверх. Но тут нас ждёт ещё один сюрприз — локальный агент шины и контроллер L3 окажутся не на одной линии с остальными. Если в этом месте шине придётся сделать 2 поворота на 90°, это ограничит её максимальную частоту работы, а т. к. она должна совпадать с частотой x86-ядер — то и их. Значит, такое решение применяется только в недорогих ЦП, которым высокая частота не очень важна — но этот вывод нарушает наличие модели Core i5 2390T, которая имеет штатную частоту 2,7 ГГц, а авторазогнанную — до 3,5 ГГц. Правда, можно также предположить, что агент остался на месте, но небольшой кусочек логики «под» ним (в правом нижнем углу ГП) перемещён в положение «над». Но это замедлит уже сам ГП, а его скорость у вышеуказанной модели — до 1,1 ГГц (почти как в топовых моделях).

На этом трудности не заканчиваются — нам ещё придётся где-то «откусить» те же 3/4 миллиметра и по ширине. Хорошо бы подошёл контроллер PCIe, но лишать процессор со слабым встроенным ГП возможности подключения мощного внешнего — кощунство (хотя это очень удобно бы объяснило «подозреваемые на пропажу» транзисторы в системном агенте). А ещё справа расположен не менее важный контроллер FDI. Драйвер DMI слева также некуда девать, к тому же между ним и драйвером GDXC есть часть графической логики…

Всё это намекает на такой итог: у инженеров графического отдела было достаточно времени, чтобы подготовить сразу две версии раскладки блоков ГП — полную (на 12 ФУ) и компактную (на 6). Причём во второй версии некоторые общие блоки удалены (!), а остальные заметно переставлены, за счёт чего и нашлось место для сокращения и по длине, и по ширине. Таким образом, «обвинения» в пропаже транзисторов могут быть предъявлены не только системному агенту (где удалена как минимум мало кому нужная GDXC, а возможно — и блок QuickSync), но и ГП.

Проверить гипотезу можно двумя способами: дождавшись фото этого кристалла и/или детально исследовав, чем отличаются версии ГП в 2-ядерных моделях, помимо числа ФУ. С «гаданиями по чипу» на сегодня закончим, но заметим, что Intel вряд ли пошла бы на такие сложности, если бы не было очень серьёзного повода для экономии этих несчастных 18 мм² (всего 12% от площади старшего 2-ядерного кристалла), при том, что 12 мм² в 4-ядернике пропадают зря. Возможно, этот повод — минимизация стоимости наиболее популярных моделей, в т. ч. и для лучшего продвижения в мобильном сегменте. Посмотрим, как это отразится на ценах…


Ядро Westmere по сравнению с синтезированной моделью ядра SB (на 2010 г.). Как видно, разработчики уместили все новшества почти на той же площади. Иллюстрация с chip-architect.com.

Производительность

Что эта глава делает в теоретическом обзоре микроархитектуры? А то, что есть один общепризнанный тест, уже 20 лет (в разных версиях) использующийся для оценки не теоретической, а программно достижимой скорости компьютеров — SPEC CPU. Он может комплексно оценить производительность процессора, причём в наилучшем для него случае — когда исходный код тестов скомпилирован и оптимизирован для тестируемой системы (т. е. походя проверяется ещё и компилятор с библиотеками). Таким образом, полезные программы окажутся быстрее лишь с написанными вручную вставками на ассемблере, на что сегодня идут редкие смельчаки-программисты с большим запасом времени. SPEC можно отнести к полусинтетическим тестам, т. к. он и ничего полезного не вычисляет, и никаких конкретных цифр не даёт (IPC, флопсы, тайминги и пр.) — «попугаи» одного ЦП нужны только для сравнения с другими.

Обычно Intel предоставляет результаты для своих ЦП почти одновременно с их выпуском. Но с SB произошла непонятная 3-месячная задержка, а полученные в марте цифры всё ещё предварительны. Что именно их задерживает — неясно, однако это всё равно лучше, чем ситуация с AMD, вообще не выпустившей официальных результатов своих последних ЦП. Нижеуказанные цифры для Opteron даны производителями серверов, использовавшими компилятор Intel, так что эти результаты могут быть недооптимизированы: что программный инструментарий Intel может сделать с кодом, исполняемым на «чужом» ЦП, мы уже знаем. ;)


Сравнение систем в тестах SPEC CPU2006. Таблица составлена Дэвидом Кантером с realworldtech.com по данным на март'2011.

В сравнении с предыдущими ЦП SB показывает превосходные (в прямом смысле) результаты в абсолюте и вовсе рекордные на каждое ядро и гигагерц. Включение HT и добавление 2 МБ к L3 даёт +3% к вещественной скорости и +15% к целой. Однако самую высокую удельную скорость имеет 2-ядерная модель, и в этом — поучительное наблюдение: очевидно, Intel задействовала AVX, но т. к. целочисленного прироста пока получить нельзя, то можно ожидать резкое ускорение лишь вещественных показателей. Но и для них никакого скачка нет, что показывает сравнение 4-ядерных моделей — а результаты для i3-2120 раскрывают причину: имея те же 2 канала ИКП, каждое ядро получает вдвое бо́льшую ПСП, что отражается 34-процентным приростом удельной вещественной скорости. Видимо, кэш L3 на 6–8 МБ слишком мал, и масштабирование его собственной ПС за счёт кольцевой шины уже не спасает. Теперь ясно, зачем Intel планирует оснастить серверные Xeon 3- и даже 4-канальными ИКП. Только вот тамошним 8 ядрам уже и их не хватит, чтобы развернуться по полной…

Дополнение: В базе SPEC появились финальные результаты SB — цифры (ожидаемо) чуть подросли, но качественные выводы те же.

Перспективы и итоги

О выходящем весной 2012 г. 22-нанометровом преемнике Sandy Bridge под названием Ivy Bridge («плющевый мост») уже многое известно. Ядра общего назначения будут поддерживать чуть обновлённый поднабор AES-NI; вполне возможно и «бесплатное» копирование регистров на стадии переименования. Улучшений в Turbo Boost не предвидится, зато ГП (который, кстати, заработает на всех версиях чипсета) нарастит максимальное число ФУ до 16, станет поддерживать подключение не двух, а трёх экранов, наконец-то обретёт нормальную поддержку OpenCL 1.1 (вместе с DirectX 11 и OpenGL 3.1) и улучшит возможности по аппаратной обработке видео. Скорее всего, уже и в настольных и мобильных моделях ИКП станет поддерживать частоту 1600 МГц, а контроллер PCIe — версию шины 3.0. Главное технологическое новшество — в кэше L3 будут использоваться (впервые в массовом микроэлектронном производстве!) транзисторы с вертикально расположенным многосторонним затвором-ребром (FinFET), имеющие радикально улучшенные электрические характеристики (детали — в одной из ближайших статей). Ходят слухи, что версии с ГП снова станут многочиповыми, только на этот раз к процессору добавят один или несколько кристаллов быстрой видеопамяти.

Ivy Bridge будет подключаться к новым чипсетам (т. е. южным мостам) 70-й серии: Z77, Z75 и H77 для дома (заменят Z68/P67/H67) и Q77, Q75 и B75 для офиса (вместо Q67/Q65/B65). Она (т. е. физическая микросхема под разными именами) по-прежнему будет иметь не более двух портов SATA 3.0, а поддержка USB 3.0 наконец-то появится, но на год позже, чем у конкурента. Встроенная поддержка PCI исчезнет (после 19 лет шине пора на покой), зато контроллер дисковой подсистемы в Z77 и Q77 получит технологию Smart Response для увеличения производительности кэшированием дисков с помощью SSD. Впрочем, наиболее волнительная новость заключается в том, что несмотря на старую добрую традицию, настольные версии Ivy Bridge не просто будут размещаться в том же разъёме LGA1155, что и SB, но и будут обратно совместимы с ними — т. е. современные платы подойдут и новому ЦП.

Ну а для энтузиастов уже в 4-м квартале этого года будет готов куда более мощный чипсет X79 (к 4–8-ядерным SB-E для «серверно-экстремального» разъёма LGA2011). Он пока не будет иметь USB 3.0, зато портов SATA 3.0 будет уже 10 из 14 (плюс поддержка 4 видов RAID), а 4 из 8 полос PCIe могут соединяться с ЦП параллельно с DMI, удваивая ПС связи «ЦП—чипсет». К сожалению, X79 не подойдёт к 8-ядерным Ivy Bridge.

В качестве исключения (а может быть, и нового правила) список того, что бы хотелось улучшить и исправить в Sandy Bridge, приводить не будем. Уже очевидно, что любое изменение является сложным компромиссом — строго по закону сохранения вещества (в формулировке Ломоносова): если где-то что-то прибыло, то где-то столько же и убудет. Если бы Intel кидалась в каждой новой архитектуре исправлять ошибки старой, то число наломанных дров и полетевших щепок могло бы превысить выгоду от полученного. Поэтому вместо крайностей и недостижимого идеала экономически выгодней искать баланс между постоянно меняющимися и подчас противоположными требованиями.

Несмотря на некоторые пятна, новая архитектура должна не только ярко засветить (что, судя по тестам, она и делает), но и затмить все предыдущие — как свои, так и соперника. Объявленные цели по производительности и экономности достигнуты, за исключением оптимизации под набор AVX, которая вот-вот должна проявиться в новых версиях популярных программ. И тогда Гордон Мур ещё раз удивится своей прозорливости. Судя по всему, Intel во всеоружии подходит к Эпической Битве между архитектурами, которую мы увидим в этом году.

Источник :Процессоры Intel Sandy Bridge


RSS лента ВСЕГО блога с комментариями RSS лента ВСЕГО блога БЕЗ комментариев RSS лента этой КАТЕГОРИИ с комментариями RSS лента этой КАТЕГОРИИ и БЕЗ комментариев RSS лента ЭТОГО ПОСТА с комментариями к нему

Первый шестиядерник AMD, встречайте - Phenom II X6 1090T!

Первый шестиядерник AMD встречайте Phenom II X6 1090T Мода на многоядерность прочно вошла в нашу жизнь, и теперь не то чтобы двухъядерным, уже и четырехъядерным процессором в домашнем компьютере кого-то удивить сложно. Но прогресс не стоит на месте, и буквально вслед за компанией Intel, неделю назад представившей свой шестиядерный процессор для настольных компьютеров, компания AMD выпустила свой шестиядерник, который мы сегодня и рассмотрим.

Процессор AMD Phenom II X6 1090T

phenom-II-x6-front.jpg

phenom-II-x6-back.jpg

Внешне процессор AMD Phenom II X6 1090T ничем не отличается от своих собратьев для платформы Socket AM3, кроме как маркировкой. А внутри он выглядит следующим образом:

phenom-II-x6-core.jpg

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

Давайте посмотрим, что скажет утилита CPU-Z о характеристиках процессора AMD Phenom II X6 1090T и тестовой системы.

cpuz-1.png

cpuz-2.png

AMD Phenom II X6 1090T выполнен по техпроцессу 45 нм, содержит шесть вычислительных ядер, по 128 Кб и 512 Кб кэш-памяти первого и второго уровня на каждое ядро, соотвественно. Также имеется общая для всех ядер кэш-память третьего уровня объемом 6 Мб, как и у четырехъядерных предшественников.

cpuz-3.png

Для знакомства с возможностями AMD Phenom II X6 1090T мы использовали материнскую плату MSI 890GXM-G65, основанную на наборе системной логики AMD 890GX.

cpuz-4.png

Эта материнская плата обладает весьма продвинутыми возможностями и, хотя у AMD Phenom II X6 1090T заявлена поддержка памяти стандарта DDR3-1333, самостоятельно установила память в режим работы DDR3-1600 с таймингами 9-9-9-24-1T, что полностью соответствует характеристикам использованных модулей памяти. К сожалению, более высоких множителей частоты памяти в BIOS не оказалось, и дальнейшее повышение частоты оперативки возможно только при увеличении базовой частоты.

Разгон

cpuz-1-2600.png

cpuz-4-2600.png

Как и при тестировании четырехъядерных процессоров Phenom II, мы попробовали увеличить частоту кэш-памяти третьего уровня - ее стабильное значение составило 2600 МГц. Отметим, что не обошлось без некоторых странностей. Дело в том, что частота работы "северного моста", встроенного в процессор, не должна превышать частоту шины HT Link, максимум которой ограничен значением 2600 МГц. Тем не менее, если в BIOS установить частоту NB в значение, скажем, 2800 МГц, то все будет работать. По крайней мере, Windows загружалась и можно было пройти некоторые тесты. Впрочем, такой режим оказался нестабильным, несмотря на повышение соответствующих напряжений. А при одинаковых частотах HT и NB, равных 2600 МГц, процессор был совершенно стабилен, поэтому результаты тестирования при таких настройках будут приведены на итоговых диаграммах производительности.

cpuz-1-ov4ghz.png

На этом эксперименты с разгоном не закончились. Мы попробовали разогнать процессор и по частоте ядер. При частоте 4,2 ГГц можно было загрузить Windows 7, но запуск любого приложения, нагружающего процессор, приводил к падению системы в синий экран. При частоте 4,1 ГГц наблюдалась та же картина, а вот частота 4,0 ГГц оказалась стабильной, на ней и были проведены все тесты при разгоне.

AMD Turbo Core

Как известно, процессоры Intel с архитектурой Nehalem могут динамически изменять частоту ядер выше номинальной, в зависимости от загрузки. И называется эта технология - Intel Turbo Boost. Шестиядерные процессоры AMD теперь также обладают похожей технологией, а называется она AMD Turbo Core. При всей схожести идей, лежащих в их основе, некоторые различия все же имеются.

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

При использовании технологии AMD Turbo Core с шестиядерными процессорами дела обстоят похожим образом, однако повышенная частота всего одна, и для ее активации необходимо, чтобы по крайней мере три ядра не были загружены работой. Рассмотрим случай с процессором AMD Phenom II X6 1090T. Ниже приведены фрагменты скриншотов утилиты AMD OverDrive, которая наглядно демонстрирует состояние ядер процессора, и позволяет управлять режимами их работы, включая разгон и изменение настроек AMD Turbo Core. Для просмотра полного скриншота нажмите на фрагменте.

1поток.png

Если загружено только одно ядро процессора, то его частота повышается до 3,6 ГГц, а напряжение на ядре с 1,3 В до 1,475 В. Частота остальных ядер при этом варьируется в довольно широких пределах - от 800 Мгц до номинальной, но напряжение на неиспользуемых ядрах остается штатным - 1,3 В. Если "нагрузить" еще два ядра, то они будут работать в точно таком же режиме, как показано на этом фрагменте, а остальные три ненагруженных - при штатном напряжении и пониженной частоте.

4поток.png

Если у процессора AMD Phenom II X6 1090T нагружены четыре ядра или более, то их частота будет равна номинальной - 3,2 ГГц, как и напряжение - 1,3 В. Остальные ненагруженные ядра могут работать на пониженной частоте.

Стоит отметить, что когда мы попытались отключить технологии энергосбережения в BIOS материнской платы, чтобы зафиксировать частоту ядер процессора на постоянном уровне, нам это не удалось. Возможно, это как то связано с особенностями конкретной материнской платы, но есть подозрение, что это процессор AMD Phenom II X6 1090T настолько "умный" и потому сам следит за своим энергопотреблением.

Кстати, значение напряжения на ядрах процессора при активации AMD Turbo Core можно регулировать с помощью все той же утилиты AMD OverDrive. И, как выяснилось при разгоне нашего экземпляра процессора, напряжение Vcore, равное 1,475 В, несколько завышено. Процессор абсолютно стабильно работал под полной нагрузкой на частоте 4 ГГц при напряжении равном 1,425 В. Что интересно, повышение напряжения Vcore никак не сказывалось на увеличении потолка разгона. Впрочем, возможно, более продвинутые и "заточенные" под разгон материнские платы на основе чипсета AMD 890FX смогут раскрыть весь потенциал новинки более полно.

Условия тестирования

Для сравнения с AMD Phenom II X6 1090T мы решили взять процессор AMD Phenom II X4 955, поскольку его штатная частота также равна 3,2 Ггц, а все остальные параметры, за исключением числа ядер, одниковы. Это позволит, с одной стороны, увидеть прирост производительности от увеличения количества ядер в многопоточных приложениях, а с другой - оценить прирост от использования технологии AMD Turbo Core на тех приложениях, которые не используют больше трех вычислительных потоков.

Также мы взяли уже рассмотренный нами шестиядерный процессор Intel Core i7 980X 3.33 GHz. Отметим, что этот процессор использовался в номинальном режиме с комплектом трехканальной памяти, работающей в режиме DDR3-1333 и таймингами 9-9-9-24-1T, а технология Intel Turbo Boost была активирована (максимальная частота ядра в этом режиме равна 3,47 ГГц). По умолчанию, технология Intel Hyper Threading активирована, то есть Intel Core i7 980X использует 12 вычислительных потоков, но дополнительно были проведены тесты и при отключении Hyper Threading. Таким образом, можно будет оценить прирост от использования Hyper Threading в том или ином тесте.

Ну и еще один представитель Intel - процессор Core i7 870. Этот процессор также тестировался в номинальном режиме с оперативной памятью, работающей в в режиме DDR3-1333 и таймингами 9-9-9-24-1T. Технология Turbo Boost была активирована, заметим, что при этом частота активных ядер процессора равна 3,6 ГГц, как и у AMD Phenom II X6 1090T при активации AMD Turbo Core. Помимо штатных частот, Intel Core i7 870 был протестирован и при разгоне до частоты 4,0 Ггц, что опять же совпадает со значением, до которого разогнался шестиядерник AMD. В этом режиме технология Turbo Boost была выключена, а оперативная память работал в режиме DDR3-1800.

Более подробный список остального использовавшегося при тестировании оборудования приведен ниже:

Тестовое оборудование
Процессоры AMD Phenom II X6 1090T 3.2 ГГц
AMD Phenom II X4 955 3.2 ГГц
Intel Core i7 870 2.93 ГГц
Intel Core i7 980X 3.33 ГГц
Система охлаждения CPU Zalman CNPS 10x Extreme @ 1600 об/мин
Материнские платы MSI 890GXM-G65, Socket AM3
Asus Maximus III Extreme, Socket LGA1156
ASUS Rampage II Extreme, Socket LGA 1366
Оперативная память 3x 1GB Apacer DDR-3 2000 MHz (9-9-9-24-2T) @ 1333 MHz (9-9-9-24-1T)
2x 2GB Super Talent DDR3-2000 @ 1600 (9-9-9-24-1T)
Видеокарта AMD Radeon HD 5870 1 Гб, Catalyst 3.10
Жесткий диск Samsung SpinPoint 750 GB
Блок питания Lian Li PS-A750GB, 750 Вт
Операционная система Windows 7 Home Premium x64

Температурные режимы

Поскольку мы использовали одну и ту же платформу, интересно было посмотреть на температурный режим новинки в сравнении с представителем четырехъядерной серии процессоров Phenom II. Как уже говорилось, использовался кулер Zalman CNPS 10x Extreme. Этот кулер имеет как плавную ручную регулировку скорости вращения вентилятора, так и фиксированными ступенями. Мы выбрали среднюю ступень, при которой вентилятор вращался со скоростью 1600 об/мин. Все доступные технологии энергосбережения процессоров были активированы.

32-ТемператураCPU,режимрабочего.png

Как видите, без нагрузки, в режиме рабочего стола Windows, температура процессора AMD Phenom II X6 1090T весьма низка и значительно ниже таковой у его младшего собрата. Однако здесь следует заметить, что при включении мониторинг BIOS материнской платы показывал температуру процессора около 45 градусов Цельсия, то есть на 22 градуса выше, чем утилита AMD Overdrive, показания которой приведены на диаграмме. Мы все же склонны верить данным утилиты AMD Overdrive, поскольку при и тестировании под нагрузкой теплосъемник кулера и тепловые трубки у его основания были лишь теплыми, а не горячими, что при температуре процессора около 70 градусов Цельсия не представляется возможным.

33-ТемператураCPU,играFarCry2.png

При прогоне нескольких циклов бенчамрка игры Far Cry 2 температура AMD Phenom II X6 1090T подросла совсем незначительно, и лишь при разгоне чуть превысила планку 40 градусов Цельсия. В то же время, процессор Phenom II X4 955 прогрелся уже до 50 градусов.

34-ТемператураCPU,OCCTLinpack64.png

Стресс-тестирование утилитой OCCT в режиме Linpack 64-bit также показало весьма занятные результаты. На номинальных частотах температура Phenom II X6 1090T составила около 45 градусов Цельсия, и только повышение напряжения на ядре и разгон до частоты 4,0 ГГц смогло прогреть новинку до 56,2 градусов. А старичок Phenom II X4 955 даже в штатном режиме уже достиг планки 60 градусов. Заметим, что указываемая AMD максимальная температура ядра процессоров Phenom II равна 62 градуса Цельсия.

Общее энергопотребление системы

С температурами все ясно - новинка получилась весьма "прохладной" и неприхотливой. Теперь давайте посмотрим на энергопотребление системы в целом. Приведенные ниже цифры соответствуют показаниям ваттметра, которые снимались до блока питания. То есть, если вы хотите прикинуть реальную потребляемую системой мощность, следует умножить эти цифры примерно на 0,8-0,85 (КПД блока питания). Итак, приступим.

28-Энергопотреблениесистемы,реж.png

В режиме рабочего стола Windows платформа AMD потребляет не более 100 Вт, причем система на базе AMD Phenom II X6 1090T оказывается чуточку экономичнее по этому показателю. Занятно, но система на базе Intel Core i7 870, работающим на меньшей частоте, потребляет несколько больше, а при разгоне так и вовсе выбивается в "лидеры". Энергопотребление системы на основе шестиядерного процессора Intel Core i7 980X оказывается примерно на 40% выше, чем у представителей AMD.

29-Энергопотреблениесистемы,игр.png

C увеличением нагрузки на систему относительная разница в результатах уменьшается. Тем не менее, система на основе Intel Core i7 980X потребляет электроэнергии несколько больше, а в "лидерах" по-прежнему разогнанный Intel Core i7 870.

30-Энергопотреблениесистемы,OCC.png

Стресс-тест OCCT Linpack 64-bit совершенно меняет картину. Самой экономичной теперь оказывается система на базе Intel Core i7 870 в номинальном режиме, затем идут представители AMD, также работающие в штатном режиме. Заметьте - здесь энергопотребление системы на основе шестиядерного процессора Phenom II X6 1090T впервые оказывается выше, чем у платформы с Phenom II X4 955, у которого четыре ядра. Чуть больше потребляет система с шестиядерным Intel Core i7 980X, ну а в лидерах оказываются платформы с процессорами, разогнанными до частоты 4,0 ГГц. Такой значительный скачок в энергопотреблении объясняется не столько повышенной частотой процессоров, сколько увеличением их напряжения питания.

И, наконец, последний в этой серии тест, нагружающий как процессор, так и видеокарту - два наиболее "прожорливых" компонента современного игрового компьютера. "Прогрев" процессора осуществлялся с помощью стресс-теста из пакета Everest Ultimate. Конечно, это не такой "тяжелый" тест, как OCCT Linpack, но и он создает весьма ощутимую нагрузку на CPU. Поскольку при полной загрузке ядер процессора тест Furmark заметно снижал "обороты" и видеокарта работала не в полную силу, в Диспетчере задач Windows бенчмарку задавалось соответствие таким образом, чтобы один вычислительный поток оставался свободным. В этом случае Furmark сразу начинал работать в полную силу и энергопотребление видеокарты резко возрастало.

31-Энергопотребление,Furmark+Ev.png

В номинальном режиме платформы на основе AMD Phenom II X6 1090T и Intel Core i7 870 демонстрируют практически одинаковое энергопотребление на уровне около 350 Вт. Система с шестиядерным Intel Core i7 980X потребляет уже чуть выше 380 Вт, а системы с разогнанными процессорами перешагнули планку 400 Вт.

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

Тестирование производительности

Теперь давайте посмотрим, что покажет AMD Phenom II X6 1090T в тестах производительности.

1-EverestUltimatev5502100,Memo.png

По сравнению с предшественником, в тесте чтения из оперативной памяти AMD Phenom II X6 1090T демонстрирует некоторый прирост, но тягаться с контроллером памяти, встроенным в процессоры Intel с архитектурой Nehalem, ему довольно затруднительно. Увеличение частоты кэш-памяти третьего уровня AMD Phenom II X6 1090T позволяет несколько улучшить результаты, но разрыв с представителями Intel все равно остается очень большим.

3-EverestUltimatev5502100,Memo.png

В тесте записи в память ситуация для процессоров AMD еще более удручающая, а в соревновании шестиядерников, работающих на номинальных частотах, Intel Core i7 980X побеждает практически с двукратным преимуществом.

4-EverestUltimatev5502100,Memo.png

Однако при копировании в памяти все оказывается уже не так плохо. В номинальном режиме AMD Phenom II X6 1090T и здесь несколько отстает от своего шестиядерного побратима из клана Intel, но даже при разгоне соревноваться с Intel Core i7 870, работающему в штатном режиме, ему не удается.

5-EverestUltimatev5502100,Memo.png

Задержки при обращении к оперативной памяти у процессоров AMD Phenom II X6 1090T и Intel Core i7 870 примерно одинаковы, а у Intel Core i7 980X значительно хуже, что, однако, не мешает ему демонстрировать впечатляющую производительность.

Теперь перейдем к синтетическим вычислительным тестам.

6-EverestUltimatev5502100,CPUQ.png

Эффект от наличия двух дополнительных ядер процессора Phenom II X6 1090T по сравнению с Phenom II X4 955 весьма ощутим, но для схватки на равных с четырехъядерным Intel Core i7 870 этого все же оказывается недостаточно. Данный тест очень хорошо "отзывается" как на увеличение частоты CPU, так и вычислительных потоков (Hyper Threading), поэтому безусловным лидером в итоге оказывается шестиядерный процессор Intel Core i7 980X, имеющий их аж 12 штук.

7-EverestUltimatev5502100,CPUP.png

В тесте Everest PhotoWorxx главную роль играет эффективность контроллера памяти, поэтому впереди закономерно оказываются представители Intel. Удивительно, но здесь AMD Phenom II X6 1090T в номинальном режиме показывает несколько худший результат, чем его четырехъядерный собрат - AMD Phenom II X4 955. Впрочем, разница исчисляется единицами процентов.

8-EverestUltimatev5502100,CPUZ.png

Этот тест чисто вычислительный, поэтому результаты участников выстроились характерными "лесенками", согласно количеству ядер и потоков. Прибавка в производительности от наличия в процессорах Intel технологии Hyper Threading в данном тесте не столь значительна, поэтому AMD Phenom II X6 1090T уверенно обходит Intel Core i7 870 в номинальном режиме, а при разгоне практически нагоняет Intel Core i7 980X.

9-EverestUltimatev5502100,CPUA.png

В этом тесте любым процессорам, не оборудованным набором инструкций AES-NI, что называется, ловить нечего. Преимущество Intel Core i7 980X над остальными участниками десятикратное. В тоже время, AMD Phenom II X6 1090T на штатной частоте показывает себя весьма неплохо по сравнению даже с разогнанным Intel Core i7 870.

10-EverestUltimatev5502100,FPUJ.png

Рост результатов AMD Phenom II X6 1090T по сравнению с Phenom II X4 955 практически линейно зависит от числа ядер. Производительность архитектуры Nehalem весьма велика, и при прочих равных условиях процессоры AMD в этом тесте значительно отстают.

11-EverestUltimatev5502100,FPUM.png

В тесте FPU Mandel картина аналогична предыдущей.

12-EverestUltimatev5502100,FPUS.png

Тест FPU SinJulia очень чутко реагирует на наличие дополнительных вычислительных потоков. Впрочем, даже при выключении Hyper Threading процессор Intel Core i7 980X оказывается примерно в 1,5 раза быстрее AMD Phenom II X6 1090T на номинальной частоте.

18-Cinebench11532-bit,multising.png

В новой версии пакета Cinebench, как и ранее, можно использовать как однопоточное, так и многопоточное тестирование. Результаты теперь измеряются в "пойнтсах". Напомним, что технология Turbo Core для процессора AMD Phenom II X6 1090T была активирована, при этом частота активных ядер в этом режиме составляет 3,6 ГГц. Именно этим и объясняется преимущество AMD Phenom II X6 1090T над Phenom II X4 955 в однопоточном режиме. Разумеется, в многопоточном тесте главную роль играет количество ядер. Как видите, и здесь AMD Phenom II X6 1090T может соревноваться на равных разве что с Intel Core i7 870, а с шестиядерником Intel он может идти на равных только при разгоне, и то, если у последнего не активирована технология Hyper Threading.

19-Cinebench11564-bit,multising.png

Поскольку мы использовали 64-разрядную версию Windows 7, было решено провести и тестирование в Cinebench 64-bit, чтобы выяснить, какие преимущества можно получить в этом случае. В целом, общая расстановка сил осталась прежней, а результаты подросли примерно на 8%.

35-WinRar39332-bit,singlemultit.png

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

36-WinRar39364-bit,singlemultit.png

В 64-разрядной версии WinRar результаты оказались практически идентичны предыдущим, хотя и чуть-чуть возрасли, примерно на 2-3%.

16-3DMarkVantage,CPUTest1,plans.png

В первом процессорном тесте 3DMark Vantage AMD Phenom II X6 1090T демонстрирует значительный прирост по сравнению с Phenom II X4 955, но даже до четырехъядерного Intel Core i7 870 ему еще очень далеко.

17-3DMarkVantage,CPUTest2,steps.png

Во втором тесте, "физическом", ситуация для AMD Phenom II X6 1090T складывается значительно лучше - он уверенно опережает Intel Core i7 870 и не очень сильно отстает от Intel Core i7 980X на номинальных частотах.

14-3DMarkVantage,Game1,fps.png

15-3DMarkVantage,Game2,fps.png

Как и следовало ожидать, в игровых тестах 3DMark Vantage все платформы показывают очень близкие результаты, обусловленные производительностью видеокарты, поскольку "дополнительные" ядра и вычислительные потоки в этом тесте никак не используются, а загружается лишь одно ядро CPU.

Перейдем непосредственно к играм.

20-ResidentEvilbenchmark,1280x1.png

В тесте Resident Evil преимущество на стороне представителей Intel, причем со значительным перевесом, и даже разгон не позволяет AMD Phenom II X6 1090T достичь результатов своих "синих" соперников. Что касается "внутриклановой" борьбы, то новинка опережает AMD Phenom II X4 955 примерно на 13%.

21-Crysis11,1280x1024,CPUtest,L.png

При низких настройках графики в CPU-тесте игры Crysis можно увидеть фантастический результат - порядка 250 кадров в секунду, полученный на шестиядернике Intel и разогнанном Core i7 870. Процессоры AMD здесь безнадежно отстают, причем ни увеличение количества ядер, ни их рабочей частоты особо не сказывается на результате. По всей видимости, в этом режиме большую роль играет эффективность контроллера оперативной памяти.

22-Crysis11,1280x1024,CPUtest,M.png

При средних настройках графики в CPU-тесте Crysis мы опять наблюдаем полуторакратное преимущество представителей архитектуры Intel Nehalem над процессорами AMD. Но что интересно, при включении Hyper Threading наблюдается не то что прирост, а даже некоторое падение результатов.

23-Crysis11,1280x1024,CPUtest,H.png

При высоких настройках графики в CPU-тесте Crysis определяющую роль начинает играть производительность видеокарты, поэтому разница в результатах невелика, но "синие" все же уверенно лидируют.

24-Crysis11,1280x1024,CPUtest,V.png

При максимальном качестве графики Crysis все определяется исключительно производительностью видеокарты, поэтому результаты разных платформ отличаются буквально на единицы fps. Впрочем, возможностей всех участников данного тестирования вполне достаточно, чтобы раскрыть потенциал Radeon HD 5870 в этом режиме.

25-FarCry2,1280x1024,Highdetail.png

26-FarCry2,1280x1024,VeryHighde.png

27-FarCry2,1280x1024,UltraHighd.png

В игре Far Cry 2 расстановка сил, в целом, похожа на ту, что мы видели в игре Crysis - преимущество процессоров Intel неоспоримо, а с увеличением "тяжести" графического режима все большую роль начинает играть видеокарта. Несколько удивляет тот факт, что при одинаковых частотах процессор Phenom II X6 1090T проигрывает своему младшему собрату - Phenom II X4 955. Причем, эта разница сохраняется во всех трех режимах тестирования и, честно говоря, у нас нет объяснения этому странному факту. Впрочем, любого из представленных процессоров достаточно для того, чтобы не испытывать ни малейшего дискомфорта в данной игре.

Выводы

Как показало тестирование, производительность процессора AMD Phenom II X6 1090T оказывается значительно ниже, чем у его "одноклассника" из Intel - Core i7 980X. Более того, во многих случаях производительность новинки AMD уступает и четырехъядерному Intel Core i7 870. Но это вовсе не повод для расстройства. Выпустив свой шестиядерный процессор, компания AMD вовсе не пыталась перехватить пальму первенства у Intel, задача была в другом - сделать доступный и "холодный" шестиядерный процессор, который мог бы эффективно работать как с многопоточными приложениями, так и теми, которые не оптимизированы под использование большего числа вычислительных потоков (большинство современных игр). И, на наш взгляд, компании AMD это вполне удалось.

Рекомендованная цена на процессор AMD Phenom II X6 1090T составляет всего $289! При этом, приобретая данный процессор в качестве замены предыдущему, нет необходимости менять платформу целиком, и в большинстве случаев достаточно просто обновить BIOS материнской платы. В то время как в партиях от 1000 штук процессор Intel Core i7 870 стоит $562, а Intel Core i7 980X и того больше - $999!

Кстати, помимо процессора Phenom II X6 1090T, компания AMD выпустила еще один шестиядерник - Phenom II X6 1055T, который отличается от старшей модели только чуть сниженной номинальной частотой - 2,8 ГГц. При активации технологии AMD Turbo Core частота активных ядер этого процессора повышается до 3,3 ГГц. А рекомендованная цена AMD Phenom II X6 1055T равна $199. Весьма любопытная модель. Но об этом мы поговорим в другой раз.

Источник: 3dnews.ru


RSS лента ВСЕГО блога с комментариями RSS лента ВСЕГО блога БЕЗ комментариев RSS лента этой КАТЕГОРИИ с комментариями RSS лента этой КАТЕГОРИИ и БЕЗ комментариев RSS лента ЭТОГО ПОСТА с комментариями к нему

Прыг: 01 02 03 04


Похожие ресурсы:

Copyright © 2009 Версия компьютеры
Сейчас 13 декабря 2017, 12:59
Система авторегистрации в каталогах, 
           статьи про раскрутку сайтов, web дизайн, flash, photoshop, хостинг, рассылки; форум, баннерная сеть, каталог сайтов, услуги 
           продвижения и рекламы сайтов

Рейтинг популярности - на эти заметки чаще всего ссылаются: