caffe源码 之 CPU与GPU数据同步类

2023-11-20

本文主要解析caffe源码文件/src/caffe/SycedMem.cpp,该文件主要实现cpu与gpu的内存同步。

先看SycedMem.hpp中SycedMem的类定义:::

#ifndef CAFFE_SYNCEDMEM_HPP_
#define CAFFE_SYNCEDMEM_HPP_

#include <cstdlib>

#include "caffe/common.hpp"

namespace caffe {

/*下面注释翻译:::
  在Cuda可用并且在GPU模式下,用cudaMallocHost可以分配得到固定的内存。
  这样分配好的内存不会被例如DMA这种内存存取机制动态占用,
  这样分配的内存对于单一的GPU来说不会有太大的用处,
  但对于并行训练来说他会更有用,尤其,这样分配的内存能显著提高大型模型在多GPU情形下的稳定性*/

// If CUDA is available and in GPU mode, host memory will be allocated pinned,
// using cudaMallocHost. It avoids dynamic pinning for transfers (DMA).
// The improvement in performance seems negligible in the single GPU case,
// but might be more significant for parallel training. Most importantly,
// it improved stability for large models on many GPUs.
inline void CaffeMallocHost(void** ptr, size_t size, bool* use_cuda) {
#ifndef CPU_ONLY
  if (Caffe::mode() == Caffe::GPU) {
    CUDA_CHECK(cudaMallocHost(ptr, size));// GPU模式下用cuda提供库函数分配内存
    *use_cuda = true;
    return;
  }
#endif
  *ptr = malloc(size);//单CPU模式下则通过c的malloc函数分配
  *use_cuda = false;
  CHECK(*ptr) << "host allocation of size " << size << " failed";
}

inline void CaffeFreeHost(void* ptr, bool use_cuda) {
#ifndef CPU_ONLY
  if (use_cuda) {
    CUDA_CHECK(cudaFreeHost(ptr));//GPU模式下用cuda库函数cudaFreeHost释放内存
    return;
  }
#endif
  free(ptr);//单cpu模式用C库函数释放内存
}


/**
 * @brief Manages memory allocation and synchronization between the host (CPU)
 *        and device (GPU).
 *
 * TODO(dox): more thorough description.
 */
class SyncedMemory {
 public:
  SyncedMemory()//构造函数,负责初始化
      : cpu_ptr_(NULL), gpu_ptr_(NULL), size_(0), head_(UNINITIALIZED),
        own_cpu_data_(false), cpu_malloc_use_cuda_(false), own_gpu_data_(false),
        gpu_device_(-1) {}
  explicit SyncedMemory(size_t size)//带explicit关键字的,有单个参数的构造函数,explicit禁止单参数构造函数的隐式转换
      : cpu_ptr_(NULL), gpu_ptr_(NULL), size_(size), head_(UNINITIALIZED),
        own_cpu_data_(false), cpu_malloc_use_cuda_(false), own_gpu_data_(false),
        gpu_device_(-1) {}
  ~SyncedMemory();
  const void* cpu_data(); /*返回分配的cpu的内存地址:cpu_ptr_*/
  void set_cpu_data(void* data); /*cpu_ptr_所指向的内存释放,并且cpu_ptr_指向入参data所指向内存*/
  const void* gpu_data(); /*如果GPU模式,返回分配的gpu的内存地址:gpu_ptr_*/
  void set_gpu_data(void* data);/*如果GPU模式,gpu_ptr_所指向的内存释放,并且gpu_ptr_指向入参data所指向内存*/
  void* mutable_cpu_data();/*返回分配的cpu的内存地址:cpu_ptr_, 置状态为head_ = HEAD_AT_CPU*/
  void* mutable_gpu_data();/*如果GPU模式,返回分配的gpu的内存地址:gpu_ptr_, 置状态为head_ = HEAD_AT_GPU*/
  enum SyncedHead { UNINITIALIZED, HEAD_AT_CPU, HEAD_AT_GPU, SYNCED }; /*SyncedHead枚举类型,用来设定head_的状态*/
  SyncedHead head() { return head_; } /*返回相应的数据内存状态*/
  size_t size() { return size_; }  /*返回数据内存大小*/

#ifndef CPU_ONLY
  void async_gpu_push(const cudaStream_t& stream);  /*异步传输数据,将数据从cpu拷贝到gpu*/
#endif

