// 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 #include #include "paddle/fluid/pir/dialect/distributed/ir/dist_attribute.h" #include "paddle/fluid/pir/dialect/distributed/ir/dist_dialect.h" #include "paddle/fluid/pir/dialect/distributed/ir/dist_interface.h" #include "paddle/fluid/pir/dialect/distributed/ir/dist_op.h" #include "paddle/fluid/pir/dialect/distributed/ir/dist_type.h" #include "paddle/fluid/pir/dialect/operator/ir/api_builder.h" #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_type.h" #include "paddle/pir/include/core/program.h" using namespace paddle::dialect; // NOLINT TEST(process_mesh_test, base) { pir::IrContext* ctx = pir::IrContext::Instance(); ctx->GetOrRegisterDialect(); std::vector mesh_shape = {2, 2}; std::vector process_ids = {0, 1, 2, 3}; std::vector dim_names = {"x", "y"}; std::vector dim_names_2 = {"x", "s"}; phi::distributed::ProcessMesh process_mesh( mesh_shape, process_ids, dim_names); // construct a ProcessMeshAttribute. auto mesh_attr = ProcessMeshAttribute::get(ctx, mesh_shape, process_ids, dim_names); auto mesh_attr_1 = ProcessMeshAttribute::get(ctx, process_mesh); auto mesh_attr_2 = ProcessMeshAttribute::get(ctx, mesh_shape, process_ids, dim_names_2); EXPECT_EQ(mesh_attr, mesh_attr_1); EXPECT_NE(mesh_attr, mesh_attr_2); // test member function. EXPECT_EQ(mesh_attr.process_mesh(), process_mesh); EXPECT_EQ(mesh_attr.shape(), mesh_shape); EXPECT_EQ(mesh_attr.process_ids(), process_ids); EXPECT_EQ(mesh_attr.dim_names(), dim_names); EXPECT_EQ(mesh_attr.size(), 4); EXPECT_EQ(mesh_attr.ndim(), 2); EXPECT_EQ(mesh_attr.dim_size(0), 2); EXPECT_EQ(mesh_attr.dim_size("y"), 2); EXPECT_FALSE(mesh_attr.empty()); EXPECT_TRUE(mesh_attr.contains(3)); EXPECT_EQ(mesh_attr.hash(), process_mesh.hash()); EXPECT_EQ(mesh_attr.to_string(), process_mesh.to_string()); } TEST(tensor_dist_attr_test, base) { pir::IrContext* ctx = pir::IrContext::Instance(); ctx->GetOrRegisterDialect(); std::vector mesh_shape = {2, 3}; std::vector process_ids = {0, 1, 2, 3, 4, 5}; std::vector dim_names = {"x", "y"}; phi::distributed::ProcessMesh process_mesh( mesh_shape, process_ids, dim_names); std::vector dims_mapping = {0, -1}; paddle::flat_hash_map partial_status, partial_status_1{{1, phi::ReduceType::kRedSum}}; auto mesh_attr = ProcessMeshAttribute::get(ctx, mesh_shape, process_ids, dim_names); // construct a TensorDistAttribute. auto tensor_dist_attr = TensorDistAttribute::get(ctx, mesh_attr, dims_mapping, partial_status); auto tensor_dist_attr_1 = TensorDistAttribute::get(ctx, process_mesh, dims_mapping, partial_status); auto tensor_dist_attr_2 = TensorDistAttribute::get( ctx, process_mesh, dims_mapping, partial_status_1); EXPECT_EQ(tensor_dist_attr, tensor_dist_attr_1); EXPECT_NE(tensor_dist_attr, tensor_dist_attr_2); // test member function. EXPECT_EQ(tensor_dist_attr.process_mesh_attr(), mesh_attr); EXPECT_EQ(tensor_dist_attr.process_mesh_attr().process_mesh(), process_mesh); EXPECT_EQ(tensor_dist_attr.dims_mapping(), dims_mapping); EXPECT_EQ(tensor_dist_attr.partial_status(), partial_status); } TEST(dist_dense_tensor_type_test, base) { pir::IrContext* ctx = pir::IrContext::Instance(); ctx->GetOrRegisterDialect(); ctx->GetOrRegisterDialect(); std::vector mesh_shape = {2, 3}; std::vector process_ids = {0, 1, 2, 3, 4, 5}; std::vector dim_names = {"x", "y"}; phi::distributed::ProcessMesh process_mesh( mesh_shape, process_ids, dim_names); auto mesh_attr = ProcessMeshAttribute::get(ctx, process_mesh); std::vector dims_mapping = {0, -1}; paddle::flat_hash_map partial_status{ {1, phi::ReduceType::kRedSum}}; // construct a TensorDistAttribute. auto tensor_dist_attr = TensorDistAttribute::get(ctx, mesh_attr, dims_mapping, partial_status); pir::Type fp32_dtype = pir::Float32Type::get(ctx); common::DDim dims = {2, 2}; common::DataLayout data_layout = common::DataLayout::NCHW; pir::LegacyLoD lod = {{0, 1, 2}}; size_t offset = 0; pir::DenseTensorType dense_tensor_type = pir::DenseTensorType::get( ctx, fp32_dtype, dims, data_layout, lod, offset); auto dist_densor_type = DistDenseTensorType::get(ctx, dense_tensor_type, tensor_dist_attr, dims); EXPECT_EQ(dist_densor_type.process_mesh_attr(), mesh_attr); EXPECT_EQ(dist_densor_type.process_mesh_attr().process_mesh(), process_mesh); EXPECT_EQ(dist_densor_type.dims_mapping(), dims_mapping); EXPECT_EQ(dist_densor_type.partial_status(), partial_status); EXPECT_EQ(dist_densor_type.dtype().isa(), true); EXPECT_EQ(dist_densor_type.global_ddim(), dims); EXPECT_EQ(dist_densor_type.data_layout(), data_layout); EXPECT_EQ(dist_densor_type.local_ddim(), dims); } TEST(dist_dense_tensor_type_test, warp_type_interface) { pir::IrContext* ctx = pir::IrContext::Instance(); ctx->GetOrRegisterDialect(); ctx->GetOrRegisterDialect(); std::vector mesh_shape = {2, 3}; std::vector process_ids = {0, 1, 2, 3, 4, 5}; std::vector dim_names = {"x", "y"}; phi::distributed::ProcessMesh process_mesh( mesh_shape, process_ids, dim_names); auto mesh_attr = ProcessMeshAttribute::get(ctx, process_mesh); std::vector dims_mapping = {0, -1}; paddle::flat_hash_map partial_status{ {1, phi::ReduceType::kRedSum}}; // construct a TensorDistAttribute. auto tensor_dist_attr = TensorDistAttribute::get(ctx, mesh_attr, dims_mapping, partial_status); pir::Type fp32_dtype = pir::Float32Type::get(ctx); common::DDim dims = {2, 2}; common::DataLayout data_layout = common::DataLayout::NCHW; pir::LegacyLoD lod = {{0, 1, 2}}; size_t offset = 0; pir::DenseTensorType dense_tensor_type = pir::DenseTensorType::get( ctx, fp32_dtype, dims, data_layout, lod, offset); pir::Type dist_densor_type = DistDenseTensorType::get(ctx, dense_tensor_type, tensor_dist_attr, dims); EXPECT_TRUE(dist_densor_type.isa()); EXPECT_EQ(dist_densor_type.dyn_cast(), dense_tensor_type); } TEST(dist_dense_tensor_type_test, dist_interface) { pir::IrContext* ctx = pir::IrContext::Instance(); ctx->GetOrRegisterDialect(); ctx->GetOrRegisterDialect(); std::vector mesh_shape = {2, 3}; std::vector process_ids = {0, 1, 2, 3, 4, 5}; std::vector dim_names = {"x", "y"}; phi::distributed::ProcessMesh process_mesh( mesh_shape, process_ids, dim_names); auto mesh_attr = ProcessMeshAttribute::get(ctx, process_mesh); std::vector dims_mapping = {0, -1}; paddle::flat_hash_map partial_status{ {1, phi::ReduceType::kRedSum}}; // construct a TensorDistAttribute. auto tensor_dist_attr = TensorDistAttribute::get(ctx, mesh_attr, dims_mapping, partial_status); pir::Type fp32_dtype = pir::Float32Type::get(ctx); common::DDim dims = {4, 8}; common::DDim local_dims = {2, 8}; common::DataLayout data_layout = common::DataLayout::NCHW; pir::LegacyLoD lod = {{0, 1, 2}}; size_t offset = 0; pir::DenseTensorType dense_tensor_type = pir::DenseTensorType::get( ctx, fp32_dtype, dims, data_layout, lod, offset); pir::Type dist_densor_type = DistDenseTensorType::get(ctx, dense_tensor_type, tensor_dist_attr); EXPECT_TRUE(dist_densor_type.isa()); EXPECT_EQ(dist_densor_type.dyn_cast(), dense_tensor_type); // test local cast auto local_dense_tensor_type = dist_densor_type.dyn_cast() .local_type() .dyn_cast(); EXPECT_TRUE(local_dense_tensor_type.isa()); EXPECT_FALSE(local_dense_tensor_type.isa()); EXPECT_EQ(local_dense_tensor_type.dtype().isa(), true); EXPECT_EQ(local_dense_tensor_type.dims(), local_dims); EXPECT_EQ(local_dense_tensor_type.data_layout(), data_layout); EXPECT_EQ(local_dense_tensor_type.lod(), lod); EXPECT_EQ(local_dense_tensor_type.offset(), offset); } TEST(operation_dist_attr_test, base) { pir::IrContext* ctx = pir::IrContext::Instance(); ctx->GetOrRegisterDialect(); ctx->GetOrRegisterDialect(); std::vector mesh_shape = {2, 3}; std::vector process_ids = {0, 1, 2, 3, 4, 5}; std::vector dim_names = {"x", "y"}; phi::distributed::ProcessMesh process_mesh( mesh_shape, process_ids, dim_names); paddle::flat_hash_map partial_status; auto mesh_attr = ProcessMeshAttribute::get(ctx, mesh_shape, process_ids, dim_names); std::vector dims_mapping = {0, -1}; // construct a OperationDistAttribute. auto x_tensor_dist_attr = TensorDistAttribute::get(ctx, process_mesh, dims_mapping, partial_status); auto y_tensor_dist_attr = TensorDistAttribute::get(ctx, mesh_attr, dims_mapping, partial_status); auto out_tensor_dist_attr = TensorDistAttribute::get(ctx, mesh_attr, dims_mapping, partial_status); auto operand_attrs = std::vector{x_tensor_dist_attr, y_tensor_dist_attr}; auto result_attrs = std::vector{out_tensor_dist_attr}; auto op_attr = OperationDistAttribute::get( ctx, process_mesh, operand_attrs, result_attrs); auto op_attr_1 = OperationDistAttribute::get(ctx, mesh_attr, operand_attrs, result_attrs); // construct another OperationDistAttribute. std::vector dim_names_2 = {"x", "s"}; auto mesh_attr_2 = ProcessMeshAttribute::get(ctx, mesh_shape, process_ids, dim_names_2); auto x_tensor_dist_attr_2 = TensorDistAttribute::get(ctx, mesh_attr_2, dims_mapping, partial_status); auto y_tensor_dist_attr_2 = TensorDistAttribute::get(ctx, mesh_attr_2, dims_mapping, partial_status); auto out_tensor_dist_attr_2 = TensorDistAttribute::get(ctx, mesh_attr_2, dims_mapping, partial_status); auto operand_attrs_2 = std::vector{x_tensor_dist_attr_2, y_tensor_dist_attr_2}; auto result_attrs_2 = std::vector{out_tensor_dist_attr_2}; auto op_attr_2 = OperationDistAttribute::get( ctx, mesh_attr_2, operand_attrs_2, result_attrs_2); // check EXPECT_EQ(op_attr, op_attr_1); EXPECT_NE(op_attr, op_attr_2); EXPECT_EQ(op_attr.process_mesh_attr(), mesh_attr); EXPECT_EQ(op_attr.process_mesh_attr().process_mesh(), process_mesh); EXPECT_EQ(op_attr.operands(), operand_attrs); EXPECT_EQ(op_attr.operand(0), operand_attrs.at(0)); EXPECT_EQ(op_attr.operand(1), operand_attrs.at(1)); EXPECT_EQ(op_attr.num_operands(), (uint32_t)2); EXPECT_EQ(op_attr.results(), result_attrs); EXPECT_EQ(op_attr.result(0), result_attrs.at(0)); EXPECT_EQ(op_attr.num_results(), (uint32_t)1); } TEST(shard_tensor_op_replicate_test, base) { pir::IrContext* ctx = pir::IrContext::Instance(); ctx->GetOrRegisterDialect(); ctx->GetOrRegisterDialect(); pir::Program program(ctx); pir::Block* block = program.block(); pir::Builder builder(ctx, block); std::vector mesh_shape = {2, 3}; std::vector process_ids = {0, 1, 2, 3, 4, 5}; std::vector dim_names = {"x", "y"}; phi::distributed::ProcessMesh process_mesh( mesh_shape, process_ids, dim_names); auto mesh_attr = ProcessMeshAttribute::get(ctx, process_mesh); std::vector data_shape = {12, 6}; paddle::flat_hash_map partial_status; // construct a replicated std::vector dims_mapping = {-1, -1}; auto data_op = builder.Build( "w0", data_shape, phi::DataType::FLOAT32, phi::CPUPlace()); std::vector local_shape = {12, 6}; auto tensor_dist_attr = TensorDistAttribute::get(ctx, mesh_attr, dims_mapping, partial_status); pir::AttributeMap attr_map = {{"tensor_dist_attr", tensor_dist_attr}}; paddle::dialect::ShardTensorOp shard_op = builder.Build(data_op.result(0), attr_map); EXPECT_TRUE(shard_op.out().type().isa()); auto op_out_type = shard_op.out().type().dyn_cast(); EXPECT_EQ(op_out_type.global_ddim(), phi::make_ddim(data_shape)); EXPECT_EQ(op_out_type.local_ddim(), phi::make_ddim(local_shape)); EXPECT_EQ(op_out_type.process_mesh_attr(), mesh_attr); EXPECT_EQ(op_out_type.dims_mapping(), dims_mapping); EXPECT_EQ(op_out_type.partial_dims().size(), (size_t)0); EXPECT_EQ( shard_op.attribute("op_dist_attr").num_operands(), (uint32_t)0); EXPECT_EQ( shard_op.attribute("op_dist_attr").num_results(), (uint32_t)1); EXPECT_EQ(shard_op.attribute("op_dist_attr") .process_mesh_attr(), mesh_attr); // check reshard std::vector dst_mesh_shape = {3, 2}; std::vector dst_dims_mapping = {-1, 0}; phi::distributed::ProcessMesh dst_process_mesh( dst_mesh_shape, process_ids, dim_names); auto dst_mesh_attr = ProcessMeshAttribute::get(ctx, dst_process_mesh); auto dst_tensor_dist_attr = TensorDistAttribute::get( ctx, dst_mesh_attr, dst_dims_mapping, partial_status); paddle::dialect::ReshardOp reshard_op = builder.Build(shard_op.out(), dst_tensor_dist_attr); EXPECT_TRUE(reshard_op.result(0).type().isa()); auto dst_op_out_type = reshard_op.result(0).type().dyn_cast(); EXPECT_EQ(dst_op_out_type.global_ddim(), phi::make_ddim(data_shape)); EXPECT_EQ(dst_op_out_type.local_ddim(), phi::make_ddim({12, 2})); EXPECT_EQ(dst_op_out_type.process_mesh_attr(), dst_mesh_attr); EXPECT_EQ(dst_op_out_type.dims_mapping(), dst_dims_mapping); EXPECT_EQ(dst_op_out_type.partial_dims().size(), (size_t)0); EXPECT_EQ(reshard_op.attribute("op_dist_attr") .num_operands(), (uint32_t)1); EXPECT_EQ(reshard_op.attribute("op_dist_attr") .num_results(), (uint32_t)1); phi::distributed::ProcessMesh flatten_process_mesh( {6}, process_ids, {"merged"}); auto flatten_mesh_attr = ProcessMeshAttribute::get(ctx, flatten_process_mesh); EXPECT_EQ(reshard_op.attribute("op_dist_attr") .process_mesh_attr(), flatten_mesh_attr); } TEST(shard_tensor_op_shard_row_test, base) { pir::IrContext* ctx = pir::IrContext::Instance(); ctx->GetOrRegisterDialect(); ctx->GetOrRegisterDialect(); pir::Program program(ctx); pir::Block* block = program.block(); pir::Builder builder(ctx, block); std::vector mesh_shape = {2, 3}; std::vector process_ids = {0, 1, 2, 3, 4, 5}; std::vector dim_names = {"x", "y"}; phi::distributed::ProcessMesh process_mesh( mesh_shape, process_ids, dim_names); auto mesh_attr = ProcessMeshAttribute::get(ctx, process_mesh); std::vector data_shape = {12, 6}; paddle::flat_hash_map partial_status; // construct a row shard std::vector dims_mapping = {1, -1}; auto data_op = builder.Build( "w1", data_shape, phi::DataType::FLOAT32, phi::CPUPlace()); std::vector local_shape = {4, 6}; auto tensor_dist_attr = TensorDistAttribute::get(ctx, mesh_attr, dims_mapping, partial_status); pir::AttributeMap attr_map = {{"tensor_dist_attr", tensor_dist_attr}}; paddle::dialect::ShardTensorOp shard_op = builder.Build(data_op.result(0), attr_map); EXPECT_TRUE(shard_op.out().type().isa()); auto op_out_type = shard_op.out().type().dyn_cast(); EXPECT_EQ(op_out_type.global_ddim(), phi::make_ddim(data_shape)); EXPECT_EQ(op_out_type.local_ddim(), phi::make_ddim(local_shape)); EXPECT_EQ(op_out_type.process_mesh_attr(), mesh_attr); EXPECT_EQ(op_out_type.dims_mapping(), dims_mapping); EXPECT_EQ(op_out_type.partial_dims().size(), (size_t)0); EXPECT_EQ( shard_op.attribute("op_dist_attr").num_operands(), (uint32_t)0); EXPECT_EQ( shard_op.attribute("op_dist_attr").num_results(), (uint32_t)1); EXPECT_EQ(shard_op.attribute("op_dist_attr") .process_mesh_attr(), mesh_attr); // check reshard std::vector dst_mesh_shape = {3, 2}; phi::distributed::ProcessMesh dst_process_mesh( dst_mesh_shape, process_ids, dim_names); auto dst_mesh_attr = ProcessMeshAttribute::get(ctx, dst_process_mesh); auto dst_tensor_dist_attr = TensorDistAttribute::get( ctx, dst_mesh_attr, dims_mapping, partial_status); paddle::dialect::ReshardOp reshard_op = builder.Build(shard_op.out(), dst_tensor_dist_attr); EXPECT_TRUE(reshard_op.result(0).type().isa()); auto dst_op_out_type = reshard_op.result(0).type().dyn_cast(); EXPECT_EQ(dst_op_out_type.global_ddim(), phi::make_ddim(data_shape)); EXPECT_EQ(dst_op_out_type.local_ddim(), phi::make_ddim({6, 6})); EXPECT_EQ(dst_op_out_type.process_mesh_attr(), dst_mesh_attr); EXPECT_EQ(dst_op_out_type.dims_mapping(), dims_mapping); EXPECT_EQ(dst_op_out_type.partial_dims().size(), (size_t)0); EXPECT_EQ(reshard_op.attribute("op_dist_attr") .num_operands(), (uint32_t)1); EXPECT_EQ(reshard_op.attribute("op_dist_attr") .num_results(), (uint32_t)1); phi::distributed::ProcessMesh flatten_process_mesh( {6}, process_ids, {"merged"}); auto flatten_mesh_attr = ProcessMeshAttribute::get(ctx, flatten_process_mesh); EXPECT_EQ(reshard_op.attribute("op_dist_attr") .process_mesh_attr(), flatten_mesh_attr); } TEST(shard_tensor_op_shard_col_test, base) { pir::IrContext* ctx = pir::IrContext::Instance(); ctx->GetOrRegisterDialect(); ctx->GetOrRegisterDialect(); pir::Program program(ctx); pir::Block* block = program.block(); pir::Builder builder(ctx, block); std::vector mesh_shape = {2, 3}; std::vector process_ids = {0, 1, 2, 3, 4, 5}; std::vector dim_names = {"x", "y"}; phi::distributed::ProcessMesh process_mesh( mesh_shape, process_ids, dim_names); auto mesh_attr = ProcessMeshAttribute::get(ctx, process_mesh); std::vector data_shape = {12, 6}; paddle::flat_hash_map partial_status; // construct a col shard std::vector dims_mapping = {-1, 0}; auto data_op = builder.Build( "w2", data_shape, phi::DataType::FLOAT32, phi::CPUPlace()); std::vector local_shape = {12, 3}; auto tensor_dist_attr = TensorDistAttribute::get(ctx, mesh_attr, dims_mapping, partial_status); pir::AttributeMap attr_map = {{"tensor_dist_attr", tensor_dist_attr}}; paddle::dialect::ShardTensorOp shard_op = builder.Build(data_op.result(0), attr_map); EXPECT_TRUE(shard_op.out().type().isa()); auto op_out_type = shard_op.out().type().dyn_cast(); EXPECT_EQ(op_out_type.global_ddim(), phi::make_ddim(data_shape)); EXPECT_EQ(op_out_type.local_ddim(), phi::make_ddim(local_shape)); EXPECT_EQ(op_out_type.process_mesh_attr(), mesh_attr); EXPECT_EQ(op_out_type.dims_mapping(), dims_mapping); EXPECT_EQ(op_out_type.partial_dims().size(), (size_t)0); EXPECT_EQ( shard_op.attribute("op_dist_attr").num_operands(), (uint32_t)0); EXPECT_EQ( shard_op.attribute("op_dist_attr").num_results(), (uint32_t)1); EXPECT_EQ(shard_op.attribute("op_dist_attr") .process_mesh_attr(), mesh_attr); // check reshard std::vector dst_dims_mapping = {0, 1}; phi::distributed::ProcessMesh dst_process_mesh( mesh_shape, process_ids, dim_names); auto dst_mesh_attr = ProcessMeshAttribute::get(ctx, dst_process_mesh); auto dst_tensor_dist_attr = TensorDistAttribute::get( ctx, dst_mesh_attr, dst_dims_mapping, partial_status); paddle::dialect::ReshardOp reshard_op = builder.Build(shard_op.out(), dst_tensor_dist_attr); EXPECT_TRUE(reshard_op.result(0).type().isa()); auto dst_op_out_type = reshard_op.result(0).type().dyn_cast(); EXPECT_EQ(dst_op_out_type.global_ddim(), phi::make_ddim(data_shape)); EXPECT_EQ(dst_op_out_type.local_ddim(), phi::make_ddim({6, 2})); EXPECT_EQ(dst_op_out_type.process_mesh_attr(), dst_mesh_attr); EXPECT_EQ(dst_op_out_type.dims_mapping(), dst_dims_mapping); EXPECT_EQ(dst_op_out_type.partial_dims().size(), (size_t)0); EXPECT_EQ(reshard_op.attribute("op_dist_attr") .num_operands(), (uint32_t)1); EXPECT_EQ(reshard_op.attribute("op_dist_attr") .num_results(), (uint32_t)1); EXPECT_EQ(reshard_op.attribute("op_dist_attr") .process_mesh_attr(), mesh_attr); } TEST(mix_to_dist_pass_test, base) { pir::IrContext* ctx = pir::IrContext::Instance(); ctx->GetOrRegisterDialect(); ctx->GetOrRegisterDialect(); pir::Program program(ctx); pir::Block* block = program.block(); pir::Builder builder(ctx, block); std::vector mesh_shape = {2, 3}; std::vector process_ids = {0, 1, 2, 3, 4, 5}; std::vector dim_names = {"x", "y"}; phi::distributed::ProcessMesh process_mesh( mesh_shape, process_ids, dim_names); auto mesh_attr = ProcessMeshAttribute::get(ctx, process_mesh); paddle::flat_hash_map partial_status; std::vector x_shape = {12, 6}; std::vector y_shape = {6, 8}; // construct x std::vector x_dims_mapping = {0, 1}; auto x_data_op = builder.Build( "x", x_shape, phi::DataType::FLOAT32, phi::CPUPlace()); std::vector x_local_shape = {6, 2}; auto x_tensor_dist_attr = TensorDistAttribute::get(ctx, mesh_attr, x_dims_mapping, partial_status); pir::AttributeMap x_attr_map = {{"tensor_dist_attr", x_tensor_dist_attr}}; // construct y std::vector y_dims_mapping = {1, -1}; auto y_data_op = builder.Build( "y", y_shape, phi::DataType::FLOAT32, phi::CPUPlace()); std::vector y_local_shape = {2, 8}; auto y_tensor_dist_attr = TensorDistAttribute::get(ctx, mesh_attr, y_dims_mapping, partial_status); pir::AttributeMap y_attr_map = {{"tensor_dist_attr", y_tensor_dist_attr}}; // shard_tensor op paddle::dialect::ShardTensorOp x_shard_op = builder.Build(x_data_op.result(0), x_attr_map); paddle::dialect::ShardTensorOp y_shard_op = builder.Build(y_data_op.result(0), y_attr_map); EXPECT_EQ(x_shard_op.attribute("op_dist_attr") .num_results(), (uint32_t)1); EXPECT_EQ(y_shard_op.attribute("op_dist_attr") .num_results(), (uint32_t)1); }