Skip to content

Commit

Permalink
LIR serialization improvements
Browse files Browse the repository at this point in the history
  • Loading branch information
v-Golubev committed Nov 27, 2023
1 parent bc78fd3 commit 878f05e
Show file tree
Hide file tree
Showing 10 changed files with 199 additions and 53 deletions.
1 change: 0 additions & 1 deletion src/common/snippets/include/snippets/lowered/linear_ir.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,6 @@ class LinearIR {
iterator find_after(iterator it, const ExpressionPtr& target) const;

void init_emitters(const std::shared_ptr<TargetMachine>& target);
void serialize(const std::string& xml, const std::string& bin) const;

class LoopManager;
using LoopManagerPtr = std::shared_ptr<LoopManager>;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
// Copyright (C) 2023 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
//

#pragma once

#include "pass.hpp"
#include "snippets/lowered/linear_ir.hpp"

namespace ov {
namespace snippets {
namespace lowered {
namespace pass {

/**
* @interface SerializeControlFlow
* @brief Serializes control flow graph of LinearIR
* @ingroup snippets
*/
class SerializeControlFlow : public Pass {
public:
OPENVINO_RTTI("SerializeControlFlow", "Pass")
SerializeControlFlow(const std::string& xml_path, const std::string& bin_path = "");
bool run(LinearIR& linear_ir) override;

private:
const std::string m_xml_path;
const std::string m_bin_path;
};

} // namespace pass
} // namespace lowered
} // namespace snippets
} // namespace ov
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
// Copyright (C) 2023 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
//

#pragma once

#include "pass.hpp"
#include "snippets/lowered/linear_ir.hpp"

namespace ov {
namespace snippets {
namespace lowered {
namespace pass {

/**
* @interface SerializeDataFlow
* @brief Serializes data flow graph of LinearIR
* @attention
* - This pass can not be run on the LinearIR after tail loop insertion.
* - Control flow operations (e.g. LoopBegin/LoopEnd) are not serialized
* @ingroup snippets
*/
class SerializeDataFlow : public Pass {
public:
OPENVINO_RTTI("SerializeDataFlow", "Pass")
SerializeDataFlow(const std::string& xml_path, const std::string& bin_path = "");
bool run(LinearIR& linear_ir) override;

private:
const std::string m_xml_path;
const std::string m_bin_path;
};

} // namespace pass
} // namespace lowered
} // namespace snippets
} // namespace ov
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,17 @@ namespace op {
*/
class SerializationNode : public ov::op::Op {
public:
OPENVINO_OP("SerializationNode", "SnippetsOpset");

SerializationNode() = default;
SerializationNode(const ov::OutputVector& args, const std::shared_ptr<lowered::Expression>& expr);

void validate_and_infer_types() override;
std::shared_ptr<Node> clone_with_new_inputs(const OutputVector &new_args) const override;
bool visit_attributes(AttributeVisitor &visitor) override;

const ::ov::DiscreteTypeInfo& get_type_info() const override {
return m_expr->get_node()->get_type_info();
}

private:
std::shared_ptr<lowered::Expression> m_expr;
};
Expand Down
1 change: 0 additions & 1 deletion src/common/snippets/include/snippets/op/subgraph.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,6 @@ class Subgraph : public ov::op::util::SubGraphOp {

void print() const;

void serialize() const;
VectorDims infer_master_shape();

static auto wrap_node_as_subgraph(const std::shared_ptr<ov::Node>& node) -> std::shared_ptr<Subgraph>;
Expand Down
33 changes: 0 additions & 33 deletions src/common/snippets/src/lowered/linear_ir.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@

#include "snippets/lowered/loop_manager.hpp"
#include "snippets/lowered/expression_factory.hpp"
#include "snippets/op/serialization_node.hpp"

#include "openvino/core/graph_util.hpp"
#include "openvino/core/type.hpp"
Expand Down Expand Up @@ -86,38 +85,6 @@ ov::NodeVector LinearIR::get_ordered_ops(const std::shared_ptr<ov::Model>& m) {
return ov::topological_sort(nodes);
}

void LinearIR::serialize(const std::string& xml, const std::string& bin) const {
auto first_node = std::make_shared<ov::op::v0::Parameter>(element::f32, Shape{});
first_node->set_friendly_name("Start");
first_node->get_rt_info()["execTimeMcs"] = 0;
std::shared_ptr<Node> serialization_node = first_node;

// This map allows to get LoopBegin serialization node by original LoopBegin node
// It is used to draw an edge between LoopBegin and LoopEnd serialization nodes
std::map<std::shared_ptr<snippets::op::LoopBegin>, std::shared_ptr<Node>> loops_map;
for (const auto& expr : m_expressions) {
const auto node = expr->get_node();
if (auto loop_end = ov::as_type_ptr<snippets::op::LoopEnd>(node)) {
OPENVINO_ASSERT(loops_map.count(loop_end->get_loop_begin()),
"Serialization can't find LoopBegin that corresponds to LoopEnd with friendly name ",
loop_end->get_friendly_name());
auto loop_begin_serialization_node = loops_map.at(loop_end->get_loop_begin());
serialization_node = std::make_shared<op::SerializationNode>(ov::OutputVector{serialization_node, loop_begin_serialization_node}, expr);
} else {
serialization_node = std::make_shared<op::SerializationNode>(ov::OutputVector{serialization_node}, expr);
if (auto loop_begin = ov::as_type_ptr<snippets::op::LoopBegin>(node)) {
loops_map[loop_begin] = serialization_node;
}
}
}
auto last_node = std::make_shared<ov::op::v0::Result>(serialization_node);
last_node->set_friendly_name("End");
const auto tmp_model = std::make_shared<ov::Model>(ResultVector {last_node},
ParameterVector {first_node},
"Lowered_IR_Serialization");
ov::pass::Serialize(xml, bin).run_on_model(tmp_model);
}

LinearIR::container LinearIR::deep_copy_range(LinearIR::container::const_iterator begin,
LinearIR::container::const_iterator end,
ExressionMap& expression_map) {
Expand Down
59 changes: 59 additions & 0 deletions src/common/snippets/src/lowered/pass/serialize_control_flow.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
// Copyright (C) 2023 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
//

#include "snippets/lowered/pass/serialize_control_flow.hpp"

#include "openvino/pass/serialize.hpp"
#include "snippets/itt.hpp"
#include "snippets/lowered/linear_ir.hpp"
#include "snippets/op/serialization_node.hpp"
#include "snippets/snippets_isa.hpp"

namespace ov {
namespace snippets {
namespace lowered {
namespace pass {

SerializeControlFlow::SerializeControlFlow(const std::string& xml_path, const std::string& bin_path)
: m_xml_path(xml_path),
m_bin_path(bin_path) {}

bool SerializeControlFlow::run(LinearIR& linear_ir) {
OV_ITT_SCOPED_TASK(ov::pass::itt::domains::SnippetsTransform, "Snippets::SerializeControlFlow")
if (linear_ir.empty())
return false;

auto first_node = std::make_shared<ov::op::v0::Parameter>(element::f32, Shape{});
first_node->set_friendly_name("Start");
first_node->get_rt_info()["execTimeMcs"] = 0;
std::shared_ptr<Node> serialization_node = first_node;

// This map allows to get LoopBegin serialization node by original LoopBegin node
// It is used to draw an edge between LoopBegin and LoopEnd serialization nodes
std::map<std::shared_ptr<snippets::op::LoopBegin>, std::shared_ptr<Node>> loops_map;
for (const auto& expr : linear_ir) {
const auto node = expr->get_node();
if (auto loop_end = ov::as_type_ptr<snippets::op::LoopEnd>(node)) {
OPENVINO_ASSERT(loops_map.count(loop_end->get_loop_begin()),
"Serialization can't find LoopBegin that corresponds to LoopEnd with friendly name ",
loop_end->get_friendly_name());
auto loop_begin_serialization_node = loops_map.at(loop_end->get_loop_begin());
serialization_node = std::make_shared<op::SerializationNode>(ov::OutputVector{serialization_node, loop_begin_serialization_node}, expr);
} else {
serialization_node = std::make_shared<op::SerializationNode>(ov::OutputVector{serialization_node}, expr);
if (auto loop_begin = ov::as_type_ptr<snippets::op::LoopBegin>(node)) {
loops_map[loop_begin] = serialization_node;
}
}
}
auto last_node = std::make_shared<ov::op::v0::Result>(serialization_node);
last_node->set_friendly_name("End");
const auto model = std::make_shared<ov::Model>(ResultVector{last_node}, ParameterVector{first_node}, "Lowered_IR_Control_Flow");
return ov::pass::Serialize(m_xml_path, m_bin_path).run_on_model(model);
}

} // namespace pass
} // namespace lowered
} // namespace snippets
} // namespace ov
60 changes: 60 additions & 0 deletions src/common/snippets/src/lowered/pass/serialize_data_flow.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
// Copyright (C) 2023 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
//

#include "snippets/lowered/pass/serialize_data_flow.hpp"

#include "openvino/pass/serialize.hpp"
#include "snippets/itt.hpp"
#include "snippets/lowered/linear_ir.hpp"
#include "snippets/op/serialization_node.hpp"
#include "snippets/snippets_isa.hpp"

namespace ov {
namespace snippets {
namespace lowered {
namespace pass {

SerializeDataFlow::SerializeDataFlow(const std::string& xml_path, const std::string& bin_path)
: m_xml_path(xml_path),
m_bin_path(bin_path) {}

bool SerializeDataFlow::run(LinearIR& linear_ir) {
OV_ITT_SCOPED_TASK(ov::pass::itt::domains::SnippetsTransform, "Snippets::SerializeDataFlow")
if (linear_ir.empty())
return false;

ov::ResultVector results;
ov::ParameterVector parameters;
std::map<ExpressionPtr, std::shared_ptr<Node>> ops_map;
for (const auto& expr : linear_ir) {
const auto node = expr->get_node();
ov::OutputVector inputs(expr->get_input_count());
for (size_t i = 0; i < expr->get_input_count(); ++i) {
const auto& input_expr = expr->get_input_port_connector(i)->get_source().get_expr();
OPENVINO_ASSERT(ops_map.count(input_expr), "input node wasn't found during serialization");
inputs[i] = ops_map[input_expr]->output(0);
}
if (auto ioexpr = std::dynamic_pointer_cast<IOExpression>(expr)) {
if (ioexpr->get_type() == IOExpression::io_type::INPUT) {
const auto parameter = std::make_shared<ov::op::v0::Parameter>(element::f32, Shape{});
ops_map[ioexpr] = parameter;
parameters.push_back(parameter);
} else {
const auto result = std::make_shared<ov::op::v0::Result>(inputs[0]);
ops_map[ioexpr] = result;
results.push_back(result);
}
} else {
const auto serialization_node = std::make_shared<op::SerializationNode>(inputs, expr);
ops_map[expr] = serialization_node;
}
}
const auto model = std::make_shared<ov::Model>(results, parameters, "Lowered_IR_Data_Flow");
return ov::pass::Serialize(m_xml_path, m_bin_path).run_on_model(model);
}

} // namespace pass
} // namespace lowered
} // namespace snippets
} // namespace ov
9 changes: 3 additions & 6 deletions src/common/snippets/src/op/serialization_node.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,11 @@ namespace op {

SerializationNode::SerializationNode(const ov::OutputVector& args, const std::shared_ptr<lowered::Expression>& expr)
: Op(args), m_expr(expr) {
if (!m_expr || !m_expr->get_node())
OPENVINO_THROW("SerializationNode requires a valid expression with non-null node pointer");
const auto &node = expr->get_node();
OPENVINO_ASSERT(m_expr && m_expr->get_node(), "SerializationNode requires a valid expression with non-null node pointer");
const auto& node = expr->get_node();
set_friendly_name(node->get_friendly_name());
std::string type = node->get_type_name();
std::string name = node->get_friendly_name();
// If node is a parameter, show another type name, so the node will be displayed correctly
get_rt_info()["layerType"] = type == "Parameter" ? "ParameterLowered" : type;
set_friendly_name(name);
constructor_validate_and_infer_types();
}

Expand Down
12 changes: 2 additions & 10 deletions src/common/snippets/src/op/subgraph.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@
#include "snippets/lowered/pass/propagate_layout.hpp"
#include "snippets/lowered/pass/cleanup_loop_offsets.hpp"
#include "snippets/lowered/pass/softmax_decomposition.hpp"
#include "snippets/lowered/pass/serialize_control_flow.hpp"
#include "snippets/lowered/pass/serialize_data_flow.hpp"
#include "snippets/lowered/pass/move_scalar_to_consumer.hpp"
#include "snippets/lowered/pass/move_result_out_of_loop.hpp"
#include "snippets/lowered/pass/clean_repeated_ptr_shifts.hpp"
Expand Down Expand Up @@ -530,16 +532,6 @@ void Subgraph::print() const {
}
}


void Subgraph::serialize() const {
std::stringstream xmlFile, binFile;
ov::pass::Serialize serializer(xmlFile, xmlFile, ov::pass::Serialize::Version::IR_V10);
serializer.run_on_model(body_ptr());
auto m_constants = binFile.str();
auto m_model = xmlFile.str();
std::cout << m_model << std::endl;
}

} // namespace op
} // namespace snippets
} // namespace ov

0 comments on commit 878f05e

Please sign in to comment.