你可以用加速器和accelerator_view類別指定要執行 C++ AMP 程式碼的裝置或模擬器。 系統可能有多個裝置或模擬器,分別在記憶體容量、共享記憶體支援、除錯支援或雙精度支援上有所不同。 C++ 加速大規模平行運算(C++ AMP)提供的 API 可讓您檢視可用的加速器、將其中一個設為預設加速器、為多次呼叫 parallel_for_each 指定多個 accelerator_views,以及進行特殊的偵錯任務。
備註
從 Visual Studio 2022 17.0 版開始,C++ AMP 標頭已被取代。
包含任何 AMP 標頭將會產生建置錯誤。 先定義 _SILENCE_AMP_DEPRECATION_WARNINGS ,再包含任何 AMP 標頭以讓警告消失。
使用預設加速器
C++ AMP 執行時會選擇預設的加速器,除非你寫程式碼選擇特定加速器。 執行時選擇預設加速器如下:
如果應用程式以除錯模式運行,則會有一個支援除錯的加速器。
否則,如果設定了環境變數,則使用由該環境變數指定的
CPPAMP_DEFAULT_ACCELERATOR加速器。否則,就用非模擬裝置。
否則,是擁有最多可用記憶體的裝置。
否則,就是未連接至顯示器的設備。
此外,執行時間會將access_type_auto指定為預設加速器的access_type。 這表示預設加速器若支援且其效能特性(頻寬與延遲)與專用(非共享)記憶體相同,則會使用共享記憶體。
你可以透過建構預設加速器並檢視其特性來判斷預設加速器的特性。 以下程式碼範例列印了預設加速器的路徑、加速器記憶體容量、共享記憶體支援、雙精度支援及有限雙精度支援。
void default_properties() {
accelerator default_acc;
std::wcout << default_acc.device_path << "\n";
std::wcout << default_acc.dedicated_memory << "\n";
std::wcout << (accs[i].supports_cpu_shared_memory ?
"CPU shared memory: true" : "CPU shared memory: false") << "\n";
std::wcout << (accs[i].supports_double_precision ?
"double precision: true" : "double precision: false") << "\n";
std::wcout << (accs[i].supports_limited_double_precision ?
"limited double precision: true" : "limited double precision: false") << "\n";
}
CPPAMP_DEFAULT_ACCELERATOR 環境變數
你可以設定CPPAMP_DEFAULT_ACCELERATOR環境變數來指定預設加速器的accelerator::device_path。 路徑依硬體而異。 以下程式碼使用函 accelerator::get_all 式取得可用加速器的清單,並顯示每個加速器的路徑與特性。
void list_all_accelerators()
{
std::vector<accelerator> accs = accelerator::get_all();
for (int i = 0; i <accs.size(); i++) {
std::wcout << accs[i].device_path << "\n";
std::wcout << accs[i].dedicated_memory << "\n";
std::wcout << (accs[i].supports_cpu_shared_memory ?
"CPU shared memory: true" : "CPU shared memory: false") << "\n";
std::wcout << (accs[i].supports_double_precision ?
"double precision: true" : "double precision: false") << "\n";
std::wcout << (accs[i].supports_limited_double_precision ?
"limited double precision: true" : "limited double precision: false") << "\n";
}
}
選擇加速器
要選擇加速器,請使用該 accelerator::get_all 方法取得可用加速器的清單,然後根據其特性選擇一個。 這個範例展示了如何選擇記憶體最多的加速器:
void pick_with_most_memory()
{
std::vector<accelerator> accs = accelerator::get_all();
accelerator acc_chosen = accs[0];
for (int i = 0; i <accs.size(); i++) {
if (accs[i].dedicated_memory> acc_chosen.dedicated_memory) {
acc_chosen = accs[i];
}
}
std::wcout << "The accelerator with the most memory is "
<< acc_chosen.device_path << "\n"
<< acc_chosen.dedicated_memory << ".\n";
}
備註
accelerator::get_all 回傳的加速器之一是 CPU 加速器。 你無法在 CPU 加速器上執行程式碼。 要篩選 CPU 加速器,請比較由accelerator::get_all返回的加速器之device_path屬性值與accelerator::cpu_accelerator的值。 欲了解更多資訊,請參閱本文中的「特殊加速器」章節。
共享記憶體
共享記憶體是指 CPU 與加速器都能存取的記憶體。 使用共享記憶體消除或大幅降低 CPU 與加速器之間複製資料的開銷。 雖然記憶體是共享的,但 CPU 與加速器無法同時存取,這會導致未定義的行為。 如果加速器支援共享記憶體,屬性 supports_cpu_shared_memory 會回傳true,且屬性 default_cpu_access_type 獲得配置在 的預設存取類型,例如與 相關的 accelerator,或在 array_view 上存取的 accelerator 物件。
C++ AMP 執行時會自動為每個 access_type選擇最佳預設accelerator值,但共享記憶體的效能特性(頻寬與延遲)在從 CPU 讀取、寫入或兩者同時執行時,可能比專用(非共享)加速記憶體差。 若共享記憶體在 CPU 讀寫上表現與專用記憶體同樣出色,則執行時會預設為 access_type_read_write; 否則,執行時會選擇較保守的預設 access_type,並且允許應用程式自行覆蓋預設,若其計算核心的記憶體存取模式從不同的 access_type 中獲益。
以下程式碼範例說明如何判斷預設的加速器是否支援共享記憶體,然後覆寫其預設的存取類型並從中建立一個 accelerator_view。
#include <amp.h>
#include <iostream>
using namespace Concurrency;
int main()
{
accelerator acc = accelerator(accelerator::default_accelerator);
// Early out if the default accelerator doesn't support shared memory.
if (!acc.supports_cpu_shared_memory)
{
std::cout << "The default accelerator does not support shared memory" << std::endl;
return 1;
}
// Override the default CPU access type.
acc.set_default_cpu_access_type(access_type_read_write);
// Create an accelerator_view from the default accelerator. The
// accelerator_view reflects the default_cpu_access_type of the
// accelerator it's associated with.
accelerator_view acc_v = acc.default_view;
}
accelerator_view 總是反映與其關聯的 default_cpu_access_typeaccelerator,且不提供介面來覆蓋或更改其 access_type。
更改預設加速器
你可以透過呼叫 accelerator::set_default 方法來更改預設加速器。 你每次執行應用程式只能更改一次預設加速器,且必須在執行任何程式碼前先更改。 任何用於改變加速器的後續函式呼叫回傳 false。 如果你想在呼叫 parallel_for_each中使用不同的加速器,請閱讀本文中的「使用多個加速器」章節。 以下程式碼範例將預設加速器設定為未模擬、未連接顯示器且支援雙精度的加速器。
bool pick_accelerator()
{
std::vector<accelerator> accs = accelerator::get_all();
accelerator chosen_one;
auto result = std::find_if(accs.begin(), accs.end(),
[] (const accelerator& acc) {
return !acc.is_emulated &&
acc.supports_double_precision &&
!acc.has_display;
});
if (result != accs.end()) {
chosen_one = *(result);
}
std::wcout <<chosen_one.description <<std::endl;
bool success = accelerator::set_default(chosen_one.device_path);
return success;
}
使用多重加速器
在應用程式中使用多個加速器有兩種方式:
你可以把物件傳
accelerator_view給 parallel_for_each 方法的呼叫。你可以使用特定物件來建立陣列物件。 C++ AMP 執行階段會從 lambda 運算式中取出
accelerator_view物件,這個物件是從已捕獲的 陣列 物件中來的。
特殊加速器
三種特殊加速器的裝置路徑可作為類別 accelerator 的特性提供:
accelerator::direct3d_ref 資料成員:此單執行緒加速器使用運行於 CPU 上的軟體來模擬一般顯示卡。 它預設用於除錯,但在生產環境中沒什麼用,因為它比硬體加速器慢。 此外,它僅在 DirectX SDK 和 Windows SDK 中提供,且不太可能安裝在你客戶的電腦上。 如需詳細資訊,請參閱 偵錯 GPU 程式代碼。
accelerator::direct3d_warp 資料成員:此加速器提供備援方案,用於使用串流 SIMD 擴充(SSE)的多核心 CPU 執行 C++ AMP 程式碼。
加速器::cpu_accelerator 資料成員:你可以用這個加速器來設定暫存陣列。 它無法執行 C++ AMP 程式碼。 欲了解更多資訊,請參閱 Parallel Programming in Native Code 部落格中關於 C++ AMP 的暫存陣列 文章。
Interoperability
C++ AMP 執行環境支援類別與 Direct3D accelerator_view之間的互通性。
create_accelerator_view 方法會接收介面IUnknown並回傳一個accelerator_view物件。
get_device 方法會接收一個accelerator_view物件並回傳一個IUnknown介面。