 private:
  void to_cpu(); /*见.cpp中注释*/
  void to_gpu(); /*见.cpp中注释*/
  void* cpu_ptr_;  /*cpu内存数据指针*/
  void* gpu_ptr_;  /*gpu内存数据指针*/
  size_t size_;    /*数据内存大小*/
  SyncedHead head_; /*数据状态*/
  bool own_cpu_data_;  /*是否有cpu内存*/
  bool cpu_malloc_use_cuda_;  
  bool own_gpu_data_;/*是否有GPU内存*/
  int gpu_device_; /*GPU的设备ID号*/

  DISABLE_COPY_AND_ASSIGN(SyncedMemory);  /*见common.cpp解析*/
};  // class SyncedMemory

}  // namespace caffe

#endif  // CAFFE_SYNCEDMEM_HPP_

其实上面的注释已经解释了大部分SycedMem成员变量与成员函数的意义了,这里主要关注函数to_cpu,与to_gpu的是如何实现的::::

#######略##########

/*如果是第一次初始化,就CaffeMallocHost分配CPU内存, 
  如果数据处在GPU状态,如果是GPU模式就分配CPU内存,把GPU内存数据拷贝到CPU,
  如果数据处在CPU状态或者已经同步,则不处理
  总之就是将数据同步到CPU*/
inline void SyncedMemory::to_cpu() {
  switch (head_) {
  case UNINITIALIZED:
    CaffeMallocHost(&cpu_ptr_, size_, &cpu_malloc_use_cuda_);
    caffe_memset(size_, 0, cpu_ptr_);
    head_ = HEAD_AT_CPU;
    own_cpu_data_ = true;
    break;
  case HEAD_AT_GPU:
#ifndef CPU_ONLY
    if (cpu_ptr_ == NULL) {
      CaffeMallocHost(&cpu_ptr_, size_, &cpu_malloc_use_cuda_);
      own_cpu_data_ = true;
    }
    caffe_gpu_memcpy(size_, gpu_ptr_, cpu_ptr_);
    head_ = SYNCED;
#else
    NO_GPU;
#endif
    break;
  case HEAD_AT_CPU:
  case SYNCED:
    break;
  }
}

/*如果是GPU模式下才处理,如果是单cpu模式下则报错
  如果数据处在第一次初始化状态,则分配GPU内存并初始化为0
  如果数据处在CPU状态,则分配GPU内存将数据从CPU拷贝到GPU
  其他情况不处理,
  总之数据同步以GPU*/
inline void SyncedMemory::to_gpu() {
#ifndef CPU_ONLY
  switch (head_) {
  case UNINITIALIZED:
    CUDA_CHECK(cudaGetDevice(&gpu_device_));
    CUDA_CHECK(cudaMalloc(&gpu_ptr_, size_));
    caffe_gpu_memset(size_, 0, gpu_ptr_);
    head_ = HEAD_AT_GPU;
    own_gpu_data_ = true;
    break;
  case HEAD_AT_CPU:
    if (gpu_ptr_ == NULL) {
      CUDA_CHECK(cudaGetDevice(&gpu_device_));
      CUDA_CHECK(cudaMalloc(&gpu_ptr_, size_));
      own_gpu_data_ = true;
    }
    caffe_gpu_memcpy(size_, cpu_ptr_, gpu_ptr_);
    head_ = SYNCED;
    break;
  case HEAD_AT_GPU:
  case SYNCED:
    break;
  }
#else
  NO_GPU;
#endif
}

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

