Skip to content

EP vendor compatibility ignores CPU vendor, marking OpenVINO EP [incompatible] on Intel-CPU machines #1274

Description

@xieofxie

Summary

EPCatalog.is_compatible() decides EP↔hardware compatibility (the "L2" vendor check) using only GPU and NPU vendor strings. CPU is never considered.

OpenVINO EP supports Intel CPU as a valid device, so on a machine with an Intel CPU but no Intel GPU/NPU, the EP is incorrectly reported as [incompatible] and is excluded from EP/device selection.

Repro

Machine: Intel Core i9-10900X CPU + NVIDIA GeForce RTX 4080 (no Intel iGPU, no NPU).

winml sys output:

OpenVINOExecutionProvider  [incompatible]
  [incompatible] Catalog (catalog default)
    Version: 1.3.0+b130ce1
    Path: C:\Program Files\WindowsApps\MicrosoftCorporationII.WinML.Intel.OpenVINO.EP.1.8_1.8.69.0_x64__8wekyb3d8bbwe\ExecutionProvider\onnxruntime_providers_openvino_plugin.dll

The DLL is installed and registers successfully (it is not an L1 [failed] row) — it is purely the L2 vendor rule that rejects it.

Detected vendor strings on this machine:

>>> from winml.modelkit.ep_path import _get_detected_vendors
>>> sorted(_get_detected_vendors())
['NVIDIA', 'NVIDIA GeForce RTX 4080']

>>> from winml.modelkit.sysinfo.hardware import CPU
>>> [(c.manufacturer, c.name) for c in CPU.get_all()]
[('GenuineIntel', 'Intel(R) Core(TM) i9-10900X CPU @ 3.70GHz')]

"Intel" is present on the CPU, but the CPU is not scanned, so EP_CATALOG.is_compatible("OpenVINOExecutionProvider") returns False.

Root cause

src/winml/modelkit/ep_path.py_get_detected_vendors() iterates only GPU and NPU:

strings: set[str] = set()
for cls in (GPU, NPU):
    for hw in cls.get_all():
        for attr in ("manufacturer", "name"):
            ...

EPCatalog.Row(name="OpenVINOExecutionProvider", ..., vendor_requirements=frozenset({"Intel"})) therefore never matches on a discrete-GPU-only Intel system.

winml.modelkit.sysinfo.hardware.CPU already exposes manufacturer ("GenuineIntel") and name ("Intel(R) Core(TM) i9-10900X ..."), so the data is available — it is simply not aggregated.

Impact

Beyond the misleading winml sys label, the same predicate gates real EP selection and validation:

  • src/winml/modelkit/commands/sys.py:893,896 — status shown as incompatible, and the device list is suppressed for the row.
  • src/winml/modelkit/config/build.py:355 — build config validation rejects the EP.
  • src/winml/modelkit/session/ep_device.py:496,612,692,764 — EP/device deduction skips the EP, so OpenVINOExecutionProvider with a CPU device cannot be auto-selected (and explicit selection is likely rejected).

Net effect: OpenVINO CPU inference is unreachable on Intel-CPU machines without an Intel GPU/NPU.

Expected behavior

An EP whose vendor requirement is satisfied by any detected device class — CPU included — should be treated as compatible. OpenVINO on an Intel CPU should show as [primary] (or [shadowed]), list its available devices, and be selectable for build/session.

Notes / open questions for design

  • Adding CPU to the _get_detected_vendors() scan is the minimal fix, but it makes the check coarser: matching is a plain substring test over a flat vendor set, so it cannot express "this EP needs an Intel NPU" vs "an Intel CPU is enough". If any future EP needs device-class-specific gating, vendor_requirements should become vendor+device-class pairs rather than bare strings.
  • Vendor requirements are currently modeled per-EP, not per-device — worth confirming whether the other gated EPs (QNN/Qualcomm, VitisAI/MIGraphX/AMD) should also honor CPU vendor, or whether CPU should be opt-in per catalog row.
  • _get_detected_vendors() is functools.cached and raises RuntimeError on detection failure by design; a CPU addition must preserve that behavior (no silent empty-set fallback).
  • Tests to extend: tests/unit/ep_path/test_compat.py, tests/unit/session/test_is_compatible.py, tests/unit/session/test_ep_device.py.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workinghardwareHardware relatedneed triageNeeds triage

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions