您的位置:首页 > Web前端

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

2016-07-18 10:32 567 查看
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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: