Это может выглядеть немного странным, но мы все же решили в рамках небольшого ретро-эксперимента разобраться в особенностях эволюции таких древних процессоров, как Pentium 4. Микроархитектуры трех ранних поколений этого CPU обладают одним свойством, которое может показаться второстепенным, но кардинально влияет на производительность оперативной памяти. Речь пойдет о способности этих процессоров Intel продолжать опережающую выборку данных (другими словами — спекулятивную загрузку) в зависимости от контекста одного из «таинственных» механизмов кэширования.
Немного теории
Как известно, приложения используют линейный адрес, преобразование которого в физический адрес лежит в основе механизма виртуальной памяти. В целях повышения производительности дескрипторы страниц, обеспечивающие такое преобразование, кэшируются в буфере TLB. В соответствии с фундаментальными принципами кэш-памяти, обращение к странице, информация о которой отсутствует в TLB, определяется как TLB miss или TLB-промах и автоматически приводит к загрузке требуемого дескриптора из ОЗУ.
Напомним: доступ к памяти может быть связан не только с чтением и записью операндов в соответствии с логикой программы. Спекулятивная опережающая загрузка или prefetch может и должна нивелировать латентность путем заблаговременного чтения данных, доступ к которым не исключен в обозримом будущем.
Интрига, изучение которой «Компостер» начал больше года назад, состоит в реакции процессора на TLB-промах, произошедший в ходе спекулятивной загрузки. Именно здесь образовался простор для проявления implementation specific особенностей чипов различных моделей одного производителя. Давайте попробуем подтвердить экспериментами тезисы ранее опубликованной статьи.
Официальная позиция Intel
В документе, который сегодня вправе считаться антикварным, содержится формулировка, незаметно исчезнувшая из современных руководств.

Согласно документации Intel, процессоры Family 15=0Fh, model 0, 1, 2 игнорируют prefetch, если он приведет к TLB miss. Family 15=0Fh, model 3, обработает prefetch, даже если для этого придется загрузить новый элемент в TLB
Итак, у процессоров Prescott (это model=3), механизм опережающей загрузки продолжает работать, несмотря на TLB-промахи. Для Northwood и Willamette такие промахи останавливают спекулятивные операции. Процессор обновит TLB позднее, явно формируя обращение к операнду. При таком обращении получить результат можно будет только через некоторое количестве процессорных тактов — латентность оперативной памяти не будет «спрятана» и проявится в полной мере.
Переходим к экспериментам
Large Pages и DRAM Read Bandwidth
Начнем с достаточно удачной, с точки зрения обеспечения прочих равных условий, пары процессоров:
- P4 Prescott 2400 MHz = 133.3 x 18, L2=1MB
- P4 Northwood 2400 MHz = 133.3 x 18, L2=512KB
Разрабатывая сценарий эксперимента воспользуемся тем, что применение больших страниц значительно уменьшает количество TLB-промахов в пересчете на объем адресуемого диапазона, ибо увеличение размера страницы от 4KB до 4MB (для 32-битной платформы) пропорционально увеличивает объем памяти, связанный с одним элементом в TLB-буфере.
Для реализации опережающей загрузки тест использует специальные инструкции prefetch hints. Эксперимент поставлен на системной плате ASRock P4Dual-915GL. Информация о конфигурации тестовой платформы содержится в скриншотах AIDA64. Графики производительности построены с помощью утилиты NCRB [1].

Оценка влияния опции Large Pages на пропускную способность при линейном чтении оперативной памяти для процессоров Prescott (верхняя пара графиков) и Northwood (нижняя пара графиков)
Как и ожидалось, в данном сценарии у Prescott большие страницы практически не влияют на пропускную способность при чтении оперативной памяти, так как опережающая загрузка работает независимо от TLB-промахов — независимо от размера страниц выходим на производительность около 4.2 GBPS.
У Northwood влияние больших страниц ощутимо, поскольку каждый переход на следующую страницу может оказаться барьером для опережающего чтения, поэтому частота появления таких барьеров (через каждые 4KB или 4MB) имеет значение. В режиме Large Pages скорость чтения возросла с 3.2 GBPS до 3.8 GBPS.
Large Pages и L2 Cache Latency
Полученный выше результат не означает бесполезность больших страниц для Prescott. Убедимся в их значительном влиянии на латентность кэш-памяти второго уровня.

