1 #ifndef CAFFE2_UTILS_MKL_MKL_MEMORY_H_ 2 #define CAFFE2_UTILS_MKL_MKL_MEMORY_H_ 8 #include "caffe2/core/tensor.h" 10 #include "caffe2/utils/mkl/mkl_dnn_cppwrapper.h" 16 CAFFE2_DECLARE_bool(caffe2_mkl_implicit_layout_change);
27 explicit PrimitiveWrapper(dnnPrimitive_t primitive) : primitive_(primitive) {}
29 template <
typename Creator,
typename FirstArg,
typename... Args>
31 creator(&primitive_, arg, args...);
36 MKLDNN_CHECK(dnnDelete<T>(primitive_));
40 template <
typename Creator,
typename... Args>
41 void Reset(Creator creator, Args&&... args) {
43 MKLDNN_SAFE_CALL(dnnDelete<T>(primitive_));
45 creator(&primitive_, args...);
48 operator dnnPrimitive_t()
const {
53 dnnPrimitive_t primitive_ = 0;
67 LayoutWrapper(
const dnnPrimitive_t primitive,
const dnnResourceType_t type) {
68 Reset(primitive, type);
73 const size_t dimension,
75 const size_t strides[]) {
76 Reset(dimension, size, strides);
82 MKLDNN_CHECK(dnnLayoutDelete<T>(layout_));
88 MKLDNN_CHECK(dnnLayoutDelete<T>(layout_));
89 CAFFE_ENFORCE(tensor.
size(),
"Cannot reset with an empty tensor.");
90 size_t dimension = tensor.
ndim();
91 size_t size[dimension];
92 size_t strides[dimension];
93 for (
int i = 0; i < dimension; ++i) {
94 size[i] = tensor.
dim(dimension - i - 1);
95 strides[i] = (i == 0) ? 1 : strides[i - 1] * size[i - 1];
97 MKLDNN_SAFE_CALL(dnnLayoutCreate<T>(&layout_, dimension, size, strides));
101 void Reset(
const dnnPrimitive_t primitive,
const dnnResourceType_t type) {
102 CAFFE_ENFORCE(primitive,
"Cannot reset with an unknwon primitive.");
104 type != dnnResourceNumber,
105 "Cannot reset with an unknown resource number.");
107 MKLDNN_CHECK(dnnLayoutDelete<T>(layout_));
110 dnnLayoutCreateFromPrimitive<T>(&layout_, primitive, type));
115 Reset(
const size_t dimension,
const size_t size[],
const size_t strides[]) {
117 MKLDNN_CHECK(dnnLayoutDelete<T>(layout_));
118 MKLDNN_SAFE_CALL(dnnLayoutCreate<T>(&layout_, dimension, size, strides));
121 operator dnnLayout_t()
const {
126 dnnLayout_t layout_ = 0;
136 template <
typename T>
144 const size_t dimension,
146 const size_t strides[],
147 const dnnPrimitive_t primitive =
nullptr,
148 const dnnResourceType_t type = dnnResourceNumber,
149 bool share_mem_if_possible =
false) {
150 Reset(dimension, size, strides, primitive, type, share_mem_if_possible);
155 template <
typename IndexType>
157 const vector<IndexType>& dims,
158 const dnnPrimitive_t primitive =
nullptr,
159 const dnnResourceType_t type = dnnResourceNumber,
160 bool share_mem_if_possible =
false) {
161 Reset(dims, primitive, type, share_mem_if_possible);
167 const size_t dimension,
169 const size_t strides[],
170 const dnnPrimitive_t primitive =
nullptr,
171 const dnnResourceType_t type = dnnResourceNumber,
172 bool share_mem_if_possible =
false) {
174 dims_.resize(dimension);
175 for (
int i = 0; i < dimension; ++i) {
176 dims_[i] = size[dimension - 1 - i];
178 user_layout_.Reset(dimension, size, strides);
180 layout_.Reset(primitive, type);
182 layout_.Reset(dimension, size, strides);
184 convert_in_.Reset(dnnConversionCreate<T>, user_layout_, layout_);
185 convert_out_.Reset(dnnConversionCreate<T>, layout_, user_layout_);
186 share_mem_if_possible_ = share_mem_if_possible;
187 layout_is_user_layout_ = dnnLayoutCompare<T>(layout_, user_layout_);
188 VLOG(2) <<
"layout is user layout? " << layout_is_user_layout_;
189 if (!share_mem_if_possible_) {
198 template <
typename IndexType>
200 const vector<IndexType>& dims,
201 const dnnPrimitive_t primitive =
nullptr,
202 const dnnResourceType_t type = dnnResourceNumber,
203 bool share_mem_if_possible =
false) {
205 dims_.resize(dims.size());
206 for (
int i = 0; i < dims.size(); ++i) {
209 size_t dimension = dims.size();
210 vector<size_t> size(dimension);
211 vector<size_t> strides(dimension);
212 for (
int i = 0; i < dimension; ++i) {
213 size[i] = dims[dimension - i - 1];
214 strides[i] = (i == 0) ? 1 : strides[i - 1] * size[i - 1];
216 user_layout_.Reset(dims.size(), size.data(), strides.data());
218 layout_.Reset(primitive, type);
220 layout_.Reset(dimension, size.data(), strides.data());
222 convert_in_.Reset(dnnConversionCreate<T>, user_layout_, layout_);
223 convert_out_.Reset(dnnConversionCreate<T>, layout_, user_layout_);
224 share_mem_if_possible_ = share_mem_if_possible;
225 layout_is_user_layout_ = dnnLayoutCompare<T>(layout_, user_layout_);
226 VLOG(2) <<
"layout is user layout? " << layout_is_user_layout_;
227 if (!share_mem_if_possible_) {
237 void CopyFrom(
const void* ptr) {
238 if (share_mem_if_possible_ && layout_is_user_layout_) {
239 VLOG(2) <<
"Sharing underlying memory and skip copy.";
240 buffer_.reset(const_cast<void*>(ptr), [](
void*) ->
void {});
242 VLOG(2) <<
"Copying external content.";
243 MKLDNN_SAFE_CALL(dnnConversionExecute<T>(
244 convert_in_, const_cast<void*>(ptr), buffer()));
252 "Dims does not match the expected dims of the resource.");
253 CopyFrom(tensor.template data<T>());
257 if (share_mem_if_possible_ && dnnLayoutCompare(other.layout_, layout_)) {
258 buffer_ = other.buffer_;
261 dnnConversionCreate<T>, other.layout_, layout_);
263 dnnConversionExecute<T>(convert, other.buffer_, buffer()));
267 bool ShareFromRaw(
const void* ptr) {
268 if (share_mem_if_possible_ && layout_is_user_layout_) {
269 buffer_.reset(const_cast<void*>(ptr), [](
void*) ->
void {});
276 bool ShareFromTensor(
const TensorCPU& tensor) {
280 "Dims does not match the expected dims of the resource.");
281 return ShareFromRaw(tensor.template data<T>());
285 if (share_mem_if_possible_ && dnnLayoutCompare<T>(other.layout_, layout_)) {
286 VLOG(2) <<
"Sharing underlying memory.";
287 buffer_ = other.buffer_;
288 if (!buffer_.get()) {
289 VLOG(2) <<
"Warning: the source MKLMemory has no content yet, so the " 290 "sharing actually has no effect.";
294 VLOG(2) <<
"Not sharing underlying memory.";
299 void CopyTo(
void* ptr)
const {
300 if (buffer_.get() == ptr) {
302 VLOG(2) <<
"CopyTo does not need actual copying, as we are sharing " 303 "memory with the output.";
307 buffer_.get(),
"Canot copy out from an uninitialized MKLMemory.");
308 VLOG(2) <<
"Copy to external memory.";
309 MKLDNN_SAFE_CALL(dnnConversionExecute<T>(convert_out_, buffer_.get(), ptr));
315 VLOG(2) <<
"CopyTo does not need actual copying, as we are sharing " 316 "memory with the output.";
328 const dnnPrimitive_t primitive =
nullptr,
329 const dnnResourceType_t type = dnnResourceNumber) {
330 if (buffer_.get() == other->buffer_.get()) {
331 VLOG(2) <<
"CopyTo does not need actual copying, as we are sharing " 332 "memory with the output.";
337 buffer_.get(),
"Canot copy out from an uninitialized MKLMemory.");
341 VLOG(2) <<
"CopyTo requires copying. Performing direct copy.";
343 dnnConversionCreate<T>, layout_, other->layout_);
344 if (dnnPrimitive_t(convert) ==
nullptr ||
345 dnnConversionExecute<T>(convert, buffer_.get(), other->buffer()) !=
347 VLOG(2) <<
"Direct copy failed, will need to allocate output.";
351 other->Reset(dims_, primitive, type);
353 dnnConversionCreate<T>, layout_, other->layout_);
355 dnnConversionExecute<T>(convert2, buffer_.get(), other->buffer()));
359 inline void* buffer() {
360 if (buffer_ ==
nullptr) {
362 layout_ !=
nullptr,
"Trying to allocate buffer but layout is empty.");
363 void* allocated =
nullptr;
364 MKLDNN_SAFE_CALL(dnnAllocateBuffer<T>(&allocated, layout_));
365 buffer_.reset(allocated, [](
void* ptr) ->
void {
366 MKLDNN_CHECK(dnnReleaseBuffer<T>(ptr));
369 return buffer_.get();
375 inline void* buffer()
const {
377 buffer_ !=
nullptr,
"Trying to refer to an unallocated buffer.");
378 return buffer_.get();
381 inline const vector<TIndex>& dims()
const {
385 inline const int ndim()
const {
return dims_.size(); }
387 inline int dim32(
const int i)
const {
388 CAFFE_ENFORCE_LT(dims_.at(i), std::numeric_limits<int>::max());
389 return static_cast<int>(dims_[i]);
397 inline TIndex
dim(
const int i)
const {
408 std::shared_ptr<void> View(
409 dnnLayout_t layout_wanted,
410 dnnPrimitive_t primitive,
411 dnnResourceType_t type)
const {
412 std::lock_guard<std::mutex> lock(buffer_lock_);
413 if (dnnLayoutCompare<T>(layout_wanted, layout_)) {
415 VLOG(2) <<
"Creating a view without the need of copying.";
416 return std::shared_ptr<void>(buffer_);
419 VLOG(2) <<
"Creating a view with copying.";
420 MKLDNN_SAFE_CALL(dnnAllocateBuffer<T>(&temp_buffer, layout_wanted));
422 dnnConversionCreate<T>, layout_, layout_wanted);
423 MKLDNN_SAFE_CALL(dnnConversionExecute<T>(
424 convert, buffer_.get(), temp_buffer));
425 if (FLAGS_caffe2_mkl_implicit_layout_change) {
426 VLOG(2) <<
"Implicit layout change set. " 427 "Changing the underlying storage.";
432 dims_, primitive, type, share_mem_if_possible_);
433 CAFFE_ENFORCE(dnnLayoutCompare<T>(layout_wanted, layout_),
434 "You passed in a target layout that is not " 435 "generated by the given primitive and type.");
436 buffer_.reset(temp_buffer, [](
void* ptr) ->
void {
437 MKLDNN_CHECK(dnnReleaseBuffer<T>(ptr));
439 return std::shared_ptr<void>(buffer_);
441 return std::shared_ptr<void>(temp_buffer, [](
void* ptr) ->
void {
442 MKLDNN_CHECK(dnnReleaseBuffer<T>(ptr));
449 bool share_mem_if_possible_;
450 bool layout_is_user_layout_;
454 mutable std::shared_ptr<void> buffer_;
456 mutable std::mutex buffer_lock_;
459 vector<TIndex> dims_;
475 #endif // CAFFE2_UTILS_MKL_MKL_MEMORY_H_ int ndim() const
Returns the number of dimensions of the data.
TIndex dim(const int i) const
Returns the i-th dimension of the tensor.
const vector< TIndex > & dims() const
Returns the dimensions of the tensor as a vector.
TIndex size() const
Returns the size (i.e.
T * mutable_data()
Returns a typed pointer of the underlying storage.
Tensor is the basic class in Caffe2 that stores a contiguous memory with its shape information...
Simple registry implementation in Caffe2 that uses static variables to register object creators durin...
TIndex dim(const int i) const
Returns the i-th dimension of the tensor.
A wrapper around an opaque MKL internal resource that has certain layouts and convertion primitives s...
Commandline flags support for Caffe2.
void Resize(Ts... dim_source)
Resizes a tensor.