3.3.内存的学习,pinnedmemory,内存效率问题

news2024/9/23 3:24:54

目录

    • 前言
    • 1. Memory
    • 总结

前言

杜老师推出的 tensorRT从零起步高性能部署 课程,之前有看过一遍,但是没有做笔记,很多东西也忘了。这次重新撸一遍,顺便记记笔记。

本次课程学习精简 CUDA 教程-内存模型,pinned memory,内存效率问题

课程大纲可看下面的思维导图

在这里插入图片描述

1. Memory

内存模型是 CUDA 中很重要的知识点,通常和高性能有关系。

主要理解 pinned memory(Host Memory)、global memory(Deivce Memory)、shared memory(Device memory)即可,其它不常用

在这里插入图片描述

图1-1 CUDA内存模型

下图展示了显卡中各种内存所处位置,这是一个不太严谨但是辅助理解的图

在这里插入图片描述

图1-2 显卡各种内存位置

其中 shared memory 为片上内存,global memory 为片外内存

显卡的内存即 GPU 内存和主机的内存即 CPU 内存在电脑主板中的位置如下

在这里插入图片描述

图1-3 电脑主板中的GPU和CPU内存

Host Memory 即主机内存如下图所示:

在这里插入图片描述

图1-4 Host Memory

对于整个 Host Memory 内存条而言,操作系统区分为两个大类(逻辑区分,物理上是同一个东西):

  1. Pageable Memory,可分页内存
  2. Page lock Memory,页锁定内存

你可以理解为 Page lock Memory 是 VIP 房间,锁定给你一个人用。而 Pageable Memory 是普通房间,在酒店房间不够的时候,选择性的把你的房间腾出来给其他人交换用(交换到硬盘上),这就可以容纳更多人了。造成房间很多的假象,代价是性能降低

基于前面的理解,我们总结如下:

  1. pinned memory 具有锁定特性,是稳定不会被交换的(这点很重要,相当于每次去这个房间都一定能找到你)
  2. pageable memory 没有锁定特性,对于第三方设备(比如GPU),去访问时,因为无法感知内存是否被交换,可能得不到正确的数据(每次去房间找,说不准你的房间被人交换了)
  3. pageable memory 的性能比 pinned memory 差,很可能降低你程序的优先级然后把内存交换给别人用
  4. pageable memory 策略能使用内存假象,实际是 8GB 但是可以使用 15GB,提高程序运行数量(不是速度)
  5. pinned memory 太多,会导致操作系统整体性能降低(程序运行数量减少),8GB 就只能用 8GB
  6. GPU 可以直接访问 pinned memory 而不能访问 pageable memory

不同的 Host Memory 数据传输到 GPU 上的方式不同,具体如下图所示:

在这里插入图片描述

图1-5 Pinned Memory和Pageable Memory数据传输到GPU

GPU 要访问 Pageable Memory 的数据必须通过 Pinned Memory,GPU 可以直接访问 Pinned Memory 数据,其轨迹主要是通过 PICE 接口到主板再到内存条。

内存方面知识点总结

原则

  1. GPU 可以直接访问 pinned memory,称之为 DMA(Direct Memory Access) 技术
  2. 对于 GPU 访问而言,距离计算单元越近,效率越高,所以 Pinned Memory<Global Memory<Shared Memory
  3. 代码中,由 new、malloc 分配的是 pageable Memory,由 cudaMallocHost 分配的是 Pinned Memory(C语言函数分配也行),由 cudaMalloc 分配的是 Global Memory
  4. 尽量多用 Pinned Memory 储存 host 数据或者显式处理 Host 到 Device 时用 Pinned Memory 做缓存都是提高性能的关键

内存模型案例代码如下:

// CUDA运行时头文件
#include <cuda_runtime.h>

#include <stdio.h>
#include <string.h>

#define checkRuntime(op)  __check_cuda_runtime((op), #op, __FILE__, __LINE__)

