Самый быстрый тип кэша в процессоре. Новый подход к кэшированию процессора. Что такое кэш, зачем он нужен и как работает

Ч то является самым грязным местом на компьютере? Думаете, корзина? Папки пользователя? Система охлаждения? Не угадали! Самое грязное место – это кэш! Ведь его постоянно приходится чистить!

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

Понятие и виды кэш-памяти

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

Собственная кэш-память есть у приложений (веб-браузеров, аудио- и видеоплееров, редакторов баз данных и т. д.), компонентов операционных систем (кэш эскизов, DNS-кэш) и оборудования (cache L1-L3 центрального процессора, фреймбуфер графического чипа, буферы накопителей). Реализована она по-разному – программно и аппаратно.

  • Кеш программ – это просто отдельная папка или файл, куда загружаются, например, картинки, меню, скрипты, мультимедийный контент и прочее содержимое посещенных сайтов. Именно в такую папку в первую очередь «ныряет» браузер, когда вы открываете веб-страницу повторно. Подкачка части контента из локального хранилища ускоряет ее загрузку и .
  • В накопителях (в частности, жестких дисках) кэш представляет собой отдельный чип RAM емкостью 1-256 Mb, расположенный на плате электроники. В него поступает информация, считанная с магнитного слоя и пока не загруженная в оперативную память, а также данные, которые чаще всего запрашивает операционная система.
  • Современный центральный процессор содержит 2-3 основных уровня кеш-памяти (ее также называют сверхоперативной памятью), размещенных в виде аппаратных модулей на одном с ним кристалле. Самым быстрым и наименьшим по объему (32-64 Kb) является cache Level 1 (L1) – он работает на той же частоте, что и процессор. L2 занимает среднее положение по скорости и емкости (от 128 Kb до 12 Mb). А L3 – самый медленный и объемный (до 40 Mb), на некоторых моделях отсутствует. Скорость L3 является низкой лишь относительно его более быстрых собратьев, но и он в сотни раз шустрее самой производительной оперативки.

Сверхоперативная память процессора применяется для хранения постоянно используемых данных, перекачанных из ОЗУ, и инструкций машинного кода. Чем ее больше, тем процессор быстрее.

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

Схематично взаимодействие уровней cache L0-L3 выглядит так (на примере Intel Xeon):

Человеческим языком о том, как всё это работает

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

Бумаги, которые нужны ему реже, хранятся недалеко на полках (в оперативной памяти ). Чтобы их достать, нужно встать и пройти несколько метров. А то, с чем человек в настоящее время не работает, сдано в архив (записано на жесткий диск ).

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

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

Стол имеет ограниченную площадь (кэш-память имеет ограниченный объем ). Иногда ее можно расширить, например, придвинув второй стол, а иногда нельзя (объем кэша можно увеличить, если такая возможность предусмотрена программой; кэш оборудования изменить нельзя, так как он реализован аппаратно ).

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

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

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

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

Хеллоу ребята Поговорим о процессоре, а если быть точнее то о его кэше. Кэш у процессора может быть разный, например у меня сейчас Pentium G3220 (1150 сокет), это современный проц и в нем 3 мб кэша. Но при этом у старой модели Pentium D965 (775 сокет) кэша 4 мб. Но при этом G3220 в несколько раз быстрее чем D965, это я к тому, что кэш это хорошо, но главное чтобы кэш был современный. Кэш-память у старых процов намного медленнее, чем у новых, учтите это.

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

Кэш процессора на что влияет? Именно в этом кэше процессор хранит то, чем часто пользуется, ну то есть всякие там команды и инструкции. Соответственно чем его больше, тем лучше, но это не совсем так. Вот сколько у вас кэша? Если не знаете, то я еще покажу как это узнать, тут все просто. Ну так вот, смотрите какая интересная ситуация, опять вернемся к старым процам. Вроде бы если много кэша, то это хорошо. Но есть процессор Q9650 (775 сокет), у которого 12 мб кэша, но он и близко не дотягивает до современных моделей Core i5 а то и Core i3. В i5 кэша в да раза меньше, то есть просто 6 мб, а в i3 его еще меньше - всего 3 мб.

Я понимаю что вообще современные процы куда быстрее, чем старые. Но я не о том. Кеш кэшу рознь, в топовом Q9650 просто медленный кэш по сравнению с процами на современном сокете. Поэтому толку от тех 12 мб никакого нет. Это все я к тому, что не гонитесь за количеством, гонитесь за качеством. Ну вот так. Это все я вам написал на заметку, надеюсь что вам пригодится

Вот на этой картинке по простому указан принцип работы кэша:

А вот другая картинка, тут также указано еще одно устройство, это контроллер, который как раз говорит о том есть ли данные в кэша или нет:

Кэш-память супер быстрая. Я не настолько разбираюсь в процах, но самому было бы интересно узнать, вот если бы этого кэша было… 100 мб.. или даже 1 гб.. был бы процессор быстрее? Это конечно даже сейчас фантастика, но уже сейчас есть процы с огромным количеством кэша.. около 30 мб или больше.. Я не уверен в этом, но вроде бы эта кэш-память очень дорогая и ее вообще сложно засунуть в проц, я имею ввиду большой обьем

Ну а теперь давайте я покажу как узнать сколько кэша в процессоре. Если у вас Windows 10, то это отлично, ибо она умеет показывать все кэши, там ведь есть три уровня. Хотя вроде бы самый главный это третий уровень, он же и самый большой. Итак, смотрите, открываете диспетчер задач и идете в на вкладку Производительность и вот нам на вкладке ЦП вы можете увидеть инфу о кэше, вот она:

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

Но скажу вот по чесноку, что это не есть четкий способ посмотреть сколько кэша у проца. Я советую использовать утилиту CPU-Z, если вы думаете типа: да это прога, нада ставить и все такое, а ну его… То стойте! Эту программу используют крутые оверлокеры, которые разгоняют свои процы. Утилита при установке не создает кучу файлов и на самом деле установка это просто распаковка проги в Program Files, потом cpuz.exe можно куда угодно скопировать и запускать, работать будет! Просто запустили и все, она собрала инфу и вы смотрите! Скачать ее можно легко в интернете, благо она есть на каждом углу. Только смотрите, чтобы вирусов не хапанули.. Для этого качайте например на софт-портале.. Так и пишите в поиске CPU-Z софт портал. Работает CPU-Z почти на всех версиях винды, ну кроме самих древних…

А вообще можете скачать вот на этом сайте: cpuid.com, я просто честно говоря не знал о нем и привык качать с других сайтов!

Ну что, надеюсь что скачать вы ее сможете без проблем. Теперь запускаете и вот тут вам о процессоре все как на ладони. Вот я запустил CPU-Z и вот что она показала о моем Pentium G3220:

Там где я обвел рамочкой, вот там и отображается кэш. Что такое way, ну вот там написано 8-way, 12-way, ну вот что это я не знаю, уж простите. Но вот как видите тут четко видно не только кэш, но и другая инфа, частота, ядра (Cores) и потоки (Threads). Ну так вот, что еще интересно, так это то что тут показывает у вас один кэш или два. Ну вот у меня тут написано просто 3 MBytes, то есть у меня просто 3 мб кэша.

А вот например что касается топового Q9650, то там немного другая ситуация, хоть там и 12 мб кэша, но это по сути два блока по 6 мб и CPU-Z это определяет:

Тут кстати еще как видите есть разгон до 4 ГГц, это неплохо. Кстати такой разгон вполне может быть и на воздушном охлаждении. Но это уже совсем другая история…

Кстати еще что интересно, что в моделях на 775 сокете нет кэша третьего уровня L3… То есть там только L1 и L2.., а я не знал…

