インテル® C++ コンパイラー 18.0 デベロッパー・ガイドおよびリファレンス

デバイスクエリー関数

プロセッサー・グラフィックス固有のさまざまな特定を照会します。このトピックは、インテル® グラフィックス・テクノロジーをターゲットとする場合にのみ適用されます。

構文

GfxGpuPlatform _GFX_get_device_platform(void);

GfxGpuSKU _GFX_get_device_sku(void);

int _GFX_get_device_hardware_thread_count(void);

int _GFX_get_device_min_frequency(void);

int _GFX_get_device_max_frequency(void);

int _GFX_get_device_current_frequency(void);

int _GFX_get_number_of_devices(void);

int _GFX_get_device_subslice_thread_count(void);

パラメーター

なし。

説明

これらの関数は、使用しているプロセッサー・グラフィックスのさまざまな特定を取得します。

次の表は、各関数で取得可能な情報を示します。

関数

説明

_GFX_get_device_platform

プロセッサー・グラフィックスの種類を取得します。

_GFX_get_device_sku

プロセッサー・グラフィックスのプラットフォーム (SKU) を取得します。

_GFX_get_device_hardware_thread_count

プロセッサー・グラフィックスで並列に実行可能な最大スレッド数を取得します。

_GFX_get_device_min_frequency

プロセッサー・グラフィックスの最小周波数を取得します。

_GFX_get_device_max_frequency

プロセッサー・グラフィックスの最大周波数を取得します。

_GFX_get_device_current_frequency

プロセッサー・グラフィックスの現在の周波数を取得します。

_GFX_get_number_of_devices

オフロードに利用可能なシステム内のプロセッサー・グラフィックス・ユニット数を取得します。

この関数を使用して、オフロード可能なプロセッサー・グラフィックスの有無に依存するコードを記述できます。

_GFX_get_device_subslice_thread_count

利用可能なインテル® プロセッサー・グラフィックス・ユニットのサブスライスごとのハードウェア・スレッド数を取得します。

この関数は、カーネル (__declspec(target(gfx_kernel)) が指定されている関数) で使用される __thread_group_local 変数の合計サイズを計算する際に役立ちます。__thread_group_local 変数の合計サイズに応じて、最小スレッド・グループ・サイズを計算する例を後述します。この値を超えると、実行時に共有ローカル・メモリー (SLM) オーバーフロー・エラーになります。

戻り値

_GFX_get_device_platform

0 - 不明

1 - SNB

2 - IVB

3 - HSW

4 - BDW

5-VLV

6 - CHV

7 - SKL

8 - BXT

_GFX_get_device_sku

0 - 不明

1- GT1

2-GT2

3-GT3

4 - GT4

5-GTVLV

6-GTVLVPLUS

7-GTCHV

10 - GT1_5

_GFX_get_device_hardware_thread_count

整数。プロセッサー・グラフィックスで並列に実行可能な最大スレッド数。

_GFX_get_device_min_frequency

整数。プロセッサー・グラフィックスの最小周波数 (MHz)。

_GFX_get_device_max_frequency

整数。プロセッサー・グラフィックスの最大周波数 (MHz)。

_GFX_get_device_current_frequency

整数。プロセッサー・グラフィックスの現在の周波数 (MHz)。

_GFX_get_number_of_devices

整数。オフロードに利用可能なインテル® プロセッサー・グラフィックス・ユニット数。利用可能なデバイスがない場合は 0 を返します。

_GFX_get_device_subslice_thread_count

整数。インテル® プロセッサー・グラフィックス・ユニットのサブスライスごとのハードウェア・スレッド数。複数のユニットが利用可能な場合、それらは同じ SKU であると仮定されます。値が不明な場合またはエラーが発生した場合は負の値を返します。

例: _GFX_get_number_of_devices

この関数は、実行時にプロセッサー・グラフィックスへのオフロードが可能かどうかに基づいて、動的に最適なパフォーマンスを達成する方法を決定します。オフロード可能な場合、アプリケーションはプロセッサー・グラフィックス向けに最適化されたコードパスを選択することがあります。そうでない場合は CPU で実行します。

インテル® Cilk™ Plus は、インテル® C++ コンパイラー 18.0 では非推奨の古い機能です。プロセッサー・グラフィックスへオフロードする代替手段は、将来のリリースで提供される予定です。詳細は、「インテル® Cilk™ Plus の代わりに OpenMP* またはインテル® TBB を使用するためのアプリケーションの移行」を参照してください。

// プロセッサー・ブラフィックス向けに最適化されたカーネル
__declspec(target(gfx_kernel))
void gfx_kernel(float *out, const float *in, int len);

// CPU 向けに最適化されたカーネル
void cpu_kernel(float *out, const float *in, int len);

void run_kernel(float *out, const float *in, int len)
{
    ...

    // 利用可能な場合はプロセッサー・グラフィックス向けのカーネルを実行
    // そうでない場合は CPU 向けのカーネルを実行
    if (_GFX_get_number_of_devices() > 0) {
        // GPU カーネルをキューに追加
        _GFX_share(in, sizeof(float) *len);
        _GFX_share(out, sizeof(float) *len);
        _GFX_offload(gfx_kernel, out, in, len);
        if (_GFX_get_last_error() != GFX_SUCCESS) {
            fatal_error();
        }
    }
    else {
        // カーネルの CPU バージョンをスポーン
        _Cilk_spawn cpu_kernel(out, in, len);
    }

    ...
}

例: _GFX_get_device_subslice_thread_count

この例は、__thead_group_local 変数を使用して、実行時に共有ローカル・メモリー・オーバーフローを引き起こすことなく、スレッドグループのスレッド数を計算する方法を示します。計算結果は、カーネルが使用している __thead_group_local メモリー空間のサイズに依存します。__thead_group_local メモリーはグループ内のスレッドで共有され、SLM に割り当てられるため、各スレッドグループはこの量の SLM を使用します。実際、スレッドグループへの SLM 割り当ては、2 の累乗に 1024 を掛けたチャンク (1024、2048、...) で行われます。以下のサンプルコードは、この点を考慮しています。

// コンパイラーによりスレッドグループごとに SLM メモリーの (int バイト) が予約される
const int c_slm_scratch_frame_size = 16;

// サブスライスごとの SLM サイズに関するハードウェアの制約
const int c_max_slm_per_ss = 1024*64;

// スレッド・グループ・サイズに関するハードウェアの制約
const int c_max_group_size = 64;


// SLM フレームサイズをハードウェアでサポートされる値にアライメントする:
int align_slm_frame_size(int slm_frame_size)
{
    const int block_size = 1024;
    const int max_slm = c_max_slm_per_ss;

    if (slm_frame_size >= max_slm || slm_frame_size <= 0) {
        return slm_frame_size;
    }
    int aligned_size = block_size;

    for (; slm_frame_size > aligned_size; aligned_size *= 2) {}

    return aligned_size;
}

int get_min_thread_group_size(int slm_per_group)
{
    slm_per_group = align_slm_frame_size(slm_per_group);
    int threads_per_ss = _GFX_get_device_subslice_thread_count();

    if (threads_per_ss <= 0) {
        printf("_GFX_get_device_subslice_thread_count failed\n");
        exit(-1);
    }
    int max_groups = std::max(1, c_max_slm_per_ss/slm_per_group);
    int group_size = std::min(c_max_group_size, (int)std::ceil((float)threads_per_ss/max_groups));

    return group_size;
}