[GPU][MLIR] MLIR Graph compiler integration - #35336
Conversation
- MLIR is used is a new ngraph transformation, compiled together with other transformations and called from CPU plugin transformation pipeline.
- The transformation identifies OV Add operation in the graph and replaces it by a new custom MLIROp operation -- a single op to enclose arbitrary MLIR program.
- Add op lowering uses linalg::AddOp on tensors. Each op is represented as isolated MLIR Module.
- MLIROp::evaluate calls MLIR-compiled partition when graph is inferred.
- Limitation: Add op should have no implicit broadcast, it is not supported and not checked. If Add implies implicit broadcast the result is undefined.
- Short code to activate the functionality (in Python, using PyTorch as a source for a small model):
import torch
import openvino as ov
class My(torch.nn.Module):
def forward(self, a):
b = a*a
return ((a+a) * (a+b)) / a
my = My()
input = torch.tensor([1, 2, 3], dtype=torch.float32)
print('Expected:', my(input))
ov_model = ov.convert_model(my, example_input=input)
print(ov_model)
ov_compiled = ov.compile_model(ov_model)
print('Result:', ov_compiled(input)[0])
Improves MLIR pipeline to avoid temporary buffer allocation and copy in linalg named binary operation conversion. Changes: - use tensor.empty in outs - add bufferization pre- and post-processing - mark outputs as 'restrict'
This creates a scenario where the Expected<T> doesn't get checked and the execution crashes, even if the engine was created correctly.
Mostly static declarations, but one unnecessarily wide lambda capture.
* Simple graph patritioner
* Multi-node MLIR lowering in a correct partition termination, explicit conversion of not broadcastale nodes: Add, Sub, Mul, Div.
* Minor: moved elementwise_f32_etc to outer scope, removed debug output
* static -> namespace {}
* Moved MLIROp, transformation pipeline and evaluation tools to a separate files mlir_op.hpp/cpp * Moved common conversion for precision nad shape to a separate file * Move SubgraphTracker to a separate file. Not use unordered_ containers and delete hash function for Output<Node>. Cleanup.
Adds cleanup right before bufferization to eliminate temporary buffer creation in multi-node pattern lowering.
* Moved ConversionContext to a separate file * Moved MarkPattern and associated helpers to conversion_context. * FIXME: One particular case of MatMul -> linalg::MatmulTransposeBOp conversion. Currently has a hack in output tensor allocation in common code, works with MatMul of specific size. * Use fill to prepare output for MatMul result, fixed dynamic output dimensions (transpose_b wasn't handled). * Fix getConstant: swap int and real parts * Removed redundant Value(...) * Small clarification in a comment * Generic mapping of dynamic dimensions from input to output of MLIROp during inference, correct output tensor allocation based on that functionality. Removed related hack in MLIROp::evaluate.
* Allow eltwise ops with static shapes * Fix matmul output shape --------- Co-authored-by: Sergey Lyalin <sergey.lyalin@intel.com>
Adds ReLU op matcher and lowering to MLIR named Linalg ops. Also, adds buffer deallocation passes to prevent memory leaks when temporary buffers are created in larger graphs.
* [GPU] Generic layer draft * mlir op
* Add support for TPP MLIR * Some CMake magic, but not enough for all tools that fail to link * Split enable_tpp_mlir into add_tpp_mlir_includes and add_tpp_mlir_libs. Removed reference of TPP in all places except transformations and main ov library. * Include TPP-MLIR headers * Use MLIR_ALL_LIBS property to link all MLIR libraries * Registering TPP related dialects in injectMLIR * Reference build scripts for MLIR and TPP-MLIR * One more library from tpp as a dependency, reduced includes * Fixed linker problems by properly ordering TPP dependencies * Minor: add more comments --------- Co-authored-by: Renato Golin <rengolin@systemcall.eu>
* Postponed of tpp_xsmm_runner_utils load * Added xsmm runner libs copying to the target ov direcotry listing the names of libs explicitly (FIXME)
Manually finds and passes XSMM runner library to the MLIR JIT engine to resolve missing TPP xsmm_* symbols when executing from Python. Works only for Linux currently.
…lyalin#149) This reverts commit a510e01.
* Broadcast support for element-wise ops and more economical way of dynamic dimensions handling based on symbols. * Simpler broadcast dims cacluations, moved to common utils. * Use common function to compute dynamic dimension values in MatMul and Relu. * Element type configurable restriction for the new BinaryEltwisePattern. Forced f32 in the conversion pipeline.
…lyalin#151) * Check MatMul expected attributes in a predicate instead of assert in the transformation callback. Fixes PyTorch addmm layer tests. * Put rank == 2 restriction on MatMul conversion. Fixes PyTorch linear layer tests.
Adds support for `linalg.matmul` and `linalg.matmul_tranpose_a`.
* Check MatMul expected attributes in a predicate instead of assert in the transformation callback. Fixes PyTorch addmm layer tests. * Put rank == 2 restriction on MatMul conversion. Fixes PyTorch linear layer tests. * Enable MLIR and TPP-MLIR activation via environment variables * Added debug macros controlled by OV_MLIR_DEBUG env variable. Disabled debug prints by default.
Relaxes MLIR conversion matchers to accept any element type.
…in return statement in is_dubug function. (slyalin#157)
Collection of MLP benchmarks using combination of OV and TPP-MLIR.
Resizes MLP benchmarks to align with existing MLIR tests. Tweaks model generator to expose full control over M,N,K dimensions of torch Linear layer.
Fewer iterations to speedup testing. Can be changed/reverted later.
Sets OV infer precision same as the data type. Minor debug print and bash fixes.
Adds option for TPP-MLIR benchmark with weights as constants which enables compile-time packing. Also, add utility benchmark runners.
* Integration with GraphCompiler Grapth Compiler is disabled by default, to enable build with -DENABLE_GRAPH_COMPILER=ON * Add suggestions from code review * Apply suggestions from code review Co-authored-by: Sergey Lyalin <sergey.lyalin@intel.com> --------- Co-authored-by: Sergey Lyalin <sergey.lyalin@intel.com>
* [GraphCompiler] Use find_package() for CMake < 3.24 * Changed the Graph Compiler git url
Signed-off-by: dchigarev <dmitry.chigarev@intel.com>
|
@EgorDuplensky , could you please review? |
There was a problem hiding this comment.
Pull request overview
This PR introduces an optional MLIR/Graph-Compiler execution path in the Intel GPU plugin by partitioning supported OpenVINO subgraphs into an internal MLIROp/mlir_primitive and executing them via Graph Compiler (OpenCL runtime objects passed through runtime metadata).
Changes:
- Adds MLIR partitioning + conversion infrastructure (patterns, converters, subgraph tracking) and integrates it as an optional GPU transformation stage gated by
ENABLE_GRAPH_COMPILER+ov::intel_gpu::enable_mlir. - Adds runtime plumbing to pass native OpenCL handles (queue/memory/events) to Graph Compiler and wrap returned
cl_events back into plugin events. - Adds a dedicated MLIR functional test suite + CI workflow(s) for MLIR-enabled builds.
Reviewed changes
Copilot reviewed 78 out of 78 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| src/plugins/intel_gpu/tests/unit/CMakeLists.txt | Adjusts unit test source lists/linking when Graph Compiler is enabled. |
| src/plugins/intel_gpu/tests/functional/CMakeLists.txt | Excludes MLIR functional tests when Graph Compiler is disabled. |
| src/plugins/intel_gpu/tests/functional/mlir_op/mlir_test_env.hpp | Adds MLIR test fixture utilities (env + runtime-graph checks). |
| src/plugins/intel_gpu/tests/functional/mlir_op/sdpa.cpp | Adds MLIR SDPA functional tests and MLIR execution verification. |
| src/plugins/intel_gpu/tests/functional/mlir_op/matmul.cpp | Adds MLIR MatMul tests (static + dynamic shapes). |
| src/plugins/intel_gpu/tests/functional/mlir_op/matmul_rms_norm_concat.cpp | Adds MLIR MatMul+RMSNorm(+Concat) tests and benchmarks. |
| src/plugins/intel_gpu/tests/functional/mlir_op/rms.cpp | Adds MLIR RMS op functional tests. |
| src/plugins/intel_gpu/tests/functional/mlir_op/reduction.cpp | Adds MLIR reduction op functional tests. |
| src/plugins/intel_gpu/tests/functional/mlir_op/concat.cpp | Adds MLIR Concat tests (incl. transpose+concat). |
| src/plugins/intel_gpu/tests/functional/mlir_op/transpose.cpp | Adds MLIR Transpose and Reshape+Transpose tests. |
| src/plugins/intel_gpu/tests/functional/mlir_op/unary_eltwise.cpp | Adds MLIR unary elementwise tests. |
| src/plugins/intel_gpu/tests/functional/mlir_op/binary_eltwise.cpp | Adds MLIR binary elementwise tests (with some currently skipped). |
| src/plugins/intel_gpu/src/runtime/ocl/ocl_stream.hpp | Exposes OpenCL queue handle + base-event wrapping API on OCL stream. |
| src/plugins/intel_gpu/src/runtime/ocl/ocl_stream.cpp | Implements base-event creation from an existing cl_event. |
| src/plugins/intel_gpu/src/runtime/ocl/ocl_memory.hpp | Exposes cl_mem native handle from OCL GPU buffer. |
| src/plugins/intel_gpu/src/runtime/ocl/ocl_base_event.hpp | Exposes cl_event native handle from OCL events. |
| src/plugins/intel_gpu/include/intel_gpu/runtime/stream.hpp | Adds generic get_native_handle() + create_base_event(void*) hooks. |
| src/plugins/intel_gpu/include/intel_gpu/runtime/memory.hpp | Adds generic memory::get_native_handle() hook. |
| src/plugins/intel_gpu/include/intel_gpu/runtime/event.hpp | Adds generic event::get_native_handle() hook. |
| src/plugins/intel_gpu/include/intel_gpu/runtime/options.inl | Adds ov::intel_gpu::enable_mlir runtime option registration. |
| src/inference/include/openvino/runtime/intel_gpu/properties.hpp | Adds public GPU property enable_mlir. |
| src/plugins/intel_gpu/src/plugin/plugin.cpp | Exposes enable_mlir in supported property list. |
| src/plugins/intel_gpu/src/plugin/transformations_pipeline.cpp | Hooks transformMLIR into the GPU pipeline and disables SDPA decomposition when MLIR is enabled. |
| src/plugins/intel_gpu/include/intel_gpu/op/mlir_op.hpp | Declares internal ov::intel_gpu::op::MLIROp node API. |
| src/plugins/intel_gpu/src/plugin/transformations/op/mlir_op.cpp | Implements MLIROp shape inference and evaluation (packed args, runtime metadata). |
| src/plugins/intel_gpu/include/intel_gpu/primitives/mlir_primitive.hpp | Declares cldnn::mlir_primitive wrapper around MLIROp. |
| src/plugins/intel_gpu/src/plugin/ops/mlir_op.cpp | Registers factory + builds mlir_primitive from MLIROp during program build. |
| src/plugins/intel_gpu/include/intel_gpu/plugin/primitives_list.hpp | Registers internal MLIR factory under GRAPH_COMPILER. |
| src/plugins/intel_gpu/src/graph/include/mlir_primitive_inst.h | Adds graph-side primitive instantiation for mlir_primitive. |
| src/plugins/intel_gpu/src/graph/mlir_primitive.cpp | Adds layout inference + JSON description for mlir_primitive. |
| src/plugins/intel_gpu/src/graph/registry/registry.hpp | Registers implementation set for mlir_primitive. |
| src/plugins/intel_gpu/src/graph/registry/mlir_primitive_impls.cpp | Wires mlir_primitive to common implementation managers. |
| src/plugins/intel_gpu/src/graph/impls/common/register.hpp | Registers common impl for mlir_primitive. |
| src/plugins/intel_gpu/src/graph/impls/common/register.cpp | Registers common impl for mlir_primitive. |
| src/plugins/intel_gpu/src/graph/impls/common/mlir_primitive.hpp | Declares common impl manager for mlir_primitive. |
| src/plugins/intel_gpu/src/graph/impls/common/mlir_primitive.cpp | Implements runtime execution: extracts OCL handles, calls MLIROp::evaluate, wraps result events. |
| src/plugins/intel_gpu/src/plugin/transformations/mlir/interface/convert.hpp | Declares transformMLIR() entry point. |
| src/plugins/intel_gpu/src/plugin/transformations/mlir/interface/mlir_evaluate_base.hpp | Defines MLIR evaluation interface used by MLIROp. |
| src/plugins/intel_gpu/src/plugin/transformations/mlir/interface/properties.hpp | Defines evaluation-context keys for wait lists/result events/USM flags. |
| src/plugins/intel_gpu/src/plugin/transformations/mlir/mlir_evaluate.hpp | Declares Graph Compiler-backed MLIR executor for GPU. |
| src/plugins/intel_gpu/src/plugin/transformations/mlir/mlir_evaluate.cpp | Implements Graph Compiler module build + execution (static/dynamic) with OCL context wiring. |
| src/plugins/intel_gpu/src/plugin/transformations/mlir/subgraph_tracker.hpp | Adds subgraph tracking structure for partitioning marked nodes. |
| src/plugins/intel_gpu/src/plugin/transformations/mlir/subgraph_tracker.cpp | Implements partitioning bookkeeping and subgraph termination logic. |
| src/plugins/intel_gpu/src/plugin/transformations/mlir/graph_converter.hpp | Declares OV→MLIR graph converter infrastructure + marking pass wrapper. |
| src/plugins/intel_gpu/src/plugin/transformations/mlir/graph_converter.cpp | Implements convertor storage in RT info + subgraph mark helpers. |
| src/plugins/intel_gpu/src/plugin/transformations/mlir/conversion/patterns.hpp | Declares MLIR marking patterns for supported ops. |
| src/plugins/intel_gpu/src/plugin/transformations/mlir/conversion/patterns.cpp | Implements patterns and match predicates (SDPA, matmul, broadcastable eltwise, etc.). |
| src/plugins/intel_gpu/src/plugin/transformations/mlir/common/README.md | Documents converter structure and conversion context responsibilities. |
| src/plugins/intel_gpu/src/plugin/transformations/mlir/common/typedefs.hpp | Adds local typedefs for MLIR conversion code. |
| src/plugins/intel_gpu/src/plugin/transformations/mlir/common/convert_common.hpp | Adds shared MLIR conversion utilities and debug macros. |
| src/plugins/intel_gpu/src/plugin/transformations/mlir/common/convert_common.cpp | Implements type/shape import, broadcast helpers, and debug env toggle. |
| src/plugins/intel_gpu/src/plugin/transformations/mlir/common/conversion_context.hpp | Declares conversion context (inputs + dynamic-dimension value hooks). |
| src/plugins/intel_gpu/src/plugin/transformations/mlir/common/conversion_context.cpp | Implements dynamic dimension value collection. |
| src/plugins/intel_gpu/src/plugin/transformations/mlir/common/converters/binary_eltwise.hpp | Implements MLIR lowering for broadcastable binary elementwise ops. |
| src/plugins/intel_gpu/src/plugin/transformations/mlir/common/converters/unary_eltwise.hpp | Implements MLIR lowering for unary elementwise ops. |
| src/plugins/intel_gpu/src/plugin/transformations/mlir/common/converters/concat.hpp | Implements MLIR lowering for Concat. |
| src/plugins/intel_gpu/src/plugin/transformations/mlir/common/converters/floor.hpp | Implements MLIR lowering for Floor. |
| src/plugins/intel_gpu/src/plugin/transformations/mlir/common/converters/gather.hpp | Implements MLIR lowering for Gather with negative-index handling. |
| src/plugins/intel_gpu/src/plugin/transformations/mlir/common/converters/matmul.hpp | Implements MLIR lowering for MatMul/BatchMatMul variants with rank adjustments. |
| src/plugins/intel_gpu/src/plugin/transformations/mlir/common/converters/reduce.hpp | Implements MLIR lowering for Reduce ops (including ReduceMean division). |
| src/plugins/intel_gpu/src/plugin/transformations/mlir/common/converters/relu.hpp | Implements MLIR lowering for Relu. |
| src/plugins/intel_gpu/src/plugin/transformations/mlir/common/converters/reshape.hpp | Implements MLIR lowering for Reshape via (expand/collapse) reassociation. |
| src/plugins/intel_gpu/src/plugin/transformations/mlir/common/converters/rms.hpp | Implements MLIR lowering for internal RMS normalization op. |
| src/plugins/intel_gpu/src/plugin/transformations/mlir/common/converters/sdpa.hpp | Implements MLIR lowering for SDPA via linalgx::AttentionOp. |
| src/plugins/intel_gpu/src/plugin/transformations/mlir/common/converters/shape_of.hpp | Implements MLIR lowering for ShapeOf. |
| src/plugins/intel_gpu/src/plugin/transformations/mlir/common/converters/slice.hpp | Implements MLIR lowering for Slice via ExtractSliceOp (limited semantics). |
| src/plugins/intel_gpu/src/plugin/transformations/mlir/common/converters/squeeze.hpp | Implements MLIR lowering for Squeeze via CollapseShapeOp. |
| src/plugins/intel_gpu/src/plugin/transformations/mlir/common/converters/transpose.hpp | Implements MLIR lowering for Transpose via linalg::TransposeOp. |
| src/plugins/intel_gpu/src/plugin/transformations/mlir/common/converters/unsqueeze.hpp | Implements MLIR lowering for Unsqueeze via ExpandShapeOp. |
| src/plugins/intel_gpu/CMakeLists.txt | Adds Graph Compiler build option and MLIR OBJECT library wiring into GPU plugin. |
| cmake/features.cmake | Adds ENABLE_GRAPH_COMPILER build option. |
| cmake/llvm.cmake | Adds LLVM/MLIR discovery helper for Graph Compiler integration. |
| cmake/graph-compiler.cmake | Adds Graph Compiler discovery/fetch logic and build-time toggles. |
| cmake/developer_package/plugins/plugins.cmake | Adds LINKABLE option to build plugins as SHARED when needed by tests. |
| .github/workflows/dev_gpu_linux_mlir.yml | Adds dedicated MLIR GPU CI workflow (build LLVM+GC, build OV, run MLIR tests). |
| .github/workflows/graph-compiler.yml | Adds a workflow intended to validate Graph Compiler GPU backend integration. |
| .github/dockerfiles/docker_tag | Updates CI docker tag reference. |
| on: | ||
| push: | ||
| pull_request: | ||
|
|
||
| permissions: | ||
| contents: read | ||
|
|
||
| env: | ||
| GC_REPO: https://x-access-token:${{ secrets.GC_TOKEN }}@github.com/intel-sandbox/graph-compiler | ||
| GC_TAG: main | ||
| BUILD_DIR: ${{ github.workspace }}-gc-build | ||
| OUTPUT_DIR: ${{ github.workspace }}-gc-bin | ||
|
|
||
| jobs: | ||
| ci: | ||
| runs-on: ${{ vars.RUNNER }} | ||
|
|
There was a problem hiding this comment.
This workflow is only used in our internal OV-fork's CI. It's not launched in the main ov-repo and will be removed just before the merge
Signed-off-by: dchigarev <dmitry.chigarev@intel.com>
Signed-off-by: dchigarev <dmitry.chigarev@intel.com>
Signed-off-by: dchigarev <dmitry.chigarev@intel.com>
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 78 out of 78 changed files in this pull request and generated 4 comments.
Suppressed comments (1)
src/plugins/intel_gpu/tests/functional/mlir_op/mlir_test_env.hpp:36
- [MEDIUM] MlirMatchAllEnv uses
setenv/unsetenvdirectly, which is not available on Windows. Other OpenVINO tests use_putenv_sunder_WIN32to keep tests portable.
Signed-off-by: dchigarev <dmitry.chigarev@intel.com>
Signed-off-by: dchigarev <dmitry.chigarev@intel.com>
Signed-off-by: dchigarev <dmitry.chigarev@intel.com>
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 78 out of 78 changed files in this pull request and generated 3 comments.
Suppressed comments (2)
src/plugins/intel_gpu/src/plugin/transformations/mlir/conversion/patterns.cpp:134
- [BLOCKER] Equal Q/K/V rank is insufficient for this lowering. OpenVINO SDPA explicitly allows NumPy broadcasting of the leading dimensions (see
src/core/shape_inference/include/scaled_dot_product_attention_shape_inference.hpp:41-65), whileConvertSDPAindexes every Q/K/V with the same batch/head induction variables and never broadcasts them. A valid case such as Q[2,7,3,4], K[2,1,5,4], V[1,7,5,6]can therefore index singleton dimensions incorrectly. Restrict the matcher to identical supported leading dimensions (and equivalent supported mask broadcasting), or materialize the required broadcasts beforeAttentionOp.
src/plugins/intel_gpu/src/plugin/transformations/mlir/conversion/patterns.cpp:83 - [HIGH] This predicate still accepts valid MatMul variants that the converter cannot lower: rank-1 operands reach
drop_back(2), and NumPy-broadcasted batch dimensions are passed directly tolinalg::BatchMatmulOpdespite the converter's explicitTODO: Support broadcasts. Such models will be marked for MLIR and fail IR construction/verification instead of falling back to the native GPU path. Require operand ranks of at least 2 and identical supported batch dimensions here, or implement vector promotion and batch broadcasting in the converter.
This issue also appears on line 130 of the same file.
| auto shape_of = shape::ShapeOfOp::create(builder, loc, mlir::ValueRange{input}); | ||
| auto cast = arith::IndexCastOp::create(builder, loc, indices_type, mlir::ValueRange{shape_of}); | ||
|
|
||
| auto empty_add = tensor::EmptyOp::create(builder, loc, indices_expanded.getType(), dynamic_index_dims); | ||
| auto add = linalg::AddOp::create(builder, loc, mlir::ValueRange{cast.getResult(), indices_expanded}, mlir::ValueRange{empty_add}); |
Presumably after LLVM comit 55b38aeec8cf, there is a precision degradation.
|
build_jenkins |
Signed-off-by: dchigarev <dmitry.chigarev@intel.com>
Signed-off-by: dchigarev <dmitry.chigarev@intel.com>
Signed-off-by: dchigarev <dmitry.chigarev@intel.com>
* Bump LLVM version to 24 * Fixed errors afetr changes in GC interfaces * Update cmake/llvm.cmake Co-authored-by: Dmitry Chigarev <dmitry.chigarev@intel.com> * Removed tests from exclude --------- Co-authored-by: Dmitry Chigarev <dmitry.chigarev@intel.com>
Signed-off-by: dchigarev <dmitry.chigarev@intel.com>
I. Brief description
The PR adds an optional MLIR-based execution path to the GPU plugin. A new stage called
transformMLIRis added to the GPU's transformation pipeline that matches suitable subgraphs inov::Model, converts them to mlir-module(s) using linalg-dialect, and inserts anov::op::MLIROpoperation representing the converted subgraph:an illustration
ov::Model transformation made by the
transformMLIRstage:Important to note, that an actual compilation and execution of the converted MLIR module happens in a separate project called
graph-compiler (GC)- the project is "ingress-agnostic" and doesn't depend on OV specifically, it handles an arbitrary mlir-linalg-code as an input and produces a GPU-binary combined with a cpu-side launching code (using opencl runtime). The Openvino side is only responsible for matching a suitable subgraph inov::Model, converting it to MLIR as is (all the optimizations are made on the graph-compiler side), and providing the runtime-info on inference (opencl queue/context handlers, buffers, etc).The
ov::op::MLIROpnaturally follows the OVs compile/infer semantic: onov::Model::compile()the MLIR module is fully compiled to a binary (even if the module has dynamic shapes), oninfer()it launches the compiled binary (no extra latency).Supported subgraphs
The main operation that we were focused on was
SDPA, we've thoroughly tested this case, spent efforts on tuning its performance and have a good understanding on how it behaves (~30% faster than gpu-native impl on BMG).SDPAis the only operation that is enabled via MLIR path by default.The MLIR path supports a lot more operations (full list here), we have unit tests for them, but never tested them on a "real model".
Enabling/disabling certain matching patterns can be controlled via
OV_MLIR_PATTERNSenv variable. For exampleOV_MLIR_PATTERNS='mart=MatMul,Add,Reshape,Transpose;rms=Power,ReduceMean,Add,Sqrt,Divide'would match projection subgraphs; Setting the variable to an empty string enables conversion for every supported operation.Feature enabling
The feature is disabled by default and gated twice:
-DENABLE_GRAPH_COMPILER=ON(defaultOFF) - when off, no MLIR related implementations are compiled (no pattern matching/conversion/unit tests/inference logic). The new MLIR-related definitions are still included to the build though (ov::op::MLIROporcldnn::mlir_primitiveheader files) to avoid sudden broken includes. We're open to discuss this to decide, how to better gate the mlir-related code in OV.ov::intel_gpu::enable_mlirproperty (env variableOV_GPU_ENABLE_MLIR) which is alsofalseby default.Lib size increase
libopenvino_intel_gpu_plugin.so:II. Changes in common / existing code
Under spoiler
1. New op:
ov::intel_gpu::op::MLIROpsrc/plugins/intel_gpu/include/intel_gpu/op/mlir_op.hpp— public declaration, next to theplugin's other internal ops, it's free of any MLIR/GC includes.
src/plugins/intel_gpu/src/plugin/transformations/op/mlir_op.cpp— implementation(
validate_and_infer_types,shape_infer,clone_with_new_inputs,evaluate,MemRefDescriptorargument packing). Guarded by#ifdef GRAPH_COMPILER.primitives_list.hpp(
REGISTER_FACTORY(internal, MLIR), under#ifdef GRAPH_COMPILER) and created bysrc/plugins/intel_gpu/src/plugin/ops/mlir_op.cpp.2. New primitive:
cldnn::mlir_primitiveinclude/intel_gpu/primitives/mlir_primitive.hpp— carries theshared_ptr<ov::Node>(the
MLIROp), ashape_infer_function, output count and output types. No MLIR/GC typescross this boundary, so the whole
graphlibrary stays MLIR-free.src/graph/include/mlir_primitive_inst.h,src/graph/mlir_primitive.cppsrc/graph/impls/common/mlir_primitive.{hpp,cpp}— extracts ocl runtime objects (queue, dependent events, buffers), callsMLIROp::evaluate(...runtime_objects...), andtranslates Graph Compiler's result
cl_events back intocldnn::events.impls/common/register.{cpp,hpp},registry/registry.hppand the newregistry/mlir_primitive_impls.cpp.3. Event / memory / stream native handles (runtime)
To hand OpenCL objects to Graph Compiler, these virtual accessors were added with
default no-op implementations and OCL overrides:
cldnn::memoryvoid* get_native_handle() constgpu_buffer→cl_memcldnn::eventvoid* get_native_handle()ocl_base_event→cl_eventcldnn::streamvoid* get_native_handle() constocl_stream→cl_command_queuecldnn::streamevent::ptr create_base_event(void* handle)ocl_stream→ wraps acl_eventNon-OCL backends (ze, sycl) keep the defaults;
mlir_primitive_implthrows if a handle isunavailable, so the MLIR path is effectively OCL-only for now.
4. Properties / config
ov::intel_gpu::enable_mlir("GPU_ENABLE_MLIR") insrc/inference/include/openvino/runtime/intel_gpu/properties.hpp, added toPlugin::get_supported_properties()(RW).OV_CONFIG_RELEASE_OPTION(ov::intel_gpu, enable_mlir, false, …)ininclude/intel_gpu/runtime/options.inl, i.e. also settable viaOV_GPU_ENABLE_MLIR.5.
transformations_pipeline.cpptransformMLIR()is registered as the last stage of the pipeline (just beforeResolveNameCollisions), receiving aloweringContextthat carries thecl_contextextracted from the plugin's remote context (
ov::intel_gpu::ocl_context).ScaledDotProductAttentionDecompositionis force-disabled whenenable_mliris on, sothat
SDPAreaches the MLIR path as a single node instead of a decomposed subgraph (can be removed in the future, when matching of the 'decomposed' SDPA is implemented).6. Build system
src/plugins/intel_gpu/CMakeLists.txt— everything undersrc/plugin/transformations/mlir/is always removed fromPLUGIN_SOURCES. WhenENABLE_GRAPH_COMPILER=ONthose files are built into a dedicated OBJECT libraryopenvino_intel_gpu_mlir_objthat alone gets the MLIR/GC include dirs and linksGraphCompiler; the object library is then linked into the plugin. This keepsmlir/*.handgc/*.hout of every other translation unit.cmake/developer_package/plugins/plugins.cmake— newLINKABLEflag forov_add_plugin(). WithBUILD_SHARED_LIBS=ONa plugin is normally aMODULE, whichcannot be linked against; the GPU plugin needs to be a
SHAREDlibrary whenENABLE_GRAPH_COMPILER=ONso thatov_gpu_unit_tests(which compilestransformations_pipeline.cppdirectly) can resolvetransformMLIRand other symbols from theopenvino_intel_gpu_mlir_obj(Open to discuss on how to make it better)III. How to build OV with MLIR support
We decided no to add gc/mlir as a third-party submodule to the project for now, and agreed that a user/developer would have to manually build a suitable llvm & graph-compiler and then provide cmake-configs during openvino build.
It's an open question on where should we keep the pinned version in ov; for now we've just pinned it in ov-mlir ci job.
steps to build
Actual steps can be taken from OV-MLIR-CI:
dev_gpu_linux_mlir.yml1. Clone suitable graph-compiler and build gc + llvm:
2. Build Openvino with MLIR support:
3. Run
IV. CI and testing
The MLIR path is tested via its own test suites located at
intel_gpu/tests/functional/mlir_op(the test suites are not included to the regular build). The suites are mostly copied from the usual OV tests (e.g.functional/single_layer_tests/dynamic/scaled_dot_product_attention.cpp-->functional/mlir_op/sdpa.cpp) but redefine the tests base class (toMlirSubgraphTest), sometimes include additional cases or change the accuracy that's suitable for mlir implementations.A new CI-job was added
dev_gpu_linux.mlirthat builds suitable gc + llvm, builds OV with MLIR support, and runs tests fromfunctional/mlir_opfolder.The job is only triggered when mlir-related files are changed.
The LLVM build is quite time consuming (~20-30 mins), so it would be great if we could cache it somewhere in OV's CI infrastructure. The OV-CI docs mention
actions/cachewhich could be a good candidate, but it currently only has only ~1.5gb of free storage (and an LLVM build is ~1gb), so I've decided not to use it for now.V. Performance of the MLIR path
For now we only tested
stable-diffusion3.5 mediumon BMG (B580), where only SDPA goes through MLIR path:Full Table
Although the inference is faster, the compilation time of the whole model degrades significantly with the mlir path. There were no efforts at all to improve the compilation time for now, but we believe that it can be improved significantly:
Full table