Нижегородский государственный университет им. Н.И.Лобачевского
Опубликован: 02.06.2014 | Доступ: свободный | Студентов: 183 / 28 | Длительность: 04:58:00

Лекция 1: Элементы оптимизации прикладных программ для Intel Xeon Phi: Intel MKL, Intel VTune Amplifier XE

Лекция 1: 12345 || Лекция 2 >

Метрики для оценки эффективности приложений на Intel Xeon Phi

В данном разделе приведено описание основных метрик для оценки эффективности приложений на Intel Xeon Phi c помощью Intel VTune Amplifier XE. Приведенные здесь метрики и рекомендации по оптимизации кода актуальны и для CPU, однако конкретные значения этих метрик приводятся только для сопроцессоров Intel Xeon Phi.

Количество тактов на инструкцию (cycles per instruction, CPI).

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

Данная метрика может вычисляться относительно аппаратного потока либо относительно ядра процессора. Чем меньше этот показатель, тем лучше работает приложение. Для сопроцессоров Intel Xeon Phi минимальные значения этого показателя приведены в таблице 6.1.

Таблица 1.1. Минимальные теоритические показатели CPI на ядро и на поток для сопроцессоров Intel Xeon Phi
Число аппаратных потоков на ядро Минимальный (лучший) показатель CPI на ядро Минимальный (лучший) показатель CPI на поток
1 1.0 1.0
2 0.5 1.0
3 0.5 1.5
4 0.5 2.0

Для вычисления описанных выше характеристик Intel VTune Amplifier XE использует события CPU_CLK_UNHALTED и INSTRUCTIONS_EXECUTED. В частности:

  • CPI Per Thread = CPU_CLK_UNHALTED / INSTRUCTIONS_EXECUTED
  • CPI Per Core = (CPI Per Thread) / (Число используемых аппаратных потоков)

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

  • CPI Per Thread <= 4.0;
  • CPI Per Core <= 1.0.

Если одна из характеристик больше соответствующего значения – это повод задуматься о дополнительной оптимизации. Причем большие значения CPI следует расценивать как повод к уменьшению латентности доступа к памяти.

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

Объем вычислений на единицу данных (compute to data access ratio).

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

Выделяют два типа этой метрики:

  • L1 Compute to Data Access Ratio – используется для оценки того, насколько ваше приложение подходит для переноса на Intel Xeon Phi. Для того чтобы программа могла эффективно выполняться на сопроцессоре, она должна быть векторизованной, и в идеале выполнять несколько операций с одними и теми же данными (или линейками кэша). Данная метрика вычисляет среднее число векторных операций, приходящихся на один доступ к L1 кэшу.
  • L2 Compute to Data Access Ratio – показывает среднее число векторных операций, приходящихся на один доступ к L2 кэшу.

Для вычисления этих метрик используются следующие события:

  • VPU_ELEMENTS_ACTIVE – число векторных операций на поток;
  • DATA_READ_OR_WRITE – число операций чтения и записи в L1 кэш данных на поток;
  • DATA_READ_MISS_OR_WRITE_MISS – число L1 кэш промахов при чтении и записи на поток.

Описанные выше метрики вычисляются по формулам:

  • L1 Compute to Data Access Ratio = VPU_ELEMENTS_ACTIVE / DATA_READ_OR_WRITE;
  • L2 Compute to Data Access Ratio = VPU_ELEMENTS_ACTIVE / DATA_READ_MISS_OR_WRITE_MISS.

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

  • L1 Compute to Data Access Ratio < показателя интенсивности векторизации (см. Векторизация);
  • L2 Compute to Data Access Ratio < 100 * (L1 Compute to Data Access Ratio) .

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

Латентность доступа к памяти.

Высокая латентность доступа к данным существенно снижает эффективность приложения. Для оценки влияния этого фактора рекомендуется использовать следующую метрику:

Оценка влияния латентности (Estimated Latency Impact) = (CPU_CLK_UNHALTED – EXEC_STAGE_CYCLES – DATA_READ_OR_WRITE) / DATA_READ_OR_WRITE_MISS.

