Caffe原始碼解讀 syncedmem類

2021-08-27 08:08:24 字數 4304 閱讀 8947

記憶體同步(syncedmem)類的作用在於管理主機(cpu)和裝置(gpu)之間的記憶體分配和資料同步,封裝了二者之間的互動操作。

這個類沒有對應的protobuffer描述,所以直接看./include/caffe/syncedmem.cpp檔案:

#ifndef caffe_syncedmem_hpp_

#define caffe_syncedmem_hpp_

#include #include "caffe/common.hpp"

namespace caffe

#endif

*ptr = malloc(size); // cpu模式下分配記憶體

*use_cuda = false;

check(*ptr) << "host allocation of size " << size << " failed";

}// 和上面函式相對應的記憶體釋放

inline void caffefreehost(void* ptr, bool use_cuda)

#endif

free(ptr); // 用的malloc分配的記憶體

}// 負責記憶體分配和裝置同步

class syncedmemory

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) {}

~syncedmemory();

// 對cpu,gpu資料的讀寫,不贅述。為什麼沒有set_cpu_diff() ???

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();

// 共享記憶體的4種狀態:未初始化,cpu資料有效,gpu資料有效,已同步

enum syncedhead ;

// 返回當前共享記憶體的狀態

syncedhead head()

// 返回儲存空間的尺寸 = 元素數 * 單個元素所佔位元組數

size_t size()

#ifndef cpu_only

void async_gpu_push(const cudastream_t& stream);

#endif

private:

void to_cpu(); // 資料同步至cpu

void to_gpu(); // 資料同步至gpu

void* cpu_ptr_; // cpu中資料的指標

void* gpu_ptr_; // gpu中資料的指標

size_t size_; // 儲存空間的大小

syncedhead head_; // 共享記憶體的狀態

bool own_cpu_data_; // cpu擁有資料所有權

bool cpu_malloc_use_cuda_; // 分配cpu記憶體是否用cudamallochost()分配。

bool own_gpu_data_; // gpu擁有資料所有權

int gpu_device_; // gpu裝置號

// 禁用拷貝構造以及賦值運算子

// 使用grep可以查到,該巨集定義在common.hpp第35行

// 該巨集就是把拷貝構造和賦值運算子設定為private而已

disable_copy_and_assign(syncedmemory);

}; // class syncedmemory

} // namespace caffe

#endif // caffe_syncedmem_hpp_

這個模擬blob簡單多了,下面看對應的./src/caffe/syncedmem.cpp檔案:

#include "caffe/common.hpp"

#include "caffe/syncedmem.hpp"

#include "caffe/util/math_functions.hpp"

namespace caffe

// 如果資料在gpu上

#ifndef cpu_only

if (gpu_ptr_ && own_gpu_data_)

cuda_check(cudafree(gpu_ptr_));

cudasetdevice(initial_device);

}#endif // cpu_only

}// 資料同步到cpu上

inline void syncedmemory::to_cpu()

caffe_gpu_memcpy(size_, gpu_ptr_, cpu_ptr_); // 資料複製

head_ = synced;

#else

no_gpu;

#endif

break;

// 資料已經為cpu擁有所有權或者在記憶體共享狀態,則什麼都不管

case head_at_cpu:

case synced:

break; }}

// 原理同上

inline void syncedmemory::to_gpu()

caffe_gpu_memcpy(size_, cpu_ptr_, gpu_ptr_); //資料拷貝,呼叫了cudamemcpy函式

head_ = synced;

break;

case head_at_gpu:

case synced:

break;

}#else

no_gpu;

#endif

}// 獲取cpu中的資料,唯讀

const void* syncedmemory::cpu_data()

// 設定獲取cpu中的資料

void syncedmemory::set_cpu_data(void* data)

cpu_ptr_ = data;

head_ = head_at_cpu;

own_cpu_data_ = false;

}// 獲取gpu中的資料,唯讀

const void* syncedmemory::gpu_data()

// 設定gpu中的資料

void syncedmemory::set_gpu_data(void* data)

// 呼叫這個函式的時候,如果gpu內有資料會被直接清空,要注意

cuda_check(cudafree(gpu_ptr_));

cudasetdevice(initial_device);

} gpu_ptr_ = data;

head_ = head_at_gpu;

own_gpu_data_ = false;

#else

no_gpu;

#endif

}// 讀寫獲取cpu資料

void* syncedmemory::mutable_cpu_data()

// 讀寫獲取gpu資料

void* syncedmemory::mutable_gpu_data()

// cuda中的流同步,這裡傳入乙個非同步流,在計算的時候向gpu複製資料。

#ifndef cpu_only

void syncedmemory::async_gpu_push(const cudastream_t& stream)

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

syncedmem模擬較簡單,主要是完成cpu和gpu之間的資料互動問題~

《21天實戰caffe》

(介紹了流同步)

caffe 分類原始碼解讀

首先,新建乙個classifier的c 類,其中標頭檔案classifier.h如下 其中,classifier函式 根據模型的配置檔案.prototxt,訓練好的模型檔案.caffemodel,建立模型,得到net 處理均值檔案,得到mean 讀入labels檔案,得到labels classif...

Caffe原始碼 math functions 解析

math function 定義了caffe 中用到的一些矩陣操作和數值計算的一些函式,這裡以float型別為例做簡單的分析 template void caffe cpu gemm const cblas transpose transa,const cblas transpose transb,...

caffe原始碼解析

目錄目錄 簡單介紹 主要函式readprotofromtextfile 函式 writeprotototextfile 函式 readprotofrombinaryfile 函式 writeprototobinaryfile 函式 readimagetocvmat 函式 matchext 函式 cv...