衡阳派盒市场营销有限公司

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

CUDA并行計算平臺的C/C++接口的簡單介紹

星星科技指導(dǎo)員 ? 來源:NVIDIA ? 作者:Mark Harris ? 2022-04-11 10:13 ? 次閱讀

本文是 CUDA C 和 C ++的一個系列,它是 CUDA 并行計算平臺的 C / C ++接口。本系列文章假定您熟悉 C 語言編程。我們將針對 Fortran 程序員運行一系列關(guān)于 CUDA Fortran 的文章。這兩個系列將介紹 CUDA 平臺上并行計算的基本概念。從這里起,除非我另有說明,我將用“ CUDA C ”作為“ CUDA C 和 C ++”的速記。 CUDA C 本質(zhì)上是 C / C ++,具有幾個擴展,允許使用并行的多個線程在 GPU 上執(zhí)行函數(shù)。

CUDA 編程模型基礎(chǔ)

在我們跳轉(zhuǎn)到 CUDA C 代碼之前, CUDA 新手將從 CUDA 編程模型的基本描述和使用的一些術(shù)語中受益。

CUDA 編程模型是一個異構(gòu)模型,其中使用了 CPU 和 GPU 。在 CUDA 中, host 指的是 CPU 及其存儲器, device 是指 GPU 及其存儲器。在主機上運行的代碼可以管理主機和設(shè)備上的內(nèi)存,還可以啟動在設(shè)備上執(zhí)行的函數(shù) kernels 。這些內(nèi)核由許多 GPU 線程并行執(zhí)行。

鑒于 CUDA 編程模型的異構(gòu)性, CUDA C 程序的典型操作序列是:

聲明并分配主機和設(shè)備內(nèi)存。

初始化主機數(shù)據(jù)。

將數(shù)據(jù)從主機傳輸?shù)皆O(shè)備。

執(zhí)行一個或多個內(nèi)核。

將結(jié)果從設(shè)備傳輸?shù)街鳈C。

記住這個操作序列,讓我們看一個 CUDA C 示例。

第一個 CUDA C 程序

在最近的一篇文章中,我演示了 薩克斯比的六種方法 ,其中包括一個 CUDA C 版本。 SAXPY 代表“單精度 A * X + Y ”,是并行計算的一個很好的“ hello world ”示例。在這篇文章中,我將剖析 CUDA C SAXPY 的一個更完整的版本,詳細(xì)解釋它的作用和原因。完整的 SAXPY 代碼是:

#include 

__global__
void saxpy(int n, float a, float *x, float *y)
{
 int i = blockIdx.x*blockDim.x + threadIdx.x;
 if (i < n) y[i] = a*x[i] + y[i];
}

