CUDA中的常量内存__constant__

2023-11-03

GPU包含数百个数学计算单元,具有强大的处理运算能力,可以强大到计算速率高于输入数据的速率,即充分利用带宽,满负荷向GPU传输数据还不够它计算的。CUDA C除全局内存和共享内存外,还支持常量内存,常量内存用于保存在核函数执行期间不会发生变化的数据,使用常量内存在一些情况下,能有效减少内存带宽,降低GPU运算单元的空闲等待。


使用常量内存提升性能


使用常量内存可以提升运算性能的原因如下:

  • 对常量内存的单次读操作可以广播到其他的“邻近(nearby)”线程,这将节约15次读取操作;
  • 高速缓存。常量内存的数据将缓存起来,因此对于相同地址的连续操作将不会产生额外的内存通信量;
在CUDA架构中,线程束是指一个包含32个线程的集合,这个线程集合被“编织在一起”并且以“步调一致(Lockstep)”的形式执行。
当处理常量内存时,NVIDIA硬件将把单次内存读取操作广播到每个半线程束(Half-Warp)。在半线程束中包含16个线程,即线程束中线程数量的一半。如果在半线程束中的每个线程从常量内存的相同地址上读取数据,那么GPU只会产生一次读取请求并在随后将数据广播到每个线程。如果从常量内存中读取大量数据,那么这种方式产生的内存流量只是使用全局内存时的1/16。


常量内存的声明

为普通变量分配内存时是先声明一个指针,然后通过cudaMalloc()来为指针分配GPU内存。而当我们将其改为常量内存时,则要将这个声明修改为在常量内存中静态地分配空间。我们不再需要对变量指针调用cudaMalloc()或者cudaFree(),而是在编译时为这个变量(如一个数组)提交固定的大小。首先用“___constant_”声明一个常量内存变量,然后使用cudaMemcpyToSymbol(而不是cudaMemcpy)把数据从主机拷贝到设备GPU中。

常量内存使用示例

以下程序用CUDA+OpenCv实现一个简单场景的光线跟踪,光线跟踪是从三维场景生成二维图像的一种方式。主要思想为:在场景中选择一个位置放上一台假想的相机,该相机包含一个光传感器来生成图像,需要判断那些光将接触到这个传感器。图像中每个像素与命中传感器的光线有相同的颜色和强度。传感器中命中的光线可能来自场景中的任意位置,想象从该像素发出一道射线进入场景中,跟踪该光线穿过场景,直到光线命中某个物体。代码实现:
#include "cuda_runtime.h"
#include <highgui/highgui.hpp>
#include <time.h>

using namespace cv;

#define INF 2e10f  
#define rnd(x) (x*rand()/RAND_MAX)  
#define SPHERES 100 //球体数量
#define DIM 1024    //图像尺寸

struct Sphere
{
	float r, g, b;
	float radius;
	float x, y, z;

	__device__ float hit(float ox, float oy, float *n)
	{
		float dx = ox - x;
		float dy = oy - y;

		if (dx*dx + dy*dy < radius*radius)
		{
			float dz = sqrt(radius*radius - dx*dx - dy*dy);
			*n = dz / sqrt(radius*radius);
			return dz + z;
		}

		return -INF;
	}
};

// Sphere *s;
__constant__ Sphere s[SPHERES];

/************************************************************************/
//__global__ void rayTracing(unsigned char* ptr, Sphere* s)  
__global__ void rayTracing(unsigned char* ptr)
{
	int x = threadIdx.x + blockIdx.x * blockDim.x;
	int y = threadIdx.y + blockIdx.y * blockDim.y;
	int offset = x + y  * blockDim.x * gridDim.x;
	float ox = (x - DIM / 2);
	float oy = (y - DIM / 2);

	float r = 0, g = 0, b = 0;
	float maxz = -INF;
	for (int i = 0; i < SPHERES; i++)
	{
		float n;
		float t = s[i].hit(ox, oy, &n);
		if (t > maxz)
		{
			float fscale = n;
			r = s[i].r * fscale;
			g = s[i].g * fscale;
			b = s[i].b * fscale;
			maxz = t;
		}
	}

	ptr[offset * 3 + 2] = (int)(r * 255);
	ptr[offset * 3 + 1] = (int)(g * 255);
	ptr[offset * 3 + 0] = (int)(b * 255);
}
/************************************************************************/


int main(int argc, char* argv[])
{
	cudaEvent_t start, stop;
	cudaEventCreate(&start);
	cudaEventCreate(&stop);
	cudaEventRecord(start, 0);

	Mat bitmap = Mat(Size(DIM, DIM), CV_8UC3, Scalar::all(0));
	unsigned char *devBitmap;
	(cudaMalloc((void**)&devBitmap, 3 * bitmap.rows*bitmap.cols));
	//  cudaMalloc((void**)&s, sizeof(Sphere)*SPHERES);  

	Sphere *temps = (Sphere*)malloc(sizeof(Sphere)*SPHERES);

	srand(time(0));  //随机数种子

	for (int i = 0; i < SPHERES; i++)
	{
		temps[i].r = rnd(1.0f);
		temps[i].g = rnd(1.0f);
		temps[i].b = rnd(1.0f);
		temps[i].x = rnd(1000.0f) - 500;
		temps[i].y = rnd(1000.0f) - 500;
		temps[i].z = rnd(1000.0f) - 500;
		temps[i].radius = rnd(100.0f) + 20;
	}

	//  cudaMemcpy(s, temps, sizeof(Sphere)*SPHERES, cudaMemcpyHostToDevice);  
	cudaMemcpyToSymbol(s, temps, sizeof(Sphere)*SPHERES);
	free(temps);

	dim3 grids(DIM / 16, DIM / 16);
	dim3 threads(16, 16);
	//  rayTracing<<<grids, threads>>>(devBitmap, s);  
	rayTracing << <grids, threads >> > (devBitmap);

	cudaMemcpy(bitmap.data, devBitmap, 3 * bitmap.rows*bitmap.cols, cudaMemcpyDeviceToHost);

	cudaEventRecord(stop, 0);
	cudaEventSynchronize(stop);

	float elapsedTime;
	cudaEventElapsedTime(&elapsedTime, start, stop);

	printf("Processing time: %3.1f ms\n", elapsedTime);

	imshow("CUDA常量内存使用示例", bitmap);
	waitKey();
	cudaFree(devBitmap);
	//  cudaFree(s);  
	return 0;
}
程序里生成球体的大小和位置是随机的,为了产生随机数,加入了随机数种子srand()。运行效果: 

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