Так что вот такие вот дела. Надеюсь что все написал понятно. Еще раз повторю, не гонитесь вы за количеством. Вот я не очень жалею, но тем не менее.. Короче взял я и собрал себе комп на 1150 сокете. Ну думаю, все ништяк. Но как мне стало немного обидно, когда я узнал, что сокет 1151 вышел вот и что он стоит также, а то и чуть дешевле.. Но там реально быстрее процы уже идут.. Ну ладно. Я просто брал комп на века, но зато я обрадовался что моя плата, а это Asus Gryphon Z87 поддерживает процессоры на ядре Devil’s Canyon! Вот это был подарок, ведь раньше Intel заявляла что эти процессоры будут поддерживаться только чипсетом Z97, а я взял то блин Z87!

Короче вот такие дела

На этом все ребята. Надеюсь все у вас будет нормуль и данная инфа была вам полезной, удачи

На главную! кэш процессор 30.07.2016

virtmachine.ru

Влияние кэш-памяти на производительность компьютера

Всем пользователям хорошо известны такие элементы компьютера, как процессор, отвечающий за обработку данных, а также оперативная память (ОЗУ или RAM), отвечающая за их хранение. Но далеко не все, наверное, знают, что существует и кэш-память процессора(Cache CPU), то есть оперативная память самого процессора (так называемая сверхоперативная память).

Функция кэш-памяти

В чем же состоит причина, которая побудила разработчиков компьютеров использовать специальную память для процессора? Разве возможностей ОЗУ для компьютера недостаточно?

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

Вообще говоря, существуют две основные технологии микросхем памяти – статическая память и динамическая память. Не углубляясь в подробности их устройства, скажем лишь, что статическая память, в отличие от динамической, не требует регенерации; кроме того, в статической памяти для одного бита информации используется 4-8 транзисторов, в то время как в динамической – 1-2 транзистора. Соответственно динамическая память гораздо дешевле статической, но в то же время и намного медленнее. В настоящее время микросхемы ОЗУ изготавливаются на основе динамической памяти.

Примерная эволюция соотношения скорости работы процессоров и ОЗУ:

Таким образом, если бы процессор брал все время информацию из оперативной памяти, то ему пришлось бы ждать медлительную динамическую память, и он все время бы простаивал. В том же случае, если бы в качестве ОЗУ использовалась статическая память, то стоимость компьютера возросла бы в несколько раз.

Именно поэтому был разработан разумный компромисс. Основная часть ОЗУ так и осталась динамической, в то время как у процессора появилась своя быстрая кэш-память, основанная на микросхемах статической памяти. Ее объем сравнительно невелик – например, объем кэш-памяти второго уровня составляет всего несколько мегабайт. Впрочем, тут стоить вспомнить о том, что вся оперативная память первых компьютеров IBM PC составляла меньше 1 МБ.

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

История кэш-памяти

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

Впервые кэш-память объемом всего в 16 КБ появилась в ПК на базе процессора i80386. На сегодняшний день современные процессоры используют различные уровни кэша, от первого (самый быстрый кэш самого маленького объема – как правило, 128 КБ) до третьего (самый медленный кэш самого большого объема – до десятков МБ).

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

Долгое время в процессорах существовали всего два уровня кэша, но в CPU Intel Itanium впервые появилась кэш-память третьего уровня, общая для всех ядер процессора. Существуют и разработки процессоров с четырехуровневым кэшем.

Архитектуры и принципы работы кэша

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

Упрощенно схему взаимодействия кэш-памяти и процессора можно описать следующим образом. Сначала происходит проверка наличия нужной процессору информации в самом быстром - кэше первого уровня, затем - в кэше второго уровня, и.т.д. Если же нужной информации в каком-либо уровне кэша не оказалось, то говорят об ошибке, или промахе кэша. Если информации в кэше нет вообще, то процессору приходится брать ее из ОЗУ или даже из внешней памяти (с жесткого диска).

Порядок поиска процессором информации в памяти:

Именно таким образом Процессор осуществляет поиск инфоромации

Для управления работой кэш-памяти и ее взаимодействия с вычислительными блоками процессора, а также ОЗУ существует специальный контроллер.

Схема организации взаимодействия ядра процессора, кэша и ОЗУ:


Кэш-контроллер является ключевым элементом связи процессора, ОЗУ и Кэш-памяти

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

Методы записи кэша

Существует два основных метода записи информации в кэш-память:

  1. Метод write-back (обратная запись) – запись данных производится сначала в кэш, а затем, при наступлении определенных условий, и в ОЗУ.
  2. Метод write-through (сквозная запись) – запись данных производится одновременно в ОЗУ и в кэш.

Архитектура ассоциативности кэш-памяти

Архитектура ассоциативности кэша определяет способ, при помощи которого данные из ОЗУ отображаются в кэше. Существуют следующие основные варианты архитектуры ассоциативности кэширования:

  1. Кэш с прямым отображением – определенный участок кэша отвечает за определенный участок ОЗУ
  2. Полностью ассоциативный кэш – любой участок кэша может ассоциироваться с любым участком ОЗУ
  3. Смешанный кэш (наборно-ассоциативный)

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

Заключение

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

biosgid.ru

Галерея эффектов кэшей процессоров

Почти все разработчики знают, что кэш процессора - это такая маленькая, но быстрая память, в которой хранятся данные из недавно посещённых областей памяти - определение краткое и довольно точное. Тем не менее, знание «скучных» подробностей относительно механизмов работы кэша необходимо для понимания факторов влияющих на производительность кода.

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

Habracut - - -

Пример 1: доступ к памяти и производительность
Как вы думаете, насколько второй цикл быстрее первого? int arr = new int;