int main(void)
{
  int N = 1<<20;
  float *x, *y, *d_x, *d_y;
  x = (float*)malloc(N*sizeof(float));
  y = (float*)malloc(N*sizeof(float));

  cudaMalloc(&d_x, N*sizeof(float));?
  cudaMalloc(&d_y, N*sizeof(float));

  for (int i = 0; i < N; i++) {
    x[i] = 1.0f;
    y[i] = 2.0f;
  }

  cudaMemcpy(d_x, x, N*sizeof(float), cudaMemcpyHostToDevice);
  cudaMemcpy(d_y, y, N*sizeof(float), cudaMemcpyHostToDevice);

  // Perform SAXPY on 1M elements
  saxpy<<<(N+255)/256, 256>>>(N, 2.0f, d_x, d_y);

  cudaMemcpy(y, d_y, N*sizeof(float), cudaMemcpyDeviceToHost);

  float maxError = 0.0f;
  for (int i = 0; i < N; i++)
    maxError = max(maxError, abs(y[i]-4.0f));
  printf("Max error: %f
", maxError);

  cudaFree(d_x);
  cudaFree(d_y);
  free(x);
  free(y);
}

函數(shù)saxpy是在 GPU 上并行運行的內(nèi)核,main函數(shù)是宿主代碼。讓我們從宿主代碼開始討論這個程序。

主機代碼

main 函數(shù)聲明兩對數(shù)組。

  float *x, *y, *d_x, *d_y;
  x = (float*)malloc(N*sizeof(float));
  y = (float*)malloc(N*sizeof(float));

  cudaMalloc(&d_x, N*sizeof(float));
  cudaMalloc(&d_y, N*sizeof(float));

指針x和y指向以典型方式使用malloc分配的主機陣列,d_x和d_y數(shù)組指向從CUDA運行時API使用cudaMalloc函數(shù)分配的設(shè)備數(shù)組。CUDA中的主機和設(shè)備有獨立的內(nèi)存空間,這兩個空間都可以從主機代碼進行管理(CUDAC內(nèi)核也可以在支持它的設(shè)備上分配設(shè)備內(nèi)存)。

然后,主機代碼初始化主機數(shù)組。在這里,我們設(shè)置了一個 1 數(shù)組,以及一個 2 數(shù)組。

  for (int i = 0; i < N; i++) {
    x[i] = 1.0f;
    y[i] = 2.0f;
  }

為了初始化設(shè)備數(shù)組,我們只需使用cudaMemcpy將數(shù)據(jù)從xy復(fù)制到相應(yīng)的設(shè)備數(shù)組d_xd_y,它的工作方式與標(biāo)準(zhǔn)的 Cmemcpy函數(shù)一樣,只是它采用了第四個參數(shù),指定了復(fù)制的方向。在本例中,我們使用cudaMemcpyHostToDevice指定第一個(目標(biāo))參數(shù)是設(shè)備指針,第二個(源)參數(shù)是主機指針。

  cudaMemcpy(d_x, x, N*sizeof(float), cudaMemcpyHostToDevice);
  cudaMemcpy(d_y, y, N*sizeof(float), cudaMemcpyHostToDevice);

在運行內(nèi)核之后,為了將結(jié)果返回到主機,我們使用cudaMemcpycudaMemcpyDeviceToHost,從d_y指向的設(shè)備數(shù)組復(fù)制到y指向的主機數(shù)組。

cudaMemcpy(y, d_y, N*sizeof(float), cudaMemcpyDeviceToHost);

啟動內(nèi)核

cord [EZX13 內(nèi)核由以下語句啟動:

saxpy<<<(N+255)/256, 256>>>(N, 2.0, d_x, d_y);

三個 V 形符號之間的信息是 執(zhí)行配置 ,它指示有多少設(shè)備線程并行執(zhí)行內(nèi)核。在 CUDA 中,軟件中有一個線程層次結(jié)構(gòu),它模仿線程處理器在 GPU 上的分組方式。在 CUDA 編程模型中,我們談到啟動一個 grid 為 螺紋塊 的內(nèi)核。執(zhí)行配置中的第一個參數(shù)指定網(wǎng)格中線程塊的數(shù)量,第二個參數(shù)指定線程塊中的線程數(shù)。

線程塊和網(wǎng)格可以通過為這些參數(shù)傳遞 dim3 (一個由 CUDA 用 x 、 y 和 z 成員定義的簡單結(jié)構(gòu))值來生成一維、二維或三維的線程塊和網(wǎng)格,但是對于這個簡單的示例,我們只需要一維,所以我們只傳遞整數(shù)。在本例中,我們使用包含 256 個線程的線程塊啟動內(nèi)核,并使用整數(shù)算術(shù)來確定處理數(shù)組( (N+255)/256 )的所有 N 元素所需的線程塊數(shù)。

對于數(shù)組中的元素數(shù)不能被線程塊大小平均整除的情況,內(nèi)核代碼必須檢查內(nèi)存訪問是否越界。

清理

完成后,我們應(yīng)該釋放所有分配的內(nèi)存。對于使用 cudaMalloc() 分配的設(shè)備內(nèi)存,只需調(diào)用 cudaFree() 。對于主機內(nèi)存,請像往常一樣使用 free() 。

cudaFree(d_x);
  cudaFree(d_y);
  free(x);
  free(y);

設(shè)備代碼

現(xiàn)在我們繼續(xù)討論內(nèi)核代碼。

__global__
void saxpy(int n, float a, float *x, float *y)
{
 int i = blockIdx.x*blockDim.x + threadIdx.x;
 if (i < n) y[i] = a*x[i] + y[i];
}

在 CUDA 中,我們使用 __global__ de __global__ 說明符定義諸如 Clara 這樣的內(nèi)核。設(shè)備代碼中定義的變量不需要指定為設(shè)備變量,因為假定它們駐留在設(shè)備上。在這種情況下, n 、 a 和 i 變量將由每個線程存儲在寄存器中,指針 x 和 y 必須是指向設(shè)備內(nèi)存地址空間的指針。這確實是真的,因為當(dāng)我們從宿主代碼啟動內(nèi)核時,我們將 d_x 和 d_y 傳遞給了內(nèi)核。但是,前兩個參數(shù) n 和 a 沒有在主機代碼中顯式傳輸?shù)皆O(shè)備。因為函數(shù)參數(shù)在 C / C ++中是默認(rèn)通過值傳遞的,所以 CUDA 運行時可以自動處理這些值到設(shè)備的傳輸。 CUDA 運行時 API 的這一特性使得在 GPU 上啟動內(nèi)核變得非常自然和簡單——這幾乎與調(diào)用 C 函數(shù)一樣。

在我們的 saxpy 內(nèi)核中只有兩行。如前所述,內(nèi)核由多個線程并行執(zhí)行。如果我們希望每個線程處理結(jié)果數(shù)組的一個元素,那么我們需要一種區(qū)分和標(biāo)識每個線程的方法。 CUDA 定義變量 blockDim 、 blockIdx 和 threadIdx 。這些預(yù)定義變量的類型為 dim3 ,類似于主機代碼中的執(zhí)行配置參數(shù)。預(yù)定義變量 blockDim 包含在內(nèi)核啟動的第二個執(zhí)行配置參數(shù)中指定的每個線程塊的維度。預(yù)定義變量 threadIdx 和 blockIdx 分別包含線程塊中線程的索引和網(wǎng)格中的線程塊的索引。表達(dá)式:

    int i = blockDim.x * blockIdx.x + threadIdx.x

生成用于訪問數(shù)組元素的全局索引。我們在這個例子中沒有使用它,但是還有一個 gridDim ,它包含在啟動的第一個執(zhí)行配置參數(shù)中指定的網(wǎng)格維度。

在使用該索引訪問數(shù)組元素之前,將根據(jù)元素的數(shù)量 n 檢查其值,以確保沒有越界內(nèi)存訪問。如果一個數(shù)組中的元素數(shù)不能被線程塊大小平均整除,并且結(jié)果內(nèi)核啟動的線程數(shù)大于數(shù)組大小,則需要進行此檢查。內(nèi)核的第二行執(zhí)行 SAXPY 的元素級工作,除了邊界檢查之外,它與 SAXPY 主機實現(xiàn)的內(nèi)部循環(huán)相同。

if (i < n) y[i] = a*x[i] + y[i];

編譯和運行代碼

CUDA C 編譯器 nvcc 是 NVIDIA CUDA 工具箱 的一部分。為了編譯我們的 SAXPY 示例,我們將代碼保存在一個擴展名為。 cu 的文件中,比如說 saxpy.cu 。然后我們可以用 nvcc 編譯它。

nvcc -o saxpy saxpy.cu

然后我們可以運行代碼:

% ./saxpy
Max error: 0.000000

總結(jié)與結(jié)論

通過對 SAXPY 的一個簡單的 CUDA C 實現(xiàn)的演練,您現(xiàn)在了解了編程 CUDA C 的基本知識。將 C 代碼“移植”到 CUDA C 只需要幾個 C 擴展:設(shè)備內(nèi)核函數(shù)的 __global__ de Clara 說明符;啟動內(nèi)核時使用的執(zhí)行配置;內(nèi)置的設(shè)備變量 blockDim 、 blockIdx 和 threadIdx 用來識別和區(qū)分并行執(zhí)行內(nèi)核的 GPU 線程。

異類 CUDA 編程模型的一個優(yōu)點是,將現(xiàn)有代碼從 C 移植到 CUDA C 可以逐步完成,一次只能移植一個內(nèi)核。

在本系列的下一篇文章中,我們將研究一些性能度量和度量。

關(guān)于作者

Mark Harris 是 NVIDIA 杰出的工程師,致力于 RAPIDS 。 Mark 擁有超過 20 年的 GPUs 軟件開發(fā)經(jīng)驗,從圖形和游戲到基于物理的模擬,到并行算法和高性能計算。當(dāng)他還是北卡羅來納大學(xué)的博士生時,他意識到了一種新生的趨勢,并為此創(chuàng)造了一個名字: GPGPU (圖形處理單元上的通用計算)。

審核編輯:郭婷

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報投訴
  • 存儲器
    +關(guān)注

    關(guān)注

    38

    文章

    7528

    瀏覽量

    164345
  • cpu
    cpu
    +關(guān)注

    關(guān)注

    68

    文章

    10904

    瀏覽量

    213023
  • gpu
    gpu
    +關(guān)注

    關(guān)注

    28

    文章

    4775

    瀏覽量

    129357
收藏 人收藏

    評論

    相關(guān)推薦

    xgboost的并行計算原理

    在大數(shù)據(jù)時代,機器學(xué)習(xí)算法需要處理的數(shù)據(jù)量日益增長。為了提高數(shù)據(jù)處理的效率,許多算法都開始支持并行計算。XGBoost作為一種高效的梯度提升樹算法,其并行計算能力是其受歡迎的原因
    的頭像 發(fā)表于 01-19 11:17 ?376次閱讀

    Spire.XLS for C++組件說明

    開發(fā)人員可以快速地在 C++ 平臺上完成對 Excel 的各種編程操作,如根據(jù)模板創(chuàng)建新的 Excel 文檔,編輯現(xiàn)有 Excel 文檔,以及對 Excel 文檔進行轉(zhuǎn)換。 Spire.XLS
    的頭像 發(fā)表于 01-14 09:40 ?145次閱讀
    Spire.XLS for <b class='flag-5'>C++</b>組件說明

    AKI跨語言調(diào)用庫神助攻C/C++代碼遷移至HarmonyOS NEXT

    量;某知名社交電商平臺使用后減少了50%以上跨語言調(diào)用接口代碼量;某圖像處理軟件所有C++代碼復(fù)用通過AKI來實現(xiàn)。使用AKI后這些項目不僅減少了項目代碼量,還顯著優(yōu)化了代碼復(fù)用與遷移流程。 目前
    發(fā)表于 01-02 17:08

    同樣是函數(shù),在CC++中有什么區(qū)別

    同樣是函數(shù),在 CC++ 中有什么區(qū)別? 第一個返回值。 C語言的函數(shù)可以不寫返回值類型,編譯器會默認(rèn)為返回 int。 但是 C++ 的函數(shù),除了構(gòu)造和析構(gòu)這兩個特殊的函數(shù),必須
    的頭像 發(fā)表于 11-29 10:25 ?429次閱讀

    C7000 C/C++優(yōu)化指南用戶手冊

    電子發(fā)燒友網(wǎng)站提供《C7000 C/C++優(yōu)化指南用戶手冊.pdf》資料免費下載
    發(fā)表于 11-09 15:00 ?0次下載
    <b class='flag-5'>C</b>7000 <b class='flag-5'>C</b>/<b class='flag-5'>C++</b>優(yōu)化指南用戶手冊

    TMS320C6000優(yōu)化C/C++編譯器v8.3.x

    電子發(fā)燒友網(wǎng)站提供《TMS320C6000優(yōu)化C/C++編譯器v8.3.x.pdf》資料免費下載
    發(fā)表于 11-01 09:35 ?0次下載
    TMS320<b class='flag-5'>C</b>6000優(yōu)化<b class='flag-5'>C</b>/<b class='flag-5'>C++</b>編譯器v8.3.x

    TMS320C28x優(yōu)化C/C++編譯器v22.6.0.LTS

    電子發(fā)燒友網(wǎng)站提供《TMS320C28x優(yōu)化C/C++編譯器v22.6.0.LTS.pdf》資料免費下載
    發(fā)表于 10-31 10:10 ?0次下載
    TMS320<b class='flag-5'>C</b>28x優(yōu)化<b class='flag-5'>C</b>/<b class='flag-5'>C++</b>編譯器v22.6.0.LTS

    C語言和C++中結(jié)構(gòu)體的區(qū)別

    同樣是結(jié)構(gòu)體,看看在C語言和C++中有什么區(qū)別?
    的頭像 發(fā)表于 10-30 15:11 ?356次閱讀

    C7000優(yōu)化C/C++編譯器

    電子發(fā)燒友網(wǎng)站提供《C7000優(yōu)化C/C++編譯器.pdf》資料免費下載
    發(fā)表于 10-30 09:45 ?0次下載
    <b class='flag-5'>C</b>7000優(yōu)化<b class='flag-5'>C</b>/<b class='flag-5'>C++</b>編譯器

    GPU加速計算平臺是什么

    GPU加速計算平臺,簡而言之,是利用圖形處理器(GPU)的強大并行計算能力來加速科學(xué)計算、數(shù)據(jù)分析、機器學(xué)習(xí)等復(fù)雜計算任務(wù)的軟硬件結(jié)合系統(tǒng)。
    的頭像 發(fā)表于 10-25 09:23 ?294次閱讀

    C++語言基礎(chǔ)知識

    電子發(fā)燒友網(wǎng)站提供《C++語言基礎(chǔ)知識.pdf》資料免費下載
    發(fā)表于 07-19 10:58 ?7次下載

    C++中實現(xiàn)類似instanceof的方法

    函數(shù),可實際上C++中沒有。但是別著急,其實C++中有兩種簡單的方法可以實現(xiàn)類似Java中的instanceof的功能。 在 C++ 中,確定對象的類型是編程中實際需求,使開發(fā)人員
    的頭像 發(fā)表于 07-18 10:16 ?673次閱讀
    <b class='flag-5'>C++</b>中實現(xiàn)類似instanceof的方法

    C/C++代碼動態(tài)測試工具VectorCAST插樁功能演示#代碼動態(tài)測試 #C++

    C++代碼
    北匯信息POLELINK
    發(fā)布于 :2024年04月18日 11:57:45

    鴻蒙OS開發(fā)實例:【Native C++

    使用DevEco Studio創(chuàng)建一個Native C++應(yīng)用。應(yīng)用采用Native C++模板,實現(xiàn)使用NAPI調(diào)用C標(biāo)準(zhǔn)庫的功能。使用C標(biāo)準(zhǔn)庫hypot
    的頭像 發(fā)表于 04-14 11:43 ?2765次閱讀
    鴻蒙OS開發(fā)實例:【Native <b class='flag-5'>C++</b>】

    使用 MISRA C++:2023? 避免基于范圍的 for 循環(huán)中的錯誤

    在前兩篇博客中,我們?向您介紹了新的 MISRA C++ 標(biāo)準(zhǔn)?和?C++ 的歷史?。在這篇博客中,我們將仔細(xì)研究以 C++ 中?for?循環(huán)為中心的特定規(guī)則。
    的頭像 發(fā)表于 03-28 13:53 ?861次閱讀
    使用 MISRA <b class='flag-5'>C++</b>:2023? 避免基于范圍的 for 循環(huán)中的錯誤
    水果机| 利好国际| 百家乐官网投注方法新版| 百家乐休闲游戏| 大发888网页版游戏| 赌场百家乐官网代理| 百家乐书籍| 吴川市| 赌博百家乐判断决策| 联兴棋牌| 百家乐赌博筹码| 百家乐官网有技巧么| 百家乐专用台布| 百家乐官网永利娱乐场开户注册 | 百家乐最佳公式| 杨公24山日课应验诀| 百家乐包赢| 百家乐谋略| 新宝百家乐官网网址| 开百家乐骗人吗| 百家乐官网的路子怎么| 南通热线棋牌中心| 免费百家乐官网统计软件| 巴塘县| 大发888娱乐场客户端下载| 百家乐蓝盾假网| 太阳城百家乐官网出千技术| 大发888客户端下载| 东京太阳城王子酒店| 太阳城百家乐优惠| 百家乐官网软件辅助器| 百加乐牌| 鼎龙娱乐城开户| 云鼎百家乐官网现金网| 大发888 娱乐平台| 网上百家乐如何打水| 百家乐官网薯片| 钟山县| 灌云县| 华克山庄娱乐| 海原县|