NvapiHelper.cs 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759
  1. using NTMiner.Gpus.Nvapi;
  2. using System;
  3. using System.Collections.Generic;
  4. namespace NTMiner.Gpus {
  5. public class NvapiHelper : IGpuHelper {
  6. public NvapiHelper() { }
  7. private static Dictionary<int, NvPhysicalGpuHandle> _handlesByBusId = null;
  8. private static readonly object _locker = new object();
  9. private static Dictionary<int, NvPhysicalGpuHandle> HandlesByBusId {
  10. get {
  11. if (_handlesByBusId != null) {
  12. return _handlesByBusId;
  13. }
  14. lock (_locker) {
  15. if (_handlesByBusId != null) {
  16. return _handlesByBusId;
  17. }
  18. _handlesByBusId = new Dictionary<int, NvPhysicalGpuHandle>();
  19. var handles = new NvPhysicalGpuHandle[NvapiConst.MAX_PHYSICAL_GPUS];
  20. var r = NvapiNativeMethods.NvEnumPhysicalGPUs(handles, out int gpuCount);
  21. if (r != NvStatus.NVAPI_OK) {
  22. NTMinerConsole.DevError(() => $"{nameof(NvapiNativeMethods.NvEnumPhysicalGPUs)} {r.ToString()}");
  23. }
  24. for (int i = 0; i < gpuCount; i++) {
  25. r = NvapiNativeMethods.NvGetBusID(handles[i], out int busId);
  26. if (r != NvStatus.NVAPI_OK) {
  27. NTMinerConsole.DevError(() => $"{nameof(NvapiNativeMethods.NvGetBusID)} {r.ToString()}");
  28. }
  29. if (!_handlesByBusId.ContainsKey(busId)) {
  30. _handlesByBusId.Add(busId, handles[i]);
  31. }
  32. }
  33. handles = new NvPhysicalGpuHandle[NvapiConst.MAX_PHYSICAL_GPUS];
  34. r = NvapiNativeMethods.NvEnumTCCPhysicalGPUs(handles, out gpuCount);
  35. if (r != NvStatus.NVAPI_OK) {
  36. NTMinerConsole.DevError(() => $"{nameof(NvapiNativeMethods.NvEnumTCCPhysicalGPUs)} {r.ToString()}");
  37. }
  38. for (int i = 0; i < gpuCount; i++) {
  39. r = NvapiNativeMethods.NvGetBusID(handles[i], out int busId);
  40. if (r != NvStatus.NVAPI_OK) {
  41. NTMinerConsole.DevError(() => $"{nameof(NvapiNativeMethods.NvGetBusID)} {r.ToString()}");
  42. }
  43. if (!_handlesByBusId.ContainsKey(busId)) {
  44. _handlesByBusId.Add(busId, handles[i]);
  45. }
  46. }
  47. return _handlesByBusId;
  48. }
  49. }
  50. }
  51. public OverClockRange GetClockRange(int busId) {
  52. OverClockRange result = new OverClockRange(busId);
  53. try {
  54. if (GetClockDelta(busId,
  55. out int outCoreCurrFreqDelta, out int outCoreMinFreqDelta, out int outCoreMaxFreqDelta,
  56. out int outMemoryCurrFreqDelta, out int outMemoryMinFreqDelta, out int outMemoryMaxFreqDelta)) {
  57. result.CoreClockMin = outCoreMinFreqDelta;
  58. result.CoreClockMax = outCoreMaxFreqDelta;
  59. result.CoreClockDelta = outCoreCurrFreqDelta;
  60. result.MemoryClockMin = outMemoryMinFreqDelta;
  61. result.MemoryClockMax = outMemoryMaxFreqDelta;
  62. result.MemoryClockDelta = outMemoryCurrFreqDelta;
  63. }
  64. if (GetPowerLimit(busId, out uint outCurrPower, out uint outMinPower, out uint outDefPower, out uint outMaxPower)) {
  65. result.PowerMin = (int)outMinPower;
  66. result.PowerMax = (int)outMaxPower;
  67. result.PowerDefault = (int)outDefPower;
  68. result.PowerCurr = (int)outCurrPower;
  69. }
  70. if (GetTempLimit(busId, out int outCurrTemp, out int outMinTemp, out int outDefTemp, out int outMaxTemp)) {
  71. result.TempLimitMin = outMinTemp;
  72. result.TempLimitMax = outMaxTemp;
  73. result.TempLimitDefault = outDefTemp;
  74. result.TempCurr = outCurrTemp;
  75. }
  76. if (GetCooler(busId, out uint minCooler, out uint currCooler, out uint maxCooler)) {
  77. result.FanSpeedCurr = (int)currCooler;
  78. result.FanSpeedMin = (int)minCooler;
  79. result.FanSpeedMax = (int)maxCooler;
  80. }
  81. #if DEBUG
  82. NTMinerConsole.DevWarn(() => $"GetClockRange {result.ToString()}");
  83. #endif
  84. }
  85. catch (Exception e) {
  86. Logger.ErrorDebugLine(e);
  87. }
  88. return result;
  89. }
  90. public bool SetCoreClock(int busId, int mHz, int voltage) {
  91. int kHz = mHz * 1000;
  92. try {
  93. if (NvGetPStateV2(busId, out NvGpuPerfPStates20InfoV2 info)) {
  94. info.numPStates = 1;
  95. info.numClocks = 1;
  96. info.pstates[0].clocks[0].domainId = NvGpuPublicClockId.NVAPI_GPU_PUBLIC_CLOCK_GRAPHICS;
  97. info.pstates[0].clocks[0].typeId = NvGpuPerfPState20ClockTypeId.NVAPI_GPU_PERF_PSTATE20_CLOCK_TYPE_SINGLE;
  98. info.pstates[0].clocks[0].freqDelta_kHz.value = kHz;
  99. var r = NvSetPStateV2(busId, ref info);
  100. if (!r) {
  101. NTMinerConsole.DevError(() => $"{nameof(SetCoreClock)} {r.ToString()}");
  102. }
  103. }
  104. return false;
  105. }
  106. catch {
  107. }
  108. return false;
  109. }
  110. public bool SetMemoryClock(int busId, int mHz, int voltage) {
  111. int kHz = mHz * 1000;
  112. try {
  113. if (NvGetPStateV2(busId, out NvGpuPerfPStates20InfoV2 info)) {
  114. info.numPStates = 1;
  115. info.numClocks = 1;
  116. info.numBaseVoltages = 0;
  117. info.pstates[0].clocks[0].domainId = NvGpuPublicClockId.NVAPI_GPU_PUBLIC_CLOCK_MEMORY;
  118. info.pstates[0].clocks[0].typeId = NvGpuPerfPState20ClockTypeId.NVAPI_GPU_PERF_PSTATE20_CLOCK_TYPE_SINGLE;
  119. info.pstates[0].clocks[0].freqDelta_kHz.value = kHz;
  120. var r = NvSetPStateV2(busId, ref info);
  121. if (!r) {
  122. NTMinerConsole.DevError(() => $"{nameof(SetMemoryClock)} {r.ToString()}");
  123. }
  124. }
  125. return false;
  126. }
  127. catch {
  128. }
  129. return false;
  130. }
  131. public bool SetTempLimit(int busId, int value) {
  132. value <<= 8;
  133. try {
  134. if (!NvThermalPoliciesGetInfo(busId, out NvGpuThermalInfo info)) {
  135. return false;
  136. }
  137. if (value == 0) {
  138. value = info.entries[0].def_temp;
  139. }
  140. else if (value > info.entries[0].max_temp) {
  141. value = info.entries[0].max_temp;
  142. }
  143. else if (value < info.entries[0].min_temp) {
  144. value = info.entries[0].min_temp;
  145. }
  146. NvGpuThermalLimit limit = NvThermalPoliciesGetLimit(busId);
  147. limit.flags = 1;
  148. limit.entries[0].value = (uint)value;
  149. return NvThermalPoliciesSetLimit(busId, ref limit);
  150. }
  151. catch {
  152. }
  153. return false;
  154. }
  155. public bool GetPowerPoliciesInfo(int busId, out uint minPower, out uint defPower, out uint maxPower) {
  156. minPower = 0;
  157. defPower = 0;
  158. maxPower = 0;
  159. if (NvPowerPoliciesGetInfo(busId, out NvGpuPowerInfo info)) {
  160. if (info.valid == 1 && info.count > 0) {
  161. minPower = info.entries[0].min_power;
  162. defPower = info.entries[0].def_power;
  163. maxPower = info.entries[0].max_power;
  164. return true;
  165. }
  166. }
  167. return false;
  168. }
  169. public bool SetPowerValue(int busId, uint percentInt) {
  170. try {
  171. if (GetPowerPoliciesInfo(busId, out uint minPower, out uint defPower, out uint maxPower)) {
  172. if (percentInt == 0) {
  173. percentInt = defPower;
  174. }
  175. else if (percentInt < minPower) {
  176. percentInt = minPower;
  177. }
  178. else if (percentInt > maxPower) {
  179. percentInt = maxPower;
  180. }
  181. if (NvPowerPoliciesGetStatus(busId, out NvGpuPowerStatus info)) {
  182. info.flags = 1;
  183. info.entries[0].power = percentInt;
  184. return NvPowerPoliciesSetStatus(busId, ref info);
  185. }
  186. return false;
  187. }
  188. }
  189. catch {
  190. }
  191. return false;
  192. }
  193. public bool GetPowerLimit(int busId, out uint outCurrPower, out uint outMinPower, out uint outDefPower, out uint outMaxPower) {
  194. outCurrPower = 0;
  195. outMinPower = 0;
  196. outDefPower = 0;
  197. outMaxPower = 0;
  198. try {
  199. if (GetPowerPoliciesInfo(busId, out outMinPower, out outDefPower, out outMaxPower)) {
  200. if (NvPowerPoliciesGetStatus(busId, out NvGpuPowerStatus info)) {
  201. outCurrPower = info.entries[0].power;
  202. outCurrPower /= 1000;
  203. outMinPower /= 1000;
  204. outDefPower /= 1000;
  205. outMaxPower /= 1000;
  206. return true;
  207. }
  208. }
  209. return false;
  210. }
  211. catch {
  212. return false;
  213. }
  214. }
  215. public bool SetPowerLimit(int busId, int powerValue) {
  216. powerValue *= 1000;
  217. return SetPowerValue(busId, (uint)powerValue);
  218. }
  219. public bool GetFanSpeed(int busId, out uint currCooler) {
  220. if (GetCooler(busId, out _, out currCooler, out _)) {
  221. return true;
  222. }
  223. return false;
  224. }
  225. public bool SetFanSpeed(int busId, int value, bool isAutoMode) {
  226. return SetCooler(busId, (uint)value, isAutoMode);
  227. }
  228. #region private methods
  229. private bool NvPowerPoliciesSetStatus(int busId, ref NvGpuPowerStatus info) {
  230. if (NvapiNativeMethods.NvPowerPoliciesSetStatus == null) {
  231. return false;
  232. }
  233. try {
  234. if (!HandlesByBusId.TryGetValue(busId, out NvPhysicalGpuHandle handle)) {
  235. return false;
  236. }
  237. var r = NvapiNativeMethods.NvPowerPoliciesSetStatus(handle, ref info);
  238. if (r != NvStatus.NVAPI_OK) {
  239. NTMinerConsole.DevError(() => $"{nameof(NvapiNativeMethods.NvPowerPoliciesSetStatus)} {r.ToString()}");
  240. }
  241. if (r == NvStatus.NVAPI_OK) {
  242. return true;
  243. }
  244. }
  245. catch {
  246. }
  247. return false;
  248. }
  249. private bool GetClockDelta(int busId,
  250. out int outCoreCurrFreqDelta, out int outCoreMinFreqDelta, out int outCoreMaxFreqDelta,
  251. out int outMemoryCurrFreqDelta, out int outMemoryMinFreqDelta, out int outMemoryMaxFreqDelta) {
  252. outCoreCurrFreqDelta = 0;
  253. outCoreMinFreqDelta = 0;
  254. outCoreMaxFreqDelta = 0;
  255. outMemoryCurrFreqDelta = 0;
  256. outMemoryMinFreqDelta = 0;
  257. outMemoryMaxFreqDelta = 0;
  258. try {
  259. bool isCoreClockPicked = false;
  260. bool isMemoryClockPicked = false;
  261. if (NvGetPStateV2(busId, out NvGpuPerfPStates20InfoV2 info)) {
  262. for (int i = 0; i < info.numPStates; i++) {
  263. for (int j = 0; j < info.numClocks; j++) {
  264. uint min = info.pstates[i].clocks[j].data.minFreq_kHz;
  265. uint max = info.pstates[i].clocks[j].data.maxFreq_kHz;
  266. var domainId = info.pstates[i].clocks[j].domainId;
  267. if (!isCoreClockPicked && domainId == NvGpuPublicClockId.NVAPI_GPU_PUBLIC_CLOCK_GRAPHICS && min > 0 && max > 0) {
  268. outCoreCurrFreqDelta = info.pstates[i].clocks[j].freqDelta_kHz.value;
  269. outCoreMinFreqDelta = info.pstates[i].clocks[j].freqDelta_kHz.mindelta;
  270. outCoreMaxFreqDelta = info.pstates[i].clocks[j].freqDelta_kHz.maxdelta;
  271. isCoreClockPicked = true;
  272. }
  273. if (!isMemoryClockPicked && domainId == NvGpuPublicClockId.NVAPI_GPU_PUBLIC_CLOCK_MEMORY && min > 0 && max > 0) {
  274. outMemoryCurrFreqDelta = info.pstates[i].clocks[j].freqDelta_kHz.value;
  275. outMemoryMinFreqDelta = info.pstates[i].clocks[j].freqDelta_kHz.mindelta;
  276. outMemoryMaxFreqDelta = info.pstates[i].clocks[j].freqDelta_kHz.maxdelta;
  277. isMemoryClockPicked = true;
  278. }
  279. if (isCoreClockPicked && isMemoryClockPicked) {
  280. return true;
  281. }
  282. }
  283. }
  284. }
  285. return false;
  286. }
  287. catch (Exception e){
  288. Logger.ErrorDebugLine(e);
  289. return false;
  290. }
  291. }
  292. private bool NvGetPStateV1(int busId, out NvGpuPerfPStates20InfoV1 info) {
  293. info = NvGpuPerfPStates20InfoV1.Create();
  294. if (NvapiNativeMethods.NvGetPStateV1 == null) {
  295. return false;
  296. }
  297. try {
  298. if (!HandlesByBusId.TryGetValue(busId, out NvPhysicalGpuHandle handle)) {
  299. return false;
  300. }
  301. var r = NvapiNativeMethods.NvGetPStateV1(handle, ref info);
  302. if (r != NvStatus.NVAPI_OK) {
  303. NTMinerConsole.DevError(() => $"{nameof(NvapiNativeMethods.NvGetPStateV1)} {r.ToString()}");
  304. return false;
  305. }
  306. return true;
  307. }
  308. catch (Exception e) {
  309. Logger.ErrorDebugLine(e);
  310. return false;
  311. }
  312. }
  313. private bool NvGetPStateV2(int busId, out NvGpuPerfPStates20InfoV2 info) {
  314. info = NvGpuPerfPStates20InfoV2.Create();
  315. if (NvapiNativeMethods.NvGetPStateV2 == null) {
  316. return false;
  317. }
  318. try {
  319. if (!HandlesByBusId.TryGetValue(busId, out NvPhysicalGpuHandle handle)) {
  320. return false;
  321. }
  322. var r = NvapiNativeMethods.NvGetPStateV2(handle, ref info);
  323. if (r != NvStatus.NVAPI_OK) {
  324. NTMinerConsole.DevError(() => $"{nameof(NvapiNativeMethods.NvGetPStateV2)} {r.ToString()}");
  325. return false;
  326. }
  327. return true;
  328. }
  329. catch (Exception e) {
  330. Logger.ErrorDebugLine(e);
  331. return false;
  332. }
  333. }
  334. private bool NvSetPStateV2(int busId, ref NvGpuPerfPStates20InfoV2 info) {
  335. if (NvapiNativeMethods.NvSetPStateV2 == null) {
  336. return false;
  337. }
  338. try {
  339. if (!HandlesByBusId.TryGetValue(busId, out NvPhysicalGpuHandle handle)) {
  340. return false;
  341. }
  342. var r = NvapiNativeMethods.NvSetPStateV2(handle, ref info);
  343. if (r != NvStatus.NVAPI_OK) {
  344. NTMinerConsole.DevError(() => $"{nameof(NvapiNativeMethods.NvSetPStateV2)} {r.ToString()}");
  345. }
  346. if (r == NvStatus.NVAPI_OK) {
  347. return true;
  348. }
  349. }
  350. catch {
  351. }
  352. return false;
  353. }
  354. private bool NvSetPStateV1(int busId, ref NvGpuPerfPStates20InfoV1 info) {
  355. if (NvapiNativeMethods.NvSetPStateV1 == null) {
  356. return false;
  357. }
  358. try {
  359. if (!HandlesByBusId.TryGetValue(busId, out NvPhysicalGpuHandle handle)) {
  360. return false;
  361. }
  362. var r = NvapiNativeMethods.NvSetPStateV1(handle, ref info);
  363. if (r != NvStatus.NVAPI_OK) {
  364. NTMinerConsole.DevError(() => $"{nameof(NvapiNativeMethods.NvSetPStateV1)} {r.ToString()}");
  365. }
  366. if (r == NvStatus.NVAPI_OK) {
  367. return true;
  368. }
  369. }
  370. catch {
  371. }
  372. return false;
  373. }
  374. private NvGpuClockFrequenciesV2 NvGetAllClockFrequenciesV2(int busId, uint type) {
  375. NvGpuClockFrequenciesV2 info = NvGpuClockFrequenciesV2.Create();
  376. if (NvapiNativeMethods.NvGetAllClockFrequenciesV2 == null) {
  377. return info;
  378. }
  379. try {
  380. if (!HandlesByBusId.TryGetValue(busId, out NvPhysicalGpuHandle handle)) {
  381. return info;
  382. }
  383. info.ClockType = type;
  384. var r = NvapiNativeMethods.NvGetAllClockFrequenciesV2(handle, ref info);
  385. if (r != NvStatus.NVAPI_OK) {
  386. NTMinerConsole.DevError(() => $"{nameof(NvapiNativeMethods.NvGetAllClockFrequenciesV2)} {r.ToString()}");
  387. }
  388. if (r == NvStatus.NVAPI_OK) {
  389. return info;
  390. }
  391. }
  392. catch {
  393. }
  394. return info;
  395. }
  396. private uint NvGetAllClockFrequenciesV2(int busId, uint clockId, uint clockType) {
  397. try {
  398. NvGpuClockFrequenciesV2 info = NvGetAllClockFrequenciesV2(busId, clockType);
  399. if (clockId < info.domain.Length) {
  400. NvGpuClockRrequenciesDomain domain = info.domain[clockId];
  401. if (domain.bIsPresent == 1 && info.ClockType == clockType) {
  402. return domain.frequency;
  403. }
  404. }
  405. }
  406. catch {
  407. }
  408. return 0;
  409. }
  410. private bool NvThermalPoliciesGetInfo(int busId, out NvGpuThermalInfo info) {
  411. info = NvGpuThermalInfo.Create();
  412. if (NvapiNativeMethods.NvThermalPoliciesGetInfo == null) {
  413. return false;
  414. }
  415. try {
  416. if (!HandlesByBusId.TryGetValue(busId, out NvPhysicalGpuHandle handle)) {
  417. return false;
  418. }
  419. var r = NvapiNativeMethods.NvThermalPoliciesGetInfo(handle, ref info);
  420. if (r != NvStatus.NVAPI_OK) {
  421. NTMinerConsole.DevError(() => $"{nameof(NvapiNativeMethods.NvThermalPoliciesGetInfo)} {r.ToString()}");
  422. return false;
  423. }
  424. return true;
  425. }
  426. catch {
  427. return false;
  428. }
  429. }
  430. private NvGpuThermalLimit NvThermalPoliciesGetLimit(int busId) {
  431. NvGpuThermalLimit info = NvGpuThermalLimit.Create();
  432. if (NvapiNativeMethods.NvThermalPoliciesGetLimit == null) {
  433. return info;
  434. }
  435. try {
  436. if (!HandlesByBusId.TryGetValue(busId, out NvPhysicalGpuHandle handle)) {
  437. return info;
  438. }
  439. var r = NvapiNativeMethods.NvThermalPoliciesGetLimit(handle, ref info);
  440. if (r != NvStatus.NVAPI_OK) {
  441. NTMinerConsole.DevError(() => $"{nameof(NvapiNativeMethods.NvThermalPoliciesGetLimit)} {r.ToString()}");
  442. }
  443. if (r == NvStatus.NVAPI_OK) {
  444. return info;
  445. }
  446. }
  447. catch {
  448. }
  449. return info;
  450. }
  451. private bool NvThermalPoliciesSetLimit(int busId, ref NvGpuThermalLimit info) {
  452. if (NvapiNativeMethods.NvThermalPoliciesSetLimit == null) {
  453. return false;
  454. }
  455. try {
  456. if (!HandlesByBusId.TryGetValue(busId, out NvPhysicalGpuHandle handle)) {
  457. return false;
  458. }
  459. var r = NvapiNativeMethods.NvThermalPoliciesSetLimit(handle, ref info);
  460. if (r != NvStatus.NVAPI_OK) {
  461. NTMinerConsole.DevError(() => $"{nameof(NvapiNativeMethods.NvThermalPoliciesSetLimit)} {r.ToString()}");
  462. }
  463. if (r == NvStatus.NVAPI_OK) {
  464. return true;
  465. }
  466. }
  467. catch {
  468. }
  469. return false;
  470. }
  471. private bool GetThermalInfo(int busId, out int minThermal, out int defThermal, out int maxThermal) {
  472. minThermal = 0;
  473. defThermal = 0;
  474. maxThermal = 0;
  475. try {
  476. var r = NvThermalPoliciesGetInfo(busId, out NvGpuThermalInfo info);
  477. minThermal = info.entries[0].min_temp / (1 << 8);
  478. defThermal = info.entries[0].def_temp / (1 << 8);
  479. maxThermal = info.entries[0].max_temp / (1 << 8);
  480. return r;
  481. }
  482. catch {
  483. return false;
  484. }
  485. }
  486. private bool GetTempLimit(int busId, out int outCurrTemp, out int outMinTemp, out int outDefTemp, out int outMaxTemp) {
  487. outCurrTemp = 0;
  488. outMinTemp = 0;
  489. outDefTemp = 0;
  490. outMaxTemp = 0;
  491. try {
  492. var r = GetThermalInfo(busId, out outMinTemp, out outDefTemp, out outMaxTemp);
  493. NvGpuThermalLimit limit = NvThermalPoliciesGetLimit(busId);
  494. outCurrTemp = (int)(limit.entries[0].value / 256);
  495. return r;
  496. }
  497. catch {
  498. return false;
  499. }
  500. }
  501. private void SetDefaultTempLimit(int busId) {
  502. if (GetTempLimit(busId, out _, out _, out int defValue, out _)) {
  503. SetTempLimit(busId, defValue);
  504. }
  505. }
  506. private bool NvPowerPoliciesGetStatus(int busId, out NvGpuPowerStatus info) {
  507. info = NvGpuPowerStatus.Create();
  508. if (NvapiNativeMethods.NvPowerPoliciesGetStatus == null) {
  509. return false;
  510. }
  511. try {
  512. if (!HandlesByBusId.TryGetValue(busId, out NvPhysicalGpuHandle handle)) {
  513. return false;
  514. }
  515. var r = NvapiNativeMethods.NvPowerPoliciesGetStatus(handle, ref info);
  516. if (r != NvStatus.NVAPI_OK) {
  517. NTMinerConsole.DevError(() => $"{nameof(NvapiNativeMethods.NvPowerPoliciesGetStatus)} {r.ToString()}");
  518. return false;
  519. }
  520. return true;
  521. }
  522. catch {
  523. }
  524. return false;
  525. }
  526. private double GetPowerPercent(int busId) {
  527. try {
  528. if (NvPowerPoliciesGetStatus(busId, out NvGpuPowerStatus info)) {
  529. return (info.entries[0].power / 1000) / 100.0;
  530. }
  531. return 1.0;
  532. }
  533. catch {
  534. }
  535. return 1.0;
  536. }
  537. private bool NvPowerPoliciesGetInfo(int busId, out NvGpuPowerInfo info) {
  538. info = NvGpuPowerInfo.Create();
  539. if (NvapiNativeMethods.NvPowerPoliciesGetInfo == null) {
  540. return false;
  541. }
  542. try {
  543. if (!HandlesByBusId.TryGetValue(busId, out NvPhysicalGpuHandle handle)) {
  544. return false;
  545. }
  546. var r = NvapiNativeMethods.NvPowerPoliciesGetInfo(handle, ref info);
  547. if (r != NvStatus.NVAPI_OK) {
  548. NTMinerConsole.DevError(() => $"{nameof(NvapiNativeMethods.NvPowerPoliciesGetInfo)} {r.ToString()}");
  549. return false;
  550. }
  551. return true;
  552. }
  553. catch {
  554. return false;
  555. }
  556. }
  557. private bool SetDefaultPowerLimit(int busId) {
  558. if (GetPowerLimit(busId, out _, out _, out uint defPower, out _)) {
  559. return SetPowerValue(busId, defPower * 1000);
  560. }
  561. return false;
  562. }
  563. private readonly HashSet<int> _nvFanCoolersGetStatusNotSupporteds = new HashSet<int>();
  564. private bool GetFanCoolersGetStatus(int busId, out PrivateFanCoolersStatusV1 info) {
  565. info = PrivateFanCoolersStatusV1.Create();
  566. if (NvapiNativeMethods.NvFanCoolersGetStatus == null) {
  567. return false;
  568. }
  569. if (_nvFanCoolersGetStatusNotSupporteds.Contains(busId)) {
  570. return false;
  571. }
  572. try {
  573. if (!HandlesByBusId.TryGetValue(busId, out NvPhysicalGpuHandle handle)) {
  574. return false;
  575. }
  576. var r = NvapiNativeMethods.NvFanCoolersGetStatus(handle, ref info);
  577. if (r != NvStatus.NVAPI_OK) {
  578. if (r == NvStatus.NVAPI_NOT_SUPPORTED || r == NvStatus.NVAPI_FIRMWARE_REVISION_NOT_SUPPORTED) {
  579. _nvFanCoolersGetStatusNotSupporteds.Add(busId);
  580. }
  581. NTMinerConsole.DevError(() => $"{nameof(NvapiNativeMethods.NvFanCoolersGetStatus)} {r.ToString()}");
  582. return false;
  583. }
  584. return true;
  585. }
  586. catch {
  587. }
  588. return false;
  589. }
  590. private readonly HashSet<int> _nvGetCoolerSettingsNotSupporteds = new HashSet<int>();
  591. private bool GetCoolerSettings(int busId, out NvCoolerSettings info) {
  592. info = NvCoolerSettings.Create();
  593. if (NvapiNativeMethods.NvGetCoolerSettings == null) {
  594. return false;
  595. }
  596. if (_nvGetCoolerSettingsNotSupporteds.Contains(busId)) {
  597. return false;
  598. }
  599. try {
  600. if (!HandlesByBusId.TryGetValue(busId, out NvPhysicalGpuHandle handle)) {
  601. return false;
  602. }
  603. NvCoolerTarget coolerIndex = NvCoolerTarget.NVAPI_COOLER_TARGET_ALL;
  604. var r = NvapiNativeMethods.NvGetCoolerSettings(handle, coolerIndex, ref info);
  605. if (r != NvStatus.NVAPI_OK) {
  606. if (r == NvStatus.NVAPI_NOT_SUPPORTED || r == NvStatus.NVAPI_FIRMWARE_REVISION_NOT_SUPPORTED || r == NvStatus.NVAPI_GPU_NOT_POWERED) {
  607. _nvGetCoolerSettingsNotSupporteds.Add(busId);
  608. }
  609. NTMinerConsole.DevError(() => $"{nameof(NvapiNativeMethods.NvGetCoolerSettings)} {r.ToString()}");
  610. return false;
  611. }
  612. return true;
  613. }
  614. catch {
  615. }
  616. return false;
  617. }
  618. private bool NvFanCoolersGetControl(int busId, out PrivateFanCoolersControlV1 info) {
  619. info = PrivateFanCoolersControlV1.Create();
  620. if (NvapiNativeMethods.NvFanCoolersGetControl == null) {
  621. return false;
  622. }
  623. try {
  624. if (!HandlesByBusId.TryGetValue(busId, out NvPhysicalGpuHandle handle)) {
  625. return false;
  626. }
  627. var r = NvapiNativeMethods.NvFanCoolersGetControl(handle, ref info);
  628. if (r != NvStatus.NVAPI_OK) {
  629. NTMinerConsole.DevError(() => $"{nameof(NvapiNativeMethods.NvFanCoolersGetControl)} {r.ToString()}");
  630. return false;
  631. }
  632. return true;
  633. }
  634. catch {
  635. }
  636. return false;
  637. }
  638. private bool SetCooler(int busId, uint value, bool isAutoMode) {
  639. if (!HandlesByBusId.TryGetValue(busId, out NvPhysicalGpuHandle handle)) {
  640. return false;
  641. }
  642. #region GTX
  643. if (NvapiNativeMethods.NvSetCoolerLevels != null) {
  644. try {
  645. NvCoolerTarget coolerIndex = NvCoolerTarget.NVAPI_COOLER_TARGET_ALL;
  646. NvCoolerLevel info = NvCoolerLevel.Create();
  647. info.coolers[0].currentLevel = isAutoMode ? 0 : value;
  648. info.coolers[0].currentPolicy = isAutoMode ? NvCoolerPolicy.NVAPI_COOLER_POLICY_AUTO : NvCoolerPolicy.NVAPI_COOLER_POLICY_MANUAL;
  649. var r = NvapiNativeMethods.NvSetCoolerLevels(handle, coolerIndex, ref info);
  650. if (r != NvStatus.NVAPI_OK) {
  651. NTMinerConsole.DevError(() => $"{nameof(NvapiNativeMethods.NvSetCoolerLevels)} {r.ToString()}");
  652. }
  653. else {
  654. return true;
  655. }
  656. }
  657. catch {
  658. }
  659. }
  660. #endregion
  661. #region RTX
  662. if (NvapiNativeMethods.NvFanCoolersSetControl == null) {
  663. return false;
  664. }
  665. try {
  666. if (NvFanCoolersGetControl(busId, out PrivateFanCoolersControlV1 info)) {
  667. for (int i = 0; i < info.FanCoolersControlCount; i++) {
  668. info.FanCoolersControlEntries[i].ControlMode = isAutoMode ? FanCoolersControlMode.Auto : FanCoolersControlMode.Manual;
  669. info.FanCoolersControlEntries[i].Level = isAutoMode ? 0u : (uint)value;
  670. }
  671. var r = NvapiNativeMethods.NvFanCoolersSetControl(handle, ref info);
  672. if (r != NvStatus.NVAPI_OK) {
  673. NTMinerConsole.DevError(() => $"{nameof(NvapiNativeMethods.NvFanCoolersSetControl)} {r.ToString()}");
  674. return false;
  675. }
  676. return true;
  677. }
  678. return false;
  679. }
  680. catch (Exception e) {
  681. Logger.ErrorDebugLine(e);
  682. return false;
  683. }
  684. #endregion
  685. }
  686. private bool GetCooler(int busId, out uint minCooler, out uint currCooler, out uint maxCooler) {
  687. currCooler = 0;
  688. minCooler = 0;
  689. maxCooler = 0;
  690. try {
  691. if (GetFanCoolersGetStatus(busId, out PrivateFanCoolersStatusV1 v1)) {
  692. if (v1.FanCoolersStatusCount > 0) {
  693. minCooler = v1.FanCoolersStatusEntries[0].CurrentMinimumLevel;
  694. currCooler = v1.FanCoolersStatusEntries[0].CurrentLevel;
  695. maxCooler = v1.FanCoolersStatusEntries[0].CurrentMaximumLevel;
  696. return true;
  697. }
  698. }
  699. if (GetCoolerSettings(busId, out NvCoolerSettings info)) {
  700. if (info.count > 0) {
  701. minCooler = info.cooler[0].currentMinLevel;
  702. currCooler = info.cooler[0].currentLevel;
  703. maxCooler = info.cooler[0].currentMaxLevel;
  704. return true;
  705. }
  706. }
  707. }
  708. catch (Exception e) {
  709. Logger.ErrorDebugLine(e);
  710. }
  711. return false;
  712. }
  713. #endregion
  714. }
  715. }