Caffe学习之——syncedmem.cpp与syncedmem.hpp源码解析

4 篇文章 0 订阅

本文主要讲解caffe master下面的 src/caffe/syncedmem.cpp include/caffe/syncedmem.hpp
这两主要用于CPU与GPU的内存同步使用而定义的类文件。

文章参考: https://blog.csdn.net/lanxuecc/article/details/53009130 
作者 _苏_的一系列caffe源码解析真的帮忙很大。

首先讲下:
syncedmem.hpp
#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_

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

/*如果是第一次初始化,就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
}

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

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值