Files
paddlepaddle--paddle/paddle/phi/kernels/onednn/add_n_kernel.cc
T
2026-07-13 12:40:42 +08:00

136 lines
4.3 KiB
C++

// 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<KernelContext*>(dev_ctx);
if (!DenseTensor::classof(dev_ctx_tmp->MutableOutputAt(0))) {
return false;
}
return true;
}
namespace funcs {
template <typename T>
class SumOneDNNHandler : public OneDNNHandlerNoCachingT<T, dnnl::sum> {
public:
SumOneDNNHandler(dnnl::engine engine,
const Place& cpu_place,
const std::vector<const TensorBase*>& x,
DenseTensor* out)
: OneDNNHandlerNoCachingT<T, dnnl::sum>(engine, cpu_place),
num_inputs_(0) {
auto dst_tz = vectorize<int64_t>(out->dims());
auto src_tz = dst_tz;
std::vector<dnnl::memory::desc> srcs_md;
srcs_md.reserve(x.size());
for (auto item : x) {
auto* input_it = (static_cast<const DenseTensor*>(item));
if (input_it->numel() == 0) {
continue;
}
srcs_md.push_back(input_it->mem_desc());
++num_inputs_;
}
std::vector<float> scales(num_inputs_, 1.0f);
auto dst_md = dnnl::memory::desc(
dst_tz, OneDNNGetDataType<T>(), OneDNNMemoryFormat::any);
this->AcquireForwardPrimitiveDescriptor(dst_md, scales, srcs_md);
}
std::shared_ptr<dnnl::memory> AcquireSrcMemory(const DenseTensor* input,
int i) {
const T* input_data = input->data<T>();
return this->AcquireMemoryFromPrimitive(this->fwd_pd_->src_desc(i),
to_void_cast<T>(input_data));
}
using OneDNNHandlerNoCachingT<T, dnnl::sum>::AcquireDstMemory;
std::shared_ptr<dnnl::memory> AcquireDstMemory() {
return this->AcquireMemoryFromPrimitive(this->fwd_pd_->dst_desc());
}
inline int GetNumInputs() { return num_inputs_; }
private:
int num_inputs_;
};
} // namespace funcs
template <typename T, typename Context>
void AddNKernel(const Context& dev_ctx,
const std::vector<const TensorBase*>& 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<const DenseTensor*>(x[0]));
bool in_place = (input0->numel() > 0) && input0->IsSharedBufferWith(*out);
funcs::SumOneDNNHandler<T> handler(onednn_engine, dev_ctx.GetPlace(), x, out);
// Create list of SRC MEMs
std::vector<std::shared_ptr<dnnl::memory>> srcs_mem;
srcs_mem.reserve(handler.GetNumInputs());
int input_index = 0;
for (auto item : x) {
auto* input_it = (static_cast<const DenseTensor*>(item));
if (input_it->numel() == 0) {
continue;
}
srcs_mem.push_back(handler.AcquireSrcMemory(input_it, input_index));
++input_index;
}
std::unordered_map<int, dnnl::memory> 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;
}