From d95dd67e2f89ebfb4102831b515452ca023a96e9 Mon Sep 17 00:00:00 2001 From: Digant Desai Date: Tue, 3 Nov 2026 06:24:23 -0800 Subject: [PATCH] [executorch][native] Pin eager kernels when generating op samples Pull Request resolved: https://github.com/pytorch/executorch/pull/24358 Eager golden outputs differed by an ulp or two between generating hosts, because MKL and oneDNN pick kernels by ISA and MKL splits work by thread count. The `op_samples` genrule and the `native_op_samples` CMake target now pin MKL to its reproducible path, oneDNN and ATen to AVX2, and OpenMP and MKL to one thread. `MKL_NUM_THREADS` is set as well as `OMP_NUM_THREADS` so a host's own value cannot override it. Authored with Claude Code. @bypass-github-export-checks @bypass-github-pytorch-ci-checks @bypass-github-executorch-ci-checks ghstack-source-id: 463657753 @exported-using-ghexport Differential Revision: [D128254894](https://our.internmc.facebook.com/intern/diff/D128254894/) --- backends/native/test/CMakeLists.txt | 11 +++++++---- backends/native/test/samples/BUCK | 6 ++++-- backends/native/test/samples/generate.py | 7 ++++++- 3 files changed, 17 insertions(+), 7 deletions(-) diff --git a/backends/native/test/CMakeLists.txt b/backends/native/test/CMakeLists.txt index eb404c4cba9..4e9c7b28837 100644 --- a/backends/native/test/CMakeLists.txt +++ b/backends/native/test/CMakeLists.txt @@ -29,7 +29,9 @@ target_compile_options( $<$>:-fexceptions> ) -# Op packages with bundled samples, one per op and quantization scheme. +# Op packages with bundled samples, one per op and quantization scheme. The +# environment pins the eager kernels' ISA and threads, so the golden is the same +# on any x86 host with AVX2. Other hosts can differ. set(_native_op_samples ${CMAKE_CURRENT_BINARY_DIR}/op_samples) file(GLOB _native_op_samples_srcs CONFIGURE_DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/samples/*.py @@ -37,9 +39,10 @@ file(GLOB _native_op_samples_srcs CONFIGURE_DEPENDS add_custom_command( OUTPUT ${_native_op_samples}.stamp COMMAND - ${CMAKE_COMMAND} -E env "PYTHONPATH=${EXECUTORCH_ROOT}/src" - ${PYTHON_EXECUTABLE} -m executorch.backends.native.test.samples.generate - --out ${_native_op_samples} + ${CMAKE_COMMAND} -E env MKL_CBWR=COMPATIBLE ONEDNN_MAX_CPU_ISA=AVX2 + ATEN_CPU_CAPABILITY=avx2 OMP_NUM_THREADS=1 MKL_NUM_THREADS=1 + "PYTHONPATH=${EXECUTORCH_ROOT}/src" ${PYTHON_EXECUTABLE} -m + executorch.backends.native.test.samples.generate --out ${_native_op_samples} COMMAND ${CMAKE_COMMAND} -E touch ${_native_op_samples}.stamp DEPENDS ${_native_op_samples_srcs} ${EXECUTORCH_ROOT}/backends/test/suite/operators/test_linear.py diff --git a/backends/native/test/samples/BUCK b/backends/native/test/samples/BUCK index 97b4b66b7db..48e83efc2d9 100644 --- a/backends/native/test/samples/BUCK +++ b/backends/native/test/samples/BUCK @@ -40,11 +40,13 @@ fbcode_target( ], ) -# Op packages with bundled samples, one per op and quantization scheme. +# Op packages with bundled samples, one per op and quantization scheme. The +# environment pins the eager kernels' ISA and threads, so the golden is the same +# on any x86 host with AVX2. Other hosts can differ. fbcode_target( _kind = runtime.genrule, name = "op_samples", out = "op_samples", - cmd = "$(exe :generate) --out $OUT", + cmd = "MKL_CBWR=COMPATIBLE ONEDNN_MAX_CPU_ISA=AVX2 ATEN_CPU_CAPABILITY=avx2 OMP_NUM_THREADS=1 MKL_NUM_THREADS=1 $(exe :generate) --out $OUT", visibility = ["//executorch/backends/native/test/..."], ) diff --git a/backends/native/test/samples/generate.py b/backends/native/test/samples/generate.py index 665a17aa22b..f98fe7e91cb 100644 --- a/backends/native/test/samples/generate.py +++ b/backends/native/test/samples/generate.py @@ -5,7 +5,12 @@ # LICENSE file in the root directory of this source tree. """Write _.ptn for each op and quantization scheme that fits a case -of the op.""" +of the op. + +Golden outputs depend on the eager kernels' ISA and threads; the op_samples +genrule and the native_op_samples CMake target pin them, so build one of those +rather than running this module to reproduce their packages. +""" import argparse import logging