cuda编程002—流

没有使用同步的情况:

#include 
#include 

__global__ void test_kernel(){

    printf("Message from Device.\n");
}
void test(){
    test_kernel<<<1, 1>>>();
}
#include 
#include 


void test();
int main(){
    
    test();
    printf("Message from Host.\n");

    getchar();

    return 0;
}

先调用的核函数,结果是先输出的Host:

cuda编程002—流_第1张图片

 进行同步,代码如下:

#include 
#include 


void test();
int main(){
    
    test();
    // cudaDeviceSynchronize();  // 设备同步,整个GPU设备的同步等待任务完成
    cudaStreamSynchronize(nullptr);  // 流同步
    printf("Message from Host.\n");

    getchar();

    return 0;
}

输出结果:

cuda编程002—流_第2张图片

cuda流整体笔记和代码

#include 
#include 
#include 

// 核函数
__global__ void test_kernel(float* array, int edge){

    int position = blockDim.x * blockIdx.x + threadIdx.x;
    if(position >= edge) return;

    array[position] *= 0.5f;
}

void test(cudaStream_t stream, float* array, int num){

    int threads = 512;
    int blocks = ceil(num / (float)threads);
    test_kernel<<>>(array, num);
}
#include 
#include 

// C++ 文件
void test(cudaStream_t stream, float* array, int num);

int main(){
    
    cudaStream_t stream;
    cudaEvent_t start, stop;

    // cudaEvent 是事件, 通常可以用来观察队列的执行情况
    // 比如,统计执行时间等操作
    cudaEventCreate(&start);
    cudaEventCreate(&stop);

    // 是重操作,不要随便创建太多,会消耗资源的
    // GPU计算的基本原则,是尽可能的使得计算密集,如果使用同步的话就是算一坨,等一会儿,算一坨,等一会。费劲吧啦的
    // 通过stream使得计算连续化、密集化,这样最好
    // GPU有个使用率,跟CPU使用了一样的,以GPU使用率越高越好
    cudaStreamCreate(&stream);

    cudaEventRecord(start, stream);

    int num = 10000;
    float* a = new float[num];
    for(int i=0; i < num; ++i)
        a[i] = i;

    float* a_device = nullptr;
    size_t a_bytes = sizeof(float) * num;
    cudaMalloc(&a_device, a_bytes);

    // 异步依赖的指针数据,必须在执行完成前一直存在,否则会造成例外结果
    // 并且异步执行时,对指针数据的修改,也需要合理的理解
    cudaMemcpyAsync(a_device, a, a_bytes, cudaMemcpyHostToDevice, stream);

    // 如果异步复制加上下面这段代码。会导致GPU边复制,CPU边修改,结果是a_device的内容不可控
    // 因此不要这么做,或者合理的去做你想做的
    // for(int i=0; i < num; ++i)
    //      a[i] = 500-i;


    test(stream, a_device, num);
    cudaMemcpyAsync(a, a_device, a_bytes, cudaMemcpyDeviceToHost, stream);

    cudaEventRecord(stop, stream);
    cudaEventSynchronize(stop);

    float ms = 0;
    cudaEventElapsedTime(&ms, start, stop);
    printf("核的执行时间是:%.8f ms\n", ms);

    // 打印前10个结果
    for(int i = 0; i < 10; ++i){
        printf(i == 0 ? "%.2f" : ", %.2f", a[i]);
    }
    printf("\n");
    
    // cudaStreamSynchronize(stream);
    // cudaDeviceSynchronize();  // 设备同步,整个GPU设备的同步等待任务完成
    // cudaStreamSynchronize(nullptr);  // 流同步

    /* 流的概率,stream, 类型全称是cudaStream_t
    1. 认为流是一个线程,任务级别的线程
    2. 认为流是一个任务队列
    3. 把异步执行的任务管理起来,在需要的时候等待或者做更多处理
    4. 默认流,指nullptr,如果给定为nullptr,就会使用默认流

    cuda核的执行都是异步的, 通过流来实现需要的同步

    任务队列
    队列特性:先进先出,后进后出

    cudaMemcpy 属于同步版本的内存拷贝
        等价于干了  ->  发送指令(任务队列中增加一个任务),我要复制了, cudaMemcpyAsync
                  ->  等待复制完成,cudaDeviceSynchronize

    */
    printf("Message from Host.\n");

    // 符合栈的方式分配和释放,就不用担心有bug
    delete [] a;
    
    cudaFree(a_device);
    cudaStreamDestroy(stream);
    cudaEventDestroy(start);
    cudaEventDestroy(stop);

    // getchar();

    return 0;
}

 

你可能感兴趣的:(linux,算法,运维)