CUDA GPU程式設計中使用結構體傳遞函式引數

2021-07-22 22:42:00 字數 3045 閱讀 5449

cuda gpu程式設計中,雖然統一定址(unified memory)技術能夠大大簡化程式設計難度和**複雜度,但是速度略有犧牲,同時對執行環境提出更多的要求。而在不使用這項技術時,程式設計時需要同時建立cpu(host)和gpu(device)端的變數指標,然後為其分別分配記憶體。操作完成後,再分別釋放記憶體。cuda工程的範例程式中,單獨編寫了__global__函式,並將其和裝置記憶體的建立,使用和釋放包裝在了乙個函式裡面,最終將這個包裝後的函式提供給使用者。使用者只需管理自己的cpu記憶體,以及簡單地呼叫該封裝函式即可實現gpu加速。

但實際處理過程中,由於資料量大或者希望使用cuda流來實現cpu和gpu並行,從而最大限度提高執行效率,由於記憶體的建立和釋放效率極低,上訴方式並不可取。而是在程式開始建立變數指標並分配記憶體,隨後對該記憶體進行多次使用,在程式執行結束時再釋放資源。這樣之前的乙個封裝函式顯然不夠用,現在需要使用者自己建立各項主機和裝置端記憶體指標,然後分別提供相應封裝函式以實現記憶體的建立、核心的gpu平行計算**、記憶體釋放若干操作。應用程式往往需要使用若干資料,而分別要在主機和裝置端建立乙個指標,因此造成函式引數數量過多的問題,我的一些程式中經常超過20個引數,這對程式的呼叫和管理造成極大的不便。

為了解決這個問題,考慮把相關必要的引數封裝在乙個結構體裡面,通過該結構體的指標進行傳輸傳遞,而封裝函式通過該結構體獲取必要的資料,從而函式的引數大大降低。而進一步,把結構體內部指標變數對應的記憶體建立、釋放封裝起來,使用者只需要建立相應的結構體再呼叫這些封裝函式即可,對**的易用性和易維護性均有很大的提公升。

下面首先提供乙個範例,這是根據cuda工程建立的範例進行的修改。

#include "cuda_runtime.h"

#include "device_launch_parameters.h"

#include #include struct procpara

;__global__ void addkernel(procpara* para)

void initprocpara(procpara* para, int arraysize)

void deinitprocpara(procpara* para)

void addwithcuda(procpara* para, unsigned int arraysize)

int main()

; const int b[arraysize] = ;

int c[arraysize] = ;

procpara* para = new procpara;

initprocpara(para, arraysize);

memcpy(para->h_a, a, arraysize * sizeof(int));

memcpy(para->h_b, b, arraysize * sizeof(int));

addwithcuda(para, arraysize);

memcpy(c, para->h_c, arraysize * sizeof(int));

printf(" + = \n",

c[0], c[1], c[2], c[3], c[4]);

deinitprocpara(para);

delete para;

return 0;

}

但是,這個程式並不能得到正確的結果。

這是因為,在傳遞給__global__函式的結構體指標的記憶體實體在主機記憶體中。而在非unified memory的條件下,gpu是不能訪問到cpu端的記憶體資料的。由此,要繼續使用結構體傳遞引數,需要進行如下的操作:

分別建立主機端和裝置端結構體指標,並分配相應的記憶體。為主機端結構體內部成員變數分別分配主機端和裝置端記憶體。然後將主機端結構體資料複製給裝置端結構體。在核心計算**中,主機端程式使用主機端結構體指標來獲取所有資料的指標(包括資料拷貝),裝置端程式使用裝置端結構體指標獲取裝置端資料的指標。修改後的**如下,這裡需要注意的是,分配記憶體用到了指向指標的指標。因為指標本身是個變數,其儲存的是個位址,分配記憶體要對該變數的內容進行更新,必須傳遞該變數的指標才有效,否則只是改變了引數變數的內容。這也是為什麼cudamalloc使用的是指標的指標的原因。

#include "cuda_runtime.h"

#include "device_launch_parameters.h"

#include #include struct procpara

;__global__ void addkernel(procpara* d_para)

void initprocpara(procpara**ha_para, procpara**da_para, int arraysize)

void deinitprocpara(procpara*h_para, procpara*d_para)

void addwithcuda(procpara* h_para, procpara* d_para, unsigned int arraysize)

int main()

; const int b[arraysize] = ;

int c[arraysize] = ;

procpara *h_para;

procpara *d_para;

initprocpara(&h_para, &d_para, arraysize);

memcpy(h_para->h_a, a, arraysize * sizeof(int));

memcpy(h_para->h_b, b, arraysize * sizeof(int));

addwithcuda(h_para, d_para, arraysize);

memcpy(c, h_para->h_c, arraysize * sizeof(int));

printf(" + = \n",c[0], c[1], c[2], c[3], c[4]);

deinitprocpara(h_para, d_para);

return 0;

}

CUDA GPU程式設計中使用結構體傳遞函式引數

cuda gpu程式設計中,雖然統一定址 unified memory 技術能夠大大簡化程式設計難度和 複雜度,但是速度略有犧牲,同時對執行環境提出更多的要求。而在不使用這項技術時,程式設計時需要同時建立cpu host 和gpu device 端的變數指標,然後為其分別分配記憶體。操作完成後,再分...

結構體中使用string

1.malloc只是負責申請一塊記憶體,沒有任何其他動作。2.直接宣告結構體或者new 乙個結構體指標,會呼叫預設建構函式。如果結構中包含類,同樣會呼叫成員類的預設建構函式。3.程式中的記憶體錯誤是因為使用malloc分配乙個結構體內存,但是string是乙個類。並沒有呼叫string的建構函式,所...

C語言中使用結構體

1 先定義結構體 struct stu char name 20 long number float score 4 再定義指向結構體型別變數的指標變數 struct stu p1,p2 或者 struct stu p1,p2 定義指標變數p 1 p 2,分別指向結構體型別變數。2 在定義型別的同時...