看到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號內存