并行计算01-基于cuda编程01

2 篇文章 0 订阅
2 篇文章 0 订阅

这里写图片描述

摘要:第一个cuda编程,主要是想看一下编程思维的与一般的编程的区别;实践一个小例子进行感性入门测试。先用起来再说,后面再去理解原理,学与做相结合的学习方法。

1. 安装cuda

这个PPT讲了cuda的安装
https://wenku.baidu.com/view/a2fab32f5fbfc77da269b1f8.html
这里写图片描述

2. 创建项目

这里写图片描述

3. Host与device编程的区别

C编译,在Host上运行:

#include <stdio.h>
int main()
{
    // 这个完全在主机上运行
    printf("hello world\n");
    system("pause");
    return 0;
}

经典的hello word, 这个只在host上运行,并没有考虑主机之外的设备【定义CUP及系统的内存称为主机;GPU及其内存称为设备;在GPU运行的函数称为核函数(Kernel)】。
增一个核函数,在设备上运行:

#include "cuda_runtime.h"
#include "device_launch_parameters.h"
#include <stdio.h>
/* 核函数:__global__修饰符告诉编译器,函数应该编译为设备运行的。这个函数将交给设备的编译器编译。
*/
__global__ void aKernel(){}
// main函数仍然是主机编译
int main()
{
    aKernel<<<1,1>>>();
    printf("hello world\n");
    system("pause");
    return 0;
}

4. 矢量分布式求和并行模型

这个模型来自JS 与 EK《GPU高性能编程 Cuda实践》
这里写图片描述

5. 相关demo代码

#include "cuda_runtime.h"
#include "device_launch_parameters.h"

#include <stdio.h>
#include<iostream>

const int N =10; 

// 核函数
__global__ void aKernel(int a, int b, int *c){
    // 设备上的指针与C指针的使用是一样的
    *c = a + b;
}

// 在CPU进行计算,这是一个串行的计算
void add( int *a ,int *b , int *c)  
{  
    int tid = 0;  // 这是第0个cup,因此索引从0开始;
    while(tid < N)       
    {  
        c[tid] = a[tid] + b[tid];  
        tid += 1;  // 由于只有一个CPU,所以每次增1          
    }  
}  

// 核加
__global__ void kernelAdd( int *a ,int *b , int *c)  
{  
    int tid = blockIdx.x;   // 计算这个索引处理的数据
    if(tid < N)  
    {  
        c[tid] = a[tid]+b[tid];  
    }  
}  