bool __check_cuda_runtime(cudaError_t code, const char* op, const char* file, int line){
    if(code != cudaSuccess){    
        const char* err_name = cudaGetErrorName(code);    
        const char* err_message = cudaGetErrorString(code);  
        printf("runtime error %s:%d  %s failed. \n  code = %s, message = %s\n", file, line, op, err_name, err_message);   
        return false;
    }
    return true;
}

int main(){

    int device_id = 0;
    checkRuntime(cudaSetDevice(device_id));

    float* memory_device = nullptr;
    checkRuntime(cudaMalloc(&memory_device, 100 * sizeof(float))); // pointer to device

    float* memory_host = new float[100];
    memory_host[2] = 520.25;
    checkRuntime(cudaMemcpy(memory_device, memory_host, sizeof(float) * 100, cudaMemcpyHostToDevice)); // 返回的地址是开辟的device地址,存放在memory_device

    float* memory_page_locked = nullptr;
    checkRuntime(cudaMallocHost(&memory_page_locked, 100 * sizeof(float))); // 返回的地址是被开辟的pin memory的地址,存放在memory_page_locked
    checkRuntime(cudaMemcpy(memory_page_locked, memory_device, sizeof(float) * 100, cudaMemcpyDeviceToHost)); // 

    printf("%f\n", memory_page_locked[2]);
    checkRuntime(cudaFreeHost(memory_page_locked));
    delete [] memory_host;
    checkRuntime(cudaFree(memory_device)); 

    return 0;
}

运行效果如下:

在这里插入图片描述

图1-6 Memory案例

代码演示了操作内存分配和数据复制,整个流程可用下面的示意图来说明。先创建三个指针(mem_device、mem_host、mem_page_locked),然后开辟三块空间,将 mem_host 的数据复制到 GPU 上,再将 GPU 上 mem_deivce 的数据复制回 mem_page_locked 上(绿色箭头代表拷贝方向)

在这里插入图片描述

图1-7 数据传输示意图

关于内存模型及其知识点(from 杜老师)

1.关于内存模型,请参照https://www.bilibili.com/video/BV1jX4y1w7Um

  • 内存大局上分为
  • 主机内存:Host Memory,也就是 CPU 内存,内存
  • 设备内存:Device Memory,也就是 GPU 内存,显存
    • 设备内存又分为:
      • 全局内存(3):Global Memory(√)
      • 寄存器内存(1):Register Memory
      • 纹理内存(2):Texture Memory
      • 共享内存(2):Shared Memory(√)
      • 常量内存(2):Constant Memory
      • 本地内存(3):Local Memory
    • 只需要知道,谁距离计算芯片近,谁速度越快,空间越小,价格越贵
      • 清单的括号数字表示到计算芯片的距离

2.通过 cudaMalloc 分配 GPU 内存,分配到 setDevice 指定的当前设备上

3.通过 cudaMallocHost 分配 page locked memory,即 pinned memory,页锁定内存

  • 页锁定内存是主机内存,CPU 可以直接访问
  • 页锁定内存也可以被 GPU 直接访问,使用 DMA(Direct Memory Access)技术
  • 注意这么做的性能会比较差,因为主机内存距离 GPU 太远,隔着 PCIE 等,不适合大量数据传输
  • 页锁定内存是物理内存,过度使用会导致系统性能地低下(导致虚拟内存等一系列技术变慢)

4.cudaMemcpy

  • 如果 host 不是页锁定内存,则:
  • Device To Host 的过程,等价于:
    • pinned = cudaMallocHost
    • copy Device to Host
    • copy pinned to Host
    • free pinned
  • Host To Device 的过程,等价于:
    • pinned = cudaMallocHost
    • copy Host to pinned
    • copy pinned to Device
    • free pinned
  • 如果 host 是页锁定内存,则:
  • Device To Host 的过程,等价于
    • copy Device to Host
  • Host To Device 的过程,等价于
    • copy Host to Device

对于分配的内存一般来说建议先分配的先释放

checkRuntime(cudaFreeHost(memory_page_locked));
delete [] memory_host;
checkRuntime(cudaFree(memory_device));

使用 CUDA API 来分配内存的一般都有自己对应的释放内存方法;而使用 new 来分配的则使用 delete 来释放

总结

本次课程简单的学习了下各种内存,其中主机内存(即 CPU 内存)需要了解 pinned memory 以及 page locked memory 两大类,设备内存(即 GPU 内存)需要知道 Global memory 和 shared memory。同时页锁定内存可以直接被 GPU 访问(DMA技术),cudaMallocHost 分配的是页锁定内存(pinned memory),new、malloc 分配的是可分页内存(pageable memory),cudaMallo 分配的是 Global Memory。
两大类,设备内存(即 GPU 内存)需要知道 Global memory 和 shared memory。同时页锁定内存可以直接被 GPU 访问(DMA技术),cudaMallocHost 分配的是页锁定内存(pinned memory),new、malloc 分配的是可分页内存(pageable memory),cudaMallo 分配的是 Global Memory。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/732655.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

2023.7.08

#include "widget.h"void Widget::my_slot() {if((edit1->text()"admin")&&(edit2->text()"123456")){qDebug()<<"登陆成功";emit jump();close();}else{qDebug()<<"登陆失败";} }void Widget::b…

OSPFv2基础02_工作原理

目录 1.OSPF接口状态 2.OSPF邻居状态 2.1 OSPF邻居状态类型 2.2 广播网络OSPF邻接关系建立 3.Router ID&#xff08;路由器ID&#xff09;选举 4.DR和BDR选举 4.1 为什么引入DR和BDR&#xff1f; 4.2 DR和BDR的作用 4.3 DR和BDR选举过程 4.4 DR和BDR选举原则 5.OSPF路…

基于单片机指纹考勤系统的设计与实现

功能介绍 以51单片机作为主控系统&#xff1b;利用指纹采集模块存储打卡信息&#xff1b;12864显示当前考勤信息&#xff0c;时间 &#xff1b;如果迟到 语音播报 您已迟到&#xff1b;按键进行注册指纹、删除指纹、设置当前时间和签到时间、查询打卡等&#xff1b;具有掉电保存…

【YOLOv7调整detect.py】1.调整检测框粗细,2.设定标签颜色,3.只显示与标签数目相同的检测结果

目录 1. 调整检测框粗细2. 设定标签颜色3. 只显示与标签数目相同的检测结果 1. 调整检测框粗细 在detect.py中按住CtrlF检索line_thickness定位过去&#xff0c;在129行左右&#xff0c;更改line_thickness的大小即可&#xff0c;例如改为line_thickness3 2. 设定标签颜色 在…

Spring核心 and 创建使用

Spring核心 and 创建使用 文章目录 Spring核心 and 创建使用一、Spring的定义1.1什么是IoC1.1.1 理解控制反转&#xff08;IoC&#xff09;1.1.2 控制反转式程序开发 1.2 使用Spring IoC核心功能2.1 DI的概念说明 二、Spring的创建和使用2.1 创建一个Maven项目2.2 添加Spring框…

解决在jupyter notebook中找不到pip安装后的库

解决在jupyter notebook中找不到已安装的库

Todo-List案例版本二

(160条消息) Todo-List案例版本一_bubbleJessica的博客-CSDN博客 引入了localStorage&#xff0c;让案例更加完善 src/App.vue <template><div id"root"><div class"todo-container"><div class"todo-wrap"><MyHe…

pycharm 打开终端,安装第三方程序

鼠标移动到左下角 弹出列表&#xff0c;选择终端&#xff0c;当然也可以用快捷键唤出&#xff0c; 可以输入命令进行第三方库的安装

Redis实战案例14-分布式锁的基本原理、不同实现方法对比以及基于Redis进行实现思路

1. 分布式锁基本原理 基于数据库的分布式锁&#xff1a;这种方式使用数据库的特性来实现分布式锁。具体流程如下&#xff1a; 获取锁&#xff1a;当一个节点需要获得锁时&#xff0c;它尝试在数据库中插入一个特定的唯一键值&#xff08;如唯一约束的主键&#xff09;&#xff…

