Cuda 澄清GPU的实时工作流程
我刚开始学习CUDA,有一点让我感到困惑。为了便于论证,假设我在海洋中有几百个浮标。假设他们每隔几毫秒间歇性地广播一次std::vector。矢量可能是5个读数,或10个读数,等等,这取决于当时海洋中的条件。无法判断事件何时触发,这是不确定的 想象一下,我的想法是,我可以通过实时收集所有这些信息来预测温度,但预测者必须首先对所有浮标上的所有std::vectos进行排序。我的问题是。每次一个Buoy触发事件时,我是否必须将整个数据复制回GPU?既然另一个浮标的数据没有改变,我可以把数据留在GPU中,只更新已经改变的内容,并要求内核重新运行预测吗 如果是,什么是[推力伪]-代码可以这样做?对于流、事件和固定内存,这是最好的方法吗?用实时数据更新GPU的速度有多快的限制Cuda 澄清GPU的实时工作流程,cuda,gpu,Cuda,Gpu,我刚开始学习CUDA,有一点让我感到困惑。为了便于论证,假设我在海洋中有几百个浮标。假设他们每隔几毫秒间歇性地广播一次std::vector。矢量可能是5个读数,或10个读数,等等,这取决于当时海洋中的条件。无法判断事件何时触发,这是不确定的 想象一下,我的想法是,我可以通过实时收集所有这些信息来预测温度,但预测者必须首先对所有浮标上的所有std::vectos进行排序。我的问题是。每次一个Buoy触发事件时,我是否必须将整个数据复制回GPU?既然另一个浮标的数据没有改变,我可以把数据留在GPU
有人告诉我,这种问题不太适合GPU,更适合FPGA。基本序列可能是这样的 设置阶段(初始排序):
b1: 1.5 1.7 2.2 2.3 2.6
i1: 1 1 1 1 1
b2: 2.4 2.5 2.6
i2: 2 2 2
b3: 2.8
i3: 3
b: 1.5 1.7 2.2 2.3 2.6 2.4 2.5 2.6 2.8
i: 1 1 1 1 1 2 2 2 3
2
发送更新:
b2: 2.5 2.7 2.9 3.0
2),则在浮标向量上执行此操作。使用相同的规则对索引向量重复remove\u if
:
b: 1.5 1.7 2.2 2.3 2.6 2.8
i: 1 1 1 1 1 3
2
temp值和索引向量)复制到设备:
b2: 2.5 2.7 2.9 3.0
i2: 2 2 2 2
2
b: 1.5 1.7 2.2 2.3 2.5 2.6 2.7 2.8 2.9 3.0
i: 1 1 1 1 2 1 2 3 2 2
std::vector
上使用的相同方法来实现。矢量大小调整在GPU上可能是“昂贵的”,就像在CPU上可能是“昂贵的”(如果调整到更大的大小会触发新的分配和复制…),但如果已知浮标的最大数量和每次更新的元素的最大数量,这也可能是有限的。在这种情况下,我们可以将整体浮标值和浮标指数向量分配为最大必要尺寸
下面是一个完全按照上述大纲工作的示例。作为占位符,我包含了一个虚拟的prediction\u kernel
调用,显示可以在哪里插入专门的预测代码,对排序后的数据进行操作
#include <stdio.h>
#include <stdlib.h>
#include <thrust/host_vector.h>
#include <thrust/device_vector.h>
#include <thrust/sort.h>
#include <thrust/merge.h>
#include <sys/time.h>
#include <time.h>
#define N_BUOYS 1024
#define N_MAX_UPDATE 1024
#define T_RANGE 100
#define N_UPDATES_TEST 1000
struct equal_func{
const int idx;
equal_func(int _idx) : idx(_idx) {}
__host__ __device__
bool operator()(int test_val) {
return (test_val == idx);
}
};
__device__ float dev_result[N_UPDATES_TEST];
// dummy "prediction" kernel
__global__ void prediction_kernel(const float *data, int iter, size_t d_size){
int idx=threadIdx.x+blockDim.x*blockIdx.x;
if (idx == 0) dev_result[iter] = data[d_size/2];
}
void create_vec(unsigned int id, thrust::host_vector<float> &data, thrust::host_vector<int> &idx){
size_t mysize = rand()%N_MAX_UPDATE;
data.resize(mysize);
idx.resize(mysize);
for (int i = 0; i < mysize; i++){
data[i] = ((float)rand()/(float)RAND_MAX)*(float)T_RANGE;
idx[i] = id;}
thrust::sort(data.begin(), data.end());
}
int main(){
timeval t1, t2;
int pp = 0;
// ping-pong processing vectors
thrust::device_vector<float> buoy_data[2];
buoy_data[0].resize(N_BUOYS*N_MAX_UPDATE);
buoy_data[1].resize(N_BUOYS*N_MAX_UPDATE);
thrust::device_vector<int> buoy_idx[2];
buoy_idx[0].resize(N_BUOYS*N_MAX_UPDATE);
buoy_idx[1].resize(N_BUOYS*N_MAX_UPDATE);
// vectors for initial buoy data
thrust::host_vector<float> h_buoy_data[N_BUOYS];
thrust::host_vector<int> h_buoy_idx[N_BUOYS];
//SETUP
// populate initial data
int lidx=0;
for (int i = 0; i < N_BUOYS; i++){
create_vec(i, h_buoy_data[i], h_buoy_idx[i]);
thrust::copy(h_buoy_data[i].begin(), h_buoy_data[i].end(), &(buoy_data[pp][lidx]));
thrust::copy(h_buoy_idx[i].begin(), h_buoy_idx[i].end(), &(buoy_idx[pp][lidx]));
lidx+= h_buoy_data[i].size();}
// sort initial data
thrust::sort_by_key(&(buoy_data[pp][0]), &(buoy_data[pp][lidx]), &(buoy_idx[pp][0]));
//UPDATE CYCLE
gettimeofday(&t1, NULL);
for (int i = 0; i < N_UPDATES_TEST; i++){
unsigned int vec_to_update = rand()%N_BUOYS;
int nidx = lidx - h_buoy_data[vec_to_update].size();
create_vec(vec_to_update, h_buoy_data[vec_to_update], h_buoy_idx[vec_to_update]);
thrust::remove_if(&(buoy_data[pp][0]), &(buoy_data[pp][lidx]), buoy_idx[pp].begin(), equal_func(vec_to_update));
thrust::remove_if(&(buoy_idx[pp][0]), &(buoy_idx[pp][lidx]), equal_func(vec_to_update));
lidx = nidx + h_buoy_data[vec_to_update].size();
thrust::device_vector<float> temp_data = h_buoy_data[vec_to_update];
thrust::device_vector<int> temp_idx = h_buoy_idx[vec_to_update];
int ppn = (pp == 0)?1:0;
thrust::merge_by_key(&(buoy_data[pp][0]), &(buoy_data[pp][nidx]), temp_data.begin(), temp_data.end(), buoy_idx[pp].begin(), temp_idx.begin(), buoy_data[ppn].begin(), buoy_idx[ppn].begin() );
pp = ppn; // update ping-pong buffer index
prediction_kernel<<<1,1>>>(thrust::raw_pointer_cast(buoy_data[pp].data()), i, lidx);
}
gettimeofday(&t2, NULL);
unsigned int tdiff_us = ((t2.tv_sec*1000000)+t2.tv_usec) - ((t1.tv_sec*1000000)+t1.tv_usec);
printf("Completed %d updates in %f sec\n", N_UPDATES_TEST, (float)tdiff_us/(float)1000000);
// float *temps = (float *)malloc(N_UPDATES_TEST*sizeof(float));
// cudaMemcpyFromSymbol(temps, dev_result, N_UPDATES_TEST*sizeof(float));
// for (int i = 0; i < 100; i++) printf("temp %d: %f\n", i, temps[i]);
return 0;
}
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#定义N_浮标1024
#定义N_MAX_更新1024
#定义T_范围100
#定义N\u更新\u测试1000
结构相等函数{
常数int idx;
相等函数(int_idx):idx(_idx){}
__主机设备__
布尔运算符()(整数测试值){
返回(test_val==idx);
}
};
__设备\uuuuuuuuu浮动开发结果[N\u更新\u测试];
//虚拟“预测”内核
__全局无效预测内核(常量浮点*数据、整数、大小){
int idx=threadIdx.x+blockDim.x*blockIdx.x;
如果(idx==0)开发结果[iter]=data[d_size/2];
}
void create_vec(无符号int-id,推力::主机向量和数据,推力::主机向量和idx){
size\u t mysize=rand()%N\u MAX\u UPDATE;
数据。调整大小(mysize);
调整大小(mysize);
for(int i=0;i#include <stdio.h>
#include <stdlib.h>
#include <thrust/host_vector.h>
#include <thrust/device_vector.h>
#include <thrust/sort.h>
#include <thrust/merge.h>
#include <sys/time.h>
#include <time.h>
#define N_BUOYS 1024
#define N_MAX_UPDATE 1024
#define T_RANGE 100
#define N_UPDATES_TEST 1000
struct equal_func{
const int idx;
equal_func(int _idx) : idx(_idx) {}
__host__ __device__
bool operator()(int test_val) {
return (test_val == idx);
}
};
__device__ float dev_result[N_UPDATES_TEST];
// dummy "prediction" kernel
__global__ void prediction_kernel(const float *data, int iter, size_t d_size){
int idx=threadIdx.x+blockDim.x*blockIdx.x;
if (idx == 0) dev_result[iter] = data[d_size/2];
}
void create_vec(unsigned int id, thrust::host_vector<float> &data, thrust::host_vector<int> &idx){
size_t mysize = rand()%N_MAX_UPDATE;
data.resize(mysize);
idx.resize(mysize);
for (int i = 0; i < mysize; i++){
data[i] = ((float)rand()/(float)RAND_MAX)*(float)T_RANGE;
idx[i] = id;}
thrust::sort(data.begin(), data.end());
}
int main(){
timeval t1, t2;
int pp = 0;
// ping-pong processing vectors
thrust::device_vector<float> buoy_data[2];
buoy_data[0].resize(N_BUOYS*N_MAX_UPDATE);
buoy_data[1].resize(N_BUOYS*N_MAX_UPDATE);
thrust::device_vector<int> buoy_idx[2];
buoy_idx[0].resize(N_BUOYS*N_MAX_UPDATE);
buoy_idx[1].resize(N_BUOYS*N_MAX_UPDATE);
// vectors for initial buoy data
thrust::host_vector<float> h_buoy_data[N_BUOYS];
thrust::host_vector<int> h_buoy_idx[N_BUOYS];
//SETUP
// populate initial data
int lidx=0;
for (int i = 0; i < N_BUOYS; i++){
create_vec(i, h_buoy_data[i], h_buoy_idx[i]);
thrust::copy(h_buoy_data[i].begin(), h_buoy_data[i].end(), &(buoy_data[pp][lidx]));
thrust::copy(h_buoy_idx[i].begin(), h_buoy_idx[i].end(), &(buoy_idx[pp][lidx]));
lidx+= h_buoy_data[i].size();}
// sort initial data
thrust::sort_by_key(&(buoy_data[pp][0]), &(buoy_data[pp][lidx]), &(buoy_idx[pp][0]));
//UPDATE CYCLE
gettimeofday(&t1, NULL);
for (int i = 0; i < N_UPDATES_TEST; i++){
unsigned int vec_to_update = rand()%N_BUOYS;
int nidx = lidx - h_buoy_data[vec_to_update].size();
create_vec(vec_to_update, h_buoy_data[vec_to_update], h_buoy_idx[vec_to_update]);
thrust::remove_if(&(buoy_data[pp][0]), &(buoy_data[pp][lidx]), buoy_idx[pp].begin(), equal_func(vec_to_update));
thrust::remove_if(&(buoy_idx[pp][0]), &(buoy_idx[pp][lidx]), equal_func(vec_to_update));
lidx = nidx + h_buoy_data[vec_to_update].size();
thrust::device_vector<float> temp_data = h_buoy_data[vec_to_update];
thrust::device_vector<int> temp_idx = h_buoy_idx[vec_to_update];
int ppn = (pp == 0)?1:0;
thrust::merge_by_key(&(buoy_data[pp][0]), &(buoy_data[pp][nidx]), temp_data.begin(), temp_data.end(), buoy_idx[pp].begin(), temp_idx.begin(), buoy_data[ppn].begin(), buoy_idx[ppn].begin() );
pp = ppn; // update ping-pong buffer index
prediction_kernel<<<1,1>>>(thrust::raw_pointer_cast(buoy_data[pp].data()), i, lidx);
}
gettimeofday(&t2, NULL);
unsigned int tdiff_us = ((t2.tv_sec*1000000)+t2.tv_usec) - ((t1.tv_sec*1000000)+t1.tv_usec);
printf("Completed %d updates in %f sec\n", N_UPDATES_TEST, (float)tdiff_us/(float)1000000);
// float *temps = (float *)malloc(N_UPDATES_TEST*sizeof(float));
// cudaMemcpyFromSymbol(temps, dev_result, N_UPDATES_TEST*sizeof(float));
// for (int i = 0; i < 100; i++) printf("temp %d: %f\n", i, temps[i]);
return 0;
}