caffe学习

初学caffe

caffe中syncedmemory简介

最近在看caffe的源码,Syncedmem类是caffe中内存分配管理的类,主要完成内存的分配和释放,以及cpu和gpu之间数据同步的函数。
1. 头文件
include “caffe/common.hpp”:此文件中主要定义了caffe的单例化接口;
include “caffe/util/math_functions.hpp”:主要定义caffe 中的数学运算函数,主要是矩阵运算;
2. 定义了两个内联函数CaffeMallocHost和CaffeFreeHost通过调用malloc()函数来实现内存的分配和释放,Syncedmem类的主要功能也由这两个函数完成。

caffe/syncedmem.hpp文件的详细介绍

#ifndef CAFFE_SYNCEDMEM_HPP_
#define CAFFE_SYNCEDMEM_HPP_
#include <cstdlib>

#ifdef USE_MKL
#include "mkl.h"
#endif
#include "caffe/common.hpp"

namespace caffe {
/*内存分配函数,如果caffe编译为cpu—only,则调用c语言中的malloc函数分配内存,如果是gpu,则调用cudaMalloc函数分配内存*/
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;
}
#endif
#ifdef USE_MKL
  *ptr = mkl_malloc(size ? size:1, 64);
#else
  *ptr = malloc(size);
#endif
  *use_cuda = false;
  CHECK(*ptr) << "host allocation of size " << size << " failed";
}
/*内存释放函数,cpu模式调用free(),gpu调用cudafree()*/
inline void CaffeFreeHost(void* ptr, bool use_cuda) {
#ifndef CPU_ONLY
  if (use_cuda) {
    CUDA_CHECK(cudaFreeHost(ptr));
    return;
  }
#endif
#ifdef USE_MKL
  mkl_free(ptr);
#else
  free(ptr);
#endif
}


/**
 * @brief Manages memory allocation and synchronization between the host (CPU)
 *        and device (GPU).
 *
 * TODO(dox): more thorough description.
 */
class SyncedMemory {
 public:
 //默认构造函数
  SyncedMemory();
  //构造函数
  explicit SyncedMemory(size_t size);
  //析构函数
  ~SyncedMemory();
  //获取cpu上的数据流
  const void* cpu_data();
  //设置cpu内存上的数据
  void set_cpu_data(void* data);
  //获取gpu上的数据
  const void* gpu_data();
  //设置gpu上的数据
  void set_gpu_data(void* data);
  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_; }

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

 private:
  void check_device();
  //使用cpu内存   
  void to_cpu();
  //使用gpu内存
  void to_gpu();
  //指向cpu内存的指针
  void* cpu_ptr_;
  //指向gpu内存的指针
  void* gpu_ptr_;
  分配内存的大小
  size_t size_;
  //同步状态
  SyncedHead head_;
  //是否拥有cpu或gpu数据
  bool own_cpu_data_;
  bool cpu_malloc_use_cuda_;
  bool own_gpu_data_;
  int device_;

  DISABLE_COPY_AND_ASSIGN(SyncedMemory);
};  // class SyncedMemory

}  // namespace caffe

#endif  // CAFFE_SYNCEDMEM_HPP_

caffe/syncedmem.cpp文件详细介绍

