Skip to content

Enable SymSgdNative on ARM64 including macOS - #7678

Closed
matouskozak wants to merge 6 commits into
mainfrom
matouskozak-macos-arm64-symsgd
Closed

Enable SymSgdNative on ARM64 including macOS#7678
matouskozak wants to merge 6 commits into
mainfrom
matouskozak-macos-arm64-symsgd

Conversation

@matouskozak

Copy link
Copy Markdown
Member

Summary

Extends the ARM64 SymSgd work from #7671 to macOS by building native assets on Apple Silicon agents.

  • builds SymSgdNative for ARM/ARM64 with the self-contained CBLAS shim
  • uses macOS-15-arm64 Azure Pipelines agents for native macOS ARM64 builds
  • packages ARM64 libomp.dylib beside libSymSgdNative.dylib
  • links OpenMP through @loader_path/libomp.dylib
  • removes the macOS ARM64 exclusions so existing SymSgd tests run on ARM64 Helix
  • includes the LLVM OpenMP redistribution notice

Validation

  • clean and incremental macOS ARM64 native builds
  • Debug and Release native package asset generation
  • NuGet package contains runtimes/osx-arm64/native/libSymSgdNative.dylib and libomp.dylib
  • otool confirms @loader_path/libomp.dylib
  • existing targeted SymSgd tests: 3 passed
  • reviewed independently with Claude Opus 5, Claude Sonnet 5, and Gemini 3.7 Flash

Related to #5798 and #7671.

Vladimir Aubrecht and others added 6 commits August 27, 2026 19:24
Build SymSgdNative and a small self-contained libMklImports shim on
arm/arm64 so the SymbolicSgdLogisticRegression trainer works there
without Intel MKL.

- MklImportsArm: implement the four CBLAS routines SymSGD needs
  (sdot, saxpy, sdoti, saxpyi) as portable C with no external BLAS
  dependency, plus DFTI stubs. Drop find_package(BLAS) so it configures
  in the CI cross-compilation sysroots (which ship no BLAS). Export the
  symbols explicitly since the native build uses -fvisibility=hidden.
- CMake: build MklImportsArm + SymSgdNative on arm, link SymSgdNative
  against the shim, and make the CBLAS calling convention portable.
- Directory.Build.targets: ship libMklImports and libSymSgdNative next
  to the managed assemblies on arm.
- SymSgdClassificationTrainer: marshal the native bool parameters of
  LearnAll as I1. The default 4-byte bool marshalling corrupts later
  stack arguments and segfaults on arm64.

Fixes #5798

Co-authored-by: Anna Maresova <anicka@anicka.net>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…Descriptor, fix misleading comment

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…rts off arm

Two CI failures on this PR:

1. macOS arm64 build: SymSgdNative linked OpenMP via the hardcoded Intel Homebrew
   path /usr/local/opt/libomp, which holds an x86_64 libomp on Apple Silicon, so
   linking failed with undefined __kmpc_*/omp_* symbols. Use `brew --prefix libomp`
   like MatrixFactorizationNative already does, so it resolves on Intel and arm Macs.

2. Windows/macOS arm64 tests: shipping the arm MklImports shim as libMklImports made
   NativeDependencyFact("MklImports") stop skipping every MKL-gated test. The shim only
   implements the 4 CBLAS routines SymSGD needs, so OLS/PCA-whitening/TimeSeries tests
   ran and failed with EntryPointNotFound (LAPACKE_dsytrd) / DllNotFound (MklProxyNative).

Fix by making SymSgd self-contained on arm and not shipping a separate libMklImports:
- SymSgdNative compiles the MklImportsArm CBLAS shim directly (no separate library),
  and the arm MklImportsArm target / its CMakeLists are removed.
- Directory.Build.targets keeps MklImports removed on arm (only SymSgdNative is copied).
- SymSgdClassificationTrainer skips the ErrorMessage(0) MKL-preload on arm (there is no
  MklImports to preload there).
- SymSgd tests are gated on NativeDependencyFact("SymSgdNative") instead of "MklImports"
  so they still run on arm; the other MKL tests skip as they did before this PR.

Verified on arm64 macOS: SymSgdNative links and is self-contained (cblas_* internal,
no MklImports dependency), SymSgd tests run and pass, and OLS/whitening tests skip.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Follow-up to the arm64 SymSgd enablement:

- macOS arm64: the cross-compilation runner only has an x86_64 libomp, and SymSGD needs
  OpenMP, so SymSgdNative cannot link there. Build it on Windows/Linux arm only and don't
  copy it on macOS arm, so its dependent tests skip there (they already skip the full-MKL
  tests). SymSgd remains enabled on Windows and Linux arm64.

