CUDA -- 规约求矩阵的行和

  求矩阵每行的和?

  可以把每行放入一个不同线程块,这样行与行之间进行粗粒度的并行。而对于每行,其对应的线程块中分配n个线程(对应行宽),使用共享存储器,让每个线程从显存中读取一个数至shared memory中,然后使用规约算法计算和。

代码如下:

#include "cuda_runtime.h" //CUDA运行时API
#include "device_launch_parameters.h"
#include <iostream>
#include <stdio.h>

cudaError_t addWithCuda(int mat[4][8], int *ans, dim3 d);

__global__ void addKernel(int *mat, int *ans, size_t pitch)
{
    int bid = blockIdx.x;
    int tid = threadIdx.x;
    __shared__ int data[8];
    int *row = (int*)((char*)mat + bid*pitch);
    data[tid] = row[tid];
    __syncthreads();
    for (int i = 4; i > 0; i /= 2) {
        if (tid < i)
            data[tid] = data[tid] + data[tid + i];
        __syncthreads();
    }
    if (tid == 0)
        ans[bid] = data[0];
}

int main()
{
    const int row = 4;
    const int col = 8;
    dim3 d(col, row);
    int mat[row][col] = { 1,2,3,4,5,1,2,3,
                        6,7,8,9,10,4,5,6,
                        11,12,13,14,15,7,8,9,
                        16,17,18,19,20,10,11,12 };
    int ans[row];
    // Add vectors in parallel.
    cudaError_t cudaStatus = addWithCuda(mat, ans, d);
    if (cudaStatus != cudaSuccess)
    {
        fprintf(stderr, "addWithCuda failed!\n");
        return 1;
    }
    // cudaThreadExit must be called before exiting in order for profiling and
    // tracing tools such as Nsight and Visual Profiler to show complete traces.
    cudaStatus = cudaThreadExit();
    if (cudaStatus != cudaSuccess)
    {
        fprintf(stderr, "cudaThreadExit failed!");
        return 1;
    }
    for (int i = 0; i < d.y; i++)
    {
        std::cout << ans[i] << " ";
    }
    return 0;
}

// 重点理解这个函数
cudaError_t addWithCuda(int mat[4][8], int *ans, dim3 d)
{
    int *dev_mat = 0; //GPU设备端数据指针
    int *dev_ans = 0;
    int pitch;
    cudaError_t cudaStatus; //状态指示
                            // Choose which GPU to run on, change this on a multi-GPU system.
    cudaStatus = cudaSetDevice(0); //选择运行平台
    if (cudaStatus != cudaSuccess)
    {
        fprintf(stderr, "cudaSetDevice failed! Do you have a CUDA-capable GPU installed?");
        goto Error;
    }
    // 分配GPU设备端内存
    cudaStatus = cudaMallocPitch((void**)&dev_mat, (size_t *)&pitch, d.x * sizeof(int), d.y);
    if (cudaStatus != cudaSuccess)
    {
        fprintf(stderr, "cudaMalloc failed!\n");
        goto Error;
    }
    cudaStatus = cudaMalloc((void**)&dev_ans, d.y * sizeof(int));
    if (cudaStatus != cudaSuccess)
    {
        fprintf(stderr, "cudaMalloc failed!\n");
        goto Error;
    }
    // 拷贝数据到GPU
    cudaStatus = cudaMemcpy2D(dev_mat, pitch, mat, d.x*sizeof(int), d.x*sizeof(int), d.y, cudaMemcpyHostToDevice);
    if (cudaStatus != cudaSuccess)
    {
        fprintf(stderr, "cudaMemcpy for dev_mat failed!\n");
        goto Error;
    }
    cudaStatus = cudaMemcpy(dev_ans, ans, d.y * sizeof(int), cudaMemcpyHostToDevice);
    if (cudaStatus != cudaSuccess)
    {
        fprintf(stderr, "cudaMemcpy for dev_ans failed!\n");
        goto Error;
    }
    // 运行核函数
    cudaEvent_t start, stop;
    cudaEventCreate(&start);
    cudaEventCreate(&stop);
    cudaEventRecord(start, 0);
    addKernel<<<d.y,d.x>>>(dev_mat, dev_ans, pitch);
    //addKernel_thd << <1, size >> >(dev_c, dev_a, dev_b);

    cudaEventRecord(stop, 0);
    cudaEventSynchronize(stop);
    float tm;
    cudaEventElapsedTime(&tm, start, stop);
    printf("GPU Elapsed time:%.6f ms.\n", tm);
    // cudaThreadSynchronize waits for the kernel to finish, and returns
    // any errors encountered during the launch.
    cudaStatus = cudaThreadSynchronize(); //同步线程
    if (cudaStatus != cudaSuccess)
    {
        fprintf(stderr, "cudaThreadSynchronize returned error code %d after launching addKernel!\n", cudaStatus);
        goto Error;
    }
    // Copy output vector from GPU buffer to host memory.
    cudaStatus = cudaMemcpy(ans, dev_ans, d.y * sizeof(int), cudaMemcpyDeviceToHost); //拷贝结果回主机
    if (cudaStatus != cudaSuccess)
    {
        fprintf(stderr, "cudaMemcpy failed!");
        goto Error;
    }
Error:
    cudaFree(dev_mat); //释放GPU设备端内存
    cudaFree(dev_ans);
    return cudaStatus;
}

原文地址:https://www.cnblogs.com/chen9510/p/11506257.html

时间: 2024-10-12 14:34:15

CUDA -- 规约求矩阵的行和的相关文章

hdu 4888 最大流给出行列和求矩阵

