共享内存实现大规模点积

项目打包下载
  1 /*
  2 * Copyright 1993-2010 NVIDIA Corporation.  All rights reserved.
  3 *
  4 * NVIDIA Corporation and its licensors retain all intellectual property and
  5 * proprietary rights in and to this software and related documentation.
  6 * Any use, reproduction, disclosure, or distribution of this software
  7 * and related documentation without an express license agreement from
  8 * NVIDIA Corporation is strictly prohibited.
  9 *
 10 * Please refer to the applicable NVIDIA end user license agreement (EULA)
 11 * associated with this source code for terms and conditions that govern
 12 * your use of this NVIDIA software.
 13 *
 14 */
 15
 16
 17 #include "../common/book.h"
 18 #include "cuda.h"
 19 #include "cuda_runtime.h"
 20 #include "device_launch_parameters.h"
 21 #include "device_functions.h"
 22 #define imin(a,b) (a<b?a:b)
 23
 24 const int N = 33 * 1024;
 25 const int threadsPerBlock = 256;//每个线程块启动256个线程
 26 const int blocksPerGrid = imin(32, (N + threadsPerBlock - 1) / threadsPerBlock);
 27
 28 /*
 29 内核函数
 30 */
 31 __global__ void dot(float *a, float *b, float *c) {
 32     //设备上的共享内存,在每个线程块中都有
 33     __shared__ float cache[threadsPerBlock];
 34     int tid = threadIdx.x + blockIdx.x * blockDim.x;
 35     //线程块中的线程索引赋值给缓冲索引
 36     int cacheIndex = threadIdx.x;
 37
 38     float   temp = 0;
 39     //当前索引小于总共的数据量时
 40     while (tid < N) {
 41         temp += a[tid] * b[tid];
 42         //步长为活动的线程数
 43         tid += blockDim.x * gridDim.x;
 44     }//如果再次在这个线程上执行时,temp中存放的是上次计算的值,也就是再次计算的结果是加上上次计算的值
 45
 46     // set the cache values
 47     //将结果存放在共享存储中,每个线程对应一个共享存储
 48     cache[cacheIndex] = temp;
 49
 50     /*
 51     synchronize threads in this block
 52     同步操作,使得每个线程都计算完毕,再继续后面的操作
 53     */
 54     __syncthreads();
 55
 56
 57     // for reductions, threadsPerBlock must be a power of 2
 58     // because of the following code
 59     /*
 60     归约操作
 61     blockDim.x / 2块中的线程个数除以2,相当于取中间值
 62     因为这个blockDim是2的倍数,所以不会有除不尽的情况
 63     */
 64     int i = blockDim.x / 2;
 65     while (i != 0) {
 66         if (cacheIndex < i)
 67             /*
 68             前半部分和后半部分对应的第一个相加,以此类推
 69             */
 70             cache[cacheIndex] += cache[cacheIndex + i];
 71         /*
 72         同步使得所有线程完成了第一次归约在进行下一次归约
 73         */
 74         __syncthreads();
 75         //下次归约的中间值
 76         i /= 2;
 77     }
 78     //最终结果存放在cache[0]中,所以将cache[0]赋给以块索引为下标的数组中
 79     if (cacheIndex == 0)
 80         c[blockIdx.x] = cache[0];
 81 }
 82
 83
 84 int main(void) {
 85     float   *a, *b, c, *partial_c;
 86     float   *dev_a, *dev_b, *dev_partial_c;
 87
 88     // allocate memory on the cpu side
 89     a = (float*)malloc(N*sizeof(float));
 90     b = (float*)malloc(N*sizeof(float));
 91     partial_c = (float*)malloc(blocksPerGrid*sizeof(float));
 92
 93     // allocate the memory on the GPU
 94     HANDLE_ERROR(cudaMalloc((void**)&dev_a,
 95         N*sizeof(float)));
 96     HANDLE_ERROR(cudaMalloc((void**)&dev_b,
 97         N*sizeof(float)));
 98     HANDLE_ERROR(cudaMalloc((void**)&dev_partial_c,
 99         blocksPerGrid*sizeof(float)));
100
101     // fill in the host memory with data
102     for (int i = 0; i<N; i++) {
103         a[i] = i;
104         b[i] = i * 2;
105     }
106
107     // copy the arrays ‘a‘ and ‘b‘ to the GPU
108     HANDLE_ERROR(cudaMemcpy(dev_a, a, N*sizeof(float),
109         cudaMemcpyHostToDevice));
110     HANDLE_ERROR(cudaMemcpy(dev_b, b, N*sizeof(float),
111         cudaMemcpyHostToDevice));
112
113     dot << <blocksPerGrid, threadsPerBlock > >>(dev_a, dev_b, dev_partial_c);
114
115     // copy the array ‘c‘ back from the GPU to the CPU
116     HANDLE_ERROR(cudaMemcpy(partial_c, dev_partial_c,
117         blocksPerGrid*sizeof(float),
118         cudaMemcpyDeviceToHost));
119
120     /* 在主机上完成最后的相加工作
121     这样是为了避免简单的工作在GPU上造成的资源浪费
122     因为好多资源处于空闲状态
123     */
124     c = 0;
125     for (int i = 0; i<blocksPerGrid; i++) {
126         c += partial_c[i];
127     }
128
129 #define sum_squares(x)  (x*(x+1)*(2*x+1)/6)
130     printf("Does GPU value %.6g = %.6g?\n", c, 2 * sum_squares((float)(N - 1)));
131
132     // free memory on the gpu side
133     HANDLE_ERROR(cudaFree(dev_a));
134     HANDLE_ERROR(cudaFree(dev_b));
135     HANDLE_ERROR(cudaFree(dev_partial_c));
136
137     // free memory on the cpu side
138     free(a);
139     free(b);
140     free(partial_c);
141 }
				