- BinaryClassifierSymSgdTest is a strict baseline comparison against the win-x64 baseline;
  SymSGD produces slightly different numbers on arm, so skip it on arm (it already skips on
  Linux). The trainer itself stays covered on arm by the SymSgdClassificationTests estimators.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The packaging exclusion kept SymSgdNative out of all arm NuGet packages, so even
though this PR builds and tests it on Windows/Linux arm64, consumers wouldn't get it.
Include it for arm64/arm except on macOS, where SymSgdNative isn't built (the macOS
cross-compilation runner has no arm64 libomp). Replaces the stale TODO.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Build macOS ARM64 assets on Apple Silicon agents and package the native OpenMP runtime beside SymSgdNative using loader-relative linkage.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: f6486565-2c30-46ac-b951-6e6468408258
Copilot AI lite review requested due to automatic review settings August 27, 2026 18:01

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Extends ML.NET’s SymSGD native enablement to macOS ARM64 by building SymSgdNative on Apple Silicon agents, packaging required native dependencies (notably libomp.dylib), and updating tests/packaging to run SymSGD scenarios on ARM64.

Changes:

  • Build SymSgdNative on ARM/ARM64 by compiling the ARM CBLAS shim into the library and updating CMake gating accordingly.
  • Enable macOS ARM64 native builds/packaging by using Apple Silicon agents and shipping libomp.dylib beside libSymSgdNative.dylib with @loader_path linkage.
  • Update test gating to depend on SymSgdNative and remove macOS ARM64 exclusions so SymSGD tests run on ARM64 Helix.

Reviewed changes

Copilot reviewed 14 out of 14 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
THIRD-PARTY-NOTICES.TXT Adds LLVM OpenMP runtime redistribution notice.
test/Microsoft.ML.Tests/TrainerEstimators/SymSgdClassificationTests.cs Switches native dependency gating from MklImports to SymSgdNative.
test/Microsoft.ML.Tests/Scenarios/Api/Estimators/SimpleTrainAndPredict.cs Switches SymSGD scenario test gating to SymSgdNative.
test/Microsoft.ML.Predictor.Tests/TestPredictors.cs Gates SymSGD baseline test on SymSgdNative and skips strict baseline compare on ARM/ARM64.
src/Native/SymSgdNative/SparseBLAS.h Makes CBLAS calling convention portable and fixes const-correctness for dense vector usage.
src/Native/SymSgdNative/CMakeLists.txt Adds ARM shim compilation path and macOS ARM64 libomp packaging / @loader_path install-name handling.
src/Native/Native.proj Packages SymSgdNative broadly and adds macOS ARM64 libomp.dylib asset; refines symbols packaging conditions.
src/Native/MklImportsArm/MklImportsArm.c Introduces ARM CBLAS shim implementation (and DFTI stubs) used to enable SymSGD without MKL on ARM.
src/Native/CMakeLists.txt Builds SymSgdNative on ARM and documents why a separate MklImports isn’t built there.
src/Microsoft.ML.Mkl.Components/SymSgdClassificationTrainer.cs Skips MKL load trigger on ARM and fixes P/Invoke bool marshalling for LearnAll.
eng/helix.proj Copies the correct libomp.dylib for macOS ARM64 Helix runs and removes SymSgd install-name patching from Helix step.
Directory.Build.targets Ensures libomp.dylib is copied next to managed assemblies on macOS ARM64 when SymSgdNative is referenced.
build/vsts-ci.yml Uses macOS ARM64 agents for Apple Silicon native asset generation.
.vsts-dotnet-ci.yml Renames/retargets macOS ARM64 job to macOS-15-arm64 pool image.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment on lines +17 to +24
execute_process(
COMMAND brew --prefix libomp
RESULT_VARIABLE BREW_LIBOMP
OUTPUT_VARIABLE BREW_LIBOMP_PREFIX
OUTPUT_STRIP_TRAILING_WHITESPACE
)
SET(OPENMP_LIBRARY "${BREW_LIBOMP_PREFIX}/lib/libomp.dylib")
include_directories("${BREW_LIBOMP_PREFIX}/include")
Comment on lines +5 to +10
// ARM replacement for Intel MKL (libMklImports.so).
//
// This provides a small, self-contained libMklImports for arm/arm64 that
// covers exactly the symbols SymSGD needs, with no external BLAS dependency.
// That is important because the cross-compilation sysroots used in CI do not
// ship OpenBLAS (or any system BLAS), so linking against one is not an option.
Comment on lines +18 to +24
// MKL DFTI (FFT) functions are stubbed — they are referenced by the managed
// MKL Components initializer but not used by SymSGD. The stubs return error
// codes so any actual FFT call fails cleanly rather than crashing.

// The native build is compiled with -fvisibility=hidden, so every symbol that
// must be visible to SymSgdNative (the CBLAS routines) or to the managed
// P/Invoke layer (DftiErrorMessage) has to be exported explicitly.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants