caffe源码阅读2-syncedmem.hpp+.cpp

Manages memory allocation and synchronization between the host (CPU) and device (GPU).

因为在看Blob.hpp的时候,有一个东西不好理解,里面最重要的两个东西data, diff是定义成:

  shared_ptr<SyncedMemory> data_;
  shared_ptr<SyncedMemory> diff_;

shared_ptr也就是智能指针,等涉及到其方法的时候再做一点说明。

那么SyncedMemory是什么呢?在syncedmem.hpp里面可以看到,方法和变量都比较少。从注释可以大概了解到,这个东西是为了处理CPU与GPU同步问题的。因为我们在运行caffe的时候,通常都会使用GPU来跑,那么在分配和释放存储的时候,自然也会分配释放显存中的存储。但是如果代码直接这样写的话,可能会出错,例如某些机器上没有GPU,直接使用CPU来跑caffe的呢?

那么此时,如果按照我自己的理解,SyncedMemory应该是对内存和显存的抽象,用户只需要分配和释放存储,而具体是分配什么地方的存储,释放什么地方的存储,全部都交给SyncedMemory来处理。不过有点可惜,从这个类的方法和变量来看,应该还没有抽象到我想象的程度。

 private:
  void to_cpu();
  void to_gpu();
  void* cpu_ptr_;
  void* gpu_ptr_;
  size_t size_;
  SyncedHead head_;
  bool own_cpu_data_;

在私有变量中,cpu_ptr_和gpu_ptr_应该很好理解,也就是只想内存和显存里面的数据的指针吧。那么size应该是内存+显存的咯。而own_cpu_data,应该只是想说明内存中是否有数据吧。至于head_,看起来像是指向数据的头,我的猜测也就是说数据头部在内存还是显存,不过在public的方法也指明了这一点:
 public:
  SyncedMemory()
      : cpu_ptr_(NULL), gpu_ptr_(NULL), size_(0), head_(UNINITIALIZED),
        own_cpu_data_(false) {}
  explicit SyncedMemory(size_t size)
      : cpu_ptr_(NULL), gpu_ptr_(NULL), size_(size), head_(UNINITIALIZED),
        own_cpu_data_(false) {}
  ~SyncedMemory();
  const void* cpu_data();
  void set_cpu_data(void* data);
  const void* gpu_data();
  void* mutable_cpu_data();
  void* mutable_gpu_data();
  enum SyncedHead { UNINITIALIZED, HEAD_AT_CPU, HEAD_AT_GPU, SYNCED };
  SyncedHead head() { return head_; }
  size_t size() { return size_; }

其中的enum SyncedHead {...},也就是说变量SyncedHead是一个枚举类型的:

UNINITIALIZED:未初始化

HEAD_AT_CPU:数据头部在内存中

HEAD_AT_GPU:数据头部在显存中

SYNCED:内存显存中都有数据头部

读到这里,其它的东西得去看看cpp了,那么to_cpu()是什么呢?

inline void SyncedMemory::to_cpu() {
  switch (head_) {
  case UNINITIALIZED:  //如果没有初始化,那么初始化数据在内存中
    CaffeMallocHost(&cpu_ptr_, size_);
    caffe_memset(size_, 0, cpu_ptr_);
    head_ = HEAD_AT_CPU;
    own_cpu_data_ = true;
    break;
  case HEAD_AT_GPU:
#ifndef CPU_ONLY  //如果没有声明CPU_ONLY,则数据可以存在于显存中,
                  //则将显存中的数据拷贝到内存中,并将own_cpu_data_赋值为true
    if (cpu_ptr_ == NULL) {
      CaffeMallocHost(&cpu_ptr_, size_);
      own_cpu_data_ = true;
    }
    caffe_gpu_memcpy(size_, gpu_ptr_, cpu_ptr_);
    head_ = SYNCED;
#else
    NO_GPU;       //如果声明了CPU_ONLY,那么数据不可能存在于显存中,应该是提示,或者报错吧
#endif
    break;
  case HEAD_AT_CPU:
  case SYNCED:
    break;
  }
}

那么to_gpu()也是类似的的吧。

cpu_data()则是先将数据写回到内存中(to_cpu()),再返回数据指针。那么gpu_data()也是一样的道理。值得注意的是方法mutable_cpu_data()mutable_gpu_data(),实现的功能基本与cpu_data(),gpu_data()一样,但是多了一个东西,就是会对数据头head_赋值,mutable_cpu_data()中的赋值就是HEAD_AT_CPU,mutable_gpu_data()中的赋值就是HEAD_AT_GPU。这样做的好处是什么呢?如果这种处理方式比直接调用cpu_data(),gpu_data()的效果好,那么为什么还要设置前两个方法呢?不理解。

另外还有一个函数,set_cpu_data(void* data)也就是将数据data写入内存。奇怪的是写入后为什么要将own_cpu_data_赋值为false呢?

void SyncedMemory::set_cpu_data(void* data) {
  CHECK(data);
  if (own_cpu_data_) {
    CaffeFreeHost(cpu_ptr_);
  }
  cpu_ptr_ = data;
  head_ = HEAD_AT_CPU;
  own_cpu_data_ = false;
}


评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值