namespace caffe {
//构造函数,未初始化
SyncedMemory::SyncedMemory()
      : cpu_ptr_(NULL), gpu_ptr_(NULL), size_(0), head_(UNINITIALIZED),
        own_cpu_data_(false), cpu_malloc_use_cuda_(false), own_gpu_data_(false) {
#ifndef CPU_ONLY
#ifdef DEBUG
  CUDA_CHECK(cudaGetDevice(&device_));
#endif
#endif
}
//构造函数,确定分配内存的大小,未初始化
SyncedMemory::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) {
#ifndef CPU_ONLY
#ifdef DEBUG
  CUDA_CHECK(cudaGetDevice(&device_));
#endif
#endif
}
//析构函数,释放内存
SyncedMemory::~SyncedMemory() {
  check_device();
  if (cpu_ptr_ && own_cpu_data_) {
CaffeFreeHost(cpu_ptr_, cpu_malloc_use_cuda_);
  }

#ifndef CPU_ONLY
  if (gpu_ptr_ && own_gpu_data_) {
CUDA_CHECK(cudaFree(gpu_ptr_));
  }
#endif  // CPU_ONLY
}   
//在Hostcpu上分配内存
inline void SyncedMemory::to_cpu() {
  check_device();
  switch (head_) {
  //如果数据未初始化,则申请cpu内存
  case UNINITIALIZED:
    CaffeMallocHost(&cpu_ptr_, size_, &cpu_malloc_use_cuda_);
    caffe_memset(size_, 0, cpu_ptr_);
    //数据在cpu上
    head_ = HEAD_AT_CPU;
    own_cpu_data_ = true;
    break;
  /*若数据在gpu上,则在cpu上重新申请内存,并将gpu上的数据同步到cpu内存上,同时将数据状态设置为SYNCED(同步)*/
  case HEAD_AT_GPU:
#ifndef CPU_ONLY
    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;
#endif
    break;
  case HEAD_AT_CPU:
  case SYNCED:
    break;
  }
}
//将数据copy到gpu上
inline void SyncedMemory::to_gpu() {
    check_device();
#ifndef CPU_ONLY
    switch (head_) {
    //若数据没有初始化,则在gpu上申请内存并将数据状态设置在gpu上
    case UNINITIALIZED:
      CUDA_CHECK(cudaMalloc(&gpu_ptr_, size_));
      caffe_gpu_memset(size_, 0, gpu_ptr_);
      head_ = HEAD_AT_GPU;
      own_gpu_data_ = true;
      break;
    //若数据在cpu上,在gpu上申请相同大小的内存,并将数据copy到gpu上,同时将数据状态设置为SYNCED(同步)
    case HEAD_AT_CPU:
      if (gpu_ptr_ == NULL) {
        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
}
//将数据同步到cpu上,并返回指向data的指针
const void* SyncedMemory::cpu_data() {
  check_device();
  to_cpu();
  return (const void*)cpu_ptr_;
}
//重新设置cpu上的数据
void SyncedMemory::set_cpu_data(void* data) {
  check_device();
  CHECK(data);
  //若cpu上拥有数据,则将指向该部分数据的内存释放,并将指针cpu_ptr_指向data
  if (own_cpu_data_) {
    CaffeFreeHost(cpu_ptr_, cpu_malloc_use_cuda_);
  }
  cpu_ptr_ = data;
  //数据状态设置为在cpu上
  head_ = HEAD_AT_CPU;
  //原有的数据被释放掉了,状态设置为false
  own_cpu_data_ = false;
}   
//返回指向gpu上数据的指针
const void* SyncedMemory::gpu_data() {
  check_device();
#ifndef CPU_ONLY
  to_gpu();
  return (const void*)gpu_ptr_;
#else
  NO_GPU;
  return NULL;
#endif
}
//重新设置gpu上的数据
void SyncedMemory::set_gpu_data(void* data) {
  check_device();
#ifndef CPU_ONLY
  CHECK(data);
  //若gpu上含有数据,就将该部分内存释放
  if (own_gpu_data_) {
    CUDA_CHECK(cudaFree(gpu_ptr_));
  }
  //指针指向data
  gpu_ptr_ = data;
  //数据存放在gpu上
  head_ = HEAD_AT_GPU;
  own_gpu_data_ = false;
#else
  NO_GPU;
#endif
}
//数据同步到cpu上
void* SyncedMemory::mutable_cpu_data() {
  check_device();
  to_cpu();
  head_ = HEAD_AT_CPU;
  return cpu_ptr_;
}
//数据同步到gpu上
void* SyncedMemory::mutable_gpu_data() {
  check_device();
#ifndef CPU_ONLY
  to_gpu();
  head_ = HEAD_AT_GPU;
  return gpu_ptr_;
#else
  NO_GPU;
  return NULL;
#endif
}
//将cpu上的数据copy到gpu上
#ifndef CPU_ONLY
void SyncedMemory::async_gpu_push(const cudaStream_t& stream) {
  check_device();
  CHECK(head_ == HEAD_AT_CPU);
  if (gpu_ptr_ == NULL) {
    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
//若有多个gpu,确认数据在哪个gpu上
void SyncedMemory::check_device() {
#ifndef CPU_ONLY
#ifdef DEBUG
  int device;
  cudaGetDevice(&device);
  CHECK(device == device_);
  if (gpu_ptr_ && own_gpu_data_) {
    cudaPointerAttributes attributes;
    CUDA_CHECK(cudaPointerGetAttributes(&attributes, gpu_ptr_));
    CHECK(attributes.device == device_);
  }
#endif
#endif
}

}  // namespace caffe

作为初入深度学习领域的菜鸟,刚刚接触caffe和c++,写此博客的目的在于加深自己的理解和记忆,当然了在理解上可能存在错误和偏差,欢迎各位大牛多多指教!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值