CUDA中的常量内存__constant__ 的相关文章

  • CUDA:如何直接在GPU上使用thrust::sort_by_key? [复制]

    这个问题在这里已经有答案了 Thrust 库可用于对数据进行排序 该调用可能如下所示 带有键和值向量 thrust sort by key d keys begin d keys end d values begin 在 CPU 上调用 d
  • 如何实现设备端CUDA虚拟功能?

    我发现 CUDA 不允许将具有虚拟函数的类传递到内核函数中 对于这个限制有什么解决方法吗 我真的很希望能够在内核函数中使用多态性 Thanks 罗伯特 克罗维拉评论中最重要的部分是 只需在设备上创建对象即可 所以记住这一点 我正在处理我有一
  • 使用非均匀节点优化 CUDA 内核插值

    原问题 我有以下内核使用非均匀节点执行插值 我想对其进行优化 global void interpolation cufftDoubleComplex Uj double points cufftDoubleComplex result i
  • nvcc fatal:安装 cuda 9.1+caffe+openCV 3.4.0 时不支持 gpu 架构“compute_20”

    我已经安装了CUDA 9 1 cudnn 9 1 opencv 3 4 0 caffe 当我尝试跑步时make all j8 in caffe目录下 出现这个错误 nvcc fatal 不支持的 GPU 架构 compute 20 我尝试过
  • 如何在 Linux 中分析 PyCuda 代码?

    我有一个简单的 经过测试的 pycuda 应用程序 正在尝试对其进行分析 我尝试过 NVidia 的 Compute Visual Profiler 它运行该程序 11 次 然后发出以下错误 NV Warning Ignoring the
  • 指定 NVCC 用于编译主机代码的编译器

    运行 nvcc 时 它始终使用 Visual C 编译器 cl exe 我怎样才能让它使用GCC编译器 设置CC环境变量到gcc没有修复它 我在可执行文件帮助输出中也找不到任何选项 在 Windows 上 NVCC 仅支持 Visual C
  • 是否可以在设备函数中调用cufft库调用?

    我在主机代码中使用 cuFFT 库调用 它们工作正常 但我想从内核调用 cuFFT 库 早期版本的 CUDA 没有这种支持 但是有了动态并行性 这可能吗 如果有任何关于如何实现这一目标的示例 那就太好了 尽管在 Kepler cc 3 5
  • 使用内置显卡,没有NVIDIA显卡,可以使用CUDA和Caffe库吗?

    使用内置显卡 没有 NVIDIA 显卡 可以使用 CUDA 和 Caffe 库吗 我的操作系统是 ubuntu 15 CPU为 Intel i5 4670 3 40GHz 4核 内存为12 0GB 我想开始学习深度学习 CUDA 适用于 N
  • 用于类型比较的 Boost 静态断言

    以下问题给我编译器错误 我不知道如何正确编写它 struct FalseType enum value false struct TrueType enum value true template
  • libstdc++.so.6 与 cuda 相关的链接器问题

    今天我在链接我编译的 cuda 内容时遇到了问题 我有一个最新的 debian 测试 w 2 6 32 3 amd64 我整天都在写我的代码 不时编译 没有问题 但在进行了较小的代码更改后 我收到以下错误 gcc o pa CUDA o h
  • Cuda Bayer/CFA 去马赛克示例

    我编写了一个 CUDA4 Bayer 去马赛克例程 但它比在 16 核 GTS250 上运行的单线程 CPU 代码慢 块大小是 16 16 图像暗淡是 16 的倍数 但更改此值并不会改善它 我做了什么明显愚蠢的事情吗 calling rou
  • 为什么numba cuda调用几次后运行速度变慢?

    我正在尝试如何在 numba 中使用 cuda 然而我却遇到了与我预想不同的事情 这是我的代码 from numba import cuda cuda jit def matmul A B C Perform square matrix m
  • 传递给 CUDA 的结构中的指针

    我已经搞砸了一段时间了 但似乎无法正确处理 我正在尝试将包含数组的对象复制到 CUDA 设备内存中 然后再复制回来 但当我遇到它时我会跨过那座桥 struct MyData float data int dataLen void copyT
  • 在linux上编译一个基本的OpenCV + Cuda程序

    我过去在linux上使用过opencv 但没有使用过cuda 几个月来我一直在与以下编译错误作斗争 在尝试了许多解决方案后 我放弃并使用 Windows 不过 我真的很想在 Linux 上工作 这是我用来编译 opencv gpu 网站上给
  • CUDA 估计 2D 网格数据的每块线程数和块数

    首先我要说的是 我已经仔细阅读了所有类似的问题 确定每个块的线程和每个网格的块 https stackoverflow com questions 4391162 cuda determining threads per block blo
  • __syncthreads() 死锁

    如果只有部分线程执行 syncthreads 会导致死锁吗 我有一个这样的内核 global void Kernel int N int a if threadIdx x
  • 设置最大 CUDA 资源

    我想知道是否可以设置 CUDA 应用程序的最大 GPU 资源 例如 如果我有一个 4GB GPU 但希望给定的应用程序只能访问 2GB 如果它尝试分配更多 就会失败 理想情况下 这可以在进程级别或 CUDA 上下文级别上设置 不 目前没有允
  • CUDA 常量内存是否应该被均匀地访问?

    我的 CUDA 应用程序的恒定内存小于 8KB 既然它都会被缓存 我是否需要担心每个线程访问相同的地址以进行优化 如果是 如何确保所有线程同时访问同一地址 既然它都会被缓存 我是否需要担心每个线程访问相同的地址以进行优化 是的 这缓存本身每
  • 尝试构建我的 CUDA 程序时出现错误 MSB4062

    当我尝试构建我的第一个 GPU 程序时 出现以下错误 有什么建议可能会出什么问题吗 错误 1 错误 MSB4062 Nvda Build CudaTasks SanitizePaths 任务 无法从程序集 C Program 加载 文件 M
  • 使用 CUDA 进行逐元素向量乘法

    我已经在 CUDA 中构建了一个基本内核来执行逐元素两个复向量的向量 向量乘法 内核代码插入如下 multiplyElementwise 它工作正常 但由于我注意到其他看似简单的操作 如缩放向量 在 CUBLAS 或 CULA 等库中进行了