Оценка влияния опции Large Pages на латентность при псевдослучайном доступе к памяти для процессоров Prescott (верхняя пара графиков) и Northwood (нижняя пара графиков)
Оценка латентности выполнена в окрестности точек исчерпания L2 (1024KB для Prescott и 512KB для Northwood). Оба процессора располагают Data TLB объемом 64 элемента, каждый элемент TLB описывает одну страницу. В режиме стандартных 4KB страниц исчерпание TLB произойдет при X = 64 * 4KB = 256 KB. В режиме Large Pages исчерпание в рассмотренном измерительном сценарии не происходит, поскольку 64 * 4 MB = 256 MB и находится за пределами исследованного интервала.
NB: Тест латентности оперирует псевдослучайной последовательностью адресов. В качестве адреса для следующего обращения к памяти используются данные, прочитанные в текущем обращении по принципу связанного списка (linked list). Таким образом, данный тест намеренно лишает CPU возможности спекулятивно предсказать адрес следующего чтения памяти до завершения текущего и применить опережающую выборку данных.
Large Pages и Prefetch hints
Заметим, что при неоптимальной prefetch-дистанции, либо в режиме чтения без использования prefetch hints, влияние больших страниц, в том числе для процессоров Northwood/Willamette, может быть менее выражено. Это подтверждает эксперимент, поставленный на системной плате Intel D850 с RDRAM. Информация о конфигурации тестовой платформы содержится в скрин-шотах AIDA64.

Оценка влияния опции Large Pages на пропускную способность при линейном чтении оперативной памяти для процессоров Willamette с использованием prefetch (верхняя пара графиков) и на той же платформе, но без использования prefetch (нижняя пара графиков)
Как видно из сравнения верхней и нижней пары графиков, влияние опции Large Pages на скорость чтения оперативной памяти существенно зависит от наличия «намеков опережающей загрузки» или prefetch hints в измерительном сценарии.
Инструкции prefetch hints появились в составе функционального расширения SSE в процессоре Pentium III. Теоретически, их применение также возможно в коде, где загрузка данных выполняется не SSE инструкциями, поскольку prefetch hint и чтение из памяти — раздельные машинные команды.
На практике, измерительный сценарий, реализованный в NCRB, использует prefetch hints для SSE и AVX тестов, если целевым объектом является DRAM, а не кэш-память, и никогда не использует их в тестах, построенных на классических x86/x64 и MMX инструкциях. Для корректного моделирования работы Legacy кода подобные сочетания избегаются.
Выводы
Мы измерили влияние TLB-промахов на работу механизма опережающей загрузки в трех поколениях чипов Pentium 4. Критерием эффективности стала скорость чтения оперативной памяти. При прочих равных условиях (тактовые частоты ядра CPU, системной шины и DRAM соответственно равные 2.4 GHz, 133 MHz и 166 MHz) производительность Northwood составила от 3.2 до 3.8 GBPS, в зависимости от размера страницы памяти. Prescott показал устойчивый результат около 4.2 GBPS вне зависимости от размера страницы памяти.
Обратим внимание на одно из свойств Prescott — утилизацию пропускной способности системной шины, близкую к 100%. Величина 4.2 GBPS соответствует произведению эффективной частоты передачи информации 533.3MHz и разрядности шины данных в байтах 64 бита = 8 байт (не путать с архитектурной разрядностью процессора). Отдельный плюс — сохранение высокой производительности доступа к оперативной памяти в условиях переполнения TLB.
Итак, способность Prescott осуществлять опережающее чтение данных, несмотря на TLB-промахи получила экспериментальное подтверждение. Спекулятивность, в хорошем техническом смысле этого термина, стала тем одним словом, которым, на наш взгляд, можно охарактеризовать эволюционный период от Willamette до Prescott.
Ссылки
[1] NCRB — NUMA CPU and RAM Benchmark, v2.0