CUDA初始化与核函数

转自:https://blog.youkuaiyun.com/sunmc1204953974/article/details/51016816

#include <stdio.h>
#include <cuda_runtime.h>
#include <math.h>

#define DATA_SIZE 1048576

int data[DATA_SIZE];

void GenerateNumbers(int *number, int size) {
    for (int i = 0; i < size; i++) {
        number[i] = rand() % 10;
    }

}



bool init_cuda() {

    int count;
    cudaGetDeviceCount(&count);


    if (count == 0) {
        fprintf(stderr, "There is no device.\n");
        return false;
    }

    int i;
    for ( i = 0; i < count; i++)
    {
        cudaDeviceProp prop;    //CUDA device properties
        if (cudaGetDeviceProperties(&prop, i) == cudaSuccess) {
            if (prop.major >= 1)//prop.major 和 prop.minor 分别代表装置支持的版本号码,例如 6.5 则 prop.major 为 6 而prop.minor 为 5
                break;//确保版本号大于1
        }
    }

    if (i == count) {
        fprintf(stderr, "There is no device support CUDA 1.x");
        return false;
    }

    cudaSetDevice(i);
    return true;
}

/*
    在 CUDA 中,在函数前面加上__global__ 表示这个函式是要在显示芯片上执行的,

    所以我们只要在正常函数之前加上一个__global__就行了

    【注意】显示芯片上执行的程序,不能有返回值!
*/
__global__ static void sumofSquares(int *num, int *result) {

    int sum = 0;
    for (int i = 0; i < DATA_SIZE; i++) {

        sum += num[i] * num[i] * num[i];
    }
    *result = sum;

}


