接觸過cuda的各位應該都了解過歸約演算法,包括歸約演算法求和、求最大最小值、求方差標準差等等。為了保證演算法的時間複雜度,我們常常會花費大量的時間去優化歸約演算法的實現,包括執行緒分散度的問題、thread分歧以及bank衝突的問題等等。當資料維度較小時還能夠冷靜的分析每乙個可能還存在優化空間的點,但當資料維度較大時,常常感覺優化的程度還是不夠。不要慌,這時就是體現cuda強大的時刻,cuda的thrust庫可以完美的解決這些問題。
本文主要記錄一下最近使用到的thrust庫中的函式,包括reduce、sort、unique等等。
在記錄函式之前,首先記錄一下thrust提供的資料型別vector,thrust中定義了host端和device端的兩種vector,分別定義在host_vector.h
和device_vector.h
中,在宣告變數時也很簡單:
thrust::host_vector hvec;
thrust::device_vector dvec;
dvec=hvec;
//device vector和 host vector可以直接用等號進行傳遞,對應於cudamemcpy的功能
thrust中還定義了device_ptr指標型別,當傳入函式的指標是指向device端的記憶體時,需要用device_ptr進行封裝:
float array[6]
=;float
*dev_array =0;
cudamalloc
(&dev_array,4*
6);cudamemcpy
(dev_array, array,4*
6, cudamemcpyhosttodevice)
;thrust::device_ptr<
float
>
dev_ptr
(dev_array)
;thrust::
reduce
(dev_ptr, dev_ptr +6)
;//由於dev_array指向device端,不能直接作為引數,需要對其封裝
thrust::host_vector hvec;
thrust::device_vector dvec;
dvec=hvec;
thrust::
reduce
(dvec.
begin()
, dvec.
end())
;//此時的引數是迭代器,不用也不能用device_ptr對其封裝
//上述的兩種函式的呼叫方法也存在host端的版本,傳入的指標或者迭代器都是host端資料
thrust::
reduce
(array, array +6)
;thrust::
reduce
(hvec.
begin()
, hvec.
end())
;//從device_ptr中提取「原始」指標需要使用raw_pointer_cast函式
float dev_array=thrust::
raw_pointer_cast
(dev_ptr)
;
上述程式中說明了thrust中的資料型別以及函式呼叫時四種呼叫方式,本文後續函式使用的例子中,乙個函式只選取一種呼叫方式,其餘的方式可以模擬呼叫。
thrust::reduce函式主要用於歸約操作,在reduce.h
中被定義,其返回值可以為乙個具體數值,呼叫的方式也很簡單:
thrust::device_ptr<
float
>
dev_xptr
(dev_xvalue)
;double sum = thrust::
reduce
(dev_xptr, dev_xptr + n)
;
也可以通過thrust::transform_reduce函式,定義自己想要的歸約方式,下面的例子定義了乙個求方差的歸約:
//隨意定義想要的歸約方式
struct variance: std::unary_function<
float
,float
>
const
float mean;
__host__ __device__ float
operator()
(float data)
const};
//需要提前通過reduce函式求和,從而獲得均值mean
float variance = thrust::
transform_reduce
(dev_ptr,dev_ptr + n,
variance
(mean)
,0.0f
,thrust::plus<
float
>()
)/ n;
sort函式用於對資料的資料進行排序,在sort.h
中定義,使用方式也很簡單:
int a[6]
=;thrust::
sort
(a, a +6)
;//result: 預設排序方式為由小到大
//sort_by_key函式可以根據鍵值來進行排序
int keys[n]=;
char values[n]=;
thrust::
sort_by_key
(keys, keys + n, values)
;//result: key
// values
當然sort函式也可以自己定義排序方式,下面的例子是對三維座標點的座標值按照由小到大排序:
struct comprule};
thrust::host_vectorp(
10);thrust::
sort
(p.begin()
, p.
end(),
comprule()
);//輸入 //輸出
//p[0] = ; p[0] = ;
//p[1] = ; p[1] = ;
//p[2] = ; p[2] = ;
//p[3] = ; p[3] = ;
//p[4] = ; p[4] = ;
//p[5] = ; p[5] = ;
//p[6] = ; p[6] = ;
//p[7] = ; p[7] = ;
//p[8] = ; p[8] = ;
//p[9] = ; p[9] = ;
最後還有stable_sort函式,與sort不同的是,其在排序時不改變相同資料的相對位置。
max_element(min_element)函式,故名思義,求最大(小)值,在extrema.h
被定義,呼叫方法如下:
thrust::device_vector
::iterator iter = thrust::
max_element
(dvec.
begin
(),dvec.
end())
;//其返回值是乙個迭代器
int position = iter - dvec.
begin()
;//獲取最大(小)值所在位置
type max_val =
*iter;
//獲取最大(小)值結果
unique函式,用來將一組資料中滿足條件的資料篩選出來,在unique.h
中被定義,也可以自定義篩選條件。下面例子的功能是刪除重複資料:
struct is_sam};
thrust::
unique
(p.begin()
, p.
end(),
is_sam()
),p.
end();
//unique函式的功能只是將滿足條件的資料篩選出來,無法直接刪除,需要結合vector的erase函式進行刪除
p.erase
(thrust::
unique
(p.begin()
, p.
end(),
is_sam()
),p.
end())
;//輸入 //unique後結果 //erase後結果
//p[0] = p[0] = p[0] =
//p[1] = p[1] = p[1] =
//p[2] = p[2] = p[2] =
//p[3] = p[3] = p[3] =
//p[4] = p[4] = p[4] =
//p[5] = p[5] = p[5] =
//p[6] = p[6] = p[6] =
//p[7] = p[7] = p[7] =
//p[8] = p[8] =
//p[9] = p[9] =
目前只接觸了以上函式的使用,後續使用過的其他函式會持續的進行新增! CUDA 紋理的使用
紋理繫結有兩種,乙個是繫結到線性記憶體就是用cudamalloc cudamemcpy 開闢的記憶體空間,另一種是繫結到cudamallocarray,cudamemcpytoarray開闢到的二維陣列或者三維陣列。先說比較簡單的就是繫結到cudamalloc開闢到的記憶體空間。首先是紋理宣告 關於...
cuda事件的使用
cudaevent t start,stop cudaeventcreate start 建立事件 cudaeventcreate stop cudaeventrecord start,0 記錄當前時間 要記錄時間的事情 工作 cudaeventrecord stop,0 記錄當前時間 cudaev...
CUDA庫的cmake寫法
cmake minimum required version 3.8 fatal error project cmake and cuda languages cxx cuda add library particles static randomize.cpp randomize.h partic...