Description
.NET Core 2.1 introduced hardware intrinsics APIs that allow C# code to take full advantage of the CPU. For example, you can now write algorithms using SSE or AVX instructions purely from C# code.
The CpuMathNative assembly exists solely so ML.NET can take advantage of SSE and AVX instructions in its algorithms. When running on .NET Core 2.1+, we can remove our dependency on this native assembly, and instead port the C++ SIMD code to using the new C# intrinsics APIs.
However, to do this (and still support the full .NET Framework), we need to do some refactoring to our assemblies and NuGet packages.
The first thing we need to do is allow Microsoft.ML.CpuMath
to be multi-targeted for netstandard2.0;netcoreapp2.1
. This will allow us to compile against the netcoreapp2.1 specific SSE APIs.
However, doing that affects our Microsoft.ML
nuget package. This is because when you make a nuget package, you put your assemblies into TFM specific folders lib\netstandard2.0
, lib\netcoreapp2.1
, etc. And the way asset picking works is that once it finds assets for a specific TFM, it stops looking. (The reasoning is typically there is a single assembly per nuget package.) So if we have a single assembly, CpuMath, that needs to go into both lib\netstandard2.0
and lib\netcoreapp2.1
, we have a problem. It means ALL our assemblies need to go into BOTH folders, which is unnecessary duplication.
To solve this duplication, I propose to split CpuMath into its own nuget package. So we will have this structure:
Microsoft.ML.CpuMath
- Contains the CpuMath managed assemblies (one for each TFM) and the CpuMathNative assemblies.
Microsoft.ML
- Has a dependency on
Microsoft.ML.CpuMath
.
- Has a dependency on
In order to do this correctly, we need to remove the assembly reference from Microsoft.ML.CpuMath.dll
on Microsoft.ML.Core.dll
. This is because the nuget dependency goes the other way. The only reason Microsoft.ML.CpuMath.dll
depends on Microsoft.ML.Core.dll
is so it can use the Contracts
class. We can break this dependency by using the PRIVATE_CONTRACTS
define constant, and source linking the Contracts.cs
file into CpuMath.