For (int i = 0; i // второй for (int i = 0; i Пример 2: влияние строк кэша Копнём глубже - попробуем другие значения шага, не только 1 и 16: for (int i = 0; i

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

Причина этого в том, что современные процессоры осуществляют доступ к памяти не побайтно, а небольшими блоками, которые называют строками кэша. Обычно размер строки составляет 64 байта. Когда вы читаете какое-либо значение из памяти, в кэш попадает как минимум одна строка кэша. Последующий доступ к какому-либо значению из этой строки происходит очень быстро. Из-за того, что 16 значений типа int занимают 64 байта, циклы с шагами от 1 до 16 обращаются к одинаковому количеству строк кэша, точнее говоря, ко всем строкам кэша массива. При шаге 32, обращение происходит к каждой второй строке, при шаге 64, к каждой четвёртой. Понимание этого очень важно для некоторых способов оптимизации. От места расположения данных в памяти зависит число обращений к ней. Например, из-за невыровненных данных может потребоваться два обращения к оперативной памяти, вместо одного. Как мы выяснили выше, скорость работы при этом будет в два раза ниже.

Пример 3: размеры кэшей первого и второго уровня (L1 и L2)
Современные процессоры, как правило, имеют два или три уровня кэшей, обычно их называют L1, L2 и L3. Для того, чтобы узнать размеры кэшей различных уровней, можно воспользоваться утилитой CoreInfo или функцией Windows API GetLogicalProcessorInfo. Оба способа так же предоставляют информацию о размере строки кэша для каждого уровня. На моей машине CoreInfo сообщает о кэшах данных L1 объёмом по 32 Кбайт, кэшах инструкций L1 объёмом по 32 Кбайт и кэшах данных L2 объёмом по 4 Мбайт. Каждое ядро имеет свои персональные кэши L1, кэши L2 общие для каждой пары ядер: Logical Processor to Cache Map: *--- Data Cache 0, Level 1, 32 KB, Assoc 8, LineSize 64 *--- Instruction Cache 0, Level 1, 32 KB, Assoc 8, LineSize 64 -*-- Data Cache 1, Level 1, 32 KB, Assoc 8, LineSize 64 -*-- Instruction Cache 1, Level 1, 32 KB, Assoc 8, LineSize 64 **-- Unified Cache 0, Level 2, 4 MB, Assoc 16, LineSize 64 --*- Data Cache 2, Level 1, 32 KB, Assoc 8, LineSize 64 --*- Instruction Cache 2, Level 1, 32 KB, Assoc 8, LineSize 64 ---* Data Cache 3, Level 1, 32 KB, Assoc 8, LineSize 64 ---* Instruction Cache 3, Level 1, 32 KB, Assoc 8, LineSize 64 --** Unified Cache 1, Level 2, 4 MB, Assoc 16, LineSize 64 Проверим эту информацию экспериментально. Для этого, пройдёмся по нашему массиву инкрементируя каждое 16-ое значение - простой способ изменить данные в каждой строке кэша. При достижении конца, возвращаемся к началу. Проверим различные размеры массива, мы должны увидеть падение производительности когда массив перестаёт помещаться в кэши разных уровней. Код такой: int steps = 64 * 1024 * 1024; // количество итераций int lengthMod = arr.Length - 1; // размер массива -- степень двойки

for (int i = 0; i {

// x & lengthMod = x % arr.Length, ибо степени двойки

Arr[(i * 16) & lengthMod]++; } Результаты тестов:

На моей машине заметны падения производительности после 32 Кбайт и 4 Мбайт - это и есть размеры кэшей L1 и L2.

Пример 4: параллелизм инструкций
Теперь давайте взглянем на кое-что другое. По вашему мнению, какой из этих двух циклов выполнится быстрее? int steps = 256 * 1024 * 1024; int a = new int;

For (int i = 0; i // второй for (int i = 0; i Пример 5: ассоциативность кэша Один из ключевых вопросов, на который необходимо дать ответ при проектировании кэша - могут ли данные из определённой области памяти храниться в любых ячейках кэша или только в некоторых из них. Три возможных решения:

  1. Кэш прямого отображения, данные каждой строки кэша в оперативной памяти хранятся только в одной заранее определённой ячейке кэша. Простейший способ вычисления отображения: индекс_строки_в_памяти % количество_ячеек_кэша. Две строки, отображённые на одну и ту же ячейку, не могут находится в кэше одновременно.
  2. N-входовый частично-ассоциативный кэш, каждая строка может храниться в N различных ячейках кэша. Например, в 16-входовом кэше строка может храниться в одной из 16-ти ячеек составляющих группу. Обычно, строки с равными младшими битами индексов разделяют одну группу.
  3. Полностью ассоциативный кэш, любая строка может быть сохранена в любую ячейку кэша. Решение эквивалентно хеш-таблице по своему поведению.
Кэши прямого отображения подвержены конфликтам, например, когда две строки соревнуются за одну ячейку, поочерёдно вытесняя друг-друга из кэша, эффективность очень низка. С другой стороны, полностью ассоциативные кэши, хотя и лишены этого недостатка, очень сложны и дороги в реализации. Частично-ассоциативные кэши - типичный компромисс между сложностью реализации и эффективностью. К примеру, на моей машине кэш L2 размером в 4 Мбайт является 16-входовым частично-ассоциативным кэшем. Вся оперативная память разделена на множества строк по младшим битам их индексов, строки из каждого множества соревнуются за одну группу из 16 ячеек кэша L2.

Так как кэш L2 имеет 65 536 ячеек (4 * 220 / 64) и каждая группа состоит из 16 ячеек, всего мы имеем 4 096 групп. Таким образом, младшие 12 битов индекса строки определяют к какой группе относится эта строка (212 = 4 096). В результате, строки с адресами кратными 262 144 (4 096 * 64) разделяют одну и ту же группу из 16-ти ячеек и соревнуются за место в ней.

Чтобы эффекты ассоциативности проявили себя, нам необходимо постоянно обращаться к большому количеству строк из одной группы, например, используя следующий код: public static long UpdateEveryKthByte(byte arr, int K) {

const int rep = 1024 * 1024; // количество итераций

Stopwatch sw = Stopwatch.StartNew();

For (int i = 0; i p += K; if (p >= arr.Length) p = 0; } sw.Stop();

return sw.ElapsedMilliseconds;

} Метод инкрементирует каждый K-ый элемент массива. По достижении конца, начинаем заново. После довольно большого количества итераций (220), останавливаемся. Я сделал прогоны для различных размеров массива и значений шага K. Результаты (синий - большое время работы, белый - маленькое):

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

Разберёмся с синими областями:

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

    Некоторые из плохих значений шага - степени двойки: 256 и 512. Для примера рассмотрим шаг 512 и массив в 8 Мбайт. При этом шаге, в массиве имеются 32 участка (8 * 220 / 262 144), которые ведут борьбу друг с другом за ячейки в 512-ти группах кэша (262 144 / 512). Участка 32, а ячеек в кэше под каждую группу только 16, поэтому места на всех не хватает.

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

  2. Почему вертикальные линии обрываются на границе в 4 Мбайт? При размере массива в 4 Мбайт или меньше, 16-входовый кэш ведёт себя так же как и полностью ассоциативный, то есть может вместить все данные массива без конфликтов. Имеется не более 16-ти областей ведущих борьбу за одну группу кэша (262 144 * 16 = 4 * 220 = 4 Мбайт).
  3. Почему слева вверху находится большой синий треугольник? Потому, что при маленьком шаге и большом массиве кэш не в состоянии уместить все необходимые данные. Степень ассоциативности кэша играет тут второстепенную роль, ограничение связано с размером кэша L2. Например, при размере массива в 16 Мбайт и шаге 128, мы обращаемся к каждому 128-му байту, таким образом, модифицируя каждую вторую строку кэша массива. Чтобы сохранить каждую вторую строку в кэше, необходим его объём в 8 Мбайт, но на моей машине есть только 4 Мбайт.

    Даже если бы кэш был полностью ассоциативным, это не позволило бы сохранить в нём 8 Мбайт данных. Заметьте, что в уже рассмотренном примере с шагом 512 и размером массива 8 Мбайт, нам необходим только 1 Мбайт кэша, чтобы сохранить все нужные данные, но это невозможно сделать из-за недостаточной ассоциативности кэша.

  4. Почему левая сторона треугольника постепенно набирает свою интенсивность? Максимум интенсивности приходится на значение шага в 64 байта, что равно размеру строки кэша. Как мы увидели в первом и во втором примере, последовательный доступ к одной и той же строке практически ничего не стоит. Скажем, при шаге в 16 байт, мы имеем четыре обращения к памяти по цене одного. Так как количество итераций равно в нашем тесте при любом значении шага, то более дешёвый шаг в результате даёт меньшее время работы.
Обнаруженные эффекты сохраняются и при больших значениях параметров:

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

Пример 6: ложное разделение кэша
На многоядерных машинах можно столкнуться с другой проблемой - согласование кэшей. Ядра процессора имеют частично или полностью раздельные кэши. На моей машине кэши L1 раздельны (как и обычно), так же имеются два кэша L2, общие для каждой пары ядер. Детали могут различаться, но в целом современные многоядерные процессоры имеют многоуровневые иерархические кэши. Причём самые быстрые, но и самые маленькие кэши, принадлежат индивидуальным ядрам.

Когда одно из ядер модифицирует значение в своём кэше, другие ядра больше не могут использовать старое значение. Значение в кэшах других ядер должно быть обновлено. Более того, должна быть обновлена полностью вся строка кэша, так как кэши оперируют данными на уровне строк.

Продемонстрируем эту проблему на следующем коде: private static int s_counter = new int;

private void UpdateCounter(int position)

{

for (int j = 0; j { s_counter = s_counter + 3; }

Если на своей четырёхядерной машине я вызову этот метод с параметрами 0, 1, 2, 3 одновременно из четырёх потоков, то время работы составит 4.3 секунды. Но если я вызову метод с параметрами 16, 32, 48, 64, то время работы составит только 0.28 секунды. Почему? В первом случае, все четыре значения, обрабатываемые потоками в каждый момент времени, с большой вероятностью попадают в одну строку кэша. Каждый раз когда одно ядро увеличивает очередное значение, оно помечает ячейки кэша, содержащие это значение в других ядрах, как невалидные. После этой операции, все остальные ядра должны будут закэшировать строку заново. Это делает механизм кэширования неработоспособным, убивая производительность.

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

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

Процессоры могут удивить вас хитрыми оптимизациями. Например, код из предыдущего примера про ложное разделение кэша не работает на моём домашнем компьютере так, как задумывалось - в простейших случаях процессор может оптимизировать работу и уменьшить негативные эффекты. Если код немного модифицировать, всё встаёт на свои места. Вот другой пример странных причуд железа: private static int A, B, C, D, E, F, G;

private static void Weirdness()

{

for (int i = 0; i { } } Если вместо подставить три разных варианта, можно получить следующие результаты:

Инкрементирование полей A, B, C, D занимает больше времени, чем инкрементирование полей A, C, E, G. Что ещё страннее, инкрементирование полей A и C занимает больше времени, чем полей A, C и E, G. Не знаю точно каковы причины этого, но возможно они связаны с банками памяти (да-да, с обычными трёхлитровыми сберегательными банками памяти, а не то, что вы подумали). Имеющих соображения на этот счёт, прошу высказываться в комментариях.

У меня на машине вышеописанного не наблюдается, тем не менее, иногда бывают аномально плохие результаты - скорее всего, планировщик задач вносит свои «коррективы».

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

Заключение
Надеюсь, что всё рассмотренное помогло вам понять устройство кэшей процессоров. Теперь вы можете использовать полученные знания на практике для оптимизации своего кода. * Source code was highlighted with Source Code Highlighter. Метки:

Первым процессором, который производился с кэшем L2, стал Pentium Pro в 1995 году. У него было 256 или 512 кбайт кэша второго уровня на кристалле, что давало существенное преимущество над обычными процессорами Pentium, чей кэш располагался на материнской плате. С появлением Pentium II в модуле Slot 1 выделенная кэш-память "поселилась" рядом с процессором. Но только у второго поколения Pentium III для Socket 370 кэш-память перешла на кристалл процессора. Так продолжается и по сей день, но есть процессоры с небольшим количеством кэша, а есть с большим. Стоит ли тратить деньги на модель с большим кэшем? В прошлом дополнительная кэш-память не всегда ощутимо влияла на производительность.

Хотя всегда можно найти измеряемые различия между двумя процессорами с разными размерами кэша, для экономии средств вполне можно было покупать процессоры с меньшим кэшем. Но ни один процессор до появления Core 2 Duo не был доступен с тремя разными вариантами кэша.

Pentium 4 в своём первом поколении (Willamette, 180 нм) оснащался 256 кбайт кэша, а в более успешном втором поколении (Northwood, 130 нм) - уже 512 кбайт кэша. В то время дешёвые процессоры Celeron с меньшим кэшем производились на тех же вычислительных ядрах. Celeron относятся к первому поколению продуктов с одной технологической базой для high-end и дешёвых моделей, различающихся только доступным размером кэша и частотами FSB/ядра. Позднее была добавлена и разница в функциях, чтобы заметнее разделить сегменты рынка.

С выпуском 90-нм ядра Prescott объём кэша L2 вырос до 1 Мбайт, и этот процессор стал основой линейки настольных процессоров Intel до появления 2-Мбайт 65-нм Cedar Mill. Intel даже использовала два таких ядра для создания процессоров Pentium D 900 второго поколения. Впрочем, более быстрые тактовые частоты и больший объём кэша даже тогда не значили очень много. Сегодня ситуация изменилась: лучшая производительность Core 2 Duo (Conroe, 65 нм) и меньшее энергопотребление немало обязаны размеру кэша.

AMD весьма сдержанно относилась к увеличению объёма кэша. Скорее всего, это связано с площадью кристалла (бюджетом транзисторов), поскольку количество 65-нм процессоров не может удовлетворить спрос на рынке, а у менее выгодных 90-нм моделей этот вопрос стоит ещё острее. У Intel, с другой стороны, есть преимущество в виде производства всех массовых процессоров по 65-нм техпроцессу, да и ёмкость кэша L2 будет ещё расти. Например, следующее поколение Core 2 на 45-нм ядре Penryn будет оснащаться до 6 Мбайт кэша L2. Можно ли рассматривать это как маркетинговый шаг, или увеличение ёмкости L2 действительно даст прирост производительности? Давайте посмотрим.

Большой кэш L2: маркетинг или рост производительности?

Кэши процессора играют вполне определённую роль: они уменьшают количество обращений к памяти, буферизуя часто используемые данные. Сегодня ёмкость ОЗУ составляет от 512 Мбайт до 4 Гбайт, а объём кэша - от 256 кбайт до 8 Мбайт, в зависимости от модели. Впрочем, даже небольшого объёма кэша в 256 или 512 кбайт достаточно, чтобы обеспечить высокую производительность, которую сегодня воспринимают само собой разумеющейся.

Есть разные способы организации иерархии кэша. В большинстве современных компьютеров установлены процессоры с небольшим кэшем первого уровня (L1, до 128 кбайт), который обычно разделяется на кэш данных и кэш инструкций. Кэш L2 большего размера обычно используется для хранения данных, он является общим для двух процессорных ядер Core 2 Duo, хотя Athlon 64 X2 или Pentium D имеют раздельные кэши на ядро. Кэш L2 может работать эксклюзивно или инклюзивно, то есть он может либо хранить копию содержимого кэша L1, либо нет. AMD вскоре представит процессоры с третьим уровнем кэша, который будет общим для четырёх ядер в процессорах AMD Phenom. То же самое ожидается и для архитектуры Nehalem, которую Intel представит в 2008 году на замену текущим Core 2.

Кэш L1 всегда был в составе процессора, но поначалу кэш L2 устанавливался на материнские платы, как было в случае многих компьютеров 486DX и Pentium. Для кэш-памяти первого уровня использовались простые чипы статической памяти (SRAM, Static RAM). Они вскоре были заменены конвейерным пакетным кэшем (pipelined burst cache) у процессоров Pentium, пока не появилась возможность устанавливать кэш на кристалл. Pentium Pro на 150 - 200 МГц стал первым процессором, содержащим 256 кбайт кэш-памяти L2 на кристалле, побив рекорд по размеру керамической упаковки для настольных ПК и рабочих станций. Pentium III для Socket 370, работающий на частотах от 500 МГц до 1,13 ГГц, стал первым процессором с 256 кбайт кэш-памяти на кристалле L2, что давало преимущество по снижению задержек, поскольку кэш работает на частоте CPU.

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

Однако кэш-память влияет не только на производительность. Она стала мощным инструментом, позволяющим создавать разные модели процессоров для low-end, массового и high-end сегментов, поскольку производитель может гибко отбирать процессоры по отбраковке и тактовым частотам. Если на кристалле нет дефектов, то можно включить весь кэш L2, да и частоты получаются высокие. Если же желаемых тактовых частот достичь не удастся, то кристалл может стать моделью начального уровня в high-end линейке, например, Core 2 Duo 6000 с 4 Мбайт кэша и низкими частотами. Если дефекты присутствуют в кэше L2, то производитель имеет возможность отключить его часть и создать модель начального уровня с меньшим объёмом кэша, например, Core 2 Duo E4000 с 2 Мбайт кэша L2 или даже Pentium Dual Core всего с 1 Мбайт кэша. Всё это действительно так, но вопрос заключается в следующем: насколько различие в объёме кэша влияет на производительность?

Варианты Core 2 Duo

Intel выпустила на рынок большой ассортимент настольных процессоров. Сегодня ещё можно найти Pentium 4 и Pentium D, но большинство моделей построено на микро-архитектуре Core. Мы не рекомендуем брать процессоры Pentium 4 или Pentium D, хотя их тактовые частоты до 3,8 ГГц могут выглядеть привлекательно. Но любой процессор Core 2 на частоте 2,2 ГГц и выше способен победить даже самые быстрые модели Pentium D (собственно, как и Athlon 64 X2), поскольку Core 2 даёт намного лучшую производительность на такт .

Благодаря меньшим тактовым частотам процессоры Core 2 более эффективны по энергопотреблению. Если топовые модели Pentium D 800 "съедают" до 130 Вт, то лишь Core 2 Extreme с четырьмя ядрами преодолевает порог 100 Вт. Все двуядерные процессоры потребляют не больше 65 Вт. Кроме того, энергопотребление в режиме бездействия процессоров Core 2 Duo ещё ниже, поскольку рабочая частота в режиме бездействия меньше (максимум 1,2 ГГц для Core 2 Duo/Quad против 2,8 ГГц для Pentium D/4). На снижение энергопотребления повлиял улучшенный дизайн транзисторов с уменьшенными токами утечки.

Сегодня доступны модели E и X. Модели E предназначены для массового рынка, а X относятся к классу Extreme Edition. Q обозначает четыре ядра, которые Intel создаёт, размещая два двуядерных кристалла в одной физической упаковке. Процессоры E6000 оснащены 4 Мбайт кэша L2, если их модельный номер выше E6400 или заканчивается на 20 (например, E6320). Модели, заканчивающиеся на 00 (например, E6600) работают с FSB 266 МГц (FSB1066), а модели, заканчивающиеся на 50 (E6750), работают с FSB 333 МГц (FSB1333). Последняя требует чипсета P35 или X38 и даёт чуть более высокую производительность. E4000 работает с FSB 200 МГц (FSB800) и имеет всего 2 Мбайт кэша L2. Версии с 1 Мбайт кэша продаются как Pentium Dual Core E2140, E2160 и E2180 с частотами от 1,6 до 2,0 ГГц. Кроме названия и некоторых функций, которые Intel отключает у дешёвых процессоров, упомянутые модели Pentium Dual Cores идентичны Core 2 Duo.

Характеристики процессоровCore 2 Duo
Номер 65-нм процессора Кэш Тактовая частота FSB Технология виртуализации Технология Trusted Execution
E6850 4 Мбайт L2 3 ГГц 333 МГц X X
E6750 4 Мбайт L2 2,66 ГГц 333 МГц X X
E6700 4 Мбайт L2 2,66 ГГц 266 МГц X
E6600 4 Мбайт L2 2,40 ГГц 266 МГц X
E6550 4 Мбайт L2 2,33 ГГц 333 МГц X X
E6540 4 Мбайт L2 2,33 ГГц 333 МГц X
E6420 4 Мбайт L2 2,13 ГГц 266 МГц X
E6400 2 Мбайт L2 2,13 ГГц 266 МГц X
E6320 4 Мбайт L2 1,86 ГГц 266 МГц X
E6300 2 Мбайт L2 1,86 ГГц 266 МГц X
E4600 2 Мбайт L2 2,40 ГГц 200 МГц
E4500 2 Мбайт L2 2,20 ГГц 200 МГц
E4400 2 Мбайт L2 2 ГГц 200 МГц
E4300 2 Мбайт L2 1,80 ГГц 200 МГц


Платформа
CPU I Intel Pentium Dual Core E2160 (65 нм; 1 800 МГц, 1 Мбайт кэша L2) на частоте 2,4 ГГц (266 МГц x9)
CPU II Intel Core 2 Duo E4400 (65 нм; 2 000 МГц, 2 Мбайт кэша L2) на частоте 2,4 ГГц (266 МГц x9)
CPU III Intel Core 2 Duo X6800 (65 нм; 3 000 МГц, 4 Мбайт кэша L2) на частоте 2,4 ГГц (266 МГц x9)
Материнская плата ASUS Blitz Formula, Rev: 1.0
Чипсет: Intel P35, BIOS 1101
Память Corsair CM2X1024-888C4D, 2x 1024 Мбайт DDR2-800 (CL 4-4-4-12 2T)
Жёсткий диск Western Digital Raptor WD1500ADFD, 150 Гбайт, 10 000 об/мин, кэш 16 Мбайт, SATA/150
DVD-ROM Samsung SH-S183
Видеокарта Zotac GeForce 8800 GTS, GPU: GeForce 8800 GTS (500 МГц), память: 320 Мбайт GDDR3 (1 600 Мгц)
Звуковая карта Встроенная
Блок питания Enermax EG565P-VE, ATX 2.01, 510 Вт
Системное ПО и драйверы
ОС Windows XP Professional 5.10.2600, Service Pack 2
Версия DirectX 9.0c (4.09.0000.0904)
Драйверы платформы Intel Version 8.3.1013
Графический драйвер nVidia Forceware 162.18

Тесты и настройки

3D-игры
Call Of Duty 2 Version: 1.3 Retail
Video Mode: 1280x960
Anti Aliasing: off
Graphics Card: medium
Timedemo demo2
Prey Version: 1.3
Video Mode: 1280x1024
Video Quality: game default
Vsync = off
Benchmark: THG-Demo
Quake 4 Version: 1.2 (Dual-Core Patch)
Video Mode: 1280x1024
Video Quality: high
THG Timedemo waste.map
timedemo demo8.demo 1 (1 = load textures)
Аудио
Lame MP3 Version 3.98 Beta 5
Audio CD "Terminator II SE", 53 min
wave to mp3
160 kbps
Видео
TMPEG 3.0 Express Version: 3.0.4.24 (no Audio)
fist 5 Minutes DVD Terminator 2 SE (704x576) 16:9
Multithreading by rendering
DivX 6.7 Version: 6.6 (4 Logical CPUs)
Profile: High Definition Profile
1-pass, 3000 kbit/s
Encoding mode: Insane Quality
Enhanced multithreading
no Audio
XviD 1.1.3 Version: 1.1.3
Target quantizer: 1.00
Mainconcept H.264 v2 Version 2.1
260 MB MPEG-2 source (1920x1080) 16:9
Codec: H.264
Mode: NTSC
Audio: AAC
Profile: High
Stream: Program
Приложения
WinRAR Version 3.70
(303 MB, 47 Files, 2 Folders)
Compression = Best
Dictionary = 4096 kB
Autodesk 3D Studio Max Version: 8.0
Characters "Dragon_Charater_rig"
rendering HTDV 1920x1080
Cinebench Version: R10
1 CPU, x CPU run
PCMark05 Pro Version: 1.2.0
CPU and Memory Tests
Windows Media Player 10.00.00.3646
Windows Media Encoder 9.00.00.2980




Заключение

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

Ответ прост: размер кэша очень важен для современных процессоров с микро-архитектурой Core 2 Duo. Мы использовали 4-Мбайт Core 2 Extreme X6800, 2-Мбайт Core 2 Duo E4400 и Pentium Dual Core E2160, который является процессором Core 2 Duo с кэшем L2 всего 1 Мбайт. Все процессоры работали на одинаковой системной шине 266 МГц и с множителем 9x, чтобы частота составила 2 400 МГц. Единственная разница заключается в размере кэша, поскольку все современные двуядерные процессоры, за исключением старого Pentium D, производятся из одинаковых кристаллов. Чем станет ядро, Core 2 Extreme Edition или Pentium Dual Core, определяется выходом годных кристаллов (дефектами) или спросом рынка.

Если вы сравните результаты 3D-шутеров Prey и Quake 4, являющих типичными игровыми приложениями, разница в производительности между 1 и 4 Мбайт составляет примерно один шаг по частоте. То же самое касается тестов кодирования видео для кодеков DivX 6.6 и XviD 1.1.2, а также архиватора WinRAR 3.7. Однако, такие интенсивно нагружающие CPU приложения, как 3DStudio Max 8, Lame MP3 Encoder или H.264 Encoder V2 от MainConcept не слишком сильно выигрывают от увеличения размера кэша.

Впрочем, подход Intel, а именно, использование всего доступного бюджета транзисторов, который увеличился при переходе с 65-нм техпроцесса на 45-нм, имеет для микро-архитектуры Core 2 Duo определённую значимость. Кэш L2 у этих процессоров работает очень эффективно, особенно, если учесть, что он общий для двух ядер. Поэтому кэш нивелирует влияние разных частот памяти и предотвращает "узкое место" в виде FSB. И делает он это замечательно, поскольку тесты наглядно показывают, что производительность процессора с одним мегабайтом кэш-памяти невысокая.

С этой точки зрения увеличение размера кэша L2 с 4 Мбайт до, максимум, 6 Мбайт у грядущих 45-нм двуядерных процессоров Penryn (линейка Core 2 Duo E8000) имеет смысл. Уменьшение техпроцесса с 65 до 45 нм позволяет Intel увеличить бюджет транзисторов, и благодаря увеличению объёма кэша мы вновь получим рост производительности. Впрочем, Intel получит выгоду из-за разных вариантов процессоров с 6, 4, 2 или даже 1 Мбайт кэша L2. Благодаря нескольким вариантам Intel может использовать большее число кристаллов с пластины, несмотря на наличие случайных дефектов, которые в противном случае приводили бы к попаданию кристалла в мусорную корзину. Большой размер кэша, как видим, важен не только для производительности, но и для прибыли Intel.

Почти все разработчики знают, что кэш процессора - это такая маленькая, но быстрая память, в которой хранятся данные из недавно посещённых областей памяти - определение краткое и довольно точное. Тем не менее, знание «скучных» подробностей относительно механизмов работы кэша необходимо для понимания факторов влияющих на производительность кода.

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

Habracut - - -

Пример 1: доступ к памяти и производительность

Как вы думаете, насколько второй цикл быстрее первого?
int arr = new int ;

// первый
for (int i = 0; i < arr.Length; i++) arr[i] *= 3;

// второй
for (int i = 0; i < arr.Length; i += 16) arr[i] *= 3;


Первый цикл умножает все значения массива на 3, второй цикл только каждое шестнадцатое значение. Второй цикл совершает только 6% работы первого цикла, но на современных машинах оба цикла выполняются примерно за равное время: 80 мс и 78 мс соответственно (на моей машине).

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

Пример 2: влияние строк кэша

Копнём глубже - попробуем другие значения шага, не только 1 и 16:
for (int i = 0; i < arr.Length; i += K /* шаг */ ) arr[i] *= 3;

Вот время работы этого цикла для различных значений шага K:

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

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

Из-за того, что 16 значений типа int занимают 64 байта, циклы с шагами от 1 до 16 обращаются к одинаковому количеству строк кэша, точнее говоря, ко всем строкам кэша массива. При шаге 32, обращение происходит к каждой второй строке, при шаге 64, к каждой четвёртой.

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

Пример 3: размеры кэшей первого и второго уровня (L1 и L2)

Современные процессоры, как правило, имеют два или три уровня кэшей, обычно их называют L1, L2 и L3. Для того, чтобы узнать размеры кэшей различных уровней, можно воспользоваться утилитой CoreInfo или функцией Windows API GetLogicalProcessorInfo . Оба способа так же предоставляют информацию о размере строки кэша для каждого уровня.

На моей машине CoreInfo сообщает о кэшах данных L1 объёмом по 32 Кбайт, кэшах инструкций L1 объёмом по 32 Кбайт и кэшах данных L2 объёмом по 4 Мбайт. Каждое ядро имеет свои персональные кэши L1, кэши L2 общие для каждой пары ядер:

Logical Processor to Cache Map: *--- Data Cache 0, Level 1, 32 KB, Assoc 8, LineSize 64 *--- Instruction Cache 0, Level 1, 32 KB, Assoc 8, LineSize 64 -*-- Data Cache 1, Level 1, 32 KB, Assoc 8, LineSize 64 -*-- Instruction Cache 1, Level 1, 32 KB, Assoc 8, LineSize 64 **-- Unified Cache 0, Level 2, 4 MB, Assoc 16, LineSize 64 --*- Data Cache 2, Level 1, 32 KB, Assoc 8, LineSize 64 --*- Instruction Cache 2, Level 1, 32 KB, Assoc 8, LineSize 64 ---* Data Cache 3, Level 1, 32 KB, Assoc 8, LineSize 64 ---* Instruction Cache 3, Level 1, 32 KB, Assoc 8, LineSize 64 --** Unified Cache 1, Level 2, 4 MB, Assoc 16, LineSize 64
Проверим эту информацию экспериментально. Для этого, пройдёмся по нашему массиву инкрементируя каждое 16-ое значение - простой способ изменить данные в каждой строке кэша. При достижении конца, возвращаемся к началу. Проверим различные размеры массива, мы должны увидеть падение производительности когда массив перестаёт помещаться в кэши разных уровней.

Код такой:

int steps = 64 * 1024 * 1024; // количество итераций
int lengthMod = arr.Length - 1; // размер массива -- степень двойки

for (int i = 0; i < steps; i++)
{
// x & lengthMod = x % arr.Length, ибо степени двойки
arr[(i * 16) & lengthMod]++;
}


Результаты тестов:

На моей машине заметны падения производительности после 32 Кбайт и 4 Мбайт - это и есть размеры кэшей L1 и L2.

Пример 4: параллелизм инструкций

Теперь давайте взглянем на кое-что другое. По вашему мнению, какой из этих двух циклов выполнится быстрее?
int steps = 256 * 1024 * 1024;
int a = new int ;

// первый
for (int i = 0; i < steps; i++) { a++; a++; }

// второй
for (int i = 0; i < steps; i++) { a++; a++; }


Оказывается, второй цикл выполняется почти в два раза быстрее, по крайней мере, на всех протестированных мной машинах. Почему? Потому, что команды внутри циклов имеют разные зависимости по данным. Команды первого имеют следующую цепочку зависимостей:

Во втором цикле зависимости такие:

Функциональные части современных процессоров способны выполнять определённое число некоторых операций одновременно, как правило, не очень большое число. Например, возможен параллельный доступ к данным из кэша L1 по двум адресам, так же возможно одновременное выполнение двух простых арифметических команд. В первом цикле процессор не может задействовать эти возможности, но может во втором.

Пример 5: ассоциативность кэша

Один из ключевых вопросов, на который необходимо дать ответ при проектировании кэша - могут ли данные из определённой области памяти храниться в любых ячейках кэша или только в некоторых из них. Три возможных решения:
  1. Кэш прямого отображения , данные каждой строки кэша в оперативной памяти хранятся только в одной заранее определённой ячейке кэша. Простейший способ вычисления отображения: индекс_строки_в_памяти % количество_ячеек_кэша. Две строки, отображённые на одну и ту же ячейку, не могут находится в кэше одновременно.
  2. N-входовый частично-ассоциативный кэш , каждая строка может храниться в N различных ячейках кэша. Например, в 16-входовом кэше строка может храниться в одной из 16-ти ячеек составляющих группу. Обычно, строки с равными младшими битами индексов разделяют одну группу.
  3. Полностью ассоциативный кэш , любая строка может быть сохранена в любую ячейку кэша. Решение эквивалентно хеш-таблице по своему поведению.
Кэши прямого отображения подвержены конфликтам, например, когда две строки соревнуются за одну ячейку, поочерёдно вытесняя друг-друга из кэша, эффективность очень низка. С другой стороны, полностью ассоциативные кэши, хотя и лишены этого недостатка, очень сложны и дороги в реализации. Частично-ассоциативные кэши - типичный компромисс между сложностью реализации и эффективностью.

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

Так как кэш L2 имеет 65 536 ячеек (4 * 2 20 / 64) и каждая группа состоит из 16 ячеек, всего мы имеем 4 096 групп. Таким образом, младшие 12 битов индекса строки определяют к какой группе относится эта строка (2 12 = 4 096). В результате, строки с адресами кратными 262 144 (4 096 * 64) разделяют одну и ту же группу из 16-ти ячеек и соревнуются за место в ней.

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

public static long UpdateEveryKthByte(byte arr, int K)
{
const int rep = 1024 * 1024; // количество итераций

Stopwatch sw = Stopwatch.StartNew();

int p = 0;
for (int i = 0; i < rep; i++)
{
arr[p]++;

P += K; if (p >= arr.Length) p = 0;
}

Sw.Stop();
return sw.ElapsedMilliseconds;
}


Метод инкрементирует каждый K-ый элемент массива. По достижении конца, начинаем заново. После довольно большого количества итераций (2 20), останавливаемся. Я сделал прогоны для различных размеров массива и значений шага K. Результаты (синий - большое время работы, белый - маленькое):

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

Разберёмся с синими областями:

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

    Некоторые из плохих значений шага - степени двойки: 256 и 512. Для примера рассмотрим шаг 512 и массив в 8 Мбайт. При этом шаге, в массиве имеются 32 участка (8 * 2 20 / 262 144), которые ведут борьбу друг с другом за ячейки в 512-ти группах кэша (262 144 / 512). Участка 32, а ячеек в кэше под каждую группу только 16, поэтому места на всех не хватает.

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

  2. Почему вертикальные линии обрываются на границе в 4 Мбайт? При размере массива в 4 Мбайт или меньше, 16-входовый кэш ведёт себя так же как и полностью ассоциативный, то есть может вместить все данные массива без конфликтов. Имеется не более 16-ти областей ведущих борьбу за одну группу кэша (262 144 * 16 = 4 * 2 20 = 4 Мбайт).
  3. Почему слева вверху находится большой синий треугольник? Потому, что при маленьком шаге и большом массиве кэш не в состоянии уместить все необходимые данные. Степень ассоциативности кэша играет тут второстепенную роль, ограничение связано с размером кэша L2.

    Например, при размере массива в 16 Мбайт и шаге 128, мы обращаемся к каждому 128-му байту, таким образом, модифицируя каждую вторую строку кэша массива. Чтобы сохранить каждую вторую строку в кэше, необходим его объём в 8 Мбайт, но на моей машине есть только 4 Мбайт.

    Даже если бы кэш был полностью ассоциативным, это не позволило бы сохранить в нём 8 Мбайт данных. Заметьте, что в уже рассмотренном примере с шагом 512 и размером массива 8 Мбайт, нам необходим только 1 Мбайт кэша, чтобы сохранить все нужные данные, но это невозможно сделать из-за недостаточной ассоциативности кэша.

  4. Почему левая сторона треугольника постепенно набирает свою интенсивность? Максимум интенсивности приходится на значение шага в 64 байта, что равно размеру строки кэша. Как мы увидели в первом и во втором примере, последовательный доступ к одной и той же строке практически ничего не стоит. Скажем, при шаге в 16 байт, мы имеем четыре обращения к памяти по цене одного.

    Так как количество итераций равно в нашем тесте при любом значении шага, то более дешёвый шаг в результате даёт меньшее время работы.

Обнаруженные эффекты сохраняются и при больших значениях параметров:

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

Пример 6: ложное разделение кэша

На многоядерных машинах можно столкнуться с другой проблемой - согласование кэшей. Ядра процессора имеют частично или полностью раздельные кэши. На моей машине кэши L1 раздельны (как и обычно), так же имеются два кэша L2, общие для каждой пары ядер. Детали могут различаться, но в целом современные многоядерные процессоры имеют многоуровневые иерархические кэши. Причём самые быстрые, но и самые маленькие кэши, принадлежат индивидуальным ядрам.

Когда одно из ядер модифицирует значение в своём кэше, другие ядра больше не могут использовать старое значение. Значение в кэшах других ядер должно быть обновлено. Более того, должна быть обновлена полностью вся строка кэша , так как кэши оперируют данными на уровне строк.

Продемонстрируем эту проблему на следующем коде:

private static int s_counter = new int ;

private void UpdateCounter(int position)
{
for (int j = 0; j < 100000000; j++)
{
s_counter = s_counter + 3;
}
}


Если на своей четырёхядерной машине я вызову этот метод с параметрами 0, 1, 2, 3 одновременно из четырёх потоков, то время работы составит 4.3 секунды . Но если я вызову метод с параметрами 16, 32, 48, 64, то время работы составит только 0.28 секунды .

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

Пример 7: сложность железа

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

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

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

Вот другой пример странных причуд железа:

private static int A, B, C, D, E, F, G;

private static void Weirdness()
{
for (int i = 0; i < 200000000; i++)
{
<какой-то код>
}
}


Если вместо <какой-то код> подставить три разных варианта, можно получить следующие результаты:

Инкрементирование полей A, B, C, D занимает больше времени, чем инкрементирование полей A, C, E, G. Что ещё страннее, инкрементирование полей A и C занимает больше времени, чем полей A, C и E, G. Не знаю точно каковы причины этого, но возможно они связаны с банками памяти (да-да, с обычными трёхлитровыми сберегательными банками памяти, а не то, что вы подумали ). Имеющих соображения на этот счёт, прошу высказываться в комментариях.

У меня на машине вышеописанного не наблюдается, тем не менее, иногда бывают аномально плохие результаты - скорее всего, планировщик задач вносит свои «коррективы».

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

Заключение

Надеюсь, что всё рассмотренное помогло вам понять устройство кэшей процессоров. Теперь вы можете использовать полученные знания на практике для оптимизации своего кода.

Сегодняшняя статья не является самостоятельным материалом - она просто продолжает исследование производительности трех поколений архитектуры Core в равных условиях (начатое в конце прошлого года и продолженное недавно). Правда, сегодня мы сделаем небольшой шаг в сторону - часто́ты ядер и кэш-памяти останутся теми же, что и ранее, а вот емкость последней уменьшится. Зачем это нужно? Мы использовали «полный» Core i7 двух последних поколений для чистоты эксперимента, тестируя его с включенной и отключенной поддержкой технологии Hyper-Threading, поскольку вот уже полтора года как Core i5 снабжаются не 8, а 6 МиБ L3. Понятно, что влияние емкости кэш-памяти на производительность не так уж велико, как иногда принято считать, но оно есть, и никуда от него не деться. К тому же, Core i5 являются более массовыми продуктами, чем Core i7, а в первом поколении по этому параметру их никто «не обижал». Зато раньше их чуть ограничивали по-другому: тактовая частота UnCore в i5 первого поколения составляла всего 2,13 ГГц, так что наш «Nehalem» - это не совсем представитель 700-й линейки на частоте 2,4 ГГц, а немного более быстрый процессор. Однако сильно расширять список участников и переделывать условия тестирования мы сочли излишним - все равно, как мы уже не раз предупреждали, тестирования этой линейки никакой новой практической информации не несут: реальные процессоры работают совсем в других режимах. А вот желающим досконально разобраться во всех тонких моментах, как нам кажется, такое тестирование будет интересно.

Конфигурация тестовых стендов

Мы решили ограничиться всего четырьмя процессорами, причем главных участников будет два: оба четырехъядерных Ivy Bridge, но с разной емкостью кэш-памяти третьего уровня. Третий - «Nehalem HT»: в прошлый раз по итоговому баллу он оказался почти идентичен «Ivy Bridge просто». И «просто Nehalem» который, как мы уже сказали, чуть-чуть быстрее настоящего Core i5 первого поколения, работающего на частоте 2,4 ГГц (из-за того, напомним, что в 700-й линейке частота UnCore была немного ниже), но не слишком радикально. Зато и сравнение интересно: с одной стороны - два шага улучшения микроархитекутры, с другой - кэш-память ограничили. Априори можно предположить, что первое в большинстве случаев перевесит, но вот насколько и вообще - как сопоставимы «первые» и «третьи» i5 (с поправкой на частоту UnCore, конечно, хотя если будет много желающих увидеть абсолютно точное сравнение, мы и его потом сделаем) - уже хорошая тема для исследования.

Тестирование

Традиционно, мы разбиваем все тесты на некоторое количество групп и приводим на диаграммах средний результат по группе тестов/приложений (детально с методикой тестирования вы можете ознакомиться в отдельной статье). Результаты на диаграммах приведены в баллах, за 100 баллов принята производительность референсной тестовой системы сайт образца 2011 года. Основывается она на процессоре AMD Athlon II X4 620, ну а объем памяти (8 ГБ) и видеокарта () являются стандартными для всех тестирований «основной линейки» и могут меняться только в рамках специальных исследований. Тем, кто интересуется более подробной информацией, опять-таки традиционно предлагается скачать таблицу в формате Microsoft Excel , в которой все результаты приведены как в преобразованном в баллы, так и в «натуральном» виде.

Интерактивная работа в трёхмерных пакетах

Некоторое влияние емкости кэш-памяти есть, однако оно менее 1%. Соответственно, оба Ivy Bridge можно считать идентичными друг другу, ну а улучшения архитектуры позволяют новым Core i5 спокойно обгонять старые Core i7 точно также, как это делают новые Core i7.

Финальный рендеринг трёхмерных сцен

В данном случае, естественно, никакие усовершенствования не могут скомпенсировать увеличение количества обрабатываемых потоков, но сегодня для нас самым важным является не это, а полное отсутствие влияния емкости кэш-памяти на производительность. Вот Celeron и Pentium, как мы уже установили , разные процессоры, так что программы рендеринга чувствительны к емкости L3, однако лишь тогда, когда последнего мало. А 6 МиБ на четыре ядра, как видим, вполне достаточно.

Упаковка и распаковка

Естественно, эти задачи восприимчивы к емкости кэш-памяти, однако и здесь эффект от ее увеличения с 6 до 8 МиБ достаточно скромный: примерно 3,6%. Более интересно, на самом деле, сравнение с первым поколением - архитектурные улучшения позволяют новым i5 на равных частотах «громить» даже старые i7, но это в общем зачете: благодаря тому, что два теста из четырех однопоточные, а еще один двухпоточный. Сжатие данных силами 7-Zip, естественно, быстрее всего на «Nehalem HT»: восемь потоков всегда быстрее четырех сравнимой производительности. А вот если ограничиться всего четырьмя, то наш «Ivy Bridge 6М» проигрывает не только своему прародителю, но и старичку Nehalem: улучшения микроархитектуры полностью пасуют перед уменьшением емкости кэш-памяти.

Кодирование аудио

Несколько неожиданным оказался не размер разницы между двумя Ivy Bridge, а то, что она вообще есть. Правда настолько копеечная, что ее можно и на особенности округления или погрешности измерения списать.

Компиляция

Важны потоки, но важна и емкость кэш-памяти. Однако, как обычно, не слишком - порядка 1,5%. Более любопытно сравнение с первым поколением Core при отключенном Hyper-Threading: «по очкам» новенький Core i5 даже на равной частоте побеждает, но один из трех компиляторов (производства Microsoft, если быть точным) отработал на обоих процессорах за одинаковое время. Даже с преимуществом в 5 секунд у более старого - притом, что в этой программе у «полнокэшевого» Ivy Bridge результаты на 4 секунды лучше, чем у Nehalem. В общем, и здесь нельзя считать, что уменьшение емкости L3 как-то сильно повлияло на Core i5 второго и третьего поколения, но есть и нюансы.

Математические и инженерные расчёты

Опять менее 1% разницы со «старшим» кристаллом и опять убедительная победа над первым поколением во всех его видах. Что скорее правило, чем исключение для подобных малопоточных тестов, но почему бы в нем в очередной раз не убедиться? Особенно в таком вот рафинированном виде, когда (в отличие от тестов в штатном режиме) не мешает разница в частотах («стандартных» или появляющаяся из-за работы Turbo Boost).

Растровая графика

Но и при более полной утилизации многопоточности картина не всегда меняется. А емкость кэш-памяти не дает вовсе ничего.

Векторная графика

И здесь аналогично. Правда и потоков вычисления нужна всего парочка.

Кодирование видео

В отличие от этой группы, где, тем не менее, даже Hyper-Threading не позволяет Nehalem бороться на равных с последователями более новых поколений. А вот им не слишком мешает уменьшение емкости кэш-памяти. Точнее, практически вообще не мешает, поскольку разница опять менее 1%.

Офисное ПО

Как и следовало ожидать, никакого прироста производительности от увеличения емкости кэш-памяти (точнее, ее падения от уменьшения) нет. Хотя если посмотреть на подробные результаты, то видно, что единственный многопоточный тест этой группы (а именно распознавание текста в FineReader) выполняется примерно на 1,5% быстрее при 8 МиБ L3, нежели на 6 МиБ. Казалось бы - что такое 1,5%? С точки зрения практики - ничто. А вот с исследовательской точки зрения уже интересно: как видим, именно многопоточным тестам чаще всего не хватает кэш-памяти. В результате разница (пусть и небольшая) иногда находится даже там, где ее быть, вроде бы, не должно. Хотя ничего такого уж необъяснимого в этом нет - грубо говоря, в малопоточных тестах мы имеем 3-6 МиБ на поток, а вот в многопоточных там же получается 1,5 МиБ. Первого - много, а вот второго может оказаться и не совсем достаточно.

Java

Впрочем, Java-машина с такой оценкой не согласна, но и это объяснимо: как мы уже не раз писали, она очень хорошо оптимизирована вовсе не под х86-процессоры, а под телефоны и кофеварки, где ядер может быть много, но вот кэш-памяти очень мало. А иногда и ядер, и кэш-памяти мало - дорогие ресурсы как по площади кристалла, так и по энергопотреблению. И, если с ядрами и мегагерцами что-то сделать получается, то вот с кэшом все сложнее: в четырехъядерной Tegra 3 его, к примеру, всего 1 МиБ. Понятно, что JVM может «схрюпать» и больше (как и все системы с байт-кодом), что мы уже видели сравнивая Celeron и Pentium, но более 1,5 МиБ на поток ей если и может пригодиться, то не в тех задачах, которые вошли в SPECjvm 2008.

Игры

На игры у нас были большие надежды, поскольку к емкости кэш-памяти они нередко оказываются более требовательными чем даже архиваторы. Но бывает такое тогда, когда ее совсем мало, а 6 МиБ - как видим, достаточно. Да и, опять же, процессоры уровня четырехъядерных Core любых поколений даже на частоте 2,4 ГГц слишком мощное решение для используемых игровых приложений, так что узким местом явно будут не они, а прочие компоненты системы. Поэтому мы решили стряхнуть пыль с режимов с низким качеством графики - понятно, что для таких систем он слишком уж синтетичен, но у нас и все тестирование синтетическое:)

Когда не мешают всякие там видеокарты и прочее, разница между двумя Ivy Bridge достигает уже «безумных» 3%: и в этом случае можно не обращать внимания на практике, но для теории - немало. Больше вышло как раз только в архиваторах.

Многозадачное окружение

Где-то мы уже такое видели. Ну да - когда тестировали шестиядерные процессоры под LGA2011. И вот ситуация повторяется: нагрузка что ни на есть многопоточная, часть используемых программ до кэш-памяти «жадная», а вот ее увеличение только снижает среднюю производительность. Чем это можно объяснить? Разве что тем, что усложняется арбитраж и увеличивается количество промахов. Причем, заметим, происходит такое только тогда, когда емкость L3 относительно велика и одновременно работающих потоков вычисления не менее четырех - в бюджетном сегменте совсем другая картина. Во всяком случае, как показало наше недавнее тестирование Pentium и Celeron, для двухъядерных процессоров увеличение L3 с 2 до 3 МиБ добавляет 6% производительности. А вот четырех- и шестиядерным не дает, мягко говоря ничего. Даже менее, чем ничего.

Итого

Закономерный общий итог: поскольку нигде существенной разницы между процессорами с разным объемом L3 не обнаружилось, нет ее и в «общем и целом». Таким образом, расстраиваться по поводу уменьшения емкости кэш-памяти во втором и третьем поколении Core i5 поводов нет - предшественники первого поколения им все равно не конкуренты. Да и старые Core i7 в среднем тоже демонстрируют лишь аналогичный уровень производительности (разумеется, в основном за счет отставания в малопоточных приложениях - а так есть сценарии, с которыми в равных условиях они справляются быстрее). Но, как мы уже говорили, на практике реальные процессоры находятся далеко не в равных условиях по частотам, так что практическая разница между поколениями больше, чем можно получить в таких вот исследованиях.

Открытым остается лишь один вопрос: нам пришлось сильно снизить тактовую частоту для обеспечения равенства условий с первым поколением Core, но сохранятся ли замеченные закономерности в более близких к реальности условиям? Ведь из того, что четыре низкоскоростных потока вычислений не видят разницы между 6 и 8 МиБ кэш-памяти, не следует, что она не обнаружится в случае четырех высокоскоростных. Правда, не следует и обратного, так что для того, чтобы окончательно закрыть тему теоретических исследований, нам понадобится еще одна лабораторная работа, которой мы и займемся в следующий раз.