К. Касперски - Техника оптимизации программ, Эффективное использование памяти (1127752), страница 54
Текст из файла (страница 54)
Таким образом, загруженная порция данных присутствует и в кэш-памяти первого уровня, и в кэш-памяти второго, что не есть хорошо. Между тем, практически все современные процессоры (АМР Кб, Р-П, Р-П1) построены именно по включающей архитектуре. Исключающая (ехс!вз)те) архитектура. Кэш-подсистема, построенная по ехс1цз!уе-архитектуре (рис. 3.14), никогда не хранит избыточных копий данных и потому эффективная емкость сверхоперативной памяти определяется суммой размеров сверхоперативной памяти всех иерархий.
гво Кэш Рис. 3.14. Ехсшина-архитактура каш-памяти Кэш-первого уровня никогда не уничтожает кэш-линейки при нехватке места. Даже если они не были модифицированы — данные в обязательном порядке вытесняются в кэш-второго уровня, помещаясь на то место, где находилась только что переданная кашу первого уровня линейка. Таким образом, кэш первого и кэш второго уровней как бы обмениваются друг с другом своими линейками, а потому сверхоперативная память используется весьма эффективно. На сегодняшний день эксклюэивная кэш-подсистема реализована в одном лишь процессоре АМ0 Агп!оп, да и то не с первых моделей (см. такзке разд.
"Особенности кэш-подсистемы пролессора А МР Агй!оп " этой главы). Раздельное хранение кода и данных Поскольку кодовый кэш тесно связан с декодером, в настоящей книге он не рассматривается, т. к. декодер и все, что с ним связано, — тема отдельной книги (см. "Предисловие. О серии книг «Оптимизация«'), подробно рассказывающей об устройстве процессора и методиках планирования эффективного потока команд. Буферы записи Для предотвращения задержки, возникающей при промахах записи, современные процессоры активно используют различные приемы буферизации.
Вместо того чтобы немедленно отправлять записываемые данные по месту 270 Глава 3 назначения, процессор временно помещает их в специальный буфер, откуда, по мере освобожления шины и/или кэш-контроллера, они выгружаются в кзш первого (второго) уровня или в основную оперативную память. Такая схема особенно полезна при значительном превышении количества операций чтения над числом операций записи. Если частота возникновения промахов записи не превышает скорости выгрузки буферов, штрафных задержек не возникает вовсе и эффективная скорость выполнения инструкции записи составляет ! такт. Часто прихолится слышать: чем больше в процессоре буферов, тем выше предельная частота промахов записи, которую без ущерба для производительности он способен выдержать.
На самом деле, это неверно. Максимальная частота промахов определяется не количеством бу!йеров, а скоростью (и политикой) их выгрузки. В частности, процессоры АМ(З Кб и А!я!оп всегда выгружают содержимое буферов записи в кэш первого уровня, благодаря чему скорость их опорожнения весьма велика (при благоприятном стечении обстоятельств каждый 32/64-байтовый буфер выгружается за один такт), а выгруженные данные вплоть ло вытеснения их из 11-кэша доступны на чтение практически мгновенна! Процессоры Рб и Р-4, напротив, направляют содержимое буферов записи в кэш второго, а не первого уровня. (Конечно, если записываемые данные уже содержатся в !.!-каше, они помещаются именно туда.) Эффективность такой стратегии не бесспорна. С одной стороны: это приводит к тому, что процессор "выносит" значительно меньшую интенсивность промахов записи, а с другой: выгрузка записываемых ланных в кэш второго уровня не загрязняет кзш первого уровня, в конечном итоге увеличивая его эффективную емкость.
Кстати, нетривиальным следствием такой политики выгрузки буферов становится искажение политики кэш-записи Несмотря на то, что кэш первого уровня формально построен по %г(ге Васк-архитектуре, фактически он работает по схеме %гйе Тгце, поскольку промах записи приводит к непосредственному обновлению кзш-памяти более высокой иерархии без загрузки модифицируемых данных в кэш. Забавно, но !пге! впервые "проговорилась" об этом факте лишь в документации по процессору Репгшш-4, где в графе "Политика записи кэша первого уровня" честно указано "%г(!е Тгце", а не "%гйе Васк", как это утверждалось в документации по процессорам предылушего поколения.
Важно понять, что увеличение количества буферов записи не компенсирует медлительность их выгрузки в память. Практически единственная польза емкого буфера в том, что он безболезненно переносит локальные перегрузки, Кэш г,г когда несколько промахов возникают одновременно (или идут с минималь- 'ным отрывом друг от друга), а затем вновь наступает "тишина". Чтение после записи. Вопреки своему названию, каждый из буферов лоступен не только на запись, но и на чтение.
Причем, чтение данных из буфера записи осуществляется по крайней мере на олин такт быстрее, нежели из кэш-памяти первого уровня.(Подробнее о том, как можно использовать это обстоятельство для оптимизации своих програыьк рассказано в раэд. "Особенности буферизации записи" этой главы). Тем не менее, чтение содержимого буферов (особенно на процессорах семейства Репбшп) следует осуществлять с большой осторожностью, т. к.
только что записанные данные в любой момент могут перекочевать в кэш второго уровня, что резко увеличит время доступа к ним. Помимо того, что буферы самопроизвольно выгружаются во время простоя шины, они незамедлительно опорожняются в следующих ситуациях; ь) при выполнении инструкции с префиксом монопольного захвата шины (ьоск); гэ при выполнении инструкции упорялоченного выполнения (например, срого); Р при выполнении инструкции выгрузки буферов згксв (Реппцш П( и выше); (З при выполнении инструкции выгрузки буферов мгвисе (Репбцпт-4); С) при возникновении исключения или вызове прерывания; ьэ при записи или чтении в/из порта ввода/вывода; 0 при выполнении инструкции взвтт. Упорядочивание записи. Помимо всего прочего, на буферы еше возложена и функция упорядочивания записи.
Старшие представители процессоров семейства х8б разбивают машинные инструкции на микрооперации, выполняя их в наиболее предпочтительном с точки зрения В)БС-ядра процессора (Кедцсед (пзггцсбоп Яе1 Согпрц1ег — компьютер с упрощенной системой команд) порядке.
Но ведь нарушение очередности операций чтения/записи в память (кэш) может запросто нарушить нормальную работу программы! Задумайтесь, что произойдет, если в следующем блоке кода?в = *р; *р = ь;" запись ячейки *р завершится раньше ее чтения? Спросите, а почему такое вообще может случиться? Да мало ли почему! Допустим, блок чтения данных занят обработкой предыдущей инструкции и команда и == -р вынужлена терпеливо дожидаться свой очереди, в то время как команда .р = ь захватывается "бездельничающим" в этот момент блоком записи. Конечно, блок записи можно ло завершения чтения и "притормозить", но производительности такая мера не добавит — это уж точно.
Выход?! Выход: временно сохранить записываемые ланные не в каше (основной памяти), а в г7г Глава 3 некотором промежуточном буфере. Чтобы не захламлять архитектуру микроядра и не вводить еще один буфер, конструкторы решили для этих целей использовать все те же буферы записи. Политика выгрузки данных из буфера гарантирует, что данные, помецгенные в буфер, покинут сто "застенки" не раньше, чем завершаться все, предшествующие им инструкции. Таким образом, из буфера данные "уходят" уже упорядоченными и потому никаких конфликтов не возникает. Причем, буферизация записи в определенной степени сокращает количество обращений к памяти„поскольку если одна и та же ячейка записывалась несколько раз, в память (кэш) попадает лишь последний результат.
Реализация и характеристики буферов записи. Младшие модели Реп!щи имели всего два буфера записи (1гг!ге Ьифегз) — по одному на каждый !3- и Ч-р!ре (канал, труба), но уже в Реп!щи ММХ количество буферов возросло до четырех, а в Репбшп П их и вовсе насчитывается двеладцагль! Причем, начиная с Репбшп П, буферы записи переименованы в складские буферы Гггога ЬиЯегг), однако, во избежание путаницы, здесь и далее мы будем пользоваться исключительно прежним термином. Все равно "вгоге" и "апге" в русском переводе — синонимы (во всяком случае, в рамках данного контекста).
Учитывая, что размер каждого из буферов составляет 32 байта, можно безболезненно сохранять до 384 байт (96 двойных слов) за один раз, не беспокоясь за кэш-промахи. По помните, что попытки записи в некэшируемую память при полностью заполненных буферах приводят к неустранимым кэш-промахам и вытекающие отсюда штрафным задержкам. Поэтому целесообразно чередовать операции записи с вычислениями, предоставляя буферам время на выгрузку своего содержимого.
Кэш-подсистеме современных процессоров Кэш-подсистема процессоров Р-П, Р-П1, Р-4 и АМО Арп)оп представляет собой многоуровневую иерархию, состоящую из слелуюших компонентов: кэша данных первого уровня, каша команд первого уровня, общего каша второго уровня, П В-каша страниц данных, ТЬВ-каша страниц кода, буфера упорядочивая записи и буферов записи (рис. 3.15). МОВ. Данные, сходящие с вычислительного конвейера, первым делом попадают на МОВ (Мепюгу Огг!ег Вцйег — буфер упорядоченной записи в память), где они, постепенно накаливаясь, ожидают своей очереди выгрузки в память. Грубо говоря, буфер упорядоченной записи играет тут жс самую роль, что и зал ожидания в аэропорту. Пассажиры прибывают туда в более или менее случайном порядке, но улетают в строгом соответствии со временем, указанным в билете, да и то при условии, что к этому моменту выдастся летная погода и самолету предоставят "коридор" (кто летал — тот поймет).
Кэш Рис. 3.15. Кзш-подсиствмв современных процессоров 1кзш кода не показан) Данные, находящиеся в МОВ, всегда доступы процессору, даже если они еще не выгружены в память, однако емкость буфера упорядоченной записи довольно невелика (40 входов на Рб), и при его переполнении вычислительный конвейер блокируется. Поэтому содержимое МОВ должно при всякой возможности незамедлительно выгружаться оттуда. Это происходит гю крайней мере тремя путями.
1. Если модифицируемая ячейка уже присутствует в кэш-памяти первого уровня, то она направляется в соответствующую ей кэш-строку, на что уходит всего один такт, в течение которого в кэш может быть записана одна или даже две любых несмежных ячейки (максимальное количество одновременно записываемых ячеек определяется архитектурой кэшподсистемы конкретного процессора — см. раэд. "В кэше первого уровня" этлой лавы).