chore: import upstream snapshot with attribution

This commit is contained in:
wehub-resource-sync
2026-07-13 12:40:42 +08:00
commit e25996e7db
15472 changed files with 3536181 additions and 0 deletions
+12
View File
@@ -0,0 +1,12 @@
if(WITH_CUSTOM_DEVICE)
paddle_test(test_custom_engine_loadlib SRCS test_custom_engine_loadlib.cc
custom_engine_op.cc)
endif()
paddle_test(test_custom_engine SRCS test_custom_engine_operation.cc
custom_engine_op.cc)
if(WITH_ONNXRUNTIME AND WIN32)
# Copy onnxruntime for some c++ test in Windows, since the test will
# be build only in CI, so suppose the generator in Windows is Ninja.
copy_onnx(test_custom_engine)
endif()
@@ -0,0 +1,184 @@
// Copyright (c) 2024 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 "test/cpp/pir/custom_engine/custom_engine_op.h"
#include "paddle/fluid/pir/dialect/operator/utils/utils.h"
namespace paddle {
namespace dialect {
const char *FakeEngineOp::attributes_name[2] = {"input_names", "output_names"};
OpInfoTuple FakeEngineOp::GetOpInfo() {
std::vector<paddle::dialect::OpInputInfo> inputs = {
OpInputInfo("x",
"pir::VectorType<paddle::dialect::DenseTensorType>",
false,
false,
false,
false)};
std::vector<paddle::dialect::OpAttributeInfo> attributes = {
paddle::dialect::OpAttributeInfo(
"input_names", "pir::ArrayAttribute", ""),
paddle::dialect::OpAttributeInfo(
"output_names", "pir::ArrayAttribute", "")};
std::vector<paddle::dialect::OpOutputInfo> outputs = {
OpOutputInfo("out",
"pir::VectorType<paddle::dialect::DenseTensorType>",
false,
false)};
paddle::dialect::OpRunTimeInfo run_time_info =
OpRunTimeInfo("", {}, "", {}, {}, {}, {}, {});
return std::make_tuple(
inputs, attributes, outputs, run_time_info, "fake_engine");
}
#define ADD_VEC_ATTRIBUTE(type, name) \
std::vector<pir::Attribute> name##_tmp; \
name##_tmp.reserve(name.size()); \
for (const auto &v : name) { \
name##_tmp.push_back(type::get(pir::IrContext::Instance(), v)); \
} \
pir::Attribute attr_##name = \
pir::ArrayAttribute::get(pir::IrContext::Instance(), name##_tmp); \
argument.AddAttribute(#name, attr_##name)
#define VERIFY_ATTRIBUTE(type, name) \
PADDLE_ENFORCE_GT( \
attributes.count(#name), \
0, \
common::errors::InvalidArgument(#name " does not exist.")); \
PADDLE_ENFORCE_EQ(attributes.at(#name).isa<type>(), \
true, \
common::errors::InvalidArgument( \
"Type of attribute: " #name " is not " #type))
void FakeEngineOp::Build(pir::Builder &builder, // NOLINT
pir::OperationArgument &argument, // NOLINT
pir::Value x,
std::vector<std::string> input_names,
std::vector<std::string> output_names,
std::vector<std::vector<int64_t>> outputs_shape,
std::vector<phi::DataType> outputs_dtype) {
VLOG(4) << "Start build FakeEngineOp";
VLOG(4) << "Builder construction inputs";
std::vector<pir::Value> argument_inputs = {x};
argument.AddInputs(argument_inputs);
VLOG(4) << "Builder construction attributes";
ADD_VEC_ATTRIBUTE(pir::StrAttribute, input_names);
ADD_VEC_ATTRIBUTE(pir::StrAttribute, output_names);
VLOG(4) << "Builder construction outputs";
std::vector<pir::Type> argument_outputs;
std::vector<pir::Type> out_types;
for (size_t i = 0; i < static_cast<size_t>(outputs_shape.size()); i++) {
if (outputs_dtype[i] == phi::DataType::UNDEFINED) {
out_types.push_back(pir::Type());
} else {
out_types.push_back(pir::DenseTensorType::get(
pir::IrContext::Instance(),
TransToIrDataType(outputs_dtype[i]),
phi::DDim(outputs_shape[i].data(), outputs_shape[i].size()),
phi::DataLayout::kNCHW,
phi::LoD(),
0));
}
}
pir::Type out_vector_type =
pir::VectorType::get(pir::IrContext::Instance(), out_types);
argument_outputs.push_back(out_vector_type);
argument.AddOutputs(argument_outputs.begin(), argument_outputs.end());
argument.AddRegion(nullptr);
::pir::PassStopGradientsDefaultly(argument);
}
void FakeEngineOp::VerifySig() {
VLOG(4) << "Start Verifying inputs, outputs and attributes for: "
"FakeEngineOp.";
VLOG(4) << "Verifying inputs:";
{
auto input_size = num_operands();
PADDLE_ENFORCE_EQ(input_size,
1,
common::errors::InvalidArgument(
"The size of inputs must be equal to 1."));
PADDLE_ENFORCE_EQ((*this)->operand_source(0).type().isa<pir::VectorType>(),
true,
common::errors::InvalidArgument(
"Type validation failed for the 0th input, got %s.",
(*this)->operand_source(0).type()));
if (auto vec_type =
(*this)->operand_source(0).type().dyn_cast<pir::VectorType>()) {
for (size_t i = 0; i < vec_type.size(); ++i) {
PADDLE_ENFORCE_EQ(
vec_type[i].isa<pir::DenseTensorType>(),
true,
common::errors::InvalidArgument(
"Type validation failed for the 0th input, got %s.",
(*this)->operand_source(0).type()));
}
}
}
VLOG(4) << "Verifying attributes:";
{
auto &attributes = this->attributes();
VERIFY_ATTRIBUTE(pir::ArrayAttribute, input_names);
VERIFY_ATTRIBUTE(pir::ArrayAttribute, output_names);
}
VLOG(4) << "Verifying outputs:";
{
auto output_size = num_results();
PADDLE_ENFORCE_EQ(output_size,
1,
common::errors::InvalidArgument(
"The size of outputs must be equal to 1."));
auto output_type = (*this)->result(0).type();
PADDLE_ENFORCE_EQ(output_type.isa<pir::VectorType>(),
true,
common::errors::InvalidArgument(
"Type validation failed for the 0th output."));
}
VLOG(4) << "End Verifying for: FakeEngineOp.";
}
pir::Block *FakeEngineOp::block() {
pir::Region &region = (*this)->region(0);
if (region.empty()) region.emplace_back();
return &region.front();
}
pir::Block *FakeEngineOp::block() const {
pir::Region &region = (*this)->region(0);
PADDLE_ENFORCE_EQ(region.empty(),
false,
::common::errors::Unavailable(
"Required CustomEngineOp's region must not be empty."));
return &region.front();
}
} // namespace dialect
} // namespace paddle
IR_DEFINE_EXPLICIT_TYPE_ID(paddle::dialect::FakeEngineOp)
@@ -0,0 +1,81 @@
// Copyright (c) 2024 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.
#pragma once
#include <glog/logging.h>
#include <vector>
#include "paddle/fluid/pir/dialect/operator/interface/op_yaml_info.h"
#include "paddle/fluid/pir/dialect/operator/ir/op_dialect.h"
#include "paddle/pir/include/core/builder.h"
#include "paddle/pir/include/core/builtin_attribute.h"
#include "paddle/pir/include/core/builtin_op.h"
#include "paddle/pir/include/core/builtin_type.h"
#include "paddle/pir/include/core/op_base.h"
#include "paddle/pir/include/core/op_trait.h"
#include "paddle/pir/include/core/operation_utils.h"
#include "test/cpp/pir/tools/macros_utils.h"
#if defined(_WIN32)
#ifndef EXPORT_API
#define EXPORT_API __declspec(dllexport)
#endif // EXPORT_API
#else
#define EXPORT_API
#endif // _WIN32
#define IR_DECLARE_EXPLICIT_PLUGIN_TYPE_ID(TYPE_CLASS) \
namespace pir { \
namespace detail { \
template <> \
class EXPORT_API TypeIdResolver<TYPE_CLASS> { \
public: \
static TypeId Resolve() { return id_; } \
static UniqueingId id_; \
}; \
} \
} // namespace pir
namespace paddle {
namespace dialect {
class FakeEngineOp
: public pir::Op<FakeEngineOp, paddle::dialect::OpYamlInfoInterface> {
public:
using Op::Op;
static const char *name() { return "custom_engine.fake_engine"; }
static const char *attributes_name[2];
static constexpr uint32_t attributes_num = 2;
static OpInfoTuple GetOpInfo();
static void Build(pir::Builder &builder, // NOLINT
pir::OperationArgument &argument, // NOLINT
pir::Value x,
std::vector<std::string> input_names,
std::vector<std::string> output_names,
std::vector<std::vector<int64_t>> outputs_shape,
std::vector<phi::DataType> outputs_dtype);
void VerifySig();
pir::Block *block();
pir::Block *block() const;
pir::Value x() { return operand_source(0); }
pir::Value out() { return result(0); }
};
} // namespace dialect
} // namespace paddle
IR_DECLARE_EXPLICIT_PLUGIN_TYPE_ID(paddle::dialect::FakeEngineOp)
@@ -0,0 +1,263 @@
// Copyright (c) 2024 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.
#pragma once
#include <unordered_map>
#include "paddle/fluid/custom_engine/custom_engine_ext.h"
#include "paddle/fluid/framework/new_executor/instruction/custom_engine_instruction.h"
#include "paddle/fluid/framework/new_executor/pir_adaptor/pir_adaptor_util.h"
#include "paddle/fluid/pir/transforms/pd_op_to_kernel_pass.h"
#include "test/cpp/pir/custom_engine/custom_engine_op.h"
#include "test/cpp/pir/custom_engine/fake_cpu_engine_base.h"
C_Status RegisterCustomEngineOp() {
pir::IrContext* ctx = pir::IrContext::Instance();
pir::Dialect* custom_engine_dialect =
ctx->GetOrRegisterDialect<paddle::dialect::CustomEngineDialect>();
EXPECT_EQ(custom_engine_dialect != nullptr, true);
ctx->RegisterOpInfo(custom_engine_dialect,
pir::TypeId::get<paddle::dialect::FakeEngineOp>(),
paddle::dialect::FakeEngineOp::name(),
paddle::dialect::FakeEngineOp::interface_set(),
paddle::dialect::FakeEngineOp::GetTraitSet(),
paddle::dialect::FakeEngineOp::attributes_num,
paddle::dialect::FakeEngineOp::attributes_name,
paddle::dialect::FakeEngineOp::VerifySigInvariants,
paddle::dialect::FakeEngineOp::VerifyRegionInvariants);
return C_SUCCESS;
}
C_Status CustomEngineOpLower(C_CustomEngineLowerParams* lower_param) {
// get lower params
pir::IrContext* ctx =
reinterpret_cast<pir::IrContext*>(lower_param->ir_context);
pir::Operation* op_item =
reinterpret_cast<pir::Operation*>(lower_param->operation);
phi::KernelKey* kernel_key =
reinterpret_cast<phi::KernelKey*>(lower_param->kernel_key);
phi::Place* place = reinterpret_cast<phi::Place*>(lower_param->place);
std::unordered_map<pir::Operation*, pir::Operation*>* map_op_pair =
reinterpret_cast<std::unordered_map<pir::Operation*, pir::Operation*>*>(
lower_param->map_op_pair);
std::unordered_map<pir::Value, pir::Value>* map_value_pair =
reinterpret_cast<std::unordered_map<pir::Value, pir::Value>*>(
lower_param->map_value_pair);
pir::Block* block = reinterpret_cast<pir::Block*>(lower_param->block);
// Prepare output types
std::vector<pir::Type> op_output_types;
for (size_t i = 0; i < op_item->num_results(); ++i) {
PushBackOutputTypes(ctx,
op_item,
op_item->result(i).type(),
*place,
*kernel_key,
&op_output_types);
}
// Prepare input
std::vector<pir::Value> vec_inputs;
for (size_t i = 0; i < op_item->num_operands(); ++i) {
auto cur_in = op_item->operand_source(i);
PADDLE_ENFORCE_EQ(
map_value_pair->count(cur_in),
true,
common::errors::PreconditionNotMet(
"[%d]'s input of [%s] op MUST in map pair", i, op_item->name()));
auto new_in = map_value_pair->at(cur_in);
vec_inputs.push_back(new_in);
}
// Prepare attr
std::unordered_map<std::string, pir::Attribute> op_attribute;
auto op_attr_map = op_item->attributes();
for (auto& map_item : op_attr_map) {
op_attribute.emplace(map_item.first, map_item.second);
}
pir::OpInfo custom_engine_op_info =
ctx->GetRegisteredOpInfo(paddle::dialect::FakeEngineOp::name());
pir::Operation* op = pir::Operation::Create(vec_inputs,
op_attribute,
op_output_types,
custom_engine_op_info,
1,
{},
true);
op->set_attribute("origin_id", pir::Int64Attribute::get(ctx, op->id()));
op->set_attribute("op_name", pir::StrAttribute::get(ctx, op->name()));
VLOG(3) << "CustomEngineOpLower get op_item subgraph block.";
pir::Region& op_item_region = op_item->region(0);
PADDLE_ENFORCE_EQ(op_item_region.empty(),
false,
::common::errors::Unavailable(
"Required CustomEngineOp's region must not be empty."));
pir::Block* sub_graph_block = &(op_item_region.front());
VLOG(3) << "CustomEngineOpLower set new op subgraph block.";
pir::Region& region = op->region(0);
if (region.empty()) {
region.emplace_back();
}
pir::Block* op_block = &(region.front());
// process subgraph block
pir::ProcessBlock(
*place, sub_graph_block, op_block, ctx, map_op_pair, map_value_pair);
if (VLOG_IS_ON(3)) {
std::stringstream ss;
ss << "CustomEngineOpLower new op:";
op->Print(ss);
VLOG(3) << ss.str();
}
(*map_op_pair)[op_item] = op;
// only deal with single output
if (op_item->num_results() > 0) {
for (size_t i = 0; i < op_item->num_results(); ++i) {
(*map_value_pair)[op_item->result(i)] = op->result(i);
}
}
block->push_back(op);
return C_SUCCESS;
}
class CustomEngine {
public:
CustomEngine(std::vector<phi::DenseTensor*> tensor_args,
std::vector<phi::DenseTensor*> return_tensor)
: tensor_args_(tensor_args), return_tensor_(return_tensor) {}
~CustomEngine() {}
void Run(const phi::DeviceContext& device_ctx, const phi::Place& place) {
PADDLE_ENFORCE_EQ(
tensor_args_.size(),
2u,
common::errors::PreconditionNotMet("tensor_args.size != 2"));
PADDLE_ENFORCE_EQ(
return_tensor_.size(),
1u,
common::errors::PreconditionNotMet("return_tensor.size != 1"));
// phi::AddKernel<float, phi::DeviceContext>(device_ctx, *(tensor_args_[0]),
// *(tensor_args_[1]),return_tensor_[0]);
phi::Copy(device_ctx, *(tensor_args_[0]), place, true, return_tensor_[0]);
return;
}
private:
std::vector<phi::DenseTensor*> tensor_args_;
std::vector<phi::DenseTensor*> return_tensor_;
std::vector<phi::DenseTensor*> template_tensor_;
};
C_Status GraphEngineExecute(C_CustomEngineInstruction instruction) {
paddle::framework::CustomEngineInstruction* instruction_ =
reinterpret_cast<paddle::framework::CustomEngineInstruction*>(
instruction);
CustomEngine* customengine =
reinterpret_cast<CustomEngine*>(instruction_->CustomEngine());
customengine->Run(instruction_->DeviceContext(),
instruction_->DeviceContext().GetPlace());
return C_SUCCESS;
}
C_Status GraphEngineBuild(C_CustomEngineInstruction instruction) {
paddle::framework::CustomEngineInstruction* instruction_ =
reinterpret_cast<paddle::framework::CustomEngineInstruction*>(
instruction);
pir::Operation* op = instruction_->Operation();
const paddle::framework::ValueExecutionInfo* value_exec_info =
instruction_->GetValueExecutionInfo();
// prepare input tensors
std::vector<phi::DenseTensor*> tensor_args;
PADDLE_ENFORCE_EQ(op->num_operands(),
1u,
common::errors::PreconditionNotMet(
"custom engine op should has 1 operand"));
auto vec_in = op->operand_source(0).defining_op()->operands_source();
for (auto in : vec_in) {
auto var_name = value_exec_info->GetVarName(in);
auto tensor = value_exec_info->GetScope()
->FindVar(var_name)
->GetMutable<phi::DenseTensor>();
tensor_args.push_back(tensor);
}
// prepare output tensors
std::vector<phi::DenseTensor*> return_tensor;
PADDLE_ENFORCE_EQ(op->num_results(),
1u,
common::errors::PreconditionNotMet(
"custom engine op should has 1 result"));
pir::Value vec_result = op->result(0);
PADDLE_ENFORCE_EQ(vec_result.type().isa<pir::VectorType>(),
true,
common::errors::PreconditionNotMet(
"custom engine op result should be vectortype"));
auto vec_out = op->result(0).first_use().owner()->results();
for (auto out : vec_out) {
bool check =
out && out.type() && out.type().isa<paddle::dialect::DenseTensorType>();
PADDLE_ENFORCE_EQ(
check,
true,
common::errors::PreconditionNotMet(
"customEngine instruction only support DenseTensorType"));
auto var_name = value_exec_info->GetVarName(out);
auto tensor = value_exec_info->GetScope()
->Var(var_name)
->GetMutable<phi::DenseTensor>();
return_tensor.push_back(tensor);
auto alloc_tensor_type =
out.type().dyn_cast<paddle::dialect::AllocatedDenseTensorType>();
tensor->set_type(
paddle::dialect::TransToPhiDataType(alloc_tensor_type.dtype()));
tensor->Resize(alloc_tensor_type.dims());
}
CustomEngine* fake_engine = new CustomEngine(tensor_args, return_tensor);
auto customEngineDeleter = [](void* ptr) {
CustomEngine* customEngine = static_cast<CustomEngine*>(ptr);
if (customEngine != nullptr) {
delete customEngine;
} else {
PADDLE_THROW(
common::errors::PreconditionNotMet("customEngine is nullptr"));
}
};
instruction_->SetCustomEngine(reinterpret_cast<void*>(fake_engine));
instruction_->SetCustomEngineDeleter(customEngineDeleter);
return C_SUCCESS;
}
void InitPluginCustomEngine(CustomEngineParams* params) {
memset(reinterpret_cast<void*>(params->interface),
0,
sizeof(C_CustomEngineInterface));
params->interface->register_custom_engine_op = RegisterCustomEngineOp;
params->interface->graph_engine_build = GraphEngineBuild;
params->interface->graph_engine_execute = GraphEngineExecute;
params->interface->custom_engine_op_lower = CustomEngineOpLower;
}
@@ -0,0 +1,173 @@
// Copyright (c) 2024 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.
#pragma once
#include <unordered_map>
#include "paddle/fluid/pir/dialect/kernel/ir/kernel_type.h"
#include "paddle/fluid/pir/dialect/operator/ir/op_dialect.h"
#include "paddle/fluid/pir/dialect/operator/ir/op_type.h"
#include "paddle/phi/common/place.h"
#include "paddle/phi/core/kernel_factory.h"
#include "paddle/phi/core/tensor_utils.h"
#include "paddle/pir/include/core/block.h"
#include "paddle/pir/include/core/builtin_attribute.h"
#include "paddle/pir/include/core/ir_context.h"
#include "paddle/pir/include/core/operation.h"
using paddle::dialect::AllocatedDenseTensorArrayType;
using paddle::dialect::AllocatedDenseTensorType;
using paddle::dialect::AllocatedSelectedRowsType;
using paddle::dialect::AllocatedSparseCooTensorType;
using paddle::dialect::AllocatedSparseCsrTensorType;
using paddle::dialect::DenseTensorArrayType;
using paddle::dialect::DenseTensorType;
using paddle::dialect::SelectedRowsType;
using paddle::dialect::SparseCooTensorType;
using paddle::dialect::SparseCsrTensorType;
template <class IrType1, class IrType2>
static pir::Type create_sparse_coo_tensor_type(pir::Type type,
const phi::Place& place,
pir::Type out_dtype,
pir::IrContext* ctx) {
auto input_type = type.dyn_cast<IrType1>();
return IrType2::get(ctx,
place,
out_dtype,
input_type.dims(),
input_type.non_zero_dims(),
input_type.data_layout(),
input_type.non_zero_indices(),
input_type.non_zero_elements(),
input_type.coalesced());
}
template <class IrType1, class IrType2>
static pir::Type create_sparse_csr_tensor_type(pir::Type type,
const phi::Place& place,
pir::Type out_dtype,
pir::IrContext* ctx) {
auto input_type = type.dyn_cast<IrType1>();
return IrType2::get(ctx,
place,
out_dtype,
input_type.dims(),
input_type.data_layout(),
input_type.non_zero_crows(),
input_type.non_zero_cols(),
input_type.non_zero_elements());
}
template <class IrType1, class IrType2>
static pir::Type create_type(pir::Type type,
const phi::Place& place,
pir::Type out_dtype,
pir::IrContext* ctx) {
auto input_type = type.dyn_cast<IrType1>();
return IrType2::get(ctx,
place,
out_dtype,
input_type.dims(),
input_type.data_layout(),
input_type.lod(),
input_type.offset());
}
static pir::Type BuildOutputType(pir::Type type,
const phi::Place& place,
pir::IrContext* ctx) {
if (type.isa<DenseTensorType>()) {
auto out_dtype = type.dyn_cast<DenseTensorType>().dtype();
return create_type<DenseTensorType, AllocatedDenseTensorType>(
type, place, out_dtype, ctx);
} else if (type.isa<SelectedRowsType>()) {
auto out_dtype = type.dyn_cast<SelectedRowsType>().dtype();
return create_type<SelectedRowsType, AllocatedSelectedRowsType>(
type, place, out_dtype, ctx);
} else if (type.isa<DenseTensorArrayType>()) {
auto array_type = type.dyn_cast<DenseTensorArrayType>();
return AllocatedDenseTensorArrayType::get(ctx,
place,
array_type.dtype(),
array_type.dims(),
array_type.data_layout());
} else if (type.isa<SparseCooTensorType>()) {
auto out_dtype = type.dyn_cast<SparseCooTensorType>().dtype();
return create_sparse_coo_tensor_type<SparseCooTensorType,
AllocatedSparseCooTensorType>(
type, place, out_dtype, ctx);
} else if (type.isa<SparseCsrTensorType>()) {
auto out_dtype = type.dyn_cast<SparseCsrTensorType>().dtype();
return create_sparse_csr_tensor_type<SparseCsrTensorType,
AllocatedSparseCsrTensorType>(
type, place, out_dtype, ctx);
} else {
PADDLE_THROW(common::errors::Unimplemented(
"BuildOutputType only support DenseTensorType, SelectedRowsType, "
"SparseCooTensorType and SparseCsrTensorType"));
}
}
void PushBackOutputTypes(pir::IrContext* ctx,
pir::Operation* op_item,
const pir::Type& origin_type,
const phi::Place& out_place,
const phi::KernelKey& kernel_key,
std::vector<pir::Type>* op_output_types) {
auto result_type = origin_type;
if (!result_type) {
op_output_types->push_back(result_type);
} else if (result_type.isa<paddle::dialect::DenseTensorType>() ||
result_type.isa<paddle::dialect::SelectedRowsType>() ||
result_type.isa<paddle::dialect::DenseTensorArrayType>() ||
result_type.isa<paddle::dialect::SparseCooTensorType>() ||
result_type.isa<paddle::dialect::SparseCsrTensorType>()) {
} else if (result_type.isa<pir::VectorType>()) {
std::vector<pir::Type> vec_inner_types;
auto base_types = result_type.dyn_cast<pir::VectorType>().data();
for (auto& base_type : base_types) {
if (base_type) {
if (base_type.isa<paddle::dialect::DenseTensorType>() ||
base_type.isa<paddle::dialect::SelectedRowsType>()) {
vec_inner_types.push_back(BuildOutputType(base_type, out_place, ctx));
} else {
PADDLE_THROW(common::errors::Unimplemented(
"only support dense tensor and selected rows in vector type "
"for now"));
}
} else {
pir::Type fp32_dtype = pir::Float32Type::get(ctx);
phi::DDim dims = {};
phi::DataLayout data_layout = phi::DataLayout::NCHW;
phi::LegacyLoD lod = {{}};
size_t offset = 0;
auto dense_tensor_dtype = paddle::dialect::DenseTensorType::get(
ctx, fp32_dtype, dims, data_layout, lod, offset);
auto allocated_dense_tensor_dtype =
paddle::dialect::AllocatedDenseTensorType::get(
ctx, out_place, dense_tensor_dtype);
vec_inner_types.push_back(allocated_dense_tensor_dtype);
}
}
pir::Type t1 = pir::VectorType::get(ctx, vec_inner_types);
op_output_types->push_back(t1);
} else {
PADDLE_THROW(common::errors::Unimplemented(
"Result type only support DenseTensorType, SelectedRowType, "
"SparseCooTensorType, SparseCsrTensorType and "
"VectorType"));
}
}
@@ -0,0 +1,152 @@
// 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 <gtest/gtest.h>
#include <array>
#include <string>
#include "paddle/fluid/custom_engine/custom_engine_manager.h"
#include "paddle/fluid/platform/init.h"
#include "paddle/phi/backends/custom/fake_cpu_device.h"
#include "paddle/phi/backends/device_manager.h"
#include "paddle/phi/common/memory_utils.h"
#include "paddle/phi/common/place.h"
#include "paddle/phi/core/memory/allocation/allocator_facade.h"
#include "paddle/phi/core/platform/device_context.h"
#include "paddle/fluid/framework/new_executor/interpretercore.h"
#include "paddle/fluid/framework/new_executor/pir_interpreter.h"
#include "paddle/fluid/pir/dialect/operator/ir/op_dialect.h"
#include "paddle/fluid/pir/dialect/operator/ir/pd_op.h"
#include "paddle/fluid/pir/transforms/pd_op_to_kernel_pass.h"
#include "paddle/pir/include/core/builtin_attribute.h"
#include "paddle/pir/include/core/builtin_dialect.h"
#include "paddle/pir/include/core/builtin_op.h"
#include "paddle/pir/include/core/ir_context.h"
#include "paddle/pir/include/core/program.h"
#include "paddle/pir/include/core/type_id.h"
#include "test/cpp/pir/custom_engine/fake_cpu_engine.h"
#define OUT_NAME "program_out"
void RegisterDevice() {
CustomRuntimeParams runtime_params;
runtime_params.size = sizeof(CustomRuntimeParams);
auto device_interface = std::make_unique<C_DeviceInterface>();
runtime_params.interface = device_interface.get();
std::memset(runtime_params.interface, 0, sizeof(C_DeviceInterface));
runtime_params.interface->size = sizeof(C_DeviceInterface);
InitFakeCPUDevice(&runtime_params);
phi::LoadCustomRuntimeLib(
runtime_params, std::move(device_interface), "", nullptr);
}
void RegisterEngine() {
CustomEngineParams engine_params;
std::memset(&engine_params, 0, sizeof(CustomEngineParams));
engine_params.size = sizeof(CustomEngineParams);
auto engine_interface = new (C_CustomEngineInterface);
engine_params.interface = engine_interface;
std::memset(engine_params.interface, 0, sizeof(C_CustomEngineInterface));
engine_params.interface->size = sizeof(C_CustomEngineInterface);
InitPluginCustomEngine(&engine_params);
paddle::custom_engine::LoadCustomEngineLib("", &engine_params);
}
void InitCustom() {
RegisterDevice();
EXPECT_GT(static_cast<int>(phi::DeviceManager::GetAllDeviceTypes().size()),
0);
auto place = phi::CustomPlace(DEVICE_TYPE, 0);
auto device = phi::DeviceManager::GetDeviceWithPlace(place);
EXPECT_NE(device, nullptr);
std::vector<phi::Place> places;
auto device_types = phi::DeviceManager::GetAllDeviceTypes();
for (auto dev_type : device_types) {
auto devices = phi::DeviceManager::GetDeviceList(dev_type);
for (auto dev_id : devices) {
places.push_back(phi::PlaceHelper::CreatePlace(dev_type, dev_id));
}
}
EXPECT_GT(static_cast<int>(places.size()), 0);
places.emplace_back(phi::CPUPlace());
phi::DeviceContextPool::Init(places);
RegisterEngine();
}
void CreateProgram(pir::Program *program) {
pir::IrContext *ctx = pir::IrContext::Instance();
ctx->GetOrRegisterDialect<paddle::dialect::OperatorDialect>();
ctx->GetOrRegisterDialect<pir::BuiltinDialect>();
pir::Block *block = program->block();
pir::Builder builder(ctx, block);
auto full_op1 =
builder.Build<paddle::dialect::FullOp>(std::vector<int64_t>{2, 2}, 100);
auto full_op2 =
builder.Build<paddle::dialect::FullOp>(std::vector<int64_t>{2, 2}, 10);
auto buildin_combine_op = builder.Build<pir::CombineOp>(
std::vector<pir::Value>{full_op1.result(0), full_op2.result(0)});
auto engine_op = builder.Build<paddle::dialect::FakeEngineOp>(
buildin_combine_op.result(0),
std::vector<std::string>{"input_0", "input_1"},
std::vector<std::string>{"output_0"},
std::vector<std::vector<int64_t>>{{2, 2}},
std::vector<phi::DataType>{phi::DataType::FLOAT32});
engine_op->region(0).emplace_back();
auto output = builder.Build<pir::SplitOp>(engine_op.result(0)).outputs()[0];
builder.Build<pir::ShadowOutputOp>(output, OUT_NAME);
return;
}
TEST(CustomDevice, Tensor) {
paddle::framework::InitMemoryMethod();
InitCustom();
pir::IrContext *ctx = pir::IrContext::Instance();
pir::Program *program = new pir::Program(ctx);
CreateProgram(program);
EXPECT_EQ(program->block()->size(), 6u);
auto kernel_program = pir::PdOpLowerToKernelPass(program);
auto place = phi::CustomPlace(DEVICE_TYPE, 0);
paddle::framework::Scope scope;
paddle::framework::InterpreterCore test_core(
place, {}, kernel_program->block(), &scope);
test_core.SetSkipGcVars({OUT_NAME});
test_core.Run({});
auto out_tensor =
test_core.local_scope() == nullptr
? scope.FindVar(OUT_NAME)->Get<phi::DenseTensor>()
: test_core.local_scope()->FindVar(OUT_NAME)->Get<phi::DenseTensor>();
bool res0 = out_tensor.data<float>()[0] == 100;
EXPECT_EQ(res0, true);
}
int main(int argc, char **argv) {
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}
@@ -0,0 +1,104 @@
// Copyright (c) 2024 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 <gtest/gtest.h>
#include <sstream>
#include "paddle/fluid/pir/dialect/operator/ir/op_dialect.h"
#include "paddle/fluid/pir/dialect/operator/ir/pd_op.h"
#include "paddle/pir/include/core/builtin_attribute.h"
#include "paddle/pir/include/core/builtin_dialect.h"
#include "paddle/pir/include/core/builtin_op.h"
#include "paddle/pir/include/core/ir_context.h"
#include "paddle/pir/include/core/program.h"
#include "paddle/pir/include/core/type_id.h"
#include "test/cpp/pir/custom_engine/custom_engine_op.h"
TEST(op_test, region_test) {
pir::IrContext *ctx = pir::IrContext::Instance();
ctx->GetOrRegisterDialect<paddle::dialect::OperatorDialect>();
ctx->GetOrRegisterDialect<pir::BuiltinDialect>();
pir::Dialect *custom_engine_dialect =
ctx->GetOrRegisterDialect<paddle::dialect::CustomEngineDialect>();
EXPECT_EQ(custom_engine_dialect != nullptr, true);
ctx->RegisterOpInfo(custom_engine_dialect,
pir::TypeId::get<paddle::dialect::FakeEngineOp>(),
paddle::dialect::FakeEngineOp::name(),
paddle::dialect::FakeEngineOp::interface_set(),
paddle::dialect::FakeEngineOp::GetTraitSet(),
paddle::dialect::FakeEngineOp::attributes_num,
paddle::dialect::FakeEngineOp::attributes_name,
paddle::dialect::FakeEngineOp::VerifySigInvariants,
paddle::dialect::FakeEngineOp::VerifyRegionInvariants);
pir::Program program(ctx);
pir::Block *block = program.block();
pir::Builder builder(ctx, block);
auto full_op1 =
builder.Build<paddle::dialect::FullOp>(std::vector<int64_t>{2, 2}, 100);
auto full_op2 =
builder.Build<paddle::dialect::FullOp>(std::vector<int64_t>{2, 2}, 10);
auto buildin_combine_op = builder.Build<pir::CombineOp>(
std::vector<pir::Value>{full_op1.result(0), full_op2.result(0)});
pir::OpInfo fake_engine_op_info =
ctx->GetRegisteredOpInfo(paddle::dialect::FakeEngineOp::name());
std::vector<pir::Type> out_types;
out_types.push_back(
pir::DenseTensorType::get(pir::IrContext::Instance(),
pir::Float32Type::get(ctx),
phi::DDim(std::vector<int64_t>{2, 2}.data(), 2),
phi::DataLayout::kNCHW,
phi::LoD(),
0));
pir::Type out_vector_type =
pir::VectorType::get(pir::IrContext::Instance(), out_types);
std::vector<pir::Type> output_types = {out_vector_type};
pir::AttributeMap attribute_map;
std::vector<pir::Attribute> val;
val.push_back(pir::StrAttribute::get(ctx, "input_0"));
val.push_back(pir::StrAttribute::get(ctx, "input_1"));
attribute_map.insert({"input_names", pir::ArrayAttribute::get(ctx, val)});
std::vector<pir::Attribute> out_val;
out_val.push_back(pir::StrAttribute::get(ctx, "output_0"));
out_val.push_back(pir::StrAttribute::get(ctx, "output_1"));
attribute_map.insert(
{"output_names", pir::ArrayAttribute::get(ctx, out_val)});
pir::Operation *op1 = pir::Operation::Create({buildin_combine_op.result(0)},
attribute_map,
output_types,
fake_engine_op_info);
// (3) Test custom operation printer
std::stringstream ss1;
op1->Print(ss1);
builder.Insert(op1);
auto op2 = builder.Build<paddle::dialect::FakeEngineOp>(
buildin_combine_op.result(0),
std::vector<std::string>{"input_0", "input_1"},
std::vector<std::string>{"output_0"},
std::vector<std::vector<int64_t>>{{2, 2}},
std::vector<phi::DataType>{phi::DataType::FLOAT32});
std::stringstream ss2;
op2->Print(ss2);
EXPECT_EQ(block->size(), 5u);
}