Как оптимизировать приложения для AMD?

12 Авг 2016

Как оптимизировать приложения для AMD?

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

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

 

Бенчмарки оперативной памяти являются типовым примером обработки non-temporal данных, так как имеет место непрерывная передача блоков, размер которых в разы превышает размер кэш-памяти. В этом случае мы намеренно нивелируем эффект кэширования данных (но не инструкций!) для создания максимальной нагрузки на шину DRAM. Иначе, вместо ОЗУ будет протестирована кэш-память. Позитивный эффект некэшируемой записи (non-temporal store) уже был исследован тестовой лабораторией «Компостера».

Практические результаты

В ходе оптимизации бенчмарок оперативной памяти для процессоров AMD, возникла необходимость поддержки некэшируемого чтения (non-temporal load). Замена обычной загрузки (инструкция MOVAPD) некэшируемой загрузкой (инструкция MOVNTDQA) дает устойчивый выигрыш около 400 мегабайт в секунду. Рассмотрим результаты отладки тестового примера в среде FASM Editor. Размер читаемого блока 1 гигабайт, запускается 4 потока, в соответствии с количеством ядер исследуемого процессора.

Обычное чтение, инструкция MOVAPD, пропускная способность DRAM около 10.5 Гигабайт в секунду
Рис.1 Обычное чтение, инструкция MOVAPD,
пропускная способность
DRAM около 10.5 Гигабайт в секунду

Некэшируемое чтение, инструкция MOVNTDQA, пропускная способность DRAM около 10.9 Гигабайт в секунду
Рис.2 Некэшируемое чтение, инструкция MOVNTDQA,
пропускная способность
DRAM около 10.9 Гигабайт в секунду

Маленькие хитрости

Помимо применения non-temporal load для операции чтения оперативной памяти, акцентируем внимание на двух дополнительных особенностях дизайна высокопроизводительного и компактного кода, особенно значимых для процессоров AMD.

  1. В ситуациях, когда достаточно восьми регистров XMM, следует использовать младшие 8 регистров XMM0-XMM7, поскольку для ряда инструкций, адресация 8 старших регистров XMM8-XMM15 приводит к увеличению размера инструкции на 1 префиксный байт.
  2. Вместо применения только положительных смещений относительно базы, указывающей на начало некоторого блока данных, мы задаем положительные и отрицательные смещения относительно базы, указывающей на середину блока. Поскольку для кодирования адресных смещений в инструкциях применяется знаковое расширение, то все смещения, находящиеся в диапазоне -128...+127 представимы одним байтом, в отличие от набора смещений в диапазоне 0...255, часть которых не представима одним байтом. В режимах Protected Mode 32/64, смещение, не поместившееся в один байт, кодируется 32-битным операндом, размер инструкции возрастет сразу на 4 байта.

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

Исследование кодирования инструкций, цикл чтения памяти в отладчике FDBG: перед исследуемым фрагментом установлена точка останова, инструкция программного прерывания INT3
Рис.3 Исследование кодирования инструкций, цикл чтения памяти в отладчике FDBG: перед исследуемым фрагментом установлена точка останова, инструкция программного прерывания INT3

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

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

Процессор AMD Athlon(tm) X4 880K Quad Core Processor. Установлен один модуль памяти PC3-12800, одноканальный режим, теоретический максимум пропускной способности около 12.8 Гигабайт в секунду. Моделируем бюджетную систему.

Особенности совместимости

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

Инструкции некэшируемого чтения MOVNTDQA/VMOVNTDQA вносят очередную нерегулярность в архитектуру векторных расширений системы команд процессора. 256-битная форма поддерживается только в рамках расширения AVX2, 128-битные формы поддерживаются в рамках SSE4.1 и AVX.

Описание инструкции MOVNTDQA/VMOVNTDQA в документации AMD
Рис.4 Описание инструкции MOVNTDQA/VMOVNTDQA в документации AMD

Описание инструкции MOVNTDQA/VMOVNTDQA в документации Intel
Рис.5 Описание инструкции MOVNTDQA/VMOVNTDQA в документации Intel

Примечательно, что для протестированного процессора, в ряде случаев, 128-битные операции SSE предпочтительнее 256-битных операций AVX, поскольку используется 128-битный вычислительный тракт, выполняющий 256-битную операцию за два 128-битных цикла. Напомним и о том, что кэш-память инструкций первого уровня (L1 instruction cache) и блок вычислений с плавающей точкой (FPU) являются ресурсами, общими в пределах пары ядер.

Выводы

Грамотный учет особенностей архитектуры и внутренней топологии взаимодействия ресурсов позволит «выжать максимум» даже из бюджетных конфигураций аппаратного обеспечения. Вместе с тем, тщательная оптимизация кода на уровне ассемблера, не является трендом в современной софт-индустрии. Присутствующие в документа­ции обоих процессорных гигантов предупреждения относительно implementation-dependent реализации некэши­ру­емой загрузки, многое объясняют в сложившемся положении дел…

Теги: