我不是一个有能力的程序员。只是有人对CUDA感到好奇,所以我正在做一些阅读。我跑过一个使用Thrust做移动平均线的例子:
Simple Moving Average Thrust Example
例如,它运行并且大多数工作正常。然而,从某种意义上来说它只能进行一次移动平均操作是微不足道的。
我如何并行地说352
这些移动平均操作,都在同一个数据流上运行?在我看来,程序流程可能是:
1000
或10000
而不是30
)351
CUDA
我的GTX 465核心4
,5
,6
,...,352
,353
,354
)我得到了这段代码
// compute SMA using standard summation
simple_moving_average(data, w, averages);
让这一切成为现实,但我如何让Thrust并行完成其中的许多工作?
我对此感兴趣的是股票数据。如果我看看GOOG的价格,我会把它放在使用所有核心的GPU中并留在那里。然后,我可以自由地进行大量处理,而无需再加载数据,只需读回每个核心的结果。注意:我可能不想在所有核心中使用GOOG。有些核心可能是GOOG,有些则带有其他符号,但我稍后会到达。我只是觉得如果每个核心都有足够的空间,我不希望全局内存中的股票数据。
我认为这对于CUDA& amp;推力?
答案 0 :(得分:3)
以下是使用arrayfire执行此操作的可能方法:
请注意,我并不隶属于此库。
我很确定这也可以用推力来完成
但是我用arrayfire发现这个更简单了。
如果图书馆是免费的,为什么我不能用它而不是推力?
在arrayfire中,您可以使用矩阵并行运行多个SMA操作:
unsigned n_SMAs = 1000; // # of SMA indicators to evaluate
unsigned len = 2000; // # of stock prices per indicator
unsigned w = 6; // window size
// generate stock prices: [0..10]
af::array data = af::randu(n_SMAs, len) * 10;
// compute inclusive prefix sums along colums of the matrix
af::array s = af::accum(data, 1);
// compute the average
af::array avg = (s.cols(w, af::end) - s.cols(0, af::end - w)) / w;
af::eval(avg);
std::cout << avg.dims() << "\n" << avg << "\n";
如果您正在寻找,请告诉我。这就是我理解你的问题的方法:并行计算几个SMA指标
答案 1 :(得分:0)
我的理解是你对以下两种情况感兴趣:
2 * RADIUS + 1
的固定平均窗口并行平均。这就是@asm提出的ArrayFire代码所做的 - 你已经接受了它。 我认为编写自己的CUDA内核来执行上述操作会更容易,而不是使用CUDA Thrust。下面是一个完整的示例,其运行方式与@asm提出的ArrayFire代码相同,因此涵盖了案例#2。修改它以涵盖案例#1将是直截了当的。
#include <thrust/device_vector.h>
#define RADIUS 3
#define BLOCK_SIZE_X 8
#define BLOCK_SIZE_Y 8
/*******************/
/* iDivUp FUNCTION */
/*******************/
int iDivUp(int a, int b){ return ((a % b) != 0) ? (a / b + 1) : (a / b); }
/********************/
/* CUDA ERROR CHECK */
/********************/
#define gpuErrchk(ans) { gpuAssert((ans), __FILE__, __LINE__); }
inline void gpuAssert(cudaError_t code, const char *file, int line, bool abort=true)
{
if (code != cudaSuccess)
{
fprintf(stderr,"GPUassert: %s %s %d\n", cudaGetErrorString(code), file, line);
if (abort) exit(code);
}
}
/**********/
/* KERNEL */
/**********/
__global__ void moving_average(unsigned int *in, unsigned int *out, unsigned int M, unsigned int N) {
__shared__ unsigned int temp[BLOCK_SIZE_Y][BLOCK_SIZE_X + 2 * RADIUS];
unsigned int gindexx = threadIdx.x + blockIdx.x * blockDim.x;
unsigned int gindexy = threadIdx.y + blockIdx.y * blockDim.y;
unsigned int gindex = gindexy * N + gindexx;
unsigned int lindexx = threadIdx.x + RADIUS;
unsigned int lindexy = threadIdx.y;
// --- Read input elements into shared memory
temp[lindexy][lindexx] = ((gindexx < N)&&(gindexy < M))? in[gindex] : 0;
if (threadIdx.x < RADIUS) {
temp[lindexy][threadIdx.x] = ((gindexx >= RADIUS)&&(gindexx < (N + RADIUS))&&(gindexy < M)) ? in[gindex - RADIUS] : 0;
temp[lindexy][threadIdx.x + (RADIUS + min(BLOCK_SIZE_X, N - blockIdx.x * BLOCK_SIZE_X))] = (((gindexx + min(BLOCK_SIZE_X, N - blockIdx.x * BLOCK_SIZE_X)) < N)&&(gindexy < M))? in[gindexy * N + gindexx + min(BLOCK_SIZE_X, N - blockIdx.x * BLOCK_SIZE_X)] : 0;
if ((threadIdx.y == 0)&&(gindexy < M)&&((gindexx + BLOCK_SIZE_X) < N)&&(gindexy < M)) printf("Inside 2 - tidx = %i; bidx = %i; tidy = %i; bidy = %i; lindexx = %i; temp = %i\n", threadIdx.x, blockIdx.x, threadIdx.y, blockIdx.y, threadIdx.x + (RADIUS + BLOCK_SIZE_X), temp[lindexy][threadIdx.x + (RADIUS + BLOCK_SIZE_X)]);
}
__syncthreads();
// --- Apply the stencil
unsigned int result = 0;
for (int offset = -RADIUS ; offset <= RADIUS ; offset++) {
result += temp[lindexy][lindexx + offset];
}
// --- Store the result
out[gindexy * N + gindexx] = result;
}
/********/
/* MAIN */
/********/
int main() {
const unsigned int M = 2;
const unsigned int N = 4 + 2 * RADIUS;
const unsigned int constant = 3;
thrust::device_vector<unsigned int> d_in(M * N, constant);
thrust::device_vector<unsigned int> d_out(M * N);
dim3 GridSize(iDivUp(N, BLOCK_SIZE_X), iDivUp(M, BLOCK_SIZE_Y));
dim3 BlockSize(BLOCK_SIZE_X, BLOCK_SIZE_Y);
moving_average<<<GridSize, BlockSize>>>(thrust::raw_pointer_cast(d_in.data()), thrust::raw_pointer_cast(d_out.data()), M, N);
gpuErrchk(cudaPeekAtLastError());
gpuErrchk(cudaDeviceSynchronize());
thrust::host_vector<unsigned int> h_out = d_out;
for (int j=0; j<M; j++) {
for (int i=0; i<N; i++)
printf("Element j = %i; i = %i; h_out = %i\n", j, i, h_out[N*j+i]);
}
return 0;
}