12

次のように定義された関数があります

inline void vec_add(__m512d &v3, const __m512d &v1, const __m512d &v2) {
    v3 = _mm512_add_pd(v1, v2);
}

(これ__m512dは、インテル MIC アーキテクチャーの SIMD レジスターへのネイティブ データ型マッピングです)

この関数はかなり短く、頻繁に呼び出されるため、呼び出しのたびにインライン化する必要があります。しかし、Intel のコンパイラは、オプション-inline-forceinline-O3オプションを使用した後でも、この関数をインライン化することに消極的です。コンパイル中に「Forceinline が呼び出されませんでした ...」と報告されます。タイプなど、コンパイラー固有の機能を使用する必要があるため__m512d、Intel コンパイラーが唯一の選択肢です。

より詳しい情報:

ファイル構造は非常に単純です。関数は、別のファイルに含まれるvec_addヘッダー ファイルで定義されます。関数はループ内で繰り返し呼び出されるだけで、関数ポインターは関係ありません。コードの簡略化されたバージョンは次のようになりますmic.htest.ccvec_addtest.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);
    }
}

構成

  • コンパイラ: インテル コンパイラ(ICC) 14.0.2
  • コンパイル オプション:-O3 -inline-forceinline -Winline

この関数をインライン化できない理由がわかりましたか? 結局、どうすればインライン化できますか(マクロにはなりたくありません)?

4

1 に答える 1

9

何らかの理由で、Intel Compiler はオフロードされたコードで関数のインライン化を行いません (私はこの概念にあまり詳しくないので、技術的な理由はわかりません)。詳細については、「intel-compilers-offload-features の効果的な使用」を参照してください (「インライン」で検索してください)。

リンクされた記事からの引用:

オフロード コンストラクトへの関数のインライン化

生成されたコードのパフォーマンスを最適化するために、関数のインライン化が必要になる場合があります。#pragma offload 内で直接呼び出される関数は 、 inline としてマークされていても、コンパイラによってインライン化されません。オフロード領域でコードの最適なパフォーマンスを有効にするには、手動で関数をインライン化するか、オフロード構造全体を独自の関数に配置します。

...

1 つの解決策は、関数 v2 に示すように、関数 f を手動でインライン化することです。

もう 1 つの解決策は、関数 v3 に示すように、オフロード コンストラクトを独自の関数に移動することです。

私がこれを正しく理解していれば、__attribute((target(mic))) でマークされた別の関数にループを配置するのが最善の方法です。

于 2014-05-15T13:02:16.280 に答える