vue 进阶---动态组件 插槽 自定义指令

目录 动态组件 如何实现动态组件渲染 使用 keep-alive 保持状态 keep-alive 对应的生命周期函数 keep-alive 的 include 属性和exclude属性 插槽 插槽的基础用法 具名插槽 作用域插槽 自定义指令 自定义指令的分类 私有自定义指令 全局自定义指令 了解 eslint 插件…

mysql 单表查询练习

mysql 单表查询练习 创建数据表代码 CREATE TABLE emp (empno int(4) NOT NULL,ename varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,job varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,mgr int(4) NULL DEFAU…

附件上传报java.lang.RuntimeException: java.nio.file.NoSuchFileException的问题

1、报错信息 java.lang.RuntimeException: java.lang.RuntimeException: java.nio.file.NoSuchFileException: /tmp/undertow.5113172416389412561.31101/undertow1781128540461109448upload 2、原因 Java项目以java -jar命令启动后&#xff0c;进行文件上传的操作&#xff0c…

android 测试google pay

1、到GooglePlay后台创建商品&#xff0c;需要注意的是要创建商品必须先发布一个带有Billing库的aab到GooglePlay&#xff08;测试渠道即可&#xff09; 2、获取并配置好商品id之后&#xff0c;将测试用的aab发布到内部测试&#xff0c;并添加测试人员的邮箱。 3、通过连接分享…

获取系统时间日期相关接口梳理

时间&日期 ##MyTime.hpp #pragma once #include <iostream> #include <ctime> #include <string>using namespace std;class MyTime { public:MyTime() {};~MyTime() {};time_t timeSec(void);uint64_t timeMs(void);string timeDate(void); };##MyTim…

端口监控:HHD Device Monitoring Studio Crack

设备监控工作室 监控、记录和分析流经 PC 端口和连接的数据 设备监控工作室 Device Monitoring Studio 是一款高性能非侵入式软件解决方案&#xff0c;用于监控、记录和分析通过 PC 端口和连接传入的数据。 在其开发过程中&#xff0c;我们特别注重所有数据拦截和处理算法的优化…

qt实现信息管理系统(学生信息管理系统)功能更完善

一、代码地址 信息系统代码地址&#xff1a;https://gitee.com/dxl96/StdMsgSystem 二、基本说明 本学生信息管理系统同升级改造的幅度较大&#xff0c;涉及到的东西对于初学者来说&#xff0c;可能稍显复杂&#xff0c;可以先移步到 https://blog.csdn.net/IT_CREATE/artic…

SWAT模型十八个案例教程

详情点击链接&#xff1a;SWAT模型十八个案例教程案例一&#xff1a;基于网络资源的SWAT模型快速建模 案例二&#xff1a;基于遥感产品的SWAT模型率定与验证 案例三&#xff1a;基于水文响应单元&#xff08;HRU&#xff09;的水资源时空分布特征 案例四&#xff1a;基于自定义…

【代码随想录day4】链表相交

题目 给你两个单链表的头节点 headA 和 headB &#xff0c;请你找出并返回两个单链表相交的起始节点。如果两个链表没有交点&#xff0c;返回 null 。 图示两个链表在节点 c1 开始相交&#xff1a; 题目数据 保证 整个链式结构中不存在环。 注意&#xff0c;函数返回结果后&a…

基于Java网络安全宣传网站设计实现(源码+lw+部署文档+讲解等)

博主介绍&#xff1a;✌全网粉丝30W,csdn特邀作者、博客专家、CSDN新星计划导师、Java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专…

硬件性能 - CPU瓶颈分析

简介 本文章通过CPU各个指标项来简单分析是否出现CPU硬件性能瓶颈。其他硬件分析如下&#xff1a; 1. 硬件性能 - 掌握内存知识 2. 硬件性能 - 磁盘瓶颈分析 3. 硬件性能 - 网络瓶颈分析 目录 1. 系统负载 2. CPU利用率 3. 中断占用 4. 上下文切换 1. 系统负载 系统负载是…