梳理caffe代码syncedmem(二)

梳理caffe代码syncedmem(二)

接着最重要的就是内存分配和Caffe的底层数据的切换(cpu模式和gpu模式),需要用到内存同步模块。这类个类的代码比较少,但是作用是非常明显的。文件对应着syncedmem.hpp,着syncedmem.cpp首先是两个全局的内联函数。如果机器是支持GPU的并且安装了cuda,通过cudaMallocHost分配的host memory将会被pinned,pinned的意思就是内存不会被paged out,我们知道内存里面是由页作为基本的管理单元。分配的内存可以常驻在内存空间中对效率是有帮助的,空间不会被别的进程所抢占。同样如果内存越大,能被分配的Pinned内存自然也越大。还有一点是,对于单一的GPU而言提升并不会太显著,但是对于多个GPU的并行而言可以显著提高稳定性。这里是两个封装过的函数,内部通过cuda来分配主机和释放内存的接口.

 

[cpp] view plain copy
 
 在CODE上查看代码片派生到我的代码片
  1. #ifndef CAFFE_SYNCEDMEM_HPP_  
  2. #define CAFFE_SYNCEDMEM_HPP_  
  3.   
  4. #include <cstdlib>  
  5.   
  6. #include "caffe/common.hpp"  
  7. #include "caffe/util/math_functions.hpp"  
  8.   
  9. namespace caffe {  
  10.   
  11. // Theoretically, CaffeMallocHost and CaffeFreeHost should simply call the  
  12. // cudaMallocHost and cudaFree functions in order to create pinned memory.  
  13. // However, those codes rely on the existence of a cuda GPU (I don't know  
  14. // why that is a must since allocating memory should not be accessing the  
  15. // GPU resource, but it just creates an error as of Cuda 5.0) and will cause  
  16. // problem when running on a machine without GPU. Thus, we simply define  
  17. // these two functions for safety and possible future change if the problem  
  18. // of calling cuda functions disappears in a future version.  
  19. //  
  20. // In practice, although we are creating unpinned memory here, as long as we  
  21. // are constantly accessing them the memory pages almost always stays in  
  22. // the physical memory (assuming we have large enough memory installed), and  
  23. // does not seem to create a memory bottleneck here.  
  24. //分别是分配和释放内存,这里指的是CPU内存。  
  25. inline void CaffeMallocHost(void** ptr, size_t size) {  
  26.   *ptr = malloc(size);  
  27.   CHECK(*ptr) << "host allocation of size " << size << " failed";  
  28. }  
  29.   
  30. inline void CaffeFreeHost(void* ptr) {  
  31.   free(ptr);  
  32. }  
  33.   
  34.   
  35. /** 
  36.  * @brief Manages memory allocation and synchronization between the host (CPU) 
  37.  *        and device (GPU). 
  38.  * 
  39.  * TODO(dox): more thorough description. 
  40.  */  
  41. //功能:Caffe的底层数据的切换(cpu模式和gpu模式),需要用到内存同步模块。  
  42. class SyncedMemory {  
  43.  public:  
  44. /* 
  45. 第一个为简单初始化,第二个只是把 size (大小)设置了,并未申请内存。 
  46. 然后是析构函数,主要就是释放数据。own_gpu_data和own_cpu_data这两个成员变量 
  47. 的作用表示是否拥有该数据,也即在cpu或gpu中是否 
  48. 有其他指针指向该数据。 
  49. */  
  50.   SyncedMemory()  
  51.       : cpu_ptr_(NULL), gpu_ptr_(NULL), size_(0), head_(UNINITIALIZED),  
  52.         own_cpu_data_(false) {}  
  53.   explicit SyncedMemory(size_t size)  
  54.       : cpu_ptr_(NULL), gpu_ptr_(NULL), size_(size), head_(UNINITIALIZED),  
  55.         own_cpu_data_(false) {}  
  56.   ~SyncedMemory();  
  57. /* 
  58. 分别是获取cpu,gpu中数据的指针,需要说明的一点是,该过程会同步数据。 
  59. 有获取,就有设置,下面两个函数就是设置数据了。这里设置后就不是拥有该数据, 
  60. 即own_cpu_data或own_gpu_data就为false,因为还有data指向该数据。 
  61. 一般来说,只有当同步后才会为true。也即to_cpu()或者to_gpu()后。 
  62. */  
  63.   const void* cpu_data();//获取cpu数据,返回void * 指针  
  64.   void set_cpu_data(void* data);//用一个void * 指针修改指针,功能:清空CPU的数据  
  65.   const void* gpu_data();//获取gpu数据,返回void * 指针  
  66.   
  67.   
  68.   void* mutable_cpu_data();//获取可以更改cpu数据,返回void * 指针,并改变数据的状态为HEAD_AT_CPU  
  69.   void* mutable_gpu_data();//获取可以更改gpu数据,返回void * 指针,并改变数据的状态为HEAD_AT_GPU  
  70. //关于SymceHead,有四种状态,分别是未初始化,数据在 cpu 中,数据在 gpu 中,  
  71. //数据在 cpu和 gpu 中都有  
  72.   enum SyncedHead { UNINITIALIZED, HEAD_AT_CPU, HEAD_AT_GPU, SYNCED };//enum枚举值  
  73. /* 
  74. 返回数据状态和大小。 
  75. */  
  76.   SyncedHead head() { return head_; }//获得枚举值  
  77.   size_t size() { return size_; }//获得数据大小  
  78.   
  79.  private:  
  80. /* 
  81. 功能:把数据放到cpu上 
  82. 1.数据未初始化,则在cpu申请内存(申请为0)。此时状态为HEAD_AT_CPU 
  83. 2.数据本来在gpu,则从gpu拷贝内存到cpu。此时状态为SYNCED 
  84. 3.数据本来在cpu,不做处理 
  85. 4.数据在cpu和gpu都有,不做处理 
  86. */  
  87.   void to_cpu();  
  88. /* 
  89. 功能:把数据放到gpu上 
  90. 1.数据未初始化,在gpu申请内存(申请为0)。此时状态为HEAD_AT_GPU 
  91. 2.数据在cpu,从cpu拷贝到gpu。此时状态为SYNCED 
  92. 3.数据在gpu,不做操作。 
  93. 4.数据在cpu和gpu都有,不做操作。 
  94. */  
  95.   void to_gpu();   
  96.   void* cpu_ptr_;//指向cpu的指针  
  97.   void* gpu_ptr_;//指向gpu的指指针  
  98.   size_t size_; //大小  
  99.   SyncedHead head_; //数据存放的位置,枚举值之一  
  100.   bool own_cpu_data_;//是否有cpu数据  
  101. /*DISABLE_COPY_AND_ASSIGN是一个宏,用来把该类的拷贝函数和等号操作符给禁止掉,如果想让你的类 
  102. 不能使用 copy 构造函数和赋值操作符,只要将该类的 copy 构造函数和赋值操作符函数定义为 private  
  103. 即可,并且只是声明,不用实现 . 
  104. */  
  105.   DISABLE_COPY_AND_ASSIGN(SyncedMemory);  
  106. };  // class SyncedMemory  
  107.   
  108. }  // namespace caffe  
  109.   
  110. #endif  // CAFFE_SYNCEDMEM_HPP_  
posted @ 2016-03-31 10:21  菜鸡一枚  阅读(835)  评论(0编辑  收藏  举报