Skip to content

Enable SymbolicSgdLogisticRegression (SymSgdNative) on arm64 - #7671

Open
vladimir-aubrecht wants to merge 6 commits into
dotnet:mainfrom
vladimir-aubrecht:feature/symsgd-arm64
Open

Enable SymbolicSgdLogisticRegression (SymSgdNative) on arm64#7671
vladimir-aubrecht wants to merge 6 commits into
dotnet:mainfrom
vladimir-aubrecht:feature/symsgd-arm64

Conversation

@vladimir-aubrecht

Copy link
Copy Markdown
Contributor

Summary

Enables the SymbolicSgdLogisticRegression trainer (backed by SymSgdNative) on arm/arm64, where Intel MKL is unavailable. Fixes #5798.

SymSGD uses only four CBLAS routines (sdot, saxpy, sdoti, saxpyi). This PR provides them via a tiny, self-contained libMklImports shim built from portable C — with no external BLAS dependency — so it configures and links in the CI cross-compilation sysroots (which ship no OpenBLAS/BLAS).

Changes

  • src/Native/MklImportsArm/ (new): implements the four CBLAS routines as plain C loops (-O3 autovectorizes the dense paths to NEON) plus MKL DFTI stubs. No find_package(BLAS) — zero external deps. Symbols are exported explicitly because the native build uses -fvisibility=hidden.
  • src/Native/CMakeLists.txt: build MklImportsArm + SymSgdNative on arm.
  • src/Native/SymSgdNative/CMakeLists.txt: link SymSgdNative against the shim on arm.
  • src/Native/SymSgdNative/SparseBLAS.h: make the CBLAS calling convention portable (__cdecl only on _WIN32).
  • Directory.Build.targets: ship libMklImports and libSymSgdNative next to the managed assemblies on arm.
  • SymSgdClassificationTrainer.cs: marshal LearnAll's native bool parameters as UnmanagedType.I1. The default 4-byte bool marshalling corrupts later stack arguments and segfaults on arm64 (works on x64 by luck).

Testing

Built native (Release + Debug) and ran the SymSGD trainer tests on Apple Silicon (arm64):

  • TestEstimatorSymSgdClassificationTrainer
  • TestEstimatorSymSgdInitPredictor
  • SimpleTrainAndPredictSymSGD

3 passed, 0 failed. Without the bool marshalling fix, these crash the test host with a SIGSEGV inside LearnAll.

Notes

  • The initial arm enablement scaffolding (MklImportsArm skeleton, CMake gating, SparseBLAS.h calling-convention guard) is based on prior work by @anicka-net (credited as co-author).
  • Broader MKL consumers in Microsoft.ML.Mkl.Components (OLS, VectorWhitening) and Microsoft.ML.TimeSeries still require a real BLAS/LAPACK and are out of scope here.
@vladimir-aubrecht

Copy link
Copy Markdown
Contributor Author

@dotnet-policy-service agree company="Microsoft"

@vladimir-aubrecht
vladimir-aubrecht marked this pull request as ready for review August 11, 2026 12:28
Copilot AI lite review requested due to automatic review settings August 11, 2026 12:28

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

Enables SymbolicSgdLogisticRegression / SymSgdNative on arm/arm64 by adding an ARM-specific MklImports shim (implementing the small subset of CBLAS APIs SymSGD needs), wiring it into the native build, and fixing managed P/Invoke marshalling that can crash on arm64.

Changes:

  • Add src/Native/MklImportsArm/ to build a self-contained MklImports shim on arm/arm64 and link SymSgdNative against it.
  • Update native build gating so SymSgdNative is built on arm/arm64 and shipped next to managed assemblies.
  • Fix LearnAll P/Invoke bool marshalling to avoid stack corruption / SIGSEGV on arm64.

Reviewed changes

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

Show a summary per file
File Description
src/Native/SymSgdNative/SparseBLAS.h Makes CBLAS calling convention portable across Windows vs non-Windows builds.
src/Native/SymSgdNative/CMakeLists.txt Adjusts how MklImports is resolved/linked on arm platforms.
src/Native/MklImportsArm/MklImportsArm.c Implements the minimal CBLAS subset + DFTI stubs for arm/arm64 as a self-contained shim.
src/Native/MklImportsArm/CMakeLists.txt Adds CMake target to build/install the ARM MklImports shim.
src/Native/CMakeLists.txt Enables building SymSgdNative on arm/arm64 and adds MklImportsArm to the build graph.
src/Microsoft.ML.Mkl.Components/SymSgdClassificationTrainer.cs Fixes P/Invoke bool marshalling for LearnAll to prevent arm64 crashes.
Directory.Build.targets Ensures MklImports and SymSgdNative are copied for arm/arm64 outputs (no longer removed).

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

Comment thread src/Native/SymSgdNative/CMakeLists.txt Outdated
Comment thread src/Native/SymSgdNative/SparseBLAS.h
Comment thread src/Native/MklImportsArm/MklImportsArm.c Outdated
@codecov

codecov Bot commented Aug 18, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 70.00000% with 3 lines in your changes missing coverage. Please review.
✅ Project coverage is 69.88%. Comparing base (240a849) to head (7a7d8dd).
⚠️ Report is 2 commits behind head on main.

Files with missing lines Patch % Lines
...est/Microsoft.ML.Predictor.Tests/TestPredictors.cs 33.33% 1 Missing and 1 partial ⚠️
...t.ML.Mkl.Components/SymSgdClassificationTrainer.cs 85.71% 0 Missing and 1 partial ⚠️
Additional details and impacted files
@@           Coverage Diff           @@
##             main    #7671   +/-   ##
=======================================
  Coverage   69.88%   69.88%           
=======================================
  Files        1487     1487           
  Lines      276214   276223    +9     
  Branches    28287    28289    +2     
=======================================
+ Hits       193019   193040   +21     
+ Misses      75708    75691   -17     
- Partials     7487     7492    +5     
Flag Coverage Δ
Debug 69.88% <70.00%> (+<0.01%) ⬆️
production 64.07% <85.71%> (+<0.01%) ⬆️
test 89.82% <33.33%> (-0.01%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

Files with missing lines Coverage Δ
.../Scenarios/Api/Estimators/SimpleTrainAndPredict.cs 94.73% <ø> (ø)
...sts/TrainerEstimators/SymSgdClassificationTests.cs 100.00% <ø> (ø)
...t.ML.Mkl.Components/SymSgdClassificationTrainer.cs 77.23% <85.71%> (+0.08%) ⬆️
...est/Microsoft.ML.Predictor.Tests/TestPredictors.cs 69.51% <33.33%> (-0.11%) ⬇️

... and 7 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
Vladimir Aubrecht and others added 4 commits August 26, 2026 14:33
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 dotnet#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>
@vladimir-aubrecht

vladimir-aubrecht commented Aug 27, 2026

Copy link
Copy Markdown
Contributor Author

Good catch — right now the PR builds and tests SymSgdNative on Windows/Linux arm64 but this packaging exclusion means it wouldn't ship in the arm64 NuGet, so consumers wouldn't actually get it. I think we should remove the exclusion here so the feature is delivered, but scoped to the platforms where we actually build it: include SymSgdNative for win-arm64 and linux-arm64, and keep it excluded for osx-arm64 (where it isn't built, since the macOS cross-compilation runner has no arm64 libomp). Done in bde8e6c — the packaging condition now includes SymSgdNative for win-arm64 and linux-arm64 and excludes only osx-arm64.

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>
Run macOS arm64 CI and native asset builds on an Apple Silicon image so Homebrew provides a matching OpenMP runtime. Build and package SymSgdNative for osx-arm64, prepare libomp dynamically for Helix, and document the dependency.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

3 participants