时间: 2024-07-31 23:03:02

共享内存实现大规模点积的相关文章

Linux环境编程之共享内存区(一):共享内存区简介

Spark生态圈,也就是BDAS(伯克利数据分析栈),是伯克利APMLab实验室精心打造的,力图在算法(Algorithms).机器(Machines).人(People)之间通过大规模集成,来展现大数据应用的一个平台,其核心引擎就是Spark,其计算基础是弹性分布式数据集,也就是RDD.通过Spark生态圈,AMPLab运用大数据.云计算.通信等各种资源,以及各种灵活的技术方案,对海量不透明的数据进行甄别并转化为有用的信息,以供人们更好的理解世界.Spark生态圈已经涉及到机器学习.数据挖掘.

Linux共享内存使用常见陷阱与分析

所谓共享内存就是使得多个进程可以访问同一块内存空间,是最快的可用IPC形式.是针对其他通信机制运行效率较低而设计的.往往与其它通信机制,如信号量结合使用,来达到进程间的同步及互斥.其他进程能把同一段共享内存段“连接到”他们自己的地址空间里去.所有进程都能访问共享内存中的地址.如果一个进程向这段共享内存写了数据,所做的改动会即时被有访问同一段共享内存的其他进程看到.共享内存的使用大大降低了在大规模数据处理过程中内存的消耗,但是共享内存的使用中有很多的陷阱,一不注意就很容易导致程序崩溃. 超过共享内

php 共享内存

转:php 共享内存 共享内存主要用于进程间通信 php中的共享内存有两套扩展可以实现 1.shmop  编译时需要开启 --enable-shmop 参数 实例: $shm_key = ftok(__FILE__, 't'); /** 开辟一块共享内存 int $key , string $flags , int $mode , int $size $flags: a:访问只读内存段 c:创建一个新内存段,或者如果该内存段已存在,尝试打开它进行读写 w:可读写的内存段 n:创建一个新内存段,如

Linux --进程间通信--共享内存

一.共享内存 共享内存是最高效的通信方式,因为不需要一个进程先拷贝到内核,另一个进程在存内核中读取. 二. ipcs -m 查看共享内存 ipcrm -m 删除共享内存 三.主要函数 shmget 创建 shmctl 删除 shmat 挂接 shmdt 取消挂接 ********* man 函数名 查看***** 四.代码实现 comm.h   1 #pragma once   2 #include<stdio.h>   3 #include<stdlib.h>   4 #incl

linux共享内存之mmap

这应该可以算得上是IPC的一种,虽然效率可能并没有其它IPC方式高. 看到map很容易联想到映射.的确,mmap就是一种映射方式,将打开的文件和一段连续的内存做映射.使得对内存进行操作即可以实现对文件的读写,反过来,也就是说,可以通过这种方式来达到进程通信. mmap系列涉及三个函数. void * mmap(void *buf, size_t len, int prot, int flag, int fd, off_t offset); 此函数建立一个共享内存,prot即为权限,可选值有PRO

linux 共享内存实现

说起共享内存,一般来说会让人想起下面一些方法:1.多线程.线程之间的内存都是共享的.更确切的说,属于同一进程的线程使用的是同一个地址空间,而不是在不同地址空间之间进行内存共享:2.父子进程间的内存共享.父进程以MAP_SHARED|MAP_ANONYMOUS选项mmap一块匿名内存,fork之后,其子孙进程之间就能共享这块内存.这种共享内存由于受到进程父子关系的限制,一般较少使用:3.mmap文件.多个进程mmap到同一个文件,实际上就是大家在共享文件page cache中的内存.不过文件牵涉到

Linux 进程间共享内存 SYSTEMV

#include <sys/ipc.h> #include <sys/shm.h> int shmget(key_t key, int size, int shmflag) key取值为IPC_PRIVATE时,shmflag应为IPC_CREAT,则新建共享内存key取值不为IPC_PRIVATE则应为已创建的key值,shmflag不应包含IPC_CREAT和IPC_EXCL,且大小小于等于原共享内存大小成功则返回共享内存id,失败返回-1 void *shmat(int sh

(转载)linux下的僵尸进程处理SIGCHLD信号Linux环境进程间通信(五): 共享内存(下)

Linux环境进程间通信(五): 共享内存(下) 在共享内存(上)中,主要围绕着系统调用mmap()进行讨论的,本部分将讨论系统V共享内存,并通过实验结果对比来阐述两者的异同.系统V共享内存指的是把所有共享数据放在共享内存区域(IPC shared memory region),任何想要访问该数据的进程都必须在本进程的地址空间新增一块内存区域,用来映射存放共享数据的物理内存页面. 系统调用mmap()通过映射一个普通文件实现共享内存.系统V则是通过映射特殊文件系统shm中的文件实现进程间的共享内

撸代码--linux进程通信(基于共享内存)

1.实现亲缘关系进程的通信,父写子读 思路分析:1)首先我们须要创建一个共享内存. 2)父子进程的创建要用到fork函数.fork函数创建后,两个进程分别独立的执行. 3)父进程完毕写的内容.同一时候要保证子进程退出后,在删除共享内存. 4)子进程完毕读的内容. 效果展示:                 代码展示:           #include <string.h> #include <unistd.h> #include <sys/types.h> #inc