Компилятор Intel генерирует следующую инструкцию предварительной выборки в цикле для доступа к массиву a_ptr
указатель:
400e93: 62 d1 78 08 18 4c 24 vprefetch0 [r12+0x80]
Если я вручную изменю (путем шестнадцатеричного редактирования исполняемого файла) это на временную предварительную выборку:
400e93: 62 d1 78 08 18 44 24 vprefetchnta [r12+0x80]
цикл работает почти в 1,5 раза быстрее (!!!). Однако я бы предпочел, чтобы компилятор генерировал для меня временную предварительную выборку. я думал так
#pragma prefetch a_ptr:_MM_HINT_NTA
до цикла должен сделать трюк, но на самом деле это не так; он генерирует те же самые инструкции, что и без прагмы. Зачем icpc
игнорирует эту прагму? Как я могу заставить его генерировать невременное предварительное обучение?
Оптик Отчет не говорит ничего полезного, насколько я вижу:
LOOP BEGIN at test-mic.cpp(56,5)
remark #15344: loop was not vectorized: vector dependence prevents vectorization
remark #15346: vector dependence: assumed ANTI dependence between b_ptr line 64 and b_ptr line 65
remark #15346: vector dependence: assumed FLOW dependence between b_ptr line 65 and b_ptr line 64
remark #25018: Total number of lines prefetched=2
remark #25019: Number of spatial prefetches=2, dist=29
remark #25021: Number of initial-value prefetches=2
remark #25139: Using second-level distance 2 for prefetching spatial memory reference [ test-mic.cpp(61,50) ]
remark #25015: Estimate of max trip count of loop=1048576
LOOP END
Это известная проблема — BKM должен использовать явные значения 0,1,2,3 для подсказок (t0, t1, t2, nta) в директивах / прагмах предварительной выборки (и НЕ использовать перечисление MM_HINT).
Это потому, что перечисление MM_HINT в файлах заголовка отображается по-разному:
/* constants to use with _mm_prefetch (extracted from *mmintrin.h) */
#define _MM_HINT_T0 1
#define _MM_HINT_T1 2
#define _MM_HINT_T2 3
#define _MM_HINT_NTA 0 <--maps here
#define _MM_HINT_ENTA 4
#define _MM_HINT_ET0 5
#define _MM_HINT_ET1 6
#define _MM_HINT_ET2 7
Кроме того, заголовки Intel и gcc используют разные значения enum — это тоже хлопотно. Таким образом, подсказка —enums должна использоваться только для встроенных функций _mm_prefetch, а НЕ для директив prefetch.
Для этого примера вы должны использовать: #pragma prefetch a_ptr: 3
Тем не менее, этот предлагаемый синтаксис в настоящее время не может использоваться из-за дефекта, когда компилятор в настоящее время не может правильно соединить загрузочную память-ref a_ptr внутри цикла с выражением в директиве prefetch; поэтому временным решением является использование следующего синтаксиса:
#pragma prefetch *: 3
Заметка: Звездочка означает, что директива будет применяться к «ВСЕМ» ссылкам памяти внутри цикла. В этом цикле b_ptr не может быть предварительно выбран компилятором, так как он не является выражением линейного адреса. Так что «*» в любом случае применяется только к a_ptr — и приводит к vprefetchnta (как на KNC, так и на KNL).
Дефект будет исправлен в следующем выпуске.
Других решений пока нет …