У меня есть функция, определенная как
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 не удостоен чести для вызова …» во время компиляции. Поскольку я должен использовать некоторые особенности компилятора, например, __m512d
типа, компилятор Intel мой единственный вариант.
Больше информации:
Структура файла довольно проста. Функция vec_add
определяется в заголовочном файле mic.h
, который включен в другой файл test.cc
, функция vec_add
просто вызывается повторно в цикле, и в нем не задействованы указатели функций. упрощенный версия кода в 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);
}
}
Конфигурации
-O3 -inline-forceinline -Winline
У вас есть идея, почему эта функция не может быть встроена?
И как мне все-таки встроить его (я не хочу обращаться к макросам)?
По какой-то причине Intel Compiler не выполняет встраивание функций в выгруженный код (я не очень знаком с этой концепцией, поэтому не знаю, какова техническая причина этого).
Увидеть эффективное использование-оф-Intel-компиляторы-разгрузка-функций для получения дополнительной информации (просто поиск «inline»).
Цитата из связанной статьи:
Встраивание функций в разгрузочные конструкции
Иногда включение функции необходимо для оптимального выполнения
сгенерированный код. Функции, вызываемые непосредственно в разгрузке #pragma
не указываются компилятором, даже если они помечены как встроенные. к
обеспечить оптимальную производительность кода в областях разгрузки, либо вручную
встроенные функции, или поместите всю конструкцию разгрузки в ее собственную
функция.…
Одним из решений является ручное включение функции f, как показано в функции
v2.Другое решение состоит в том, чтобы переместить конструкцию разгрузки в свою собственную
функция, как показано в функции v3.
Если я правильно понимаю, лучше всего было бы поместить циклы в отдельную функцию, также помеченную символом __attribute ((target (mic))).