Caffe源碼解析2:SycedMem

轉載請註明出處,樓燚(yì)航的blog,http://www.cnblogs.com/louyihang loves baiyan/

看到SyncedMem就知道,這是在作內存同步的操做。這類個類的代碼比較少,可是做用是很是明顯的。文件對應着syncedmem.hpp,着syncedmem.cpp異步

首先是兩個全局的內聯函數。若是機器是支持GPU的而且安裝了cuda,經過cudaMallocHost分配的host memory將會被pinned,這裏我谷歌了一下,pinned的意思就是內存不會被paged out,咱們知道內存裏面是由頁做爲基本的管理單元。分配的內存能夠常駐在內存空間中對效率是有幫助的,空間不會被別的進程所搶佔。一樣若是內存越大,能被分配的Pinned內存天然也越大。還有一點是,對於單一的GPU而言提高並不會太顯著,可是對於多個GPU的並行而言能夠顯著提升穩定性。async

這裏是兩個封裝過的函數,內部經過cuda來分配主機和釋放內存的接口函數

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);//若是沒有cuda則經過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));//cuda的主機內存釋放操做
    return;
  }
#endif
  free(ptr);//c的釋放操做
}

SyncedMemory類,首先是構造函數和析構函數指針

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();//其在析構時調用的也是CaffeFreeHost

這幾個函數分別是code

const void* cpu_data();
  void set_cpu_data(void* data);
  const void* gpu_data();
  void set_gpu_data(void* data);

cpu_data()主要是得到cpu上data的地址,set_cpu_data是將cpu的data指針指向一個新的區域由data指針傳入,而且將原來申請的內存釋放。下面兩個同理,分別是得到gpu數據地址和set gpu數據地址。blog

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_; }

前兩個分別是返回cpu和gpu上的data指針,而且置狀態爲head_ = HEAD_AT_CPU和響應的gpu版本。SyncedHead主要是個枚舉類型,用來設定head_的狀態,head()函數即返回相應的數據狀態,而size()函數返回數據大小接口

#ifndef CPU_ONLY
  void async_gpu_push(const cudaStream_t& stream);
#endif

這是一個cuda拷貝的異步傳輸,從數據從cpu拷貝到gpu,異步傳輸是已經假定caller會在使用以前作同步操做。進程

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

  DISABLE_COPY_AND_ASSIGN(SyncedMemory);//禁止該類的拷貝與賦值
};  // class SyncedMemory

其實這裏的東西也很少了,to_cpu(),to_gpu()這個看名字就知道了,須要注意的是,若是head 是未被初始化的狀態,那麼首先須要先分配內存,這個根據cpu和gpu視狀況而定,以後再將數據從cpu或者gpu拷貝到另外一處。以後函數會從新標記Head的狀態,數據是否在cpu或者在gpu中,cpu這裏是簡稱,實際上是主機。
cpu_ptr和gpu_ptr分別是在cpu和gpu中的數據指針,size_這就再也不說了,head_以前也液晶提到過了,後面都是幾個相應的標記爲,以及gpu的ID號內存

相關文章
相關標籤/搜索