Лекция 3 (2012-10-29)

Организация процессора

Сегодня про организацию процессора.

Схема.

Ряд качеств:

  1. Конвейерный принцип.
  2. Суперскалярность -- несколько операций за такт (благодаря нескольким FU).

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

  1. Ещё одинм важным аспектом является то, что порядок операций не жесткий. Происходит вычисление зависимостей, в некоторых реализациях осуществляется спекулятивное выполнение.

Раньше инструкции и операции были одинаковы, теперь сложная инструкция на входе разбивается на простые опы внутри, что позволяет упрощать архитектуру и повышать тактовую частоту.

Все это обмазано каким-то количеством кэщей. Здесь нарисован л1 л2, вообще их больше, дальше попробуем рассказать.

Как происходит выполнение команд?

  1. Чтение в кэш. Чтоб можно было их сколь либо быстро разбирать.
  2. Разбираются они в кэш инструкции. В х86 они разбираются в л1 инстракшн кэш. Сейчас будем рассматривать х86, но для повер писи, спарков до ниагары, мипсы всё похоже, с точностью до размеров. Перед попаданием в инстракшн кэш в некоторых реализациях может выполняться полное или частичное декодирование. Полное делается в нетберст, частичное в к7(Атлон), к8(Атлон64) и интел кор 2 и старще -- там частичное декодирование.
  3. Из инстракшн кэша происходит забор инструкций. После обработки в блоке декодирования появляется поток мопов. У повер писи они называются опы, у интел микрооперации, у амд мопы.
  4. Аллокация регистров. В процессоре есть архитектурные регистры (операнды инструкций) и внутри бэкенда используются физические регистры, которых существенно больше, потому что мы пытаемся делать скалярное, спекулятивное, внеочередное выполнение, и без доп. регистров это трудно.
  5. В процессе аллокации после этого операция попадает в буфера планировщика и блок переупорядочивания. В нём и происходит уже непосредственно ожидание на выполнение команд. В РОБ хранятся все операции, которые ещё не завершили выполнение и одновременно с этим эти операции находятся в ожидании на выполнение внутри блока планировшика,обычно они там уже привязаны к определенным фу.
  6. Когда устройство освобождается и планировшик решает, что оп может быть выполнена( все данные готовы, регистр под результат есть), то она запускается на выполнение.
  7. Операция может возыметь эффект на бранч предикшн, регистры, кэши.

Попытаемся подробно рассмотреть каждый из данных блоков.

Инстракшн кэш. Обычно представляет собой некую память, обычно срам (довольно быстрая память, работающая на частоте не сильно меньше процессора и имеет объем 8 кб для пентиум 4, нехалем сандибридж 22 кб, в хасвелл есть желание радикально увеличить размер л1 кэша, правда непонятно, за счет чего. Сейчас это порядка 32 кб.

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

Первый термин -- строка кэша, кэш лайн. Чаще всего от 32 до 128. В х86 обычно 64 байта. Младшие 6 бит адресуют байт внутри строки. Остается 26 бит, кэш в 512 строк. Поиск за один такт малоосуществим. Скажем, что 9 бит адреса нам скажет, какая строка используется, а старшие биты это просто некий тег, и если он совпал, то это та строка, которую мы искали. Если нет, то у нас произошел хэш-мисс и строку надо грузить из памяти. Это называется дайрект адрессинг. Такой способ не является эффективным. Если не влезает все в кэш, у нас сразу возникают проблемы, потому что мы начинаем выбивать строчки рандомно и никак не учитываем историю её использования, что сильно ухудщает производительность кэша. Поэтому везде пытаются сделать некую ассоциативность. Асс -- сгруппируем строки по 4/8/16. У интела по 8. Тег становится на 3 бита больше (с 6 по 11). Теперь уже не 9 бит а меньше, если асс уровня 8, то ... Таким образом мы выбираем набор, а это уже используется как тег, но мы его ищем среди набора из 8 строк. И думаем про то, какую из 8 строк выкидываем, если не нашли и все заняты. Обычно используется лист рисентли юзд. Строка, которая использовалась позднее всего выкидывается. Для этого требуется дополнительные три бита.

В итоге, кэш имеет примерно следующую структуру

Схема

Кэш первого уровня для ассемблера прозрачен. Кэш 2-3 уровня обычно можно потюнить. Хотя в реальности все можно потюнить, везде поставить счетчики, и все не так чудесно.

Чем больше строк, тем больше алиасинг. Тем меньше строк, тем меньше флексибилити.

Есть ряд схем, где реализуется полная ассоциативность.

Пусть тег имеет 20 бит, и нам надо сравнить его сразу с 8 значениями. Схема, на вход 8*20-20=140 сигналов. Это занимает много места и очень грустно. Если не 32-разрядная, а 64 разрядная адресация, то под адресацию может уходить до 48 бит. Сейчас планомерно патчиками увеличивают количество битов доступных для адреса (про ядро линукса). Там сначала мапинг физ устройств, потом...

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

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

БПП помогает пытаться угадать, куда может быть сделан переход и заранее начать декодировать и аллоцировать операции. Если базируемся целиком на спекулятивным выполнении (Intel Itanium, Cell) -- гибрид ежа с ужом, с одной стороны влив, с другой стороны много всяких вкусностей. Там фактически выкинули бпп и вместо этого опирались на спекулятивное выполнение. 128 слово состоит из 3 комманд и некоторых битов маркеров, в которых говорилось, что команда должна выполняться спекулятивно. Спекулятивные команды в итоге либо давали эффект либо нет.Счастья не случилось, потому что чтобы генерировать код, для которого это было бы хорошо, оказалось сложно, компиляторов под это так никто и не сделал. То, что касается целлов -- они имеют частично схожую архитектуру.

В х86 используется бренч таргет буффер в котором сохраняется адреса команд, на которые производились переходы. Он имеет размер типа 512 записей. И когда появляется эффект команды, туда помещается адрес инструкции если на нее был переход. Используется во всяких циклах, безусловных переходах и так далее.

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

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

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

Далее ещё один сложный в плане реализации блок -- декодирование. Сложный в х86, потому что инструкции имеют разную длину - до 16 байт + префиксы, минимальный 1 байт (подряд много нопов можно сделать очень маленькими). Борятся с проблемой сложности амд и интел по разному. Амд делает предварительную разметку. В л1и у амд с к8 инструкции уже размечены. У интела предекодирование начиная с кор2. Схема след -- берутся куски выдранные по 16 байт и скармливаются 16 PLA (Programmable Logic Array) -- скармливаются с разным смещением. И каждый пытается понять, является ли 4 байта началом команды, 1 байт префиксом. Делается за 1 такт. Потом информация собирается начиная с первой. Таким образом можно понять, где начинается команда, итд.

Сама команда. Префиксы задают режим команды. За одним из префиксов куча команд -- всё ссе, итд. Сама команда - операция и аргументы, а в конце интермидиат аргумент и, например, смещение, если того требует формат команды.

Интел долго не мог отказаться от специальных регистров, accumulator, counter, base, data -- они все имели специальный смысл. Например, цикл был только по cx, или команда сильно усложнялась и начинались всякие упражнения.

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

Из важного есть (типы):

  1. Op просто операция, использует физ регистры
  2. Load для загрузки данных в физ регистры
  3. Store данные с физ регистра поместить туда-то

На операции такого вида у вас происходит разбивка команд.

mul %ebx, %edx[2] 

Будет разбита на

load %edx, 2
op mul
store (...)

Обычно есть более главный декодер, генерирующий 4 мопа за такт, и менее главные, которые генерируют 1-2 мопа за такт. В кор 2 схема стала типа 4-2-2. У к8 схема 2-2-2. У нехалема и сандибриджа ещё больше. Реально кор2 мог читать 4 инструкции и выдавать до 6 мопов за такт.

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

Далее мопы попадают в реордер буффер и ставятся в очередь на выполнение.

Про аллокацию. В х86 физ регистры имеют размер 80 бит. Если опер ссе, то аллоцируются 2 физ регистра. Начиная с нехалема размер внутр. регистров кажется был увеличен. Этих регистров толи 32, то ли 64. Их гораздо больше, чем архитектурных.

Это чистилище ещё называется reservation station -- где опер ожидают свое выполнение. В пентиум м и корах это было один блок сложения, один умножения, один лоад, один стор. В кор2 кол-во фу увеличилось, в нехалеме ещё увеличилось, но в нехалеме появился гипертрединг и жестко делил ресурсы декодера и буферов, а тут все было довольно гибко, но чтобы его компенсировать он стал достаточно широким. В первых корах 40 мопов, кор 2 64, нехалем 128. Проиграть по сравнению с кор2 было нельзя с включенным гипертредингом. Ну и декодер стал более мощным в нехалеме.

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

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

То ли в нехалеме, то ли в сандибридже был сделан рывок и они стали выполнть до 8 операций за такт, что сейчас убивает амд.

В случае с повер пс декодер значительно проще, и довольно много фу, за счет чего в пересчете на такт он производителен, но у него хуже с бранч предикщн, за счет чего он в принципе страдает.

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

В след раз сказ про память. 3 ноября, суббота, 12.30, сбор около 73.

Translation Lookahead Buffer

Встретим, когда будем говорить про страничную организацию памяти и этом всем. Операнды, которые в инструкциях, получили адреса натуальные, а выборку из памяти делаем по адресам физическим. В х86 механизм реализован аппаратно. Это ещё один кэш, обычно двух уровневый, в котором хранится соответствие старших битов натуральных адресов физическим. Важно, что бы те биты, адреса, что мы ищем в кэше, они укладывались в страницу, то есть в 12 бит. Нужно это для того, что вот этот тег преобразуется в тлб и сразу идет на поиск в кэш. То есть на самом деле есть ещё это преобразование из натурального в физический.

Nehalem и SandyBridge

Сначала хотел бы рассказать про две интел архитектуры. После того как интел выкинул нетберст, в предыдущей лекции отличия почти не упоминались, но они есть. нб оперирует трассами. Декодирование выполняет полностью, трассы как элемент переходов и так далее. Набор решений в сумме получился не очень удачный. Интел её тянула 5 лет, но в конце таки выбросила.

Эволюционно было PIII, P-M(стал получше декодер, появился моп-фьюжн), Core (PM-2), Core 2, Nehalem и SandyBridge. Изначально казалось, что нехалем позиционируется как попытка перейти к контроллерам памяти внутри процессора. В кор2 впервые появились 4 ядерные чипы, которые в принципе делались за счет 2 чипов на одной подложке. Два чипа, один субстрейт, по ногам тоже самое, увеличенное количество конденсаторов.

Схема

l2 кэш в корах был эксклюзивным.

Если вы делаете эксклюзивный кэш, то когда вы его себе забираете, у других он пропадает.

Одно из главных нововведений нехалем -- л3 кэш, причем он был инклюзив. Это позволило ещё немножко увеличить количество ядер. При этом л1-л2 синхронизировались.

Миграция процессов между ядрами в нехалеме стала менее болезненным мероприятием.

Контроллер памяти таки переехал на чип, в процессор. Задержки по досутпу в память сильно уменьшились. Эту архитектуру удалось раскочегарить до 10 ядер. Вестмеры по технологии 6+4, плюс гипертрединг, получалось 20 тредов с одного чипа.

Помимо этого в нехалеме было произведено довольно много микроархитектурных изменений. Для хоть сколько нибудь нормальной работы гипертрединга понадобилось увеличить количество всех ресурсов внутри ядра -- буфферов бранч предикшн, бранч хистори предикщн, добавилось эвристик. Увеличились размеры ROB, увеличилось количество операций в резервации, увеличился буффер на операции лоад и стор, что позволило минимизировать негативные эффекты, связанные с гипертредингом, и им стало реально пользоваться -- по сравнению с кор 2 не происходит деградации производительности. Была заменена шина, она стало более униформенной. Начиная с нехалемов появилась qpi (quick Path Interconnect). Она реально стала изображать из себя интерконнект -- роутинг, это всё. Супермикра на базе 4 сокетных вестмеров реализовали 80 ядерную конфигурацию. Это вызов в сторону паверовских смп машин, которые издревле этим славились.

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

Санди бридж

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

Перенесли пси экспресс на чип, что решило проблему нехалемов с дма.

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

Надо брать хеон е7_ 8 серии, по 4 тыщи долларов за штуку, тогда у вас все будет хорошо.

В санди бридж было сделано дальнейшее продвижение на пути поддержки большого количества ядер.

AVX увеличилась ширина регистра.

LecturesCMC/ComputerArchitecture2012/Conspects/02 (последним исправлял пользователь Allena 2012-12-21 02:28:39)