// 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 "pybind11/stl.h" #include "paddle/fluid/distributed/collective/reducer.h" #include "paddle/fluid/pir/dialect/distributed/ir/dist_api.h" #include "paddle/fluid/pir/dialect/distributed/ir/dist_attribute.h" #include "paddle/fluid/pir/dialect/distributed/ir/dist_tools.h" #include "paddle/fluid/pir/dialect/distributed/transforms/dist_to_dense_pass.h" #include "paddle/fluid/pir/dialect/operator/ir/ir_tensor.h" #include "paddle/fluid/pybind/dist_api.h" #include "paddle/fluid/pybind/dist_static_op_function.h" #include "paddle/phi/core/distributed/auto_parallel/reshard/reshard_utils.h" #include "paddle/phi/core/enforce.h" #include "paddle/pir/include/core/builtin_attribute.h" namespace py = pybind11; namespace pybind11::detail { template struct type_caster> : map_caster, Key, Value> {}; } // namespace pybind11::detail using paddle::dialect::DistTypeInterface; using paddle::dialect::OperationDistAttribute; using paddle::dialect::PlacementsAttribute; using paddle::dialect::ProcessMeshAttribute; using paddle::dialect::TensorDistAttribute; using pir::ArrayAttribute; using pir::DenseTensorType; using pir::Value; using pybind11::return_value_policy; namespace paddle::pybind { void BindOperationDistAttribute(py::module *m) { py::class_ dist_attr( *m, "OperationDistAttribute"); dist_attr .def("__str__", [](OperationDistAttribute &self) { std::ostringstream print_stream; print_stream << self; return print_stream.str(); }) .def_property_readonly("process_mesh", [](OperationDistAttribute &self) { return self.process_mesh_attr().process_mesh(); }) .def_property_readonly( "chunk_id", [](OperationDistAttribute &self) { return self.chunk_id(); }) .def("num_operands", &OperationDistAttribute::num_operands) .def("operands", &OperationDistAttribute::operands) .def("operand", &OperationDistAttribute::operand) .def("num_results", &OperationDistAttribute::num_results) .def("results", &OperationDistAttribute::results) .def("result", &OperationDistAttribute::result); } void BindTensorDistAttribute(py::module *m) { py::class_ dist_attr( *m, "TensorDistAttribute"); dist_attr .def("__str__", [](TensorDistAttribute &self) { std::ostringstream print_stream; print_stream << self; return print_stream.str(); }) .def_property_readonly("process_mesh", [](TensorDistAttribute &self) { return self.process_mesh_attr().process_mesh(); }) .def_property_readonly( "dims_mapping", [](TensorDistAttribute &self) { return self.dims_mapping(); }) .def_property_readonly( "partial_status", [](TensorDistAttribute &self) { return self.partial_status(); }) .def_property_readonly( "partial_dims", [](TensorDistAttribute &self) { return self.partial_dims(); }) .def_property_readonly( "placements", [](TensorDistAttribute &self) { return self.placements(); }) .def_property_readonly("placements_attr", [](TensorDistAttribute &self) { std::optional placements_attr = self.placements_attr(); if (placements_attr.has_value()) { PyObject *py_obj = ToPyObject(placements_attr->placements()); return py::reinterpret_borrow(py_obj); } else { return py::none().cast(); } }); } void BindDistType(py::module *m) { py::class_ dist_type(*m, "DistType"); dist_type.def("dist_attr", &DistTypeInterface::tensor_dist_attr); } void BindDistOpsAPI(pybind11::module *module) { { if (PyModule_AddFunctions(module->ptr(), DistOpsAPI) < 0) { { PADDLE_THROW( common::errors::Fatal("Add C++ DistOpsAPI to core.ops failed!")); } } } } TensorDistAttribute CreateTensorDistAttribute( const phi::distributed::ProcessMesh &mesh, const std::vector &dims_mapping, const flat_hash_map &partial_status = {}) { return TensorDistAttribute::get( pir::IrContext::Instance(), mesh, dims_mapping, partial_status); } OperationDistAttribute CreateOperationDistAttribute( const phi::distributed::ProcessMesh &mesh, const std::vector &operands, const std::vector &results, const int64_t &chunk_id) { return OperationDistAttribute::get( pir::IrContext::Instance(), mesh, operands, results, chunk_id); } ArrayAttribute CreateArrayAttribute( const std::vector &elements) { return ArrayAttribute::get(pir::IrContext::Instance(), elements); } std::vector> AssignValueGroupBySize( const std::vector &values, const std::vector &group_size_limits) { std::vector tensors; tensors.reserve(values.size()); for (auto value : values) { auto x = value.type().dyn_cast(); PADDLE_ENFORCE_NE(x.storage(), nullptr, common::errors::Fatal( "Only support assign group for dense tensor value!")); auto ir_tensor = std::make_shared( dialect::TransToPhiDataType(x.dtype()), x.dims(), x.data_layout(), x.lod(), x.offset()); tensors.emplace_back(ir_tensor); } return distributed::Eager_AssignGroupBySize( tensors, std::vector(tensors.size(), false), group_size_limits); } void BindDistUtils(pybind11::module *m) { m->def("create_tensor_dist_attribute", CreateTensorDistAttribute); m->def("create_array_dist_attribute", CreateArrayAttribute); m->def("create_op_dist_attribute", CreateOperationDistAttribute); m->def("create_op_dist_attribute", &CreateOperationDistAttribute, py::arg("mesh"), py::arg("operands"), py::arg("results"), py::arg("chunk_id") = -1); m->def("create_process_mesh", [](const std::vector &shape, const std::vector &process_ids, const std::vector &dim_names) { return phi::distributed::ProcessMesh(shape, process_ids, dim_names); }); m->def("create_array_attribute", CreateArrayAttribute); m->def("get_sub_meshes", phi::distributed::GetSubMeshes); m->def("cvt_to_dist_type", &dialect::CvtToPirDistType, py::arg("global_type"), py::arg("dist_attr"), py::arg("local_ddim") = std::vector()); m->def("assign_value_group_by_size", AssignValueGroupBySize, py::arg("values"), py::arg("group_size_limits")); } void BindDistPassAPI(pybind11::module *module) { module->def("apply_dist2dense_pass", paddle::dialect::DistToDensePass); } void BindOpsFunction(py::module *m) { m->def("reshard_v2", [](const pir::Value &x, const TensorDistAttribute &dist_attr) { return reshard(x, dist_attr); }); } void BindDistApi(pybind11::module *module) { auto ir_module = module->def_submodule("pir"); BindOperationDistAttribute(&ir_module); BindTensorDistAttribute(&ir_module); BindDistType(&ir_module); BindDistUtils(&ir_module); BindDistPassAPI(&ir_module); auto ops_modules = ir_module.def_submodule("ops"); BindDistOpsAPI(&ops_modules); BindOpsFunction(&ops_modules); } } // namespace paddle::pybind