You can not select more than 25 topics Topics must start with a chinese character,a letter or number, can include dashes ('-') and can be up to 35 characters long.

NativeLibraryConfig.cs 6.7 kB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189
  1. using System;
  2. namespace LLama.Native
  3. {
  4. #if NET6_0_OR_GREATER
  5. /// <summary>
  6. /// Allows configuration of the native llama.cpp libraries to load and use.
  7. /// All configuration must be done before using **any** other LLamaSharp methods!
  8. /// </summary>
  9. public sealed class NativeLibraryConfig
  10. {
  11. private static readonly Lazy<NativeLibraryConfig> _instance = new(() => new NativeLibraryConfig());
  12. /// <summary>
  13. /// Get the config instance
  14. /// </summary>
  15. public static NativeLibraryConfig Instance => _instance.Value;
  16. /// <summary>
  17. /// Whether there's already a config for native library.
  18. /// </summary>
  19. public static bool LibraryHasLoaded { get; internal set; } = false;
  20. private string _libraryPath = string.Empty;
  21. private bool _useCuda = true;
  22. private AvxLevel _avxLevel;
  23. private bool _allowFallback = true;
  24. private bool _skipCheck = false;
  25. private bool _logging = false;
  26. private static void ThrowIfLoaded()
  27. {
  28. if (LibraryHasLoaded)
  29. throw new InvalidOperationException("NativeLibraryConfig must be configured before using **any** other LLamaSharp methods!");
  30. }
  31. /// <summary>
  32. /// Load a specified native library as backend for LLamaSharp.
  33. /// When this method is called, all the other configurations will be ignored.
  34. /// </summary>
  35. /// <param name="libraryPath"></param>
  36. /// <exception cref="InvalidOperationException">Thrown if `LibraryHasLoaded` is true.</exception>
  37. public NativeLibraryConfig WithLibrary(string libraryPath)
  38. {
  39. ThrowIfLoaded();
  40. _libraryPath = libraryPath;
  41. return this;
  42. }
  43. /// <summary>
  44. /// Configure whether to use cuda backend if possible.
  45. /// </summary>
  46. /// <param name="enable"></param>
  47. /// <returns></returns>
  48. /// <exception cref="InvalidOperationException">Thrown if `LibraryHasLoaded` is true.</exception>
  49. public NativeLibraryConfig WithCuda(bool enable = true)
  50. {
  51. ThrowIfLoaded();
  52. _useCuda = enable;
  53. return this;
  54. }
  55. /// <summary>
  56. /// Configure the prefferred avx support level of the backend.
  57. /// </summary>
  58. /// <param name="level"></param>
  59. /// <returns></returns>
  60. /// <exception cref="InvalidOperationException">Thrown if `LibraryHasLoaded` is true.</exception>
  61. public NativeLibraryConfig WithAvx(AvxLevel level)
  62. {
  63. ThrowIfLoaded();
  64. _avxLevel = level;
  65. return this;
  66. }
  67. /// <summary>
  68. /// Configure whether to allow fallback when there's no match for preferred settings.
  69. /// </summary>
  70. /// <param name="enable"></param>
  71. /// <returns></returns>
  72. /// <exception cref="InvalidOperationException">Thrown if `LibraryHasLoaded` is true.</exception>
  73. public NativeLibraryConfig WithAutoFallback(bool enable = true)
  74. {
  75. ThrowIfLoaded();
  76. _allowFallback = enable;
  77. return this;
  78. }
  79. /// <summary>
  80. /// Whether to skip the check when you don't allow fallback. This option
  81. /// may be useful under some complex conditions. For example, you're sure
  82. /// you have your cublas configured but LLamaSharp take it as invalid by mistake.
  83. /// </summary>
  84. /// <param name="enable"></param>
  85. /// <returns></returns>
  86. /// <exception cref="InvalidOperationException">Thrown if `LibraryHasLoaded` is true.</exception>
  87. public NativeLibraryConfig SkipCheck(bool enable = true)
  88. {
  89. ThrowIfLoaded();
  90. _skipCheck = enable;
  91. return this;
  92. }
  93. /// <summary>
  94. /// Whether to output the logs to console when loading the native library with your configuration.
  95. /// </summary>
  96. /// <param name="enable"></param>
  97. /// <returns></returns>
  98. /// <exception cref="InvalidOperationException">Thrown if `LibraryHasLoaded` is true.</exception>
  99. public NativeLibraryConfig WithLogs(bool enable = true)
  100. {
  101. ThrowIfLoaded();
  102. _logging = enable;
  103. return this;
  104. }
  105. internal static Description CheckAndGatherDescription()
  106. {
  107. if (Instance._allowFallback && Instance._skipCheck)
  108. {
  109. throw new ArgumentException("Cannot skip the check when fallback is allowed.");
  110. }
  111. return new Description(Instance._libraryPath, Instance._useCuda, Instance._avxLevel, Instance._allowFallback, Instance._skipCheck, Instance._logging);
  112. }
  113. internal static string AvxLevelToString(AvxLevel level)
  114. {
  115. return level switch
  116. {
  117. AvxLevel.None => string.Empty,
  118. AvxLevel.Avx => "avx",
  119. AvxLevel.Avx2 => "avx2",
  120. AvxLevel.Avx512 => "avx512",
  121. _ => throw new ArgumentException($"Unknown AvxLevel '{level}'")
  122. };
  123. }
  124. /// <summary>
  125. /// Private constructor prevents new instances of this class being created
  126. /// </summary>
  127. private NativeLibraryConfig()
  128. {
  129. // Automatically detect the highest supported AVX level
  130. if (System.Runtime.Intrinsics.X86.Avx.IsSupported)
  131. _avxLevel = AvxLevel.Avx;
  132. if (System.Runtime.Intrinsics.X86.Avx2.IsSupported)
  133. _avxLevel = AvxLevel.Avx2;
  134. #if NET8_0_OR_GREATER
  135. if (System.Runtime.Intrinsics.X86.Avx512F.IsSupported)
  136. _avxLevel = AvxLevel.Avx512;
  137. #endif
  138. }
  139. /// <summary>
  140. /// Avx support configuration
  141. /// </summary>
  142. public enum AvxLevel
  143. {
  144. /// <summary>
  145. /// No AVX
  146. /// </summary>
  147. None,
  148. /// <summary>
  149. /// Advanced Vector Extensions (supported by most processors after 2011)
  150. /// </summary>
  151. Avx,
  152. /// <summary>
  153. /// AVX2 (supported by most processors after 2013)
  154. /// </summary>
  155. Avx2,
  156. /// <summary>
  157. /// AVX512 (supported by some processors after 2016, not widely supported)
  158. /// </summary>
  159. Avx512,
  160. }
  161. internal record Description(string Path, bool UseCuda, AvxLevel AvxLevel, bool AllowFallback, bool SkipCheck, bool Logging);
  162. }
  163. #endif
  164. }