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 7.0 kB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201
  1. using System;
  2. namespace LLama.Native
  3. {
  4. #if NET6_0_OR_GREATER
  5. /// <summary>
  6. /// A class about configurations when loading native libraries.
  7. /// Note that it could be configured only once before any call to llama model apis.
  8. /// </summary>
  9. public class NativeLibraryConfig
  10. {
  11. private static NativeLibraryConfig? instance;
  12. private static readonly object lockObject = new object();
  13. public static NativeLibraryConfig Default
  14. {
  15. get
  16. {
  17. return GetInstance();
  18. }
  19. }
  20. /// <summary>
  21. /// Whether there's already a config for native library.
  22. /// </summary>
  23. public static bool LibraryHasLoaded { get; internal set; } = false;
  24. private string _libraryPath;
  25. private bool _useCuda;
  26. private AvxLevel _avxLevel;
  27. private bool _allowFallback;
  28. private bool _skipCheck;
  29. private bool _logging;
  30. internal static NativeLibraryConfig GetInstance()
  31. {
  32. if (instance is null)
  33. {
  34. lock (lockObject)
  35. {
  36. if (instance is null)
  37. {
  38. instance = new NativeLibraryConfig();
  39. }
  40. }
  41. }
  42. return instance;
  43. }
  44. /// <summary>
  45. /// Load a specified native library as backend for LLamaSharp.
  46. /// When this method is called, all the other configurations will be ignored.
  47. /// </summary>
  48. /// <param name="libraryPath"></param>
  49. /// <exception cref="InvalidOperationException"></exception>
  50. public NativeLibraryConfig WithLibrary(string libraryPath)
  51. {
  52. if (LibraryHasLoaded)
  53. {
  54. throw new InvalidOperationException("NativeLibraryConfig could be configured only once before any call to llama model apis.");
  55. }
  56. _libraryPath = libraryPath;
  57. return this;
  58. }
  59. /// <summary>
  60. /// Configure whether to use cuda backend if possible.
  61. /// </summary>
  62. /// <param name="enable"></param>
  63. /// <returns></returns>
  64. /// <exception cref="InvalidOperationException"></exception>
  65. public NativeLibraryConfig WithCuda(bool enable = true)
  66. {
  67. if (LibraryHasLoaded)
  68. {
  69. throw new InvalidOperationException("NativeLibraryConfig could be configured only once before any call to llama model apis.");
  70. }
  71. _useCuda = enable;
  72. return this;
  73. }
  74. /// <summary>
  75. /// Configure the prefferred avx support level of the backend.
  76. /// </summary>
  77. /// <param name="level"></param>
  78. /// <returns></returns>
  79. /// <exception cref="InvalidOperationException"></exception>
  80. public NativeLibraryConfig WithAvx(AvxLevel level)
  81. {
  82. if (LibraryHasLoaded)
  83. {
  84. throw new InvalidOperationException("NativeLibraryConfig could be configured only once before any call to llama model apis.");
  85. }
  86. _avxLevel = level;
  87. return this;
  88. }
  89. /// <summary>
  90. /// Configure whether to allow fallback when there's not match for preffered settings.
  91. /// </summary>
  92. /// <param name="enable"></param>
  93. /// <returns></returns>
  94. /// <exception cref="InvalidOperationException"></exception>
  95. public NativeLibraryConfig WithAutoFallback(bool enable = true)
  96. {
  97. if (LibraryHasLoaded)
  98. {
  99. throw new InvalidOperationException("NativeLibraryConfig could be configured only once before any call to llama model apis.");
  100. }
  101. _allowFallback = enable;
  102. return this;
  103. }
  104. /// <summary>
  105. /// Whether to skip the check when you don't allow fallback. This option
  106. /// may be useful under some complex conditions. For example, you're sure
  107. /// you have your cublas configured but LLamaSharp take it as invalid by mistake.
  108. /// </summary>
  109. /// <param name="enable"></param>
  110. /// <returns></returns>
  111. /// <exception cref="InvalidOperationException"></exception>
  112. public NativeLibraryConfig SkipCheck(bool enable = true)
  113. {
  114. if (LibraryHasLoaded)
  115. {
  116. throw new InvalidOperationException("NativeLibraryConfig could be configured only once before any call to llama model apis.");
  117. }
  118. _skipCheck = enable;
  119. return this;
  120. }
  121. /// <summary>
  122. /// Whether to output the logs to console when loading the native library with your configuration.
  123. /// </summary>
  124. /// <param name="enable"></param>
  125. /// <returns></returns>
  126. /// <exception cref="InvalidOperationException"></exception>
  127. public NativeLibraryConfig WithLogs(bool enable = true)
  128. {
  129. if (LibraryHasLoaded)
  130. {
  131. throw new InvalidOperationException("NativeLibraryConfig could be configured only once before any call to llama model apis.");
  132. }
  133. _logging = enable;
  134. return this;
  135. }
  136. internal static Description CheckAndGatherDescription()
  137. {
  138. if (Default._allowFallback && Default._skipCheck)
  139. {
  140. throw new ArgumentException("Cannot skip the check when fallback is allowed.");
  141. }
  142. return new Description(Default._libraryPath, Default._useCuda, Default._avxLevel, Default._allowFallback, Default._skipCheck, Default._logging);
  143. }
  144. internal static string AvxLevelToString(AvxLevel level)
  145. {
  146. return level switch
  147. {
  148. AvxLevel.None => string.Empty,
  149. AvxLevel.Avx => "avx",
  150. AvxLevel.Avx2 => "avx2",
  151. #if NET8_0_OR_GREATER
  152. AvxLevel.Avx512 => "avx512"
  153. #endif
  154. _ => throw new ArgumentException($"Cannot recognize Avx level {level}")
  155. };
  156. }
  157. private NativeLibraryConfig()
  158. {
  159. _libraryPath = string.Empty;
  160. _useCuda = true;
  161. _avxLevel = AvxLevel.Avx2;
  162. _allowFallback = true;
  163. _skipCheck = false;
  164. _logging = false;
  165. }
  166. /// <summary>
  167. /// Avx support configuration
  168. /// </summary>
  169. public enum AvxLevel
  170. {
  171. /// <inheritdoc />
  172. None = 0,
  173. /// <inheritdoc />
  174. Avx = 1,
  175. /// <inheritdoc />
  176. Avx2 = 2,
  177. #if NET8_0_OR_GREATER
  178. /// <inheritdoc />
  179. Avx512 = 3,
  180. #endif
  181. }
  182. internal record Description(string Path = "", bool UseCuda = true, AvxLevel AvxLevel = AvxLevel.Avx2,
  183. bool AllowFallback = true, bool SkipCheck = false, bool Logging = false);
  184. }
  185. #endif
  186. }