Skip to content

Commit adb4703

Browse files
authored
[Snippets] LIR serialization improvements (openvinotoolkit#21291)
1 parent d18d8a4 commit adb4703

File tree

12 files changed

+270
-58
lines changed

12 files changed

+270
-58
lines changed

src/common/snippets/include/snippets/lowered/linear_ir.hpp

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,6 @@ class LinearIR {
125125
iterator find_after(iterator it, const ExpressionPtr& target) const;
126126

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

130129
class LoopManager;
131130
using LoopManagerPtr = std::shared_ptr<LoopManager>;
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
// Copyright (C) 2023 Intel Corporation
2+
// SPDX-License-Identifier: Apache-2.0
3+
//
4+
5+
#pragma once
6+
7+
#include "pass.hpp"
8+
#include "snippets/lowered/linear_ir.hpp"
9+
10+
namespace ov {
11+
namespace snippets {
12+
namespace lowered {
13+
namespace pass {
14+
15+
/**
16+
* @interface SerializeBase
17+
* @brief Base class for LinearIR serialization passes
18+
* @ingroup snippets
19+
*/
20+
class SerializeBase : public Pass {
21+
public:
22+
OPENVINO_RTTI("SerializeBase", "Pass")
23+
SerializeBase(const std::string& xml_path);
24+
25+
protected:
26+
std::string get_bin_path_from_xml(const std::string& xml_path);
27+
28+
const std::string m_xml_path;
29+
const std::string m_bin_path;
30+
};
31+
32+
} // namespace pass
33+
} // namespace lowered
34+
} // namespace snippets
35+
} // namespace ov
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
// Copyright (C) 2023 Intel Corporation
2+
// SPDX-License-Identifier: Apache-2.0
3+
//
4+
5+
#pragma once
6+
7+
#include "serialize_base.hpp"
8+
#include "snippets/lowered/linear_ir.hpp"
9+
10+
namespace ov {
11+
namespace snippets {
12+
namespace lowered {
13+
namespace pass {
14+
15+
/**
16+
* @interface SerializeControlFlow
17+
* @brief Serializes control flow graph of LinearIR
18+
* @ingroup snippets
19+
*/
20+
class SerializeControlFlow : public SerializeBase {
21+
public:
22+
OPENVINO_RTTI("SerializeControlFlow", "Pass", SerializeBase)
23+
SerializeControlFlow(const std::string& xml_path) : SerializeBase(xml_path) {}
24+
bool run(LinearIR& linear_ir) override;
25+
};
26+
27+
} // namespace pass
28+
} // namespace lowered
29+
} // namespace snippets
30+
} // namespace ov
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
// Copyright (C) 2023 Intel Corporation
2+
// SPDX-License-Identifier: Apache-2.0
3+
//
4+
5+
#pragma once
6+
7+
#include "serialize_base.hpp"
8+
#include "snippets/lowered/linear_ir.hpp"
9+
10+
namespace ov {
11+
namespace snippets {
12+
namespace lowered {
13+
namespace pass {
14+
15+
/**
16+
* @interface SerializeDataFlow
17+
* @brief Serializes data flow graph of LinearIR
18+
* @attention - This pass can not be run on the LinearIR after tail loop insertion.
19+
* @attention - Control flow operations (e.g. LoopBegin/LoopEnd) are not serialized
20+
* @ingroup snippets
21+
*/
22+
class SerializeDataFlow : public SerializeBase {
23+
public:
24+
OPENVINO_RTTI("SerializeDataFlow", "Pass", SerializeBase)
25+
SerializeDataFlow(const std::string& xml_path) : SerializeBase(xml_path) {}
26+
bool run(LinearIR& linear_ir) override;
27+
};
28+
29+
} // namespace pass
30+
} // namespace lowered
31+
} // namespace snippets
32+
} // namespace ov

src/common/snippets/include/snippets/op/serialization_node.hpp

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,17 +19,28 @@ namespace op {
1919
*/
2020
class SerializationNode : public ov::op::Op {
2121
public:
22-
OPENVINO_OP("SerializationNode", "SnippetsOpset");
23-
22+
enum SerializationMode { DATA_FLOW, CONTROL_FLOW };
2423
SerializationNode() = default;
25-
SerializationNode(const ov::OutputVector& args, const std::shared_ptr<lowered::Expression>& expr);
24+
SerializationNode(const ov::OutputVector& args,
25+
const std::shared_ptr<lowered::Expression>& expr,
26+
SerializationMode mode = SerializationMode::CONTROL_FLOW);
2627

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

32+
_OPENVINO_HIDDEN_METHOD static const DiscreteTypeInfo& get_type_info_static() {
33+
static ::ov::DiscreteTypeInfo type_info_static{"SerializationNode", "SnippetsOpset"};
34+
return type_info_static;
35+
}
36+
37+
const ::ov::DiscreteTypeInfo& get_type_info() const override {
38+
return m_expr->get_node()->get_type_info();
39+
}
40+
3141
private:
3242
std::shared_ptr<lowered::Expression> m_expr;
43+
SerializationMode m_mode;
3344
};
3445

3546
} // namespace op

src/common/snippets/include/snippets/op/subgraph.hpp

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,6 @@ class Subgraph : public ov::op::util::SubGraphOp {
124124

125125
void print() const;
126126

127-
void serialize() const;
128127
VectorDims infer_master_shape();
129128

130129
static auto wrap_node_as_subgraph(const std::shared_ptr<ov::Node>& node) -> std::shared_ptr<Subgraph>;

src/common/snippets/src/lowered/linear_ir.cpp

Lines changed: 0 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88

99
#include "snippets/lowered/loop_manager.hpp"
1010
#include "snippets/lowered/expression_factory.hpp"
11-
#include "snippets/op/serialization_node.hpp"
1211

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

89-
void LinearIR::serialize(const std::string& xml, const std::string& bin) const {
90-
auto first_node = std::make_shared<ov::op::v0::Parameter>(element::f32, Shape{});
91-
first_node->set_friendly_name("Start");
92-
first_node->get_rt_info()["execTimeMcs"] = 0;
93-
std::shared_ptr<Node> serialization_node = first_node;
94-
95-
// This map allows to get LoopBegin serialization node by original LoopBegin node
96-
// It is used to draw an edge between LoopBegin and LoopEnd serialization nodes
97-
std::map<std::shared_ptr<snippets::op::LoopBegin>, std::shared_ptr<Node>> loops_map;
98-
for (const auto& expr : m_expressions) {
99-
const auto node = expr->get_node();
100-
if (auto loop_end = ov::as_type_ptr<snippets::op::LoopEnd>(node)) {
101-
OPENVINO_ASSERT(loops_map.count(loop_end->get_loop_begin()),
102-
"Serialization can't find LoopBegin that corresponds to LoopEnd with friendly name ",
103-
loop_end->get_friendly_name());
104-
auto loop_begin_serialization_node = loops_map.at(loop_end->get_loop_begin());
105-
serialization_node = std::make_shared<op::SerializationNode>(ov::OutputVector{serialization_node, loop_begin_serialization_node}, expr);
106-
} else {
107-
serialization_node = std::make_shared<op::SerializationNode>(ov::OutputVector{serialization_node}, expr);
108-
if (auto loop_begin = ov::as_type_ptr<snippets::op::LoopBegin>(node)) {
109-
loops_map[loop_begin] = serialization_node;
110-
}
111-
}
112-
}
113-
auto last_node = std::make_shared<ov::op::v0::Result>(serialization_node);
114-
last_node->set_friendly_name("End");
115-
const auto tmp_model = std::make_shared<ov::Model>(ResultVector {last_node},
116-
ParameterVector {first_node},
117-
"Lowered_IR_Serialization");
118-
ov::pass::Serialize(xml, bin).run_on_model(tmp_model);
119-
}
120-
12188
LinearIR::container LinearIR::deep_copy_range(LinearIR::container::const_iterator begin,
12289
LinearIR::container::const_iterator end,
12390
ExressionMap& expression_map) {
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
// Copyright (C) 2023 Intel Corporation
2+
// SPDX-License-Identifier: Apache-2.0
3+
//
4+
5+
#include "snippets/lowered/pass/serialize_base.hpp"
6+
7+
#include "snippets/itt.hpp"
8+
9+
namespace ov {
10+
namespace snippets {
11+
namespace lowered {
12+
namespace pass {
13+
14+
SerializeBase::SerializeBase(const std::string& xml_path)
15+
: m_xml_path(xml_path),
16+
m_bin_path(get_bin_path_from_xml(xml_path)) {}
17+
18+
std::string SerializeBase::get_bin_path_from_xml(const std::string& xml_path) {
19+
#if defined(__linux__)
20+
return "/dev/null";
21+
#else
22+
return "";
23+
#endif
24+
}
25+
26+
} // namespace pass
27+
} // namespace lowered
28+
} // namespace snippets
29+
} // namespace ov
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
// Copyright (C) 2023 Intel Corporation
2+
// SPDX-License-Identifier: Apache-2.0
3+
//
4+
5+
#include "snippets/lowered/pass/serialize_control_flow.hpp"
6+
7+
#include "openvino/pass/serialize.hpp"
8+
#include "snippets/itt.hpp"
9+
#include "snippets/lowered/linear_ir.hpp"
10+
#include "snippets/op/serialization_node.hpp"
11+
#include "snippets/snippets_isa.hpp"
12+
13+
namespace ov {
14+
namespace snippets {
15+
namespace lowered {
16+
namespace pass {
17+
18+
bool SerializeControlFlow::run(LinearIR& linear_ir) {
19+
OV_ITT_SCOPED_TASK(ov::pass::itt::domains::SnippetsTransform, "Snippets::SerializeControlFlow")
20+
if (linear_ir.empty())
21+
return false;
22+
23+
auto first_node = std::make_shared<ov::op::v0::Parameter>(element::f32, Shape{});
24+
first_node->set_friendly_name("Start");
25+
first_node->get_rt_info()["execTimeMcs"] = 0;
26+
std::shared_ptr<Node> serialization_node = first_node;
27+
28+
// This map allows to get LoopBegin serialization node by original LoopBegin node
29+
// It is used to draw an edge between LoopBegin and LoopEnd serialization nodes
30+
std::map<std::shared_ptr<snippets::op::LoopBegin>, std::shared_ptr<Node>> loops_map;
31+
for (const auto& expr : linear_ir) {
32+
const auto node = expr->get_node();
33+
if (auto loop_end = ov::as_type_ptr<snippets::op::LoopEnd>(node)) {
34+
OPENVINO_ASSERT(loops_map.count(loop_end->get_loop_begin()),
35+
"Serialization can't find LoopBegin that corresponds to LoopEnd with friendly name ",
36+
loop_end->get_friendly_name());
37+
auto loop_begin_serialization_node = loops_map.at(loop_end->get_loop_begin());
38+
serialization_node = std::make_shared<op::SerializationNode>(ov::OutputVector{serialization_node, loop_begin_serialization_node}, expr);
39+
} else {
40+
serialization_node = std::make_shared<op::SerializationNode>(ov::OutputVector{serialization_node}, expr);
41+
if (auto loop_begin = ov::as_type_ptr<snippets::op::LoopBegin>(node)) {
42+
loops_map[loop_begin] = serialization_node;
43+
}
44+
}
45+
}
46+
auto last_node = std::make_shared<ov::op::v0::Result>(serialization_node);
47+
last_node->set_friendly_name("End");
48+
const auto model = std::make_shared<ov::Model>(ResultVector{last_node}, ParameterVector{first_node}, "Lowered_IR_Control_Flow");
49+
return ov::pass::Serialize(m_xml_path, m_bin_path).run_on_model(model);
50+
}
51+
52+
} // namespace pass
53+
} // namespace lowered
54+
} // namespace snippets
55+
} // namespace ov
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
// Copyright (C) 2023 Intel Corporation
2+
// SPDX-License-Identifier: Apache-2.0
3+
//
4+
5+
#include "snippets/lowered/pass/serialize_data_flow.hpp"
6+
7+
#include "openvino/pass/serialize.hpp"
8+
#include "snippets/itt.hpp"
9+
#include "snippets/lowered/linear_ir.hpp"
10+
#include "snippets/op/serialization_node.hpp"
11+
#include "snippets/snippets_isa.hpp"
12+
13+
namespace ov {
14+
namespace snippets {
15+
namespace lowered {
16+
namespace pass {
17+
18+
bool SerializeDataFlow::run(LinearIR& linear_ir) {
19+
OV_ITT_SCOPED_TASK(ov::pass::itt::domains::SnippetsTransform, "Snippets::SerializeDataFlow")
20+
if (linear_ir.empty())
21+
return false;
22+
23+
ov::ResultVector results;
24+
ov::ParameterVector parameters;
25+
std::map<ExpressionPtr, std::shared_ptr<Node>> ops_map;
26+
const auto serialization_mode = op::SerializationNode::SerializationMode::DATA_FLOW;
27+
for (const auto& expr : linear_ir) {
28+
const auto node = expr->get_node();
29+
ov::OutputVector inputs(expr->get_input_count());
30+
for (size_t i = 0; i < expr->get_input_count(); ++i) {
31+
const auto& input_expr = expr->get_input_port_connector(i)->get_source().get_expr();
32+
OPENVINO_ASSERT(ops_map.count(input_expr), "input node wasn't found during serialization");
33+
inputs[i] = ops_map[input_expr]->output(expr->get_input_port_connector(i)->get_source().get_index());
34+
}
35+
if (auto ioexpr = std::dynamic_pointer_cast<IOExpression>(expr)) {
36+
if (ioexpr->get_type() == IOExpression::io_type::INPUT) {
37+
const auto parameter = std::make_shared<ov::op::v0::Parameter>(element::f32, Shape{});
38+
ops_map[ioexpr] = parameter;
39+
parameters.push_back(parameter);
40+
} else {
41+
const auto result = std::make_shared<ov::op::v0::Result>(inputs[0]);
42+
ops_map[ioexpr] = result;
43+
results.push_back(result);
44+
}
45+
} else {
46+
const auto serialization_node = std::make_shared<op::SerializationNode>(inputs, expr, serialization_mode);
47+
ops_map[expr] = serialization_node;
48+
}
49+
}
50+
const auto model = std::make_shared<ov::Model>(results, parameters, "Lowered_IR_Data_Flow");
51+
return ov::pass::Serialize(m_xml_path, m_bin_path).run_on_model(model);
52+
}
53+
54+
} // namespace pass
55+
} // namespace lowered
56+
} // namespace snippets
57+
} // namespace ov

0 commit comments

Comments
 (0)