随机推荐

  • matlab语音去除白噪声_基于的MATLAB的语音加噪去噪处理

    龙源期刊网 http www qikan com cn 基于的 MATLAB 的语音加噪去噪处理 作者 张大林 何威 李瑶瑶 来源 中国科技博览 2019 年第 01 期 摘 要 语音是语言的声学表现 是人类交流信息最自然 最有效 最方便的
  • 【SpringCloud】Spring cloud Alibaba Sentinel 降级规则

    文章目录 1 概述 2 服务降级 2 1 RT 2 2 异常比例 2 3 异常数 1 概述 本章是接着上一章讲解 SpringCloud Spring cloud Alibaba Sentinel 服务降级 阿里版本Hystrix 2 服务
  • 寻找URL、域名、网站名对应区别和组合关系

    URL URL由三部分组成 资源类型 存放资源的主机域名 资源文件名 也可认为由4部分组成 协议 主机 端口 路径 例如 百度一下 你就知道 http 协议 www 服务器 baidu com 域名 表示根目录 也就是平常我们文件夹的D 是
  • 傅里叶变换回顾与总结

    傅里叶变换回顾与总结对傅里叶变换进行回顾总结 遗忘 要用的时候回顾此浓缩版即可 内容来源于不同出处 函数名称 符号使用不是十分统一 一维二维表达同时存在 略表歉意 1 两个前提线性性 两个信号加权和输出为它们分别输出和的加权 权值为标量 时
  • openwrt无线中继WIFI的设置--WR703N

    主要是配置两个文件 一 vi etc config wireless 在 option disabled 1 这一行下面加入OpenWRT连接WIFI的配置 内容如下 config wifi iface wlan0 option devic
  • QGIS之十四连接PostGIS数据库

    背景 有时候我们需要用到qgis来连接PostGIS数据库进行一些可视化或者空间分析的操作 那我们来了解QGIS如何连接PostGIS数据库 步骤 1 新建连接 在qgis的浏览器窗口中找到PostGIS 右键新建连接 2 输入数据库参数
  • 埋点的机制

    埋点事件 所谓埋点事件 就是埋点需要采集的活动 activity 埋点一般会获取三种事件 曝光事件 页面停留事件 点击事件 曝光事件 主要记录页面被用户浏览次数 上报机制 用户成功进入一个页面时记录一次曝光事件 刷新一次页面也会上报一次 如
  • 使用R语言进行回归诊断

    人们提出所谓回归诊断的问题 其主要内容有 关于误差项是否满足 独立性 等方差性 正态性 选择线性模型是否合适 是否存在异常样本 回归分析的结果是否对某些样本依赖过重 也就是回归模型是否具有稳定性 自变量之间是否存在高度相关 即是否存在多重共
  • MySQL数据库增删改查

    前言 MySQL准确来说是一款开源关系型数据库管理系统 支持多种数据库类型 包括整型 字符型 日期 时间型等 它还支持BLOB 二进制大对象 和文本类型 使得存储各种类型的数据变得更加便捷 平时工作中主要操作无非是增删改查 本文将通过Nav
  • c++学习之虚析构和纯虚析构

    1 多态使用时 如果子类中有属性开辟到堆区 那么父类指针在释放时无法调用子类的析构代码 解决方法 将父类中的析构函数改为虚析构或者是纯虚析构 2 虚析构和纯虚析构共性 1 都可以解决父类指针无法释放子类对象的问题 2 都需要有具体的函数实现
  • vue.js水平时间轴_用Vue.js制作的简单水平时间轴组件

    vue js水平时间轴 Vue水平时间线 Vue Horizontal Timeline a simple horizontal timeline component made with Vue js 一个由Vue js制作的简单水平时间轴
  • happens-before原则与内存屏障

    1 happens before原则定义 编译器和处理器会对我们程序优化而进行指令重排 但需要保证前一个操作结果对后一个依赖操作可见 其实只是在单线程下能保证 否则就禁止指令重排 1 1 指令重排带来的问题 虽然指令重排满足happens
  • Angular 1.0 入门指南

    Angular 1 0 入门指南 1 angular 1 0 特点 数据双向绑定MVVM 隔离作用域 2 Angular 的作用域 scope scope rootScope 先来看一下 angular 的一般使用格式 作用域定义 模块注入
  • 解析最全的 Aspose.Words功能介绍,看这篇就够了

    Aspose Words 为用户提供了广泛的功能 用户可以执行大量与文档相关的任务 从简单地将文档从一种受支持的格式转换为另一种格式并在转换过程中修改这些文档到业务任务 例如创建结构化和视觉上吸引人的文档或自动报告 现代文档格式和标准很复杂
  • nslookup DNS 域名解析 故障排除

    nslookup是一个可以监测DNS服务器是否正常运行 且是否能正确解析域名的工具 参考文章 http www t086 com article 5138 常用方法 nslookup 某一域名A 服务器 正在工作的DNS服务器主机名 Add
  • 如何使用Jar命令将指定文件夹打包成Jar包

    一 场景描述 通常我们在进行项目开发的时候都会使用很多第三方封装的依赖 那么有时候团队内部也会编写一些工具类需要打包成Jar包供其他团队或项目使用 本文主要介绍如果使用jar命令打包指定文件夹下的文件 生成非可执行Jar包 二 Jar命令
  • JavaWeb笔记——JDBC

    1 JDBC综述 在开发中我们使用的是java语言 那么势必要通过java语言操作数 据库中的数据 这就是接下来要学习的JDBC 一套标准接口 1 SQL语句是操作数据库的唯一手段 容易犯错误的几个认知 Navicat与MySQL的关系 前
  • 中移链(基于EOS)DDC-SDK实战-如何集成中移链DDC-SDK

    本文档是关于中移链 DDC SDK 实战 即如何集成基于 EOS 的中移链 DDC SDK 的操作指南 适用于 BSN 开放联盟链 中移链 DDC SDK 开发者 帮助读者了解如何以平台方的角色集成中移链 DDC SDK 前言 2021年1
  • 7--归并排序

    思想 将待排序序列分为两个子序列 再将两个子序列递归的继续分下去 直到序列有序 即序列中只有一个元素 再把所有有序子序列逐层合并为一个整体有序序列 每次合并是将两个有序表合并成一个有序表 图示 具体实现 把待排序序列分为两个子序列 然后让子
  • CUDA中的常量内存__constant__

    GPU包含数百个数学计算单元 具有强大的处理运算能力 可以强大到计算速率高于输入数据的速率 即充分利用带宽 满负荷向GPU传输数据还不够它计算的 CUDA C除全局内存和共享内存外 还支持常量内存 常量内存用于保存在核函数执行期间不会发生变