К. Касперски - Техника оптимизации программ, Эффективное использование памяти (1127752), страница 59
Текст из файла (страница 59)
Что же это за особенности такие— пускай разбираются сами читателип И разберемся! Секрет (впрочем, какой это теперь секрет) фирмы !иге! состоит в том, что при записи ячеек памтпи соответствующие им линейки загружаются в кэи второго уровня как эксклюзивные. Остальные же процессоры (в частности, уже упомянутые Агп1оп и Кб), напротив, помечают эти линейки как модифицируемые.
Не знаю, "раздерет" ли меня Ппе! на клочки, но я все-таки рискну не только "пустить пыль в глаза", но и подробно разъясню все вышесказанное. Итак, мысленно представим, как происходит процесс записи ячейки, отсутствующей в кэш-памяти первого уровня. Если ни одного свободного буфера записи нет (а при интенсивной записи памяти их и не будет), процессор вынужден загружать модифицируемую ячейку в кэш первого уровня. Он посылает сигнал кэшу второго уровня, который считывает 32-байтовый блок памяти в одну из своих строк, присваивает ей атрибут "эксклюзивная" и пе- Глава 3 редает ее копию кэшу первого уровня. Так продолжается ло тех пор, пока обрабатываемый блок не превысит размеров кэша первого уровня и тогда процессор будет вынужден избавиться от наименее нужной строки, чтобы освободить место лля новой. Поскольку все строки модифицированы, выбирается наиболее старая из них и отправляется в кэш второго уровня.
Поскольку в кэше второго уровня уже есть ее копия, он просто обновляет содержимое соответствуюшей ей линейки и изменяет атрибут "эксклюзивный" на "модифицируемый". А теперь мы дождемся момента, когда кэш второго уровня будет полностью заполнен, но процессор предпримет попытку записи еше одной ячейки. Что происходит? Кэш первого уровня отправляет кэшу второго уровня сразу два запроса: запрос на загрузку новой порции данных и запрос на обновление вытесняемой кэш-линейки, чем серьезно его озадачивает, — ведь свободное место уже исчерпано. "Ага, — "говорит" кэш второго уровня, — сейчас мы выкинем самое ненужное". А что у нас ненужное? Правильно — эксклюзивные строки. Их удаление не требует предварительной выгрузки в основную память, а потому и обходится дешевле.
Тем временем, пока кэш второго уровня загружает новую порцию данных из оперативной памяти, строка, вытесненная из кэша первого уровня, содержится в специальном буфере и в дальнейшем записывается в основную память минуя кэш второго уровня. Ключевой момент истории состоит в том, что вновь загруженная порция данных получает атрибут эксклюзивной, что делает ее кандидатом номер один на вытеснение. Постойте! Но ведь это означает, что нри выходе за нредеяы кэгиа внгорого уровня занисываемые данные будут замещать одиу и ту зке кзги-строку, сохраняя ранее занисанные строки в неприкосновенности! Это выгодно отличает Р-П, Р-1П от процессоров Кб и Аг1з1оп, в обработке блока, не умешаюшегося в кэше второго уровня, что приводит к последовательному замещению всех его строк.
Допустим, размер записываемых данных вдвое превышает емкость кэшпамяти второго уровня. Тогда в Кб и Аг1з!оп кэш будет крутиться полностью "вхолостую", а на Р-П и Р-Ш только половина обращений вызовет промахи, а остальная благополучно сохранится в кэше.
Впрочем, если говорить объективно, это не совсем так. Вследствие ограниченной ассоциативности кэша постоянным перезагрузкам подвернется не одна-единственная строка„а целый банк. Теперь, в свете вновь открывшихся обстоятельств, становится ясен характер кривой, сопровождаюший выход обрабатываемого блока за границы кэша второго уровня. Действительно, сохранение части кэшируемой памяти как бы оттягивает момент насыщения, округляя острые углы графика записи. Более того, полное насышение вообще не наступает, т. к.
при любом конечном размере обрабатываемого блока, сколь бы большим он ни был, сохраненные строки в той или иной мере повышают производительность. Другой Кэш ВЕОСК51ХЕ вопрос, что с ростом соотношения эффективность такой 1 2.САСНЕ.Ь1ХЕ стратегии стремится к нулю и если размер обрабатываемого блока превосходит емкость кэша в четыре или более раз, ей можно пренебречь. Чтение перед записью и запись перед чтением. Операция записи ячейки с последующим ее чтением выполняется так же быстро, как и одиночная запись. Это не покажется удивительным, если вспомнить, что при промахе кэша первого уровня записываемые данные временно сохраняются в буфере, откуда они могут быть прочитаны в течение такта записи. Другое дело— чтение с последующей записью.
Тут, крути не крути, а при каждом промахе придется дожидаться пока данные не будут прочитаны из кэша второго уровня, в результате каждая операция потребует по меньшей мере четырех дополнительных тактов. Измерения показывают, что так оно и есть. Влияние размера исполняемого кода на производительность В целом, кодовый кэш устроен практически точно так же, как и кэш данных. Даже проще, ведь машинные команды, в отличие от данных, не требуют поддержки операций записи.
1Попытка модификации исполняемого кода приводит к непосредственному обновлению кэшируемой памяти и перезагрузке соответствующей строки кодового кэша, поэтому во избежание падения производительности прибегать к самомодифицирующемуся коду в глубоко вложенных циклах категорически не следует.) Если не углубляться в детали, можно сказать, что влияние размера исполняемого кода на производительность подчиняется тем же законам, что и размер читаемого (не модифицируемого!) блока данных. Давайте проследим, как меняется скорость исполнения блока кода при увеличении его размеров.
Это не такая простая задачка! Ведь, в отличии от обработки данных, мы не можем, не прибегая к самомодифицирующемуся коду, менять размер исполняемого блока по своему желанию. Тем не менее, выход есть и довольно элегантный. Достаточно лишь отказаться от высокоуровневых языков и обратиться к макроассемблеру, развитые препроцессорные средства которого позволят нам сгенерировать блоки исполняемого кода произвольного размера. Для предотвращения возможных побочных эффектов мы будем оформлять каждый блок кода отдельной программой и, чтобы не задавать параметры трансляции каждый раз вручную, воспользуемся пакетным файлом.
В результате, у нас получится следующее 1листинг 3.2). (Полный исходный текст этой программы читатель найдет в файле ~это~13].сасне~ соде.сас1зел1ге.хт, который находится на прилагаемом компакт-диске.) Глава 3 // Макрос СОБР Б12Е автоматически О генерируется пакетньм СООЕ 212Е ЕСО 2 // файлом-транслятором МАКРОС, ГЕНЕРИРУЩИЙ Н мваинньпс команд НОР (команда ИОР буквалько обозначает "нет операцьвт' и ваньаьаат ровно одьвь байт, т.е. Н команд НОР дают Н байт исполняемого кода) // НАЧАЛО МАКРОСА // Е := Н (получаем переданный макросу аргумент) А — переменная-счетчик цикла НОР1НС МАСЕО Н ХН1ЬЕ А НЕ Н а ьфе( А <= и)( вставляем в исходный текст "НОР" ) ОР ) ) О конел мйкросА // ВЕРОВ МАЕРОСА ДЛЯ СОБДАНИЯ ЕЛОЕА ИБ СООЕ 81ЕЕ ЕВ «онанд НОР НОР1НО СООЕ БТЕЕ*1024 б- этот файл формируется пакетным ()1пс1пбе "себе.сасЬе.а1ке.б" транслятором и содержит определение СОРЕ Б12Е (Полный исходный текст программы, показанной в листинге 3.3, читатель найдет в файле ~Бгс~[3].сас]зев,сас))е.Б)2е.с, который находится на прилагае- мом компакт-диске.) Кзш 4>пс1цбе <ОосРО.Л> вм4п() ьпв а; А ВЕО1на); ОоСРО (ба) 1 А ело а) ) // вывод результатов замера на экран ргьпвг("зогб1С аб'~п", СООЕ 812Е, А аКта>)) )Командный файл ~бгс~[3(.сасйе~соде.сасЛе Б(гелпа)4е.пеЛУ.Ьаг (листинг 3.4) читатель найдет на прилагаемом компакт-диске.) Бесно огг 1Р 4814==4МА«Е РОКФ БОТО маге ьв есно = сБОРкА пРимеРА, дйеонстРукл)ЕГО ОпРеделение РАЗмеРА кодОВОГО кэшА = = ЕСНО Утилита к книге ~ "Техника оптимизации программ" /* название рабочее "/ ЕСНО 6ЕСНО ОР)' > СООЕ.САСНЕ.Б18Е.ВОН.ВАТ ЕСНО ЕСНО = = демонстрация определения размера кээа = = » соое.слоне.81ге.лОБ.ВАт ЕСНО ЕСНО Утилита к книге "Техника оптимизации программ" » соое.сАсне.81ге.БОЕ.ВАт » » РОЛ ЗЛА 1Н (2, 4, 8, 1б, 32, б4, 128, 256, 512, 1024, 2048) 00 САЬЬ %0 МАКЕ РОЛ ЪЪА ЕСНО ОЕЬ $$0 » соое.слоне.81ге.кон.ВАт БОТО епб :ваке ьт ЕСНО /%0/41/82 * ЕСНО ЕСНО Н НОР ...СЬССК...
соое.слоне.81ге.лон.алт ЕСНО ЕСНО— соое.слоне.812Б.БОБ.ВАт 4- начало замера времени выполнения выполняем блок иэ СООЕ 818Е команд НОР 4- конец замера времени выполнения Глава 3 БНТГТ СОВЕ 5125 ЕОВ 11 ЯНе11пе СОРЕ 512Е 11 СОРЕ. САСНЕ.Б12Е.ХМ > СОРЕ. САСНЕ.512Е.МОР > СОВЕ. САСНЕ.5125.Н » сОВе.снсне.Б1ге.мОВ > НВЬ ЕСНО ЕСНО САЬ1 С1ССК.МАКЕ.ЯАТ СОВЕ.
САСНЕ.512Е.С РЕЬ СОРЕ. САСНЕ.Б12Е.МОР РЕЬ СОРЕ. САСНЕ.512Е.Н 1Г НОТ ЕХ15Т СОРЕ. САСНЕ.Б12Е.ЕХЕ СОТО етг 1Е ех15т СОРБ. САсне.512е.е1.ехе Реь соэе.схсне.512е.гг.ехе нен сОРе. сАсне.Б12е.ехе ООРе.снсне.51ге.е1.ехе ЕСНО СОВЕ. САСНЕ.5125.ЪЬ.ЕХЕ СОРЕ. САСНЕ.5125.НРН.ВАТ ЕСНО РЕЬ СОРЕ. САСНЕ.5125.21.ЕХЕ СОРЕ. САСНЕ.5125.НВН.ВАТ БОТО епН » » :ЕТТ ЯСНО -ЕНН пеиеие ипмпипииии! пепребиее см. СОРЕ.
САСНЕ.5125.ЕНН ТУРЕ СОРЕ, САСНЕ.512Е,ЕКН :епи Выход за пределы каша первого уровня Прогон полученной программы показывает, что выход за пределы кодового кэша первого уровня вызывает суц!ественное снижение производительно- сти, гораздо более сушественное, нежели при обработке данных. Объясняется это тем, что многостадийные конвейеры современных процес- соров крайне "болезненно" реагируют даже на кратковременные прерывания потока данных.
В частности, на АМ0 АЕЫоп !050 удельное время выполнения команд при выходе за пределы кэша первого уровня увеличивается по меньшей мере втрое (вспомним, что удельное время доступа к данным в аналогичной ситуации возрастает всего лишь на !0% (см. рис, 3.21). На Р-!П (за счет большой ширины шины) падение быстродействия, к счастью, не столь значительно, но все-таки достигает добрых 25%, запросто так "съедая" четверть производительности. С другой стороны, размер кодового кэша составляет всего 32 Кбайт против 64 Кбайт процессора АМ(3 А!!11оп— вот пойди разберись, какой из них предпочтительнее.