int main() {

    if (!init_cuda()) {
        fprintf(stderr, "Cuda init failed!!");
        return 0;
    }
    printf("CUDA initialized.\n");

    //生成随机数
    GenerateNumbers(data, DATA_SIZE);


    //把数据复制到显卡内存
    int *gpudata, *result;

    //在显卡中分配一块大小为 sizeof(int)*DATA_SIZE 的内存
    cudaMalloc((void**)&gpudata, sizeof(int)*DATA_SIZE);//&gpudata代表指针gpudata的地址----(void**)是类型转换
    cudaMalloc((void**)&result, sizeof(int));

    cudaMemcpy(gpudata, data, sizeof(int)*DATA_SIZE, cudaMemcpyHostToDevice);
            // dst ,    src----把CPU中的data 传到 GPU中的gpudata

    // 在CUDA 中执行函数 语法:函数名称<<<block 数目, thread 数目, shared memory 大小>>>(参数...);
    sumofSquares <<<1, 1, 0 >>> (gpudata, result);

    int sum;

    cudaMemcpy(&sum, result, sizeof(int), cudaMemcpyDeviceToHost);

    //Free

    cudaFree(gpudata);
    cudaFree(result);

    printf("GpuSum = %d\n", sum);

    sum = 0;
    for (int i = 0; i < DATA_SIZE; i++) {
        sum += data[i] * data[i] * data[i];
    }

    printf("CpuSum = %d\n", sum);
    getchar();
    return 0;

}
<think>我们在CUDA编程中启动核函数需要指定执行配置,即网格(grid)和块(block)的维度。核函数的启动使用三重尖括号语法<<<grid, block>>>,其中grid和block可以是整数(一维)或dim3类型(多维)。核函数必须使用__global__限定符声明。 步骤: 1. 定义核函数:使用__global__修饰符,返回类型为void。 2. 配置执行参数:确定网格和块的维度(每个块中的线程数以及网格中的块数)。 3. 调用核函数:使用<<<grid, block>>>语法,并传递必要的参数。 注意:核函数只能在主机端(CPU)调用,并在设备端(GPU)执行。 示例:启动一个简单的核函数,将数组中的每个元素乘以2。 首先,定义核函数: ```cpp __global__ void multiplyByTwo(int *d_array, int n) { int idx = blockIdx.x * blockDim.x + threadIdx.x; if (idx < n) { d_array[idx] *= 2; } } ``` 然后,在主机代码中分配设备内存,拷贝数据,配置执行参数并启动核函数: ```cpp #include <cuda_runtime.h> #include <iostream> int main() { const int n = 1000; int *h_array = new int[n]; // 主机数组 int *d_array; // 设备数组 // 初始化主机数组 for (int i = 0; i < n; i++) { h_array[i] = i; } // 分配设备内存 cudaMalloc(&d_array, n * sizeof(int)); // 将数据从主机复制到设备 cudaMemcpy(d_array, h_array, n * sizeof(int), cudaMemcpyHostToDevice); // 配置执行参数:每个块256个线程,计算块的数量 int blockSize = 256; int numBlocks = (n + blockSize - 1) / blockSize; // 启动核函数 multiplyByTwo<<<numBlocks, blockSize>>>(d_array, n); // 将结果复制回主机 cudaMemcpy(h_array, d_array, n * sizeof(int), cudaMemcpyDeviceToHost); // 检查结果(可选) for (int i = 0; i < n; i++) { if (h_array[i] != 2 * i) { std::cerr << "Error at index " << i << std::endl; break; } } // 释放内存 delete[] h_array; cudaFree(d_array); return 0; } ``` 说明: - 核函数启动是异步的:主机代码在启动核函数后继续执行,不会等待核函数完成。因此,通常需要调用cudaDeviceSynchronize()来等待核函数执行完成(但上面的代码中,由于后面的cudaMemcpy(设备到主机)是同步操作,会等待核函数完成,所以不需要显式同步)。 - 执行配置:<<<grid, block>>>中,grid和block可以是dim3类型,例如:<<<dim3(2,2), dim3(16,16)>>>表示网格有2x2个块,每个块有16x16个线程。 注意事项: - 每个块的最大线程数有限制(例如1024),因此需要根据问题规模和硬件限制合理配置。 - 网格和块的维度可以是1维、2维或3维,通常根据数据访问模式选择以优化性能。 引用说明:在CUDA编程中,核函数的启动配置是并行计算的关键步骤[^1][^2]。</think>### CUDA核函数启动方法 在CUDA编程中启动核函数需要三个关键步骤,遵循特定的语法和执行配置: #### 1. **核函数定义** 使用`__global__`限定符声明核函数,其返回类型必须为`void`: ```cpp __global__ void myKernel(int* data, int size) { int idx = blockIdx.x * blockDim.x + threadIdx.x; if (idx < size) { data[idx] *= 2; // 示例操作 } } ``` #### 2. **执行配置** 使用三重尖括号语法`<<<grid, block>>>`指定并行层次: ```cpp dim3 blockDim(256); // 每个块包含256个线程 dim3 gridDim((n + 255) / 256); // 根据数据量n计算所需块数 ``` #### 3. **启动核函数** 调用核函数并传递参数: ```cpp myKernel<<<gridDim, blockDim>>>(d_data, n); ``` #### 完整示例流程 ```cpp #include <cuda_runtime.h> int main() { const int n = 1000; int* d_data; // 1. 分配设备内存 cudaMalloc(&d_data, n * sizeof(int)); // 2. 配置执行参数 dim3 block(256); dim3 grid((n + block.x - 1) / block.x); // 3. 启动核函数 myKernel<<<grid, block>>>(d_data, n); // 4. 同步等待核函数完成 cudaDeviceSynchronize(); // 5. 释放资源 cudaFree(d_data); return 0; } ``` #### 关键注意事项 1. **参数传递**:核函数参数需通过值传递,不支持引用传递 2. **内存类型**:核函数只能访问设备内存(如`cudaMalloc`分配的内存) 3. **异步执行**:核函数启动后立即返回主机线程,需显式同步(`cudaDeviceSynchronize()`) 4. **维度限制**: - 每个块最多1024个线程(现代GPU) - 网格维度上限为$2^{31}-1$(x方向) 5. **错误检查**:建议使用`cudaGetLastError()`检查启动错误 > 执行配置`<<<>>>`实际定义了线程层次结构: > - **网格(Grid)**:由多个线程块组成 > - **线程块(Block)**:包含一组协同线程,可共享内存 > 线程索引计算公式: > $全局线程ID = blockIdx.x \times blockDim.x + threadIdx.x$[^1][^2]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值