caffe源码 之 CPU与GPU数据同步类 的相关文章

  • 如何根据CPU能力实现渲染器

    我想知道在 JavaScript 中实现渲染器的最佳方法是什么 这里真正重要的并不是渲染的内容部分 我更想知道何时以及如何有效地运行渲染器代码 目前 我有window setInterval renderFunc 1000 20 每 50
  • 为什么numba cuda调用几次后运行速度变慢?

    我正在尝试如何在 numba 中使用 cuda 然而我却遇到了与我预想不同的事情 这是我的代码 from numba import cuda cuda jit def matmul A B C Perform square matrix m
  • cuda 共享内存 - 结果不一致

    我正在尝试并行缩减以对 CUDA 中的数组求和 目前我传递一个数组来存储每个块中元素的总和 这是我的代码 include
  • Visual Studio - 过滤掉 nvcc 警告

    我正在编写 CUDA 程序 但收到令人讨厌的警告 Warning Cannot tell what pointer points to assuming global memory space 这是来自 nvcc 我无法禁用它 有没有办法过
  • 什么是微编码指令?

    我看过很多参考微编码指令的文献 这些是什么以及为什么使用它们 CPU 读取机器代码并将其解码为内部控制信号 将正确的数据发送到正确的执行单元 大多数指令映射到一个内部操作 并且可以直接解码 例如 在 x86 上 add eax edx只是将
  • 如何优化这个 CUDA 内核

    我已经分析了我的模型 似乎该内核约占我总运行时间的 2 3 我一直在寻找优化它的建议 代码如下 global void calcFlux double concs double fluxes double dt int idx blockI
  • 仅使用 CUDA 进行奇异值计算

    我正在尝试使用新的cusolverDnSgesvdCUDA 7 0 用于计算奇异值的例程 完整代码如下 include cuda runtime h include device launch parameters h include
  • 如何确定完整的 CUDA 版本 + 颠覆版本?

    Linux 上的 CUDA 发行版曾经有一个名为version txt例如 CUDA Version 10 2 89 这非常有用 但是 从 CUDA 11 1 开始 该文件不再存在 我如何在 Linux 上通过命令行确定并检查 path t
  • python 进程占用 100% CPU

    我正在尝试运行 python 应用程序并根据指定的时间间隔执行操作 下面的代码持续消耗 100 的 CPU def action print print hello there interval 5 next run 0 while Tru
  • 如何加载 caffe 模型并转换为 numpy 数组?

    我有一个 caffemodel 文件 其中包含 ethereon 的 caffe tensorflow 转换实用程序不支持的层 我想生成我的咖啡模型的 numpy 表示 我的问题是 如何将 caffemodel 文件 我还有 prototx
  • C# - 获取 GPU 的总使用百分比

    我正在向我的程序添加一些新功能 这些功能当前通过串行连接将 CPU 使用情况和 RAM 使用情况发送到 Arduino 请参阅this https create arduino cc projecthub thesahilsaluja cp
  • TensorRT 多线程

    我正在尝试使用 python API 来使用 TensorRt 我试图在多个线程中使用它 其中 Cuda 上下文与所有线程一起使用 在单个线程中一切正常 我使用 docker 和 tensorrt 20 06 py3 图像 onnx 模型和
  • 有没有一种有效的方法来优化我的序列化代码?

    这个问题缺乏细节 因此 我决定创建另一个问题而不是编辑这个问题 新问题在这里 我可以并行化我的代码吗 还是不值得 https stackoverflow com questions 17937438 can i parallelize my
  • 普通的 x86 或 AMD PC 是直接从 ROM 运行启动/BIOS 代码,还是先将其复制到 RAM? [关闭]

    Closed 这个问题不符合堆栈溢出指南 help closed questions 目前不接受答案 我知道现代计算机已经修改了哈佛架构 它们可以从保存数据的地方以外的地方读取指令 这一事实是否允许它们直接从 ROM 芯片获取指令 他们是先
  • 超出 CreateConstantBufferView 处虚拟地址的末尾

    我正在遵循 使用 DirectX12 进行游戏编程 ch 6 代码 但在 ID3DDevice CreateConstantBufferView 中 我发现 D3D12 错误 D3D12 错误 ID3D12Device CreateCons
  • 错误:NVIDIA-SMI 失败,因为无法与 NVIDIA 驱动程序通信

    NVIDIA SMI 抛出此错误 NVIDIA SMI 失败 因为无法与 NVIDIA 通信 司机 确保安装了最新的 NVIDIA 驱动程序并且 跑步 我清除了 NVIDIA 并按照提到的步骤重新安装了它here https askubun
  • 如何为 CUDA 内核选择网格和块尺寸?

    这是一个关于如何确定CUDA网格 块和线程大小的问题 这是对已发布问题的附加问题here https stackoverflow com a 5643838 1292251 通过此链接 talonmies 的答案包含一个代码片段 见下文 我
  • 每个 CPU 核心处于 C0 电源状态的时间

    任何帮助弄清楚如何做到这一点都会很棒 在过去一秒内 每个 CPU 核心处于 C0 电源状态的时间有多少 这是针对 Mac 应用程序的 因此需要 Objective C cocoa 和 c OS X 没有任何公开 CPU c 状态的 API
  • GPU的编程语言有哪些

    我读过一篇文章 指出 GPU 是超级计算的未来 我想知道在GPU上编程使用什么编程语言 OpenCL 是开放式跨平台解决方案 可在 GPU 和 CPU 上运行 另一个是 NVIDIA 为其 GPU 构建的 CUDA HLSL Cg 等少数几
  • 内联 PTX 汇编代码强大吗?

    我看到一些代码示例 人们在 C 代码中使用内联 PTX 汇编代码 CUDA工具包中的文档提到PTX很强大 为什么会这样呢 如果我们在 C 代码中使用这样的代码 我们会得到什么好处 内联 PTX 使您可以访问未通过 CUDA 内在函数公开的指

