using System; namespace LLama { #if NET6_0_OR_GREATER /// /// A class about configurations when loading native libraries. /// Note that it could be configured only once before any call to llama model apis. /// public class NativeLibraryConfig { private static NativeLibraryConfig? instance; private static readonly object lockObject = new object(); /// /// Whether there's already a config for native library. /// public bool Initialied { get; private set; } internal Description Desc { get; private set; } internal static NativeLibraryConfig GetInstance() { if (instance is null) { lock (lockObject) { if (instance is null) { instance = new NativeLibraryConfig(); } } } return instance; } /// /// Load a specified native library as backend for LLamaSharp /// /// /// public static void WithLibrary(string libraryPath) { var config = GetInstance(); if (config.Initialied) { throw new InvalidOperationException("NativeLibraryConfig could be configured only once before any call to llama model apis."); } config.Desc = new Description(libraryPath); } /// /// Ass rules to match a suitable library from installed LLamaSharp backend. /// /// /// /// Whether to allow fall-back when your hardware doesn't support your configuration. /// Whether to skip the check when fallback is allowed. /// It's especially useful when your cuda library is not in the default path. /// public static void WithMatchRule(bool useCuda = true, AvxLevel avxLevel = AvxLevel.Avx2, bool allowFallback = true, bool skipCheck = false) { if(allowFallback && skipCheck) { throw new ArgumentException("Cannot skip the check when fallback is allowed."); } var config = GetInstance(); if (config.Initialied) { throw new InvalidOperationException("NativeLibraryConfig could be configured only once before any call to llama model apis."); } config.Desc = new Description(UseCuda: useCuda, AvxLevel: avxLevel, AllowFallback: allowFallback, SkipCheck: skipCheck); } internal static string AvxLevelToString(AvxLevel level) { return level switch { AvxLevel.None => string.Empty, AvxLevel.Avx => "avx", AvxLevel.Avx2 => "avx2", #if NET8_0_OR_GREATER AvxLevel.Avx512 => "avx512" #endif _ => throw new ArgumentException($"Cannot recognize Avx level {level}") }; } private NativeLibraryConfig() { Desc = new Description(); } /// /// Avx support configuration /// public enum AvxLevel { /// None = 0, /// Avx = 1, /// Avx2 = 2, #if NET8_0_OR_GREATER /// Avx512 = 3, #endif } internal record Description(string Path = "", bool UseCuda = true, AvxLevel AvxLevel = AvxLevel.Avx2, bool AllowFallback = true, bool SkipCheck = false); } #endif }