Cuda 澄清GPU的实时工作流程

Cuda 澄清GPU的实时工作流程,cuda,gpu,Cuda,Gpu,我刚开始学习CUDA,有一点让我感到困惑。为了便于论证,假设我在海洋中有几百个浮标。假设他们每隔几毫秒间歇性地广播一次std::vector。矢量可能是5个读数,或10个读数,等等,这取决于当时海洋中的条件。无法判断事件何时触发,这是不确定的 想象一下,我的想法是,我可以通过实时收集所有这些信息来预测温度,但预测者必须首先对所有浮标上的所有std::vectos进行排序。我的问题是。每次一个Buoy触发事件时,我是否必须将整个数据复制回GPU?既然另一个浮标的数据没有改变,我可以把数据留在GPU

我刚开始学习CUDA,有一点让我感到困惑。为了便于论证,假设我在海洋中有几百个浮标。假设他们每隔几毫秒间歇性地广播一次std::vector。矢量可能是5个读数,或10个读数,等等,这取决于当时海洋中的条件。无法判断事件何时触发,这是不确定的

想象一下,我的想法是,我可以通过实时收集所有这些信息来预测温度,但预测者必须首先对所有浮标上的所有std::vectos进行排序。我的问题是。每次一个Buoy触发事件时,我是否必须将整个数据复制回GPU?既然另一个浮标的数据没有改变,我可以把数据留在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;
    
    }