int main()
{   
    printf("############demo01 hello word###################");
    int c;
    int *dev_c;
    // 分配内存,第一个参数是一个指针,指向用于保存新分配内存地址的变量,第二个参数是分配内存的大小
    // 主机可以作用dev_c作为参数的引用,不用可读取与写数据,也不要对它进行free。因为这个是在设备上的。
    cudaMalloc( (void**)&dev_c,sizeof(int));
    aKernel<<<1,1>>>(2,7,dev_c);
    // 把结果复制回主机:内存指针,设备指针,大小,内存复制方向;另外还有两个cudaMemcpyHostToDevice&&cudaMemcpyDeviceToDevice ; 如果两个是主内存就是C了。
    cudaMemcpy(&c, dev_c, sizeof(int), cudaMemcpyDeviceToHost);
    printf("2+7=%d\n",c);
    cudaFree(dev_c);

    /*
       主机上的指针只能访问主机的上的内存,设备上的指针只能访问设备上的内存。两个不可以相互操作。主机可以调用cudaMemcpy来访问设备的内存。
    */

    printf("############demo02 device info###################\n");
    cudaDeviceProp prop;
    int count;
    cudaGetDeviceCount(&count);
    printf("count: %d\n",count);
    for(int i = 0 ; i  < count; i++){
        cudaGetDeviceProperties(&prop, i);
        printf("devide No:%d\n",i);
        printf("标识设备的ASCII字符串: %s\n",prop.name);
        printf("设备上全局内存的总量,单位为字节: %u\n",prop.totalGlobalMem);
        printf("在一个线程块(Block)中可使用的共享内存总量,单位为字节: %u\n",prop.sharedMemPerBlock);
        printf("每个线程块中可用的32位寄存器数量: %d\n",prop.regsPerBlock);
        printf("在一个线程束(warp)中包含的线程数量: %d\n",prop.warpSize);
        printf("在内存复制中最大的修正量(Pitch),单位为字节: %u\n",prop.memPitch);
        printf("在一个线程块中包含的最大线程数目: %d\n",prop.maxThreadsPerBlock);
        printf("在多维线程块数组中,每一维包含的最大线程数量:[%d,%d,%d]\n",prop.maxThreadsDim[0],prop.maxThreadsDim[1],prop.maxThreadsDim[2]);
        printf("在一个线程格(Grid)中,每一维可以包含的线程块的数量: [%d,%d,%d]\n",prop.maxGridSize[0],prop.maxGridSize[1],prop.maxGridSize[2]);
        printf("常量内存的总量: %u\n",prop.totalConstMem);
        printf("设备计算功能集的主版本号: %d\n",prop.major);
        printf("设备计算功能集的次版本号: %d\n",prop.minor);
        printf("clock Rate: %d\n",prop.clockRate);
        printf("设备的纹理对齐要求: %d\n",prop.textureAlignment);
        printf("一个布尔类型值,表示设备是否可以同时执行一个cudaMemory()调用和一个核函数调用: %d\n",prop.deviceOverlap);
        printf("设备上多处理器的数量: %d\n",prop.multiProcessorCount);
        printf("一个布尔值,表示该设备上执行的核函数是否存在运行时限制: %d\n",prop.kernelExecTimeoutEnabled);
        printf("一个布尔值,表示设备是否是一个集成的GPU: %d\n",prop.integrated);
        printf("一个布尔值,表示设备是否将主机内存映射到cuda设备地址空间: %d\n",prop.canMapHostMemory);
        printf("表示设备的计算模式:默认,独占或禁止: %d\n",prop.computeMode);
        printf("一维纹理的最大大小: %d\n",prop.maxTexture1D);
        printf("二维纹理的最大维数: [%d,%d]\n",prop.maxTexture2D[0],prop.maxTexture2D[1]);
        printf("三维纹理的最大维数: [%d,%d,%d]\n",prop.maxTexture3D[0],prop.maxTexture3D[1],prop.maxTexture3D[2]);
        //printf("二维纹理数组的最大维数: [%d,%d,%d]\n",prop.maxTexture2DArray[0],prop.maxTexture2DArray[1],prop.maxTexture2DArray[2]);
        printf("一个布尔值,表示设备是否支持在同一个上下文中同时执行多个核函数: %d\n",prop.concurrentKernels);
    }

    printf("############demo03 矢量求和【CPU】###################\n");
    int a[N],b[N],csum[N];  
    //在CPU上对数组'a''b'赋值  
    for(int i=0;i<N;i++)     
    {  
        a[i] = -1;  
        b[i] = i * i;          
    }  
    add(a,b,csum);

    //打印结果  
    for(int i=0;i<N;i++)   
    {  
        printf("%d+%d=%d\n",a[i],b[i],csum[i]);          
    }  

    printf("############demo03 矢量求和【GPU】###################\n");
    int d_a[N],d_b[N],d_c[N];  
    int *dev_a0, *dev_b0, *dev_c0;  

    //allocate memory on GPU  
    cudaMalloc( (void**)&dev_a0, N*sizeof(int) ) ;  
    cudaMalloc( (void**)&dev_b0, N*sizeof(int) ) ;  
    cudaMalloc( (void**)&dev_c0, N*sizeof(int) ) ;  

    // 初始化数
    for(int i=0;i<N;i++)  
    {  
        d_a[i] = -1;  
        d_b[i] = i * i ;  
    }  
    // 从内存复制到设备
    cudaMemcpy( dev_a0 , d_a, N*sizeof(int), cudaMemcpyHostToDevice ) ;  
    cudaMemcpy( dev_b0 , d_b, N*sizeof(int), cudaMemcpyHostToDevice ) ;  

    // 调用核函数:N表示设备在执行函数时使用的并行线程块的数量。这里也就意味着会有N个副本,通过blockIdx.x可获取线程块来计算,blockIdx为内置变量。
    // cuda支持二维的线程块数组,例如矩阵运算或图像处理。直接使用二维索引就可以了。。
    // 尖括号的1表示,每个线程块中线程的个数为1
    kernelAdd<<<N,1>>>(dev_a0,dev_b0,dev_c0);  
    //把处理的结果从设备中复制数据回内存
    cudaMemcpy(d_c, dev_c0, N*sizeof(int), cudaMemcpyDeviceToHost) ;  
    for(int i=0;i<N;i++)  
    {  
        printf("%d+%d=%d\n",d_a[i],d_b[i],d_c[i]);   
    }  
    //release the memory on GPU  
    cudaFree(dev_a0);  
    cudaFree(dev_b0);  
    cudaFree(dev_c0);  

    system("pause");
    return 0;
}

运行结果
这里写图片描述

6. 遇到问题与解决

生成项目出错:

1>CUDACOMPILE : nvcc warning : The 'compute_20', 'sm_20', and 'sm_21' architectures are deprecated, and may be removed in a future release (Use -Wno-deprecated-gpu-targets to suppress warning).
1>CUDACOMPILE : nvcc warning : nvcc support for Microsoft Visual Studio 2010 and earlier has been deprecated and is no longer being maintained
1>  kernel.cu
1>  support for Microsoft Visual Studio 2010 has been deprecated!
1>ManifestResourceCompile:
1>  所有输出均为最新。
1>LINK : fatal error LNK1123: 转换到 COFF 期间失败: 文件无效或损坏
1>
1>生成失败。
1>
1>已用时间 00:00:01.57
========== 生成: 成功 0 个,失败 1 个,最新 0 个,跳过 0 个 ==========

解决:
参考
http://yacare.iteye.com/blog/2010049
具体操作,在代码空白处点击,选择项目-属性xxxx-如下图选择,最后点应用,就OK了。
这里写图片描述
运行结果【加入system(“pause”);】让cmd窗口停下来。

【作者:happyprince, http://blog.csdn.net/ld326/article/details/78572168

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值