第一步,考虑如何求是否有解.使用网络流求解,每一行和每一列分别对应一个点,加上源点和汇点一共有N+M+2个点.有三类边: 1. 源点 -> 每一行对应的点,流量限制为该行的和 2. 每一行对应的点 -> 每一列对应的点,流量限制为 K 3. 每一列对应的点 -> 汇点,流量限制为该列的和 对上图做最大流,若源点出发的边和到达汇点的边全都满流,则有解,否则无解.若要求构造方案,则 (i,j) 对应的整数就是行 i–> 列 j 的流量. 第二步,考虑解是否唯一.显然,解唯一的充分必要条

数组-09. 求矩阵的局部极大值

数组-09. 求矩阵的局部极大值(15) 时间限制 400 ms 内存限制 65536 kB 代码长度限制 8000 B 判题程序 Standard 作者 徐镜春(浙江大学) 给定M行N列的整数矩阵A,如果A的非边界元素A[i][j]大于相邻的上下左右4个元素,那么就称元素A[i][j]是矩阵的局部极大值.本题要求给定矩阵的全部局部极大值及其所在的位置. 输入格式: 输入在第1行中给出矩阵A的行数M和列数N(3<=M,N<=20):最后M行,每行给出A在该行的N个元素的值.数字间以空格分隔.

HDU 1542 Atlantis (线段树求矩阵覆盖面积)

题意:给你n个矩阵求覆盖面积. 思路:看了别人的结题报告 给定一个矩形的左下角坐标和右上角坐标分别为:(x1,y1).(x2,y2),对这样的一个矩形,我们构造两条线段,一条定位在x1,它在y坐标的区间是[y1,y2],并且给定一个cover域值为1:另一条线段定位在x2,区间一样是[y1,y2],给定它一个cover值为-1.根据这样的方法对每个矩形都构造两个线段,最后将所有的线段根据所定位的x从左到右进行排序 #include <iostream> #include <stdio.h

Armadillo之求矩阵的逆(inverse)

求一个矩阵的逆(inverse or multiplicative inverse)使用矩阵的.i()方法或用inv()函数 m.i() //返回m的逆 1 若m不是方正的(square),则函数抛出std::logic_error异常. 2 如果m是奇异的(singular),则输出的矩阵将被重置,且抛出std::runtime_error异常 inv(m)   //返回m的逆 inv(A,m) //A被设为m的逆 1 若m不是方正的(square),则函数抛出std::logic_error

08-2. 求矩阵的局部极大值(15)

给定M行N列的整数矩阵A,如果A的非边界元素A[i][j]大于相邻的上下左右4个元素,那么就称元素A[i][j]是矩阵的局部极大值.本题要求给定矩阵的全部局部极大值及其所在的位置. 输入格式: 输入在第1行中给出矩阵A的行数M和列数N(3<=M,N<=20):最后M行,每行给出A在该行的N个元素的值.数字间以空格分隔. 输出格式: 每行按照“元素值 行号 列号”的格式输出一个局部极大值,其中行.列编号从1开始.要求按照行号递增输出:若同行有超过1个局部极大值,则该行按列号递增输出.若没有局部极

JAVA 基础编程练习题29 【程序 29 求矩阵对角线之和】

29 [程序 29 求矩阵对角线之和] 题目:求一个 3*3 矩阵对角线元素之和 程序分析:利用双重 for 循环控制输入二维数组,再将 a[i][i]累加后输出. package cskaoyan; public class cskaoyan29 { @org.junit.Test public void diagonal() { java.util.Scanner in = new java.util.Scanner(System.in); int[][] arr = new int[3][

论如何求矩阵的逆?先看看基础芝士!

这是关于矩阵的一个bugblog (如果觉得格式看不下去请移步:洛咕) 矩阵求逆是个有趣(但暂且不知道有什么神奇运用)的东西, 不过矩阵这玩意儿貌似和线性代数以及向量之类的东西相关,所以学了绝对不亏 xiao 另外,本篇blog 并不一定毫无错误,甚至可能会有些理解上的小偏差,所以请各位观看的神仙及时指出好让作者修改精进,谢谢. 还有矩阵求逆的两种方法将会放在最后讲解 想要学会矩阵求逆的话,首先你得了解几个关于矩阵的概念以及名称的含义 (当然如果你知道这些概念的话可以直接往下跳) 基本概念 1.

结对开发二——求矩阵子矩阵和的最大

一.开发思路 先设计一个3行4列的矩阵. 然后将12行的每一列相加作为第4行. 将23行的每一列相加作为第5行. 将123行的每一列作为第六行. 然后列出每一行的子数组求出最大值. 最后比较每一行的最大值的大小,求出最终结果. 二.开发代码 #include<iostream.h>int main(){int x,y,n,m;int s[10][20];// int a[10][20];int sum[10][20];cout<<"请输入3行4列的矩阵:"<

算法学习之动态规划(求矩阵连乘最小相乘次数)

基本思想:动态规划算法与分治法类似,其基本思想是将带求解的问题划分成若干个独立子问题,根据求得子问题的解合并而得到原问题的解.而动态规划划分的子问题往往不是相互独立的,因此若采用同分治法相同的求解问题的方法会导致大量的子问题被重复计算,为了避免这种情况发生,我们可以用一个表来记录我们求得的子问题的解,无论该子问题的解以后是否会用到,只要被计算,就将其填入表中.这便是动态规划的基本思想. 求解的基本步骤: (1)找出最优解的性质,并刻画其结构特征. (2)递归的定义最优值. (3)以自底向上的方式