// Copyright (c) 2022 PaddlePaddle Authors. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #include "paddle/phi/kernels/add_n_kernel.h" #include "paddle/phi/backends/onednn/onednn_reuse.h" #include "paddle/phi/core/kernel_registry.h" namespace phi { bool AddNCheckIfOneDNNSupport(const KernelContext* dev_ctx) { for (size_t i = 0; i < dev_ctx->InputsSize(); i++) { if (!DenseTensor::classof(dev_ctx->MutableInputAt(i))) { return false; } } KernelContext* dev_ctx_tmp = const_cast(dev_ctx); if (!DenseTensor::classof(dev_ctx_tmp->MutableOutputAt(0))) { return false; } return true; } namespace funcs { template class SumOneDNNHandler : public OneDNNHandlerNoCachingT { public: SumOneDNNHandler(dnnl::engine engine, const Place& cpu_place, const std::vector& x, DenseTensor* out) : OneDNNHandlerNoCachingT(engine, cpu_place), num_inputs_(0) { auto dst_tz = vectorize(out->dims()); auto src_tz = dst_tz; std::vector srcs_md; srcs_md.reserve(x.size()); for (auto item : x) { auto* input_it = (static_cast(item)); if (input_it->numel() == 0) { continue; } srcs_md.push_back(input_it->mem_desc()); ++num_inputs_; } std::vector scales(num_inputs_, 1.0f); auto dst_md = dnnl::memory::desc( dst_tz, OneDNNGetDataType(), OneDNNMemoryFormat::any); this->AcquireForwardPrimitiveDescriptor(dst_md, scales, srcs_md); } std::shared_ptr AcquireSrcMemory(const DenseTensor* input, int i) { const T* input_data = input->data(); return this->AcquireMemoryFromPrimitive(this->fwd_pd_->src_desc(i), to_void_cast(input_data)); } using OneDNNHandlerNoCachingT::AcquireDstMemory; std::shared_ptr AcquireDstMemory() { return this->AcquireMemoryFromPrimitive(this->fwd_pd_->dst_desc()); } inline int GetNumInputs() { return num_inputs_; } private: int num_inputs_; }; } // namespace funcs template void AddNKernel(const Context& dev_ctx, const std::vector& x, DenseTensor* out) { const auto& onednn_engine = dev_ctx.GetEngine(); PADDLE_ENFORCE_NE( x.empty(), true, errors::InvalidArgument("Input variable is empty.")); auto* input0 = (static_cast(x[0])); bool in_place = (input0->numel() > 0) && input0->IsSharedBufferWith(*out); funcs::SumOneDNNHandler handler(onednn_engine, dev_ctx.GetPlace(), x, out); // Create list of SRC MEMs std::vector> srcs_mem; srcs_mem.reserve(handler.GetNumInputs()); int input_index = 0; for (auto item : x) { auto* input_it = (static_cast(item)); if (input_it->numel() == 0) { continue; } srcs_mem.push_back(handler.AcquireSrcMemory(input_it, input_index)); ++input_index; } std::unordered_map args; for (size_t i = 0; i < srcs_mem.size(); ++i) { args.insert({DNNL_ARG_MULTIPLE_SRC + i, *(srcs_mem[i])}); } auto dst_mem = in_place ? srcs_mem[0] : handler.AcquireDstMemory(out); args.insert({DNNL_ARG_DST, *dst_mem}); auto sum_p = handler.AcquireForwardPrimitive(); auto& astream = OneDNNContext::tls().get_stream(); sum_p->execute(astream, args); astream.wait(); out->set_mem_desc(dst_mem->get_desc()); } } // namespace phi PD_REGISTER_KERNEL( add_n, OneDNN, ONEDNN, phi::AddNKernel, float, phi::bfloat16) { kernel->check_if_onednn_kernel_support_ = phi::AddNCheckIfOneDNNSupport; }