インテル® 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 であると仮定されます。値が不明な場合またはエラーが発生した場合は負の値を返します。 |
この関数は、実行時にプロセッサー・グラフィックスへのオフロードが可能かどうかに基づいて、動的に最適なパフォーマンスを達成する方法を決定します。オフロード可能な場合、アプリケーションはプロセッサー・グラフィックス向けに最適化されたコードパスを選択することがあります。そうでない場合は 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);
}
...
}
この例は、__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;
}