diff --git a/packaging/fedora/44/installed-manifest.toml b/packaging/fedora/44/installed-manifest.toml index 9f04f28..6950353 100644 --- a/packaging/fedora/44/installed-manifest.toml +++ b/packaging/fedora/44/installed-manifest.toml @@ -8,17 +8,17 @@ source_lock_sha256 = "3701e9913758f724998dc9b201a5a3d694257d5c3db65464609bbe70a3 [[providers]] name = "intel-npu-compiler" -nevr = "0:2026.2.1-1.intelnpu.fc44" +nevr = "0:2026.2.1-2.intelnpu.fc44" arch = "x86_64" -rpm_filename = "intel-npu-compiler-2026.2.1-1.intelnpu.fc44.x86_64.rpm" -rpm_sha256 = "b23747b356f5c5bf9d1a91a2d821dc51d5cb425d2907cd2ef444666dab19b0a6" +rpm_filename = "intel-npu-compiler-2026.2.1-2.intelnpu.fc44.x86_64.rpm" +rpm_sha256 = "42acda9c94ffeb9f453a391a1d0a84a9f32f1aba2708d4f8d70bd4a002bdbae1" license = "Apache-2.0 AND MIT AND BSL-1.0 AND HPND AND BSD-3-Clause AND (GPL-2.0-only OR BSD-3-Clause) AND (Apache-2.0 WITH LLVM-exception) AND NCSA AND BSD-2-Clause AND ISC AND Spencer-94 AND Unicode-DFS-2015 AND LicenseRef-LLVM-MD5" [[providers.files]] path = "/usr/lib64/openvino-2026.2.1/libopenvino_intel_npu_compiler.so" -sha256 = "75c20d701d54ab05d8b2d6a0d6f0095c8b560664671fc7b89e18dcc479de1ced" +sha256 = "d43d99034d4c377794e5581aab1b111ff1410dd8faa21226b8c6d7ba9500b545" [[providers.files]] path = "/usr/lib64/openvino-2026.2.1/libopenvino_intel_npu_compiler_loader.so" -sha256 = "95103389cadb22f06987f549449de1d88c930585c782a690584b45b9e045f9c0" +sha256 = "6ff2df0f103e2f33df3ea1de287ca20d37e3ab4bbed542fa9e47bb32b2cee775" [[providers]] name = "intel-npu-driver" @@ -44,69 +44,69 @@ sha256 = "cdfe2ebd66aaec21d896134c93d82d60de2d8eede75a2c62898aeb9006e5a26f" [[providers]] name = "libopenvino-ir-frontend" -nevr = "0:2026.2.1-1.intelnpu.fc44" +nevr = "0:2026.2.1-2.intelnpu.fc44" arch = "x86_64" -rpm_filename = "libopenvino-ir-frontend-2026.2.1-1.intelnpu.fc44.x86_64.rpm" -rpm_sha256 = "2ee3a30bf624827c7f977d57037edd4b9c54a3ab8ab4189b96a8f2298a74ca8c" +rpm_filename = "libopenvino-ir-frontend-2026.2.1-2.intelnpu.fc44.x86_64.rpm" +rpm_sha256 = "7c266da799a146982158cfc5cb778e2a405570b8f96c4a324aa378c004770c67" license = "Apache-2.0 AND MIT AND BSL-1.0 AND HPND AND BSD-3-Clause AND (GPL-2.0-only OR BSD-3-Clause)" [[providers.files]] path = "/usr/lib64/libopenvino_ir_frontend.so.2026.2.1" -sha256 = "7f1fc805bafbd90ba1a73e973b09b3b69da9f33deebd9b6ccb833fa4d3f5431d" +sha256 = "328e7e47c945360bb2afff390c57e315581ab67307fa6f10e7eabef6ef1da497" [[providers]] name = "libopenvino-onnx-frontend" -nevr = "0:2026.2.1-1.intelnpu.fc44" +nevr = "0:2026.2.1-2.intelnpu.fc44" arch = "x86_64" -rpm_filename = "libopenvino-onnx-frontend-2026.2.1-1.intelnpu.fc44.x86_64.rpm" -rpm_sha256 = "1e195d7e261ab219026e1fcc7db28b853234b8ab7240f997ad0a203521507cf7" +rpm_filename = "libopenvino-onnx-frontend-2026.2.1-2.intelnpu.fc44.x86_64.rpm" +rpm_sha256 = "013bf6bd75f8a73dc52158452be4c7c345d06ee8b67be4b70b5a82f5410b6df2" license = "Apache-2.0 AND MIT AND BSL-1.0 AND HPND AND BSD-3-Clause AND (GPL-2.0-only OR BSD-3-Clause)" [[providers.files]] path = "/usr/lib64/libopenvino_onnx_frontend.so.2026.2.1" -sha256 = "d32c762615683baa1e7ab23314bacd7482f14e094c09b5f3dcd4974125ed2ebf" +sha256 = "9f6750418a4561de3d16a0793aecad28518124d7d054c02fdccd1db3844d7c21" [[providers]] name = "libopenvino-paddle-frontend" -nevr = "0:2026.2.1-1.intelnpu.fc44" +nevr = "0:2026.2.1-2.intelnpu.fc44" arch = "x86_64" -rpm_filename = "libopenvino-paddle-frontend-2026.2.1-1.intelnpu.fc44.x86_64.rpm" -rpm_sha256 = "f74b2b946a1a522e89684d9d55e909d198d27b70574af1cd11f06282772f06e8" +rpm_filename = "libopenvino-paddle-frontend-2026.2.1-2.intelnpu.fc44.x86_64.rpm" +rpm_sha256 = "ca9d8c2c1a990391ff180fceec943d883ac7c39736c266ddd49395c7588357d6" license = "Apache-2.0 AND MIT AND BSL-1.0 AND HPND AND BSD-3-Clause AND (GPL-2.0-only OR BSD-3-Clause)" [[providers.files]] path = "/usr/lib64/libopenvino_paddle_frontend.so.2026.2.1" -sha256 = "383c183f7b02fa54f0cf408cb32af53e11883bd71a9dde634561985a8a887e8e" +sha256 = "30708d122c220aad3899b11dc6f8c01da370ee195e3e12e7225effbf55796cfe" [[providers]] name = "libopenvino-pytorch-frontend" -nevr = "0:2026.2.1-1.intelnpu.fc44" +nevr = "0:2026.2.1-2.intelnpu.fc44" arch = "x86_64" -rpm_filename = "libopenvino-pytorch-frontend-2026.2.1-1.intelnpu.fc44.x86_64.rpm" -rpm_sha256 = "e03c0572ecbde4d7b2728f65c43781908475f7f17d7ed3abbb5d26d5fadd16da" +rpm_filename = "libopenvino-pytorch-frontend-2026.2.1-2.intelnpu.fc44.x86_64.rpm" +rpm_sha256 = "63497c0db3269099e34594ce2cd83400f82a078a825c203a25c53b28d0156116" license = "Apache-2.0 AND MIT AND BSL-1.0 AND HPND AND BSD-3-Clause AND (GPL-2.0-only OR BSD-3-Clause)" [[providers.files]] path = "/usr/lib64/libopenvino_pytorch_frontend.so.2026.2.1" -sha256 = "48d7ca02fcbee8e8d6a3e98fe43af79c47e1b571e937159f6dc759abfc44f091" +sha256 = "71454f2effcb98e6b95713a201ed0f32dd793a0b6c53e174b56c87e6f8e01177" [[providers]] name = "libopenvino-tensorflow-frontend" -nevr = "0:2026.2.1-1.intelnpu.fc44" +nevr = "0:2026.2.1-2.intelnpu.fc44" arch = "x86_64" -rpm_filename = "libopenvino-tensorflow-frontend-2026.2.1-1.intelnpu.fc44.x86_64.rpm" -rpm_sha256 = "f92f6aa71f27b4826cb8766c4b4bfa6f0eccee5a26dc37991bd76b6fa7c3d80c" +rpm_filename = "libopenvino-tensorflow-frontend-2026.2.1-2.intelnpu.fc44.x86_64.rpm" +rpm_sha256 = "a8d7ea5fc3df982f61e68b087b1b292b5c7a4411636370ac0ab9b367d3caeef1" license = "Apache-2.0 AND MIT AND BSL-1.0 AND HPND AND BSD-3-Clause AND (GPL-2.0-only OR BSD-3-Clause)" [[providers.files]] path = "/usr/lib64/libopenvino_tensorflow_frontend.so.2026.2.1" -sha256 = "42ee551ce3de0e6cc633ae689d66a5fb30a4a4b7cc84b21f83a10e27931b4b12" +sha256 = "f98ddc0f2b0230bfff9bbc681a16ee074882d6cfd177fd4e71263c5afe6260a4" [[providers]] name = "libopenvino-tensorflow-lite-frontend" -nevr = "0:2026.2.1-1.intelnpu.fc44" +nevr = "0:2026.2.1-2.intelnpu.fc44" arch = "x86_64" -rpm_filename = "libopenvino-tensorflow-lite-frontend-2026.2.1-1.intelnpu.fc44.x86_64.rpm" -rpm_sha256 = "bb8422862f68a05b47de024eb1665b2e1bc445d3e8ebae72e93d7c5792a72960" +rpm_filename = "libopenvino-tensorflow-lite-frontend-2026.2.1-2.intelnpu.fc44.x86_64.rpm" +rpm_sha256 = "108948c9a1fdaf7a114d44386e5f177fbc60d97271913c1728616d3953513696" license = "Apache-2.0 AND MIT AND BSL-1.0 AND HPND AND BSD-3-Clause AND (GPL-2.0-only OR BSD-3-Clause)" [[providers.files]] path = "/usr/lib64/libopenvino_tensorflow_lite_frontend.so.2026.2.1" -sha256 = "4c5b17ea4c7729137cc4f37419c9fa9cfe54ab101695a0857b162577c6d22096" +sha256 = "12ca49aeb343b6d8c40b53ee6ea073c5e1bda8b869fc009d54cab39915b4c198" [[providers]] name = "oneapi-level-zero" @@ -127,40 +127,40 @@ sha256 = "cb40020b63fba2ce06dd24d86b0379ecb3deb46e1e0aa7bc78ecdae1d529db17" [[providers]] name = "openvino" -nevr = "0:2026.2.1-1.intelnpu.fc44" +nevr = "0:2026.2.1-2.intelnpu.fc44" arch = "x86_64" -rpm_filename = "openvino-2026.2.1-1.intelnpu.fc44.x86_64.rpm" -rpm_sha256 = "6b21decd0fd9a9b869786f292fc666673c711994dafc54a134edd49a88e983cc" +rpm_filename = "openvino-2026.2.1-2.intelnpu.fc44.x86_64.rpm" +rpm_sha256 = "7a931d6a0de76f0fdfbd8d2cbe842366d048a7ba6957701174faaa0da845e0fb" license = "Apache-2.0 AND MIT AND BSL-1.0 AND HPND AND BSD-3-Clause AND (GPL-2.0-only OR BSD-3-Clause)" [[providers.files]] path = "/usr/lib64/libopenvino.so.2026.2.1" -sha256 = "c88fbb03e1eba6ec1f84ab60e1fbf1df343469d10143b035f1e68478ae7f73a6" +sha256 = "4951bfb32b088acc72aca1a3eca55de571349e03ddfd47e5d233eb7697e688f9" [[providers.files]] path = "/usr/lib64/libopenvino_c.so.2026.2.1" -sha256 = "2874084046c324bd8e18d3e2771c62f4075910a123888b5d000958eb36764f18" +sha256 = "bee6060131115df7705d95acfeceef31169c7f073a038b3b0d60afbd4dd5a620" [[providers]] name = "openvino-plugins" -nevr = "0:2026.2.1-1.intelnpu.fc44" +nevr = "0:2026.2.1-2.intelnpu.fc44" arch = "x86_64" -rpm_filename = "openvino-plugins-2026.2.1-1.intelnpu.fc44.x86_64.rpm" -rpm_sha256 = "b65db4a9409ea6ee002ba532371457e4ad3dcd7bf651e552d0da73e826b3c05f" +rpm_filename = "openvino-plugins-2026.2.1-2.intelnpu.fc44.x86_64.rpm" +rpm_sha256 = "8313df55462af8e452245c0cca021e7482e5384d2d0c00e0e99917a14972ee21" license = "Apache-2.0 AND MIT AND BSL-1.0 AND HPND AND BSD-3-Clause AND (GPL-2.0-only OR BSD-3-Clause)" [[providers.files]] path = "/usr/lib64/openvino-2026.2.1/cache.json" sha256 = "0b2ad2a99516a3411ce3fef274e8ae2880b41a6f00c9bac6768cd4a94b87c41c" [[providers.files]] path = "/usr/lib64/openvino-2026.2.1/libopenvino_auto_plugin.so" -sha256 = "0772f409d80caef2610c829541af3aaf25380e30da0499a522add1f629b028db" +sha256 = "dc9782da46e6c63e6568fb2dc939d7050bb26d100caca8bc8f8c65b562d22e95" [[providers.files]] path = "/usr/lib64/openvino-2026.2.1/libopenvino_hetero_plugin.so" -sha256 = "eea13817f0da4e04c95a35c2580399a93e526038ea3b8a6c39bfa4bef458e66a" +sha256 = "2ad2981519570814da602170395fe092382f2daa38b3e95042caf07b8a1db877" [[providers.files]] path = "/usr/lib64/openvino-2026.2.1/libopenvino_intel_cpu_plugin.so" -sha256 = "fa47affa46b208453fb8a1aef22fbbc9a0c84bd7fc98a649a3b351fb61370a37" +sha256 = "3a96453588ef09c472f7d6a273ecfe819fe68f9f579db12144870282dbb1f7dd" [[providers.files]] path = "/usr/lib64/openvino-2026.2.1/libopenvino_intel_gpu_plugin.so" -sha256 = "eb17e2afef4814891eeaf688f254265c5c7c8dbce61142f40fd3e368c8dcf53a" +sha256 = "07013bb06a6faeae9d8f11fc3ba35e33a136a8f8a91f4e4be39ab9120908c7d9" [[providers.files]] path = "/usr/lib64/openvino-2026.2.1/libopenvino_intel_npu_plugin.so" -sha256 = "8c36e7618aaa81480f859a24e67d91b02f3870914d83d2fbd88c710ad1908233" +sha256 = "7254e45867fe993196b058d607bc2be98e45132b688619f818da657477604738" diff --git a/packaging/fedora/44/package-gate.py b/packaging/fedora/44/package-gate.py index 9b462e6..763b661 100644 --- a/packaging/fedora/44/package-gate.py +++ b/packaging/fedora/44/package-gate.py @@ -26,7 +26,7 @@ RECIPES = {'firmware': ('intel-npu-stack-firmware', '1.38.0-1.intelnpu.fc44', 'noarch'), 'driver': ('intel-npu-driver', '1.38.0-1.intelnpu.fc44', 'x86_64'), 'level-zero': ('oneapi-level-zero', '1.32.0-1.intelnpu.fc44', 'x86_64'), - 'openvino': ('openvino', '2026.2.1-1.intelnpu.fc44', 'x86_64')} + 'openvino': ('openvino', '2026.2.1-2.intelnpu.fc44', 'x86_64')} def require(value, message): diff --git a/packaging/fedora/44/rpm/intel-npu-stack/check-packages.py b/packaging/fedora/44/rpm/intel-npu-stack/check-packages.py index 3ecdc83..8968fd3 100644 --- a/packaging/fedora/44/rpm/intel-npu-stack/check-packages.py +++ b/packaging/fedora/44/rpm/intel-npu-stack/check-packages.py @@ -37,16 +37,16 @@ def sha(path): and manifest.get('reboot_required') is True, 'manifest candidate/activation policy') required = { 'intel-npu-stack': { - ('intel-npu-stack-tools(x86-64)', '=', '0.2.0-3.intelnpu.fc44'), + ('intel-npu-stack-tools(x86-64)', '=', '0.2.0-4.intelnpu.fc44'), ('intel-npu-driver(x86-64)', '=', '1.38.0-1.intelnpu.fc44'), ('intel-npu-stack-firmware', '=', '1.38.0-1.intelnpu.fc44'), ('oneapi-level-zero(x86-64)', '=', '1.32.0-1.intelnpu.fc44'), - ('openvino(x86-64)', '=', '2026.2.1-1.intelnpu.fc44'), - ('openvino-plugins(x86-64)', '=', '2026.2.1-1.intelnpu.fc44'), - ('intel-npu-compiler(x86-64)', '=', '2026.2.1-1.intelnpu.fc44'), + ('openvino(x86-64)', '=', '2026.2.1-2.intelnpu.fc44'), + ('openvino-plugins(x86-64)', '=', '2026.2.1-2.intelnpu.fc44'), + ('intel-npu-compiler(x86-64)', '=', '2026.2.1-2.intelnpu.fc44'), }, 'intel-npu-stack-tools': { - ('openvino(x86-64)', '=', '2026.2.1-1.intelnpu.fc44'), + ('openvino(x86-64)', '=', '2026.2.1-2.intelnpu.fc44'), ('oneapi-level-zero(x86-64)', '=', '1.32.0-1.intelnpu.fc44'), }, } @@ -69,7 +69,7 @@ def sha(path): require(name in required and name not in packages, 'exact two distinct package identities') packages.add(name) expected_arch = 'noarch' if name == 'intel-npu-stack' else 'x86_64' - require(nevr == '0:0.2.0-3.intelnpu.fc44' and arch == expected_arch and algorithm == '8', 'RPM version/arch/SHA256') + require(nevr == '0:0.2.0-4.intelnpu.fc44' and arch == expected_arch and algorithm == '8', 'RPM version/arch/SHA256') for option in ['--scripts', '--triggers', '--filetriggers']: require(not query(rpm, option).strip(), 'script-free package: ' + name) relations = set() diff --git a/packaging/fedora/44/rpm/intel-npu-stack/intel-npu-stack-tools.spec b/packaging/fedora/44/rpm/intel-npu-stack/intel-npu-stack-tools.spec index 7863904..3c69269 100644 --- a/packaging/fedora/44/rpm/intel-npu-stack/intel-npu-stack-tools.spec +++ b/packaging/fedora/44/rpm/intel-npu-stack/intel-npu-stack-tools.spec @@ -5,7 +5,7 @@ Name: intel-npu-stack-tools Version: 0.2.0 -Release: 3.intelnpu.fc44 +Release: 4.intelnpu.fc44 Summary: Read-only Intel NPU stack status and diagnostic tools License: Apache-2.0 AND Artistic-2.0 AND BSD-3-Clause AND ISC AND MIT AND MPL-2.0 AND Unicode-3.0 AND (Apache-2.0 WITH LLVM-exception) Source0: intel-npu-stack-0.1.0.tar @@ -22,11 +22,11 @@ BuildRequires: gcc-c++ = 16.2.1-2.fc44 BuildRequires: ninja-build = 1.13.2-2.fc44 BuildRequires: python3 = 3.14.7-1.fc44 BuildRequires: oneapi-level-zero-devel = 1.28.6-1.fc44 -BuildRequires: openvino-devel = 2026.2.1-1.intelnpu.fc44 +BuildRequires: openvino-devel = 2026.2.1-2.intelnpu.fc44 BuildRequires: util-linux-core = 2.41.5-1.fc44 Requires: oneapi-level-zero%{?_isa} = 1.32.0-1.intelnpu.fc44 -Requires: openvino%{?_isa} = 2026.2.1-1.intelnpu.fc44 +Requires: openvino%{?_isa} = 2026.2.1-2.intelnpu.fc44 %description Read-only status CLI, isolated native probes, documentation and a manifest @@ -41,9 +41,9 @@ Requires: intel-npu-stack-tools(x86-64) = %{version}-%{release} Requires: intel-npu-driver(x86-64) = 1.38.0-1.intelnpu.fc44 Requires: intel-npu-stack-firmware = 1.38.0-1.intelnpu.fc44 Requires: oneapi-level-zero(x86-64) = 1.32.0-1.intelnpu.fc44 -Requires: openvino(x86-64) = 2026.2.1-1.intelnpu.fc44 -Requires: openvino-plugins(x86-64) = 2026.2.1-1.intelnpu.fc44 -Requires: intel-npu-compiler(x86-64) = 2026.2.1-1.intelnpu.fc44 +Requires: openvino(x86-64) = 2026.2.1-2.intelnpu.fc44 +Requires: openvino-plugins(x86-64) = 2026.2.1-2.intelnpu.fc44 +Requires: intel-npu-compiler(x86-64) = 2026.2.1-2.intelnpu.fc44 %description -n intel-npu-stack Metadata-only package selecting the exact candidate provider versions. @@ -104,6 +104,11 @@ ctest --test-dir %{__cmake_builddir} --output-on-failure --no-tests=error %{_datadir}/intel-npu-stack/installed-manifest.toml %changelog +* Mon Oct 26 2026 Wisbendji Fimerlus - 0.2.0-4.intelnpu.fc44 +- Bind the candidate tools and metapackage to the reproducible OpenVINO + 2026.2.1-2 provider set with the LP-efficiency-core scheduling correction. +- Refresh the embedded candidate manifest; keep the CLI workspace version + and unqualified candidate status unchanged. * Tue Oct 06 2026 Wisbendji Fimerlus - 0.2.0-3.intelnpu.fc44 - Move the tools and metapackage to 0.2.0-3 on the 2026.2.1-1 provider set: the openvino 2026.2.1-1 rebuild whose compiler subpackage pins the 1.38.0 diff --git a/packaging/fedora/44/rpm/intel-npu-stack/test-package-contract.py b/packaging/fedora/44/rpm/intel-npu-stack/test-package-contract.py index a6de2bb..8a935fb 100644 --- a/packaging/fedora/44/rpm/intel-npu-stack/test-package-contract.py +++ b/packaging/fedora/44/rpm/intel-npu-stack/test-package-contract.py @@ -37,23 +37,23 @@ def case(mutation): spec.write_text('''%global debug_package %{nil} Name: intel-npu-stack-tools Version: 0.2.0 -Release: 3.intelnpu.fc44 +Release: 4.intelnpu.fc44 Summary: Contract fixture License: Apache-2.0 -Requires: openvino(x86-64) = 2026.2.1-1.intelnpu.fc44 +Requires: openvino(x86-64) = 2026.2.1-2.intelnpu.fc44 Requires: oneapi-level-zero(x86-64) = 1.32.0-1.intelnpu.fc44 %description Tool fixture. %package -n intel-npu-stack Summary: Metadata fixture BuildArch: noarch -Requires: intel-npu-stack-tools(x86-64) = 0.2.0-3.intelnpu.fc44 +Requires: intel-npu-stack-tools(x86-64) = 0.2.0-4.intelnpu.fc44 Requires: intel-npu-driver(x86-64) = ''' + requirement + '''-1.intelnpu.fc44 Requires: intel-npu-stack-firmware = 1.38.0-1.intelnpu.fc44 Requires: oneapi-level-zero(x86-64) = 1.32.0-1.intelnpu.fc44 -Requires: openvino(x86-64) = 2026.2.1-1.intelnpu.fc44 -Requires: openvino-plugins(x86-64) = 2026.2.1-1.intelnpu.fc44 -Requires: intel-npu-compiler(x86-64) = 2026.2.1-1.intelnpu.fc44 +Requires: openvino(x86-64) = 2026.2.1-2.intelnpu.fc44 +Requires: openvino-plugins(x86-64) = 2026.2.1-2.intelnpu.fc44 +Requires: intel-npu-compiler(x86-64) = 2026.2.1-2.intelnpu.fc44 %description -n intel-npu-stack Metadata fixture. %install diff --git a/packaging/fedora/44/rpm/openvino/SOURCES.md b/packaging/fedora/44/rpm/openvino/SOURCES.md index d574b76..21b6a24 100644 --- a/packaging/fedora/44/rpm/openvino/SOURCES.md +++ b/packaging/fedora/44/rpm/openvino/SOURCES.md @@ -285,6 +285,37 @@ behavior unchanged). The same defect is present in `npu_ud_2026_28_rc1` and `check-unbounded-reshape-guard.py` runs after `%prep` and refuses the unguarded spelling in the prepared source. +Patch 0016 schedules LP efficiency cores in the shared stream configuration. +With a process affinity mask holding only LP efficiency cores (Lunar Lake +`taskset -c 4-7` and `4,5`), `update_executor_config()` omitted +`LP_EFFICIENT_CORE_PROC` from its counts and allocation types, produced an +empty streams table and dereferenced element zero: the GPU plugin's +`compile_model` aborts before any inference. Reported upstream as openvino +issue 39088. The patch counts and allocates LP cores, selects the largest +feasible homogeneous stream width across core kinds and NUMA nodes, skips +unused pools too small for that width, scopes zero-count contribution rows +to their ALL_PROC header, and raises a clear exception +instead of reading an empty table. Precomputed streams tables are unchanged. +No-LP behavior is preserved except for the intended correction to mixed-stream +contribution accounting. Regression tests cover requested stream widths, +unused small pools, reservation, pinning and default configurations. +Generated unpinned `ECORE_ONLY` streams use one efficient core kind per stream, +since the existing arena interface cannot represent an E/LP union. A single +LP contribution becomes a typed LP row with its NUMA/socket locality retained. +Pinned mixed streams keep observer-based binding. Singleton TBB mapping also +handles the ordered `[LP, E]` pair only when the original table contains both +efficient kinds and no P/HT cores, without +assuming contiguous type IDs. This does not enable a new TBB union mode or +change precomputed-table contents. Physical enforcement of the core-type hint +depends on TBB topology support; process-affinity GPU tests do not prove it. +As with the existing mapping, OpenVINO and TBB must initialize against a +stable process affinity; changing it between their cached snapshots is not +covered by this backport. +Upstream acceptance is open; drop the patch when an upstream release carries +the fix. +`check-lp-ecore-executor-guard.py` runs after `%prep` and requires the +LP-aware scheduling in the prepared source. + The GPU component also installs its pinned `kernel_selector/cache/cache.json` tuning data beside the plugin. The Linux kernel selector looks up that exact path. `openvino-plugins` owns it and the staged-layout check requires it; the diff --git a/packaging/fedora/44/rpm/openvino/check-lp-ecore-executor-guard.py b/packaging/fedora/44/rpm/openvino/check-lp-ecore-executor-guard.py new file mode 100644 index 0000000..16e3371 --- /dev/null +++ b/packaging/fedora/44/rpm/openvino/check-lp-ecore-executor-guard.py @@ -0,0 +1,68 @@ +#!/usr/bin/python3 +# SPDX-License-Identifier: Apache-2.0 +"""Require LP-efficiency-core scheduling in the prepared OpenVINO source.""" +from pathlib import Path +import sys + +root = Path(sys.argv[1]).resolve(strict=True) +source = root / 'src/inference/src/dev/threading/istreams_executor.cpp' +text = source.read_text(encoding='utf-8') + +unguarded = 'core_types = {MAIN_CORE_PROC, EFFICIENT_CORE_PROC, HYPER_THREADING_PROC};' +required = { + 'std::vector core_types{MAIN_CORE_PROC, EFFICIENT_CORE_PROC, LP_EFFICIENT_CORE_PROC, HYPER_THREADING_PROC};': 1, + 'core_types = {EFFICIENT_CORE_PROC, LP_EFFICIENT_CORE_PROC};': 1, + 'proc_type_table[0][LP_EFFICIENT_CORE_PROC] > 0 ? LP_EFFICIENT_CORE_PROC': 1, + 'OPENVINO_ASSERT(!_streams_info_table.empty(),': 1, + 'if (mixed_stream) {': 2, + 'proc_type_table[0][EFFICIENT_CORE_PROC] + proc_type_table[0][LP_EFFICIENT_CORE_PROC]': 2, + 'if (proc_type_table[0][LP_EFFICIENT_CORE_PROC] > 0 && homogeneous_streams)': 1, + '_streams > 1 || (_thread_preferred_core_type == ov::hint::SchedulingCoreType::ECORE_ONLY && !_cpu_pinning);': 1, + '!homogeneous_streams && _streams == 1 &&': 1, + 'while (_threads_per_stream > 1)': 1, + 'if (proc_type_table[0][LP_EFFICIENT_CORE_PROC] > 0 && homogeneous_streams &&\n' + ' _threads_per_stream > proc_type_table[i][j]) {\n' + ' continue;\n' + ' }': 1, + 'streams_num += proc_type_table[i][type] / _threads_per_stream;': 1, + 'const auto num_cores = proc_type_table[0][MAIN_CORE_PROC] + proc_type_table[0][EFFICIENT_CORE_PROC] +\n' + ' proc_type_table[0][LP_EFFICIENT_CORE_PROC];': 1, + '_streams_info_table[0][PROC_TYPE] = LP_EFFICIENT_CORE_PROC;': 1, + '_streams_info_table[0][STREAM_NUMA_NODE_ID] = _streams_info_table[1][STREAM_NUMA_NODE_ID];': 1, + '_streams_info_table[0][STREAM_SOCKET_ID] = _streams_info_table[1][STREAM_SOCKET_ID];': 1, +} +requirements = { + 'src/inference/src/dev/threading/istreams_executor.cpp': required, + 'src/inference/src/dev/threading/cpu_streams_executor.cpp': { + 'const auto proc_types = get_org_proc_type_table();': 1, + 'get_tbb_core_type(core_type, core_types, proc_types);': 1, + }, + 'src/inference/src/dev/threading/cpu_streams_executor_internal.cpp': { + 'int get_tbb_core_type(int proc_type,': 1, + 'core_types.size() == 2 && !proc_type_table.empty() &&': 1, + 'proc_type_table[0][EFFICIENT_CORE_PROC] > 0 && proc_type_table[0][LP_EFFICIENT_CORE_PROC] > 0 &&': 1, + 'proc_type_table[0][MAIN_CORE_PROC] == 0 && proc_type_table[0][HYPER_THREADING_PROC] == 0': 1, + }, + 'src/inference/dev_api/openvino/runtime/threading/cpu_streams_executor_internal.hpp': { + 'int get_tbb_core_type(int proc_type,': 1, + 'const std::vector>& proc_type_table);': 1, + }, +} + +if unguarded in text: + raise SystemExit(f'check-lp-ecore-executor-guard: LP-unaware core-type list present in {source}') +if '_threads_per_stream = std::min(_threads_per_stream, proc_type_table[i][type]);' in text: + raise SystemExit(f'check-lp-ecore-executor-guard: unused small pools still reduce stream width in {source}') +for relative, markers in requirements.items(): + source = root / relative + try: + text = source.read_text(encoding='utf-8') + except OSError as error: + raise SystemExit(f'check-lp-ecore-executor-guard: cannot read {source}: {error}') from error + for spelling, count in markers.items(): + if text.count(spelling) != count: + raise SystemExit( + f'check-lp-ecore-executor-guard: expected {count} occurrence(s) of {spelling!r} in {source}, ' + f'found {text.count(spelling)}' + ) +print('check-lp-ecore-executor-guard: ok') diff --git a/packaging/fedora/44/rpm/openvino/openvino.spec b/packaging/fedora/44/rpm/openvino/openvino.spec index 4bf3062..92f4b02 100644 --- a/packaging/fedora/44/rpm/openvino/openvino.spec +++ b/packaging/fedora/44/rpm/openvino/openvino.spec @@ -22,7 +22,7 @@ package or when debugging this package.\ Name: openvino Version: 2026.2.1 -Release: 1.intelnpu.fc44 +Release: 2.intelnpu.fc44 Summary: Toolkit for optimizing and deploying AI inference License: Apache-2.0 AND MIT AND BSL-1.0 AND HPND AND BSD-3-Clause AND (GPL-2.0-only OR BSD-3-Clause) @@ -77,6 +77,8 @@ Source46: provider-license-evidence.tar Source47: json-3.12.0-LICENSE.MIT Source48: 0015-check-unbounded-reshape-input-bounds.patch Source49: check-unbounded-reshape-guard.py +Source50: 0016-schedule-lp-efficiency-cores.patch +Source51: check-lp-ecore-executor-guard.py ExclusiveArch: x86_64 @@ -251,6 +253,8 @@ mv intel-npu-nn-cost-model thirdparty/npu-compiler/thirdparty/vpucostmodel /usr/bin/patch --batch --forward --fuzz=0 -p1 \ -d thirdparty/npu-compiler < %{SOURCE48} /usr/bin/python3 %{SOURCE49} "$PWD" +/usr/bin/patch --batch --forward --fuzz=0 -p1 < %{SOURCE50} +/usr/bin/python3 %{SOURCE51} "$PWD" /usr/bin/python3 %{SOURCE44} --kind openvino \ --source "$PWD" --archives "$(dirname -- '%{SOURCE0}')" --spec %{_specdir}/openvino.spec \ @@ -438,6 +442,11 @@ cp -a ../provider-notices/openvino ../provider-notices/intel-npu-compiler \ %{_libdir}/libopenvino_tensorflow_lite_frontend.so.%{so_ver} %changelog +* Sat Oct 24 2026 Intel NPU Stack maintainers - 2026.2.1-2.intelnpu.fc44 +- Add 0016 to schedule LP efficiency cores in the shared stream config, so + GPU compile_model no longer aborts when the process affinity leaves only + LP efficiency cores (reported upstream as openvino issue 39088). +- Preserve feasible stream widths when unused core pools are smaller. * Wed Sep 30 2026 Intel NPU Stack maintainers - 2026.2.1-1.intelnpu.fc44 - OpenVINO 2026.2.1 (NPU plugin shared Level Zero command-queue priority fix) and the NPU compiler from npu_ud_2026_28_rc2. Add 0015 to reject an diff --git a/packaging/fedora/44/rpm/openvino/patches/0016-schedule-lp-efficiency-cores.patch b/packaging/fedora/44/rpm/openvino/patches/0016-schedule-lp-efficiency-cores.patch new file mode 100644 index 0000000..d829990 --- /dev/null +++ b/packaging/fedora/44/rpm/openvino/patches/0016-schedule-lp-efficiency-cores.patch @@ -0,0 +1,895 @@ +Subject: [PATCH] Schedule LP efficiency cores in the shared stream config + +When a process affinity mask leaves only LP efficiency cores, +update_executor_config() omitted LP_EFFICIENT_CORE_PROC from the little-core +count and allocation types. With more than one requested stream, the table +could remain empty and its first-element access aborted GPU compilation. +Reported upstream as openvinotoolkit/openvino issue 39088. + +Count LP cores as little cores, allocate them independently for ANY_CORE and +ECORE_ONLY, and keep PCORE_ONLY free of LP cores when P cores are available. +Choose the largest requested stream width that the eligible per-core-kind, +per-NUMA-node pools can supply. Skip smaller unused pools rather than reducing +otherwise feasible streams or emitting partial homogeneous rows. This also +preserves explicit P-core requests when an unused SMT pool is smaller. + +Contribution rows after an ALL_PROC header carry zero streams. The zero-stream +helper selects LP cores before hyperthreads, and an empty generated table +raises a clear exception instead of reading element zero. Precomputed tables +are unchanged. No-LP behavior is preserved except for the intended correction +to mixed-stream contribution accounting. + +Keep generated unpinned ECORE_ONLY streams homogeneous: the existing arena +interface cannot express an E/LP union. A single LP contribution becomes a +typed row with its original locality. Correct singleton TBB type selection +for the ordered [LP, E] pair only when the original table contains both +efficient kinds and no P/HT cores; preserve existing no-LP, P-present, +three-type and automatic mappings. Pinned mixed streams retain +their observer-based binding. This does not add a new TBB union mode. + +Native regression tests cover LP-only preferences, reservation, pinning, +fragmented pools, NUMA, default factories, arena routing, noncontiguous TBB +type IDs and precomputed tables. The source +guard runs after %prep; it does not replace these behavioral tests. +Upstream acceptance remains open. Drop this patch when a release carries the +corresponding fix. + +--- +diff --git a/src/inference/src/dev/threading/istreams_executor.cpp b/src/inference/src/dev/threading/istreams_executor.cpp +--- a/src/inference/src/dev/threading/istreams_executor.cpp ++++ b/src/inference/src/dev/threading/istreams_executor.cpp +@@ -95,7 +95,8 @@ + if (proc_type_table.empty()) { + return 1; + } +- const auto num_cores = proc_type_table[0][MAIN_CORE_PROC] + proc_type_table[0][EFFICIENT_CORE_PROC]; ++ const auto num_cores = proc_type_table[0][MAIN_CORE_PROC] + proc_type_table[0][EFFICIENT_CORE_PROC] + ++ proc_type_table[0][LP_EFFICIENT_CORE_PROC]; + if (0 == num_cores % 4) + return std::max(4, num_cores / 4); + else if (0 == num_cores % 5) +@@ -116,20 +117,22 @@ + } + + int num_cores = proc_type_table[0][ALL_PROC]; ++ const auto little_cores = proc_type_table[0][EFFICIENT_CORE_PROC] + proc_type_table[0][LP_EFFICIENT_CORE_PROC]; + +- if (proc_type_table[0][EFFICIENT_CORE_PROC] > 0 && proc_type_table[0][MAIN_CORE_PROC] > 0) { ++ if (little_cores > 0 && proc_type_table[0][MAIN_CORE_PROC] > 0) { + if (streamConfig._thread_preferred_core_type == ov::hint::SchedulingCoreType::ANY_CORE) { + num_cores = proc_type_table[0][ALL_PROC]; + } else if (streamConfig._thread_preferred_core_type == ov::hint::SchedulingCoreType::PCORE_ONLY) { + num_cores = proc_type_table[0][MAIN_CORE_PROC]; + } else if (streamConfig._thread_preferred_core_type == ov::hint::SchedulingCoreType::ECORE_ONLY) { +- num_cores = proc_type_table[0][EFFICIENT_CORE_PROC]; ++ num_cores = little_cores; + } + } + + const auto threads = streamConfig._threads ? streamConfig._threads : num_cores; + int threads_per_stream = streamConfig._streams ? std::max(1, threads / streamConfig._streams) : threads; +- if (proc_type_table[0][EFFICIENT_CORE_PROC] > 0 && proc_type_table[0][MAIN_CORE_PROC] > 0 && ++ if (proc_type_table[0][LP_EFFICIENT_CORE_PROC] == 0 && proc_type_table[0][EFFICIENT_CORE_PROC] > 0 && ++ proc_type_table[0][MAIN_CORE_PROC] > 0 && + streamConfig._thread_preferred_core_type == ov::hint::SchedulingCoreType::ANY_CORE) { + if (streamConfig._streams > 1) { + threads_per_stream = +@@ -194,7 +197,8 @@ + + const auto total_num_cores = proc_type_table[0][ALL_PROC]; + const auto total_num_big_cores = proc_type_table[0][MAIN_CORE_PROC] + proc_type_table[0][HYPER_THREADING_PROC]; +- const auto total_num_little_cores = proc_type_table[0][EFFICIENT_CORE_PROC]; ++ const auto total_num_little_cores = ++ proc_type_table[0][EFFICIENT_CORE_PROC] + proc_type_table[0][LP_EFFICIENT_CORE_PROC]; + + if ((total_num_little_cores == 0 && _thread_preferred_core_type == ov::hint::SchedulingCoreType::ECORE_ONLY) || + (total_num_big_cores == 0 && _thread_preferred_core_type == ov::hint::SchedulingCoreType::PCORE_ONLY) || +@@ -225,21 +229,54 @@ + return; + } + ++ const size_t start = proc_type_table.size() > 1 ? 1 : 0; ++ std::vector core_types{MAIN_CORE_PROC, EFFICIENT_CORE_PROC, LP_EFFICIENT_CORE_PROC, HYPER_THREADING_PROC}; ++ if (_thread_preferred_core_type == ov::hint::SchedulingCoreType::PCORE_ONLY) { ++ core_types = {MAIN_CORE_PROC, HYPER_THREADING_PROC}; ++ } else if (_thread_preferred_core_type == ov::hint::SchedulingCoreType::ECORE_ONLY) { ++ core_types = {EFFICIENT_CORE_PROC, LP_EFFICIENT_CORE_PROC}; ++ } ++ // The unpinned arena interface selects one core kind, not an E/LP ++ // union. Keep an ECORE_ONLY stream representable by that interface. ++ const bool homogeneous_streams = ++ _streams > 1 || (_thread_preferred_core_type == ov::hint::SchedulingCoreType::ECORE_ONLY && !_cpu_pinning); ++ if (proc_type_table[0][LP_EFFICIENT_CORE_PROC] > 0 && homogeneous_streams) { ++ // A typed stream must fit within one core kind and one NUMA node. ++ // Keep the requested width when the usable pools can supply it; ++ // an unused smaller pool must not reduce every stream's width. ++ while (_threads_per_stream > 1) { ++ int streams_num = 0; ++ for (int type : core_types) { ++ for (size_t i = start; i < proc_type_table.size(); ++i) { ++ streams_num += proc_type_table[i][type] / _threads_per_stream; ++ } ++ } ++ if (streams_num >= _streams) { ++ break; ++ } ++ --_threads_per_stream; ++ } ++ } ++ + // create stream_info_table based on core type + std::vector stream_info(CPU_STREAMS_TABLE_SIZE, 0); + stream_info[THREADS_PER_STREAM] = _threads_per_stream; + stream_info[STREAM_NUMA_NODE_ID] = 0; + stream_info[STREAM_SOCKET_ID] = 0; + int cur_threads = _streams * _threads_per_stream; +- if (_thread_preferred_core_type == ov::hint::SchedulingCoreType::ECORE_ONLY) { ++ if (_thread_preferred_core_type == ov::hint::SchedulingCoreType::ECORE_ONLY && ++ proc_type_table[0][LP_EFFICIENT_CORE_PROC] == 0) { + stream_info[PROC_TYPE] = EFFICIENT_CORE_PROC; + stream_info[NUMBER_OF_STREAMS] = _streams; + _streams_info_table.push_back(std::move(stream_info)); + } else { +- int start = proc_type_table.size() > 1 ? 1 : 0; +- std::vector core_types; + // Using cores crossed sockets or hyper threads when streams = 1 +- if (_streams == 1 && _threads_per_stream > proc_type_table[start][ov::MAIN_CORE_PROC]) { ++ const auto first_core_type = _thread_preferred_core_type == ov::hint::SchedulingCoreType::ECORE_ONLY ++ ? EFFICIENT_CORE_PROC ++ : MAIN_CORE_PROC; ++ const bool mixed_stream = ++ !homogeneous_streams && _streams == 1 && _threads_per_stream > proc_type_table[start][first_core_type]; ++ if (mixed_stream) { + stream_info[NUMBER_OF_STREAMS] = _streams; + stream_info[PROC_TYPE] = ALL_PROC; + stream_info[STREAM_NUMA_NODE_ID] = proc_type_table.size() > 1 ? -1 : 0; +@@ -247,16 +284,19 @@ + _streams_info_table.push_back(stream_info); + stream_info[NUMBER_OF_STREAMS] = 0; + } +- if (_thread_preferred_core_type == ov::hint::SchedulingCoreType::PCORE_ONLY && +- proc_type_table[0][EFFICIENT_CORE_PROC] > 0) { +- core_types = {MAIN_CORE_PROC, HYPER_THREADING_PROC}; +- } else { +- core_types = {MAIN_CORE_PROC, EFFICIENT_CORE_PROC, HYPER_THREADING_PROC}; +- } + for (int j : core_types) { + for (size_t i = start; i < proc_type_table.size(); i++) { + if (proc_type_table[i][j] > 0 && cur_threads > 0) { +- if (_threads_per_stream > proc_type_table[i][j]) { ++ if (proc_type_table[0][LP_EFFICIENT_CORE_PROC] > 0 && homogeneous_streams && ++ _threads_per_stream > proc_type_table[i][j]) { ++ continue; ++ } ++ if (mixed_stream || _threads_per_stream > proc_type_table[i][j]) { ++ if (mixed_stream) { ++ // Rows after an ALL_PROC header contribute to ++ // that stream instead of naming new streams. ++ stream_info[NUMBER_OF_STREAMS] = 0; ++ } + stream_info[THREADS_PER_STREAM] = std::min(proc_type_table[i][j], cur_threads); + cur_threads -= stream_info[THREADS_PER_STREAM]; + } else { +@@ -272,8 +312,23 @@ + } + } + } ++ ++ if (_streams_info_table.size() == 2 && _streams_info_table[0][PROC_TYPE] == ALL_PROC && ++ _streams_info_table[0][NUMBER_OF_STREAMS] == 1 && ++ _streams_info_table[1][PROC_TYPE] == LP_EFFICIENT_CORE_PROC && ++ _streams_info_table[1][NUMBER_OF_STREAMS] == 0 && ++ _streams_info_table[0][THREADS_PER_STREAM] == _streams_info_table[1][THREADS_PER_STREAM]) { ++ // A single LP pool needs no mixed row; keep its arena restriction ++ // and locality even when explicit thread pinning is disabled. ++ _streams_info_table[0][PROC_TYPE] = LP_EFFICIENT_CORE_PROC; ++ _streams_info_table[0][STREAM_NUMA_NODE_ID] = _streams_info_table[1][STREAM_NUMA_NODE_ID]; ++ _streams_info_table[0][STREAM_SOCKET_ID] = _streams_info_table[1][STREAM_SOCKET_ID]; ++ _streams_info_table.pop_back(); ++ } + } + ++ OPENVINO_ASSERT(!_streams_info_table.empty(), "No streams could be configured for the available CPU resources."); ++ + if (_cpu_pinning || _cpu_reservation) { + reserve_available_cpus(_streams_info_table, _stream_processor_ids, _cpu_reservation ? CPU_USED : NOT_USED); + } +@@ -342,9 +397,10 @@ + int socket_id = 0; + + if (proc_type_table.size() > 0) { +- core_type = proc_type_table[0][MAIN_CORE_PROC] > 0 +- ? MAIN_CORE_PROC +- : (proc_type_table[0][EFFICIENT_CORE_PROC] > 0 ? EFFICIENT_CORE_PROC : HYPER_THREADING_PROC); ++ core_type = proc_type_table[0][MAIN_CORE_PROC] > 0 ? MAIN_CORE_PROC ++ : proc_type_table[0][EFFICIENT_CORE_PROC] > 0 ? EFFICIENT_CORE_PROC ++ : proc_type_table[0][LP_EFFICIENT_CORE_PROC] > 0 ? LP_EFFICIENT_CORE_PROC ++ : HYPER_THREADING_PROC; + numa_id = std::max(0, proc_type_table[0][PROC_NUMA_NODE_ID]); + socket_id = std::max(0, proc_type_table[0][PROC_SOCKET_ID]); + } +diff --git a/src/inference/src/dev/threading/cpu_streams_executor.cpp b/src/inference/src/dev/threading/cpu_streams_executor.cpp +--- a/src/inference/src/dev/threading/cpu_streams_executor.cpp ++++ b/src/inference/src/dev/threading/cpu_streams_executor.cpp +@@ -152,13 +152,8 @@ + .set_max_threads_per_core(max_threads_per_core)}); + } else if (stream_type == STREAM_WITH_CORE_TYPE) { + const auto core_types = custom::info::core_types(); +- auto real_core_type = (core_type == MAIN_CORE_PROC || core_type == HYPER_THREADING_PROC) +- ? core_types.back() +- : core_types.front(); +- // core_types=[LPECore, Ecore, Pcore] +- if (core_type == EFFICIENT_CORE_PROC && core_types.size() >= MIN_CORE_TYPES_FOR_PTL) { +- real_core_type = *(core_types.end() - MIN_CORE_TYPES_FOR_PTL + 1); +- } ++ const auto proc_types = get_org_proc_type_table(); ++ const auto real_core_type = get_tbb_core_type(core_type, core_types, proc_types); + _taskArena.reset(new custom::task_arena{custom::task_arena::constraints{} + .set_core_type(real_core_type) + .set_max_concurrency(concurrency) +diff --git a/src/inference/src/dev/threading/cpu_streams_executor_internal.cpp b/src/inference/src/dev/threading/cpu_streams_executor_internal.cpp +--- a/src/inference/src/dev/threading/cpu_streams_executor_internal.cpp ++++ b/src/inference/src/dev/threading/cpu_streams_executor_internal.cpp +@@ -81,6 +81,22 @@ + } + } + ++int get_tbb_core_type(int proc_type, ++ const std::vector& core_types, ++ const std::vector>& proc_type_table) { ++ auto real_core_type = ++ (proc_type == MAIN_CORE_PROC || proc_type == HYPER_THREADING_PROC) ? core_types.back() : core_types.front(); ++ if (proc_type == EFFICIENT_CORE_PROC && core_types.size() >= 3) { ++ real_core_type = *(core_types.end() - 2); ++ } else if (proc_type == EFFICIENT_CORE_PROC && core_types.size() == 2 && !proc_type_table.empty() && ++ proc_type_table[0][EFFICIENT_CORE_PROC] > 0 && proc_type_table[0][LP_EFFICIENT_CORE_PROC] > 0 && ++ proc_type_table[0][MAIN_CORE_PROC] == 0 && proc_type_table[0][HYPER_THREADING_PROC] == 0) { ++ // Without P cores the ordered pair is [LP, E], not [E, P]. ++ real_core_type = core_types.back(); ++ } ++ return real_core_type; ++} ++ + void reserve_cpu_by_streams_info(const std::vector> _streams_info_table, + const int _numa_nodes, + std::vector>& _cpu_mapping_table, +diff --git a/src/inference/dev_api/openvino/runtime/threading/cpu_streams_executor_internal.hpp b/src/inference/dev_api/openvino/runtime/threading/cpu_streams_executor_internal.hpp +--- a/src/inference/dev_api/openvino/runtime/threading/cpu_streams_executor_internal.hpp ++++ b/src/inference/dev_api/openvino/runtime/threading/cpu_streams_executor_internal.hpp +@@ -45,6 +45,12 @@ + int& socket_id, + int& max_threads_per_core); + ++// Map OpenVINO's processor kind to the ordered, nonempty type list returned ++// by oneTBB. IDs are runtime values, not necessarily contiguous integers. ++int get_tbb_core_type(int proc_type, ++ const std::vector& core_types, ++ const std::vector>& proc_type_table); ++ + /** + * @brief Reserve cpu resource by streams info + * @param[in] _streams_info_table streams info table +@@ -74,4 +80,4 @@ + std::vector>& _proc_type_table); + + } // namespace threading +-} // namespace ov +\ No newline at end of file ++} // namespace ov +diff --git a/src/inference/tests/unit/executor_config_test.cpp b/src/inference/tests/unit/executor_config_test.cpp +--- a/src/inference/tests/unit/executor_config_test.cpp ++++ b/src/inference/tests/unit/executor_config_test.cpp +@@ -4,7 +4,10 @@ + + #include + ++#include ++ + #include "common_test_utils/test_common.hpp" ++#include "openvino/runtime/threading/cpu_streams_executor_internal.hpp" + #include "openvino/runtime/threading/cpu_streams_info.hpp" + #include "openvino/runtime/threading/istreams_executor.hpp" + #include "os/cpu_map_info.hpp" +@@ -17,6 +20,517 @@ + + #if defined(__linux__) || defined(_WIN32) + ++class LPExecutorConfigTest : public ov::test::TestsCommon { ++protected: ++ using Table = std::vector>; ++ using CoreType = ov::hint::SchedulingCoreType; ++ CPU& cpu = cpu_info(); ++ const Table saved_proc = cpu._proc_type_table; ++ const Table saved_org_proc = cpu._org_proc_type_table; ++ const Table saved_mapping = cpu._cpu_mapping_table; ++ const int saved_numa_nodes = cpu._numa_nodes; ++ const int saved_sockets = cpu._sockets; ++ ++ void TearDown() override { ++ cpu._proc_type_table = saved_proc; ++ cpu._org_proc_type_table = saved_org_proc; ++ cpu._cpu_mapping_table = saved_mapping; ++ cpu._numa_nodes = saved_numa_nodes; ++ cpu._sockets = saved_sockets; ++ } ++ ++ void set_topology(int main, int efficient, int lp, int hyper = 0) { ++ cpu._proc_type_table = {{main + efficient + lp + hyper, main, efficient, lp, hyper, 0, 0}}; ++ cpu._org_proc_type_table = cpu._proc_type_table; ++ cpu._cpu_mapping_table.clear(); ++ cpu._numa_nodes = cpu._sockets = 1; ++ for (int type = MAIN_CORE_PROC; type <= HYPER_THREADING_PROC; ++type) { ++ for (int n = 0; n < cpu._proc_type_table[0][type]; ++n) { ++ const int core = static_cast(cpu._cpu_mapping_table.size()); ++ const int physical_core = type == HYPER_THREADING_PROC ? n : core; ++ cpu._cpu_mapping_table.push_back({core + 4, 0, 0, physical_core, type, physical_core, NOT_USED}); ++ } ++ } ++ } ++ ++ void check_config(const IStreamsExecutor::Config& config, ++ const Table& expected_ids, ++ bool reservation = true, ++ bool pinning = true) { ++ EXPECT_EQ(reservation, config.get_cpu_reservation()); ++ EXPECT_EQ(pinning, config.get_cpu_pinning()); ++ const auto table = config.get_streams_info_table(); ++ ASSERT_FALSE(table.empty()); ++ std::vector typed_threads(HYPER_THREADING_PROC + 1, 0); ++ int streams = 0; ++ int threads = 0; ++ bool all_proc = false; ++ for (size_t i = 0; i < table.size(); ++i) { ++ const auto& row = table[i]; ++ ASSERT_EQ(CPU_STREAMS_TABLE_SIZE, row.size()); ++ ASSERT_GE(row[PROC_TYPE], ALL_PROC); ++ ASSERT_LE(row[PROC_TYPE], HYPER_THREADING_PROC); ++ EXPECT_GT(row[THREADS_PER_STREAM], 0); ++ EXPECT_GE(row[NUMBER_OF_STREAMS], 0); ++ if (row[NUMBER_OF_STREAMS] > 0) { ++ streams += row[NUMBER_OF_STREAMS]; ++ threads += row[NUMBER_OF_STREAMS] * row[THREADS_PER_STREAM]; ++ all_proc = row[PROC_TYPE] == ALL_PROC; ++ } else { ++ EXPECT_TRUE(all_proc); ++ } ++ if (row[PROC_TYPE] == ALL_PROC) { ++ ASSERT_LT(i + 1, table.size()); ++ EXPECT_EQ(0, table[i + 1][NUMBER_OF_STREAMS]); ++ } else { ++ typed_threads[row[PROC_TYPE]] += std::max(1, row[NUMBER_OF_STREAMS]) * row[THREADS_PER_STREAM]; ++ } ++ } ++ std::vector expected_typed_threads(HYPER_THREADING_PROC + 1, 0); ++ std::vector selected_ids; ++ for (const auto& ids : expected_ids) { ++ ASSERT_FALSE(ids.empty()); ++ for (int id : ids) { ++ ASSERT_GE(id, 4); ++ ASSERT_LT(static_cast(id - 4), cpu._cpu_mapping_table.size()); ++ ++expected_typed_threads[cpu._cpu_mapping_table[id - 4][CPU_MAP_CORE_TYPE]]; ++ selected_ids.push_back(id); ++ } ++ } ++ EXPECT_EQ(expected_ids.size(), static_cast(streams)); ++ EXPECT_EQ(streams, config.get_streams()); ++ EXPECT_EQ(selected_ids.size(), static_cast(threads)); ++ EXPECT_EQ(threads, config.get_threads()); ++ EXPECT_EQ(table[0][THREADS_PER_STREAM], config.get_threads_per_stream()); ++ EXPECT_EQ(expected_typed_threads, typed_threads); ++ EXPECT_EQ(pinning || reservation ? expected_ids : Table{}, config.get_stream_processor_ids()); ++ auto remaining = cpu._org_proc_type_table; ++ if (reservation) { ++ remaining[0][ALL_PROC] -= static_cast(selected_ids.size()); ++ for (int type = MAIN_CORE_PROC; type <= HYPER_THREADING_PROC; ++type) ++ remaining[0][type] -= expected_typed_threads[type]; ++ if (remaining[0][ALL_PROC] == 0) ++ remaining[0][PROC_SOCKET_ID] = -1; ++ } ++ EXPECT_EQ(remaining, cpu._proc_type_table); ++ for (const auto& row : cpu._cpu_mapping_table) { ++ const bool selected = ++ std::find(selected_ids.begin(), selected_ids.end(), row[CPU_MAP_PROCESSOR_ID]) != selected_ids.end(); ++ EXPECT_EQ(reservation && selected ? CPU_USED : NOT_USED, row[CPU_MAP_USED_FLAG]); ++ } ++ } ++}; ++ ++TEST(TbbCoreTypeMappingTest, RegularEfficiencyTypeWithoutPerformanceCores) { ++ const std::vector> topology{{3, 0, 2, 1, 0, 0, 0}}; ++ EXPECT_EQ(17, get_tbb_core_type(EFFICIENT_CORE_PROC, {5, 17}, topology)); ++ EXPECT_EQ(5, get_tbb_core_type(LP_EFFICIENT_CORE_PROC, {5, 17}, topology)); ++} ++ ++TEST(TbbCoreTypeMappingTest, NoLPCoresKeepLegacyMappingWithoutPerformanceCores) { ++ // OpenVINO can have a narrower cached topology than TBB. No LP cores in ++ // that snapshot must leave the legacy two-type mapping unchanged. ++ EXPECT_EQ(5, get_tbb_core_type(EFFICIENT_CORE_PROC, {5, 17}, {{2, 0, 2, 0, 0, 0, 0}})); ++} ++ ++TEST(TbbCoreTypeMappingTest, PreservesExistingTwoTypeMapping) { ++ const std::vector> topology{{4, 2, 2, 0, 0, 0, 0}}; ++ EXPECT_EQ(5, get_tbb_core_type(EFFICIENT_CORE_PROC, {5, 17}, topology)); ++ EXPECT_EQ(5, get_tbb_core_type(LP_EFFICIENT_CORE_PROC, {5, 17}, topology)); ++ EXPECT_EQ(17, get_tbb_core_type(MAIN_CORE_PROC, {5, 17}, topology)); ++ EXPECT_EQ(17, get_tbb_core_type(HYPER_THREADING_PROC, {5, 17}, topology)); ++} ++ ++TEST(TbbCoreTypeMappingTest, HyperThreadsPreventEfficiencyPairMapping) { ++ EXPECT_EQ(5, get_tbb_core_type(EFFICIENT_CORE_PROC, {5, 17}, {{4, 0, 2, 1, 1, 0, 0}})); ++} ++ ++TEST(TbbCoreTypeMappingTest, PreservesExistingThreeTypeMapping) { ++ const std::vector> topology{{6, 2, 2, 2, 0, 0, 0}}; ++ EXPECT_EQ(5, get_tbb_core_type(LP_EFFICIENT_CORE_PROC, {5, 11, 17}, topology)); ++ EXPECT_EQ(11, get_tbb_core_type(EFFICIENT_CORE_PROC, {5, 11, 17}, topology)); ++ EXPECT_EQ(17, get_tbb_core_type(MAIN_CORE_PROC, {5, 11, 17}, topology)); ++} ++ ++TEST(TbbCoreTypeMappingTest, PreservesSingleAutomaticType) { ++ const std::vector> topology{{3, 0, 2, 1, 0, 0, 0}}; ++ EXPECT_EQ(-1, get_tbb_core_type(LP_EFFICIENT_CORE_PROC, {-1}, topology)); ++ EXPECT_EQ(-1, get_tbb_core_type(EFFICIENT_CORE_PROC, {-1}, topology)); ++} ++ ++class LPOnlyExecutorConfigTest ++ : public LPExecutorConfigTest, ++ public testing::WithParamInterface> {}; ++ ++TEST_P(LPOnlyExecutorConfigTest, PreservesLPResourcesAndBinding) { ++ const auto core_type = std::get<0>(GetParam()); ++ const int streams = std::get<1>(GetParam()); ++ const bool reservation = std::get<2>(GetParam()); ++ const bool pinning = std::get<3>(GetParam()); ++ set_topology(0, 0, 4); ++ IStreamsExecutor::Config config{"lp only", streams, streams == 1 ? 4 : 1, core_type, reservation, pinning}; ++ check_config(config, streams == 1 ? Table{{4, 5, 6, 7}} : Table{{4}, {5}, {6}, {7}}, reservation, pinning); ++} ++ ++INSTANTIATE_TEST_SUITE_P(smoke_LPOnlyExecutorConfig, ++ LPOnlyExecutorConfigTest, ++ testing::Combine(testing::Values(ov::hint::SchedulingCoreType::ANY_CORE, ++ ov::hint::SchedulingCoreType::ECORE_ONLY, ++ ov::hint::SchedulingCoreType::PCORE_ONLY), ++ testing::Values(1, 4, 8), ++ testing::Bool(), ++ testing::Bool())); ++ ++TEST_F(LPExecutorConfigTest, PCoreOnlyExcludesLPCores) { ++ set_topology(2, 0, 4, 2); ++ IStreamsExecutor::Config config{"pcore only", 8, 1, CoreType::PCORE_ONLY, true, true}; ++ check_config(config, {{4}, {5}, {10}, {11}}); ++} ++ ++TEST_F(LPExecutorConfigTest, PCoreOnlyIgnoresUnusedSmallHyperThreadPool) { ++ for (bool reservation : {false, true}) { ++ for (bool pinning : {false, true}) { ++ SCOPED_TRACE(reservation); ++ SCOPED_TRACE(pinning); ++ set_topology(6, 1, 2, 1); ++ IStreamsExecutor::Config config{"pcore capacity", 2, 3, CoreType::PCORE_ONLY, reservation, pinning}; ++ check_config(config, {{4, 5, 6}, {7, 8, 9}}, reservation, pinning); ++ EXPECT_EQ(3, config.get_threads_per_stream()); ++ EXPECT_EQ((Table{{2, MAIN_CORE_PROC, 3, 0, 0}}), config.get_streams_info_table()); ++ } ++ } ++} ++ ++TEST_F(LPExecutorConfigTest, DefaultPCoreOnlyKeepsFeasibleThreadCount) { ++ set_topology(6, 1, 2, 1); ++ IStreamsExecutor::Config initial{"default pcore capacity", 2, 0, CoreType::PCORE_ONLY, false, false}; ++ const auto config = IStreamsExecutor::Config::make_default_multi_threaded(initial); ++ check_config(config, {{4, 5, 6}, {7, 8, 9}}, false, false); ++ EXPECT_EQ(3, config.get_threads_per_stream()); ++ EXPECT_EQ((Table{{2, MAIN_CORE_PROC, 3, 0, 0}}), config.get_streams_info_table()); ++} ++ ++TEST_F(LPExecutorConfigTest, UnpinnedLPOnlyStreamKeepsEfficientArenaConstraint) { ++ set_topology(2, 0, 4); ++ IStreamsExecutor::Config config{"unpinned lp", 1, 4, CoreType::ECORE_ONLY, false, false}; ++ EXPECT_EQ((Table{{1, LP_EFFICIENT_CORE_PROC, 4, 0, 0}}), config.get_streams_info_table()); ++ StreamCreateType type = STREAM_WITHOUT_PARAM; ++ int concurrency = 0, core_type = 0, numa_node = 0, socket = 0, max_threads = 0; ++ get_cur_stream_info(0, ++ false, ++ cpu._org_proc_type_table, ++ config.get_streams_info_table(), ++ type, ++ concurrency, ++ core_type, ++ numa_node, ++ socket, ++ max_threads); ++ EXPECT_EQ(4, concurrency); ++ EXPECT_EQ(STREAM_WITH_CORE_TYPE, type); ++ EXPECT_EQ(LP_EFFICIENT_CORE_PROC, core_type); ++ EXPECT_FALSE(config.get_cpu_pinning()); ++ EXPECT_FALSE(config.get_cpu_reservation()); ++ EXPECT_TRUE(config.get_stream_processor_ids().empty()); ++} ++ ++TEST_F(LPExecutorConfigTest, UnpinnedMixedEfficientStreamKeepsRestrictedArena) { ++ for (bool reservation : {false, true}) { ++ set_topology(2, 2, 2); ++ IStreamsExecutor::Config config{"unpinned mixed ecore", 1, 4, CoreType::ECORE_ONLY, reservation, false}; ++ check_config(config, {{6, 7}}, reservation, false); ++ EXPECT_EQ((Table{{1, EFFICIENT_CORE_PROC, 2, 0, 0}}), config.get_streams_info_table()); ++ StreamCreateType type = STREAM_WITHOUT_PARAM; ++ int concurrency = 0, core_type = 0, numa_node = 0, socket = 0, max_threads = 0; ++ get_cur_stream_info(0, ++ false, ++ cpu._org_proc_type_table, ++ config.get_streams_info_table(), ++ type, ++ concurrency, ++ core_type, ++ numa_node, ++ socket, ++ max_threads); ++ EXPECT_EQ(2, concurrency); ++ EXPECT_EQ(STREAM_WITH_CORE_TYPE, type); ++ EXPECT_EQ(EFFICIENT_CORE_PROC, core_type); ++ } ++} ++ ++TEST_F(LPExecutorConfigTest, UnpinnedEfficientStreamUsesLargerLPPool) { ++ for (bool reservation : {false, true}) { ++ set_topology(2, 1, 6); ++ IStreamsExecutor::Config config{"unpinned large lp", 1, 4, CoreType::ECORE_ONLY, reservation, false}; ++ check_config(config, {{7, 8, 9, 10}}, reservation, false); ++ EXPECT_EQ((Table{{1, LP_EFFICIENT_CORE_PROC, 4, 0, 0}}), config.get_streams_info_table()); ++ StreamCreateType type = STREAM_WITHOUT_PARAM; ++ int concurrency = 0, core_type = 0, numa_node = 0, socket = 0, max_threads = 0; ++ get_cur_stream_info(0, ++ false, ++ cpu._org_proc_type_table, ++ config.get_streams_info_table(), ++ type, ++ concurrency, ++ core_type, ++ numa_node, ++ socket, ++ max_threads); ++ EXPECT_EQ(4, concurrency); ++ EXPECT_EQ(STREAM_WITH_CORE_TYPE, type); ++ EXPECT_EQ(LP_EFFICIENT_CORE_PROC, core_type); ++ } ++} ++ ++TEST_F(LPExecutorConfigTest, UnpinnedRegularEfficiencyStreamWithoutPerformanceCores) { ++ for (bool reservation : {false, true}) { ++ set_topology(0, 2, 1); ++ IStreamsExecutor::Config config{"unpinned regular ecore", 1, 3, CoreType::ECORE_ONLY, reservation, false}; ++ check_config(config, {{4, 5}}, reservation, false); ++ EXPECT_EQ((Table{{1, EFFICIENT_CORE_PROC, 2, 0, 0}}), config.get_streams_info_table()); ++ StreamCreateType type = STREAM_WITHOUT_PARAM; ++ int concurrency = 0, core_type = 0, numa_node = 0, socket = 0, max_threads = 0; ++ get_cur_stream_info(0, ++ false, ++ cpu._org_proc_type_table, ++ config.get_streams_info_table(), ++ type, ++ concurrency, ++ core_type, ++ numa_node, ++ socket, ++ max_threads); ++ EXPECT_EQ(2, concurrency); ++ EXPECT_EQ(STREAM_WITH_CORE_TYPE, type); ++ EXPECT_EQ(17, get_tbb_core_type(core_type, {5, 17}, cpu._org_proc_type_table)); ++ } ++} ++ ++TEST_F(LPExecutorConfigTest, UnpinnedNoLPEfficiencyStreamKeepsLegacyMapping) { ++ set_topology(0, 2, 0); ++ IStreamsExecutor::Config config{"unpinned no lp", 1, 2, CoreType::ECORE_ONLY, false, false}; ++ check_config(config, {{4, 5}}, false, false); ++ EXPECT_EQ((Table{{1, EFFICIENT_CORE_PROC, 2, 0, 0}}), config.get_streams_info_table()); ++ StreamCreateType type = STREAM_WITHOUT_PARAM; ++ int concurrency = 0, core_type = 0, numa_node = 0, socket = 0, max_threads = 0; ++ get_cur_stream_info(0, ++ false, ++ cpu._org_proc_type_table, ++ config.get_streams_info_table(), ++ type, ++ concurrency, ++ core_type, ++ numa_node, ++ socket, ++ max_threads); ++ EXPECT_EQ(STREAM_WITH_CORE_TYPE, type); ++ EXPECT_EQ(2, concurrency); ++ EXPECT_EQ(5, get_tbb_core_type(core_type, {5, 17}, cpu._org_proc_type_table)); ++} ++ ++TEST_F(LPExecutorConfigTest, PinnedMixedEfficientStreamKeepsObserver) { ++ for (bool reservation : {false, true}) { ++ set_topology(2, 2, 2); ++ IStreamsExecutor::Config config{"pinned mixed ecore", 1, 4, CoreType::ECORE_ONLY, reservation, true}; ++ check_config(config, {{6, 7, 8, 9}}, reservation, true); ++ EXPECT_EQ( ++ (Table{{1, ALL_PROC, 4, 0, 0}, {0, EFFICIENT_CORE_PROC, 2, 0, 0}, {0, LP_EFFICIENT_CORE_PROC, 2, 0, 0}}), ++ config.get_streams_info_table()); ++ StreamCreateType type = STREAM_WITHOUT_PARAM; ++ int concurrency = 0, core_type = 0, numa_node = 0, socket = 0, max_threads = 0; ++ get_cur_stream_info(0, ++ true, ++ cpu._org_proc_type_table, ++ config.get_streams_info_table(), ++ type, ++ concurrency, ++ core_type, ++ numa_node, ++ socket, ++ max_threads); ++ EXPECT_EQ(4, concurrency); ++ EXPECT_EQ(STREAM_WITH_OBSERVE, type); ++ } ++} ++ ++TEST_F(LPExecutorConfigTest, SingleLPEfficiencyPoolPreservesLocality) { ++ const Table topology{{6, 2, 0, 4, 0, -1, -1}, {2, 2, 0, 0, 0, 0, 0}, {4, 0, 0, 4, 0, 1, 1}}; ++ for (bool pinning : {false, true}) { ++ cpu._proc_type_table = cpu._org_proc_type_table = topology; ++ cpu._numa_nodes = cpu._sockets = 2; ++ cpu._cpu_mapping_table = {{4, 0, 0, 0, MAIN_CORE_PROC, 0, NOT_USED}, ++ {5, 0, 0, 1, MAIN_CORE_PROC, 1, NOT_USED}, ++ {6, 1, 1, 2, LP_EFFICIENT_CORE_PROC, 2, NOT_USED}, ++ {7, 1, 1, 3, LP_EFFICIENT_CORE_PROC, 3, NOT_USED}, ++ {8, 1, 1, 4, LP_EFFICIENT_CORE_PROC, 4, NOT_USED}, ++ {9, 1, 1, 5, LP_EFFICIENT_CORE_PROC, 5, NOT_USED}}; ++ IStreamsExecutor::Config config{"local lp pool", 1, 4, CoreType::ECORE_ONLY, false, pinning}; ++ EXPECT_EQ((Table{{1, LP_EFFICIENT_CORE_PROC, 4, 1, 1}}), config.get_streams_info_table()); ++ EXPECT_EQ((pinning ? Table{{6, 7, 8, 9}} : Table{}), config.get_stream_processor_ids()); ++ EXPECT_EQ(topology, cpu._proc_type_table); ++ EXPECT_EQ(4, config.get_threads()); ++ StreamCreateType type = STREAM_WITHOUT_PARAM; ++ int concurrency = 0, core_type = 0, numa_node = 0, socket = 0, max_threads = 0; ++ get_cur_stream_info(0, ++ pinning, ++ cpu._org_proc_type_table, ++ config.get_streams_info_table(), ++ type, ++ concurrency, ++ core_type, ++ numa_node, ++ socket, ++ max_threads); ++ EXPECT_EQ(pinning ? STREAM_WITH_OBSERVE : STREAM_WITH_CORE_TYPE, type); ++ EXPECT_EQ(LP_EFFICIENT_CORE_PROC, core_type); ++ EXPECT_EQ(1, numa_node); ++ EXPECT_EQ(1, socket); ++ } ++} ++ ++TEST_F(LPExecutorConfigTest, PrecomputedMixedEfficientStreamsRemainUnchanged) { ++ set_topology(2, 2, 2); ++ const Table streams{{1, ALL_PROC, 4, 0, 0}, ++ {0, EFFICIENT_CORE_PROC, 2, 0, 0}, ++ {0, LP_EFFICIENT_CORE_PROC, 2, 0, 0}}; ++ IStreamsExecutor::Config config{"precomputed mixed ecore", 1, 4, CoreType::ECORE_ONLY, false, false, true, streams}; ++ EXPECT_EQ(streams, config.get_streams_info_table()); ++ check_config(config, {{6, 7, 8, 9}}, false, false); ++} ++ ++TEST_F(LPExecutorConfigTest, ECoreOnlySkipsUnusedSmallRegularCorePool) { ++ for (bool reservation : {false, true}) { ++ for (bool pinning : {false, true}) { ++ SCOPED_TRACE(reservation); ++ SCOPED_TRACE(pinning); ++ set_topology(0, 1, 6); ++ IStreamsExecutor::Config config{"ecore capacity", 2, 3, CoreType::ECORE_ONLY, reservation, pinning}; ++ check_config(config, {{5, 6, 7}, {8, 9, 10}}, reservation, pinning); ++ EXPECT_EQ(3, config.get_threads_per_stream()); ++ EXPECT_EQ((Table{{2, LP_EFFICIENT_CORE_PROC, 3, 0, 0}}), config.get_streams_info_table()); ++ } ++ } ++} ++ ++TEST_F(LPExecutorConfigTest, SkipsUnusedSmallNumaPoolWithoutReducingThreads) { ++ const Table topology{{9, 7, 0, 2, 0, -1, -1}, {3, 1, 0, 2, 0, 0, 0}, {6, 6, 0, 0, 0, 1, 1}}; ++ cpu._proc_type_table = cpu._org_proc_type_table = topology; ++ cpu._numa_nodes = cpu._sockets = 2; ++ cpu._cpu_mapping_table = {{4, 0, 0, 0, MAIN_CORE_PROC, 0, NOT_USED}, ++ {5, 1, 1, 1, MAIN_CORE_PROC, 1, NOT_USED}, ++ {6, 1, 1, 2, MAIN_CORE_PROC, 2, NOT_USED}, ++ {7, 1, 1, 3, MAIN_CORE_PROC, 3, NOT_USED}, ++ {8, 1, 1, 4, MAIN_CORE_PROC, 4, NOT_USED}, ++ {9, 1, 1, 5, MAIN_CORE_PROC, 5, NOT_USED}, ++ {10, 1, 1, 6, MAIN_CORE_PROC, 6, NOT_USED}, ++ {11, 0, 0, 7, LP_EFFICIENT_CORE_PROC, 7, NOT_USED}, ++ {12, 0, 0, 8, LP_EFFICIENT_CORE_PROC, 8, NOT_USED}}; ++ IStreamsExecutor::Config config{"numa capacity", 2, 3, CoreType::ANY_CORE, false, true}; ++ EXPECT_EQ(2, config.get_streams()); ++ EXPECT_EQ(6, config.get_threads()); ++ EXPECT_EQ(3, config.get_threads_per_stream()); ++ EXPECT_EQ((Table{{2, MAIN_CORE_PROC, 3, 1, 1}}), config.get_streams_info_table()); ++ EXPECT_EQ((Table{{5, 6, 7}, {8, 9, 10}}), config.get_stream_processor_ids()); ++ EXPECT_EQ(topology, cpu._proc_type_table); ++} ++ ++TEST_F(LPExecutorConfigTest, ECoreOnlyIncludesBothEfficientKinds) { ++ for (int streams : {1, 4}) { ++ SCOPED_TRACE(streams); ++ set_topology(2, 2, 2); ++ IStreamsExecutor::Config config{"ecore only", streams, 4 / streams, CoreType::ECORE_ONLY, true, true}; ++ check_config(config, streams == 1 ? Table{{6, 7, 8, 9}} : Table{{6}, {7}, {8}, {9}}); ++ } ++} ++ ++TEST_F(LPExecutorConfigTest, ZeroStreamsUsesLPHelperWithoutBindingOrReservation) { ++ set_topology(0, 0, 4); ++ IStreamsExecutor::Config config{"zero streams", 0, 4, CoreType::ANY_CORE, true, true}; ++ EXPECT_EQ(0, config.get_streams()); ++ EXPECT_EQ((Table{{1, LP_EFFICIENT_CORE_PROC, 1, 0, 0}}), config.get_streams_info_table()); ++ EXPECT_FALSE(config.get_cpu_pinning()); ++ EXPECT_FALSE(config.get_cpu_reservation()); ++ EXPECT_TRUE(config.get_stream_processor_ids().empty()); ++ EXPECT_EQ(cpu._org_proc_type_table, cpu._proc_type_table); ++} ++ ++TEST_F(LPExecutorConfigTest, PrecomputedLPStreamsOverrideCorePreference) { ++ set_topology(0, 0, 4); ++ const Table streams{{2, LP_EFFICIENT_CORE_PROC, 2, 0, 0}}; ++ IStreamsExecutor::Config config{"precomputed", 2, 2, CoreType::PCORE_ONLY, true, true, true, streams}; ++ EXPECT_EQ(streams, config.get_streams_info_table()); ++ check_config(config, {{4, 5}, {6, 7}}); ++} ++ ++TEST_F(LPExecutorConfigTest, RejectsOversubscribedPrecomputedLPStreams) { ++ set_topology(0, 0, 4); ++ const Table streams{{1, LP_EFFICIENT_CORE_PROC, 5, 0, 0}}; ++ EXPECT_THROW(IStreamsExecutor::Config("oversubscribed", 1, 5, CoreType::ANY_CORE, true, true, true, streams), ++ ov::Exception); ++ EXPECT_EQ(cpu._org_proc_type_table, cpu._proc_type_table); ++ for (const auto& row : cpu._cpu_mapping_table) ++ EXPECT_EQ(NOT_USED, row[CPU_MAP_USED_FLAG]); ++} ++ ++TEST_F(LPExecutorConfigTest, FragmentedEfficientKindsUseFeasibleStreams) { ++ for (bool reservation : {false, true}) { ++ for (bool pinning : {false, true}) { ++ SCOPED_TRACE(reservation); ++ SCOPED_TRACE(pinning); ++ set_topology(0, 1, 3); ++ IStreamsExecutor::Config config{"fragmented", 2, 2, CoreType::ECORE_ONLY, reservation, pinning}; ++ check_config(config, {{4}, {5}}, reservation, pinning); ++ EXPECT_EQ(1, config.get_threads_per_stream()); ++ } ++ } ++} ++ ++TEST_F(LPExecutorConfigTest, FragmentedNumaNodesUseFeasibleStreams) { ++ const Table topology{{4, 0, 2, 2, 0, -1, -1}, {2, 0, 1, 1, 0, 0, 0}, {2, 0, 1, 1, 0, 1, 1}}; ++ for (bool reservation : {false, true}) { ++ for (bool pinning : {false, true}) { ++ SCOPED_TRACE(reservation); ++ SCOPED_TRACE(pinning); ++ cpu._proc_type_table = cpu._org_proc_type_table = topology; ++ cpu._numa_nodes = cpu._sockets = 2; ++ cpu._cpu_mapping_table = {{4, 0, 0, 0, EFFICIENT_CORE_PROC, 0, NOT_USED}, ++ {5, 0, 0, 1, LP_EFFICIENT_CORE_PROC, 1, NOT_USED}, ++ {6, 1, 1, 2, EFFICIENT_CORE_PROC, 2, NOT_USED}, ++ {7, 1, 1, 3, LP_EFFICIENT_CORE_PROC, 3, NOT_USED}}; ++ IStreamsExecutor::Config config{"fragmented numa", 2, 2, CoreType::ECORE_ONLY, reservation, pinning}; ++ EXPECT_EQ(2, config.get_streams()); ++ EXPECT_EQ(2, config.get_threads()); ++ EXPECT_EQ(1, config.get_threads_per_stream()); ++ EXPECT_EQ((Table{{1, EFFICIENT_CORE_PROC, 1, 0, 0}, {1, EFFICIENT_CORE_PROC, 1, 1, 1}}), ++ config.get_streams_info_table()); ++ EXPECT_EQ((reservation || pinning ? Table{{4}, {6}} : Table{}), config.get_stream_processor_ids()); ++ const Table remaining{{2, 0, 0, 2, 0, -1, -1}, {1, 0, 0, 1, 0, 0, 0}, {1, 0, 0, 1, 0, 1, 1}}; ++ EXPECT_EQ(reservation ? remaining : topology, cpu._proc_type_table); ++ } ++ } ++} ++ ++TEST_F(LPExecutorConfigTest, DefaultStreamCountIncludesLPCores) { ++ set_topology(2, 0, 6); ++ EXPECT_EQ(4, IStreamsExecutor::Config::get_default_num_streams()); ++ set_topology(0, 0, 4); ++ EXPECT_EQ(4, IStreamsExecutor::Config::get_default_num_streams()); ++ set_topology(1, 1, 2); ++ EXPECT_EQ(4, IStreamsExecutor::Config::get_default_num_streams()); ++} ++ ++TEST_F(LPExecutorConfigTest, NoLPPartialPoolKeepsIndependentStreams) { ++ for (bool reservation : {false, true}) { ++ for (bool pinning : {false, true}) { ++ SCOPED_TRACE(reservation); ++ SCOPED_TRACE(pinning); ++ set_topology(3, 1, 0); ++ IStreamsExecutor::Config config{"no lp partial pool", 2, 2, CoreType::ANY_CORE, reservation, pinning}; ++ check_config(config, {{4, 5}, {7}}, reservation, pinning); ++ } ++ } ++} ++ + struct ExecutorConfigTestCase { + std::vector> _proc_type_table; + std::vector> _cpu_mapping_table; +diff --git a/src/inference/tests/unit/make_default_multi_threaded_test.cpp b/src/inference/tests/unit/make_default_multi_threaded_test.cpp +--- a/src/inference/tests/unit/make_default_multi_threaded_test.cpp ++++ b/src/inference/tests/unit/make_default_multi_threaded_test.cpp +@@ -6,6 +6,7 @@ + + #include + ++#include "openvino/runtime/threading/cpu_streams_info.hpp" + #include "openvino/runtime/threading/istreams_executor.hpp" + #include "os/cpu_map_info.hpp" + +@@ -17,6 +18,73 @@ + + #if defined(__linux__) || defined(_WIN32) + ++struct LPDefaultMultiThreadsTestCase { ++ std::vector topology; ++ int threads; ++ std::vector> streams; ++}; ++ ++class LPDefaultMultiThreadsTest : public ov::test::TestsCommon, ++ public testing::WithParamInterface { ++protected: ++ CPU& cpu = cpu_info(); ++ const std::vector> saved_proc = cpu._proc_type_table; ++ const std::vector> saved_org_proc = cpu._org_proc_type_table; ++ const int saved_numa_nodes = cpu._numa_nodes; ++ const int saved_sockets = cpu._sockets; ++ ++ void TearDown() override { ++ cpu._proc_type_table = saved_proc; ++ cpu._org_proc_type_table = saved_org_proc; ++ cpu._numa_nodes = saved_numa_nodes; ++ cpu._sockets = saved_sockets; ++ } ++}; ++ ++TEST_P(LPDefaultMultiThreadsTest, UsesTwoFeasibleHomogeneousStreams) { ++ const auto& test_data = GetParam(); ++ const auto& topology = test_data.topology; ++ cpu._org_proc_type_table = cpu._proc_type_table = {topology}; ++ cpu._numa_nodes = cpu._sockets = 1; ++ const auto core_type = topology[EFFICIENT_CORE_PROC] > 0 ? ov::hint::SchedulingCoreType::ECORE_ONLY ++ : ov::hint::SchedulingCoreType::ANY_CORE; ++ IStreamsExecutor::Config initial{"lp default", 2, 0, core_type}; ++ const auto config = IStreamsExecutor::Config::make_default_multi_threaded(initial); ++ const auto table = config.get_streams_info_table(); ++ ASSERT_FALSE(table.empty()); ++ EXPECT_EQ(test_data.streams, table); ++ int streams = 0; ++ int threads = 0; ++ for (const auto& row : table) { ++ ASSERT_EQ(CPU_STREAMS_TABLE_SIZE, row.size()); ++ ASSERT_GT(row[PROC_TYPE], ALL_PROC); ++ ASSERT_LE(row[PROC_TYPE], HYPER_THREADING_PROC); ++ ASSERT_GT(row[NUMBER_OF_STREAMS], 0); ++ EXPECT_GT(row[THREADS_PER_STREAM], 0); ++ streams += row[NUMBER_OF_STREAMS]; ++ threads += row[NUMBER_OF_STREAMS] * row[THREADS_PER_STREAM]; ++ } ++ EXPECT_EQ(2, streams); ++ EXPECT_EQ(2, config.get_streams()); ++ EXPECT_EQ(test_data.threads, threads); ++ EXPECT_EQ(test_data.threads, config.get_threads()); ++ EXPECT_EQ(test_data.streams[0][THREADS_PER_STREAM], config.get_threads_per_stream()); ++ EXPECT_TRUE(config.get_stream_processor_ids().empty()); ++ EXPECT_EQ(cpu._org_proc_type_table, cpu._proc_type_table); ++} ++ ++INSTANTIATE_TEST_SUITE_P( ++ smoke_LPDefaultMultiThreads, ++ LPDefaultMultiThreadsTest, ++ testing::Values(LPDefaultMultiThreadsTestCase{{4, 0, 0, 4, 0, 0, 0}, 4, {{2, LP_EFFICIENT_CORE_PROC, 2, 0, 0}}}, ++ // Width four cannot supply two streams; width three can ++ // use the LP pool without consuming the smaller MAIN pool. ++ LPDefaultMultiThreadsTestCase{{8, 2, 0, 6, 0, 0, 0}, 6, {{2, LP_EFFICIENT_CORE_PROC, 3, 0, 0}}}, ++ LPDefaultMultiThreadsTestCase{ ++ {4, 0, 1, 3, 0, 0, 0}, ++ 2, ++ {{1, EFFICIENT_CORE_PROC, 1, 0, 0}, {1, LP_EFFICIENT_CORE_PROC, 1, 0, 0}}})); ++ + struct MakeDefaultMultiThreadsTestCase { + std::vector> _proc_type_table; + int _num_streams; diff --git a/packaging/fedora/44/test-profile-generation.py b/packaging/fedora/44/test-profile-generation.py index 79e4c7d..23ab060 100644 --- a/packaging/fedora/44/test-profile-generation.py +++ b/packaging/fedora/44/test-profile-generation.py @@ -8,20 +8,20 @@ manifest=tomllib.loads(Path('packaging/fedora/44/installed-manifest.toml').read_text()) packages={p['name']:p for p in manifest['providers']} packages['intel-npu-driver']['license'] = 'MIT AND Apache-2.0 AND (GPL-2.0-only WITH Linux-syscall-note)' -packages['intel-npu-stack-tools']={'nevr':'0:0.2.0-3.intelnpu.fc44','arch':'x86_64','license':'Apache-2.0 AND Artistic-2.0 AND BSD-3-Clause AND ISC AND MIT AND MPL-2.0 AND Unicode-3.0 AND (Apache-2.0 WITH LLVM-exception)', +packages['intel-npu-stack-tools']={'nevr':'0:0.2.0-4.intelnpu.fc44','arch':'x86_64','license':'Apache-2.0 AND Artistic-2.0 AND BSD-3-Clause AND ISC AND MIT AND MPL-2.0 AND Unicode-3.0 AND (Apache-2.0 WITH LLVM-exception)', 'files':[{'path':'/usr/bin/intel-npu-stack'}, {'path':'/usr/libexec/intel-npu-stack/intel-npu-level-zero-probe'}, {'path':'/usr/libexec/intel-npu-stack/intel-npu-openvino-probe'}, {'path':'/usr/share/intel-npu-stack/installed-manifest.toml'}]} -packages['intel-npu-stack']={'nevr':'0:0.2.0-3.intelnpu.fc44','arch':'noarch','license':'Apache-2.0','files':[]} +packages['intel-npu-stack']={'nevr':'0:0.2.0-4.intelnpu.fc44','arch':'noarch','license':'Apache-2.0','files':[]} packages['intel-npu-compiler']['license'] = 'Apache-2.0 AND MIT AND BSL-1.0 AND HPND AND BSD-3-Clause AND (GPL-2.0-only OR BSD-3-Clause) AND (Apache-2.0 WITH LLVM-exception) AND NCSA AND BSD-2-Clause AND ISC AND Spencer-94 AND Unicode-DFS-2015 AND LicenseRef-LLVM-MD5' license_owners={'intel-npu-stack-tools','intel-npu-driver','intel-npu-stack-firmware','oneapi-level-zero','openvino','intel-npu-compiler'} with tempfile.TemporaryDirectory(prefix='profile-rpm-contract-') as temporary: root=Path(temporary) for name in ['BUILD','SOURCES','SPECS','RPMS','SRPMS','tmp']:(root/name).mkdir() - spec=['%global debug_package %{nil}', 'Name: intel-npu-stack-tools', 'Version: 0.2.0', 'Release: 3.intelnpu.fc44', + spec=['%global debug_package %{nil}', 'Name: intel-npu-stack-tools', 'Version: 0.2.0', 'Release: 4.intelnpu.fc44', 'Summary: Profile generation fixture','License: '+packages['intel-npu-stack-tools']['license'], 'Requires: oneapi-level-zero(x86-64) = 1.32.0-1.intelnpu.fc44', - 'Requires: openvino(x86-64) = 2026.2.1-1.intelnpu.fc44','%description','Fixture.'] + 'Requires: openvino(x86-64) = 2026.2.1-2.intelnpu.fc44','%description','Fixture.'] for name,p in sorted(packages.items()): if name=='intel-npu-stack-tools':continue version,release=p['nevr'].split(':')[1].split('-',1) @@ -29,7 +29,7 @@ 'Release: '+release,'License: '+p['license']] if p['arch']=='noarch':spec.append('BuildArch: noarch') if name.startswith('libopenvino-') or name in ['intel-npu-compiler','openvino-plugins']: - spec.append('Requires: openvino(x86-64) = 2026.2.1-1.intelnpu.fc44') + spec.append('Requires: openvino(x86-64) = 2026.2.1-2.intelnpu.fc44') if name=='intel-npu-stack': for dependency in ['intel-npu-stack-tools','intel-npu-driver','intel-npu-stack-firmware', 'oneapi-level-zero','openvino','openvino-plugins','intel-npu-compiler']: diff --git a/scripts/ci/test_lp_ecore_guard.py b/scripts/ci/test_lp_ecore_guard.py new file mode 100644 index 0000000..1cdb1b5 --- /dev/null +++ b/scripts/ci/test_lp_ecore_guard.py @@ -0,0 +1,113 @@ +# SPDX-License-Identifier: Apache-2.0 +"""Prepared-source guard contracts; runtime behavior is tested in OpenVINO.""" +from pathlib import Path +import subprocess +import sys +import tempfile +import unittest + +ROOT = Path(__file__).resolve().parents[2] +GUARD = ROOT / 'packaging/fedora/44/rpm/openvino/check-lp-ecore-executor-guard.py' +SOURCE = Path('src/inference/src/dev/threading/istreams_executor.cpp') +MARKERS = [ + 'std::vector core_types{MAIN_CORE_PROC, EFFICIENT_CORE_PROC, LP_EFFICIENT_CORE_PROC, HYPER_THREADING_PROC};', + 'core_types = {EFFICIENT_CORE_PROC, LP_EFFICIENT_CORE_PROC};', + 'proc_type_table[0][LP_EFFICIENT_CORE_PROC] > 0 ? LP_EFFICIENT_CORE_PROC', + 'OPENVINO_ASSERT(!_streams_info_table.empty(),', + 'if (mixed_stream) {', + 'if (mixed_stream) {', + 'proc_type_table[0][EFFICIENT_CORE_PROC] + proc_type_table[0][LP_EFFICIENT_CORE_PROC]', + 'proc_type_table[0][EFFICIENT_CORE_PROC] + proc_type_table[0][LP_EFFICIENT_CORE_PROC]', + 'if (proc_type_table[0][LP_EFFICIENT_CORE_PROC] > 0 && homogeneous_streams)', + '_streams > 1 || (_thread_preferred_core_type == ov::hint::SchedulingCoreType::ECORE_ONLY && !_cpu_pinning);', + '!homogeneous_streams && _streams == 1 &&', + 'while (_threads_per_stream > 1)', + 'if (proc_type_table[0][LP_EFFICIENT_CORE_PROC] > 0 && homogeneous_streams &&\n' + ' _threads_per_stream > proc_type_table[i][j]) {\n' + ' continue;\n' + ' }', + 'streams_num += proc_type_table[i][type] / _threads_per_stream;', + 'const auto num_cores = proc_type_table[0][MAIN_CORE_PROC] + proc_type_table[0][EFFICIENT_CORE_PROC] +\n' + ' proc_type_table[0][LP_EFFICIENT_CORE_PROC];', + '_streams_info_table[0][PROC_TYPE] = LP_EFFICIENT_CORE_PROC;', + '_streams_info_table[0][STREAM_NUMA_NODE_ID] = _streams_info_table[1][STREAM_NUMA_NODE_ID];', + '_streams_info_table[0][STREAM_SOCKET_ID] = _streams_info_table[1][STREAM_SOCKET_ID];', +] +EXTRA_MARKERS = { + Path('src/inference/src/dev/threading/cpu_streams_executor.cpp'): [ + 'const auto proc_types = get_org_proc_type_table();', + 'get_tbb_core_type(core_type, core_types, proc_types);', + ], + Path('src/inference/src/dev/threading/cpu_streams_executor_internal.cpp'): [ + 'int get_tbb_core_type(int proc_type,', + 'core_types.size() == 2 && !proc_type_table.empty() &&', + 'proc_type_table[0][EFFICIENT_CORE_PROC] > 0 && proc_type_table[0][LP_EFFICIENT_CORE_PROC] > 0 &&', + 'proc_type_table[0][MAIN_CORE_PROC] == 0 && proc_type_table[0][HYPER_THREADING_PROC] == 0', + ], + Path('src/inference/dev_api/openvino/runtime/threading/cpu_streams_executor_internal.hpp'): [ + 'int get_tbb_core_type(int proc_type,', + 'const std::vector>& proc_type_table);', + ], +} + + +class LPExecutorGuardTest(unittest.TestCase): + def run_guard(self, markers, extra_markers=None): + with tempfile.TemporaryDirectory() as directory: + for relative, lines in {SOURCE: markers, **(EXTRA_MARKERS if extra_markers is None else extra_markers)}.items(): + source = Path(directory) / relative + source.parent.mkdir(parents=True, exist_ok=True) + source.write_text('\n'.join(lines), encoding='utf-8') + return subprocess.run( + [sys.executable, str(GUARD), directory], + capture_output=True, text=True, timeout=10, + ) + + def test_accepts_complete_prepared_source_markers(self): + result = self.run_guard(MARKERS) + self.assertEqual(result.returncode, 0, result.stderr) + + def test_rejects_each_missing_requirement(self): + for index, marker in enumerate(MARKERS): + with self.subTest(marker=marker): + result = self.run_guard(MARKERS[:index] + MARKERS[index + 1:]) + self.assertNotEqual(result.returncode, 0, marker) + self.assertIn('check-lp-ecore-executor-guard:', result.stderr) + + def test_rejects_duplicate_requirement(self): + result = self.run_guard(MARKERS + [MARKERS[0]]) + self.assertNotEqual(result.returncode, 0) + + def test_rejects_legacy_core_list(self): + result = self.run_guard(MARKERS + [ + 'core_types = {MAIN_CORE_PROC, EFFICIENT_CORE_PROC, HYPER_THREADING_PROC};', + ]) + self.assertNotEqual(result.returncode, 0) + + def test_rejects_unused_small_pool_clamp(self): + result = self.run_guard(MARKERS + [ + '_threads_per_stream = std::min(_threads_per_stream, proc_type_table[i][type]);', + ]) + self.assertNotEqual(result.returncode, 0) + self.assertIn('unused small pools', result.stderr) + + def test_rejects_each_missing_mapping_requirement(self): + for path, markers in EXTRA_MARKERS.items(): + for index, marker in enumerate(markers): + with self.subTest(path=path, marker=marker): + sources = dict(EXTRA_MARKERS) + sources[path] = markers[:index] + markers[index + 1:] + result = self.run_guard(MARKERS, sources) + self.assertNotEqual(result.returncode, 0) + self.assertIn('check-lp-ecore-executor-guard:', result.stderr) + + def test_rejects_missing_mapping_source(self): + sources = dict(EXTRA_MARKERS) + del sources[next(iter(sources))] + result = self.run_guard(MARKERS, sources) + self.assertNotEqual(result.returncode, 0) + self.assertIn('check-lp-ecore-executor-guard:', result.stderr) + + +if __name__ == '__main__': + unittest.main() diff --git a/xtask/src/fedora_profile.rs b/xtask/src/fedora_profile.rs index 0fdaf52..f928d49 100644 --- a/xtask/src/fedora_profile.rs +++ b/xtask/src/fedora_profile.rs @@ -128,7 +128,7 @@ fn expected_packages() -> BTreeMap { ] { packages.insert( name.to_owned(), - ("0:2026.2.1-1.intelnpu.fc44".to_owned(), "x86_64".to_owned()), + ("0:2026.2.1-2.intelnpu.fc44".to_owned(), "x86_64".to_owned()), ); } for (name, nevr, arch) in [ @@ -139,8 +139,8 @@ fn expected_packages() -> BTreeMap { "noarch", ), ("oneapi-level-zero", "0:1.32.0-1.intelnpu.fc44", "x86_64"), - ("intel-npu-stack", "0:0.2.0-3.intelnpu.fc44", "noarch"), - ("intel-npu-stack-tools", "0:0.2.0-3.intelnpu.fc44", "x86_64"), + ("intel-npu-stack", "0:0.2.0-4.intelnpu.fc44", "noarch"), + ("intel-npu-stack-tools", "0:0.2.0-4.intelnpu.fc44", "x86_64"), ] { packages.insert(name.to_owned(), (nevr.to_owned(), arch.to_owned())); } @@ -374,7 +374,7 @@ fn license_provider<'a>( let relationship = ( "openvino(x86-64)".to_owned(), "=".to_owned(), - "2026.2.1-1.intelnpu.fc44".to_owned(), + "2026.2.1-2.intelnpu.fc44".to_owned(), ); require( shared_family diff --git a/xtask/tests/fedora_openvino_package_contract.rs b/xtask/tests/fedora_openvino_package_contract.rs index 35fb275..939e37d 100644 --- a/xtask/tests/fedora_openvino_package_contract.rs +++ b/xtask/tests/fedora_openvino_package_contract.rs @@ -735,7 +735,7 @@ fn production_spec_declares_the_source_built_openvino_npu_boundary() { for required in [ "Name: openvino", "Version: 2026.2.1", - "Release: 1.intelnpu.fc44", + "Release: 2.intelnpu.fc44", "ExclusiveArch: x86_64", "openvino.tar", "npu-compiler.tar", diff --git a/xtask/tests/native_opensvino_version_contract.rs b/xtask/tests/native_opensvino_version_contract.rs index 4351009..6904684 100644 --- a/xtask/tests/native_opensvino_version_contract.rs +++ b/xtask/tests/native_opensvino_version_contract.rs @@ -2,7 +2,7 @@ //! Regression contract for the native SDK probe's OpenVINO version acceptance. //! -//! The tools package builds against the 2026.2.1-1 providers while local SDK +//! The tools package builds against the 2026.2.1 providers while local SDK //! checks against an installed 0.1.1 stack resolve OpenVINO 2026.2.0, so the //! native configure step must accept exactly those two versions and refuse //! any other one instead of silently taking whatever the SDK ships.