forked from huawei/mindspore2022
unified runtime support the execution order running
This commit is contained in:
parent
693af7f260
commit
d3e6080a9b
|
|
@ -23,6 +23,7 @@
|
|||
#include <utility>
|
||||
#include <thread>
|
||||
#include <algorithm>
|
||||
#include <map>
|
||||
#include "utils/hash_map.h"
|
||||
#include "mindrt/include/actor/op_actor.h"
|
||||
#include "runtime/device/device_address.h"
|
||||
|
|
@ -47,8 +48,14 @@ constexpr int kSuccess = 0;
|
|||
constexpr int kFailure = 1;
|
||||
|
||||
enum class GraphExecutionStrategy {
|
||||
kPipeline, // The actor running is triggered only by data.
|
||||
kStep // The actor running need be triggered by control in addition.
|
||||
kPipeline, // The actor running is triggered only by data.
|
||||
kStep, // The actor running need be triggered by control in addition.
|
||||
kPipelineWithExecutionOrder // The actor running is triggered by data with the persistent execution order.
|
||||
};
|
||||
static const std::map<GraphExecutionStrategy, std::string> kGraphExecutionStrategyStr = {
|
||||
{GraphExecutionStrategy::kPipeline, "pipeline"},
|
||||
{GraphExecutionStrategy::kStep, "step"},
|
||||
{GraphExecutionStrategy::kPipelineWithExecutionOrder, "pipeline_with_execution_order"},
|
||||
};
|
||||
|
||||
const char kDataPrepareActorNameSuffix[] = "_DataPrepareActor";
|
||||
|
|
|
|||
|
|
@ -25,7 +25,6 @@
|
|||
#include <map>
|
||||
#include <stack>
|
||||
#include <utility>
|
||||
#include <unordered_map>
|
||||
#include <algorithm>
|
||||
#include "utils/hash_map.h"
|
||||
#include "runtime/hardware/device_context.h"
|
||||
|
|
@ -87,7 +86,8 @@ using FrontNodeToKernelGraph = mindspore::HashMap<AnfNodePtr, KernelGraphPtr>;
|
|||
using FuncGraphCallRelation = mindspore::HashMap<FuncGraphPtr, std::vector<std::set<FuncGraphPtr>>>;
|
||||
using CallNodeToFuncGraph = mindspore::HashMap<AnfNodePtr, std::set<FuncGraphPtr>>;
|
||||
using KernelGraphToDeviceContext = mindspore::HashMap<KernelGraphPtr, DeviceContext *>;
|
||||
using GroupNameToCommuNodes = std::unordered_map<std::string, std::vector<CNodePtr>>;
|
||||
using GroupNameToCommuNodes =
|
||||
mindspore::HashMap<std::string, std::pair<std::vector<CNodePtr>, std::vector<KernelGraphPtr>>>;
|
||||
// In the control flow, heterogeneous kernel graphs need to be reconnected in the same group, and the kernel graph
|
||||
// group info is used to store the inputs and outputs of the group.
|
||||
// Need stack indicates whether a stack actor needs to be created for the group.
|
||||
|
|
|
|||
|
|
@ -88,7 +88,7 @@ struct BACKEND_EXPORT GraphCompilerInfo {
|
|||
size_t outputs_num_;
|
||||
std::string name_;
|
||||
bool need_erase_;
|
||||
GraphExecutionStrategy strategy_;
|
||||
mutable GraphExecutionStrategy strategy_;
|
||||
};
|
||||
|
||||
class GraphCompiler {
|
||||
|
|
|
|||
|
|
@ -492,11 +492,13 @@ ActorSet *GraphScheduler::Transform(const GraphCompilerInfo &graph_compiler_info
|
|||
}
|
||||
scheduler_->graph_output_to_actor_.clear();
|
||||
scheduler_->copy_actors_.clear();
|
||||
scheduler_->execution_order_running_ = false;
|
||||
}
|
||||
};
|
||||
// cppcheck-suppress unreadVariable
|
||||
ScopeCleaner cleaner(this);
|
||||
MS_LOG(INFO) << "Graph(" << graph_compiler_info.name_ << ") transforms actor begin.";
|
||||
MS_LOG(INFO) << "Graph(" << graph_compiler_info.name_
|
||||
<< ") transforms actor begin, strategy:" << kGraphExecutionStrategyStr.at(graph_compiler_info.strategy_);
|
||||
if (graph_compiler_info.graphs_.size() == 0) {
|
||||
MS_LOG(EXCEPTION) << "The number of graphs is zero.";
|
||||
}
|
||||
|
|
@ -504,6 +506,10 @@ ActorSet *GraphScheduler::Transform(const GraphCompilerInfo &graph_compiler_info
|
|||
MS_LOG(EXCEPTION) << "The number of graphs is not equal to the number of device contexts.";
|
||||
}
|
||||
|
||||
if (graph_compiler_info.strategy_ == GraphExecutionStrategy::kPipelineWithExecutionOrder) {
|
||||
execution_order_running_ = true;
|
||||
graph_compiler_info.strategy_ = GraphExecutionStrategy::kPipeline;
|
||||
}
|
||||
PersistDeviceTensor(graph_compiler_info);
|
||||
const auto &actor_set = Build(graph_compiler_info);
|
||||
MS_EXCEPTION_IF_NULL(actor_set);
|
||||
|
|
@ -761,8 +767,10 @@ void GraphScheduler::Link(ActorSet *actor_set, const GraphCompilerInfo &graph_co
|
|||
std::vector<CNodePtr> communication_nodes;
|
||||
const auto &group_name = (parser->IsInited() ? parser->FetchGroupNameByKernelGraph(graph) : default_group_name);
|
||||
LinkDataArrowInNonSinkMode(graph, graph_compiler_info, &auto_monad_actors, &communication_nodes);
|
||||
group_name_to_communication_nodes[group_name].insert(group_name_to_communication_nodes[group_name].end(),
|
||||
communication_nodes.begin(), communication_nodes.end());
|
||||
group_name_to_communication_nodes[group_name].first.insert(
|
||||
group_name_to_communication_nodes[group_name].first.end(), communication_nodes.begin(),
|
||||
communication_nodes.end());
|
||||
(void)group_name_to_communication_nodes[group_name].second.emplace_back(graph);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1645,9 +1653,16 @@ void GraphScheduler::LinkGlobalControlArrow(ActorSet *const actor_set,
|
|||
const std::vector<AbstractActor *> &auto_monad_actors,
|
||||
const GraphCompilerInfo &graph_compiler_info) {
|
||||
MS_EXCEPTION_IF_NULL(actor_set);
|
||||
// Link the control arrow by the execution order.
|
||||
if (execution_order_running_) {
|
||||
for (auto &graph : graph_compiler_info.graphs_) {
|
||||
LinkControlArrowByExecutionOrder(graph);
|
||||
}
|
||||
}
|
||||
|
||||
for (const auto &communication_nodes : communication_node_groups) {
|
||||
// Link the control arrows by the communication nodes to ensure communication nodes running order.
|
||||
LinkControlArrowByCommunicationNode(communication_nodes.second, graph_compiler_info);
|
||||
LinkControlArrowByCommunicationNode(communication_nodes.second.first, communication_nodes.second.second);
|
||||
}
|
||||
|
||||
// Auto monad actor may modify the device tensor store.
|
||||
|
|
@ -1775,8 +1790,20 @@ void GraphScheduler::LinkControlArrowForCustomActor(ActorSet *const actor_set,
|
|||
}
|
||||
}
|
||||
|
||||
void GraphScheduler::LinkControlArrowByExecutionOrder(const KernelGraphPtr &graph) {
|
||||
MS_EXCEPTION_IF_NULL(graph);
|
||||
auto &execution_order = graph->execution_order();
|
||||
for (size_t i = 1; i < execution_order.size(); ++i) {
|
||||
auto from_actor = FetchActor(execution_order[i - 1]->fullname_with_scope());
|
||||
auto to_actor = FetchActor(execution_order[i]->fullname_with_scope());
|
||||
if ((from_actor != nullptr) && (to_actor != nullptr)) {
|
||||
AddControlArrow(from_actor, to_actor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GraphScheduler::LinkControlArrowByCommunicationNode(const std::vector<CNodePtr> &communication_nodes,
|
||||
const GraphCompilerInfo &graph_compiler_info) {
|
||||
const std::vector<KernelGraphPtr> &graphs) {
|
||||
const size_t kCommunicationNodesMinNum = 2;
|
||||
if (communication_nodes.size() < kCommunicationNodesMinNum) {
|
||||
return;
|
||||
|
|
@ -1793,15 +1820,9 @@ void GraphScheduler::LinkControlArrowByCommunicationNode(const std::vector<CNode
|
|||
|
||||
// Ensure all actors execute orderly to optimize the execution performance in the multi device scenario currently.
|
||||
// Using the multi stream to optimize the performance in the future.
|
||||
for (auto &graph : graph_compiler_info.graphs_) {
|
||||
MS_EXCEPTION_IF_NULL(graph);
|
||||
auto &execution_order = graph->execution_order();
|
||||
for (size_t i = 1; i < execution_order.size(); ++i) {
|
||||
auto from_actor = FetchActor(execution_order[i - 1]->fullname_with_scope());
|
||||
auto to_actor = FetchActor(execution_order[i]->fullname_with_scope());
|
||||
if ((from_actor != nullptr) && (to_actor != nullptr)) {
|
||||
AddControlArrow(from_actor, to_actor);
|
||||
}
|
||||
if (!execution_order_running_) {
|
||||
for (auto &graph : graphs) {
|
||||
LinkControlArrowByExecutionOrder(graph);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -2279,7 +2300,10 @@ void GraphScheduler::DumpActor(const ActorSet *actor_set, const GraphCompilerInf
|
|||
auto first_graph_id = kernel_graphs.front()->graph_id();
|
||||
MS_EXCEPTION_IF_NULL(kernel_graphs.back());
|
||||
auto last_graph_id = kernel_graphs.back()->graph_id();
|
||||
std::string strategy = (graph_compiler_info.strategy_ == GraphExecutionStrategy::kPipeline) ? "pipeline" : "step";
|
||||
std::string strategy = kGraphExecutionStrategyStr.at(graph_compiler_info.strategy_);
|
||||
if (execution_order_running_) {
|
||||
strategy = "pipeline_with_excution_order";
|
||||
}
|
||||
std::string save_name = "actor_set_" + strategy + "_kernel_graph_" + std::to_string(first_graph_id);
|
||||
if (last_graph_id != first_graph_id) {
|
||||
save_name = save_name + "-" + std::to_string(last_graph_id);
|
||||
|
|
|
|||
|
|
@ -166,9 +166,10 @@ class BACKEND_EXPORT GraphScheduler {
|
|||
const std::vector<AbstractActor *> &auto_monad_actors,
|
||||
const GraphCompilerInfo &graph_compiler_info);
|
||||
void LinkControlArrowForCustomActor(ActorSet *const actor_set, const GraphCompilerInfo &graph_compiler_info);
|
||||
void LinkControlArrowByExecutionOrder(const KernelGraphPtr &graph);
|
||||
// Link the control arrows by the communication nodes in the kernel graph to ensure communication nodes running order.
|
||||
void LinkControlArrowByCommunicationNode(const std::vector<CNodePtr> &communication_nodes,
|
||||
const GraphCompilerInfo &graph_compiler_info);
|
||||
const std::vector<KernelGraphPtr> &graphs);
|
||||
void LinkDeviceTensorStoreForAutoMonadActor(const std::vector<AbstractActor *> &auto_monad_actors);
|
||||
void LinkControlArrowForDataPrepareActor(DataPrepareActor *data_prepare_actor, const ActorSet *actor_set,
|
||||
const ControlNodeParserPtr &parser);
|
||||
|
|
@ -222,6 +223,9 @@ class BACKEND_EXPORT GraphScheduler {
|
|||
const AID *recorder_aid_{nullptr};
|
||||
const AID *debug_aid_{nullptr};
|
||||
|
||||
// Whether actor running by the persistent execution order.
|
||||
bool execution_order_running_{false};
|
||||
|
||||
bool init_{false};
|
||||
};
|
||||
} // namespace runtime
|
||||
|
|
|
|||
Loading…
Reference in New Issue