随机推荐

  • 使用opencv实现简单的人脸识别

    一 opencv模块的使用 1 简介 opencv python是一个python绑定库 旨在解决计算机视觉问题 使用opencv模块 可以实现一些对图片和视频的操作 2 安装 安装opencv之前需要先安装numpy matplotlib
  • kubernetes RC 与 Deployment ,Pod,Horizontal Pod Autoscaling ,replica set资源

    Pod Pod是 kubernetes 的最基本的操作单元 包含一个或多个紧密相关的容器 kubernetes 使用pod在容器之上再封装一层 其一个很重要的原因是 docker容器之间的通信受到docker网络机制的限制 在docker中
  • 华为OD机试真题- Linux发行版的数量【2023Q1】【JAVA、Python、C++】

    题目描述 Linux操作系统有多个发行版 distrowatch com提供了各个发行版的资料 这些发行版互相存在关联 例如Ubuntu基于Debian开发 而Mint又基于Ubuntu开发 那么我们认为Mint同Debian也存在关联 发
  • C++11新特性:四种类型转换cast说明

    目录 引言 1 static cast 1 1 基本类型转换 1 2 类的上行转换 安全 1 3 类的下行转换 不安全 2 const cast 2 1 改变常量属性 3 dynamic cast 3 1 类的上行转换 安全 3 2 类的下
  • <Linux开发>驱动开发 -之- Linux LCD 驱动

    Linux开发 驱动开发 之 Linux LCD 驱动 交叉编译环境搭建 Linux开发 linux开发工具 之 交叉编译环境搭建 uboot移植可参考以下 Linux开发 之 系统移植 uboot移植过程详细记录 第一部分 Linux开发
  • 碎碎念之工作②

  • [Transformer] PVT系列:PVT & CPVT & Twins

    PVT Pyramid Vision Transformer A Versatile Backbone for Dense Prediction without Convolutions 论文 https arxiv org abs 210
  • Windows环境下使用GTK

    一 前言 维基百科 GTK 原名GTK 最初是GIMP的专用开发库 GIMP Toolkit 后来发展为Unix like系统下开发图形界面的应用程序的主流开发工具之一 GTK是自由软件 并且是GNU计划的一部分 自2019年2月6日起 G
  • C语言函数大全-- x 开头的函数(4)

    x 开头的函数 4 1 xdr struct 1 1 函数说明 1 2 演示示例 2 xdr u char 2 1 函数说明 2 2 演示示例 3 xdr u hyper 3 1 函数说明 3 2 演示示例 4 xdr u int 4 1
  • 【瑞吉外卖day04】

    菜品管理业务 1 文件上传下载 1 1 文件上传介绍 1 2 文件下载介绍 1 3 文件上传代码实现 前端页面直接使用现成的 源码这里
  • Freertos代码之临界函数

    芯 片 STM32F427VITx 指 令 集 ARMV7 Thumb2 编译环境 arm gcc FreeRTOS有如下临界节管理的宏定义 define portSET INTERRUPT MASK FROM ISR ulPortRais
  • Java上传文件大小受限怎么解决

    一般控制台上会出现像这样 1048576 bytes 这大小限制 org springframework web multipart MaxUploadSizeExceededException Maximum upload size ex
  • rttread-nano 使用记录:rt_kprintf函数格式化打印无法左对齐

    rttread nano 使用记录 rt kprintf函数格式化打印无法左对齐 今天用rt kprintf函数打印输出一个表格 为了表格好看每一列我都使用格式化参数 负号符号设置为了左对齐 但是发现无法打印 也无法打印浮点数 换成微库的p
  • 使用presto调用hive

    启动hive metastore服务 hive service hivestore 关于最后的一个 告诉小白一下是后台运行的意思 presto配置使用hive插件 presto所在的文件中etc 自建 的catalog 自建 中hive p
  • 输出数组的最大值、最小值及其位置

    题目 输入一个长度为10的数组 输出数组的最大值 最小值及其最大值 最小值在数组里的位置 思路 如果只需找出最大值 我们可以假定最大值max为数组的第一个元素 然后将剩余的元素逐个和max比较 如果有比max更大的元素 就将其记录下来 直到
  • Qt HTTP POST json 访问服务器

    form格式访问服务器 QByteArray postArray postArray append grant type authorization code postArray append client id 32u2w95f200D4
  • 数据中台与数据仓库区别

    1 数据源不同 先从数据来源上来说 数据中台的数据来源可以是结构化数据或者非结构化的数据 而传统数仓的数据来源主要是业务数据库 数据格式也是以结构化数据为主 2 数据的处理不同 数据中台不仅仅是汇聚企业各种数据 而且让这些数据遵循相同的标准
  • 用户复购周期计算

    用户复购周期 两次购买之间的时间间隔 一 首先使用SQL进行计算 注 用户在一天中发生多次购买则只记为1次购买 1 根据用户id与购买日期进行分组 将一天内发生多次消费记录进行合并 DROP TABLE member Repurchase
  • Python播放GIF图片(ChatGPT代码参考)

    在网上找了好几个方法 最后还是出现各种问题 解决不了播放GIF的功能 最后 通过ChatGPT给出了简单明了的方案 使用第三方库imageio和matplotlib animation来实现 调试直接通过 但有小瑕疵 就是显示gif时隐藏掉
  • caffe源码 之 CPU与GPU数据同步类

    本文主要解析caffe源码文件 src caffe SycedMem cpp 该文件主要实现cpu与gpu的内存同步 先看SycedMem hpp中SycedMem的类定义 ifndef CAFFE SYNCEDMEM HPP define