Здесь EXEC_STAGE_CYCLES – число тактов процессора, на которых поток выполнял вычислительные операции. Остальные события описаны выше.

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

Использование TLB кэша.

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

Для оценки эффективности доступа в TLB кэш используются следующие показатели:

  • L1 TLB miss ratio = DATA_PAGE_WALK / DATA_READ_OR_WRITE
  • L2 TLB miss ratio = LONG_DATA_PAGE_WALK / DATA_READ_OR_WRITE
  • L1 TLB misses per L2 TLB miss = DATA_PAGE_WALK / LONG_DATA_PAGE_WALK

Здесь DATA_PAGE_WALK – число промахов L1 TLB кэша, а LONG_DATA_PAGE_WALK – число промахов L2 TLB кэша.

Необходимость в оптимизации здесь появляется, если:

  • L1 TLB miss ratio > 1%;
  • L2 TLB miss ratio > 0.1%;
  • L1 TLB misses per L2 TLB miss > 1.

Для улучшения ситуации следует обратить внимание на эффективность использования кэша и уменьшать латентность доступа к памяти.

Если отношение (L1 TLB miss / L2 TLB miss) достаточно велико, можно попробовать использовать страницы TLB кэша большего размера.

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

Векторизация.

Рассмотрим такую метрику, как интенсивность векторизации. Она показывает, насколько эффективно векторизован ваш код:

Интенсивность векторизации (vectorization intensity) = VPU_ELEMENTS_ACTIVE / VPU_INSTRUCTIONS_EXECUTED.

Здесь VPU_INSTRUCTIONS_EXECUTED – число векторных инструкций, выполняемых потоком, VPU_ELEMENTS_ACTIVE – число активных векторных элементов на векторную инструкцию, или, другими словами, число векторных операций (за одну векторную инструкцию может выполняться несколько операций).

Оптимизировать нужно, если этот параметр меньше 8 при использовании чисел двойной точности и меньше 16 при использовании чисел одинарной точности.

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

Для подсказки компилятору используйте директивы #pragma ivdep, #pragma simd и др. Для ручной векторизации используйте возможности технологии Intel Cilk Plus.

Следите за выравниванием данных при векторизации.

Пропуская способность памяти.

Величина показателя пропускной способности памяти вычисляется следующим образом:

  • Read bandwidth = (L2_DATA_READ_MISS_MEM_FILL + L2_DATA_WRITE_MISS_MEM_FILL + HWP_L2MISS) * 64 / CPU_CLK_UNHALTED
  • Write bandwidth = L2_VICTIM_REQ_WITH_DATA + SNP_HITM_L2) * 64 / CPU_CLK_UNHALTED
  • Memory Bandwidth = (Read bandwidth + Write bandwidth) * (Частота процессора в ГГц).

Здесь:

  • L2_DATA_READ_MISS_MEM_FILL – число операций чтения, приводящих к обращению к оперативной памяти, включая операции предвыборки;
  • L2_DATA_WRITE_MISS_MEM_FILL – число операций записи, приводящих к обращению к оперативной памяти на чтение, включая операции предвыборки;
  • L2_VICTIM_REQ_WITH_DATA – число замещений данных, приводящих к обращению к оперативной памяти на запись;
  • HWP_L2MISS – число аппаратных предвыборок, которые привели к L2 кэш промаху;
  • SNP_HITM_L2 – число событий возникающих в случае, когда данные, измененные в кэше одного ядра, нужны другому ядру;
  • CPU_CLK_UNHALTED – число тактов процессора.

Если эта величина < 80 GB/сек (практический максимум для 8 контроллеров памяти равен 140 GB/сек), тогда имеет смысл выполнять соответствующую оптимизацию.

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

Подробнее об этих метриках и приемах оптимизации приложений для Intel Xeon Phi можно узнать здесь [1.4,1.5].

Лекция 1: 12345 || Лекция 2 >