【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…...
通过Wrangler CLI在worker中创建数据库和表
官方使用文档:Getting started Cloudflare D1 docs 创建数据库 在命令行中执行完成之后,会在本地和远程创建数据库: npx wranglerlatest d1 create prod-d1-tutorial 在cf中就可以看到数据库: 现在,您的Cloudfla…...
Java如何权衡是使用无序的数组还是有序的数组
在 Java 中,选择有序数组还是无序数组取决于具体场景的性能需求与操作特点。以下是关键权衡因素及决策指南: ⚖️ 核心权衡维度 维度有序数组无序数组查询性能二分查找 O(log n) ✅线性扫描 O(n) ❌插入/删除需移位维护顺序 O(n) ❌直接操作尾部 O(1) ✅内存开销与无序数组相…...
【网络安全产品大调研系列】2. 体验漏洞扫描
前言 2023 年漏洞扫描服务市场规模预计为 3.06(十亿美元)。漏洞扫描服务市场行业预计将从 2024 年的 3.48(十亿美元)增长到 2032 年的 9.54(十亿美元)。预测期内漏洞扫描服务市场 CAGR(增长率&…...
根据万维钢·精英日课6的内容,使用AI(2025)可以参考以下方法:
根据万维钢精英日课6的内容,使用AI(2025)可以参考以下方法: 四个洞见 模型已经比人聪明:以ChatGPT o3为代表的AI非常强大,能运用高级理论解释道理、引用最新学术论文,生成对顶尖科学家都有用的…...
mysql已经安装,但是通过rpm -q 没有找mysql相关的已安装包
文章目录 现象:mysql已经安装,但是通过rpm -q 没有找mysql相关的已安装包遇到 rpm 命令找不到已经安装的 MySQL 包时,可能是因为以下几个原因:1.MySQL 不是通过 RPM 包安装的2.RPM 数据库损坏3.使用了不同的包名或路径4.使用其他包…...
Rapidio门铃消息FIFO溢出机制
关于RapidIO门铃消息FIFO的溢出机制及其与中断抖动的关系,以下是深入解析: 门铃FIFO溢出的本质 在RapidIO系统中,门铃消息FIFO是硬件控制器内部的缓冲区,用于临时存储接收到的门铃消息(Doorbell Message)。…...
AspectJ 在 Android 中的完整使用指南
一、环境配置(Gradle 7.0 适配) 1. 项目级 build.gradle // 注意:沪江插件已停更,推荐官方兼容方案 buildscript {dependencies {classpath org.aspectj:aspectjtools:1.9.9.1 // AspectJ 工具} } 2. 模块级 build.gradle plu…...
Pinocchio 库详解及其在足式机器人上的应用
Pinocchio 库详解及其在足式机器人上的应用 Pinocchio (Pinocchio is not only a nose) 是一个开源的 C 库,专门用于快速计算机器人模型的正向运动学、逆向运动学、雅可比矩阵、动力学和动力学导数。它主要关注效率和准确性,并提供了一个通用的框架&…...
【Go语言基础【13】】函数、闭包、方法
文章目录 零、概述一、函数基础1、函数基础概念2、参数传递机制3、返回值特性3.1. 多返回值3.2. 命名返回值3.3. 错误处理 二、函数类型与高阶函数1. 函数类型定义2. 高阶函数(函数作为参数、返回值) 三、匿名函数与闭包1. 匿名函数(Lambda函…...
深入浅出深度学习基础:从感知机到全连接神经网络的核心原理与应用
文章目录 前言一、感知机 (Perceptron)1.1 基础介绍1.1.1 感知机是什么?1.1.2 感知机的工作原理 1.2 感知机的简单应用:基本逻辑门1.2.1 逻辑与 (Logic AND)1.2.2 逻辑或 (Logic OR)1.2.3 逻辑与非 (Logic NAND) 1.3 感知机的实现1.3.1 简单实现 (基于阈…...
