Невозможно принудительно включить функцию С++ с помощью компилятора Intel
У меня есть функция, определенная как
inline void vec_add(__m512d &v3, const __m512d &v1, const __m512d &v2) {
v3 = _mm512_add_pd(v1, v2);
}
(__m512d
- это собственное сопоставление типа данных для регистров SIMD в архитектуре Intel MIC)
Поскольку эта функция довольно короткая и часто вызывается, я бы хотел, чтобы она была встроена при каждом вызове. Но компилятор Intel, похоже, неохотно встраивает эту функцию даже после использования опций -inline-forceinline
и -O3
. В нем сообщается, что "Forceinline not honored for call..." при компиляции. Поскольку я должен использовать некоторые специфичные для компилятора функции, например. тип __m512d
, компилятор Intel - мой единственный вариант.
Дополнительная информация:
Структура файла довольно проста. Функция vec_add
определяется в заголовочном файле mic.h
, который включен в другой файл test.cc
. Функция vec_add
просто вызывается повторно в цикле, и в ней нет указателей на функции. A упрощенная версия кода в test.cc
выглядит так:
for (int i = 0; i < LENGTH; i += 8) {
// a, b, c are arrays of doubles, and each SIMD register can hold 8 doubles
__mm512d va = _mm512_load_pd(a + i); // load SIMD register from memory
__mm512d vb = _mm512_load_pd(b + i); // ditto
__mm512d vc;
vec_add(vc, va, vb); // store SIMD register to memory
_mm512_store_pd(c + i, vc);
}
Я пробовал всевозможные подсказки, такие как __attribute__((always_inline))
, __forceinline
и параметр компилятора -inline-forceinline
, ни один из которых не работал.
Полный код
Я собрал весь соответствующий код в упрощенной форме. Вы можете попробовать, если у вас есть компилятор Intel. Используйте опцию -Winline
для просмотра встроенных отчетов и -inline-forceinline
для принудительной вставки.
#include <stdio.h>
#include <stdlib.h>
#include <immintrin.h>
#define LEN (1<<20)
__attribute((target(mic)))
inline void vec_add(__m512d &v3, const __m512d &v1, const __m512d &v2) {
v3 = _mm512_add_pd(v1, v2);
}
int main() {
#pragma offload target(mic)
{
double *a = (double*)_mm_malloc(LEN*sizeof(double), 64);
double *b = (double*)_mm_malloc(LEN*sizeof(double), 64);
double *c = (double*)_mm_malloc(LEN*sizeof(double), 64);
for (int i = 0; i < LEN; i++) {
a[i] = (double)rand()/RAND_MAX;
b[i] = (double)rand()/RAND_MAX;
}
for (int i = 0; i < LEN; i += 8) {
__m512d va = _mm512_load_pd(a + i);
__m512d vb = _mm512_load_pd(b + i);
__m512d vc;
vec_add(vc, va, vb);
_mm512_store_pd(c + i, vc);
}
_mm_free(a);
_mm_free(b);
_mm_free(c);
}
}
Конфигурация
- Компилятор: компилятор Intel (ICC) 14.0.2
- Параметры компиляции:
-O3 -inline-forceinline -Winline
У вас есть идея, почему эта функция не может быть встроена?
И как я могу получить его inlined в конце концов (я не хочу обращаться к макросам)?
Ответы
Ответ 1
По какой-то причине Intel Compiler не выполняет функции функций в выгруженном коде (я не так хорошо знаком с этой концепцией, поэтому не знаю, какая техническая причина для этого).
См. effective-use-of-the-intel-compilers-offload-features для получения дополнительной информации (просто найдите "встроенный" ).
Цитата из связанной статьи:
Функция Встраивание в конструкцию выгрузки
Иногда для обеспечения максимальной производительности сгенерированный код. Функции, вызываемые непосредственно внутри разгрузки #pragma не встроены компилятором, даже если они отмечены как встроенные. к обеспечить оптимальную производительность кода в регионах разгрузки, либо вручную встроенные функции, или поместить всю конструкцию разгрузки в ее собственную функция.
...
Одним из решений является функция inline вручную, как показано в функции v2.
Другое решение - переместить конструкцию разгрузки в ее собственную как показано в функции v3.
Если я правильно понимаю это, лучше всего сделать для вас петли в отдельную функцию, которая также отмечена __attribute ((target (mic))).