【cuda学习日记】4.3 结构体数组与数组结构体
4.3 数组结构体(AoS)和结构体数组(SoA)
AoS方法进行存储
struct innerStruct{float x;float y;
};struct innerStruct myAOS[N];
SoA方法来存储数据
struct innerArray{float x[N];float y[N];
};struct innerArray moa;
如图说明了AoS和SoA方法的内存布局,用AoS模式在GPU上存储示例数据并执行一个只有x字段的应用程序,将导致50%的带宽损失

4.3.1 简单示例AoS
#include <cuda_runtime.h>
#include <stdio.h>
#include "../common/common.h"
#include <stdlib.h>
#include <time.h>
#include <string.h>
#include <windows.h>#define LEN 1 << 20struct innerStruct{float x;float y;
};struct innerArray{float x[LEN];float y[LEN];
};__global__ void testInnerStruct(innerStruct *data, innerStruct *result, const int n){unsigned int i = blockIdx.x * blockDim.x + threadIdx.x;if (i < n){innerStruct tmp = data[i];tmp.x += 10.f;tmp.y += 20.f;result[i] = tmp;}
}__global__ void warmup(innerStruct *data, innerStruct *result, const int n){unsigned int i = blockIdx.x * blockDim.x + threadIdx.x;if (i < n){innerStruct tmp = data[i];tmp.x += 10.f;tmp.y += 20.f;result[i] = tmp;}
}void testInnerStructHost(innerStruct *data, innerStruct *result, const int n){for (int i = 0; i < n ; i ++){innerStruct tmp = data[i];tmp.x += 10.f;tmp.y += 20.f;result[i] = tmp;}
}void initialInnerStruct(innerStruct *ip, int size)
{for (int i = 0; i < size; i++){ip[i].x = (float)(rand() & 0xFF) / 100.0f;ip[i].y = (float)(rand() & 0xFF) / 100.0f;}return;
}void checkInnerStruct(innerStruct *hostRef, innerStruct *gpuRef, const int N)
{double epsilon = 1.0E-8;bool match = 1;for (int i = 0; i < N; i++){if (abs(hostRef[i].x - gpuRef[i].x) > epsilon){match = 0;printf("different on %dth element: host %f gpu %f\n", i,hostRef[i].x, gpuRef[i].x);break;}if (abs(hostRef[i].y - gpuRef[i].y) > epsilon){match = 0;printf("different on %dth element: host %f gpu %f\n", i,hostRef[i].y, gpuRef[i].y);break;}}if (!match) printf("Arrays do not match.\n\n");
}int main(int argc, char ** argv){int dev = 0;cudaSetDevice(dev);cudaDeviceProp deviceprop;CHECK(cudaGetDeviceProperties(&deviceprop,dev));printf("device %d: %s \n", dev, deviceprop.name);int nElem = LEN;size_t nBytes = nElem * sizeof(innerStruct);innerStruct *h_A = (innerStruct *)malloc(nBytes);innerStruct *hostRef = (innerStruct *)malloc(nBytes);innerStruct *gpuRef = (innerStruct *)malloc(nBytes);initialInnerStruct(h_A, nElem);testInnerStructHost(h_A, hostRef, nElem);innerStruct *d_A, *d_C;cudaMalloc((innerStruct**)&d_A, nBytes);cudaMalloc((innerStruct**)&d_C, nBytes);cudaMemcpy(d_A, h_A, nBytes,cudaMemcpyHostToDevice);int blocksize = 128;if (argc > 1) blocksize = atoi(argv[1]);dim3 block(blocksize,1);dim3 grid((nElem + block.x - 1)/block.x, 1);Timer timer;timer.start();warmup<<<grid,block>>>(d_A, d_C, nElem);cudaDeviceSynchronize();timer.stop();float elapsedTime = timer.elapsedms();printf("warmup <<<%4d, %4d>>> elapsed %f ms \n", grid.x, block.x, elapsedTime);timer.start();testInnerStruct<<<grid,block>>>(d_A, d_C, nElem);cudaDeviceSynchronize();timer.stop();elapsedTime = timer.elapsedms();printf("testInnerStruct <<<%4d, %4d>>> elapsed %f ms \n", grid.x, block.x, elapsedTime);cudaMemcpy(gpuRef, d_C, nBytes, cudaMemcpyDeviceToHost);checkInnerStruct(hostRef, gpuRef, nElem);cudaFree(d_A);cudaFree(d_C);free(h_A);free(hostRef);free(gpuRef);cudaDeviceReset();return 0;
}
用NCU查看加载内存效率,只有50%:
smsp__sass_average_data_bytes_per_sector_mem_global_op_ld.pct [%] 50
执行时间:
testInnerStruct <<<8192, 128>>> elapsed 0.036864 ms
4.3.1 简单示例SoA
#include <cuda_runtime.h>
#include <stdio.h>
#include "../common/common.h"
#include <stdlib.h>
#include <time.h>
#include <string.h>
#include <windows.h>#define LEN 1 << 20struct innerStruct{float x;float y;
};struct innerArray{float x[LEN];float y[LEN];
};__global__ void testInnerArray( innerArray *data, innerArray *result, const int n){unsigned int i = blockIdx.x * blockDim.x + threadIdx.x;if (i < n) {float tmpx = data -> x[i];float tmpy = data -> y[i];tmpx += 10.0f;tmpy += 20.0f;result -> x[i] = tmpx;result -> y[i] = tmpy;}
}__global__ void warmup( innerArray *data, innerArray *result, const int n){unsigned int i = blockIdx.x * blockDim.x + threadIdx.x;if (i < n) {float tmpx = data -> x[i];float tmpy = data -> y[i];tmpx += 10.0f;tmpy += 20.0f;result -> x[i] = tmpx;result -> y[i] = tmpy;}
}// functions for inner array outer struct
void initialInnerArray(innerArray *ip, int size)
{for (int i = 0; i < size; i++){ip->x[i] = (float)( rand() & 0xFF ) / 100.0f;ip->y[i] = (float)( rand() & 0xFF ) / 100.0f;}return;
}void testInnerArrayHost(innerArray *A, innerArray *C, const int n)
{for (int idx = 0; idx < n; idx++){C->x[idx] = A->x[idx] + 10.f;C->y[idx] = A->y[idx] + 20.f;}return;
}void checkInnerArray(innerArray *hostRef, innerArray *gpuRef, const int N)
{double epsilon = 1.0E-8;bool match = 1;for (int i = 0; i < N; i++){if (abs(hostRef->x[i] - gpuRef->x[i]) > epsilon){match = 0;printf("different on x %dth element: host %f gpu %f\n", i,hostRef->x[i], gpuRef->x[i]);break;}if (abs(hostRef->y[i] - gpuRef->y[i]) > epsilon){match = 0;printf("different on y %dth element: host %f gpu %f\n", i,hostRef->y[i], gpuRef->y[i]);break;}}if (!match) printf("Arrays do not match.\n\n");
}int main(int argc, char ** argv){int dev = 0;cudaSetDevice(dev);cudaDeviceProp deviceprop;CHECK(cudaGetDeviceProperties(&deviceprop,dev));printf("device %d: %s \n", dev, deviceprop.name);int nElem = LEN;size_t nBytes = sizeof(innerArray);innerArray *h_A = (innerArray *)malloc(nBytes);innerArray *hostRef = (innerArray *)malloc(nBytes);innerArray *gpuRef = (innerArray *)malloc(nBytes);initialInnerArray(h_A, nElem);testInnerArrayHost(h_A, hostRef, nElem);innerArray *d_A, *d_C;cudaMalloc((innerArray**)&d_A, nBytes);cudaMalloc((innerArray**)&d_C, nBytes);cudaMemcpy(d_A, h_A, nBytes,cudaMemcpyHostToDevice);int blocksize = 128;if (argc > 1) blocksize = atoi(argv[1]);dim3 block(blocksize,1);dim3 grid((nElem + block.x - 1)/block.x, 1);Timer timer;timer.start();warmup<<<grid,block>>>(d_A, d_C, nElem);cudaDeviceSynchronize();timer.stop();float elapsedTime = timer.elapsedms();printf("warmup <<<%4d, %4d>>> elapsed %f ms \n", grid.x, block.x, elapsedTime);timer.start();testInnerArray<<<grid,block>>>(d_A, d_C, nElem);cudaDeviceSynchronize();timer.stop();elapsedTime = timer.elapsedms();printf("testInnerArray <<<%4d, %4d>>> elapsed %f ms \n", grid.x, block.x, elapsedTime);cudaMemcpy(gpuRef, d_C, nBytes, cudaMemcpyDeviceToHost);checkInnerArray(hostRef, gpuRef, nElem);cudaFree(d_A);cudaFree(d_C);free(h_A);free(hostRef);free(gpuRef);cudaDeviceReset();return 0;
}
NCU查看内存加载效率:
smsp__sass_average_data_bytes_per_sector_mem_global_op_ld.pct [%] 100
优化设备内存带宽利用率有两个目标:
·对齐及合并内存访问,以减少带宽的浪费
·足够的并发内存操作,以隐藏内存延迟
相关文章:
【cuda学习日记】4.3 结构体数组与数组结构体
4.3 数组结构体(AoS)和结构体数组(SoA) AoS方法进行存储 struct innerStruct{float x;float y; };struct innerStruct myAOS[N];SoA方法来存储数据 struct innerArray{float x[N];float y[N]; };struct innerArray moa;如图说明…...
2025最新高维多目标优化:基于城市场景下无人机三维路径规划的导航变量的多目标粒子群优化算法(NMOPSO),MATLAB代码
一、基于导航变量的多目标粒子群优化算法(NMOPSO)介绍 基于导航变量的多目标粒子群优化算法(Navigation variable-based multi-objective particle swarm optimization,NMOPSO)是2025年提出的一种用于无人机路径规划的…...
数字IC后端设计实现OCC(On-chip Clock Controller)电路介绍及时钟树综合案例
数字IC后端时钟树综合专题(OCC电路案例分享) 复杂时钟设计时钟树综合(clock tree synthesis)常见20个典型案例 1、什么是OCC? 片上时钟控制器(On-chip Clock Controllers ,OCC),也称为扫描时钟控制器(Scan Clock Con…...
Linux内核,slub分配流程
我们根据上面的流程图,依次看下slub是如何分配的 首先从kmem_cache_cpu中分配,如果没有则从kmem_cache_cpu的partial链表分配,如果还没有则从kmem_cache_node中分配,如果kmem_cache_node中也没有,则需要向伙伴系统申请…...
本地部署DeepSeek-R1(Ollama+Docker+OpenWebUI知识库)
安装Ollama 打开 Ollama官网 https://ollama.com/下载安装 Ollama服务默认只允许本机访问,修改允许其它主机访问 OLLAMA_HOST0.0.0.0 ollama serve也可以添加系统环境变量 都知道模型体积很大,顺便也通过环境变量修改模型存放位置,我这…...
Java 实现快速排序算法:一条快速通道,分而治之
大家好,今天我们来聊聊快速排序(QuickSort)算法,这个经典的排序算法被广泛应用于各种需要高效排序的场景。作为一种分治法(Divide and Conquer)算法,快速排序的效率在平均情况下非常高ÿ…...
20250223下载并制作RTX2080Ti显卡的显存的测试工具mats
20250223下载并制作RTX2080Ti显卡的显存的测试工具mats 2025/2/23 23:23 缘起:我使用X99的主板,使用二手的RTX2080Ti显卡【显存22GB版本,准备学习AI的】 但是半年后发现看大码率的视频容易花屏,最初以为是WIN10经常更换显卡/来回更…...
element-ui的组件使用
1. 安装 Element UI(在文件夹最上面输入cmd进入dos窗口,然后输入安装指令 npm install element-ui --save) 2.在main.js文件全局引入(main.js文件负责 全局注册 ),在该文件注册的所有组件在其他文件都能直接调用,一般…...
医疗AI领域中GPU集群训练的关键技术与实践经验探究(上)
医疗AI领域中GPU集群训练的关键技术与实践经验探究(上) 一、引言 1.1 研究背景与意义 在科技飞速发展的当下,医疗 AI 作为人工智能技术与医疗领域深度融合的产物,正引领着医疗行业的深刻变革。近年来,医疗 AI 在疾病诊断、药物研发、健康管理等诸多方面取得了显著进展,…...
详解Redis淘汰策略
引言 Redis 是一个高性能的内存数据库,广泛应用于缓存系统、消息队列等场景。当 Redis 的内存达到限制时,需要根据一定的策略来淘汰数据,以便腾出空间给新数据。本文将深入解析 Redis 的内存淘汰机制,帮助更好地配置 Redis&#…...
HarmonyOS 5.0应用开发——鸿蒙接入高德地图实现POI搜索
【高心星出品】 文章目录 鸿蒙接入高德地图实现POI搜索运行结果:准备地图编写ArkUI布局来加载HTML地图 鸿蒙接入高德地图实现POI搜索 在当今数字化时代,地图应用已成为移动设备中不可或缺的一部分。随着鸿蒙系统的日益普及,如何在鸿蒙应用中…...
nginx关于配置SSL后启动失败原因分析
在配置SSL后,启动./nginx失败,报错提示如下: nginx: [emerg] the "ssl" parameter requires ngx_http_ssl_module in /usr/local/nginx-1.27.4/conf/nginx.conf:36 这个错误提示表在配置nginx启用SSL时,nginx未启用 ng…...
【自学嵌入式(9)ESP8266网络服务器的使用】
ESP8266网络服务器的使用 ESP8266WiFi 库① WiFiClass② WiFiClient③ WiFiServer④ WiFiUDP ESP8266WiFiMulti 库① WiFiMulti ESP8266WebServer 库① ESP8266WebServer 网络服务器实例在浏览器中控制ESP8266指示灯将开发板引脚状态显示在网页中 在之前的文章中,曾…...
危化品经营单位安全管理人员的职责及注意事项
危化品经营单位安全管理人员肩负着保障经营活动安全的重要责任,以下是其主要职责及注意事项: 职责 1. 安全制度建设与执行:负责组织制定本单位安全生产规章制度、操作规程和生产安全事故应急救援预案,确保这些制度符合国家相关法…...
项目实战--网页五子棋(匹配模块)(5)
上期我们实现了websocket后端的大部分代码,这期我们实现具体的匹配逻辑 1. 定义Mather类 我们新建一个Matcher类用来实现匹配逻辑 Component public class Matcher {//每个匹配队列代表不同的段位,这里约定每一千分为一个段位private ArrayList<Queue<User…...
mysql 迁移到人大金仓数据库
我是在windows上安装了客户端工具 运行数据库迁移工具 打开 在浏览器输入http://localhost:54523/ 账号密码都是kingbase 添加mysql源数据库连接 添加人大金仓目标数据库 添加好的两个数据库连接 新建迁移任务 选择数据库 全选 迁移中 如果整体迁移不过去可以单个单个或者几个…...
uniapp 网络请求封装(uni.request 与 uView-Plus)
一、背景 在开发项目中,需要经常与后端服务器进行交互;为了提高开发效率和代码维护性,以及降低重复性代码,便对网络请求进行封装统一管理。 二、创建环境文件 2.1、根目录新建utils文件夹,utils文件夹内新建env.js文…...
计算机网络与通讯知识总结
计算机网络与通讯知识总结 基础知识总结 1)FTP:文件传输 SSH:远程登录 HTTP:网址访问 2)交换机 定义:一种基于MAC地址实现局域网(LAN)内数据高速转发的网络设备,可为接入设备提供独享通信通道。 - 核心功能: 1.数据链路层(OSI第二层)工作,通过MAC地址…...
DPVS-2:单臂负载均衡测试
上一篇编译安装了DPVS,这一篇开启DPVS的负载均衡测试 : 单臂 FULL NAT模式 拓扑-单臂 单臂模式 DPVS 单独物理机 CLINET,和两个RS都是另一个物理机的虚拟机,它们网卡都绑定在一个桥上br0 , 二层互通。 启动DPVS …...
open webui 部署 以及解决,首屏加载缓慢,nginx反向代理访问404,WebSocket后端服务器链接失败等问题
项目地址:GitHub - open-webui/open-webui: User-friendly AI Interface (Supports Ollama, OpenAI API, ...) 选择了docker部署 如果 Ollama 在您的计算机上,请使用以下命令 docker run -d -p 3000:8080 --add-hosthost.docker.internal:host-gatewa…...
XML Group端口详解
在XML数据映射过程中,经常需要对数据进行分组聚合操作。例如,当处理包含多个物料明细的XML文件时,可能需要将相同物料号的明细归为一组,或对相同物料号的数量进行求和计算。传统实现方式通常需要编写脚本代码,增加了开…...
RocketMQ延迟消息机制
两种延迟消息 RocketMQ中提供了两种延迟消息机制 指定固定的延迟级别 通过在Message中设定一个MessageDelayLevel参数,对应18个预设的延迟级别指定时间点的延迟级别 通过在Message中设定一个DeliverTimeMS指定一个Long类型表示的具体时间点。到了时间点后…...
树莓派超全系列教程文档--(61)树莓派摄像头高级使用方法
树莓派摄像头高级使用方法 配置通过调谐文件来调整相机行为 使用多个摄像头安装 libcam 和 rpicam-apps依赖关系开发包 文章来源: http://raspberry.dns8844.cn/documentation 原文网址 配置 大多数用例自动工作,无需更改相机配置。但是,一…...
【OSG学习笔记】Day 18: 碰撞检测与物理交互
物理引擎(Physics Engine) 物理引擎 是一种通过计算机模拟物理规律(如力学、碰撞、重力、流体动力学等)的软件工具或库。 它的核心目标是在虚拟环境中逼真地模拟物体的运动和交互,广泛应用于 游戏开发、动画制作、虚…...
无法与IP建立连接,未能下载VSCode服务器
如题,在远程连接服务器的时候突然遇到了这个提示。 查阅了一圈,发现是VSCode版本自动更新惹的祸!!! 在VSCode的帮助->关于这里发现前几天VSCode自动更新了,我的版本号变成了1.100.3 才导致了远程连接出…...
Java-41 深入浅出 Spring - 声明式事务的支持 事务配置 XML模式 XML+注解模式
点一下关注吧!!!非常感谢!!持续更新!!! 🚀 AI篇持续更新中!(长期更新) 目前2025年06月05日更新到: AI炼丹日志-28 - Aud…...
04-初识css
一、css样式引入 1.1.内部样式 <div style"width: 100px;"></div>1.2.外部样式 1.2.1.外部样式1 <style>.aa {width: 100px;} </style> <div class"aa"></div>1.2.2.外部样式2 <!-- rel内表面引入的是style样…...
06 Deep learning神经网络编程基础 激活函数 --吴恩达
深度学习激活函数详解 一、核心作用 引入非线性:使神经网络可学习复杂模式控制输出范围:如Sigmoid将输出限制在(0,1)梯度传递:影响反向传播的稳定性二、常见类型及数学表达 Sigmoid σ ( x ) = 1 1 +...
【SSH疑难排查】轻松解决新版OpenSSH连接旧服务器的“no matching...“系列算法协商失败问题
【SSH疑难排查】轻松解决新版OpenSSH连接旧服务器的"no matching..."系列算法协商失败问题 摘要: 近期,在使用较新版本的OpenSSH客户端连接老旧SSH服务器时,会遇到 "no matching key exchange method found", "n…...
深度学习水论文:mamba+图像增强
🧀当前视觉领域对高效长序列建模需求激增,对Mamba图像增强这方向的研究自然也逐渐火热。原因在于其高效长程建模,以及动态计算优势,在图像质量提升和细节恢复方面有难以替代的作用。 🧀因此短时间内,就有不…...
