Caffe源码中syncedmem文件分析
生活随笔
收集整理的這篇文章主要介紹了
Caffe源码中syncedmem文件分析
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
Caffe源碼(caffe version:09868ac , date: 2015.08.15)中有一些重要文件,這里介紹下syncedmem文件。
1.??????include文件:
(1)、<caffe/common.hpp>:此文件的介紹可以參考:http://blog.csdn.net/fengbingchun/article/details/54955236? ;
(2)、<caffe/util/math_functions.hpp>:此文件的介紹可以參考: http://blog.csdn.net/fengbingchun/article/details/56280708?;
2.??????內聯函數CaffeMallocHost/CaffeFreeHost:
(1)、CaffeMallocHost:CPU模式下,通過調用C語言的malloc函數分配內存;
(2)、CaffeFreeHost:CPU模式下,通過調用C語言的free函數釋放內存;
3.????????類SyncedMemory:在主機(CPU)和設備(GPU)之間管理內存分配和數據同步,封裝CPU和GPU之間數據交互操作。
<caffe/syncedmem.hpp>文件的詳細介紹如下:
#ifndef CAFFE_SYNCEDMEM_HPP_
#define CAFFE_SYNCEDMEM_HPP_#include <cstdlib>#include "caffe/common.hpp"
#include "caffe/util/math_functions.hpp"namespace caffe {// If CUDA is available and in GPU mode, host memory will be allocated pinned,
// using cudaMallocHost. It avoids dynamic pinning for transfers (DMA).
// The improvement in performance seems negligible in the single GPU case,
// but might be more significant for parallel training. Most importantly,
// it improved stability for large models on many GPUs.
// CPU模式下,通過調用C語言的malloc函數分配內存
inline void CaffeMallocHost(void** ptr, size_t size) {
#ifndef CPU_ONLYif (Caffe::mode() == Caffe::GPU) {CUDA_CHECK(cudaMallocHost(ptr, size));return;}
#endif*ptr = malloc(size);CHECK(*ptr) << "host allocation of size " << size << " failed";
}// CPU模式下,通過調用C語言的free函數釋放內存
inline void CaffeFreeHost(void* ptr) {
#ifndef CPU_ONLYif (Caffe::mode() == Caffe::GPU) {CUDA_CHECK(cudaFreeHost(ptr));return;}
#endiffree(ptr);
}/*** @brief Manages memory allocation and synchronization between the host (CPU)* and device (GPU).** TODO(dox): more thorough description.*/
// 在主機(Host/CPU)和設備(Device/GPU)之間管理內存分配和數據同步,封裝CPU和GPU之間數據交互操作
class SyncedMemory {public:
// 默認構造函數,簡單初始化,數據狀態置為UNINITIALIZEDSyncedMemory(): cpu_ptr_(NULL), gpu_ptr_(NULL), size_(0), head_(UNINITIALIZED),own_cpu_data_(false), own_gpu_data_(false), gpu_device_(-1) {}
// 帶size參數的顯示構造函數,并未分配內存,數據狀態置為UNINITIALIZEDexplicit SyncedMemory(size_t size): cpu_ptr_(NULL), gpu_ptr_(NULL), size_(size), head_(UNINITIALIZED),own_cpu_data_(false), own_gpu_data_(false), gpu_device_(-1) {}
// 析構函數,CPU模式下,當cpu_ptr_非空并且own_cpu_data_為true時,僅會調用CaffeFreeHost函數釋放內存~SyncedMemory();
// 獲取CPU數據指針,數據不可更改,內部會調用to_cpu函數,在CPU模式下,數據狀態為HEAD_AT_CPU,在GPU模式下,數據狀態置為SYNCEDconst void* cpu_data();
// 調用CaffeFreeHost釋放內存,如果own_cpu_data_為非空,則調用CaffeFreeHost釋放內存,并修改CPU數據指針使其指向data,并置own_cpu_data_為false,數據狀態置為HEAD_AT_CPUvoid set_cpu_data(void* data);
// 獲取GPU數據指針,數據不可更改,在GPU模式下,數據狀態為HEAD_AT_GPU,在CPU模式下,數據狀態置為SYNCEDconst void* gpu_data();
// 在GPU模式下,內部會調用to_gpu函數,如果own_gpu_data_為非空,調用cudaFree釋放顯存,并修改GPU數據指針使其指向data,并置own_gpu_data_為false,在GPU模式下,數據狀態置為HEAD_AT_GPUvoid set_gpu_data(void* data);
// 獲取CPU數據指針,數據可更改,內部會調用to_cpu函數,數據狀態置為HEAD_AT_CPUvoid* mutable_cpu_data();
// 獲取GPU數據指針,數據可更改,在GPU模式下,內部會調用to_gpu函數,數據狀態置為HEAD_AT_GPUvoid* mutable_gpu_data();
// SyncedHead為枚舉類型,數據存放的位置,包括四種數據狀態,依次為未初始化、在CPU、在GPU、已同步enum SyncedHead { UNINITIALIZED, HEAD_AT_CPU, HEAD_AT_GPU, SYNCED };
// 返回數據狀態,即數據存放的位置SyncedHead head() { return head_; }
// 返回數據大小(字節)size_t size() { return size_; }#ifndef CPU_ONLY
// 異步推送數據從CPU到GPU,并置數據狀態為SYNCEDvoid async_gpu_push(const cudaStream_t& stream);
#endifprivate:
// 把數據存放到CPU上,
// 如果數據狀態為UNINITIALIZED,則調用CaffeMallocHost分配內存,并初始化數據內容為0,置own_cpu_data_為true,置數據狀態為HEAD_AT_CPU,
// 如果數據狀態為HEAD_AT_GPU,如果在GPU模式下,如果cpu_ptr_為空,則調用CaffeMallocHost分配內存,并置own_cpu_data_為true,然后則將顯存數據拷貝到內存(數據同步),并將數據狀態置為SYNCED// 其它數據狀態不作任何操作void to_cpu();
// 把數據存放到GPU上,僅在GPU模式作操作,在CPU模式下不作任何操作,
// 如果數據狀態為UNINITIALIZED,則調用cudaMalloc分配顯存,并初始化數據內容為0,置數據狀態為HEAD_AT_GPU,并置own_gpu_data_為true
// 如果數據狀態為HEAD_AT_CPU,如果gpu_ptr_為空,則調用cudaMalloc分配顯存,并置own_gpu_data_為true,然后將內存數據拷貝到顯存(數據同步),并將數據狀態置為SYNCED
// 其它數據狀態不作任何操作void to_gpu();
// 指向CPU的數據指針void* cpu_ptr_;
// 指向GPU的數據指針void* gpu_ptr_;
// 數據大小(字節)size_t size_;
// 數據狀態,當前數據存放的位置SyncedHead head_;
// 是否通過SyncedMemory類分配了CPU內存bool own_cpu_data_;
// 是否通過SyncedMemory類分配了GPU顯存bool own_gpu_data_;
// 設備編號int gpu_device_;// 禁止使用SyncedMemory類的拷貝和賦值操作DISABLE_COPY_AND_ASSIGN(SyncedMemory);
}; // class SyncedMemory} // namespace caffe#endif // CAFFE_SYNCEDMEM_HPP_
測試代碼如下:
int test_caffe_syncedmem()
{caffe::SyncedMemory mem(10);caffe::SyncedMemory* p_mem = new caffe::SyncedMemory(10 * sizeof(float));if (mem.head() != caffe::SyncedMemory::UNINITIALIZED ||mem.size() != 10 ||p_mem->size() != 10 * sizeof(float) ||mem.cpu_data() == nullptr ||mem.mutable_cpu_data() == nullptr ||mem.head() != caffe::SyncedMemory::HEAD_AT_CPU) {fprintf(stderr, "Error\n");return -1;}fprintf(stderr, "p_mem size: %d\n", p_mem->size());fprintf(stderr, "mem size: %d\n", mem.size());void* cpu_data = mem.mutable_cpu_data();if (mem.head() != caffe::SyncedMemory::HEAD_AT_CPU) {fprintf(stderr, "Error\n");return -1;}caffe::caffe_memset(mem.size(), 1, cpu_data);for (int i = 0; i < mem.size(); ++i) {if ((static_cast<char*>(cpu_data))[i] != 1) {fprintf(stderr, "Error\n");return -1;}}cpu_data = mem.mutable_cpu_data();if (mem.head() != caffe::SyncedMemory::HEAD_AT_CPU) {fprintf(stderr, "Error\n");return -1;}caffe::caffe_memset(mem.size(), 2, cpu_data);for (int i = 0; i < mem.size(); ++i) {if ((static_cast<char*>(cpu_data))[i] != 2) {fprintf(stderr, "Error\n");return -1;}}delete p_mem;return 0;
}
測試結果如下:
GitHub: https://github.com/fengbingchun/Caffe_Test
總結
以上是生活随笔為你收集整理的Caffe源码中syncedmem文件分析的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Caffe源码中math_functio
- 下一篇: Intel TBB简介及在Windows