caffe1源码解析从入门到放弃1):内存管理syncedmem.hpp / syncedmem.cpp
来源:互联网 发布:mac 不能剪切 编辑:程序博客网 时间:2024/05/21 06:41
/*这些代码都是本人在linux-nsight-eclipse环境下纯手打。 文章结尾都会抛出一些本人尚未解决的问题,欢迎各路大神拍砖。 文章属于学习交流性质,随着本人学力的提升,此blog将会长期修正更新。 * syncedmem.hpp * Created on: Jun 4, 2017 * Author: pan */#ifndef SYNCEDMEM_HPP_#define SYNCEDMEM_HPP_#include <cstdlib>#include "caffe/common.hpp"/*定义了caffe名称空间,内部封装了caffe所有的类和方法, * eg:using namespace caffe / using namespace std*/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. /*如果主机支持CUDA并且工作在GPU模式下,主机内存将会 allocated(分配) pinned, 使用cudaMallocHost(). * 它避免了dynamic pinning for transfers (DMA).在单GPU情况下使用cudaMallocHost(),这个操作在性能 * 上的提高看起来几乎可以忽视。但是在多GPU并行训练的情况下,cudaMallocHost()可能会显的更重要。最重要的是, * cudaMallocHost()的使用提高了在多GPU环境下大模型的稳定性。 * caffe工作在GPU模式下使用cudaMallocHost()在主机上分配内存将会比使用malloc()方法有性能和稳定性的提高。 */ /*在主机上分配内存,CaffeMallocHost(&cpu_ptr_, size_, &cpu_malloc_use_cuda_);方法使用二级指针 cpu_ptr_分配内存*/ inline void CaffeMallocHost(void** ptr, size_t size, bool* use_cuda) { #ifndef CPU_ONLY if(Caffe::mode() == Caffe::GPU) { CUDA_CHECK(cudaMallocHost(ptr, size));//***************** *use_cuda = true; return ;//在void类型的函数中,return用于返回空,不是返回 0 值 } #endif /*这里分配了size个字节的内存,由于使用的是void*最后要强制类型转换成特定类型的 * 指针eg: static_cast<int*> cpu_ptr_ 。这点在Blob中会详细陈述*/ *ptr = malloc(size); *use_cuda = false; CHECK(*ptr)<<"host allocation of size "<< size <<" failed";//********************** } /*内存释放方法,由于在cuda环境下有两种主机分配内存的方法,所以在这里做了一个宏定义处理,分别是 cudaFreeHost()和 free()*/ inline void CaffeFreeHost(void* ptr, bool use_cuda) { #ifndef CPU_ONLY if(use_cuda) { CUDA_CHECK(cudaFreeHost(ptr));//*************** return ; } #endif free(ptr); } /** * @brief Manages memory allocation and synchronization between the host (CPU) * and device (GPU). * * TODO(dox): more thorough description. */ /* *SyncedMemory类 @简单的用于在主机(CPU)和 设备(GPU)之间进行内存分配和同步工作,也就是说在CPU和GPU *之间管理内存。 *TODO(dox): more thorough description. * */ 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 表示构造函数不接受隐式转换 eg: ********************/ explicit SyncedMemory(size_t size) : 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){} /*析构函数中定义了释放堆区内存的操作,在caffe的数据容器Blob中,定义了shared_ptr<syncedmemory> data_ * 定义了shared_ptr<syncedmemory> diff_ 的智能指针,通过reset方法控制内存的释放。由于nvcc编译器 * 对C++11支持的不好,暂且不能够使用unique_ptr智能指针,目前只能调用boost库的shared_ptr*/ ~SyncedMemory(){}; public: /*cpu_data()和gpu_data()返回值为const void* 表示cpu_ptr_和gpu_ptr_所指向的内存空间不允许被修改 * 与此相反void* mutable_cpu_data() 和 void* mutable_gpu_data(); 返回的是void* 的指针,也即内存返回的 * 内存空间是允许修改的*/ const void* cpu_data(); void set_cpu_data(void* data); const void* gpu_data(); void set_gpu_data(void* data); void* mutable_cpu_data(); void* mutable_gpu_data(); /*此处定义了一个枚举类型SyncedHead主要作用是标志头指针状态,其中SYNCED表示内存已经同步*/ enum SyncedHead {UNINITIALIZED, HEAD_AT_CPU, HEAD_AT_GPU, SYNCED}; SyncedHead head() {return head_;} //size_t是标准C库中定义的,应为unsigned int,在64位系统中为 long unsigned int size_t size() {return size_;} #ifndef CPU_ONLY void async_gpu_push(const cudaStream_t& stream);//***************** #endif private: SyncedHead head_;//头指针位置 /*控制内存同步的方法,如果head在cpu上执行to_cpu()表示内存已经同步,否则要调用caffe_gpu_memcpy()方法 * 实质上调用的是cudaMemcpy(Y, X, N, cudaMemcpyDefault),caffe_gpu_memcpy()做了一层封装而已。 * 同理to_gpu()*/ void to_cpu(); void to_gpu(); void* cpu_ptr_; void* gpu_ptr_; size_t size_; bool own_cpu_data_; bool cpu_malloc_use_cuda_; bool own_gpu_data_; int gpu_device_; DISABLE_COPY_AND_ASSIGN(SyncedMemory);//*************** };// class SyncedMemory};//namespace caffe#endif /* SYNCEDMEM_HPP_ */---------------------------------------------------------------------------------------------------------------------------------------/* * syncedmem.cpp * * Created on: Jun 4, 2017 * Author: pan */#include "common.hpp"#include "syncedmem.hpp"#include "util/math_functions.hpp"namespace caffe{ SyncedMemory::~SyncedMemory() { /*cpu_ptr_不为NULL,不能释放NULL指针, own_cpu_data_标志位不为 0这个标志位不知道如何理解 ??????????????????*/ if(cpu_ptr_ && own_cpu_data_) { CaffeFreeHost(cpu_ptr_, cpu_malloc_use_cuda_); } #ifndef CPU_ONLY if(gpu_ptr_ && own_gpu_data_) { int initial_device; cudaGetDevice(&initial_device); if (gpu_device_ != -1) { CUDA_CHECK(cudaSetDevice(gpu_device_));//???????????????? } CUDA_CHECK(cudaFree(gpu_ptr_)); cudaSetDevice(initial_device); } #endif } //同步内存到CPU 即设置cpu_ptr_ inline void SyncedMemory::to_cpu() { switch (head_) { case UNINITIALIZED: CaffeMallocHost(&cpu_ptr_, size_, &cpu_malloc_use_cuda_); caffe_memset(size_, 0, cpu_ptr_); head_ = HEAD_AT_CPU; own_cpu_data_ = true; break; case HEAD_AT_GPU: #ifndef CPU_ONLY//Makefile.config中定义 if (cpu_ptr_ == NULL) { CaffeMallocHost(&cpu_ptr_, size_, &cpu_malloc_use_cuda_); own_cpu_data_ = true; } caffe_gpu_memcpy(size_, gpu_ptr_, cpu_ptr_); head_ = SYNCED; #else NO_GPU;//Makefile.config中定义 #endif break; case HEAD_AT_CPU://头指针指向CPU内存已经同步 case SYNCED: break; } }//to_cpu() //同步内存到CPU 即设置gpu_ptr_ inline void SyncedMemory::to_gpu() { #ifndef CPU_ONLY switch (head_) { case UNINITIALIZED://???????????????????/ head_ = HEAD_AT_GPU; own_gpu_data_ = true; break; case HEAD_AT_CPU: if(gpu_ptr_ == NULL) { CUDA_CHECK(cudaGetDevice(&gpu_device_)); CUDA_CHECK(cudaMalloc(&gpu_ptr_, size_)); own_gpu_data_ = true; } caffe_gpu_memcpy(size_, cpu_ptr_, gpu_ptr_); head_ = SYNCED; break; case HEAD_AT_GPU: case SYNCED: break; } #else NO_GPU #endif }//to_gpu() //获取cpu 堆区内存头指针 const void* SyncedMemory::cpu_data() { to_cpu(); return (const void*)cpu_ptr_; } void SyncedMemory::set_cpu_data(void* data) { CHECK(data);//??????????????????????? //????if(data == NULL) return -1;????????????????? if(own_cpu_data_) { CaffeFreeHost(cpu_ptr_, cpu_malloc_use_cuda_); } cpu_ptr_ = data; head_ = HEAD_AT_CPU; own_cpu_data_ = false; } const void* SyncedMemory::gpu_data() { #ifndef CPU_ONLY to_gpu(); return (const void*)gpu_ptr_; #else NO_GPU; return NULL; #endif } void SyncedMemory::set_gpu_data(void* data) { #ifndef CPU_ONLY CHECK(data); if (own_gpu_data_) { int initial_device; cudaGetDevice(&initial_device); if (gpu_device_ != -1) { CUDA_CHECK(cudaSetDevice(gpu_device_)); } CUDA_CHECK(cudaFree(gpu_ptr_)); cudaSetDevice(initial_device); } gpu_ptr_ = data; head_ = HEAD_AT_GPU; own_gpu_data_ = false; #else NO_GPU; #endif } void* SyncedMemory::mutable_cpu_data() { to_cpu(); head_ = HEAD_AT_CPU; return cpu_ptr_; } void* SyncedMemory::mutable_gpu_data() { #ifndef CPU_ONLY to_gpu(); head_ = HEAD_AT_GPU; return gpu_ptr_; #else NO_GPU; return NULL; #endif }#ifndef CPU_ONLY void SyncedMemory::async_gpu_push(const cudaStream_t& stream) { CHECK(head_ == HEAD_AT_CPU); if (gpu_ptr_ == NULL) { CUDA_CHECK(cudaGetDevice(&gpu_device_)); CUDA_CHECK(cudaMalloc(&gpu_ptr_, size_)); own_gpu_data_ = true; } const cudaMemcpyKind put = cudaMemcpyHostToDevice; CUDA_CHECK(cudaMemcpyAsync(gpu_ptr_, cpu_ptr_, size_, put, stream)); // Assume caller will synchronize on the stream before use head_ = SYNCED; }#endif};//namespace caffe
自己写的测试代码分析构造函数和析构函数的行为/* * caffe.cpp * * Created on: Jun 5, 2017 * Author: pan */#include <iostream>#include <climits>#include <cstdlib>#include <boost/shared_ptr.hpp>using namespace std;using boost::shared_ptr;// inline void CaffeMallocHost(void** ptr, size_t size, bool* use_cuda)inline void CaffeMallocoHost(void** ptr, size_t size){// #ifndef CPU_ONLY// cudaMallocHost(ptr, size);// void* ptr = (void*)(new char[size]); *ptr = malloc(size); if(ptr == NULL) { cout<<"malloc error in fuction CaffeMallocoHost !"<<endl; }}inline void CaffeFreeHost(void* ptr){ cout<<">>>>>>>>>>>>>CaffeFreeHost"; if(ptr != NULL) { free(ptr); cout<<">>>>>>>>>>>now free cpu_ptr_ "<<endl; }}class synced{public: synced(size_t size, int num) : cpu_ptr_(NULL), gpu_ptr_(NULL), own_cpu_data_(false),own_gpu_data_(false), size_(size), cpu_malloc_use_cuda_(0),num_(num){cout<<"constructor "<< num_<<" called !\n";} ~synced() { CaffeFreeHost(cpu_ptr_); cout<<"destructor "<<num_<<" called!\n"; } void to_cpu() { CaffeMallocoHost(&cpu_ptr_, size_); } void* cpu_data() { to_cpu(); return cpu_ptr_; }private: void* cpu_ptr_; bool own_cpu_data_; void* gpu_ptr_; bool own_gpu_data_; bool cpu_malloc_use_cuda_; size_t size_; int num_;};int main(){ shared_ptr<synced> data; data.reset(new synced(10 * sizeof(int), 1)); int* ptr = static_cast<int*>(data->cpu_data()); ptr[9] = 10; // cout<< INT_MAX <<endl; return 0;}
抛出问题: caffe内存管理如何使用new delete 形式重写CaffeFreeHost() ; CaffeMallocHost()。 主要困难是c++如何分配一个void* 并delete 一个void* 。
阅读全文
1 0
- caffe1源码解析从入门到放弃1):内存管理syncedmem.hpp / syncedmem.cpp
- caffe源码阅读2-syncedmem.hpp+.cpp
- caffe源码深入学习3:更底层的数据信息存取与交换代码:syncedmem.hpp和syncedmem.cpp
- Caffe源码解读2--syncedmem.hpp
- Caffe源码解析2:SyncedMem
- caffe源码追踪--syncedmem
- Caffe源码中syncedmem文件分析
- Caffe 源码阅读笔记 [基本模块] Syncedmem & Blob
- mybatis从入门到放弃(1)
- Vue源码 --- 从入门到放弃
- 从入门到放弃C语言-入门篇(1)
- 梳理caffe代码syncedmem(二)
- 从入门到放弃C语言-瞎倒腾(1)
- JavaWeb从入门到放弃(1)-配置环境
- Java web从入门到放弃(1)
- JavaScript从入门到放弃 1
- OpenLayers从入门到放弃(1)
- WebMagic从入门到放弃(1)
- Executor并发框架
- es2015
- 向zendDesk发送ticket
- app电量测试
- 187. Repeated DNA Sequences
- caffe1源码解析从入门到放弃1):内存管理syncedmem.hpp / syncedmem.cpp
- 排序算法(九)——八大排序算法总结
- thinkphp3.2.1分页路由
- 快速排序的稳定化实现
- js、jQuery、layer实现弹出层的打开、关闭
- java在list集合指定位置插入对象和js在数组指定位置插入对象的方法
- java线程
- ECMAScript6(6):数组的扩展
- 最全的常用正则表达式大全——包括校验数字、字符、一些特殊的需求等