Skip to content
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,26 @@ Examples:
OV_SNIPPETS_DUMP_LIR="passes=ExtractLoopInvariants dir=path/dumpdir formats=all" binary ...
OV_SNIPPETS_DUMP_LIR="passes=all dir=path/dumpdir formats=control_flow" binary ...
OV_SNIPPETS_DUMP_LIR="passes=FuseLoops,InsertLoops,InsertLoadStore formats=data_flow" binary ...
OV_SNIPPETS_DUMP_LIR="passes=final formats=control_flow name_modifier=subgraph_name" binary ...
OV_SNIPPETS_DUMP_LIR="passes=all dir=path/dumpdir name_modifier=branchA" binary ...
```

Dumped files have below names:
- Regular passes: `lir_<index>_<pass>_(control_flow|data_flow)_(in|out).xml` (creates both input and output files)
- Final dump: `lir_<index>_Final_(control_flow|data_flow).xml` (creates single file only)

When `name_modifier` is provided, it is prepended to file names as a prefix:
- `name_modifier=subgraph_name` prepends the Snippets Subgraph friendly name where available (e.g., final dump).
- any other non-empty value prepends that literal value (e.g., `branchA_lir_...`).

Option names are case insensitive, the following options are supported:
- `passes` : Dump LIR around the passes if passes name are specified.
It support multiple comma separated pass names. The names are case insensitive.
Key word 'all' means to dump LIR around every pass.
This option is a must have, should not be omitted.
Special values: 'all' - dump all passes (includes 'final'), 'final' - dump final LIR snapshot right before code generation (single file, no _in/_out suffix).
- `dir` : Path to dumped LIR files.
If omitted, it defaults to snippets_LIR_dump.
If specified path doesn't exist, the directory will be created automatically.
- `formats` : Support values are control_flow, data_flow and all.
If omitted, it defaults to control_flow.
If omitted, it defaults to control_flow.
- `name_modifier` : Optional file-name prefix. Special value `subgraph_name` prepends the Snippets Subgraph friendly name to dumped files (where available). Any other non-empty value is used as a literal prefix. If omitted, no name modification is performed. Note: when using `subgraph_name`, characters '/' and ':' in the subgraph name are replaced with '_' for filesystem compatibility.
10 changes: 9 additions & 1 deletion src/common/snippets/include/snippets/lowered/linear_ir.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#include <list>
#include <memory>
#include <set>
#include <string>
#include <type_traits>
#include <unordered_map>
#include <utility>
Expand Down Expand Up @@ -102,7 +103,12 @@ class LinearIR {
size_t get_static_buffer_scratchpad_size() const {
return m_static_buffer_scratchpad_size;
}

const std::string& get_friendly_name() const {
return m_friendly_name;
}
void set_friendly_name(std::string name) {
m_friendly_name = std::move(name);
}
void set_loop_depth(size_t loop_depth) {
m_config.m_loop_depth = loop_depth;
}
Expand Down Expand Up @@ -394,6 +400,8 @@ class LinearIR {

// Size of static Buffer Scratchpad (Buffers with defined allocation size)
size_t m_static_buffer_scratchpad_size = 0;
// Human-readable identifier; typically set from Subgraph node friendly name
std::string m_friendly_name;
};
using LinearIRPtr = std::shared_ptr<LinearIR>;
using LinearIRCPtr = std::shared_ptr<const LinearIR>;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ class DebugCapsConfig {
std::string dir = "snippets_LIR_dump";
LIRFormatFilter format = {1 << LIRFormatFilter::controlFlow};
std::vector<std::string> passes;
std::string name_modifier;

std::vector<PropertySetterPtr> getPropertySetters() override {
return {PropertySetterPtr(new StringPropertySetter("dir", dir, "path to dumped LIRs")),
Expand All @@ -59,7 +60,13 @@ class DebugCapsConfig {
"passes",
passes,
"indicate dump LIRs around the passes. Support multiple passes with comma separated and case "
"insensitive. 'all' means dump all passes"))};
"insensitive. Special values: 'all' - dump all passes (includes 'final'), 'final' - dump final "
"LIR")),
PropertySetterPtr(new StringPropertySetter(
"name_modifier",
name_modifier,
"optional file-name prefix; special value 'subgraph_name' uses the Subgraph friendly name; any "
"other non-empty value is used as a literal prefix"))};
}
} dumpLIR;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#include <utility>
#ifdef SNIPPETS_DEBUG_CAPS

# include "openvino/util/common_util.hpp"
# include "openvino/util/file_util.hpp"
# include "snippets/lowered/linear_ir.hpp"
# include "snippets/lowered/pass/serialize_control_flow.hpp"
Expand All @@ -17,20 +18,41 @@ namespace ov::snippets {

class LIRPassDump {
public:
explicit LIRPassDump(const lowered::LinearIR& linear_ir, std::string pass_name)
enum class DumpMode : uint8_t { Both, SingleDump };

explicit LIRPassDump(const lowered::LinearIR& linear_ir, std::string pass_name, DumpMode mode = DumpMode::Both)
: linear_ir(linear_ir),
pass_name(std::move(pass_name)),
dump_mode(mode),
debug_config(*linear_ir.get_config().debug_config) {
dump("_in");
if (dump_mode == DumpMode::Both) {
dump("_in");
} else {
dump("");
}
}
~LIRPassDump() {
dump("_out");
if (dump_mode == DumpMode::Both) {
dump("_out");
}
}

private:
void dump(const std::string&& postfix) const {
static int num = 0; // just to keep dumped IRs ordered in filesystem
const auto pathAndName = debug_config.dumpLIR.dir + "/lir_";
auto pathAndName = debug_config.dumpLIR.dir + "/";
const auto nm_lower = ov::util::to_lower(debug_config.dumpLIR.name_modifier);
if (nm_lower == std::string("subgraph_name")) {
auto name_prefix = linear_ir.get_friendly_name();
// Replace '/' and ':' characters with '_' to ensure filesystem compatibility
// These characters are problematic in file paths
std::replace(name_prefix.begin(), name_prefix.end(), '/', '_');
std::replace(name_prefix.begin(), name_prefix.end(), ':', '_');
pathAndName += name_prefix + "_";
} else if (!debug_config.dumpLIR.name_modifier.empty()) {
pathAndName += debug_config.dumpLIR.name_modifier + "_";
}
pathAndName += "lir_";

ov::util::create_directory_recursive(debug_config.dumpLIR.dir);

Expand All @@ -51,6 +73,7 @@ class LIRPassDump {

const lowered::LinearIR& linear_ir;
const std::string pass_name;
const DumpMode dump_mode;
const DebugCapsConfig& debug_config;
};

Expand All @@ -67,4 +90,4 @@ class LIRPassDump {
: nullptr
#else
# define SNIPPETS_DEBUG_LIR_PASS_DUMP(_linear_ir, _pass)
#endif // SNIPPETS_DEBUG_CAPS
#endif // SNIPPETS_DEBUG_CAPS
1 change: 1 addition & 0 deletions src/common/snippets/src/lowered/linear_ir_builder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ std::vector<std::shared_ptr<ov::Node>> clone_nodes(const std::vector<std::shared
void LinearIRBuilder::clone(const LinearIR* src, LinearIR* dst, ExpressionMap& expression_map) const {
OPENVINO_ASSERT(src && dst, "Invalid pointers were provided for LinearIRBuilder::clone");
dst->m_config = src->m_config;
dst->m_friendly_name = src->m_friendly_name;

dst->m_expressions = clone_range(src->m_expressions.cbegin(), src->m_expressions.cend(), expression_map);
for (const auto& expr : dst->m_expressions) {
Expand Down
14 changes: 14 additions & 0 deletions src/common/snippets/src/op/subgraph.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#include <algorithm>
#include <cassert>
#include <cstddef>
#include <cstdlib>
#include <functional>
#include <map>
#include <memory>
Expand Down Expand Up @@ -97,6 +98,7 @@
#include "snippets/shape_inference/shape_inference.hpp"
#include "snippets/shape_types.hpp"
#include "snippets/utils/debug_caps_config.hpp"
#include "snippets/utils/linear_ir_pass_dumper.hpp"
#include "snippets/utils/utils.hpp"

using namespace ov::op::util;
Expand Down Expand Up @@ -412,6 +414,7 @@ std::shared_ptr<lowered::LinearIR> Subgraph::convert_body_to_linear_ir(
#endif // SNIPPETS_DEBUG_CAPS

m_linear_ir = std::make_shared<lowered::LinearIR>(body_ptr(), shape_infer_factory, lowering_config);
m_linear_ir->set_friendly_name(get_friendly_name());
m_shape_infer = m_linear_ir->get_shape_infer_instance();
return m_linear_ir;
}
Expand Down Expand Up @@ -619,6 +622,17 @@ snippets::Schedule Subgraph::generate(const void* compile_params) const {
shape_dependent_pipeline.run(*linear_ir);
}

#ifdef SNIPPETS_DEBUG_CAPS
const auto& debug_conf = *linear_ir->get_config().debug_config;
const auto& dump_names = debug_conf.dumpLIR.passes;
const bool dump_final =
(std::find(dump_names.begin(), dump_names.end(), std::string("final")) != dump_names.end()) ||
(std::find(dump_names.begin(), dump_names.end(), std::string("all")) != dump_names.end());
if (dump_final) {
LIRPassDump final_dump(*linear_ir, std::string("Final"), LIRPassDump::DumpMode::SingleDump);
}
#endif

auto lowering_result = m_generator->generate(linear_ir, compile_params);
return Schedule{std::move(lowering_result)};
}
Expand Down
Loading