diff --git a/NiceHashMiner.sln b/NiceHashMiner.sln index 6db0cc88d..c0975765f 100644 --- a/NiceHashMiner.sln +++ b/NiceHashMiner.sln @@ -14,8 +14,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Miners", "Miners", "{F40126 EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tools", "Tools", "{BB931C9A-EE48-42A6-B5F3-3A193B1A051A}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MP.NBMiner", "src\Miners\NBMiner\MP.NBMiner.csproj", "{A4B0CDCB-D1D7-4563-9888-D58E0B36D0F8}" -EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MinerProcessCounter", "src\Tools\MinerProcessCounter\MinerProcessCounter.csproj", "{69B58028-8F30-4D3F-8E51-DEF85C08E4CC}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CreateLogReport", "src\Tools\CreateLogReport\CreateLogReport.csproj", "{663285C0-8F68-4638-BEB2-4BB042868445}" @@ -34,8 +32,6 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "runnhmasadmin", "src\Tools\ EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NiceHashMiner", "src\NiceHashMiner\NiceHashMiner.csproj", "{56653651-3BF1-4A89-A20C-3178C06A29A3}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MP.XMRig", "src\Miners\XMRig\MP.XMRig.csproj", "{850CBE9E-AB73-4C24-AFBD-2FA4911E07B5}" -EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NHMCore", "src\NHMCore\NHMCore.csproj", "{43DCAF38-D0C4-4335-983D-650F78461EB2}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NiceHashMinerLauncher", "src\NiceHashMinerLauncher\NiceHashMinerLauncher.csproj", "{674DECD6-9BC3-4BA7-B0AE-4C2EA7D74C51}" @@ -80,7 +76,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CrowdinTranslationsConverte EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AssemblyInfoVersionManager", "src\Tools\AssemblyInfoVersionManager\AssemblyInfoVersionManager.csproj", "{A1481D50-D481-409C-BF07-C44F9AF1DD51}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MP.GMiner", "src\Miners\GMiner\MP.GMiner.csproj", "{72746BBD-6A91-4441-87AA-8EFE4B2DA7BB}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MP.GMiner", "src\Miners\GMiner\MP.GMiner.csproj", "{72746BBD-6A91-4441-87AA-8EFE4B2DA7BB}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -98,14 +94,6 @@ Global {279A5B29-3799-43FA-9734-E462E046BA81}.Release|Any CPU.Build.0 = Release|Any CPU {279A5B29-3799-43FA-9734-E462E046BA81}.Release|x64.ActiveCfg = Release|Any CPU {279A5B29-3799-43FA-9734-E462E046BA81}.Release|x64.Build.0 = Release|Any CPU - {A4B0CDCB-D1D7-4563-9888-D58E0B36D0F8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {A4B0CDCB-D1D7-4563-9888-D58E0B36D0F8}.Debug|Any CPU.Build.0 = Debug|Any CPU - {A4B0CDCB-D1D7-4563-9888-D58E0B36D0F8}.Debug|x64.ActiveCfg = Debug|Any CPU - {A4B0CDCB-D1D7-4563-9888-D58E0B36D0F8}.Debug|x64.Build.0 = Debug|Any CPU - {A4B0CDCB-D1D7-4563-9888-D58E0B36D0F8}.Release|Any CPU.ActiveCfg = Release|Any CPU - {A4B0CDCB-D1D7-4563-9888-D58E0B36D0F8}.Release|Any CPU.Build.0 = Release|Any CPU - {A4B0CDCB-D1D7-4563-9888-D58E0B36D0F8}.Release|x64.ActiveCfg = Release|Any CPU - {A4B0CDCB-D1D7-4563-9888-D58E0B36D0F8}.Release|x64.Build.0 = Release|Any CPU {69B58028-8F30-4D3F-8E51-DEF85C08E4CC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {69B58028-8F30-4D3F-8E51-DEF85C08E4CC}.Debug|Any CPU.Build.0 = Debug|Any CPU {69B58028-8F30-4D3F-8E51-DEF85C08E4CC}.Debug|x64.ActiveCfg = Debug|Any CPU @@ -178,14 +166,6 @@ Global {56653651-3BF1-4A89-A20C-3178C06A29A3}.Release|Any CPU.Build.0 = Release|Any CPU {56653651-3BF1-4A89-A20C-3178C06A29A3}.Release|x64.ActiveCfg = Release|Any CPU {56653651-3BF1-4A89-A20C-3178C06A29A3}.Release|x64.Build.0 = Release|Any CPU - {850CBE9E-AB73-4C24-AFBD-2FA4911E07B5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {850CBE9E-AB73-4C24-AFBD-2FA4911E07B5}.Debug|Any CPU.Build.0 = Debug|Any CPU - {850CBE9E-AB73-4C24-AFBD-2FA4911E07B5}.Debug|x64.ActiveCfg = Debug|Any CPU - {850CBE9E-AB73-4C24-AFBD-2FA4911E07B5}.Debug|x64.Build.0 = Debug|Any CPU - {850CBE9E-AB73-4C24-AFBD-2FA4911E07B5}.Release|Any CPU.ActiveCfg = Release|Any CPU - {850CBE9E-AB73-4C24-AFBD-2FA4911E07B5}.Release|Any CPU.Build.0 = Release|Any CPU - {850CBE9E-AB73-4C24-AFBD-2FA4911E07B5}.Release|x64.ActiveCfg = Release|Any CPU - {850CBE9E-AB73-4C24-AFBD-2FA4911E07B5}.Release|x64.Build.0 = Release|Any CPU {43DCAF38-D0C4-4335-983D-650F78461EB2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {43DCAF38-D0C4-4335-983D-650F78461EB2}.Debug|Any CPU.Build.0 = Debug|Any CPU {43DCAF38-D0C4-4335-983D-650F78461EB2}.Debug|x64.ActiveCfg = Debug|Any CPU @@ -367,12 +347,10 @@ Global HideSolutionNode = FALSE EndGlobalSection GlobalSection(NestedProjects) = preSolution - {A4B0CDCB-D1D7-4563-9888-D58E0B36D0F8} = {F40126B4-5B3B-4085-B47D-A5EF4B51570C} {69B58028-8F30-4D3F-8E51-DEF85C08E4CC} = {BB931C9A-EE48-42A6-B5F3-3A193B1A051A} {663285C0-8F68-4638-BEB2-4BB042868445} = {BB931C9A-EE48-42A6-B5F3-3A193B1A051A} {1B657592-641E-42EC-BC44-ABCAE62EF1FD} = {F40126B4-5B3B-4085-B47D-A5EF4B51570C} {3712894A-0836-4CE3-A4A9-C21A32AACBEC} = {BB931C9A-EE48-42A6-B5F3-3A193B1A051A} - {850CBE9E-AB73-4C24-AFBD-2FA4911E07B5} = {F40126B4-5B3B-4085-B47D-A5EF4B51570C} {ED4101C4-C44E-4C6C-8F93-73A950388823} = {BB931C9A-EE48-42A6-B5F3-3A193B1A051A} {FBB69B33-8A14-4087-909C-F33791384D35} = {F40126B4-5B3B-4085-B47D-A5EF4B51570C} {E9A55CE7-37B9-462F-92E8-AE929C5ADCCA} = {F40126B4-5B3B-4085-B47D-A5EF4B51570C} diff --git a/doc/UserPlugins/09.png b/doc/UserPlugins/09.png new file mode 100644 index 000000000..f7be1b0a0 Binary files /dev/null and b/doc/UserPlugins/09.png differ diff --git a/doc/UserPlugins/10.png b/doc/UserPlugins/10.png new file mode 100644 index 000000000..38abe3081 Binary files /dev/null and b/doc/UserPlugins/10.png differ diff --git a/doc/UserPlugins/README.md b/doc/UserPlugins/README.md index dd84d9545..94fa4fd07 100644 --- a/doc/UserPlugins/README.md +++ b/doc/UserPlugins/README.md @@ -7,21 +7,21 @@ NiceHash Miner from version 3.0.7.0 supports generic plugins for experimental pu ## #1 Generating generic plugin files -### 1 First, navigate to the **NiceHash Miner root directory > internals > UserMinerPlugins.json**
+### 1. First, navigate to the **NiceHash Miner root directory > internals > UserMinerPlugins.json**
-### 2 Add a plugin name here, we will use **ExamplePlugin**.
+### 2. Add a plugin name here, we will use **ExamplePlugin**.
-### 3 Start NiceHash Miner for the files to be created automatically. Close NiceHash Miner after it initializes. +### 3. Start NiceHash Miner for the files to be created automatically. Close NiceHash Miner after it initializes. -### 4 New files will be generated in the **..\miner_plugins\ExamplePlugin** directory.
+### 4. New files will be generated in the **..\miner_plugins\ExamplePlugin** directory.
## #2 Moving the miner files to plugin bins directory -### 1 Download the preferred miner from the official source. +### 1. Download the preferred miner from the official source.
-### 2 Create a new folder named **bins** in the **NiceHash Miner\miner_plugins\ExamplePlugin** directory and move the miner file (all files included in the miner folder, not just the executable) to the **bins** directory. +### 2. Create a new folder named **bins** in the **NiceHash Miner\miner_plugins\ExamplePlugin** directory and move the miner file (all files included in the miner folder, not just the executable) to the **bins** directory. @@ -29,20 +29,33 @@ NiceHash Miner from version 3.0.7.0 supports generic plugins for experimental pu ## #3 Editing the plugin settings -### 1 Open **NiceHash Miner\miner_plugins\ExamplePlugin\Devices.json** and mark each compatible device as compatible with the plugin by changing **`"compatible": false`** to **`"compatible": true`**.

If the miner uses custom device IDs (has different GPU detection technique), make sure to manually change the device ID ("miner_device_id") also. +### 1. Open **NiceHash Miner\miner_plugins\ExamplePlugin\Devices.json** and mark each compatible device as compatible with the plugin by changing **`"compatible": false`** to **`"compatible": true`**.

If the miner uses custom device IDs (has different GPU detection technique), make sure to manually change the device ID ("miner_device_id") also.
-### 2 Open NiceHash Miner\miner_plugins\ExamplePlugin\MinerSettings.json and change the algorithm_command_line to a compatible command for the selected miner.
You can use all the placeholders from the top default_command_line. Example of a algorithm_command_line: `-a {ALGORITHM} -o nicehash+tcp://{POOL_URL}:{POOL_PORT} -u {USERNAME} -api 127.0.0.1:{API_PORT} -log -d {DEVICES} {EXTRA_LAUNCH_PARAMETERS}`
Optionally, change the "device_seperator" for the miner.
+### 2. Open NiceHash Miner\miner_plugins\ExamplePlugin\MinerSettings.json and change the algorithm_command_line to a compatible command for the selected miner.
You can use all the placeholders from the top default_command_line. Example of a algorithm_command_line: `-a {ALGORITHM} -o nicehash+tcp://{POOL_URL}:{POOL_PORT} -u {USERNAME} -api 127.0.0.1:{API_PORT} -log -d {DEVICES} {EXTRA_LAUNCH_PARAMETERS}`
Optionally, change the "device_seperator" for the miner.

-### 3 Navigate to ExamplePlugin\Internals and open MinersBinsUrlsSettings.json +### 3. Navigate to ExamplePlugin\Internals and open MinersBinsUrlsSettings.json Change the `"bin_path"` to the miner executable name. Do not use any specific path, NHM will automatically look for the miner in NiceHash Miner\miner_plugins\ExamplePlugin\bins.
+### 4. Navigate to NiceHash Miner\configs\AcceptedPlugins.json + +Add the name of the plugin you added in the `"UserMinerPlugins.json"` to the last line. + +
+ +### 5. Navigate to NiceHash Miner\miner_plugins\ExamplePlugin\PluginSupportedAlgorithmsSettings.json + +Add the target algorithms to target device groups, default is DaggerHashimoto and RandomXmonero (for example we configured to add DaggerHashimoto algo in the MinersSettings.json earlier): + +
+ + # Additional information Navigate to `NiceHash Miner\miner_plugins\ExamplePlugin\internals` and check the included files. There are other customizations possible through these files. Including adding extra launch parameters and supported algorithms. All of the settings are self-explanatory to advanced users. diff --git a/pre_compiled_libs/device_detection_x64/device_detection.exe b/pre_compiled_libs/device_detection_x64/device_detection.exe index 6e84cf7a6..7e4430543 100644 Binary files a/pre_compiled_libs/device_detection_x64/device_detection.exe and b/pre_compiled_libs/device_detection_x64/device_detection.exe differ diff --git a/pre_compiled_libs/device_detection_x64/device_detection_igcl.dll b/pre_compiled_libs/device_detection_x64/device_detection_igcl.dll new file mode 100644 index 000000000..873ce624e Binary files /dev/null and b/pre_compiled_libs/device_detection_x64/device_detection_igcl.dll differ diff --git a/pre_compiled_libs/device_detection_x64/device_detection_opencl_adl.dll b/pre_compiled_libs/device_detection_x64/device_detection_opencl_adl.dll index b3cd7e1a9..c676ffb13 100644 Binary files a/pre_compiled_libs/device_detection_x64/device_detection_opencl_adl.dll and b/pre_compiled_libs/device_detection_x64/device_detection_opencl_adl.dll differ diff --git a/pre_compiled_libs/device_monitoring_x64/device_monitoring_amd.dll b/pre_compiled_libs/device_monitoring_x64/device_monitoring_amd.dll index f373c32a7..d948aa238 100644 Binary files a/pre_compiled_libs/device_monitoring_x64/device_monitoring_amd.dll and b/pre_compiled_libs/device_monitoring_x64/device_monitoring_amd.dll differ diff --git a/pre_compiled_libs/device_monitoring_x64/device_monitoring_intel.dll b/pre_compiled_libs/device_monitoring_x64/device_monitoring_intel.dll new file mode 100644 index 000000000..99302a740 Binary files /dev/null and b/pre_compiled_libs/device_monitoring_x64/device_monitoring_intel.dll differ diff --git a/pre_compiled_libs/device_monitoring_x64/device_monitoring_nvidia.dll b/pre_compiled_libs/device_monitoring_x64/device_monitoring_nvidia.dll index 9edfe1881..733aa893c 100644 Binary files a/pre_compiled_libs/device_monitoring_x64/device_monitoring_nvidia.dll and b/pre_compiled_libs/device_monitoring_x64/device_monitoring_nvidia.dll differ diff --git a/pre_compiled_libs/device_monitoring_x64/pid_controller.dll b/pre_compiled_libs/device_monitoring_x64/pid_controller.dll new file mode 100644 index 000000000..e012d300a Binary files /dev/null and b/pre_compiled_libs/device_monitoring_x64/pid_controller.dll differ diff --git a/src/Miners/Excavator/CmdConfig.cs b/src/Miners/Excavator/CmdConfig.cs index 4a4d3478b..47a59fa8f 100644 --- a/src/Miners/Excavator/CmdConfig.cs +++ b/src/Miners/Excavator/CmdConfig.cs @@ -46,9 +46,10 @@ public static string CreateTemplate(IEnumerable gpuUuids, string algorithmN return CreateDefaultTemplateAndCreateCMD("__SUBSCRIBE_PARAM_LOCATION__", "__SUBSCRIBE_PARAM_USERNAME__", gpuUuids, algorithmName); } - public static string CommandFileTemplatePath(string pluginUUID) + public static string CommandFileTemplatePath(string pluginUUID, string binPath, string fileName) { - return Paths.MinerPluginsPath(pluginUUID, "internals", "CommandLineTemplate.json"); + var path = Paths.MinerPluginsPath(pluginUUID, binPath, fileName); + return path; } private static List CreateInitialCommands(string subscribeLocation, string subscribeUsername, IEnumerable excavatorIds, string algorithmName) @@ -58,9 +59,24 @@ private static List CreateInitialCommands(string subscribeLocation, str new Command { Id = 1, Method = "subscribe", Params = new List{ subscribeLocation, subscribeUsername } }, new Command { Id = 2, Method = "algorithm.add", Params = new List{ algorithmName.ToLower() } }, }; + return initialCommands; + } + private static List CreateExtraCommands(IEnumerable excavatorIds, string algorithmName, List mandatoryCMDS = null) + { + var initialCommands = new List(); if (algorithmName == "randomx") { initialCommands.AddRange(excavatorIds.Select((dev, index) => new Command { Id = index + 3, Method = "worker.add", Params = new List { algorithmName, dev.ToString(), "NTHREADS=0", "HIGHPRIORITY=0", "USELARGEPAGE=1", "USEMSR=1" } })); + if (mandatoryCMDS != null) + { + foreach (var c in initialCommands) + { + var crossRef = mandatoryCMDS.FirstOrDefault(m => m.Id == c.Id); + if (crossRef == null) continue; + c.Params = crossRef.Params; + } + } + } else initialCommands.AddRange(excavatorIds.Select((dev, index) => new Command { Id = index + 3, Method = "worker.add", Params = new List { algorithmName.ToLower(), dev.ToString() } })); return initialCommands; @@ -78,6 +94,11 @@ private static string CreateDefaultTemplateAndCreateCMD(string subscribeLocation Commands = CreateInitialCommands(subscribeLocation, subscribeUsername, excavatorIds, algorithmName), }, new CommandList + { + Time = 1, + Commands = CreateExtraCommands(excavatorIds, algorithmName), + }, + new CommandList { Event = "on_quit", Commands = new List{ }, @@ -91,9 +112,10 @@ private static string CreateDefaultTemplateAndCreateCMD(string subscribeLocation return null; } } - private static string[] _invalidTemplateMethods = new string[] { "subscribe", "algorithm.add", "worker.add" }; + private static string[] _invalidTemplateMethods = new string[] { "subscribe", "algorithm.add" }; private static string ParseTemplateFileAndCreateCMD(string templateFilePath, IEnumerable excavatorIds, string subscribeLocation, string subscribeUsername, string algorithmName) { + if (!File.Exists(templateFilePath)) return null; try { @@ -103,9 +125,26 @@ private static string ParseTemplateFileAndCreateCMD(string templateFilePath, IEn .Select(cmd => (cmd, commands: cmd.Commands.ToList())) .Where(p => p.commands.Any()) .ToArray(); + + var otherCmds = template + .Where(cmd => cmd.Commands.All(c => _invalidTemplateMethods.Contains(c.Method))) + .Select(cmd => (cmd, commands: cmd.Commands.ToList())) + .Where(p => p.commands.Any()) + .ToArray(); + foreach (var (cmd, commands) in validCmds) { cmd.Commands = commands; + foreach(var c in cmd.Commands) + { + if(c.Method == "worker.add") + { + if (c.Params.Count >= 2 && c.Params[0].ToLower() != "randomx") + { + c.Params = new List { algorithmName.ToLower(), c.Params[1] }; + } + } + } } var commandListTemplate = new List { @@ -115,7 +154,10 @@ private static string ParseTemplateFileAndCreateCMD(string templateFilePath, IEn Commands = CreateInitialCommands(subscribeLocation, subscribeUsername, excavatorIds, algorithmName), }, }; - if (validCmds.Any()) commandListTemplate.AddRange(validCmds.Select(p => p.cmd)); + if (validCmds.Any()) + { + commandListTemplate.AddRange(validCmds.Select(p => p.cmd)); + } return JsonConvert.SerializeObject(commandListTemplate, Formatting.Indented, _jsonSettings); } catch (Exception e) @@ -136,16 +178,16 @@ private static string CreateCommandWithTemplate(string subscribeLocation, string return template; } private static string GetServiceLocation(string miningLocation) - { + { if (BuildOptions.BUILD_TAG == BuildTag.TESTNET) return $"nhmp-test.auto.nicehash.com:443"; if (BuildOptions.BUILD_TAG == BuildTag.TESTNETDEV) return $"nhmp-dev.auto.nicehash.com:443"; //BuildTag.PRODUCTION return $"nhmp.auto.nicehash.com:443"; } - public static string CmdJSONString(string pluginUUID, string _miningLocation, string username, string algorithmName, params int[] excavatorIds) { + public static string CmdJSONString(string pluginUUID, string _miningLocation, string username, string algorithmName, string fileName, string binPath, params int[] excavatorIds) { var miningLocation = GetMiningLocation(_miningLocation); - var templatePath = CommandFileTemplatePath(pluginUUID); + var templatePath = CommandFileTemplatePath(pluginUUID, binPath, fileName); var miningServiceLocation = GetServiceLocation(miningLocation); var command = CreateCommandWithTemplate(miningServiceLocation, username, excavatorIds, templatePath, algorithmName); if (command == null) Logger.Error("Excavator.CmdConfig", "command is NULL"); diff --git a/src/Miners/Excavator/Excavator.cs b/src/Miners/Excavator/Excavator.cs index 10d6aa47c..400b79958 100644 --- a/src/Miners/Excavator/Excavator.cs +++ b/src/Miners/Excavator/Excavator.cs @@ -31,6 +31,7 @@ public Excavator(string uuid, Dictionary mappedIDs) : base(uuid) private HttpClient _httpClient; private string _authToken = Guid.NewGuid().ToString(); new protected int _apiPort; + private readonly int SpeedAnomalySeconds = 50; private ApiData LastApiData { @@ -154,7 +155,8 @@ protected override string MiningCreateCommandLine() var (excavatorIds, ids) = GetUUIDsAndIDs(_miningPairs); var (_, cwd) = GetBinAndCwdPaths(); var fileName = $"cmd_{string.Join("_", excavatorIds)}.json"; - var cmdStr = CmdConfig.CmdJSONString(_uuid, _miningLocation, _username, AlgorithmName(_algorithmType), excavatorIds.ToArray()); + var binPath = GetBinAndCwdPaths(); + var cmdStr = CmdConfig.CmdJSONString(_uuid, _miningLocation, _username, AlgorithmName(_algorithmType), fileName, binPath.cwdPath, excavatorIds.ToArray()); File.WriteAllText(Path.Combine(cwd, fileName), cmdStr); var commandLine = $"-wp {_apiPort} -wa \"{_authToken}\" -c {fileName} -m -qx {_extraLaunchParameters}"; return commandLine; @@ -183,16 +185,28 @@ private void _miningProcess_Exited(object sender, EventArgs e) private static bool IsSpeedOk(ApiData ad) { - const double PER_GPU_ANOMALY = 200 * 1000 * 1000; // 200MH/s - const double SUM_GPU_ANOMALY = 2 * 1000 * 1000 * 1000; // 2GH/s - if (ad == null) return false; // no speeds - if (ad.AlgorithmSpeedsPerDevice == null) return false; // no speeds - var speedsPerDevice = ad.AlgorithmSpeedsPerDevice.Values.Select(speeds => speeds.Select(pair => pair.speed).FirstOrDefault()).ToArray(); - var isPerGPUAnomaly = speedsPerDevice.Any(deviceSpeed => deviceSpeed >= PER_GPU_ANOMALY); - var isPerGPUZeroSpeed = speedsPerDevice.Any(deviceSpeed => Math.Abs(deviceSpeed) < Double.Epsilon); - var isSumGPUAnomaly = speedsPerDevice.Sum() >= SUM_GPU_ANOMALY; - if (isPerGPUAnomaly || isPerGPUZeroSpeed || isSumGPUAnomaly) return false; // speeds anomally + //THIS METHOD WAS ONLY CAUSING PROBLEMS + //const double PER_GPU_ANOMALY = 200000000 * 2; // 400MH/s + //const double SUM_GPU_ANOMALY = 2000000000d * 2; // 4GH/s + //const double PER_GPU_ANOMALY_LARGE = PER_GPU_ANOMALY * 10 * 2; + //const double SUM_GPU_ANOMALY_LARGE = SUM_GPU_ANOMALY * 10 * 2; + //if (ad == null) return false; // no speeds + //if (ad.AlgorithmSpeedsPerDevice == null) return false; // no speeds + ////var speedsPerDevice = ad.AlgorithmSpeedsPerDevice.Values.Select(speeds => speeds.Select(pair => pair.speed).FirstOrDefault()).ToArray(); + //var speedsPerDevice = ad.AlgorithmSpeedsPerDevice.Values.SelectMany(i => i).ToArray(); + + ////var isPerGPUAnomaly = speedsPerDevice.Any(deviceSpeed => deviceSpeed >= PER_GPU_ANOMALY); + //var isPerGPUAnomaly = speedsPerDevice.Any(deviceSpeed => deviceSpeed.type == AlgorithmType.KHeavyHash ? deviceSpeed.speed >= PER_GPU_ANOMALY_LARGE : deviceSpeed.speed >= PER_GPU_ANOMALY); + ////var isPerGPUZeroSpeed = speedsPerDevice.Any(deviceSpeed => Math.Abs(deviceSpeed) < Double.Epsilon); + //var isPerGPUZeroSpeed = speedsPerDevice.Any(deviceSpeed => Math.Abs(deviceSpeed.speed) < Double.Epsilon); + ////var isSumGPUAnomaly = speedsPerDevice.Sum() >= SUM_GPU_ANOMALY; + //var sumGPUAnomalyNormal = speedsPerDevice.Where(s => s.type != AlgorithmType.KHeavyHash)?.Select(s => s.speed)?.Sum(); + //var sumGPUAnomalyLarge = speedsPerDevice.Where(s => s.type == AlgorithmType.KHeavyHash)?.Select(s => s.speed)?.Sum(); + //if (sumGPUAnomalyNormal is double sn && sn >= SUM_GPU_ANOMALY) return false; + //if (sumGPUAnomalyLarge is double sl && sl >= SUM_GPU_ANOMALY_LARGE) return false; + ////if (isPerGPUAnomaly || isPerGPUZeroSpeed || isSumGPUAnomaly) return false; // speeds anomally + //if (isPerGPUAnomaly || isPerGPUZeroSpeed) return false; // speeds anomally return true; } @@ -215,7 +229,7 @@ private async Task MinerSpeedsLoop(CancellationTokenSource ct) while (isActive()) { var elapsed = DateTime.UtcNow - lastSuccessfulSpeeds; - if (elapsed >= TimeSpan.FromSeconds(50)) + if (elapsed >= TimeSpan.FromSeconds(SpeedAnomalySeconds)) { Logger.Info("EXCAVATOR-MinerSpeedsLoop", $"Restaring excavator due to speed anomaly"); //_ = await ExecuteCommand(@"{""id"":1,""method"":""quit"",""params"":[]}"); diff --git a/src/Miners/Excavator/ExcavatorPlugin.PluginSupportedAlgorithms.cs b/src/Miners/Excavator/ExcavatorPlugin.PluginSupportedAlgorithms.cs index 0aec4d54b..1decb038a 100644 --- a/src/Miners/Excavator/ExcavatorPlugin.PluginSupportedAlgorithms.cs +++ b/src/Miners/Excavator/ExcavatorPlugin.PluginSupportedAlgorithms.cs @@ -16,22 +16,28 @@ public partial class ExcavatorPlugin DeviceType.NVIDIA, new List { - new SAS(AlgorithmType.DaggerHashimoto), - new SAS(AlgorithmType.EtcHash), - new SAS(AlgorithmType.Autolykos) { Enabled = false }, - new SAS(AlgorithmType.KAWPOW) { Enabled = false }, - new SAS(AlgorithmType.NeoScrypt), + new SAS(AlgorithmType.DaggerHashimoto) { Enabled = true}, + new SAS(AlgorithmType.EtcHash) { Enabled = true}, + new SAS(AlgorithmType.Autolykos) { Enabled = true}, + new SAS(AlgorithmType.KAWPOW) { Enabled = true, NonDefaultRAMLimit = (4UL << 30) }, + new SAS(AlgorithmType.NeoScrypt) { Enabled = true}, + new SAS(AlgorithmType.ZelHash) { Enabled = true}, + new SAS(AlgorithmType.FishHash) { Enabled = true}, + new SAS(AlgorithmType.XelisHashV2) { Enabled = true} } }, { DeviceType.AMD, new List { - new SAS(AlgorithmType.DaggerHashimoto), - new SAS(AlgorithmType.EtcHash), - new SAS(AlgorithmType.Autolykos) { Enabled = false }, - new SAS(AlgorithmType.KAWPOW) { Enabled = false }, - new SAS(AlgorithmType.NeoScrypt), + new SAS(AlgorithmType.DaggerHashimoto) { Enabled = true }, + new SAS(AlgorithmType.EtcHash) { Enabled = true }, + new SAS(AlgorithmType.Autolykos) { Enabled = true }, + new SAS(AlgorithmType.KAWPOW) { Enabled = true, NonDefaultRAMLimit = (4UL << 30) }, + new SAS(AlgorithmType.NeoScrypt) { Enabled = true }, + new SAS(AlgorithmType.ZelHash) { Enabled = true }, + new SAS(AlgorithmType.FishHash) { Enabled = true }, + new SAS(AlgorithmType.XelisHashV2) { Enabled = true } } }, { @@ -49,7 +55,10 @@ public partial class ExcavatorPlugin { AlgorithmType.Autolykos, "autolykos" }, { AlgorithmType.KAWPOW, "kawpow" }, { AlgorithmType.NeoScrypt, "neoscrypt" }, - { AlgorithmType.RandomXmonero, "randomx" } + { AlgorithmType.RandomXmonero, "randomx" }, + { AlgorithmType.ZelHash, "zelhash" }, + { AlgorithmType.FishHash, "fishhash" }, + { AlgorithmType.XelisHashV2, "xelishash" } } }; } diff --git a/src/Miners/Excavator/ExcavatorPlugin.cs b/src/Miners/Excavator/ExcavatorPlugin.cs index 3e68527f4..75abc2cb1 100644 --- a/src/Miners/Excavator/ExcavatorPlugin.cs +++ b/src/Miners/Excavator/ExcavatorPlugin.cs @@ -10,10 +10,6 @@ using System.Linq; using NHM.MinerPluginToolkitV1.Interfaces; using System.Threading.Tasks; -using System.Net.Http; -using System.Threading; -using Newtonsoft.Json; -using System.Diagnostics; namespace Excavator { @@ -31,11 +27,11 @@ public ExcavatorPlugin() MinersBinsUrlsSettings = new MinersBinsUrlsSettings { - BinVersion = "v1.8.3.0", - ExePath = new List { "NHQM_v0.6.3.0_RC", "excavator.exe" }, + BinVersion = "v1.9.1.0", + ExePath = new List { "NHQM_v0.6.13.0", "excavator.exe" }, Urls = new List { - "https://github.com/nicehash/NiceHashQuickMiner/releases/download/v0.6.3.0_RC/NHQM_v0.6.3.0_RC.zip" + "https://github.com/nicehash/NiceHashQuickMiner/releases/download/v0.6.13.0/NHQM_v0.6.13.0.zip" } }; PluginMetaInfo = new PluginMetaInfo @@ -45,7 +41,7 @@ public ExcavatorPlugin() }; } - public override Version Version => new Version(19, 4); + public override Version Version => new Version(25, 1); public override string PluginUUID => "27315fe0-3b03-11eb-b105-8d43d5bd63be"; public override string Name => "Excavator"; @@ -75,7 +71,7 @@ public override Dictionary> GetSupportedAlg return supported; } - private static Version NVIDIA_Min_Version = new Version(411, 0); + private static Version NVIDIA_Min_Version = new Version(527, 41); private Dictionary> GetSupportedDevicesAndAlgorithms(IEnumerable devices) { bool isNVIDIADriverGreaterThanMinVersion() => CUDADevice.INSTALLED_NVIDIA_DRIVERS >= NVIDIA_Min_Version; @@ -94,22 +90,22 @@ bool isSupportedGPU(BaseDevice gpu) => .ToDictionary(p => p.gpu, p => p.algos); } - private void CreateExcavatorCommandTemplate(IEnumerable uuids, string algorithmName) - { - try - { - var templatePath = CmdConfig.CommandFileTemplatePath(PluginUUID); - var template = CmdConfig.CreateTemplate(uuids, algorithmName); - if (!File.Exists(templatePath) && template != null) - { - File.WriteAllText(templatePath, template); - } - } - catch (Exception e) - { - Logger.Error("ExcavatorPlugin", $"CreateExcavatorCommandTemplate {e}"); - } - } + //private void CreateExcavatorCommandTemplate(IEnumerable uuids, string algorithmName, string filename) + //{ + // try + // { + // var templatePath = CmdConfig.CommandFileTemplatePath(PluginUUID, filename); + // var template = CmdConfig.CreateTemplate(uuids, algorithmName); + // if (!File.Exists(templatePath) && template != null) + // { + // File.WriteAllText(templatePath, template); + // } + // } + // catch (Exception e) + // { + // Logger.Error("ExcavatorPlugin", $"CreateExcavatorCommandTemplate {e}"); + // } + //} protected override MinerBase CreateMinerBase() { @@ -143,6 +139,7 @@ void deleteDirectoryInfo(DirectoryInfo dirInfo) foreach (var file in dirInfo.GetFiles()) { try { + if (file.Name.Contains("cmd_")) continue; if (!filesToLeave.Any(leaveFile => file.Name.Contains(leaveFile))) file.Delete(); } catch (Exception e) @@ -191,12 +188,12 @@ public override bool ShouldReBenchmarkAlgorithmOnDevice(BaseDevice device, Versi public (DriverVersionCheckType ret, Version minRequired) IsDriverMinimumRecommended(BaseDevice device) { - return DriverVersionChecker.CompareCUDADriverVersions(device, CUDADevice.INSTALLED_NVIDIA_DRIVERS, new Version(461, 33)); + return DriverVersionChecker.CompareCUDADriverVersions(device, CUDADevice.INSTALLED_NVIDIA_DRIVERS, new Version(527, 41)); } public (DriverVersionCheckType ret, Version minRequired) IsDriverMinimumRequired(BaseDevice device) { - return DriverVersionChecker.CompareCUDADriverVersions(device, CUDADevice.INSTALLED_NVIDIA_DRIVERS, new Version(411, 31)); + return DriverVersionChecker.CompareCUDADriverVersions(device, CUDADevice.INSTALLED_NVIDIA_DRIVERS, new Version(527, 41)); } public async Task DevicesCrossReference(IEnumerable devices) diff --git a/src/Miners/GMiner/GMinerPlugin.PluginSupportedAlgorithms.cs b/src/Miners/GMiner/GMinerPlugin.PluginSupportedAlgorithms.cs index 8358897ea..128568c1a 100644 --- a/src/Miners/GMiner/GMinerPlugin.PluginSupportedAlgorithms.cs +++ b/src/Miners/GMiner/GMinerPlugin.PluginSupportedAlgorithms.cs @@ -11,7 +11,6 @@ namespace MP.GMiner { public partial class GMinerPlugin { - const ulong KAWPOW_RamLimit = (2UL << 30) + (2UL << 29) + (2UL << 28); protected override PluginSupportedAlgorithmsSettings DefaultPluginSupportedAlgorithmsSettings => new PluginSupportedAlgorithmsSettings { // TODO fees are not just 2% @@ -27,30 +26,28 @@ public partial class GMinerPlugin DeviceType.NVIDIA, new List { - new SAS(AlgorithmType.DaggerHashimoto), - new SAS(AlgorithmType.EtcHash) {NonDefaultRAMLimit = (4UL << 29) + (5UL << 28) + (1UL << 26) }, - new SAS(AlgorithmType.KAWPOW) { NonDefaultRAMLimit = KAWPOW_RamLimit }, + new SAS(AlgorithmType.DaggerHashimoto){Enabled = false}, + new SAS(AlgorithmType.EtcHash) {NonDefaultRAMLimit = (4UL << 29) + (5UL << 28) + (1UL << 26), Enabled = false }, + new SAS(AlgorithmType.KAWPOW) { NonDefaultRAMLimit = (4UL << 30) }, new SAS(AlgorithmType.Autolykos), - new SAS(AlgorithmType.KHeavyHash) { NonDefaultRAMLimit = (2UL << 29) }, - new SAS(AlgorithmType.CuckooCycle), - new SAS(AlgorithmType.ZelHash), - new SAS(AlgorithmType.GrinCuckatoo32), - new SAS(AlgorithmType.ZHash) + new SAS(AlgorithmType.CuckooCycle){Enabled = false}, + new SAS(AlgorithmType.ZelHash){Enabled = false}, + new SAS(AlgorithmType.ZHash){Enabled = false}, + new SAS(AlgorithmType.Octopus) {NonDefaultRAMLimit = (5UL << 30) + (4UL << 29)}, } }, { DeviceType.AMD, new List { - new SAS(AlgorithmType.DaggerHashimoto), - new SAS(AlgorithmType.EtcHash) {NonDefaultRAMLimit = (4UL << 29) + (5UL << 28) + (1UL << 26) }, - new SAS(AlgorithmType.KAWPOW) { NonDefaultRAMLimit = KAWPOW_RamLimit }, - //new SAS(AlgorithmType.Autolykos), - //new SAS(AlgorithmType.KHeavyHash), - new SAS(AlgorithmType.CuckooCycle), - new SAS(AlgorithmType.ZelHash), - new SAS(AlgorithmType.GrinCuckatoo32), - new SAS(AlgorithmType.ZHash) + new SAS(AlgorithmType.DaggerHashimoto){Enabled = false}, + new SAS(AlgorithmType.EtcHash) {NonDefaultRAMLimit = (4UL << 29) + (5UL << 28) + (1UL << 26), Enabled = false }, + new SAS(AlgorithmType.KAWPOW) { NonDefaultRAMLimit = (4UL << 30) }, + new SAS(AlgorithmType.Autolykos), + new SAS(AlgorithmType.CuckooCycle){Enabled = false}, + new SAS(AlgorithmType.ZelHash){Enabled = false}, + new SAS(AlgorithmType.ZHash){Enabled = false}, + new SAS(AlgorithmType.Octopus) {NonDefaultRAMLimit = (5UL << 30) + (4UL << 29)}, } } } diff --git a/src/Miners/GMiner/GMinerPlugin.cs b/src/Miners/GMiner/GMinerPlugin.cs index 1b91f3bba..8f80b913c 100644 --- a/src/Miners/GMiner/GMinerPlugin.cs +++ b/src/Miners/GMiner/GMinerPlugin.cs @@ -27,11 +27,11 @@ public GMinerPlugin() MinerBenchmarkTimeSettings = PluginInternalSettings.BenchmarkTimeSettings; MinersBinsUrlsSettings = new MinersBinsUrlsSettings { - BinVersion = "v3.12", + BinVersion = "v3.44", ExePath = new List { "", "miner.exe" }, Urls = new List { - "https://github.com/develsoftware/GMinerRelease/releases/download/3.12/gminer_3_12_windows64.zip" // original + "https://github.com/develsoftware/GMinerRelease/releases/download/3.44/gminer_3_44_windows64.zip" // original } }; PluginMetaInfo = new PluginMetaInfo @@ -45,7 +45,7 @@ public GMinerPlugin() public override string Name => "GMiner"; - public override Version Version => new Version(19, 1); + public override Version Version => new Version(24, 0); public override string Author => "info@nicehash.com"; @@ -82,7 +82,6 @@ public override Dictionary> GetSupportedAlg { _mappedIDs[gpu.UUID] = minerDeviceId; var algorithms = GetSupportedAlgorithmsForDevice(gpu); - if (gpu is CUDADevice cuda && cuda.SM_major >= 8) algorithms = algorithms.Where(a => a.FirstAlgorithmType != AlgorithmType.GrinCuckatoo32).ToList(); if (algorithms.Count > 0) supported.Add(gpu, algorithms); } @@ -111,7 +110,7 @@ public async Task DevicesCrossReference(IEnumerable devices) { if (_mappedIDs.Count == 0) return; var (minerBinPath, minerCwdPath) = GetBinAndCwdPaths(); - var output = await DevicesCrossReferenceHelpers.MinerOutput(minerBinPath, "--list_devices --watchdog 0"); // AMD + NVIDIA + var output = await DevicesCrossReferenceHelpers.MinerOutput(minerBinPath, "--list_devices"); // AMD + NVIDIA var dumpFile = $"d{DateTime.UtcNow.Ticks}.txt"; try { diff --git a/src/Miners/GMiner/PluginInternalSettings.cs b/src/Miners/GMiner/PluginInternalSettings.cs index cd514cb9a..533fc5db8 100644 --- a/src/Miners/GMiner/PluginInternalSettings.cs +++ b/src/Miners/GMiner/PluginInternalSettings.cs @@ -35,11 +35,7 @@ internal static class PluginInternalSettings }, { $"{AlgorithmType.Autolykos}", - $"-a ergo -s stratum+tcp://{_urlPort} -u {_username} --api 127.0.0.1:{_apiPort} -d {_devices} --watchdog 0 {_extraLaunchParameters}" - }, - { - $"{AlgorithmType.KHeavyHash}", - $"-a kheavyhash -s stratum+tcp://{_urlPort} -u {_username} --api 127.0.0.1:{_apiPort} -d {_devices} --watchdog 0 {_extraLaunchParameters}" + $"-a autolykos2 -s stratum+tcp://{_urlPort} -u {_username} --api 127.0.0.1:{_apiPort} -d {_devices} --watchdog 0 {_extraLaunchParameters}" }, { $"{AlgorithmType.BeamV3}", @@ -53,14 +49,14 @@ internal static class PluginInternalSettings $"{AlgorithmType.ZelHash}", $"-a equihash125_4 -s stratum+tcp://{_urlPort} -u {_username} --api 127.0.0.1:{_apiPort} -d {_devices} --watchdog 0 {_extraLaunchParameters}" }, - { - $"{AlgorithmType.GrinCuckatoo32}", - $"-a cuckatoo32 -s stratum+tcp://{_urlPort} -u {_username} --api 127.0.0.1:{_apiPort} -d {_devices} --watchdog 0 {_extraLaunchParameters}" - }, { $"{AlgorithmType.ZHash}", $"-a equihash144_5 --pers auto -s stratum+tcp://{_urlPort} -u {_username} --api 127.0.0.1:{_apiPort} -d {_devices} --watchdog 0 {_extraLaunchParameters}" - } + }, + { + $"{AlgorithmType.Octopus}", + $"-a octopus -s stratum+tcp://{_urlPort} -u {_username} --api 127.0.0.1:{_apiPort} -d {_devices} --watchdog 0 {_extraLaunchParameters}" + }, }, AlgorithmCommandLineSSL = new Dictionary { @@ -78,11 +74,7 @@ internal static class PluginInternalSettings }, { $"{AlgorithmType.Autolykos}", - $"-a ergo -s stratum+ssl://{_url}:443 -u {_username} --api 127.0.0.1:{_apiPort} -d {_devices} --watchdog 0 {_extraLaunchParameters}" - }, - { - $"{AlgorithmType.KHeavyHash}", - $"-a kheavyhash -s stratum+ssl://{_url}:443 -u {_username} --api 127.0.0.1:{_apiPort} -d {_devices} --watchdog 0 {_extraLaunchParameters}" + $"-a autolykos2 -s stratum+ssl://{_url}:443 -u {_username} --api 127.0.0.1:{_apiPort} -d {_devices} --watchdog 0 {_extraLaunchParameters}" }, { $"{AlgorithmType.BeamV3}", @@ -96,15 +88,14 @@ internal static class PluginInternalSettings $"{AlgorithmType.ZelHash}", $"-a equihash125_4 -s stratum+ssl://{_url}:443 -u {_username} --api 127.0.0.1:{_apiPort} -d {_devices} --watchdog 0 {_extraLaunchParameters}" }, - { - $"{AlgorithmType.GrinCuckatoo32}", - $"-a cuckatoo32 -s stratum+ssl://{_url}:443 -u {_username} --api 127.0.0.1:{_apiPort} -d {_devices} --watchdog 0 {_extraLaunchParameters}" - }, { $"{AlgorithmType.ZHash}", $"-a equihash144_5 --pers auto -s stratum+ssl://{_url}:443 -u {_username} --api 127.0.0.1:{_apiPort} -d {_devices} --watchdog 0 {_extraLaunchParameters}" - } - + }, + { + $"{AlgorithmType.Octopus}", + $"-a octopus -s stratum+ssl://{_url}:443 -u {_username} --api 127.0.0.1:{_apiPort} -d {_devices} --watchdog 0 {_extraLaunchParameters}" + }, } }; diff --git a/src/Miners/LolMiner/LolMinerPlugin.PluginSupportedAlgorithms.cs b/src/Miners/LolMiner/LolMinerPlugin.PluginSupportedAlgorithms.cs index da0cbcd2c..a5716f3b5 100644 --- a/src/Miners/LolMiner/LolMinerPlugin.PluginSupportedAlgorithms.cs +++ b/src/Miners/LolMiner/LolMinerPlugin.PluginSupportedAlgorithms.cs @@ -11,29 +11,6 @@ public partial class LolMinerPlugin const ulong AMD_6GBMemory = 5UL << 30; // 5GB but really 6GB const ulong AMD_3GBMemory = 3UL << 30; // 3GB but really 4GB // NVIDIA OpenCL backend is not really that stable - internal static List SupportedNVIDIAOpenCLAlgos(bool enabled = false) - { - return new List - { - new SAS(AlgorithmType.GrinCuckatoo31) {Enabled = enabled } - }; - } - internal static List SupportedAMDAlgos() - { - return new List - { - new SAS(AlgorithmType.GrinCuckatoo31) { NonDefaultRAMLimit = AMD_8GBMemory}, - new SAS(AlgorithmType.GrinCuckatoo32), - new SAS(AlgorithmType.CuckooCycle), - new SAS(AlgorithmType.ZHash), - new SAS(AlgorithmType.BeamV3) { NonDefaultRAMLimit = AMD_3GBMemory }, - new SAS(AlgorithmType.DaggerHashimoto) { Enabled = false }, - new SAS(AlgorithmType.EtcHash) {NonDefaultRAMLimit = (4UL << 29) + (5UL << 28) + (1UL << 26), Enabled = false }, - new SAS(AlgorithmType.ZelHash), - new SAS(AlgorithmType.KHeavyHash), - new SAS(AlgorithmType.Autolykos) { Enabled = false }, - }; - } protected override PluginSupportedAlgorithmsSettings DefaultPluginSupportedAlgorithmsSettings => new PluginSupportedAlgorithmsSettings { // fixed fee @@ -54,22 +31,43 @@ internal static List SupportedAMDAlgos() DeviceType.NVIDIA, new List { - new SAS(AlgorithmType.GrinCuckatoo31), - new SAS(AlgorithmType.GrinCuckatoo32), new SAS(AlgorithmType.CuckooCycle), new SAS(AlgorithmType.ZHash), new SAS(AlgorithmType.BeamV3), new SAS(AlgorithmType.DaggerHashimoto) { Enabled = false }, new SAS(AlgorithmType.EtcHash){NonDefaultRAMLimit = (4UL << 29) + (5UL << 28) + (1UL << 26), Enabled = false }, new SAS(AlgorithmType.ZelHash), - new SAS(AlgorithmType.KHeavyHash), new SAS(AlgorithmType.Autolykos) { Enabled = false }, - + new SAS(AlgorithmType.NexaPow), + new SAS(AlgorithmType.FishHash) { Enabled = true }, + new SAS(AlgorithmType.Octopus) { Enabled = false }, } }, { DeviceType.AMD, - SupportedAMDAlgos() + new List + { + new SAS(AlgorithmType.CuckooCycle), + new SAS(AlgorithmType.ZHash), + new SAS(AlgorithmType.BeamV3) { NonDefaultRAMLimit = AMD_3GBMemory }, + new SAS(AlgorithmType.DaggerHashimoto) { Enabled = false }, + new SAS(AlgorithmType.EtcHash) {NonDefaultRAMLimit = (4UL << 29) + (5UL << 28) + (1UL << 26), Enabled = false }, + new SAS(AlgorithmType.ZelHash), + new SAS(AlgorithmType.Autolykos) { Enabled = false }, + new SAS(AlgorithmType.NexaPow), + new SAS(AlgorithmType.FishHash) { Enabled = true }, + new SAS(AlgorithmType.Octopus) { Enabled = false }, + } + }, + { + DeviceType.INTEL, + new List + { + new SAS(AlgorithmType.BeamV3), + new SAS(AlgorithmType.Autolykos), + new SAS(AlgorithmType.ZelHash), + new SAS(AlgorithmType.ZHash) + } } } }; diff --git a/src/Miners/LolMiner/LolMinerPlugin.cs b/src/Miners/LolMiner/LolMinerPlugin.cs index b31c4c885..7c1c3df50 100644 --- a/src/Miners/LolMiner/LolMinerPlugin.cs +++ b/src/Miners/LolMiner/LolMinerPlugin.cs @@ -25,11 +25,11 @@ public LolMinerPlugin() // https://github.com/Lolliedieb/lolMiner-releases/releases | https://bitcointalk.org/index.php?topic=4724735.0 MinersBinsUrlsSettings = new MinersBinsUrlsSettings { - BinVersion = "1.65", - ExePath = new List { "1.65", "lolMiner.exe" }, + BinVersion = "1.95a", + ExePath = new List { "1.95a", "lolMiner.exe" }, Urls = new List { - "https://github.com/Lolliedieb/lolMiner-releases/releases/download/1.65/lolMiner_v1.65_Win64.zip" // original + "https://github.com/Lolliedieb/lolMiner-releases/releases/download/1.95a/lolMiner_v1.95a_Win64.zip" // original } }; PluginMetaInfo = new PluginMetaInfo @@ -39,7 +39,7 @@ public LolMinerPlugin() }; } - public override Version Version => new Version(19, 7); + public override Version Version => new Version(24, 5); public override string Author => "info@nicehash.com"; @@ -62,7 +62,7 @@ public override Dictionary> GetSupportedAlg } var gpus = devices - .Where(dev => IsSupportedAMDDevice(dev) || IsSupportedNVIDIADevice(dev, isDriverSupported)) + .Where(dev => IsSupportedAMDDevice(dev) || IsSupportedNVIDIADevice(dev, isDriverSupported) || IsSupportedINTELDevice(dev)) .Where(dev => dev is IGpuDevice) .Cast() .OrderBy(gpu => gpu.PCIeBusID) @@ -88,6 +88,12 @@ private static bool IsSupportedAMDDevice(BaseDevice dev) return isSupported; } + private static bool IsSupportedINTELDevice(BaseDevice dev) + { + var idSupported = dev is IntelDevice; + return idSupported; + } + private static bool IsSupportedNVIDIADevice(BaseDevice dev, bool isDriverSupported) { var isSupported = dev is CUDADevice gpu && gpu.SM_major >= 5; diff --git a/src/Miners/LolMiner/PluginInternalSettings.cs b/src/Miners/LolMiner/PluginInternalSettings.cs index ac88a0502..7ec6cc9b2 100644 --- a/src/Miners/LolMiner/PluginInternalSettings.cs +++ b/src/Miners/LolMiner/PluginInternalSettings.cs @@ -23,14 +23,6 @@ internal static class PluginInternalSettings $"{AlgorithmType.ZHash}", $"--coin AUTO144_5 --pool {_urlPort} --user {_username} --tls 0 --apiport {_apiPort} --disablewatchdog 1 --devices {_devices} {_extraLaunchParameters}" }, - { - $"{AlgorithmType.GrinCuckatoo31}", - $"--algo C31 --pool {_urlPort} --user {_username} --tls 0 --apiport {_apiPort} --disablewatchdog 1 --devices {_devices} {_extraLaunchParameters}" - }, - { - $"{AlgorithmType.GrinCuckatoo32}", - $"--algo C32 --pool {_urlPort} --user {_username} --tls 0 --apiport {_apiPort} --disablewatchdog 1 --devices {_devices} {_extraLaunchParameters}" - }, { $"{AlgorithmType.BeamV3}", $"--algo BEAM-III --pool {_urlPort} --user {_username} --tls 0 --apiport {_apiPort} --disablewatchdog 1 --devices {_devices} {_extraLaunchParameters}" @@ -51,15 +43,22 @@ internal static class PluginInternalSettings $"{AlgorithmType.EtcHash}", $"--algo ETCHASH --pool {_urlPort} --user {_username} --tls 0 --apiport {_apiPort} --disablewatchdog 1 --devices {_devices} {_extraLaunchParameters} --ethstratum ETHV1" }, - { - $"{AlgorithmType.KHeavyHash}", - $"--algo KASPA --pool {_urlPort} --user {_username} --tls 0 --apiport {_apiPort} --disablewatchdog 1 --devices {_devices} {_extraLaunchParameters}" - }, { $"{AlgorithmType.CuckooCycle}", $"--algo C29AE --pool {_urlPort} --user {_username} --tls 0 --apiport {_apiPort} --disablewatchdog 1 --devices {_devices} {_extraLaunchParameters}" }, - + { + $"{AlgorithmType.NexaPow}", + $"--algo NEXA --pool {_urlPort} --user {_username} --tls 0 --apiport {_apiPort} --disablewatchdog 1 --devices {_devices} {_extraLaunchParameters}" + }, + { + $"{AlgorithmType.FishHash}", + $"--algo FISHHASH --pool {_urlPort} --user {_username} --tls 0 --apiport {_apiPort} --disablewatchdog 1 --devices {_devices} {_extraLaunchParameters}" + }, + { + $"{AlgorithmType.Octopus}", + $"--algo OCTOPUS --pool {_urlPort} --user {_username} --tls 0 --apiport {_apiPort} --disablewatchdog 1 --devices {_devices} {_extraLaunchParameters}" + } }, AlgorithmCommandLineSSL = new Dictionary { @@ -67,14 +66,6 @@ internal static class PluginInternalSettings $"{AlgorithmType.ZHash}", $"--coin AUTO144_5 --pool {_url}:443 --user {_username} --tls 1 --apiport {_apiPort} --disablewatchdog 1 --devices {_devices} {_extraLaunchParameters}" }, - { - $"{AlgorithmType.GrinCuckatoo31}", - $"--algo C31 --pool {_url}:443 --user {_username} --tls 1 --apiport {_apiPort} --disablewatchdog 1 --devices {_devices} {_extraLaunchParameters}" - }, - { - $"{AlgorithmType.GrinCuckatoo32}", - $"--algo C32 --pool {_url}:443 --user {_username} --tls 1 --apiport {_apiPort} --disablewatchdog 1 --devices {_devices} {_extraLaunchParameters}" - }, { $"{AlgorithmType.BeamV3}", $"--algo BEAM-III --pool {_url}:443 --user {_username} --tls 1 --apiport {_apiPort} --disablewatchdog 1 --devices {_devices} {_extraLaunchParameters}" @@ -95,14 +86,22 @@ internal static class PluginInternalSettings $"{AlgorithmType.EtcHash}", $"--algo ETCHASH --pool {_url}:443 --user {_username} --tls 1 --apiport {_apiPort} --disablewatchdog 1 --devices {_devices} {_extraLaunchParameters} --ethstratum ETHV1" }, - { - $"{AlgorithmType.KHeavyHash}", - $"--algo KASPA --pool {_url}:443 --user {_username} --tls 1 --apiport {_apiPort} --disablewatchdog 1 --devices {_devices} {_extraLaunchParameters}" - }, { $"{AlgorithmType.CuckooCycle}", $"--algo C29AE --pool {_url}:443 --user {_username} --tls 1 --apiport {_apiPort} --disablewatchdog 1 --devices {_devices} {_extraLaunchParameters}" }, + { + $"{AlgorithmType.NexaPow}", + $"--algo NEXA --pool {_url}:443 --user {_username} --tls 1 --apiport {_apiPort} --disablewatchdog 1 --devices {_devices} {_extraLaunchParameters}" + }, + { + $"{AlgorithmType.FishHash}", + $"--algo FISHHASH --pool {_url}:443 --user {_username} --tls 1 --apiport {_apiPort} --disablewatchdog 1 --devices {_devices} {_extraLaunchParameters}" + }, + { + $"{AlgorithmType.Octopus}", + $"--algo OCTOPUS --pool {_url}:443 --user {_username} --tls 1 --apiport {_apiPort} --disablewatchdog 1 --devices {_devices} {_extraLaunchParameters}" + } } }; diff --git a/src/Miners/NBMiner/NBMinerPlugin.PluginSupportedAlgorithms.cs b/src/Miners/NBMiner/NBMinerPlugin.PluginSupportedAlgorithms.cs index cf497fcf9..df6fba16c 100644 --- a/src/Miners/NBMiner/NBMinerPlugin.PluginSupportedAlgorithms.cs +++ b/src/Miners/NBMiner/NBMinerPlugin.PluginSupportedAlgorithms.cs @@ -7,7 +7,6 @@ namespace NBMiner { public partial class NBMinerPlugin { - const ulong KAWPOW_RamLimit = (2UL << 30) + (2UL << 29) + (2UL << 28); protected override PluginSupportedAlgorithmsSettings DefaultPluginSupportedAlgorithmsSettings => new PluginSupportedAlgorithmsSettings { // TODO fees are not just 2% @@ -25,10 +24,10 @@ public partial class NBMinerPlugin new List { new SAS(AlgorithmType.DaggerHashimoto) { Enabled = false }, - new SAS(AlgorithmType.KAWPOW) { NonDefaultRAMLimit = KAWPOW_RamLimit }, + new SAS(AlgorithmType.KAWPOW) { NonDefaultRAMLimit = (4UL << 30), Enabled = false }, new SAS(AlgorithmType.BeamV3) { Enabled = false }, - new SAS(AlgorithmType.Octopus) {NonDefaultRAMLimit = 5UL << 30}, - new SAS(AlgorithmType.Autolykos), + new SAS(AlgorithmType.Octopus) {NonDefaultRAMLimit = (5UL << 30) + (4UL << 29), Enabled = false}, + new SAS(AlgorithmType.Autolykos) { Enabled = false }, new SAS(AlgorithmType.EtcHash) {NonDefaultRAMLimit = (4UL << 29) + (5UL << 28) + (1UL << 26) , Enabled = false }, new SAS(AlgorithmType.CuckooCycle) {Enabled = false}, @@ -38,11 +37,11 @@ public partial class NBMinerPlugin DeviceType.AMD, new List { - new SAS(AlgorithmType.KAWPOW) {NonDefaultRAMLimit = KAWPOW_RamLimit }, + new SAS(AlgorithmType.KAWPOW) {NonDefaultRAMLimit = (4UL << 30), Enabled = false }, new SAS(AlgorithmType.DaggerHashimoto) { Enabled = false }, - new SAS(AlgorithmType.Autolykos), + new SAS(AlgorithmType.Autolykos) { Enabled = false }, new SAS(AlgorithmType.EtcHash) {NonDefaultRAMLimit = (4UL << 29) + (5UL << 28) + (1UL << 26) , Enabled = false }, - new SAS(AlgorithmType.Octopus) {NonDefaultRAMLimit = 5UL << 30}, + new SAS(AlgorithmType.Octopus) {NonDefaultRAMLimit = (5UL << 30) + (4UL << 29), Enabled = false}, } } } diff --git a/src/Miners/NBMiner/NBMinerPlugin.cs b/src/Miners/NBMiner/NBMinerPlugin.cs index 316222956..4e3cf6fea 100644 --- a/src/Miners/NBMiner/NBMinerPlugin.cs +++ b/src/Miners/NBMiner/NBMinerPlugin.cs @@ -46,8 +46,8 @@ public NBMinerPlugin() public override string Name => "NBMiner"; - public override Version Version => new Version(19, 4); - + public override Version Version => new Version(23, 1); + public override string Author => "info@nicehash.com"; @@ -83,7 +83,6 @@ public override Dictionary> GetSupportedAlg { _mappedIDs[gpu.UUID] = minerDeviceId; var algorithms = GetSupportedAlgorithmsForDevice(gpu); - if (gpu is CUDADevice cuda && cuda.SM_major >= 8) algorithms = algorithms.Where(a => a.FirstAlgorithmType != AlgorithmType.GrinCuckatoo32).ToList(); if (algorithms.Count > 0) supported.Add(gpu, algorithms); } @@ -168,7 +167,7 @@ public override bool ShouldReBenchmarkAlgorithmOnDevice(BaseDevice device, Versi return DriverVersionChecker.CompareCUDADriverVersions(device, CUDADevice.INSTALLED_NVIDIA_DRIVERS, new Version(411, 31)); } - public (DriverVersionCheckType ret, Version minRequired) IsDriverMinimumRecommended(BaseDevice device) + public (DriverVersionCheckType ret, Version minRequired) IsDriverMinimumRecommended(BaseDevice device) { return DriverVersionChecker.CompareAMDDriverVersions(device, new Version(21, 5, 2)); } diff --git a/src/Miners/NanoMiner/NanoMinerPlugin.PluginSupportedAlgorithms.cs b/src/Miners/NanoMiner/NanoMinerPlugin.PluginSupportedAlgorithms.cs index a47f6ee82..69ec67a00 100644 --- a/src/Miners/NanoMiner/NanoMinerPlugin.PluginSupportedAlgorithms.cs +++ b/src/Miners/NanoMiner/NanoMinerPlugin.PluginSupportedAlgorithms.cs @@ -16,7 +16,7 @@ public partial class NanoMinerPlugin DeviceType.AMD, new List { - new SAS(AlgorithmType.KAWPOW){NonDefaultRAMLimit = 4UL << 30, Enabled = false }, + new SAS(AlgorithmType.KAWPOW){NonDefaultRAMLimit = (4UL << 30) , Enabled = false }, new SAS(AlgorithmType.DaggerHashimoto) { Enabled = false}, new SAS(AlgorithmType.Autolykos) { Enabled = false}, new SAS(AlgorithmType.EtcHash) {NonDefaultRAMLimit = (4UL << 29) + (5UL << 28) + (1UL << 26), Enabled = false } @@ -26,8 +26,8 @@ public partial class NanoMinerPlugin DeviceType.NVIDIA, new List { - new SAS(AlgorithmType.KAWPOW){ NonDefaultRAMLimit = (2UL << 30) + (2UL << 29) + (2UL << 28), Enabled = false }, - new SAS(AlgorithmType.Octopus) { Enabled = false}, + new SAS(AlgorithmType.KAWPOW){ NonDefaultRAMLimit = (4UL << 30) , Enabled = false }, + new SAS(AlgorithmType.Octopus) { Enabled = false, NonDefaultRAMLimit = (5UL << 30) + (4UL << 29)}, new SAS(AlgorithmType.DaggerHashimoto) { Enabled = false}, new SAS(AlgorithmType.Autolykos) { Enabled = false}, new SAS(AlgorithmType.EtcHash) {NonDefaultRAMLimit = (4UL << 29) + (5UL << 28) + (1UL << 26), Enabled = false } diff --git a/src/Miners/NanoMiner/NanoMinerPlugin.cs b/src/Miners/NanoMiner/NanoMinerPlugin.cs index 37208ab5d..bc93b3b54 100644 --- a/src/Miners/NanoMiner/NanoMinerPlugin.cs +++ b/src/Miners/NanoMiner/NanoMinerPlugin.cs @@ -24,11 +24,11 @@ public NanoMinerPlugin() // https://github.com/nanopool/nanominer/releases MinersBinsUrlsSettings = new MinersBinsUrlsSettings { - BinVersion = "v3.7.5", - ExePath = new List { "nanominer-windows-3.7.5-cuda11", "nanominer.exe" }, + BinVersion = "v3.10.0", + ExePath = new List { "nanominer-windows-3.10.0", "nanominer.exe" }, Urls = new List { - "https://github.com/nanopool/nanominer/releases/download/v3.7.5/nanominer-windows-3.7.5-cuda11.zip", // original + "https://github.com/nanopool/nanominer/releases/download/v3.10.0/nanominer-windows-3.10.0.zip", // original } }; PluginMetaInfo = new PluginMetaInfo @@ -43,7 +43,7 @@ public NanoMinerPlugin() public override string Name => "NanoMiner"; - public override Version Version => new Version(19, 3); + public override Version Version => new Version(24, 1); public override string Author => "info@nicehash.com"; @@ -77,7 +77,7 @@ public override Dictionary> GetSupportedAlg .Select(gpu => (gpu, algorithms: GetSupportedAlgorithmsForDevice(gpu))) .Where(p => p.algorithms.Any()) .ToDictionary(p => p.gpu, p => p.algorithms); - + foreach (var cpu in cpus) { supported.Add(cpu, GetSupportedAlgorithmsForDevice(cpu)); diff --git a/src/Miners/XMRig/BenchmarkHelpers.cs b/src/Miners/XMRig/BenchmarkHelpers.cs deleted file mode 100644 index dd5ef370d..000000000 --- a/src/Miners/XMRig/BenchmarkHelpers.cs +++ /dev/null @@ -1,65 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Globalization; -using System.Linq; - -namespace XMRig -{ - public static class BenchmarkHelpers - { - public static Tuple TryGetHashrateAfter(this string s, string contains) - { - if (!s.Contains(contains)) - { - return Tuple.Create(0d, false); ; - } - s = s.Substring(s.IndexOf(contains)); - var splittedString = s.Split(' '); - - var afterString = splittedString[2].ToLower(); - var numString = new string(afterString - .ToCharArray() - .SkipWhile(c => !char.IsDigit(c)) - .TakeWhile(c => char.IsDigit(c) || c == '.') - .ToArray()); - - if (!double.TryParse(numString, NumberStyles.Float, CultureInfo.InvariantCulture, out var hash)) - { - return Tuple.Create(0d, false); - } - - var postfixString = splittedString[5]; - for (var i = 0; i < postfixString.Length - 1; ++i) - { - var c = postfixString[i]; - if (!Char.IsLetter(c)) continue; - var c2 = postfixString[i + 1]; - - foreach (var kvp in _postfixes) - { - var postfix = Char.ToLower(kvp.Key); - var mult = kvp.Value; - if (postfix == c && 'h' == c2) - { - var hashrate = hash * mult; - return Tuple.Create(hashrate, true); - } - } - } - return Tuple.Create(hash, true); - } - - private static int pow10(int power) => (int)Math.Pow(10, power); - private static readonly Dictionary _postfixes = new Dictionary - { - {'k', pow10(3)}, - {'M', pow10(6)}, - {'G', pow10(9)}, - {'T', pow10(12)}, - {'P', pow10(15)}, - {'E', pow10(15)}, - {'Z', pow10(21)}, - {'Y', pow10(24)}, - }; - } -} diff --git a/src/Miners/XMRig/JsonApiResponse.cs b/src/Miners/XMRig/JsonApiResponse.cs deleted file mode 100644 index 718174721..000000000 --- a/src/Miners/XMRig/JsonApiResponse.cs +++ /dev/null @@ -1,18 +0,0 @@ -using System; -using System.Collections.Generic; - -namespace XMRig -{ - [Serializable] - public class Hashrate - { - public List total { get; set; } - } - - [Serializable] - public class JsonApiResponse - { - public string version { get; set; } - public Hashrate hashrate { get; set; } - } -} diff --git a/src/Miners/XMRig/MP.XMRig.csproj b/src/Miners/XMRig/MP.XMRig.csproj deleted file mode 100644 index 10e838095..000000000 --- a/src/Miners/XMRig/MP.XMRig.csproj +++ /dev/null @@ -1,24 +0,0 @@ - - - - - - - - - - - - net6.0 - x64 - true - true - - - - - - - diff --git a/src/Miners/XMRig/PluginInternalSettings.cs b/src/Miners/XMRig/PluginInternalSettings.cs deleted file mode 100644 index b84873eee..000000000 --- a/src/Miners/XMRig/PluginInternalSettings.cs +++ /dev/null @@ -1,36 +0,0 @@ -using NHM.Common.Enums; -using NHM.MinerPluginToolkitV1.Configs; -using System.Collections.Generic; - -namespace XMRig -{ - internal static class PluginInternalSettings - { - static string _urlPort => $"{MinerCommandLineSettings.POOL_URL_TEMPLATE}:{MinerCommandLineSettings.POOL_PORT_TEMPLATE}"; - static string _url=> MinerCommandLineSettings.POOL_URL_TEMPLATE; - static string _username => MinerCommandLineSettings.USERNAME_TEMPLATE; - static string _apiPort => MinerCommandLineSettings.API_PORT_TEMPLATE; - static string _extraLaunchParameters => MinerCommandLineSettings.EXTRA_LAUNCH_PARAMETERS_TEMPLATE; - - internal static MinerCommandLineSettings MinerCommandLineSettings = new MinerCommandLineSettings - { - DevicesSeparator = ",", - AlgorithmCommandLine = new Dictionary - { - { - $"{AlgorithmType.RandomXmonero}", - $"-a rx/0 -o {_urlPort} -u {_username} --http-enabled --http-port={_apiPort} --nicehash --donate-level=1 {_extraLaunchParameters}" - } - }, - AlgorithmCommandLineSSL = new Dictionary - { - { - $"{AlgorithmType.RandomXmonero}", - $"-a rx/0 -o {_url}:443 -u {_username} --http-enabled --http-port={_apiPort} --nicehash --tls --donate-level=1 {_extraLaunchParameters}" - } - } - }; - - - } -} diff --git a/src/Miners/XMRig/XMRig.cs b/src/Miners/XMRig/XMRig.cs deleted file mode 100644 index f6f00ecfe..000000000 --- a/src/Miners/XMRig/XMRig.cs +++ /dev/null @@ -1,113 +0,0 @@ -using Newtonsoft.Json; -using NHM.Common; -using NHM.Common.Enums; -using NHM.MinerPlugin; -using NHM.MinerPluginToolkitV1; -using NHM.MinerPluginToolkitV1.Interfaces; -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Net.Http; -using System.Threading.Tasks; - -namespace XMRig -{ - public class XMRig : MinerBase, IBeforeStartMining, IDisposable - { - protected readonly HttpClient _httpClient = new HttpClient(); - - public XMRig(string uuid) : base(uuid) { } - - public async override Task GetMinerStatsDataAsync() - { - var api = new ApiData(); - try - { - var result = await _httpClient.GetStringAsync($"http://127.0.0.1:{_apiPort}/1/summary"); - api.ApiResponse = result; - var summary = JsonConvert.DeserializeObject(result); - - var totalSpeed = 0d; - var perDeviceSpeedInfo = new Dictionary>(); - var perDevicePowerInfo = new Dictionary(); - // init per device sums - foreach (var pair in _miningPairs) - { - var uuid = pair.Device.UUID; - var currentSpeed = summary.hashrate.total.FirstOrDefault() ?? 0d; - totalSpeed += currentSpeed; - perDeviceSpeedInfo.Add(uuid, new List<(AlgorithmType type, double speed)>() { (_algorithmType, currentSpeed * (1 - DevFee * 0.01)) }); - // no power usage info - perDevicePowerInfo.Add(uuid, -1); - } - - api.AlgorithmSpeedsPerDevice = perDeviceSpeedInfo; - api.PowerUsagePerDevice = perDevicePowerInfo; - api.PowerUsageTotal = -1; - } - catch (Exception e) - { - Logger.Error(_logGroup, $"Error occured while getting API stats: {e.Message}"); - } - - return api; - } - - protected override void Init() - { - } - - - private static HashSet _deleteConfigs = new HashSet { "config.json" }; - private static bool IsDeleteConfigFile(string file) - { - foreach (var conf in _deleteConfigs) - { - if (file.Contains(conf)) return true; - } - return false; - } - void IBeforeStartMining.BeforeStartMining() - { - var binCwd = GetBinAndCwdPaths().cwdPath; - var txtFiles = Directory.GetFiles(binCwd, "*.json", SearchOption.AllDirectories) - .Where(file => IsDeleteConfigFile(file)) - .ToArray(); - foreach (var deleteFile in txtFiles) - { - try - { - File.Delete(deleteFile); - } - catch (Exception e) - { - Logger.Error(_logGroup, $"BeforeStartMining error while deleting file '{deleteFile}': {e.Message}"); - } - } - } - private bool _disposed = false; - public virtual void Dispose() - { - Dispose(true); - GC.SuppressFinalize(this); - } - protected void Dispose(bool disposing) - { - if (_disposed) return; - if (disposing) - { - try - { - _httpClient.Dispose(); - } - catch (Exception) { } - } - _disposed = true; - } - ~XMRig() - { - Dispose(false); - } - } -} diff --git a/src/Miners/XMRig/XMRigPlugin.PluginSupportedAlgorithms.cs b/src/Miners/XMRig/XMRigPlugin.PluginSupportedAlgorithms.cs deleted file mode 100644 index 1b92b17f6..000000000 --- a/src/Miners/XMRig/XMRigPlugin.PluginSupportedAlgorithms.cs +++ /dev/null @@ -1,26 +0,0 @@ -using NHM.Common.Enums; -using NHM.MinerPluginToolkitV1.Configs; -using System.Collections.Generic; -using SAS = NHM.MinerPluginToolkitV1.Configs.PluginSupportedAlgorithmsSettings.SupportedAlgorithmSettings; - -namespace XMRig -{ - public partial class XMRigPlugin - { - protected override PluginSupportedAlgorithmsSettings DefaultPluginSupportedAlgorithmsSettings => new PluginSupportedAlgorithmsSettings - { - // default is 5 but we set it to 1 - DefaultFee = 1.0, - Algorithms = new Dictionary> - { - { - DeviceType.CPU, - new List - { - new SAS(AlgorithmType.RandomXmonero) { Enabled = false }, - } - } - } - }; - } -} diff --git a/src/Miners/XMRig/XMRigPlugin.cs b/src/Miners/XMRig/XMRigPlugin.cs deleted file mode 100644 index baf9f467e..000000000 --- a/src/Miners/XMRig/XMRigPlugin.cs +++ /dev/null @@ -1,93 +0,0 @@ -using NHM.Common.Algorithm; -using NHM.Common.Device; -using NHM.Common.Enums; -using NHM.MinerPluginToolkitV1; -using NHM.MinerPluginToolkitV1.Configs; -using NHM.MinerPluginToolkitV1.Interfaces; -using System; -using System.Collections.Generic; -using System.Linq; - -namespace XMRig -{ - public partial class XMRigPlugin : PluginBase, IAdditionalELP - { - public XMRigPlugin() - { - // mandatory init - InitInsideConstuctorPluginSupportedAlgorithmsSettings(); - MinerCommandLineSettings = PluginInternalSettings.MinerCommandLineSettings; - // set default internal settings - // https://github.com/xmrig/xmrig - MinersBinsUrlsSettings = new MinersBinsUrlsSettings - { - BinVersion = "v6.8.1", - ExePath = new List { "xmrig-6.8.1", "xmrig.exe" }, - Urls = new List - { - "https://github.com/xmrig/xmrig/releases/download/v6.8.1/xmrig-6.8.1-msvc-win64.zip" // original - } - }; - PluginMetaInfo = new PluginMetaInfo - { - PluginDescription = "CryptoNight and RandomX (Monero) CPU miner", - SupportedDevicesAlgorithms = SupportedDevicesAlgorithmsDict() - }; - } - - public override string PluginUUID => "0e0a7320-94ec-11ea-a64d-17be303ea466"; - - public override Version Version => new Version(19, 1); - - public override string Name => "XMRig"; - - public override string Author => "info@nicehash.com"; - - private readonly List> AdditionalELPs = new List>() - { - new List() - { - "--cpu-priority", - "0" - } - }; - public List> GetAdditionalELPs() - { - return AdditionalELPs; - } - - protected override MinerBase CreateMinerBase() - { - return new XMRig(PluginUUID); - } - public override Dictionary> GetSupportedAlgorithms(IEnumerable devices) - { - var supported = new Dictionary>(); - - var cpus = devices.Where(dev => dev is CPUDevice).Cast(); - foreach (var cpu in cpus) - { - supported.Add(cpu, GetSupportedAlgorithmsForDevice(cpu)); - } - - return supported; - } - public override IEnumerable CheckBinaryPackageMissingFiles() - { - var (_, pluginRootBinsPath) = GetBinAndCwdPaths(); - return BinaryPackageMissingFilesCheckerHelpers.ReturnMissingFiles(pluginRootBinsPath, new List { "xmrig.exe" }); - } - public override bool ShouldReBenchmarkAlgorithmOnDevice(BaseDevice device, Version benchmarkedPluginVersion, params AlgorithmType[] ids) - { - //try - //{ - - //} - //catch (Exception e) - //{ - // Logger.Error(PluginUUID, $"ShouldReBenchmarkAlgorithmOnDevice {e.Message}"); - //} - return false; - } - } -} diff --git a/src/Miners/__DEV__ExamplePlugin/ExamplePlugin.cs b/src/Miners/__DEV__ExamplePlugin/ExamplePlugin.cs index a4aed2fc9..81d9cc3fb 100644 --- a/src/Miners/__DEV__ExamplePlugin/ExamplePlugin.cs +++ b/src/Miners/__DEV__ExamplePlugin/ExamplePlugin.cs @@ -69,16 +69,6 @@ public Dictionary> GetSupportedAlgorithms(I { algorithms.Add(new Algorithm(PluginUUID, AlgorithmType.DaggerHashimoto)); } - // only NVIDIA supports Lyra2REv3 - if (device.DeviceType == DeviceType.NVIDIA) - { - algorithms.Add(new Algorithm(PluginUUID, AlgorithmType.Lyra2REv3)); - } - // only AMD supports - if (device.DeviceType == DeviceType.AMD) - { - algorithms.Add(new Algorithm(PluginUUID, AlgorithmType.GrinCuckatoo32)); - } supported.Add(device, algorithms); } diff --git a/src/Miners/__DEV__FakePlugin/FakePlugin.PluginSupportedAlgorithmsSettings.cs b/src/Miners/__DEV__FakePlugin/FakePlugin.PluginSupportedAlgorithmsSettings.cs index 356f5c2e7..9ba9b146b 100644 --- a/src/Miners/__DEV__FakePlugin/FakePlugin.PluginSupportedAlgorithmsSettings.cs +++ b/src/Miners/__DEV__FakePlugin/FakePlugin.PluginSupportedAlgorithmsSettings.cs @@ -23,12 +23,10 @@ public partial class FakePlugin new List { new SAS(AlgorithmType.ZHash), - new SAS(AlgorithmType.GrinCuckatoo31), new SAS(AlgorithmType.CuckooCycle) {Enabled = false }, new SAS(AlgorithmType.BeamV3), new SAS(AlgorithmType.KAWPOW), new SAS(AlgorithmType.DaggerHashimoto, AlgorithmType.ZHash), - new SAS(AlgorithmType.GrinCuckatoo32), } }, { @@ -45,7 +43,6 @@ public partial class FakePlugin new List { new SAS(AlgorithmType.RandomXmonero), - new SAS(AlgorithmType.Lyra2REv3), new SAS(AlgorithmType.KAWPOW), } }, diff --git a/src/NHM.Common/DemoUser.cs b/src/NHM.Common/DemoUser.cs index ec49953ec..6d77f7204 100644 --- a/src/NHM.Common/DemoUser.cs +++ b/src/NHM.Common/DemoUser.cs @@ -9,7 +9,7 @@ public static class DemoUser { BuildTag.TESTNET => "2N6ibfrTwUSSvzAz1esPe1gYULG82asTHiS", BuildTag.TESTNETDEV => "2N2e2ET1jMY9r5is9KaTKnU3bkCFaYHEEEx", - _ => "33hGFJZQAfbdzyHGqhJPvZwncDjUBdZqjW", // BuildTag.PRODUCTION + _ => "NHbQTA7iMnCUuPjhkVCa99zbNUDFAry1nLH4", // BuildTag.PRODUCTION }; } } diff --git a/src/NHM.Common/Device/AMDDevice.cs b/src/NHM.Common/Device/AMDDevice.cs index c0935b26d..32cc4eaf5 100644 --- a/src/NHM.Common/Device/AMDDevice.cs +++ b/src/NHM.Common/Device/AMDDevice.cs @@ -21,5 +21,6 @@ public class AMDDevice : BaseDevice, IGpuDevice // AMD always true public bool IsOpenCLBackendEnabled => true; + public bool IsIntegrated { get; set; } = false; } } diff --git a/src/NHM.Common/Device/IntelDevice.cs b/src/NHM.Common/Device/IntelDevice.cs new file mode 100644 index 000000000..fa4134101 --- /dev/null +++ b/src/NHM.Common/Device/IntelDevice.cs @@ -0,0 +1,23 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace NHM.Common.Device +{ + public class IntelDevice : BaseDevice, IGpuDevice + { + public static string RawDetectionOutput = string.Empty; + + // TODO does it make sense to set here the actual installed NVIDIA drivers?? + public Version DEVICE_INTEL_DRIVER = new Version(0, 0); // or use just null + + public int PCIeBusID { get; init; } + public ulong GpuRam { get; init; } + + // we assume disabled and we check it after OpenCL detection. + public bool IsOpenCLBackendEnabled { get; private set; } = false; + public string RawDeviceData { get; init; } + } +} diff --git a/src/NHM.Common/Enums/AlgorithmType.cs b/src/NHM.Common/Enums/AlgorithmType.cs index 41d1ec604..8861e4cdc 100644 --- a/src/NHM.Common/Enums/AlgorithmType.cs +++ b/src/NHM.Common/Enums/AlgorithmType.cs @@ -90,9 +90,9 @@ public enum AlgorithmType Beam = 37, [Obsolete("UNUSED Algorithm", true)] GrinCuckaroo29 = 38, - //[Obsolete("UNUSED Algorithm")] + [Obsolete("UNUSED Algorithm")] GrinCuckatoo31 = 39, - //[Obsolete("UNUSED Algorithm")] + [Obsolete("UNUSED Algorithm")] Lyra2REv3 = 40, [Obsolete("NOT SUPPORTED. UNUSED Algorithm", true)] MTP = 41, @@ -112,7 +112,7 @@ public enum AlgorithmType Eaglesong = 48, [Obsolete("UNUSED Algorithm", true)] Cuckaroom = 49, - //[Obsolete("UNUSED Algorithm")] + [Obsolete("UNUSED Algorithm")] GrinCuckatoo32 = 50, [Obsolete("UNUSED Algorithm", true)] Handshake = 51, @@ -136,8 +136,23 @@ public enum AlgorithmType EtcHash = 60, //[Obsolete("UNUSED Algorithm")] VerusHash = 61, - //[Obsolete("UNUSED Algorithm")] + [Obsolete("UNUSED Algorithm")] KHeavyHash = 62, + //[Obsolete("UNUSED Algorithm")] + NexaPow = 63, + [Obsolete("UNUSED Algorithm")] + IronFish = 64, + [Obsolete("UNUSED Algorithm")] + KarlsenHash = 65, + [Obsolete("UNUSED Algorithm")] + Alephium = 66, //24 + //[Obsolete("UNUSED Algorithm")] + FishHash = 67, + [Obsolete("UNUSED Algorithm")] + PyrinHash = 68, + //[Obsolete("UNUSED Algorithm")] + XelisHashV2 = 69 + #endregion // NiceHashAPI } diff --git a/src/NHM.Common/Enums/DeviceDynamicProperties.cs b/src/NHM.Common/Enums/DeviceDynamicProperties.cs new file mode 100644 index 000000000..d0a090d47 --- /dev/null +++ b/src/NHM.Common/Enums/DeviceDynamicProperties.cs @@ -0,0 +1,28 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace NHM.Common.Enums +{ + public enum DeviceDynamicProperties + { + NONE, + Load, + MemoryControllerLoad, + Temperature, + FanSpeedPercentage, + PowerUsage, + VramTemp, + HotspotTemp, + CoreClock, + MemClock, + TDP, + TDPWatts, + CoreVoltage, + CoreClockDelta, + MemClockDelta, + FanSpeedRPM + } +} diff --git a/src/NHM.Common/Enums/DeviceState.cs b/src/NHM.Common/Enums/DeviceState.cs index ec36a5447..f90978ca9 100644 --- a/src/NHM.Common/Enums/DeviceState.cs +++ b/src/NHM.Common/Enums/DeviceState.cs @@ -1,4 +1,5 @@  +using System; namespace NHM.Common.Enums { public enum DeviceState @@ -10,7 +11,9 @@ public enum DeviceState Pending, Disabled, #if NHMWS4 + [Obsolete("UNUSED status", true)] Gaming, + Testing #endif // TODO Extra states, NotProfitable } diff --git a/src/NHM.Common/Enums/DeviceType.cs b/src/NHM.Common/Enums/DeviceType.cs index 2a6a91cb2..7f6327cf2 100644 --- a/src/NHM.Common/Enums/DeviceType.cs +++ b/src/NHM.Common/Enums/DeviceType.cs @@ -4,6 +4,7 @@ public enum DeviceType { CPU = 0, NVIDIA, - AMD + AMD, + INTEL } } diff --git a/src/NHM.Common/Enums/RigManagementReturn.cs b/src/NHM.Common/Enums/RigManagementReturn.cs new file mode 100644 index 000000000..38213e998 --- /dev/null +++ b/src/NHM.Common/Enums/RigManagementReturn.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace NHM.Common.Enums +{ + public enum RigManagementReturn + { + Success, + PartialSuccess, + Fail + } +} diff --git a/src/NHM.Common/Enums/RigStatus.cs b/src/NHM.Common/Enums/RigStatus.cs index 8cf5ede7b..89503904a 100644 --- a/src/NHM.Common/Enums/RigStatus.cs +++ b/src/NHM.Common/Enums/RigStatus.cs @@ -1,4 +1,5 @@  +using System; namespace NHM.Common.Enums { public enum RigStatus @@ -10,6 +11,10 @@ public enum RigStatus Error, Pending, Disabled, + [Obsolete("UNUSED status", true)] Gaming, +#if NHMWS4 + Testing, +#endif } } diff --git a/src/NHM.Common/NHM.Common.csproj b/src/NHM.Common/NHM.Common.csproj index 73d17b805..fb6051148 100644 --- a/src/NHM.Common/NHM.Common.csproj +++ b/src/NHM.Common/NHM.Common.csproj @@ -8,12 +8,12 @@ 1701;1702;CA1416 - $(DefineConstants)TRACE + $(DefineConstants)TRACE;NHMWS4 1701;1702;CA1416 - $(DefineConstants)TRACE + $(DefineConstants)TRACE;NHMWS4 diff --git a/src/NHM.Common/PluginsListCacheManager.cs b/src/NHM.Common/PluginsListCacheManager.cs new file mode 100644 index 000000000..7f05908c2 --- /dev/null +++ b/src/NHM.Common/PluginsListCacheManager.cs @@ -0,0 +1,129 @@ +using System; +using System.Collections.Generic; +using System.Globalization; +using System.IO; +using System.Linq; +using System.Net; +using System.Net.Http; +using System.Net.Http.Json; +using System.Security.Policy; +using System.Text; +using System.Text.Json; +using System.Threading.Tasks; + +namespace NHM.Common +{ + public static class PluginsListCacheManager + { + //private static DateTime lastVersion = DateTime.MinValue; + readonly static string dateFilePath = Paths.AppRootPath("cachedplugindate"); + readonly static string pluginFilePath = Paths.AppRootPath("cachedplugins"); + private static readonly string format = "d MMM yyyy HH:mm 'GMT'"; + private static readonly string _TAG = "PluginsListCacheManager"; + + private static DateTime GetLastVersion(string version) + { + return GetCachedDateTime(version); + } + private static void SetLastVersion(DateTime dt, string version) + { + WriteNewCachedDateTime(dt, version); + } + + public static DateTime GetCachedDateTime(string version) + { + string filePath = $"{dateFilePath}_v{version}.json"; + if (!File.Exists(filePath)) return DateTime.MinValue; + try + { + string fileContent = File.ReadAllText(filePath); + DateTime deserializedDateTime = JsonSerializer.Deserialize(fileContent); + return deserializedDateTime; + } + catch (Exception ex) + { + Logger.Error(_TAG, ex.Message); + return DateTime.MinValue; + } + } + + public static void WriteNewCachedDateTime(DateTime newCachedDateTime, string version) + { + string filePath = $"{dateFilePath}_v{version}.json"; + try + { + string jsonString = JsonSerializer.Serialize(newCachedDateTime); + File.WriteAllText(filePath, jsonString); + } + catch (Exception ex) + { + Logger.Error(_TAG, ex.Message); + } + } + + public static async Task CheckIfShouldUpdateAndUpdateLatestDate(string url, int version) + { + try + { + using (HttpClient client = new HttpClient()) + { + client.DefaultRequestHeaders.Add("User-Agent", "PluginsListCacheManager"); + HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Head, $"{url}?v={version}"); + HttpResponseMessage response = await client.SendAsync(request); + if (response.StatusCode != HttpStatusCode.OK) return true; + if (response.Content.Headers.NonValidated.Contains("Last-Modified")) + { + var lastModifiedStr = response.Content.Headers.NonValidated.GetValueOrDefault("Last-Modified"); + if (DateTime.TryParseExact(lastModifiedStr.ToString(), format, CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal, out DateTime result)) + { + var lastVer = GetLastVersion(version.ToString()); + if (lastVer == result) + { + Logger.Debug("PluginsListCacheManager", $"Plugin update loop: versions {version} - no update needed - {result}"); + return false; + } + Logger.Debug("PluginsListCacheManager", $"Plugin update loop: versions {version} - WILL UPDATE - {lastVer}/{result}"); + SetLastVersion(result, version.ToString()); + return true; + } + } + } + } + catch (HttpRequestException ex) + { + Logger.Error(_TAG, $"Error: {ex.Message}"); + } + return true; + } + + public static bool WritePluginCache(int version, string plugins) + { + string filePath = $"{pluginFilePath}_v{version}.json"; + try + { + File.WriteAllText(filePath, plugins); + return true; + } + catch (Exception ex) + { + Logger.Error(_TAG, $"Error: {ex.Message}"); + } + return false; + } + + public static string ReadPluginCache(int version) + { + string filePath = $"{pluginFilePath}_v{version}.json"; + try + { + if (!File.Exists(filePath)) return string.Empty; + return File.ReadAllText(filePath); + } + catch (Exception ex) + { + Logger.Error(_TAG, $"Error: {ex.Message}"); + } + return string.Empty; + } + } +} diff --git a/src/NHM.CommonWin32/NHMRegistry.cs b/src/NHM.CommonWin32/NHMRegistry.cs index edb979118..5b75042fc 100644 --- a/src/NHM.CommonWin32/NHMRegistry.cs +++ b/src/NHM.CommonWin32/NHMRegistry.cs @@ -1,12 +1,15 @@ using Microsoft.Win32; using NHM.Common; +using NHM.Common.Enums; using System; +using System.Reflection.Metadata.Ecma335; namespace NHM.CommonWin32 { public static class NHMRegistry { private static string NHM_SUBKEY => @"SOFTWARE\" + APP_GUID.GUID; + private static string QM_SUBKEY => @"SOFTWARE\NiceHash QuickMiner"; private static bool EnsureNHMSubKeyCalled = false; private static void EnsureNHMSubKey() { @@ -95,8 +98,15 @@ public static void Set_QM_MiningaddressFromRegistry(string btc) { try { - using var key = Registry.LocalMachine.OpenSubKey(@"SOFTWARE\NiceHash QuickMiner", true); + if (BuildOptions.BUILD_TAG != BuildTag.PRODUCTION) return; + var key = Registry.LocalMachine.OpenSubKey(QM_SUBKEY, true); + if (key == null) + { + Registry.LocalMachine.CreateSubKey(QM_SUBKEY); + key = Registry.LocalMachine.OpenSubKey(QM_SUBKEY, true); + } key.SetValue("MiningAddress", btc); + key.Close(); } catch (Exception ex) { diff --git a/src/NHM.CommonWin32/Properties/AssemblyInfo.cs b/src/NHM.CommonWin32/Properties/AssemblyInfo.cs index 4828fbf45..84028bd6d 100644 --- a/src/NHM.CommonWin32/Properties/AssemblyInfo.cs +++ b/src/NHM.CommonWin32/Properties/AssemblyInfo.cs @@ -31,5 +31,5 @@ // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("3.1.0.4")] -[assembly: AssemblyFileVersion("3.1.0.4")] +[assembly: AssemblyVersion("3.1.1.6")] +[assembly: AssemblyFileVersion("3.1.1.6")] diff --git a/src/NHM.CredentialValidators/WorkernameValidator.cs b/src/NHM.CredentialValidators/WorkernameValidator.cs index 7cf94962e..1a5c9cad1 100644 --- a/src/NHM.CredentialValidators/WorkernameValidator.cs +++ b/src/NHM.CredentialValidators/WorkernameValidator.cs @@ -6,7 +6,7 @@ internal static class WorkernameValidator { private static Regex _IsAlphaNumeric = new Regex(@"^[a-zA-Z0-9\s,]*$"); private static bool IsAlphaNumeric(string strToCheck) => _IsAlphaNumeric.IsMatch(strToCheck); - private const int MAX_WORKERNAME_LENGTH = 15; + private const int MAX_WORKERNAME_LENGTH = 24; internal static bool ValidateWorkerName(string workername) { diff --git a/src/NHM.DeviceDetection/AMD/AMDBusIDVersionResult.cs b/src/NHM.DeviceDetection/AMD/AMDBusIDVersionResult.cs index 8362ea0e7..1f26a380f 100644 --- a/src/NHM.DeviceDetection/AMD/AMDBusIDVersionResult.cs +++ b/src/NHM.DeviceDetection/AMD/AMDBusIDVersionResult.cs @@ -8,5 +8,6 @@ internal record AMDBusIDVersionResult public int BUS_ID { get; set; } = -1; public int ADLRetCode { get; set; } = -1; public int FunctionCall { get; set; } = -1; + public bool IsIntegrated { get; set; } = false; } } diff --git a/src/NHM.DeviceDetection/AMD/AMDDetector.cs b/src/NHM.DeviceDetection/AMD/AMDDetector.cs index 1c5d4f677..bf8d7f781 100644 --- a/src/NHM.DeviceDetection/AMD/AMDDetector.cs +++ b/src/NHM.DeviceDetection/AMD/AMDDetector.cs @@ -46,7 +46,7 @@ private static string convertSize(double size) return null; } } - public static async Task> TryQueryAMDDevicesAsync(List availableVideoControllers) + public static async Task> TryQueryAMDDevicesAsync(List availableVideoControllers, bool detectIntegrated) { Logger.Info(Tag, "TryQueryAMDDevicesAsync START"); var (rawOutput, parsed) = await OpenCLDetector.TryQueryOpenCLDevicesAsync(); @@ -79,6 +79,7 @@ public static async Task> TryQueryAMDDevicesAsync(List p.dev).Where(d => !d.IsIntegrated).ToList(); return result.Select(p => p.dev).ToList(); } @@ -128,10 +129,12 @@ public static async Task> TryQueryAMDDevicesAsync(List ver.BUS_ID == oclDev.BUS_ID); if(thisDeviceExtraADLResult != null && thisDeviceExtraADLResult.BUS_ID == oclDev.BUS_ID) { + amdDevice.IsIntegrated = thisDeviceExtraADLResult.IsIntegrated; amdDevice.ADLFunctionCall = thisDeviceExtraADLResult.FunctionCall; amdDevice.ADLReturnCode = thisDeviceExtraADLResult.ADLRetCode; amdDevice.RawDriverVersion = thisDeviceExtraADLResult.AdrenalinVersion; diff --git a/src/NHM.DeviceDetection/DeviceDetection.cs b/src/NHM.DeviceDetection/DeviceDetection.cs index 0c58822cb..0fa0bacd1 100644 --- a/src/NHM.DeviceDetection/DeviceDetection.cs +++ b/src/NHM.DeviceDetection/DeviceDetection.cs @@ -3,6 +3,7 @@ using NHM.Common.Configs; using NHM.Common.Device; using NHM.Common.Enums; +using NHM.DeviceDetection.IntelGPU; using NHM.DeviceDetection.NVIDIA; using System; using System.Collections.Generic; @@ -188,9 +189,9 @@ private static async Task DetectCUDADevices() Logger.Info(Tag, stringBuilder.ToString()); } - private static async Task DetectAMDDevices() + private static async Task DetectAMDDevices(bool detectIntegrated) { - var amdDevices = await AMD.AMDDetector.TryQueryAMDDevicesAsync(DetectionResult.AvailableVideoControllers.ToList()); + var amdDevices = await AMD.AMDDetector.TryQueryAMDDevicesAsync(DetectionResult.AvailableVideoControllers.ToList(), detectIntegrated); if (amdDevices == null || amdDevices.Count == 0) { Logger.Info(Tag, "DetectAMDDevices ZERO Found."); @@ -210,18 +211,49 @@ private static async Task DetectAMDDevices() stringBuilder.AppendLine($"\t\tNAME: {amdDev.Name}"); stringBuilder.AppendLine($"\t\tCodename: {amdDev.Codename}"); stringBuilder.AppendLine($"\t\tInfSection: {amdDev.InfSection}"); - stringBuilder.AppendLine($"\t\tMEMORY: {amdDev.GpuRam}"); + stringBuilder.AppendLine($"\t\tMEMORY: {amdDev.GpuRam}"); stringBuilder.AppendLine($"\t\tOpenCLPlatformID: {amdDev.OpenCLPlatformID}"); + stringBuilder.AppendLine($"\t\tIsIntegrated: {amdDev.IsIntegrated}"); } Logger.Info(Tag, stringBuilder.ToString()); } + private static async Task DetectIntelGPUs(bool detectIntegrated) + { + var intelDevices = await IntelGpuDetector.TryQueryIGCLDevicesAsync(); + var result = intelDevices.parsed; + if (result?.IgclDevices?.Count > 0) + { + // we got INTEL devices + List igclDevices = new List(); + if (detectIntegrated) + { + igclDevices = result.IgclDevices + .Where(dev => !dev.IsIntegrated) + .Select(dev => IntelGpuDetector.Transform(dev)).ToList(); + } + else igclDevices = result.IgclDevices.Select(dev => IntelGpuDetector.Transform(dev)).ToList(); + // filter out no supported SM versions + + DetectionResult.IntelDevices = igclDevices.OrderBy(igclDev => igclDev.PCIeBusID).ToList(); + // INTEL drivers + var igclLoaded = result?.IgclLoaded ?? -1; + } + + // log result + var stringBuilder = new StringBuilder(); + stringBuilder.AppendLine(""); + stringBuilder.AppendLine("DetectIntelGPUDevices:"); + IntelGpuDetector.LogDevices(stringBuilder, DetectionResult.IntelDevices); + Logger.Info(Tag, stringBuilder.ToString()); + } + private static void DetectFAKE_Devices() { DetectionResult.FAKEDevices = Settings.Devices; } - public static async Task DetectDevices(IProgress progress) + public static async Task DetectDevices(bool detectIntegrated, IProgress progress) { if (_initCalled) return; _initCalled = true; @@ -232,7 +264,9 @@ public static async Task DetectDevices(IProgress progress) progress?.Report(DeviceDetectionStep.NVIDIA_CUDA); if (!Settings.FakeDevices) await DetectCUDADevices(); progress?.Report(DeviceDetectionStep.AMD_OpenCL); - if (!Settings.FakeDevices) await DetectAMDDevices(); + if (!Settings.FakeDevices) await DetectAMDDevices(detectIntegrated); + progress?.Report(DeviceDetectionStep.INTEL_GPU); + if (!Settings.FakeDevices) await DetectIntelGPUs(detectIntegrated); progress?.Report(DeviceDetectionStep.FAKE); if (Settings.FakeDevices) DetectFAKE_Devices(); // after we detect AMD we will have platforms and now we can check if NVIDIA OpenCL backend works @@ -270,6 +304,15 @@ public static IEnumerable GetDetectedDevices() yield return amdDev; } } + // INTEL + if (DetectionResult.IntelDevices != null) + { + foreach (var intelDev in DetectionResult.IntelDevices) + { + yield return intelDev; + } + } + // FAKE if (DetectionResult.FAKEDevices != null) { foreach (var fakeDev in DetectionResult.FAKEDevices) @@ -282,13 +325,13 @@ public static IEnumerable GetDetectedDevices() } // We check only missing from inital detection. Case like device poping back is not covered (ultra rare case) - public static async Task CheckIfMissingGPUs() + public static async Task<(bool isMissing, List uuids)> CheckIfMissingGPUs(bool detectIntegrated) { - async Task anyMissingCUDA_Devices() + async Task<(bool isMissing, List uuids)> anyMissingCUDA_Devices() { try { - if (!DetectionResult.HasCUDADevices) return false; + if (!DetectionResult.HasCUDADevices) return (false, new List()); var cudaQueryResult = await CUDADetector.TryQueryCUDADevicesAsync(); var supportedCudaDevices = cudaQueryResult.parsed.CudaDevices .Select(CUDADetector.Transform) @@ -299,21 +342,21 @@ async Task anyMissingCUDA_Devices() if (missing.Any()) { Logger.Error(Tag, $"CUDA missing devices:\n{string.Join("\n", missing.Select(dev => $"\t{dev.UUID}"))}"); - return true; + return (true, missing.Select(dev => dev.UUID).ToList()); } } catch (Exception e) { Logger.Error(Tag, $"CUDA CheckIfMissingDevices error: {e}"); } - return false; + return (false, new List()); } - async Task anyMissingAMD_Devices() + async Task<(bool isMissing, List uuids)> anyMissingAMD_Devices() { try { - if (!DetectionResult.HasAMDDevices) return false; - var amdDevices = await AMD.AMDDetector.TryQueryAMDDevicesAsync(DetectionResult.AvailableVideoControllers.ToList()); + if (!DetectionResult.HasAMDDevices) return (false, new List()); + var amdDevices = await AMD.AMDDetector.TryQueryAMDDevicesAsync(DetectionResult.AvailableVideoControllers.ToList(), detectIntegrated); var amdDevicesUUIDs = amdDevices .Select(dev => dev.UUID) .ToArray(); @@ -321,16 +364,46 @@ async Task anyMissingAMD_Devices() if (missing.Any()) { Logger.Error(Tag, $"AMD missing devices:\n{string.Join("\n", missing.Select(dev => $"\t{dev.UUID}"))}"); - return true; + return (true, missing.Select(dev => dev.UUID).ToList()); } } catch (Exception e) { Logger.Error(Tag, $"AMD CheckIfMissingDevices error: {e}"); } - return false; + return (false, new List()); + } + async Task<(bool isMissing, List uuids)> anyMissingIntel_Devices() + { + try + { + if (!DetectionResult.HasIntelDevices) return (false, new List()); + var intelDevices = await IntelGpuDetector.TryQueryIGCLDevicesAsync(); + var intelDevicesUUIDs = intelDevices.parsed.IgclDevices + .Select(IntelGpuDetector.Transform) + .Select(dev => dev.UUID) + .ToArray(); + var missing = DetectionResult.IntelDevices.Where(detected => !intelDevicesUUIDs.Contains(detected.UUID)); + if (missing.Any()) + { + Logger.Error(Tag, $"IntelGPU missing devices:\n{string.Join("\n", missing.Select(dev => $"\t{dev.UUID}"))}"); + return (true, missing.Select(dev => dev.UUID).ToList()); + } + } + catch (Exception e) + { + Logger.Error(Tag, $"AMD CheckIfMissingDevices error: {e}"); + } + return (false, new List()); + } + var amdsMissing = await anyMissingAMD_Devices(); + var nvsMissing = await anyMissingCUDA_Devices(); + var intelMissing = await anyMissingIntel_Devices(); + if(!amdsMissing.isMissing && !nvsMissing.isMissing && !intelMissing.isMissing) + { + return (false, new List()); } - return await anyMissingCUDA_Devices() || await anyMissingAMD_Devices(); + return (true, nvsMissing.uuids.Concat(amdsMissing.uuids).Concat(intelMissing.uuids).ToList()); } } } diff --git a/src/NHM.DeviceDetection/DeviceDetectionResult.cs b/src/NHM.DeviceDetection/DeviceDetectionResult.cs index e61434709..c1bf78174 100644 --- a/src/NHM.DeviceDetection/DeviceDetectionResult.cs +++ b/src/NHM.DeviceDetection/DeviceDetectionResult.cs @@ -31,7 +31,10 @@ public class DeviceDetectionResult public Version AmdDriver { get; internal set; } public bool AMDDriverObsolete { get; internal set; } - + // INTEL + public IReadOnlyList IntelDevices { get; internal set; } = new List(); + public bool HasIntelDevices => IntelDevices != null && IntelDevices.Count > 0; + public Version IntelDriver { get; internal set; } // FAKE public IReadOnlyList FAKEDevices { get; internal set; } diff --git a/src/NHM.DeviceDetection/DeviceDetectionStep.cs b/src/NHM.DeviceDetection/DeviceDetectionStep.cs index 20a8a0010..fdf6809e0 100644 --- a/src/NHM.DeviceDetection/DeviceDetectionStep.cs +++ b/src/NHM.DeviceDetection/DeviceDetectionStep.cs @@ -6,6 +6,7 @@ public enum DeviceDetectionStep WMIVideoControllers, NVIDIA_CUDA, AMD_OpenCL, + INTEL_GPU, FAKE } } diff --git a/src/NHM.DeviceDetection/IntelGPU/IntelGpuDetector.cs b/src/NHM.DeviceDetection/IntelGPU/IntelGpuDetector.cs new file mode 100644 index 000000000..c4c5c60c1 --- /dev/null +++ b/src/NHM.DeviceDetection/IntelGPU/IntelGpuDetector.cs @@ -0,0 +1,101 @@ +using Newtonsoft.Json; +using NHM.Common; +using NHM.Common.Device; +using NHM.Common.Enums; +using NHM.UUID; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace NHM.DeviceDetection.IntelGPU +{ + internal static class IntelGpuDetector + { + private const string Tag = "IntelGpuDetector"; + + public static async Task<(string rawOutput, IntelGpuDeviceDetectionResult parsed)> TryQueryIGCLDevicesAsync() + { + var execStr = "igcl -n"; + Logger.Info(Tag, $"TryQueryIGCLDevicesAsync START {execStr}"); + var result = await DeviceDetectionPrinter.GetDeviceDetectionResultAsync(execStr, 30 * 1000); + Logger.Info(Tag, $"TryQueryIGCLDevicesAsync END {execStr}"); + + return result; + } + + private static string convertSize(double size) + { + try + { + string[] units = new string[] { "B", "KB", "MB", "GB", "TB", "PB" }; + double mod = 1024.0; + int i = 0; + + while (size >= mod) + { + size /= mod; + i++; + } + var GBResult = Math.Round(size, 0); + // if number is odd we can assume that free memory was presented and we can return the upper even... + if (GBResult > 5.0 && GBResult % 2 != 0)//1,3,5gb gpus exist + { + GBResult += 1; + } + return GBResult + units[i]; + } + catch + { + return null; + } + } + + public static IntelDevice Transform(IntelGpuDeviceDetectionResult.Device igclDevice) + { + var uuid = ""; + // if no nvml loaded fallback ID + if (string.IsNullOrEmpty(uuid)) + { + var infoToHashed = $"{igclDevice.PciDeviceId}--{DeviceType.INTEL}--{igclDevice.DeviceName}--{igclDevice.PciBusID}"; + var uuidHEX = UUID.UUID.GetHexUUID(infoToHashed); + uuid = $"GPU-{uuidHEX}"; + } + var intelDev = new IntelDevice + { + DeviceType = DeviceType.INTEL, + UUID = uuid, + Name = igclDevice.DeviceName, + ID = igclDevice.PciDeviceId, + PCIeBusID = igclDevice.PciBusID, + GpuRam = igclDevice.DeviceMemory, + RawDeviceData = JsonConvert.SerializeObject(igclDevice), + }; + if (Version.TryParse(igclDevice.DriverVersion, out var parsedVer)) intelDev.DEVICE_INTEL_DRIVER = parsedVer; + return intelDev; + } + + public static void LogDevices(StringBuilder stringBuilder, IEnumerable devs) + { + if (devs == null || devs.Count() == 0) + { + var emptyStr = "\tADDED DEVICES ZERO"; + stringBuilder.AppendLine(emptyStr); + return; + } + var supportedStr = "ADDED"; + stringBuilder.AppendLine($"\t{supportedStr} devices:"); + foreach (var intelDev in devs) + { + stringBuilder.AppendLine($"\t\t--"); + stringBuilder.AppendLine($"\t\tUUID: {intelDev.UUID}"); + stringBuilder.AppendLine($"\t\tID: {intelDev.ID}"); + stringBuilder.AppendLine($"\t\tBusID: {intelDev.PCIeBusID}"); + stringBuilder.AppendLine($"\t\tNAME: {intelDev.Name}"); + stringBuilder.AppendLine($"\t\tMEMORY: {intelDev.GpuRam}"); + stringBuilder.AppendLine($"\t\tDRIVER: {intelDev.DEVICE_INTEL_DRIVER}"); + } + } + } +} diff --git a/src/NHM.DeviceDetection/IntelGPU/IntelGpuDeviceDetectionResult.cs b/src/NHM.DeviceDetection/IntelGPU/IntelGpuDeviceDetectionResult.cs new file mode 100644 index 000000000..f621729f3 --- /dev/null +++ b/src/NHM.DeviceDetection/IntelGPU/IntelGpuDeviceDetectionResult.cs @@ -0,0 +1,29 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace NHM.DeviceDetection.IntelGPU +{ + [Serializable] + internal class IntelGpuDeviceDetectionResult + { + internal record Device + { + public int VendorId { get; set; } + public int PciSubSystemId { get; set; } + public int PciDeviceId { get; set; } + public int PciBusID { get; set; } + public string DeviceName { get; set; } + public string DriverVersion { get; set; } + public ulong DeviceMemory { get; set; } + public bool IsIntegrated { get; set; } + } + + public List IgclDevices { get; set; } + public string ErrorString { get; set; } + public int IgclLoaded { get; set; } + public int IgclInitialized { get; set; } + } +} diff --git a/src/NHM.DeviceDetection/Properties/AssemblyInfo.cs b/src/NHM.DeviceDetection/Properties/AssemblyInfo.cs index 872290833..cae1f37fa 100644 --- a/src/NHM.DeviceDetection/Properties/AssemblyInfo.cs +++ b/src/NHM.DeviceDetection/Properties/AssemblyInfo.cs @@ -32,6 +32,6 @@ // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("3.1.0.4")] -[assembly: AssemblyFileVersion("3.1.0.4")] +[assembly: AssemblyVersion("3.1.1.6")] +[assembly: AssemblyFileVersion("3.1.1.6")] [assembly: InternalsVisibleTo("NHM.DeviceDetectionTests")] diff --git a/src/NHM.DeviceMonitoring/AMD/AMD_ODN.cs b/src/NHM.DeviceMonitoring/AMD/AMD_ODN.cs index d598208d7..dbf01eccf 100644 --- a/src/NHM.DeviceMonitoring/AMD/AMD_ODN.cs +++ b/src/NHM.DeviceMonitoring/AMD/AMD_ODN.cs @@ -35,6 +35,8 @@ internal static class AMD_ODN [DllImport(dll, CallingConvention = CallingConvention.StdCall)] public static extern int nhm_amd_device_set_fan_speed_percentage(int bus_number, int set_fan_speed_percentage); [DllImport(dll, CallingConvention = CallingConvention.StdCall)] + public static extern int nhm_amd_device_reset_fan_speed_percentage(int bus_number); + [DllImport(dll, CallingConvention = CallingConvention.StdCall)] public static extern int nhm_amd_device_get_tdp_min_max_default(int bus_number, ref int min, ref int max, ref int defaultV); [DllImport(dll, CallingConvention = CallingConvention.StdCall)] public static extern int nhm_amd_device_get_tdp(int bus_number, ref int get_tdp); @@ -47,15 +49,27 @@ internal static class AMD_ODN [DllImport(dll, CallingConvention = CallingConvention.StdCall)] public static extern int nhm_amd_device_set_core_clocks(int bus_number, int core_clocks); [DllImport(dll, CallingConvention = CallingConvention.StdCall)] + public static extern int nhm_amd_device_reset_core_clocks(int bus_number); + [DllImport(dll, CallingConvention = CallingConvention.StdCall)] public static extern int nhm_amd_device_get_memory_clocks_min_max_default(int bus_number, ref int min, ref int max, ref int defaultV); [DllImport(dll, CallingConvention = CallingConvention.StdCall)] public static extern int nhm_amd_device_get_memory_clocks(int bus_number, ref int memory_clocks); [DllImport(dll, CallingConvention = CallingConvention.StdCall)] public static extern int nhm_amd_device_set_memory_clocks(int bus_number, int memory_clocks); [DllImport(dll, CallingConvention = CallingConvention.StdCall)] + public static extern int nhm_amd_device_reset_memory_clocks(int bus_number); + [DllImport(dll, CallingConvention = CallingConvention.StdCall)] public static extern int nhm_amd_device_get_special_temperatures(int bus_number, ref int hotspot_temp, ref int vram_temp); [DllImport(dll, CallingConvention = CallingConvention.StdCall)] public static extern int nhm_amd_device_get_memory_controller_load(int bus_number, ref int mem_ctrl_load); + [DllImport(dll, CallingConvention = CallingConvention.StdCall)] + public static extern int nhm_amd_device_get_voltage_min_max_default(int bus_number, ref int min, ref int max, ref int default_v); + [DllImport(dll, CallingConvention = CallingConvention.StdCall)] + public static extern int nhm_amd_device_get_voltage(int bus_number, ref int voltage); + [DllImport(dll, CallingConvention = CallingConvention.StdCall)] + public static extern int nhm_amd_device_set_voltage(int bus_number, int voltage); + [DllImport(dll, CallingConvention = CallingConvention.StdCall)] + public static extern int nhm_amd_device_reset_voltage(int bus_number); [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)] diff --git a/src/NHM.DeviceMonitoring/Core_clock/ICoreClock.cs b/src/NHM.DeviceMonitoring/Core_clock/ICoreClock.cs new file mode 100644 index 000000000..d0cde77ae --- /dev/null +++ b/src/NHM.DeviceMonitoring/Core_clock/ICoreClock.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace NHM.DeviceMonitoring.Core_clock +{ + public interface ICoreClock + { + int CoreClock { get; } + } +} diff --git a/src/NHM.DeviceMonitoring/Core_clock/ICoreClockDelta.cs b/src/NHM.DeviceMonitoring/Core_clock/ICoreClockDelta.cs new file mode 100644 index 000000000..7a7fa5f6f --- /dev/null +++ b/src/NHM.DeviceMonitoring/Core_clock/ICoreClockDelta.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace NHM.DeviceMonitoring.Core_clock +{ + public interface ICoreClockDelta + { + int CoreClockDelta { get; } + } +} diff --git a/src/NHM.DeviceMonitoring/Core_clock/ICoreClockRange.cs b/src/NHM.DeviceMonitoring/Core_clock/ICoreClockRange.cs new file mode 100644 index 000000000..b81e1872f --- /dev/null +++ b/src/NHM.DeviceMonitoring/Core_clock/ICoreClockRange.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace NHM.DeviceMonitoring.Core_clock +{ + public interface ICoreClockRange + { + (bool ok, int min, int max, int def) CoreClockRange { get; } + } +} diff --git a/src/NHM.DeviceMonitoring/Core_clock/ICoreClockRangeDelta.cs b/src/NHM.DeviceMonitoring/Core_clock/ICoreClockRangeDelta.cs new file mode 100644 index 000000000..db02c0273 --- /dev/null +++ b/src/NHM.DeviceMonitoring/Core_clock/ICoreClockRangeDelta.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace NHM.DeviceMonitoring.Core_clock +{ + public interface ICoreClockRangeDelta + { + (bool ok, int min, int max, int def) CoreClockRangeDelta { get; } + } +} diff --git a/src/NHM.DeviceMonitoring/Core_clock/ICoreClockSet.cs b/src/NHM.DeviceMonitoring/Core_clock/ICoreClockSet.cs new file mode 100644 index 000000000..3ded2c1c2 --- /dev/null +++ b/src/NHM.DeviceMonitoring/Core_clock/ICoreClockSet.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace NHM.DeviceMonitoring.Core_clock +{ + public interface ICoreClockSet + { + bool SetCoreClock(int coreClock); + bool ResetCoreClock(); + } +} diff --git a/src/NHM.DeviceMonitoring/Core_clock/ICoreClockSetDelta.cs b/src/NHM.DeviceMonitoring/Core_clock/ICoreClockSetDelta.cs new file mode 100644 index 000000000..ac8afe6ad --- /dev/null +++ b/src/NHM.DeviceMonitoring/Core_clock/ICoreClockSetDelta.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace NHM.DeviceMonitoring.Core_clock +{ + public interface ICoreClockSetDelta + { + bool SetCoreClockDelta(int coreClock); + bool ResetCoreClockDelta(); + } +} diff --git a/src/NHM.DeviceMonitoring/Core_voltage/ICoreVoltage.cs b/src/NHM.DeviceMonitoring/Core_voltage/ICoreVoltage.cs new file mode 100644 index 000000000..ac3a3c303 --- /dev/null +++ b/src/NHM.DeviceMonitoring/Core_voltage/ICoreVoltage.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace NHM.DeviceMonitoring.Core_voltage +{ + public interface ICoreVoltage + { + int CoreVoltage { get; } + } +} diff --git a/src/NHM.DeviceMonitoring/Core_voltage/ICoreVoltageRange.cs b/src/NHM.DeviceMonitoring/Core_voltage/ICoreVoltageRange.cs new file mode 100644 index 000000000..6e14c62b8 --- /dev/null +++ b/src/NHM.DeviceMonitoring/Core_voltage/ICoreVoltageRange.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace NHM.DeviceMonitoring.Core_voltage +{ + public interface ICoreVoltageRange + { + (bool ok, int min, int max, int def) CoreVoltageRange { get; } + } +} diff --git a/src/NHM.DeviceMonitoring/Core_voltage/ICoreVoltageSet.cs b/src/NHM.DeviceMonitoring/Core_voltage/ICoreVoltageSet.cs new file mode 100644 index 000000000..01231bb71 --- /dev/null +++ b/src/NHM.DeviceMonitoring/Core_voltage/ICoreVoltageSet.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace NHM.DeviceMonitoring.Core_voltage +{ + public interface ICoreVoltageSet + { + bool SetCoreVoltage(int coreVoltage); + bool ResetCoreVoltage(); + } +} diff --git a/src/NHM.DeviceMonitoring/DeviceMonitorAMD.cs b/src/NHM.DeviceMonitoring/DeviceMonitorAMD.cs index 234cedfa3..1cc477180 100644 --- a/src/NHM.DeviceMonitoring/DeviceMonitorAMD.cs +++ b/src/NHM.DeviceMonitoring/DeviceMonitorAMD.cs @@ -1,13 +1,19 @@ using NHM.Common; using NHM.DeviceMonitoring.AMD; +using NHM.DeviceMonitoring.Core_clock; +using NHM.DeviceMonitoring.Core_voltage; +using NHM.DeviceMonitoring.Memory_clock; +using NHM.DeviceMonitoring.NVIDIA; using NHM.DeviceMonitoring.TDP; using System; namespace NHM.DeviceMonitoring { - internal class DeviceMonitorAMD : DeviceMonitor, IFanSpeedRPM, IGetFanSpeedPercentage, ILoad, IPowerUsage, ITemp, ITDP, IMemControllerLoad, ISpecialTemps + internal class DeviceMonitorAMD : DeviceMonitor, IFanSpeedRPM, IGetFanSpeedPercentage, ILoad, IPowerUsage, ITemp, ITDP, IMemControllerLoad, ISpecialTemps, ICoreClock, IMemoryClock, ICoreClockSet, IMemoryClockSet, IMemoryClockRange, ICoreClockRange, ISetFanSpeedPercentage, IResetFanSpeed, ICoreVoltageRange, ICoreVoltage, ICoreVoltageSet, ITDPLimits { public int BusID { get; private set; } + private const int RET_OK = 0; + private static readonly TimeSpan _delayedLogging = TimeSpan.FromMinutes(0.5); @@ -50,7 +56,7 @@ internal DeviceMonitorAMD(string uuid, int busID) { int percentage = 0; int ok = AMD_ODN.nhm_amd_device_get_fan_speed_percentage(BusID, ref percentage); - if (ok != 0) Logger.InfoDelayed(LogTag, $"nhm_amd_device_get_fan_speed_rpm failed with error code {ok}", _delayedLogging); + if (ok != 0) Logger.InfoDelayed(LogTag, $"nhm_amd_device_get_fan_speed_percentage failed with error code {ok}", _delayedLogging); return (ok, percentage); } @@ -112,7 +118,15 @@ private bool SetTdpADL(double percValue) Logger.InfoDelayed(LogTag, $"nhm_amd_device_get_tdp_ranges failed with error code {ok}", _delayedLogging); return false; } - +#if NHMWS4 + int ok2 = AMD_ODN.nhm_amd_device_set_tdp(BusID, (int)percValue); + if (ok2 != 0) + { + Logger.InfoDelayed(LogTag, $"nhm_amd_device_set_tdp failed with error code {ok}", _delayedLogging); + return false; + } + return true; +#else // We limit 100% to the default as max var limit = 0.0d; if (percValue > 1) @@ -127,13 +141,14 @@ private bool SetTdpADL(double percValue) int ok2 = AMD_ODN.nhm_amd_device_set_tdp(BusID, (int)limit); if (ok2 != 0) { - Logger.InfoDelayed(LogTag, $"nhm_amd_device_set_tdp failed with error code {ok}", _delayedLogging); + Logger.InfoDelayed(LogTag, $"nhm_amd_device_set_tdp failed with error code {ok2}", _delayedLogging); return false; } return true; +#endif } - #region ITDP +#region ITDP public TDPSettingType SettingType { get; set; } = TDPSettingType.SIMPLE; public double TDPPercentage @@ -162,18 +177,13 @@ public double TDPPercentage public TDPSimpleType TDPSimple { get; private set; } = TDPSimpleType.HIGH; - public bool SetTDPPercentage(double percentage) + public bool SetTDP(double percentage) { - if (DeviceMonitorManager.DisableDevicePowerModeSettings) - { - Logger.InfoDelayed(LogTag, $"SetTDPPercentage Disabled DeviceMonitorManager.DisableDevicePowerModeSettings==true", TimeSpan.FromSeconds(30)); - return false; - } - if (percentage < 0.0d) - { - Logger.Error(LogTag, $"SetTDPPercentage {percentage} out of bounds. Setting to 0.0d"); - percentage = 0.0d; - } + //if (percentage < 0.0d) + //{ + // Logger.Error(LogTag, $"SetTDPPercentage {percentage} out of bounds. Setting to 0.0d"); + // percentage = 0.0d; + //} Logger.Info(LogTag, $"SetTDPPercentage setting to {percentage}."); return SetTdpADL(percentage); } @@ -188,11 +198,6 @@ public bool SetTDPPercentage(double percentage) public bool SetTDPSimple(TDPSimpleType level) { - if (DeviceMonitorManager.DisableDevicePowerModeSettings) - { - Logger.InfoDelayed(LogTag, $"SetTDPSimple Disabled DeviceMonitorManager.DisableDevicePowerModeSettings==true", TimeSpan.FromSeconds(30)); - return false; - } var percentage = PowerLevelToTDPPercentage(level); if (!percentage.HasValue) { @@ -206,7 +211,7 @@ public bool SetTDPSimple(TDPSimpleType level) Logger.Info(LogTag, $"SetTDPSimple {execRet}."); return execRet; } - #endregion ITDP +#endregion ITDP private (int vramTemp, int hotspotTemp) GetSpecialTemperatures() { int vramT = 0; @@ -217,6 +222,81 @@ public bool SetTDPSimple(TDPSimpleType level) return (-1, -1); } + public bool SetMemoryClock(int memoryClock) + { + var ok = AMD_ODN.nhm_amd_device_set_memory_clocks(BusID, memoryClock); + if (ok == RET_OK) return true; + Logger.InfoDelayed(LogTag, $"nhm_amd_device_set_memory_clocks failed with error code {ok}", _delayedLogging); + return false; + } + + public bool SetCoreClock(int coreClock) + { + var ok = AMD_ODN.nhm_amd_device_set_core_clocks(BusID, coreClock); + if(ok == RET_OK) return true; + Logger.InfoDelayed(LogTag, $"nhm_amd_device_set_core_clocks failed with error code {ok}", _delayedLogging); + return false; + } + + public bool SetCoreVoltage(int coreVoltage) + { + var ok = AMD_ODN.nhm_amd_device_set_voltage(BusID, coreVoltage); + if (ok == RET_OK) return true; + Logger.InfoDelayed(LogTag, $"nhm_amd_device_set_voltage failed with error code {ok}", _delayedLogging); + return false; + } + + public bool SetFanSpeedPercentage(int percentage) + { + var ok = percentage <= 0 ? AMD_ODN.nhm_amd_device_reset_fan_speed_percentage(BusID) : AMD_ODN.nhm_amd_device_set_fan_speed_percentage(BusID, percentage); + if (ok == RET_OK) return true; + Logger.InfoDelayed(LogTag, $"nhm_amd_device_set_fan_speed_percentage failed with error code {ok}", _delayedLogging); + return false; + } + + public bool ResetFanSpeedPercentage() + { + var ok = AMD_ODN.nhm_amd_device_reset_fan_speed_percentage(BusID); + if (ok == RET_OK) return true; + Logger.InfoDelayed(LogTag, $"nhm_amd_device_reset_fan_speed_percentage failed with error code {ok}", _delayedLogging); + return false; + } + + public bool ResetCoreClock() + { + var ok = AMD_ODN.nhm_amd_device_reset_core_clocks(BusID); + if (ok == RET_OK) return true; + Logger.InfoDelayed(LogTag, $"nhm_amd_device_reset_core_clocks failed with error code {ok}", _delayedLogging); + return false; + } + + public bool ResetMemoryClock() + { + var ok = AMD_ODN.nhm_amd_device_reset_memory_clocks(BusID); + if (ok == RET_OK) return true; + Logger.InfoDelayed(LogTag, $"nhm_amd_device_reset_memory_clocks failed with error code {ok}", _delayedLogging); + return false; + } + + public bool ResetCoreVoltage() + { + var ok = AMD_ODN.nhm_amd_device_reset_voltage(BusID); + if (ok == RET_OK) return true; + Logger.InfoDelayed(LogTag, $"nhm_amd_device_reset_voltage failed with error code {ok}", _delayedLogging); + return false; + } + + public (bool ok, int min, int max, int def) GetTDPLimits() + { + int min = -1; + int max = -1; + int def = -1; + var ok = AMD_ODN.nhm_amd_device_get_tdp_min_max_default(BusID, ref min, ref max, ref def); + if (ok == RET_OK) return (true, min, max, def); + Logger.InfoDelayed(LogTag, $"nhm_amd_device_get_tdp_min_max_default failed with error code {ok}", _delayedLogging); + return (false, -1, -1, -1); + } + public int HotspotTemp { get @@ -242,5 +322,83 @@ public int MemoryControllerLoad return -1; } } + + public int MemoryClock + { + get + { + int memoryClock = 0; + int ok = AMD_ODN.nhm_amd_device_get_memory_clocks(BusID, ref memoryClock); + if (ok == RET_OK) return memoryClock; + Logger.InfoDelayed(LogTag, $"nhm_amd_device_get_memory_clocks failed with error code {ok}", _delayedLogging); + return -1; + } + } + + public int CoreClock + { + get + { + int coreClock = 0; + int ok = AMD_ODN.nhm_amd_device_get_core_clocks(BusID, ref coreClock); + if (ok == RET_OK) return coreClock; + Logger.InfoDelayed(LogTag, $"nhm_amd_device_get_core_clocks failed with error code {ok}", _delayedLogging); + return -1; + } + } + + public int CoreVoltage + { + get + { + int coreVoltage = 0; + int ok = AMD_ODN.nhm_amd_device_get_voltage(BusID, ref coreVoltage); + if (ok == RET_OK) return coreVoltage; + Logger.InfoDelayed(LogTag, $"nhm_amd_device_get_voltage failed with error code {ok}", _delayedLogging); + return -1; + } + } + + public (bool ok, int min, int max, int def) MemoryClockRange + { + get + { + int min = 0; + int max = 0; + int def = 0; + int ok = AMD_ODN.nhm_amd_device_get_memory_clocks_min_max_default(BusID, ref min, ref max, ref def); + if (ok == RET_OK) return (true, min, max, def); + Logger.InfoDelayed(LogTag, $"nhm_amd_device_get_memory_clocks_min_max_default failed with error code {ok}", _delayedLogging); + return (false, -1, -1, -1); + } + } + + public (bool ok, int min, int max, int def) CoreClockRange + { + get + { + int min = 0; + int max = 0; + int def = 0; + int ok = AMD_ODN.nhm_amd_device_get_core_clocks_min_max_default(BusID, ref min, ref max, ref def); + if (ok == RET_OK) return (true, min, max, def); + Logger.InfoDelayed(LogTag, $"nhm_amd_device_get_core_clocks_min_max_default failed with error code {ok}", _delayedLogging); + return (false, -1, -1, -1); + } + } + + public (bool ok, int min, int max, int def) CoreVoltageRange + { + get + { + int min = 0; + int max = 0; + int def = 0; + int ok = AMD_ODN.nhm_amd_device_get_voltage_min_max_default(BusID, ref min, ref max, ref def); + if (ok == RET_OK) return (true, min, max, def); + Logger.InfoDelayed(LogTag, $"nhm_amd_device_get_voltage_min_max_default failed with error code {ok}", _delayedLogging); + return (false, -1, -1, -1); + } + } } } diff --git a/src/NHM.DeviceMonitoring/DeviceMonitorINTEL.cs b/src/NHM.DeviceMonitoring/DeviceMonitorINTEL.cs new file mode 100644 index 000000000..24ee57138 --- /dev/null +++ b/src/NHM.DeviceMonitoring/DeviceMonitorINTEL.cs @@ -0,0 +1,299 @@ +using NHM.Common; +using NHM.DeviceMonitoring.AMD; +using NHM.DeviceMonitoring.Core_clock; +using NHM.DeviceMonitoring.Core_voltage; +using NHM.DeviceMonitoring.INTEL; +using NHM.DeviceMonitoring.Memory_clock; +using NHM.DeviceMonitoring.NVIDIA; +using NHM.DeviceMonitoring.TDP; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace NHM.DeviceMonitoring +{ + internal class DeviceMonitorINTEL : DeviceMonitor, IFanSpeedRPM, ILoad, IPowerUsage, ITemp, ISpecialTemps, ITDP, ITDPWatts, ICoreClock, IMemoryClock, ICoreClockSet, ICoreClockRange, ICoreVoltageRange, ICoreVoltage, ICoreVoltageSet, ITDPLimits + { + public int BusID { get; private set; } + private const int RET_OK = 0; + + private static readonly TimeSpan _delayedLogging = TimeSpan.FromMinutes(0.5); + + private string LogTag => $"DeviceMonitorINTEL-uuid({UUID})-busid({BusID})"; + + internal DeviceMonitorINTEL(string uuid, int busID) + { + UUID = uuid; + BusID = busID; + } + + public int FanSpeedRPM + { + get + { + int rpm = 0; + int ok = INTEL_IGCL.nhm_intel_device_get_fan_speed_rpm(BusID, ref rpm); + if (ok == 0) return rpm; + Logger.InfoDelayed(LogTag, $"nhm_intel_device_get_fan_speed_rpm failed with error code {ok}", _delayedLogging); + return -1; + } + } + + public float Temp + { + get + { + int temperature = 0; + int ok = INTEL_IGCL.nhm_intel_device_get_temperature(BusID, ref temperature); + if (ok == 0) return temperature; + Logger.InfoDelayed(LogTag, $"nhm_intel_device_get_temperature failed with error code {ok}", _delayedLogging); + return -1; + } + } + + public float Load + { + get + { + int load_perc = 0; + int ok = INTEL_IGCL.nhm_intel_device_get_load_percentage(BusID, ref load_perc); + if (ok == 0) return load_perc; + Logger.InfoDelayed(LogTag, $"nhm_intel_device_get_load_percentage failed with error code {ok}", _delayedLogging); + return -1; + } + } + + public double PowerUsage + { + get + { + int power_usage = 0; + int ok = INTEL_IGCL.nhm_intel_device_get_power_usage(BusID, ref power_usage); + if (ok == 0) return power_usage; + Logger.InfoDelayed(LogTag, $"nhm_intel_device_get_power_usage failed with error code {ok}", _delayedLogging); + return -1; + } + } + + public int VramTemp + { + get + { + int vramT = 0; + int ok = INTEL_IGCL.nhm_intel_device_get_vram_temperature(BusID, ref vramT); + if (ok == 0) return vramT; + Logger.InfoDelayed(LogTag, $"nhm_intel_device_get_vram_temperature failed with error code {ok}", _delayedLogging); + return -1; + } + } + + public int HotspotTemp + { + get + { + return -1; + } + } + + public int CoreClock + { + get + { + int coreClock = 0; + int ok = INTEL_IGCL.nhm_intel_device_get_core_clocks(BusID, ref coreClock); + if (ok == 0) return coreClock; + Logger.InfoDelayed(LogTag, $"nhm_intel_device_get_core_clocks failed with error code {ok}", _delayedLogging); + return -1; + } + } + + public int MemoryClock + { + get + { + int memClock = 0; + int ok = INTEL_IGCL.nhm_intel_device_get_memory_clocks(BusID, ref memClock); + if (ok == 0) return memClock; + Logger.InfoDelayed(LogTag, $"nhm_intel_device_get_memory_clocks failed with error code {ok}", _delayedLogging); + return -1; + } + } + + public int CoreVoltage + { + get + { + int coreVoltage = 0; + int ok = INTEL_IGCL.nhm_intel_device_get_core_voltage(BusID, ref coreVoltage); + if (ok == RET_OK) return coreVoltage; + Logger.InfoDelayed(LogTag, $"nhm_intel_device_get_core_voltage failed with error code {ok}", _delayedLogging); + return -1; + } + } + + public TDPSettingType SettingType { get; set; } = TDPSettingType.SIMPLE; + + public int TDPWatts + { + get + { + int tdpRaw = 0; + int ok = INTEL_IGCL.nhm_intel_device_get_power_limit(BusID, ref tdpRaw); + if (ok != 0) + { + Logger.InfoDelayed(LogTag, $"nhm_intel_device_get_power_limit failed with error code {ok}", _delayedLogging); + return -1; + } + return tdpRaw; + } + } + + public double TDPPercentage + { + get + { + int tdpRaw = 0; + int ok = INTEL_IGCL.nhm_intel_device_get_power_limit(BusID, ref tdpRaw); + if (ok != 0) + { + Logger.InfoDelayed(LogTag, $"nhm_intel_device_get_power_limit failed with error code {ok}", _delayedLogging); + return -1; + } + int min = 0, max = 0, defaultValue = 0; + int ok2 = INTEL_IGCL.nhm_intel_device_get_power_limit_min_max_default(BusID, ref min, ref max, ref defaultValue); + if (ok2 != 0) + { + Logger.InfoDelayed(LogTag, $"nhm_intel_device_get_power_limit_min_max_default failed with error code {ok}", _delayedLogging); + return -1; + } + // We limit 100% to the default as max + var tdpPerc = RangeCalculator.CalculatePercentage(tdpRaw, min, max); + return tdpPerc; // 0.0d - 1.0d + } + } + + public TDPSimpleType TDPSimple { get; private set; } = TDPSimpleType.HIGH; + + public (bool ok, int min, int max, int def) CoreClockRange + { + get + { + int min = 0; + int max = 0; + int def = 0; + int ok = INTEL_IGCL.nhm_intel_device_get_core_clocks_min_max_default_delta(BusID, ref min, ref max, ref def); + if (ok == RET_OK) return (true, min, max, def); + Logger.InfoDelayed(LogTag, $"nhm_intel_device_get_core_clocks_min_max_default_delta failed with error code {ok}", _delayedLogging); + return (false, -1, -1, -1); + } + } + + public (bool ok, int min, int max, int def) CoreVoltageRange + { + get + { + int min = 0; + int max = 0; + int def = 0; + int ok = INTEL_IGCL.nhm_intel_device_get_core_voltage_min_max_default_delta(BusID, ref min, ref max, ref def); + if (ok == RET_OK) return (true, min, max, def); + Logger.InfoDelayed(LogTag, $"nhm_intel_device_get_core_voltage_min_max_default_delta failed with error code {ok}", _delayedLogging); + return (false, -1, -1, -1); + } + } + + public (bool ok, int min, int max, int def) GetTDPLimits() + { + int min = -1; + int max = -1; + int def = -1; + var ok = INTEL_IGCL.nhm_intel_device_get_power_limit_min_max_default(BusID, ref min, ref max, ref def); + if (ok == RET_OK) return (true, min, max, def); + Logger.InfoDelayed(LogTag, $"nhm_intel_device_get_power_limit_min_max_default failed with error code {ok}", _delayedLogging); + return (false, -1, -1, -1); + } + + private static double? PowerLevelToTDPPercentage(TDPSimpleType level) => + level switch + { + TDPSimpleType.LOW => 0.6d, // 60% + TDPSimpleType.MEDIUM => 0.8d,// 80% + TDPSimpleType.HIGH => 1.0d, // 100% + _ => null, + }; + + public bool SetCoreClock(int coreClock) + { + var ok = INTEL_IGCL.nhm_intel_device_set_core_clocks_delta(BusID, coreClock); + if (ok == RET_OK) return true; + Logger.InfoDelayed(LogTag, $"nhm_intel_device_set_core_clocks_delta failed with error code {ok}", _delayedLogging); + return false; + } + + public bool SetCoreVoltage(int coreVoltage) + { + var ok = INTEL_IGCL.nhm_intel_device_set_core_voltage_delta(BusID, coreVoltage); + if (ok == RET_OK) return true; + Logger.InfoDelayed(LogTag, $"nhm_intel_device_set_core_voltage_delta failed with error code {ok}", _delayedLogging); + return false; + } + + public bool SetTDP(double watts) + { + var value = watts; + if (value <= 1.0d) + { + int min = -1; + int max = -1; + int def = -1; + var ok = INTEL_IGCL.nhm_intel_device_get_power_limit_min_max_default(BusID, ref min, ref max, ref def); + value = watts * def; + } + + Logger.Info(LogTag, $"SetTDP setting to {value}."); + + var execRet = INTEL_IGCL.nhm_intel_device_set_power_limit(BusID, (int)value); + Logger.Info(LogTag, $"SetTDP returned {execRet}."); + return execRet == RET_OK; + } + public bool SetTDPSimple(TDPSimpleType level) + { + var percentage = PowerLevelToTDPPercentage(level); + if (!percentage.HasValue) + { + Logger.Error(LogTag, $"SetTDPSimple unkown PowerLevel {level}. Defaulting to {TDPSimpleType.HIGH}"); + level = TDPSimpleType.HIGH; + percentage = PowerLevelToTDPPercentage(level); + } + Logger.Info(LogTag, $"SetTDPSimple setting PowerLevel to {level}."); + int min = -1; + int max = -1; + int def = -1; + var ok = INTEL_IGCL.nhm_intel_device_get_power_limit_min_max_default(BusID, ref min, ref max, ref def); + var watts = percentage * def; + + var execRet = INTEL_IGCL.nhm_intel_device_set_power_limit(BusID, (int)watts); + if (execRet == RET_OK) TDPSimple = level; + Logger.Info(LogTag, $"SetTDPSimple {execRet}."); + return execRet == RET_OK; + } + + public bool ResetCoreClock() + { + var ok = INTEL_IGCL.nhm_intel_device_reset_core_clocks_delta(BusID); + if (ok == RET_OK) return true; + Logger.InfoDelayed(LogTag, $"nhm_intel_device_reset_core_clocks_delta failed with error code {ok}", _delayedLogging); + return false; + } + + public bool ResetCoreVoltage() + { + var ok = INTEL_IGCL.nhm_intel_device_reset_core_voltage_delta(BusID); + if (ok == RET_OK) return true; + Logger.InfoDelayed(LogTag, $"nhm_intel_device_reset_core_voltage_delta failed with error code {ok}", _delayedLogging); + return false; + } + } +} diff --git a/src/NHM.DeviceMonitoring/DeviceMonitorManager.cs b/src/NHM.DeviceMonitoring/DeviceMonitorManager.cs index 2ec39fe46..6c542bdd1 100644 --- a/src/NHM.DeviceMonitoring/DeviceMonitorManager.cs +++ b/src/NHM.DeviceMonitoring/DeviceMonitorManager.cs @@ -2,6 +2,7 @@ using NHM.Common; using NHM.Common.Device; using NHM.DeviceMonitoring.AMD; +using NHM.DeviceMonitoring.INTEL; using NHM.DeviceMonitoring.NVIDIA; using System; using System.Collections.Generic; @@ -15,7 +16,6 @@ namespace NHM.DeviceMonitoring public static class DeviceMonitorManager { public static bool DisableDeviceStatusMonitoring { get; set; } = false; - public static bool DisableDevicePowerModeSettings { get; set; } = true; internal static readonly bool IsElevated; @@ -40,6 +40,7 @@ int customLogSettings(string fileName) } _amdDebugLogLevel = customLogSettings("AMD_ODN_LOG.txt"); _nvidiaDebugLogLevel = customLogSettings("NVIDIA_MON_LOG.txt"); + _intelDebugLogLevel = customLogSettings("INTEL_IGCL_LOG.txt"); try { @@ -69,6 +70,13 @@ private static void LogNvidia_MON(string logStr) Logger.InfoDelayed("NVIDIA_MON", logStr, TimeSpan.FromSeconds(10)); } + private static int _intelDebugLogLevel = 0; + private static readonly INTEL_IGCL.log_cb _intelLog= new INTEL_IGCL.log_cb(LogIntel_IGCL); + private static void LogIntel_IGCL(string logStr) + { + Logger.InfoDelayed("INTEL_IGCL", logStr, TimeSpan.FromSeconds(10)); + } + private static T[] GetDeviceTypes(this IEnumerable devices) where T : BaseDevice { return devices.Where(dev => dev is T).Cast().ToArray(); @@ -124,7 +132,6 @@ void addNVIDIAs() var initialNvmlRestartTimeWait = Math.Min(500 * nvidias.Length, 5000); // 500ms per GPU or initial MAX of 5seconds var nvidiaUUIDAndBusIds = nvidias.ToDictionary(nvidia => nvidia.UUID, nvidia => nvidia.PCIeBusID); var nvidiaInit = NVIDIA_MON.nhm_nvidia_init(); - NVIDIA_MON.nhm_nvidia_reg_log_cb(_nvidiaLog); DeviceMonitorNVIDIA.Init(); if (nvidiaInit != 0) @@ -138,9 +145,29 @@ void addNVIDIAs() ret.Add(new DeviceMonitorNVIDIA(nvidia.UUID, nvidia.PCIeBusID)); } } + void addINTELs() + { + var intels = devices.GetDeviceTypes(); + if (!intels.Any()) return; + + INTEL_IGCL.nhm_intel_set_debug_log_level(_intelDebugLogLevel); + INTEL_IGCL.nhm_intel_reg_log_cb(_intelLog); + var intelInit = INTEL_IGCL.nhm_intel_init(); + if (0 != intelInit) + { + Logger.Info("DeviceMonitorManager", $"INTEL nhm_intel_init {intelInit}"); + return; + } + + foreach( var intel in intels) + { + ret.Add(new DeviceMonitorINTEL(intel.UUID, intel.PCIeBusID)); + } + } addCPUs(); addAMDs(); addNVIDIAs(); + addINTELs(); return ret; }); } diff --git a/src/NHM.DeviceMonitoring/DeviceMonitorNVIDIA.cs b/src/NHM.DeviceMonitoring/DeviceMonitorNVIDIA.cs index 2112af7ac..a11ace877 100644 --- a/src/NHM.DeviceMonitoring/DeviceMonitorNVIDIA.cs +++ b/src/NHM.DeviceMonitoring/DeviceMonitorNVIDIA.cs @@ -1,4 +1,7 @@ using NHM.Common; +using NHM.DeviceMonitoring.Core_clock; +using NHM.DeviceMonitoring.Core_voltage; +using NHM.DeviceMonitoring.Memory_clock; using NHM.DeviceMonitoring.NVIDIA; using NHM.DeviceMonitoring.TDP; using System; @@ -6,7 +9,7 @@ namespace NHM.DeviceMonitoring { - internal class DeviceMonitorNVIDIA : DeviceMonitor, IFanSpeedRPM, IGetFanSpeedPercentage, ILoad, IPowerUsage, ITemp, ITDP, IMemoryTimings, IMemControllerLoad, ISpecialTemps + internal class DeviceMonitorNVIDIA : DeviceMonitor, IFanSpeedRPM, IGetFanSpeedPercentage, ILoad, IPowerUsage, ITemp, ITDP, ITDPWatts, IMemoryTimings, IMemControllerLoad, ISpecialTemps, ICoreClock, IMemoryClock, ICoreClockSet, IMemoryClockSet, IMemoryClockRange, ICoreClockRange, ISetFanSpeedPercentage, IResetFanSpeed, ITDPLimits, IMemoryClockDelta, ICoreClockDelta, ICoreClockRangeDelta, IMemoryClockRangeDelta, ICoreVoltage, ICoreVoltageRange, ICoreVoltageSet, ICoreClockSetDelta, IMemoryClockSetDelta { private const int RET_OK = 0; public static object _lock = new object(); @@ -134,12 +137,38 @@ public bool SetFanSpeedPercentage(int percentage) return true; } + public bool ResetFanSpeedPercentage() + { + int ok = NVIDIA_MON.nhm_nvidia_device_reset_fan(BusID); + if(ok != RET_OK) + { + Logger.InfoDelayed(LogTag, $"nhm_nvidia_device_reset_fan failed with error code {ok}", _delayedLogging); + return false; + } + return true; + } + #region ITDP public TDPSettingType SettingType { get; set; } = TDPSettingType.SIMPLE; public TDPSimpleType TDPSimple { get; private set; } = TDPSimpleType.HIGH; + public int TDPWatts + { + get + { + int tdpRaw = 0; + int ok = NVIDIA_MON.nhm_nvidia_device_get_tdp_watt(BusID, ref tdpRaw); + if (ok != RET_OK) + { + Logger.InfoDelayed(LogTag, $"nhm_nvidia_device_get_tdp_watt failed with error code {ok}", _delayedLogging); + return -1; + } + return tdpRaw; + } + } + public double TDPPercentage { get @@ -167,11 +196,6 @@ public double TDPPercentage public bool SetTDPSimple(TDPSimpleType level) { - if (DeviceMonitorManager.DisableDevicePowerModeSettings) - { - Logger.InfoDelayed(LogTag, $"SetTDPSimple Disabled DeviceMonitorManager.DisableDevicePowerModeSettings==true", TimeSpan.FromSeconds(30)); - return false; - } var percentage = PowerLevelToTDPPercentage(level); if (!percentage.HasValue) { @@ -180,32 +204,46 @@ public bool SetTDPSimple(TDPSimpleType level) percentage = PowerLevelToTDPPercentage(level); } Logger.Info(LogTag, $"SetTDPSimple setting PowerLevel to {level}."); - var execRet = NVIDIA_MON.nhm_nvidia_device_set_tdp(BusID, (int)(percentage*100)); + uint min = 0; + uint max = 0; + uint def = 0; + var ok = NVIDIA_MON.nhm_nvidia_device_get_tdp_min_max_default(BusID, ref min, ref max, ref def); + + Logger.Info(LogTag, $"SetTDPSimple setting PowerLevel to {level}."); + + var watts = percentage * def; + + var execRet = NVIDIA_MON.nhm_nvidia_device_set_tdp(BusID, (int)(watts)); if (execRet == RET_OK) TDPSimple = level; Logger.Info(LogTag, $"SetTDPSimple {execRet}."); return execRet == RET_OK; } - public bool SetTDPPercentage(double percentage) + public bool SetTDP(double watts) { - if (DeviceMonitorManager.DisableDevicePowerModeSettings) - { - Logger.InfoDelayed(LogTag, $"SetTDPPercentage Disabled DeviceMonitorManager.DisableDevicePowerModeSettings==true", TimeSpan.FromSeconds(30)); - return false; - } - if (percentage < 0.0d) + var value = watts; + if (value <= 1.0d) { - Logger.Error(LogTag, $"SetTDPPercentage {percentage} out of bounds. Setting to 0.0d"); - percentage = 0.0d; + uint min = 0; + uint max = 0; + uint def = 0; + var ok = NVIDIA_MON.nhm_nvidia_device_get_tdp_min_max_default(BusID, ref min, ref max, ref def); + value = watts * def; } - Logger.Info(LogTag, $"SetTDPPercentage setting to {percentage}."); + Logger.Info(LogTag, $"SetTDP setting to {value}."); +#if NHMWS4 + + + var execRet = NVIDIA_MON.nhm_nvidia_device_set_tdp(BusID, (int)value); +#else var execRet = NVIDIA_MON.nhm_nvidia_device_set_tdp(BusID, (int)percentage*100); - Logger.Info(LogTag, $"SetTDPPercentage {execRet}."); +#endif + Logger.Info(LogTag, $"SetTDP returned {execRet}."); return execRet == RET_OK; } - #endregion ITDP +#endregion ITDP public int SetMemoryTimings(string mt) { return NVIDIA_MON.nhm_nvidia_device_set_memory_timings(BusID, mt); @@ -248,9 +286,195 @@ public int MemoryControllerLoad return -1; } } + + public int CoreClock + { + get + { + int coreClock = 0; + int ok = NVIDIA_MON.nhm_nvidia_device_get_core_clocks(BusID, ref coreClock); + if (ok == RET_OK) return coreClock; + Logger.InfoDelayed(LogTag, $"nhm_nvidia_device_get_core_clocks failed with error code {ok}", _delayedLogging); + return -1; + } + } + + public int CoreClockDelta + { + get + { + int coreClockDelta = 0; + int ok = NVIDIA_MON.nhm_nvidia_device_get_core_clocks_delta(BusID, ref coreClockDelta); + if (ok == RET_OK) return coreClockDelta; + Logger.InfoDelayed(LogTag, $"nhm_nvidia_device_get_core_clocks_delta failed with error code {ok}", _delayedLogging); + return -1; + } + } + + public int MemoryClock + { + get + { + int memoryClock = 0; + int ok = NVIDIA_MON.nhm_nvidia_device_get_memory_clocks(BusID, ref memoryClock); + if (ok == RET_OK) return memoryClock; + Logger.InfoDelayed(LogTag, $"nhm_nvidia_device_get_memory_clocks failed with error code {ok}", _delayedLogging); + return -1; + } + } + + public int MemoryClockDelta + { + get + { + int memoryClockDelta = 0; + int ok = NVIDIA_MON.nhm_nvidia_device_get_memory_clocks_delta(BusID, ref memoryClockDelta); + if (ok == RET_OK) return memoryClockDelta; + Logger.InfoDelayed(LogTag, $"nhm_nvidia_device_get_memory_clocks_delta failed with error code {ok}", _delayedLogging); + return -1; + } + } + public int CoreVoltage + { + get + { + int coreVoltage = 0; + int ok = NVIDIA_MON.nhm_nvidia_device_get_core_voltage(BusID, ref coreVoltage); + if(ok == RET_OK) return coreVoltage; + Logger.InfoDelayed(LogTag, $"nhm_nvidia_device_get_core_voltage failed with error code {ok}", _delayedLogging); + return -1; + } + } + public void PrintMemoryTimings() { NVIDIA_MON.nhm_nvidia_device_print_memory_timings(BusID); } + + public bool SetCoreClock(int coreClock) + { + return NVIDIA_MON.nhm_nvidia_device_set_core_clocks(BusID, coreClock, true) == 0; + } + public bool SetMemoryClock(int memoryClock) + { + return NVIDIA_MON.nhm_nvidia_device_set_memory_clocks(BusID, memoryClock, true) == 0; + } + public bool SetCoreClockDelta(int coreClockDelta) + { + return NVIDIA_MON.nhm_nvidia_device_set_core_clocks(BusID, coreClockDelta, false) == 0; + } + public bool SetMemoryClockDelta(int memoryClockDelta) + { + return NVIDIA_MON.nhm_nvidia_device_set_memory_clocks(BusID, memoryClockDelta, false) == 0; + } + public (bool ok, int min, int max, int def) GetTDPLimits() + { + uint min = 0; + uint max = 0; + uint def = 0; + var ok = NVIDIA_MON.nhm_nvidia_device_get_tdp_min_max_default(BusID, ref min, ref max, ref def); + if (ok == RET_OK) return (true, (int)min, (int)max, (int)def); + Logger.InfoDelayed(LogTag, $"nhm_nvidia_device_get_tdp_min_max_default failed with error code {ok}", _delayedLogging); + return (false, 0, 0, 0); + } + + public bool SetCoreVoltage(int coreVoltage) + { + return NVIDIA_MON.nhm_nvidia_device_set_core_voltage(BusID, coreVoltage) == 0; + } + + public bool ResetCoreVoltage() + { + return NVIDIA_MON.nhm_nvidia_device_reset_core_voltage(BusID) == 0; + } + + public bool ResetMemoryClock() + { + return NVIDIA_MON.nhm_nvidia_device_reset_memory_clocks(BusID, true) == 0; + } + + public bool ResetCoreClock() + { + return NVIDIA_MON.nhm_nvidia_device_reset_core_clocks(BusID, true) == 0; + } + + public bool ResetMemoryClockDelta() + { + return NVIDIA_MON.nhm_nvidia_device_reset_memory_clocks(BusID, false) == 0; + } + + public bool ResetCoreClockDelta() + { + return NVIDIA_MON.nhm_nvidia_device_reset_core_clocks(BusID, false) == 0; + } + public (bool ok, int min, int max, int def) CoreClockRange + { + get + { + int min = 0; + int max = 0; + int def = 0; + var ok = NVIDIA_MON.nhm_nvidia_device_get_core_clocks_min_max_default_absolute(BusID, ref min, ref max, ref def); + if (ok == RET_OK) return (true, min, max, def); + Logger.InfoDelayed(LogTag, $"nhm_nvidia_device_get_core_clocks_min_max_default_absolute failed with error code {ok}", _delayedLogging); + return (false, 0, 0, 0); + + } + } + public (bool ok, int min, int max, int def) MemoryClockRange + { + get + { + int min = 0; + int max = 0; + int def = 0; + var ok = NVIDIA_MON.nhm_nvidia_device_get_memory_clocks_min_max_default_absolute(BusID, ref min, ref max, ref def); + if (ok == RET_OK) return (true, min, max, def); + Logger.InfoDelayed(LogTag, $"nhm_nvidia_device_get_memory_clocks_min_max_default_absolute failed with error code {ok}", _delayedLogging); + return (false, 0, 0, 0); + } + } + + public (bool ok, int min, int max, int def) MemoryClockRangeDelta + { + get + { + int min = 0; + int max = 0; + int def = 0; + var ok = NVIDIA_MON.nhm_nvidia_device_get_memory_clocks_min_max_default_delta(BusID, ref min, ref max, ref def); //problem here not found + if (ok == RET_OK) return (true, min, max, def); + Logger.InfoDelayed(LogTag, $"nhm_nvidia_device_get_memory_clocks_min_max_default_delta failed with error code {ok}", _delayedLogging); + return (false, 0, 0, 0); + } + } + + public (bool ok, int min, int max, int def) CoreClockRangeDelta + { + get + { + int min = 0; + int max = 0; + int def = 0; + var ok = NVIDIA_MON.nhm_nvidia_device_get_core_clocks_min_max_default_delta(BusID, ref min, ref max, ref def);//problem here not found + if(ok == RET_OK) return (true, min, max, def); + Logger.InfoDelayed(LogTag, $"nhm_nvidia_device_get_core_clocks_min_max_default_delta failed with error code {ok}", _delayedLogging); + return (false, 0, 0, 0); + } + } + + public (bool ok, int min, int max, int def) CoreVoltageRange + { + get + { + int min = 0; + int max = 0; + int def = 0; + var ok = NVIDIA_MON.nhm_nvidia_device_get_core_voltage_min_max_default(BusID, ref min, ref max, ref def); + if(ok == RET_OK) return (true, min, max, def); + Logger.InfoDelayed(LogTag, $"nhm_nvidia_device_get_core_voltage_min_max_default failed with error code {ok}", _delayedLogging); + return (false, 0, 0, 0); + } + } } } diff --git a/src/NHM.DeviceMonitoring/INTEL/INTEL_IGCL.cs b/src/NHM.DeviceMonitoring/INTEL/INTEL_IGCL.cs new file mode 100644 index 000000000..b26719697 --- /dev/null +++ b/src/NHM.DeviceMonitoring/INTEL/INTEL_IGCL.cs @@ -0,0 +1,79 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.InteropServices; +using System.Text; +using System.Threading.Tasks; + +namespace NHM.DeviceMonitoring.INTEL +{ + internal static class INTEL_IGCL + { + const string dll = "device_monitoring_intel.dll"; + public delegate void log_cb(string error); + [DllImport(dll, CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Ansi)] + public static extern int nhm_intel_reg_log_cb(log_cb cb); + [DllImport(dll, CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Ansi)] + public static extern int nhm_intel_set_debug_log_level(int level); + [DllImport(dll, CallingConvention = CallingConvention.StdCall)] + public static extern int nhm_intel_init(); + [DllImport(dll, CallingConvention = CallingConvention.StdCall)] + public static extern int nhm_intel_deinit(); + [DllImport(dll, CallingConvention = CallingConvention.StdCall)] + public static extern int nhm_intel_device_get_load_percentage(int bus_number, ref int get_load_percentage); + [DllImport(dll, CallingConvention = CallingConvention.StdCall)] + public static extern int nhm_intel_device_get_temperature(int bus_number, ref int get_temperature); + [DllImport(dll, CallingConvention = CallingConvention.StdCall)] + public static extern int nhm_intel_device_get_vram_temperature(int bus_number, ref int get_vram_temperature); + [DllImport(dll, CallingConvention = CallingConvention.StdCall)] + public static extern int nhm_intel_device_get_fan_speed_rpm(int bus_number, ref int get_fan_speed_rpm); + [DllImport(dll, CallingConvention = CallingConvention.StdCall)] + public static extern int nhm_intel_device_set_fan_speed_rpm(int bus_number, int set_fan_speed_rpm); + [DllImport(dll, CallingConvention = CallingConvention.StdCall)] + public static extern int nhm_intel_device_reset_fan_speed_rpm(int bus_number); + [DllImport(dll, CallingConvention = CallingConvention.StdCall)] + public static extern int nhm_intel_device_get_core_clocks_min_max_default_delta(int bus_number, ref int min, ref int max, ref int def); + [DllImport(dll, CallingConvention = CallingConvention.StdCall)] + public static extern int nhm_intel_device_get_core_clocks(int bus_number, ref int get_core_clock); + [DllImport(dll, CallingConvention = CallingConvention.StdCall)] + public static extern int nhm_intel_device_get_core_clocks_delta(int bus_number, ref int get_core_clock_delta); + [DllImport(dll, CallingConvention = CallingConvention.StdCall)] + public static extern int nhm_intel_device_set_core_clocks_delta(int bus_number, int set_core_clock_delta_delta); + [DllImport(dll, CallingConvention = CallingConvention.StdCall)] + public static extern int nhm_intel_device_set_locked_core_clocks(int bus_number, int set_locked_core_clock, int set_voltage); + [DllImport(dll, CallingConvention = CallingConvention.StdCall)] + public static extern int nhm_intel_device_reset_locked_core_clocks(int bus_number); + [DllImport(dll, CallingConvention = CallingConvention.StdCall)] + public static extern int nhm_intel_device_reset_core_clocks_delta(int bus_number); + [DllImport(dll, CallingConvention = CallingConvention.StdCall)] + public static extern int nhm_intel_device_get_memory_clocks_min_max_default_delta(int bus_number, ref int min, ref int max, ref int def); + [DllImport(dll, CallingConvention = CallingConvention.StdCall)] + public static extern int nhm_intel_device_get_memory_clocks(int bus_number, ref int get_memory_clock); + [DllImport(dll, CallingConvention = CallingConvention.StdCall)] + public static extern int nhm_intel_device_get_memory_clocks_delta(int bus_number, ref int get_memory_clock_delta); + [DllImport(dll, CallingConvention = CallingConvention.StdCall)] + public static extern int nhm_intel_device_set_memory_clocks_delta(int bus_number, int set_memory_clock_delta); + [DllImport(dll, CallingConvention = CallingConvention.StdCall)] + public static extern int nhm_intel_device_reset_memory_clocks_delta(int bus_number); + [DllImport(dll, CallingConvention = CallingConvention.StdCall)] + public static extern int nhm_intel_device_get_core_voltage_min_max_default_delta(int bus_number, ref int min, ref int max, ref int def); + [DllImport(dll, CallingConvention = CallingConvention.StdCall)] + public static extern int nhm_intel_device_get_core_voltage(int bus_number, ref int get_core_voltage); + [DllImport(dll, CallingConvention = CallingConvention.StdCall)] + public static extern int nhm_intel_device_get_core_voltage_delta(int bus_number, ref int get_core_voltage_delta); + [DllImport(dll, CallingConvention = CallingConvention.StdCall)] + public static extern int nhm_intel_device_set_core_voltage_delta(int bus_number, int set_core_voltage); + [DllImport(dll, CallingConvention = CallingConvention.StdCall)] + public static extern int nhm_intel_device_reset_core_voltage_delta(int bus_number); + [DllImport(dll, CallingConvention = CallingConvention.StdCall)] + public static extern int nhm_intel_device_get_power_limit_min_max_default(int bus_number, ref int min, ref int max, ref int def); + [DllImport(dll, CallingConvention = CallingConvention.StdCall)] + public static extern int nhm_intel_device_get_power_usage(int bus_number, ref int get_power_usage); + [DllImport(dll, CallingConvention = CallingConvention.StdCall)] + public static extern int nhm_intel_device_get_power_limit(int bus_number, ref int get_power_limit); + [DllImport(dll, CallingConvention = CallingConvention.StdCall)] + public static extern int nhm_intel_device_set_power_limit(int bus_number, int set_power_limit); + [DllImport(dll, CallingConvention = CallingConvention.StdCall)] + public static extern int nhm_intel_device_reset_power_limit(int bus_number); + } +} diff --git a/src/NHM.DeviceMonitoring/IResetFanSpeed.cs b/src/NHM.DeviceMonitoring/IResetFanSpeed.cs new file mode 100644 index 000000000..550338f10 --- /dev/null +++ b/src/NHM.DeviceMonitoring/IResetFanSpeed.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace NHM.DeviceMonitoring +{ + public interface IResetFanSpeed + { + bool ResetFanSpeedPercentage(); + } +} diff --git a/src/NHM.DeviceMonitoring/ISetFanSpeedPercentage.cs b/src/NHM.DeviceMonitoring/ISetFanSpeedPercentage.cs new file mode 100644 index 000000000..805a2310b --- /dev/null +++ b/src/NHM.DeviceMonitoring/ISetFanSpeedPercentage.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace NHM.DeviceMonitoring +{ + public interface ISetFanSpeedPercentage + { + bool SetFanSpeedPercentage(int percentage); + } +} diff --git a/src/NHM.DeviceMonitoring/Memory_clock/IMemoryClock.cs b/src/NHM.DeviceMonitoring/Memory_clock/IMemoryClock.cs new file mode 100644 index 000000000..78e300835 --- /dev/null +++ b/src/NHM.DeviceMonitoring/Memory_clock/IMemoryClock.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace NHM.DeviceMonitoring.Memory_clock +{ + public interface IMemoryClock + { + int MemoryClock { get; } + } +} diff --git a/src/NHM.DeviceMonitoring/Memory_clock/IMemoryClockDelta.cs b/src/NHM.DeviceMonitoring/Memory_clock/IMemoryClockDelta.cs new file mode 100644 index 000000000..da7fd1f2e --- /dev/null +++ b/src/NHM.DeviceMonitoring/Memory_clock/IMemoryClockDelta.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace NHM.DeviceMonitoring.Memory_clock +{ + public interface IMemoryClockDelta + { + int MemoryClockDelta { get; } + } +} diff --git a/src/NHM.DeviceMonitoring/Memory_clock/IMemoryClockRange.cs b/src/NHM.DeviceMonitoring/Memory_clock/IMemoryClockRange.cs new file mode 100644 index 000000000..1cb7a3dc1 --- /dev/null +++ b/src/NHM.DeviceMonitoring/Memory_clock/IMemoryClockRange.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace NHM.DeviceMonitoring.Memory_clock +{ + public interface IMemoryClockRange + { + (bool ok, int min, int max, int def) MemoryClockRange { get; } + } +} diff --git a/src/NHM.DeviceMonitoring/Memory_clock/IMemoryClockRangeDelta.cs b/src/NHM.DeviceMonitoring/Memory_clock/IMemoryClockRangeDelta.cs new file mode 100644 index 000000000..84c70b4be --- /dev/null +++ b/src/NHM.DeviceMonitoring/Memory_clock/IMemoryClockRangeDelta.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace NHM.DeviceMonitoring.Memory_clock +{ + public interface IMemoryClockRangeDelta + { + (bool ok, int min, int max, int def) MemoryClockRangeDelta { get; } + } +} diff --git a/src/NHM.DeviceMonitoring/Memory_clock/IMemoryClockSet.cs b/src/NHM.DeviceMonitoring/Memory_clock/IMemoryClockSet.cs new file mode 100644 index 000000000..0ab542009 --- /dev/null +++ b/src/NHM.DeviceMonitoring/Memory_clock/IMemoryClockSet.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace NHM.DeviceMonitoring.Memory_clock +{ + public interface IMemoryClockSet + { + bool SetMemoryClock(int memoryClock); + bool ResetMemoryClock(); + } +} diff --git a/src/NHM.DeviceMonitoring/Memory_clock/IMemoryClockSetDelta.cs b/src/NHM.DeviceMonitoring/Memory_clock/IMemoryClockSetDelta.cs new file mode 100644 index 000000000..7b8eca745 --- /dev/null +++ b/src/NHM.DeviceMonitoring/Memory_clock/IMemoryClockSetDelta.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace NHM.DeviceMonitoring.Memory_clock +{ + public interface IMemoryClockSetDelta + { + bool SetMemoryClockDelta(int memoryClock); + bool ResetMemoryClockDelta(); + } +} diff --git a/src/NHM.DeviceMonitoring/NHM.DeviceMonitoring.csproj b/src/NHM.DeviceMonitoring/NHM.DeviceMonitoring.csproj index 16afebc5e..2293fcf37 100644 --- a/src/NHM.DeviceMonitoring/NHM.DeviceMonitoring.csproj +++ b/src/NHM.DeviceMonitoring/NHM.DeviceMonitoring.csproj @@ -8,9 +8,11 @@ 1701;1702;CA1416 + $(DefineConstants)TRACE;NHMWS4 1701;1702;CA1416 + $(DefineConstants)TRACE;NHMWS4 diff --git a/src/NHM.DeviceMonitoring/NVIDIA/NVIDIA_MON.cs b/src/NHM.DeviceMonitoring/NVIDIA/NVIDIA_MON.cs index 09242a3dc..6389c34cb 100644 --- a/src/NHM.DeviceMonitoring/NVIDIA/NVIDIA_MON.cs +++ b/src/NHM.DeviceMonitoring/NVIDIA/NVIDIA_MON.cs @@ -30,35 +30,37 @@ internal static class NVIDIA_MON [DllImport(dll, CallingConvention = CallingConvention.StdCall)] public static extern int nhm_nvidia_device_get_fan_speed_rpm(int bus_number, ref int get_fan_speed_rpm); [DllImport(dll, CallingConvention = CallingConvention.StdCall)] - public static extern int nhm_nvidia_device_get_fan_speed_rpm_v2(int bus_number, ref int get_fan_speed_rpm); - [DllImport(dll, CallingConvention = CallingConvention.StdCall)] public static extern int nhm_nvidia_device_get_fan_speed_percentage(int bus_number, ref int get_fan_speed_percentage); [DllImport(dll, CallingConvention = CallingConvention.StdCall)] public static extern int nhm_nvidia_device_set_fan_speed_percentage(int bus_number, int set_fan_speed_percentage); [DllImport(dll, CallingConvention = CallingConvention.StdCall)] + public static extern int nhm_nvidia_device_reset_fan(int bus_number); + [DllImport(dll, CallingConvention = CallingConvention.StdCall)] public static extern int nhm_nvidia_device_get_tdp_min_max_default(int bus_number, ref uint min, ref uint max, ref uint defaultV); [DllImport(dll, CallingConvention = CallingConvention.StdCall)] + public static extern int nhm_nvidia_device_get_tdp_min_max_default_perc(int bus_number, ref uint min, ref uint max, ref uint def); + [DllImport(dll, CallingConvention = CallingConvention.StdCall)] public static extern int nhm_nvidia_device_get_tdp(int bus_number, ref int get_tdp); [DllImport(dll, CallingConvention = CallingConvention.StdCall)] + public static extern int nhm_nvidia_device_get_tdp_watt(int bus_number, ref int get_tdp); + [DllImport(dll, CallingConvention = CallingConvention.StdCall)] public static extern int nhm_nvidia_device_set_tdp(int bus_number, int set_tdp); [DllImport(dll, CallingConvention = CallingConvention.StdCall)] public static extern int nhm_nvidia_device_get_core_clocks(int bus_number, ref int core_clocks); [DllImport(dll, CallingConvention = CallingConvention.StdCall)] - public static extern int nhm_nvidia_device_set_core_clocks(int bus_number, int core_clocks); + public static extern int nhm_nvidia_device_get_core_clocks_delta(int bus_number, ref int core_clocks_delta); [DllImport(dll, CallingConvention = CallingConvention.StdCall)] - public static extern int nhm_nvidia_device_set_core_clocks_delta(int bus_number, int core_clocks_delta); + public static extern int nhm_nvidia_device_set_core_clocks(int bus_number, int core_clocks, bool is_absolute); [DllImport(dll, CallingConvention = CallingConvention.StdCall)] - public static extern int nhm_nvidia_device_get_memory_clocks(int bus_number, ref int memory_clocks); - [DllImport(dll, CallingConvention = CallingConvention.StdCall)] - public static extern int nhm_nvidia_device_set_memory_clocks_delta(int bus_number, int memory_clocks_delta); + public static extern int nhm_nvidia_device_reset_core_clocks(int bus_number, bool is_absolute); [DllImport(dll, CallingConvention = CallingConvention.StdCall)] - public static extern int nhm_nvidia_device_get_memory_info(int bus_number, ref ulong free, ref ulong total, ref ulong used); + public static extern int nhm_nvidia_device_get_memory_clocks(int bus_number, ref int memory_clocks); [DllImport(dll, CallingConvention = CallingConvention.StdCall)] - public static extern int nhm_nvidia_device_restore_fan_speed(int bus_number); + public static extern int nhm_nvidia_device_get_memory_clocks_delta(int bus_number, ref int memory_clocks); [DllImport(dll, CallingConvention = CallingConvention.StdCall)] - public static extern int nhm_nvidia_device_get_clocks_delta(int bus_number, ref int core_clock, ref int mem_clock); + public static extern int nhm_nvidia_device_set_memory_clocks(int bus_number, int memory_clocks, bool is_absolute); [DllImport(dll, CallingConvention = CallingConvention.StdCall)] - public static extern int nhm_nvidia_device_get_oc_limits_delta(int bus_number, ref int delta_core_min, ref int delta_core_max, ref int delta_mem_min, ref int delta_mem_max); + public static extern int nhm_nvidia_device_reset_memory_clocks(int bus_number, bool is_absolute); [DllImport(dll, CallingConvention = CallingConvention.StdCall)] public static extern int nhm_nvidia_device_set_memory_timings(int bus_number, string memory_timings); [DllImport(dll, CallingConvention = CallingConvention.StdCall)] @@ -68,15 +70,23 @@ internal static class NVIDIA_MON [DllImport(dll, CallingConvention = CallingConvention.StdCall)] public static extern int nhm_nvidia_device_get_memory_controller_load(int bus_number, ref int mem_ctrl_load); [DllImport(dll, CallingConvention = CallingConvention.StdCall)] - public static extern int nhm_nvidia_device_print_memory_timings(int bus_number); - - //Excavator no longer has these functions (or they have been moved) - //[DllImport(dll, CallingConvention = CallingConvention.StdCall)] - //public static extern int nhm_amd_device_set_memory_clocks(int bus_number, int memory_clocks); - //[DllImport(dll, CallingConvention = CallingConvention.StdCall)] - //public static extern int nhm_amd_device_get_core_clocks_min_max_default(int bus_number, ref int min, ref int max, ref int defaultV); - //[DllImport(dll, CallingConvention = CallingConvention.StdCall)] - //public static extern int nhm_amd_device_get_memory_clocks_min_max_default(int bus_number, ref int min, ref int max, ref int defaultV); + public static extern void nhm_nvidia_device_print_memory_timings(int bus_number); + [DllImport(dll, CallingConvention = CallingConvention.StdCall)] + public static extern int nhm_nvidia_device_get_core_clocks_min_max_default_absolute(int bus_number, ref int min, ref int max, ref int def); + [DllImport(dll, CallingConvention = CallingConvention.StdCall)] + public static extern int nhm_nvidia_device_get_core_clocks_min_max_default_delta(int bus_number, ref int min, ref int max, ref int def); + [DllImport(dll, CallingConvention = CallingConvention.StdCall)] + public static extern int nhm_nvidia_device_get_memory_clocks_min_max_default_absolute(int bus_number, ref int min, ref int max, ref int def); + [DllImport(dll, CallingConvention = CallingConvention.StdCall)] + public static extern int nhm_nvidia_device_get_memory_clocks_min_max_default_delta(int bus_number, ref int min, ref int max, ref int def); + [DllImport(dll, CallingConvention = CallingConvention.StdCall)] + public static extern int nhm_nvidia_device_get_core_voltage(int bus_number, ref int core_voltage); + [DllImport(dll, CallingConvention = CallingConvention.StdCall)] + public static extern int nhm_nvidia_device_get_core_voltage_min_max_default(int bus_number, ref int min, ref int max, ref int def); + [DllImport(dll, CallingConvention = CallingConvention.StdCall)] + public static extern int nhm_nvidia_device_reset_core_voltage(int bus_number); + [DllImport(dll, CallingConvention = CallingConvention.StdCall)] + public static extern int nhm_nvidia_device_set_core_voltage(int bus_number, int core_voltage); } } diff --git a/src/NHM.DeviceMonitoring/PID/PID_CONTROLLER.cs b/src/NHM.DeviceMonitoring/PID/PID_CONTROLLER.cs new file mode 100644 index 000000000..797da6672 --- /dev/null +++ b/src/NHM.DeviceMonitoring/PID/PID_CONTROLLER.cs @@ -0,0 +1,30 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.InteropServices; +using System.Text; +using System.Threading.Tasks; + +namespace NHM.DeviceMonitoring.PID +{ + internal class PID_CONTROLLER + { + const string dll = "pid_controller.dll"; + + [DllImport(dll, CallingConvention = CallingConvention.StdCall)] + public static extern int nhm_pid_init(); + [DllImport(dll, CallingConvention = CallingConvention.StdCall)] + public static extern int nhm_pid_deinit(); + [DllImport(dll, CallingConvention = CallingConvention.StdCall)] + public static extern double nhm_pid_get_output(double actual_temp, double setpoint); + + [DllImport(dll, CallingConvention = CallingConvention.StdCall)] + public static extern void nhm_set_output_limit(double fan_speed_limit); + [DllImport(dll, CallingConvention = CallingConvention.StdCall)] + public static extern void nhm_set_output_limits(double min_speed, double max_speed); + [DllImport(dll, CallingConvention = CallingConvention.StdCall)] + public static extern void nhm_set_pid(double p, double i, double d); + [DllImport(dll, CallingConvention = CallingConvention.StdCall)] + public static extern void nhm_set_reversed(bool reversed); + } +} diff --git a/src/NHM.DeviceMonitoring/PidController.cs b/src/NHM.DeviceMonitoring/PidController.cs new file mode 100644 index 000000000..bada0d1a3 --- /dev/null +++ b/src/NHM.DeviceMonitoring/PidController.cs @@ -0,0 +1,39 @@ +using NHM.DeviceMonitoring.PID; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace NHM.DeviceMonitoring +{ + public class PidController + { + + public double GetOutput(double temp, double setpoint) + { + var fan_speed = 0.0; + fan_speed = PID_CONTROLLER.nhm_pid_get_output(temp, setpoint); + return fan_speed; + } + + public void SetOutputLimit(double max_fan_speed) + { + PID_CONTROLLER.nhm_set_output_limit(max_fan_speed); + } + + public void SetOutputLimits(double min_speed, double max_speed) + { + PID_CONTROLLER.nhm_set_output_limits(min_speed, max_speed); + } + + public void SetPid(double p, double i, double d) + { + PID_CONTROLLER.nhm_set_pid(p, i, d); + } + public void SetReversed(bool reversed) + { + PID_CONTROLLER.nhm_set_reversed(reversed); + } + } +} diff --git a/src/NHM.DeviceMonitoring/Properties/AssemblyInfo.cs b/src/NHM.DeviceMonitoring/Properties/AssemblyInfo.cs index 1f8c5c2a6..98460167c 100644 --- a/src/NHM.DeviceMonitoring/Properties/AssemblyInfo.cs +++ b/src/NHM.DeviceMonitoring/Properties/AssemblyInfo.cs @@ -31,5 +31,5 @@ // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("3.1.0.4")] -[assembly: AssemblyFileVersion("3.1.0.4")] +[assembly: AssemblyVersion("3.1.1.6")] +[assembly: AssemblyFileVersion("3.1.1.6")] diff --git a/src/NHM.DeviceMonitoring/TDP/ITDP.cs b/src/NHM.DeviceMonitoring/TDP/ITDP.cs index 65aea56dc..0142c3a58 100644 --- a/src/NHM.DeviceMonitoring/TDP/ITDP.cs +++ b/src/NHM.DeviceMonitoring/TDP/ITDP.cs @@ -6,8 +6,7 @@ public interface ITDP TDPSettingType SettingType { get; set; } double TDPPercentage { get; } - bool SetTDPPercentage(double percentage); - + bool SetTDP(double percentage); TDPSimpleType TDPSimple { get; } bool SetTDPSimple(TDPSimpleType level); } diff --git a/src/NHM.DeviceMonitoring/TDP/ITDPLimits.cs b/src/NHM.DeviceMonitoring/TDP/ITDPLimits.cs new file mode 100644 index 000000000..e0e8ab284 --- /dev/null +++ b/src/NHM.DeviceMonitoring/TDP/ITDPLimits.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace NHM.DeviceMonitoring.TDP +{ + public interface ITDPLimits + { + (bool ok, int min, int max, int def) GetTDPLimits(); + } +} diff --git a/src/NHM.DeviceMonitoring/TDP/ITDPWatts.cs b/src/NHM.DeviceMonitoring/TDP/ITDPWatts.cs new file mode 100644 index 000000000..e65415751 --- /dev/null +++ b/src/NHM.DeviceMonitoring/TDP/ITDPWatts.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace NHM.DeviceMonitoring.TDP +{ + public interface ITDPWatts + { + int TDPWatts { get; } + } +} diff --git a/src/NHM.MinerPluginToolkitV1/Checkers.cs b/src/NHM.MinerPluginToolkitV1/Checkers.cs index 072906454..5d1d77443 100644 --- a/src/NHM.MinerPluginToolkitV1/Checkers.cs +++ b/src/NHM.MinerPluginToolkitV1/Checkers.cs @@ -36,7 +36,7 @@ public static bool IsGcn2(AMDDevice dev) return false; } - private static int[] _supportedMajorVersions = new int[] { 19 }; + private static int[] _supportedMajorVersions = new int[] { 24, 25 }; public static int GetLatestSupportedVersion => _supportedMajorVersions.Max(); public static IEnumerable SupportedMajorVersions => _supportedMajorVersions; public static bool IsMajorVersionSupported(int major) => _supportedMajorVersions.Contains(major); @@ -62,6 +62,15 @@ public static bool IsGcn2(AMDDevice dev) "3d4e56b0-7238-11e9-b20c-f9f12eb6d835", "4aec5ec0-10f8-11ea-bad3-8dea21141bbb", "5532d300-7238-11e9-b20c-f9f12eb6d835", + "eda6abd0-94eb-11ea-a64d-17be303ea466", + "03f80500-94ec-11ea-a64d-17be303ea466", + "074d4a80-94ec-11ea-a64d-17be303ea466", + "0a07d6a0-94ec-11ea-a64d-17be303ea466", + "1484c660-94ec-11ea-a64d-17be303ea466", + "01177a50-94ec-11ea-a64d-17be303ea466", + "fa369d10-94eb-11ea-a64d-17be303ea466", + "e7a58030-94eb-11ea-a64d-17be303ea466", + "fd45fff0-94eb-11ea-a64d-17be303ea466", }; } } diff --git a/src/NHM.MinerPluginToolkitV1/Configs/PluginSupportedAlgorithmsSettings.cs b/src/NHM.MinerPluginToolkitV1/Configs/PluginSupportedAlgorithmsSettings.cs index 55bbc1869..3fa6a7dfe 100644 --- a/src/NHM.MinerPluginToolkitV1/Configs/PluginSupportedAlgorithmsSettings.cs +++ b/src/NHM.MinerPluginToolkitV1/Configs/PluginSupportedAlgorithmsSettings.cs @@ -28,7 +28,7 @@ public class PluginSupportedAlgorithmsSettings : IInternalSetting public Dictionary> Algorithms { get; set; } = null; // for single algos - [Obsolete("UNUSED", false)] + //[Obsolete("UNUSED", false)] [JsonProperty("plugin_algorithm_name")] public Dictionary AlgorithmNames { get; set; } = null; diff --git a/src/NHM.MinerPluginToolkitV1/PluginBase.cs b/src/NHM.MinerPluginToolkitV1/PluginBase.cs index b3f5e64c9..a1f6331b8 100644 --- a/src/NHM.MinerPluginToolkitV1/PluginBase.cs +++ b/src/NHM.MinerPluginToolkitV1/PluginBase.cs @@ -167,7 +167,7 @@ public virtual bool UnsafeLimits() public virtual Dictionary> SupportedDevicesAlgorithmsDict() { - DeviceType[] deviceTypes = new DeviceType[] { DeviceType.CPU, DeviceType.AMD, DeviceType.NVIDIA }; + DeviceType[] deviceTypes = new DeviceType[] { DeviceType.CPU, DeviceType.AMD, DeviceType.NVIDIA, DeviceType.INTEL }; var ret = new Dictionary> { }; foreach (var deviceType in deviceTypes) { diff --git a/src/NHM.MinersDownloader/Properties/AssemblyInfo.cs b/src/NHM.MinersDownloader/Properties/AssemblyInfo.cs index 797030524..abc880d0b 100644 --- a/src/NHM.MinersDownloader/Properties/AssemblyInfo.cs +++ b/src/NHM.MinersDownloader/Properties/AssemblyInfo.cs @@ -31,5 +31,5 @@ // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("3.1.0.4")] -[assembly: AssemblyFileVersion("3.1.0.4")] +[assembly: AssemblyVersion("3.1.1.6")] +[assembly: AssemblyFileVersion("3.1.1.6")] diff --git a/src/NHM.UUID/Properties/AssemblyInfo.cs b/src/NHM.UUID/Properties/AssemblyInfo.cs index 1a909502d..8958b7352 100644 --- a/src/NHM.UUID/Properties/AssemblyInfo.cs +++ b/src/NHM.UUID/Properties/AssemblyInfo.cs @@ -31,5 +31,5 @@ // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("3.1.0.4")] -[assembly: AssemblyFileVersion("3.1.0.4")] +[assembly: AssemblyVersion("3.1.1.6")] +[assembly: AssemblyFileVersion("3.1.1.6")] diff --git a/src/NHMCore/ApplicationState/BenchmarkManagerState.cs b/src/NHMCore/ApplicationState/BenchmarkManagerState.cs index 53c22d990..0426b039e 100644 --- a/src/NHMCore/ApplicationState/BenchmarkManagerState.cs +++ b/src/NHMCore/ApplicationState/BenchmarkManagerState.cs @@ -56,6 +56,7 @@ private void SetStatus(AlgorithmContainer algorithmContainer) var anyToBench = _algorithmsBenchmarksStates.Where(benchStatus => benchStatus.Key.Contains(algorithmContainer.ComputeDevice.Uuid)).Where(pair => pair.Value).Count(); _deviceCanStartBenchmarkingStates[algorithmContainer.ComputeDevice.Uuid] = algorithmContainer.ComputeDevice.State == DeviceState.Stopped && anyToBench > 0; OnPropertyChanged(nameof(CanStartBenchmarking)); + OnPropertyChanged(nameof(StartEnabled)); } } @@ -134,6 +135,19 @@ public bool CanStart lock (_lock) return _canStartCount > 0; } } + private bool _startEnabled = true; + public bool StartEnabled + { + get + { + lock (_lock) return _startEnabled; + } + set + { + lock(_lock) _startEnabled = value; + OnPropertyChanged(nameof(StartEnabled)); + } + } public bool CanStartBenchmarking { @@ -171,6 +185,7 @@ internal void RemoveAlgorithmContainer(AlgorithmContainer algorithmContainer) var anyToBench = _algorithmsBenchmarksStates.Where(benchStatus => benchStatus.Key.Contains(algorithmContainer.ComputeDevice.Uuid)).Where(pair => pair.Value).Count(); _deviceCanStartBenchmarkingStates[algorithmContainer.ComputeDevice.Uuid] = algorithmContainer.ComputeDevice.State == DeviceState.Stopped && anyToBench > 0; OnPropertyChanged(nameof(CanStartBenchmarking)); + OnPropertyChanged(nameof(StartEnabled)); } } diff --git a/src/NHMCore/ApplicationState/MiningState.cs b/src/NHMCore/ApplicationState/MiningState.cs index 74d9ab7e0..74944ef29 100644 --- a/src/NHMCore/ApplicationState/MiningState.cs +++ b/src/NHMCore/ApplicationState/MiningState.cs @@ -17,6 +17,11 @@ private MiningState() _intProps = new NotifyPropertyChangedHelper(OnPropertyChanged); IsDemoMining = false; IsCurrentlyMining = false; + IsCurrentlyMiningOrELPFromRigManager = IsCurrentlyMining || + AvailableDevices.Devices + .SelectMany(d => d.AlgorithmSettings) + .Any(a => a.ActiveELPProfile != null || a.ActiveELPTestProfile != null); + IsNotRunningOrELP = !IsCurrentlyMiningOrELPFromRigManager; } // auto properties don't trigger NotifyPropertyChanged so add this shitty boilerplate @@ -65,7 +70,19 @@ public bool IsCurrentlyMining get => _boolProps.Get(nameof(IsCurrentlyMining)); private set => _boolProps.Set(nameof(IsCurrentlyMining), value); } +#if NHMWS4 + public bool IsCurrentlyMiningOrELPFromRigManager + { + get => _boolProps.Get(nameof(IsCurrentlyMiningOrELPFromRigManager)); + private set => _boolProps.Set(nameof(IsCurrentlyMiningOrELPFromRigManager), value); + } + public bool IsNotRunningOrELP + { + get => _boolProps.Get(nameof(IsNotRunningOrELP)); + private set => _boolProps.Set(nameof(IsNotRunningOrELP), value); + } +#endif #region DeviceState Counts public int StoppedDeviceStateCount { @@ -108,7 +125,7 @@ public void CalculateDevicesStateChange() // DeviceState Counts StoppedDeviceStateCount = AvailableDevices.Devices.Count(dev => dev.State == DeviceState.Stopped); #if NHMWS4 - MiningDeviceStateCount = AvailableDevices.Devices.Count(dev => dev.State == DeviceState.Mining || dev.State == DeviceState.Gaming); + MiningDeviceStateCount = AvailableDevices.Devices.Count(dev => dev.State == DeviceState.Mining || dev.State == DeviceState.Testing); #else MiningDeviceStateCount = AvailableDevices.Devices.Count(dev => dev.State == DeviceState.Mining); #endif @@ -121,12 +138,19 @@ public void CalculateDevicesStateChange() AnyDeviceEnabled = AvailableDevices.Devices.Any(dev => dev.Enabled); AnyDeviceStopped = AvailableDevices.Devices.Any(dev => dev.State == DeviceState.Stopped && (dev.State != DeviceState.Disabled)); #if NHMWS4 - AnyDeviceRunning = AvailableDevices.Devices.Any(dev => dev.State == DeviceState.Mining || dev.State == DeviceState.Benchmarking || dev.State == DeviceState.Gaming); + AnyDeviceRunning = AvailableDevices.Devices.Any(dev => dev.State == DeviceState.Mining || dev.State == DeviceState.Benchmarking || dev.State == DeviceState.Testing); #else AnyDeviceRunning = AvailableDevices.Devices.Any(dev => dev.State == DeviceState.Mining || dev.State == DeviceState.Benchmarking); #endif IsNotBenchmarkingOrMining = !AnyDeviceRunning; IsCurrentlyMining = AnyDeviceRunning; +#if NHMWS4 + IsCurrentlyMiningOrELPFromRigManager = IsCurrentlyMining || + AvailableDevices.Devices + .SelectMany(d => d.AlgorithmSettings) + .Any(a => a.ActiveELPProfile != null || a.ActiveELPTestProfile != null); + IsNotRunningOrELP = !IsCurrentlyMiningOrELPFromRigManager; +#endif IsDemoMining = !CredentialsSettings.Instance.IsBitcoinAddressValid && IsCurrentlyMining; if (IsNotBenchmarkingOrMining) MiningManuallyStarted = false; } diff --git a/src/NHMCore/ApplicationStateManager/ApplicationStateManager.Devices.cs b/src/NHMCore/ApplicationStateManager/ApplicationStateManager.Devices.cs index 86a66e290..7be705417 100644 --- a/src/NHMCore/ApplicationStateManager/ApplicationStateManager.Devices.cs +++ b/src/NHMCore/ApplicationStateManager/ApplicationStateManager.Devices.cs @@ -26,38 +26,40 @@ public static async Task SetDeviceEnabledState(object sender, (string uuid, bool // TODO log sender var isAllDevices = "*" == uuid; var devicesToSet = isAllDevices ? AvailableDevices.Devices : new ComputeDevice[] { AvailableDevices.GetDeviceWithUuidOrB64Uuid(uuid) }; - + bool startMiningViaToggleCondition = false; var tasks = devicesToSet .Where(dev => dev != null) .Distinct() .Select(dev => SetDeviceEnabledState(dev, enabled)) .ToArray(); - - var thisDevice = AvailableDevices.GetDeviceWithUuidOrB64Uuid(uuid); - var isAnyOtherDeviceMining = AvailableDevices.Devices?.Where(d => d.Enabled)? - .SelectMany(d => d.AlgorithmSettings)? - .Where(a => a.ComputeDevice.B64Uuid != thisDevice.B64Uuid)? - .Any(a => a.IsCurrentlyMining); - var isThisDeviceMining = thisDevice.AlgorithmSettings?.Any(a => a.IsCurrentlyMining); - if (isAnyOtherDeviceMining != null && isThisDeviceMining != null) //when mining and stop by toggle, this device mining is false... + foreach(var devUuid in devicesToSet.Select(d => d.Uuid)) { - if (enabled) + var thisDevice = AvailableDevices.GetDeviceWithUuidOrB64Uuid(devUuid); + var isAnyOtherDeviceMining = AvailableDevices.Devices?.Where(d => d.Enabled)? + .SelectMany(d => d.AlgorithmSettings)? + .Where(a => a.ComputeDevice.B64Uuid != thisDevice.B64Uuid)? + .Any(a => a.IsCurrentlyMining); + var isThisDeviceMining = thisDevice.AlgorithmSettings?.Any(a => a.IsCurrentlyMining); + if (isAnyOtherDeviceMining != null && isThisDeviceMining != null) //when mining and stop by toggle, this device mining is false... { - if ((bool)!isThisDeviceMining && !(bool)isAnyOtherDeviceMining && MiningState.Instance.MiningStoppedByToggle) + if (enabled) { - MiningState.Instance.MiningStoppedByToggle = false; - _ = StartAllAvailableDevicesTask(); + if ((bool)!isThisDeviceMining && !(bool)isAnyOtherDeviceMining && MiningState.Instance.MiningStoppedByToggle) + { + MiningState.Instance.MiningStoppedByToggle = false; + startMiningViaToggleCondition = true; + } } - } - else - { - if ((bool)isThisDeviceMining && !(bool)isAnyOtherDeviceMining) //todo check if this device not mining by now + else { - MiningState.Instance.MiningStoppedByToggle = true; + if ((bool)isThisDeviceMining && !(bool)isAnyOtherDeviceMining) //todo check if this device not mining by now + { + MiningState.Instance.MiningStoppedByToggle = true; + } } } } - + if(startMiningViaToggleCondition) _ = StartAllAvailableDevicesTask(); // await tasks await Task.WhenAll(tasks); } diff --git a/src/NHMCore/ApplicationStateManager/ApplicationStateManager.Init.cs b/src/NHMCore/ApplicationStateManager/ApplicationStateManager.Init.cs index c88c3863d..7c4f1b8e5 100644 --- a/src/NHMCore/ApplicationStateManager/ApplicationStateManager.Init.cs +++ b/src/NHMCore/ApplicationStateManager/ApplicationStateManager.Init.cs @@ -6,6 +6,7 @@ using NHM.DeviceMonitoring; using NHMCore.ApplicationState; using NHMCore.Configs; +using NHMCore.Configs.Managers; using NHMCore.Mining; using NHMCore.Mining.Plugins; using NHMCore.Nhmws; @@ -13,6 +14,7 @@ using NHMCore.Schedules; using NHMCore.Utils; using System; +using System.IO; using System.Linq; using System.Threading.Tasks; using static NHMCore.Translations; @@ -21,7 +23,7 @@ namespace NHMCore { static partial class ApplicationStateManager { - private static bool isInitFinished = false; + public static bool isInitFinished = false; private class LoaderConverter : IStartupLoader { @@ -54,6 +56,9 @@ int nextProgPerc() if (perc > 100) return 100; return perc; }; +#if NHMWS4 + EventManager.Instance.Init(); +#endif NotificationsManager.Instance.ReadLoggedNotifications(); // STEP // Checking System Memory @@ -72,6 +77,7 @@ string detectionStepMessage(DeviceDetectionStep step) DeviceDetectionStep.CPU => Tr("Checking CPU Info"), DeviceDetectionStep.NVIDIA_CUDA => Tr("Querying CUDA devices"), DeviceDetectionStep.AMD_OpenCL => Tr("Checking AMD OpenCL GPUs"), + DeviceDetectionStep.INTEL_GPU => Tr("Checking Intel GPUs"), _ => Tr("Checking Windows Video Controllers"), //DeviceDetectionStep.WMIWMIVideoControllers }; }; @@ -80,7 +86,7 @@ string detectionStepMessage(DeviceDetectionStep step) var msg = detectionStepMessage(step); loader.PrimaryProgress?.Report((msg, nextProgPerc())); }); - await DeviceDetection.DetectDevices(devDetectionProgress); + await DeviceDetection.DetectDevices(MiscSettings.Instance.DetectIntegratedDevices, devDetectionProgress); if(DeviceDetection.DetectionResult.CUDADevices.Any(dev => dev.IsLHR) && !Helpers.IsElevated && CUDADevice.INSTALLED_NVIDIA_DRIVERS < new Version(522, 25)) { AvailableNotifications.CreateLHRPresentAdminRunRequired(); @@ -97,6 +103,7 @@ string getDeviceNameCount(DeviceType deviceType, int index) => DeviceType.CPU => $"CPU#{index}", DeviceType.AMD => $"AMD#{index}", DeviceType.NVIDIA => $"GPU#{index}", + DeviceType.INTEL => $"INTEL#{index}", _ => $"UNKNOWN#{index}", }; @@ -109,7 +116,7 @@ string getDeviceNameCount(DeviceType deviceType, int index) => AvailableDevices.UncheckCpuIfGpu(); - var ramCheckOK = SystemSpecs.CheckRam(AvailableDevices.AvailGpus, AvailableDevices.AvailNvidiaGpuRam, AvailableDevices.AvailAmdGpuRam); + var ramCheckOK = SystemSpecs.CheckRam(AvailableDevices.AvailGpus, AvailableDevices.AvailNvidiaGpuRam, AvailableDevices.AvailAmdGpuRam, AvailableDevices.AvailIntelGpuRam); if (!ramCheckOK) { AvailableNotifications.CreateIncreaseVirtualMemoryInfo(); @@ -148,7 +155,7 @@ string getDeviceNameCount(DeviceType deviceType, int index) => // now init device settings ConfigManager.InitDeviceSettings(); - if (!Helpers.IsElevated && !GlobalDeviceSettings.Instance.DisableDevicePowerModeSettings && AvailableDevices.HasNvidia) + if (!Helpers.IsElevated && AvailableDevices.HasNvidia) { AvailableNotifications.CreateDeviceMonitoringNvidiaElevateInfo(); } @@ -177,7 +184,7 @@ string getDeviceNameCount(DeviceType deviceType, int index) => ///////////////////////////////////////////// /////// from here on we have our devices and Miners initialized MiningState.Instance.CalculateDevicesStateChange(); - + SchedulesManager.Instance.Init(); // STEP // connect to nhmws loader.PrimaryProgress?.Report((Tr("Connecting to nhmws..."), nextProgPerc())); @@ -235,20 +242,20 @@ string getDeviceNameCount(DeviceType deviceType, int index) => // Detected devices cross reference with miner indexes await MinerPluginsManager.DevicesCrossReferenceIDsWithMinerIndexes(loader); if (btc != NHMRegistry.Get_QM_MiningaddressFromRegistry() && Helpers.IsElevated && CredentialValidators.ValidateBitcoinAddress(btc)) NHMRegistry.Set_QM_MiningaddressFromRegistry(btc); - if (AvailableDevices.HasGpuToPause) - { - var deviceToPauseUuid = AvailableDevices.Devices.FirstOrDefault(dev => dev.PauseMiningWhenGamingMode && dev.DeviceType != DeviceType.CPU).Uuid; - MiningSettings.Instance.DeviceIndex = AvailableDevices.GetDeviceIndexFromUuid(deviceToPauseUuid); - } - else if (MiningSettings.Instance.DeviceToPauseUuid != "") - { - MiningSettings.Instance.DeviceIndex = AvailableDevices.GetDeviceIndexFromUuid(MiningSettings.Instance.DeviceToPauseUuid); - AvailableDevices.GPUs.FirstOrDefault(dev => dev.Uuid == MiningSettings.Instance.DeviceToPauseUuid).PauseMiningWhenGamingMode = true; - } + //if (AvailableDevices.HasGpuToPause) + //{ + // var deviceToPauseUuid = AvailableDevices.Devices.FirstOrDefault(dev => dev.PauseMiningWhenGamingMode && dev.DeviceType != DeviceType.CPU).Uuid; + // MiningSettings.Instance.DeviceIndex = AvailableDevices.GetDeviceIndexFromUuid(deviceToPauseUuid); + //} + //else if (MiningSettings.Instance.DeviceToPauseUuid != "") + //{ + // MiningSettings.Instance.DeviceIndex = AvailableDevices.GetDeviceIndexFromUuid(MiningSettings.Instance.DeviceToPauseUuid); + // AvailableDevices.GPUs.FirstOrDefault(dev => dev.Uuid == MiningSettings.Instance.DeviceToPauseUuid).PauseMiningWhenGamingMode = true; + //} else if (AvailableDevices.HasGpu) { MiningSettings.Instance.DeviceIndex = 0; - AvailableDevices.GPUs.FirstOrDefault().PauseMiningWhenGamingMode = true; + //AvailableDevices.GPUs.FirstOrDefault().PauseMiningWhenGamingMode = true; } GPUProfileManager.Instance.Init(); if (GPUProfileManager.Instance.SystemContainsSupportedDevicesNotSystemElevated) @@ -256,12 +263,24 @@ string getDeviceNameCount(DeviceType deviceType, int index) => if (MiscSettings.Instance.UseOptimizationProfiles) AvailableNotifications.CreateOptimizationProfileElevateInfo(); else AvailableNotifications.CreateOptimizationProfileNotEnabledInfo(); } - - SchedulesManager.Instance.Init(); +#if NHMWS4 + if (!Helpers.IsElevated) + { + AvailableNotifications.CreateNotAdminForRigManagement(); + } +#endif + var backupPath = Paths.ConfigsPath(".runOnStartup.txt"); + if (File.Exists(backupPath)) + { + var value = Helpers.GetRunOnStartupBackupValue(); + MiscSettings.Instance.RunAtStartup = value; + File.Delete(backupPath); + } + //SchedulesManager.Instance.Init(); } catch (Exception e) { - Logger.Error("ApplicationStateManager.Init", $"Exception: {e.Message}"); + Logger.Error("ApplicationStateManager.Init", $"Exception: {e.Message} \n TRACE:{e.StackTrace}"); } finally { diff --git a/src/NHMCore/ApplicationStateManager/ApplicationStateManager.Mining.cs b/src/NHMCore/ApplicationStateManager/ApplicationStateManager.Mining.cs index ace358fe5..728f4db58 100644 --- a/src/NHMCore/ApplicationStateManager/ApplicationStateManager.Mining.cs +++ b/src/NHMCore/ApplicationStateManager/ApplicationStateManager.Mining.cs @@ -2,7 +2,11 @@ using NHM.Common.Configs; using NHM.Common.Enums; using NHMCore.ApplicationState; +using NHMCore.Configs; using NHMCore.Mining; +using NHMCore.Nhmws; +using NHMCore.Notifications; +using NHMCore.Utils; using System; using System.Collections.Generic; using System.IO; @@ -18,6 +22,7 @@ static partial class ApplicationStateManager // TODO add check for any enabled algorithms public static async Task<(bool started, string failReason)> StartAllAvailableDevicesTask() { + EventManager.Instance.AddEventRigStarted(true); MiningState.Instance.MiningStoppedByToggle = false; // TODO consider trying to start the error state devices as well var devicesToStart = AvailableDevices.Devices.Where(dev => dev.State == DeviceState.Stopped); @@ -69,12 +74,16 @@ static partial class ApplicationStateManager device.State = DeviceState.Error; started = false; failReason = "Cannot start a device with all disabled algoirhtms"; + Logger.Error("ApplicationStateManager", $"{device.Name} is in error state due to all algos being disabled"); + EventManager.Instance.AddEventDeviceError(device.Name, device.B64Uuid); } else if (isAllZeroPayingState && !needBenchmarkOrRebench) { device.State = DeviceState.Error; started = false; failReason = "No enabled algorithm is profitable"; + Logger.Error("ApplicationStateManager", $"{device.Name} is in error state due to isAllZeroPayingState && !needBenchmarkOrRebench"); + EventManager.Instance.AddEventDeviceError(device.Name, device.B64Uuid); } else { @@ -86,8 +95,13 @@ static partial class ApplicationStateManager public static async Task<(bool stopped, string failReason)> StopAllDevicesTask() { + EventManager.Instance.AddEventRigStopped(true); // TODO when starting and stopping we are not taking Pending and Error states into account +#if NHMWS4 + var devicesToStop = AvailableDevices.Devices.Where(dev => dev.State == DeviceState.Mining || dev.State == DeviceState.Benchmarking || dev.State == DeviceState.Testing); +#else var devicesToStop = AvailableDevices.Devices.Where(dev => dev.State == DeviceState.Mining || dev.State == DeviceState.Benchmarking); +#endif if (devicesToStop.Count() == 0) { return (false, "No new devices to stop"); @@ -121,7 +135,16 @@ static partial class ApplicationStateManager return (false, $"Device {device.Uuid} already stopped"); case DeviceState.Mining: case DeviceState.Benchmarking: +#if NHMWS4 + case DeviceState.Testing: +#endif await MiningManager.StopDevice(device); +#if NHMWS4 + if (Helpers.IsElevated) + { + device.ResetEverything(); + } +#endif return (true, ""); default: return (false, $"Cannot handle state {device.State} for device {device.Uuid}"); @@ -149,7 +172,40 @@ public static void StartBenchmark() .ToArray(); _ = Task.WhenAll(startBenchmarkingDevices); } - + public static Task<(ErrorCode err, string msg)> StartReBenchmark() + { + //check if any exist + var startBenchmarkingDevices = AvailableDevices.Devices + .Where(device => device.State == DeviceState.Stopped)? + .Where(device => device.AnyAlgorithmEnabled()); + if(startBenchmarkingDevices == null || startBenchmarkingDevices.Count() == 0) + { + return Task.FromResult((ErrorCode.ErrNoAlgoDataFound, "No targets found. Stop mining first.")); + } + foreach (var device in startBenchmarkingDevices) device.PrepareForRebenchmark(); + var completeBenchmarkDevices = startBenchmarkingDevices + .Select(StartDeviceTask) + .ToArray(); + _ = Task.WhenAll(completeBenchmarkDevices); + return Task.FromResult((ErrorCode.NoError, "Success")); + } + public static Task<(ErrorCode err, string msg)> StartRebenchmarkSpecific(string deviceUUID) + { + var startBenchmarkingDevices = AvailableDevices.Devices + .Where(device => device.B64Uuid == deviceUUID)? + .Where(device => device.State == DeviceState.Stopped)? + .Where(device => device.AnyAlgorithmEnabled()); + if (startBenchmarkingDevices == null || startBenchmarkingDevices.Count() == 0) + { + return Task.FromResult((ErrorCode.ErrNoAlgoDataFound, "No targets found. Stop mining first.")); + } + foreach (var device in startBenchmarkingDevices) device.PrepareForRebenchmark(); + var completeBenchmarkDevices = startBenchmarkingDevices + .Select(StartDeviceTask) + .ToArray(); + _ = Task.WhenAll(completeBenchmarkDevices); + return Task.FromResult((ErrorCode.NoError, "Success")); + } public static Task StopBenchmark() { var stoptDevices = AvailableDevices.Devices @@ -159,14 +215,17 @@ public static Task StopBenchmark() return Task.WhenAll(stoptDevices); } - #region Updater mining state save/restore +#region Updater mining state save/restore private static string _miningStateFilePath => Paths.InternalsPath("DeviceRestoreStates.json"); private struct DeviceRestoreState { public bool IsStarted { get; set; } public DeviceState LastState { get; set; } - +#if NHMWS4 + public bool ShouldStart() => IsStarted || LastState == DeviceState.Benchmarking || LastState == DeviceState.Mining || LastState == DeviceState.Testing; +#else public bool ShouldStart() => IsStarted || LastState == DeviceState.Benchmarking || LastState == DeviceState.Mining; +#endif } internal static void SaveMiningState() { @@ -209,6 +268,6 @@ internal static async Task RestoreMiningState() await Task.WhenAll(startTasks); } - #endregion Update state push/pop +#endregion Update state push/pop } } diff --git a/src/NHMCore/ApplicationStateManager/ApplicationStateManager.Program.cs b/src/NHMCore/ApplicationStateManager/ApplicationStateManager.Program.cs index f35c905b1..f84159496 100644 --- a/src/NHMCore/ApplicationStateManager/ApplicationStateManager.Program.cs +++ b/src/NHMCore/ApplicationStateManager/ApplicationStateManager.Program.cs @@ -65,6 +65,7 @@ public static async Task BeforeExit() _beforeExitCalled = true; try { + DeviceActionsBeforeExit(); // should close websocket ExitApplication.Cancel(); ConfigManager.GeneralConfigFileCommit(); @@ -83,6 +84,16 @@ public static async Task BeforeExit() { } } + private static void DeviceActionsBeforeExit() + { + if (Helpers.IsElevated) + { + AvailableDevices.Devices.ToList().ForEach(d => { + d.ResetEverything(); + }); + + } + } private static bool _restartCalled = false; public static async Task RestartProgram() diff --git a/src/NHMCore/ApplicationStateManager/ApplicationStateManager.Timers.cs b/src/NHMCore/ApplicationStateManager/ApplicationStateManager.Timers.cs index bdf1273a4..c731f0d94 100644 --- a/src/NHMCore/ApplicationStateManager/ApplicationStateManager.Timers.cs +++ b/src/NHMCore/ApplicationStateManager/ApplicationStateManager.Timers.cs @@ -1,6 +1,9 @@ using NHM.Common; +using NHM.Common.Enums; using NHM.DeviceDetection; using NHMCore.Configs; +using NHMCore.Mining; +using NHMCore.Nhmws.V4; using NHMCore.Notifications; using NHMCore.Utils; using System; @@ -73,8 +76,12 @@ private static void StartComputeDevicesCheckTimer() // this function checks if count of CUDA devices is same as it was on application start, reason for that is // because of some reason (especially when algo switching occure) CUDA devices are dissapiring from system // creating tons of problems e.g. miners stop mining, lower rig hashrate etc. - var hasMissingGPUs = await DeviceDetection.CheckIfMissingGPUs(); - if (!hasMissingGPUs) return; + var hasMissingGPUs = await DeviceDetection.CheckIfMissingGPUs(MiscSettings.Instance.DetectIntegratedDevices); + if (!hasMissingGPUs.isMissing) return; + foreach(var missingItem in hasMissingGPUs.uuids) + { + EventManager.Instance.AddEventMissingDevice(missingItem); + } if (GlobalDeviceSettings.Instance.RestartMachineOnLostGPU) { Logger.Info("ApplicationStateManager.Timers", $"Detected missing GPUs will execute 'OnGPUsLost.bat'"); @@ -138,5 +145,50 @@ public static void StopInternetCheckTimer() } #endregion InternetCheck timer + + #region FanProfile timer + private static AppTimer _fanProfileTimer; + + public static void StartFanProfileTimer() + { + if (_fanProfileTimer?.IsActive ?? false) return; + _fanProfileTimer = new AppTimer((object sender, ElapsedEventArgs e) => + { + var devices = AvailableDevices.GPUs; + foreach (var device in devices) device.SetFanSpeedWithPidController(); + },5000); + _fanProfileTimer.Start(); + } + + public static void StopFanProfileTimer() + { + _fanProfileTimer?.Stop(); + } + #endregion + + #region DeviceTimer + private static AppTimer _deviceTimer; + + public static void StartDeviceCheckTimer() + { + if (_deviceTimer?.IsActive ?? false) return; + _deviceTimer = new AppTimer((object sender, ElapsedEventArgs e) => + { + var devs = AvailableDevices.Devices.SortedDevices(); + foreach (var d in devs) + { + if (d.DeviceType != DeviceType.CPU) + NhmwsOverheatDetector.Instance.UpdateTempsAndWarnIfNeeded(d.ID, d.Name, d.B64Uuid, (int)d.Temp, d.VramTemperature); + else + NhmwsOverheatDetector.Instance.UpdateCPUTempsAndWarnIfNeeded(d.ID, d.Name, d.B64Uuid, (int)d.Temp); + } + }, 30000); + _deviceTimer.Start(); + } + public static void StopDeviceCheckTimer() + { + _deviceTimer?.Stop(); + } + #endregion } } diff --git a/src/NHMCore/ApplicationStateManager/ApplicationStateManager.cs b/src/NHMCore/ApplicationStateManager/ApplicationStateManager.cs index ae3d6f44a..27c4918e9 100644 --- a/src/NHMCore/ApplicationStateManager/ApplicationStateManager.cs +++ b/src/NHMCore/ApplicationStateManager/ApplicationStateManager.cs @@ -37,7 +37,7 @@ public static void SetNhmwsConnectionChanged(bool isConnected) }); } - + public static void ReSendLoginMessage() => ResetNiceHashStatsCredentials(); static void ResetNiceHashStatsCredentials() { if (CredentialsSettings.Instance.IsCredentialValid) @@ -160,6 +160,10 @@ internal static bool StartMining() { StartComputeDevicesCheckTimer(); StartInternetCheckTimer(); +#if NHMWS4 + StartFanProfileTimer(); + StartDeviceCheckTimer(); +#endif return true; } @@ -167,6 +171,10 @@ internal static void StopMining() { StopComputeDevicesCheckTimer(); StopInternetCheckTimer(); +#if NHMWS4 + StopFanProfileTimer(); + StopDeviceCheckTimer(); +#endif DisplayNoInternetConnection(false); // hide warning DisplayMiningProfitable(true); // hide warning } @@ -196,7 +204,7 @@ public static RigStatus CalcRigStatus() rigState = RigStatus.Stopped; } #if NHMWS4 - var anyMining = allDevs.Any(dev => dev.State == DeviceState.Mining || dev.State == DeviceState.Gaming); + var anyMining = allDevs.Any(dev => dev.State == DeviceState.Mining || dev.State == DeviceState.Testing); #else var anyMining = allDevs.Any(dev => dev.State == DeviceState.Mining); #endif @@ -230,6 +238,8 @@ public static string CalcRigStatusString() RigStatus.Error => "ERROR", RigStatus.Pending => "PENDING", RigStatus.Disabled => "DISABLED", + //RigStatus.Gaming => "GAMING", + RigStatus.Testing => "TESTING", _ => "UNKNOWN", }; } diff --git a/src/NHMCore/Configs/ConfigManager.cs b/src/NHMCore/Configs/ConfigManager.cs index 94adad892..658105385 100644 --- a/src/NHMCore/Configs/ConfigManager.cs +++ b/src/NHMCore/Configs/ConfigManager.cs @@ -4,6 +4,7 @@ using NHMCore.Configs.Data; using NHMCore.Mining; using NHMCore.Mining.Plugins; +using NHMCore.Notifications; using NHMCore.Schedules; using System; using System.Collections.Generic; @@ -123,7 +124,7 @@ public static void CreateBackup() LogToFile = LoggingDebugConsoleSettings.Instance.LogToFile, LogMaxFileSize = LoggingDebugConsoleSettings.Instance.LogMaxFileSize, DisableWindowsErrorReporting = WarningSettings.Instance.DisableWindowsErrorReporting, - DisableDevicePowerModeSettings = GlobalDeviceSettings.Instance.DisableDevicePowerModeSettings, + AllowMultipleInstances = MiscSettings.Instance.AllowMultipleInstances, }; _benchmarkConfigsBackup = new Dictionary(); foreach (var cDev in AvailableDevices.Devices) @@ -139,14 +140,25 @@ public static bool IsRestartNeeded() || LoggingDebugConsoleSettings.Instance.LogToFile != _generalConfigBackup.LogToFile || LoggingDebugConsoleSettings.Instance.LogMaxFileSize != _generalConfigBackup.LogMaxFileSize || WarningSettings.Instance.DisableWindowsErrorReporting != _generalConfigBackup.DisableWindowsErrorReporting - || GlobalDeviceSettings.Instance.DisableDevicePowerModeSettings != _generalConfigBackup.DisableDevicePowerModeSettings; + || MiscSettings.Instance.AllowMultipleInstances != _generalConfigBackup.AllowMultipleInstances; } public static void GeneralConfigFileCommit() { ApplicationStateManager.App.Dispatcher.Invoke(() => { - InternalConfigs.WriteFileSettings(GeneralConfigPath, GeneralConfig); + var res = InternalConfigs.WriteFileSettings(GeneralConfigPath, GeneralConfig); + if (!res) + { + try + { + EventManager.Instance.AddEventGeneralCfg(); + } + catch(Exception ex) + { + Logger.Error("ConfigManager", ex.Message); + } + } ShowRestartRequired?.Invoke(null, IsRestartNeeded()); }); } @@ -227,6 +239,7 @@ private class GeneralConfigBackup public long LogMaxFileSize { get; set; } public bool DisableWindowsErrorReporting { get; set; } public bool DisableDevicePowerModeSettings { get; set; } + public bool AllowMultipleInstances { get; set; } } public static void SetDefaults() diff --git a/src/NHMCore/Configs/Data/GeneralConfig.cs b/src/NHMCore/Configs/Data/GeneralConfig.cs index 8c7a540a5..be48d5f03 100644 --- a/src/NHMCore/Configs/Data/GeneralConfig.cs +++ b/src/NHMCore/Configs/Data/GeneralConfig.cs @@ -90,6 +90,26 @@ public bool AdvancedMode get => MiscSettings.Instance.AdvancedMode; set => MiscSettings.Instance.AdvancedMode = value; } + public bool SendEvents + { + get => MiscSettings.Instance.SendEvents; + set => MiscSettings.Instance.SendEvents = value; + } + public bool AutoResetOC + { + get => MiscSettings.Instance.AutoResetOC; + set => MiscSettings.Instance.AutoResetOC = value; + } + public bool EnableGPUManagement + { + get => MiscSettings.Instance.EnableGPUManagement; + set => MiscSettings.Instance.EnableGPUManagement = value; + } + public bool DetectIntegratedDevices + { + get => MiscSettings.Instance.DetectIntegratedDevices; + set => MiscSettings.Instance.DetectIntegratedDevices = value; + } #endregion MiningSettings #region IdleMiningSettings @@ -328,11 +348,6 @@ public bool DisableDeviceStatusMonitoring get => GlobalDeviceSettings.Instance.DisableDeviceStatusMonitoring; set => GlobalDeviceSettings.Instance.DisableDeviceStatusMonitoring = value; } - public bool DisableDevicePowerModeSettings - { - get => GlobalDeviceSettings.Instance.DisableDevicePowerModeSettings; - set => GlobalDeviceSettings.Instance.DisableDevicePowerModeSettings = value; - } public bool ShowGPUPCIeBusIDs { get => GlobalDeviceSettings.Instance.ShowGPUPCIeBusIDs; @@ -412,12 +427,14 @@ public void SetDefaults() RunAtStartup = false; GUIWindowsAlwaysOnTop = false; DisableDeviceStatusMonitoring = false; - DisableDevicePowerModeSettings = true; MineRegardlessOfProfit = true; AutoUpdateNiceHashMiner2 = false; AutoUpdateMinerPlugins = true; AdvancedMode = false; + SendEvents = true; + AutoResetOC = true; + EnableGPUManagement = true; } public void SetValues(GeneralConfigOld configOld) @@ -478,12 +495,14 @@ public void SetValues(GeneralConfigOld configOld) RunAtStartup = configOld.RunAtStartup; GUIWindowsAlwaysOnTop = configOld.GUIWindowsAlwaysOnTop; DisableDeviceStatusMonitoring = configOld.DisableDeviceStatusMonitoring; - DisableDevicePowerModeSettings = configOld.DisableDevicePowerModeSettings; MineRegardlessOfProfit = configOld.MineRegardlessOfProfit; AutoUpdateNiceHashMiner2 = configOld.AutoUpdateNiceHashMiner2; AutoUpdateMinerPlugins = configOld.AutoUpdateMinerPlugins; AdvancedMode = false; + SendEvents = true; + AutoResetOC = true; + EnableGPUManagement = true; } public void FixSettingBounds() diff --git a/src/NHMCore/Configs/Data/GeneralConfigOld.cs b/src/NHMCore/Configs/Data/GeneralConfigOld.cs index 540c17217..527c0c4d6 100644 --- a/src/NHMCore/Configs/Data/GeneralConfigOld.cs +++ b/src/NHMCore/Configs/Data/GeneralConfigOld.cs @@ -320,11 +320,6 @@ public bool DisableDeviceStatusMonitoring get => GlobalDeviceSettings.Instance.DisableDeviceStatusMonitoring; set => GlobalDeviceSettings.Instance.DisableDeviceStatusMonitoring = value; } - public bool DisableDevicePowerModeSettings - { - get => GlobalDeviceSettings.Instance.DisableDevicePowerModeSettings; - set => GlobalDeviceSettings.Instance.DisableDevicePowerModeSettings = value; - } public bool ShowGPUPCIeBusIDs { get => GlobalDeviceSettings.Instance.ShowGPUPCIeBusIDs; diff --git a/src/NHMCore/Configs/ELPDataModels/AlgoELPData.cs b/src/NHMCore/Configs/ELPDataModels/AlgoELPData.cs index 6a00c089b..e9ba94cc2 100644 --- a/src/NHMCore/Configs/ELPDataModels/AlgoELPData.cs +++ b/src/NHMCore/Configs/ELPDataModels/AlgoELPData.cs @@ -1,6 +1,6 @@ using NHM.Common; using NHMCore.ApplicationState; -using NHMCore.Utils; +using NHMCore.Configs.Managers; using System; using System.Collections.Generic; using System.Collections.ObjectModel; diff --git a/src/NHMCore/Configs/ELPDataModels/MinerELPData.cs b/src/NHMCore/Configs/ELPDataModels/MinerELPData.cs index 044f5ab7e..a7b91085e 100644 --- a/src/NHMCore/Configs/ELPDataModels/MinerELPData.cs +++ b/src/NHMCore/Configs/ELPDataModels/MinerELPData.cs @@ -1,7 +1,7 @@ using NHM.Common; using NHM.MinerPluginToolkitV1.CommandLine; using NHMCore.ApplicationState; -using NHMCore.Utils; +using NHMCore.Configs.Managers; using System; using System.Collections.Generic; using System.Collections.ObjectModel; diff --git a/src/NHMCore/Configs/GlobalDeviceSettings.cs b/src/NHMCore/Configs/GlobalDeviceSettings.cs index bdddefe65..137cd2a36 100644 --- a/src/NHMCore/Configs/GlobalDeviceSettings.cs +++ b/src/NHMCore/Configs/GlobalDeviceSettings.cs @@ -40,16 +40,6 @@ public bool DisableDeviceStatusMonitoring } } - public bool DisableDevicePowerModeSettings - { - get => DeviceMonitorManager.DisableDevicePowerModeSettings; - set - { - DeviceMonitorManager.DisableDevicePowerModeSettings = value; - OnPropertyChanged(nameof(DisableDevicePowerModeSettings)); - } - } - private bool _showGPUPCIeBusIDs = false; public bool ShowGPUPCIeBusIDs { diff --git a/src/NHMCore/Configs/Managers/BundleManager.cs b/src/NHMCore/Configs/Managers/BundleManager.cs new file mode 100644 index 000000000..eacffc641 --- /dev/null +++ b/src/NHMCore/Configs/Managers/BundleManager.cs @@ -0,0 +1,123 @@ +using Newtonsoft.Json; +using NHM.Common; +using NHMCore.ApplicationState; +using NHMCore.Mining; +using NHMCore.Nhmws.V4; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace NHMCore.Configs.Managers +{ + public static class BundleManager + { + private static readonly string _TAG = "BundleManager"; + private static string BundleName = string.Empty; + private static string BundleID = string.Empty; + private static string _path = Paths.AppRootPath("bundle.json"); + public static void SetBundleInfo(string name, string id) + { + BundleName = name; + BundleID = id; + } + public static (string BundleName, string BundleID) GetBundleInfo() + { + return (BundleName, BundleID); + } + public static void ResetBundleInfo() + { + BundleName = string.Empty; + BundleID = string.Empty; + try + { + File.WriteAllText(_path, string.Empty); + } + catch (Exception e) + { + Logger.Error(_TAG, e.Message); + } + } + public static void Init() + { + if (!File.Exists(_path)) + { + File.Create(_path); + return; + } + try + { + if (!MiscSettings.Instance.EnableGPUManagement) + { + Logger.Warn("BundleManager", "Did not load bundle, Gpu management is disabled"); + return; + } + var content = File.ReadAllText(_path); + var bundleToApply = JsonConvert.DeserializeObject(content); + if(bundleToApply != null) + { + SetBundleInfo(bundleToApply.Name, bundleToApply.Id); + ApplyBundleOnInit(bundleToApply); + } + } + catch(Exception e) + { + Logger.Error(_TAG, e.Message); + File.WriteAllText(_path, string.Empty); + } + } + private static void ApplyBundleOnInit(Bundle bundle) + { + OCManager.Instance.ApplyOcBundle(bundle.OcBundles); + FanManager.Instance.ApplyFanBundle(bundle.FanBundles); + ELPManager.Instance.ApplyELPBundle(bundle.ElpBundles); + MiningState.Instance.CalculateDevicesStateChange(); + } + public static async Task SaveBundle(Bundle bundle) + { + var text = JsonConvert.SerializeObject(bundle);//todo not saving + await File.AppendAllTextAsync(_path, text); + } + public static List FindTargetGPUNames(string bundleGPU) + { + var retGPU = bundleGPU; + var potentialTargets = AvailableDevices.Devices.Where(d => d.Name.ToLower().Contains(retGPU.ToLower())); + if (potentialTargets == null) return new() { bundleGPU }; + //order matters + if (bundleGPU.ToLower().Contains("laptop gpu")) + { + return potentialTargets.Where(d => d.Name.ToLower().Contains("laptop gpu")).Select(d => d.Name.ToLower())?.ToList(); + } + if (bundleGPU.ToLower().Contains("ti")) + { + return potentialTargets.Where(d => d.Name.ToLower().Contains("ti")).Select(d => d.Name.ToLower())?.ToList(); + } + if (bundleGPU.ToLower().Contains("super")) + { + return potentialTargets.Where(d => d.Name.ToLower().Contains("super")).Select(d => d.Name.ToLower())?.ToList(); + } + if (bundleGPU.ToLower().Contains("xtx")) + { + return potentialTargets.Where(d => d.Name.ToLower().Contains("xtx")).Select(d => d.Name.ToLower())?.ToList(); + } + if (bundleGPU.ToLower().Contains("xt")) + { + return potentialTargets.Where(d => d.Name.ToLower().Contains("xt")).Select(d => d.Name.ToLower())?.ToList(); + } + if(bundleGPU.ToLower().Contains("collectors edition")) + { + return potentialTargets.Where(d => d.Name.ToLower().Contains("collectors edition")).Select(d => d.Name.ToLower())?.ToList(); + } + return potentialTargets.Where(d => !d.Name.ToLower().Contains("laptop gpu") && + !d.Name.ToLower().Contains("ti") && + !d.Name.ToLower().Contains("super") && + !d.Name.ToLower().Contains("xtx") && + !d.Name.ToLower().Contains("xt") && + !d.Name.ToLower().Contains("collectors edition")) + .Select(d => d.Name.ToLower())? + .ToList(); + } + } +} diff --git a/src/NHMCore/Utils/ELPManager.cs b/src/NHMCore/Configs/Managers/ELPManager.cs similarity index 64% rename from src/NHMCore/Utils/ELPManager.cs rename to src/NHMCore/Configs/Managers/ELPManager.cs index a97c04dd7..e5b1d497b 100644 --- a/src/NHMCore/Utils/ELPManager.cs +++ b/src/NHMCore/Configs/Managers/ELPManager.cs @@ -1,22 +1,27 @@ using NHM.Common; using NHM.Common.Enums; using NHM.MinerPluginToolkitV1.CommandLine; +using NHMCore.ApplicationState; using NHMCore.Configs; using NHMCore.Configs.ELPDataModels; using NHMCore.Mining; +using NHMCore.Nhmws; +using NHMCore.Nhmws.V4; using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Linq; +using System.Threading.Tasks; using static NHM.MinerPluginToolkitV1.CommandLine.MinerConfigManager; -namespace NHMCore.Utils +namespace NHMCore.Configs.Managers { public delegate void NotifyELPChangeEventHandler(object sender, EventArgs e); public class ELPManager { private ELPManager() { } public static ELPManager Instance { get; } = new ELPManager(); + private readonly string _TAG = "ELPManager"; public event NotifyELPChangeEventHandler ELPReiteration; const int HEADER = 0; const int FLAG = 0; @@ -47,7 +52,7 @@ public MinerConfig CreateDefaultConfig(PluginConfiguration pconf) defCfg.MinerName = pconf.PluginName; defCfg.MinerUUID = pconf.PluginUUID; defCfg.MinerCommands.AddRange(pconf.MinerSpecificCommands); - Dictionary> algorithmDevicePairs = new(); + Dictionary> algorithmDevicePairs = new(); foreach (var devAlgoPair in pconf.SupportedDevicesAlgorithms) { foreach (var algo in devAlgoPair.Value) @@ -56,14 +61,14 @@ public MinerConfig CreateDefaultConfig(PluginConfiguration pconf) var devs = pconf.Devices.Where(dev => dev.deviceType.ToString().Contains(devAlgoPair.Key))? .Select(dev => new { P = (dev.Uuid, dev.FullName) })? .Select(p => p.P); - if(devs != null) algorithmDevicePairs[algo].AddRange(devs); + if (devs != null) algorithmDevicePairs[algo].AddRange(devs); } } foreach (var algoPairs in algorithmDevicePairs) { - var devicesDict = new Dictionary(); - algoPairs.Value.ForEach(dev => devicesDict.TryAdd(dev.uuid, new Device() { DeviceName = dev.name, Commands = new List>() })); - defCfg.Algorithms.Add(new Algo() { AlgorithmName = algoPairs.Key, Devices = devicesDict }); + var devicesDict = new Dictionary(); + algoPairs.Value.ForEach(dev => devicesDict.TryAdd(dev.uuid, new MinerConfigManager.Device() { DeviceName = dev.name, Commands = new List>() })); + defCfg.Algorithms.Add(new MinerConfigManager.Algo() { AlgorithmName = algoPairs.Key, Devices = devicesDict }); } return defCfg; } @@ -103,7 +108,7 @@ public MinerConfig FixConfigIntegrityIfNeeded(MinerConfig data, PluginConfigurat public void UpdateMinerELPConfig() { - foreach(var miner in _minerELPs) + foreach (var miner in _minerELPs) { var config = ConstructConfigFromMinerELPData(miner); WriteConfig(config); @@ -198,9 +203,35 @@ public string FindAppropriateCommandForAlgoContainer(List mi var selectionGroup = devParams.Where((_, index) => group.Contains(index)).ToList(); deviceParamsGroups.Add(group, selectionGroup); } - return MinerExtraParameters.Parse(minerParams, algoParams, deviceParamsGroups.FirstOrDefault().Value.Select(v => v.paramList).ToList()); + var localPart = MinerExtraParameters.Parse(minerParams, algoParams, deviceParamsGroups.FirstOrDefault().Value.Select(v => v.paramList).ToList()); + var rigManagerPart = string.Empty; + var targetMP = miningPairs.FirstOrDefault(); + if (targetMP.ActiveELPTestProfile != null) + { + rigManagerPart = targetMP.ActiveELPTestProfile.Elp; + } + if(!targetMP.HasTestProfileAndCanSet() && targetMP.ActiveELPProfile != null) + { + rigManagerPart = targetMP.ActiveELPProfile.Elp; + } + return $"{localPart} {rigManagerPart}".Trim(); } + public void SetAlgoCMDString(AlgorithmContainer ac, string newCMD) + { + if (ac == null) return; + var target = _minerELPs + .Where(miner => miner.UUID == ac.MinerUUID)? + .FirstOrDefault()? + .Algos.Where(algo => algo.Name == ac.AlgorithmName)? + .FirstOrDefault(); + if (target == null) return; + + var index = target.AllCMDStrings.ToList().FindIndex(i => i.uuid == ac.ComputeDevice.Uuid); + if (index == -1) return; + target.AllCMDStrings.RemoveAt(index); + target.AllCMDStrings.Add((ac.ComputeDevice.Uuid, newCMD)); + } public MinerELPData ConstructMinerELPDataFromConfig(MinerConfig cfg) { var minerELP = new MinerELPData(); @@ -221,12 +252,12 @@ public MinerELPData ConstructMinerELPDataFromConfig(MinerConfig cfg) .Distinct()? .ToList(); uniqueFlags?.ForEach(f => tempAlgo.Devices[HEADER].AddELP(f)); - if (!uniqueFlags.Any()) tempAlgo.Devices[HEADER].ELPs.Add(new DeviceELPElement(false) { ELP = String.Empty }); + if (!uniqueFlags.Any()) tempAlgo.Devices[HEADER].ELPs.Add(new DeviceELPElement(false) { ELP = string.Empty }); tempAlgo.Name = algo.AlgorithmName; foreach (var dev in algo.Devices) { var tempELPElts = new DeviceELPElement[uniqueFlags?.Count + 1 ?? 1]; - tempELPElts[tempELPElts.Length - 1] = new DeviceELPElement() { ELP = String.Empty }; + tempELPElts[tempELPElts.Length - 1] = new DeviceELPElement() { ELP = string.Empty }; foreach (var arg in dev.Value.Commands) { if (arg.Count != 3) continue; @@ -261,7 +292,7 @@ private MinerConfig ConstructConfigFromMinerELPData(MinerELPData miner) miner.DoubleParams.ForEach(dbl => minerConfig.MinerCommands.Add(new List() { dbl.name, dbl.value })); foreach (var algo in miner.Algos) { - var tempAlgo = new Algo(); + var tempAlgo = new MinerConfigManager.Algo(); tempAlgo.AlgorithmName = algo.Name; if (algo.SingleParams == null) algo.SingleParams = new(); algo.SingleParams.ForEach(single => tempAlgo.AlgoCommands.Add(new List() { single })); @@ -273,14 +304,14 @@ private MinerConfig ConstructConfigFromMinerELPData(MinerELPData miner) { var deviceParams = new List>(); if (dev.IsDeviceDataHeader) continue; - for (int i = 0; i < dev.ELPs.Count; i++) + for (var i = 0; i < dev.ELPs.Count; i++) { if (header.ELPs[i] == null || header.ELPs[i].ELP == null) continue; var flagAndDelim = header.ELPs[i].ELP.Trim().Split(' '); if (flagAndDelim.Length != 2) continue; deviceParams.Add(new List { flagAndDelim[0], dev.ELPs[i].ELP, flagAndDelim[1] }); } - tempAlgo.Devices.Add(dev.UUID, new Device() { DeviceName = dev.DeviceName, Commands = deviceParams }); + tempAlgo.Devices.Add(dev.UUID, new MinerConfigManager.Device() { DeviceName = dev.DeviceName, Commands = deviceParams }); } minerConfig.Algorithms.Add(tempAlgo); } @@ -306,19 +337,19 @@ private void IterateSubModelsAndConstructELPsForPlugin(MinerELPData miner) .Select((elp, index) => new { elp, index }) .Where(item => string.IsNullOrEmpty(item.elp.ELP.Trim())) .FirstOrDefault(); - bool shouldDelete = false; - if(columnToDelete != null) shouldDelete = columnToDelete.index < header.ELPs.Count - 1; + var shouldDelete = false; + if (columnToDelete != null) shouldDelete = columnToDelete.index < header.ELPs.Count - 1; List<(string devUUID, List> paramList)> devParams = new(); if (algo.Devices == null) algo.Devices = new(); foreach (var dev in algo.Devices) { if (dev.IsDeviceDataHeader && !string.IsNullOrEmpty(dev.ELPs?.LastOrDefault()?.ELP)) shouldAddnewColumn = true; - if (shouldAddnewColumn) dev.ELPs.Add(new DeviceELPElement(!dev.IsDeviceDataHeader) { ELP = String.Empty }); + if (shouldAddnewColumn) dev.ELPs.Add(new DeviceELPElement(!dev.IsDeviceDataHeader) { ELP = string.Empty }); if (header.ELPs == null || dev.ELPs == null) continue; if (columnToDelete != null && shouldDelete) dev.ELPs.RemoveAt(columnToDelete.index); if (header.ELPs.Count != dev.ELPs.Count) continue; List> oneDevParams = new(); - for (int i = 0; i < dev.ELPs.Count; i++) + for (var i = 0; i < dev.ELPs.Count; i++) { var flagAndDelim = header.ELPs[i].ELP.Trim().Split(' '); if (flagAndDelim.Length != 2) continue; @@ -330,24 +361,24 @@ private void IterateSubModelsAndConstructELPsForPlugin(MinerELPData miner) dev.ConstructedELPs = oneDevParams; } Dictionary, List<(string devUUID, List> paramList)>> deviceParamsGroups = new(); - for (int first = 1; first < devParams.Count; first++) + for (var first = 1; first < devParams.Count; first++) { var isPartOfGroup = deviceParamsGroups.Keys.Any(keys => keys.Contains(first)); if (isPartOfGroup) continue; var group = new HashSet { first }; - for (int second = first + 1; second < devParams.Count; second++) + for (var second = first + 1; second < devParams.Count; second++) { if (MinerExtraParameters.CheckIfCanGroup(new List>> { devParams[first].paramList, devParams[second].paramList })) group.Add(second); } var selectionGroup = devParams.Where((_, index) => group.Contains(index)).ToList(); - deviceParamsGroups.Add(group, selectionGroup); + deviceParamsGroups.Add(group, selectionGroup); } var parsedCommandsPerGroup = new List<(string uuid, string command)>(); foreach (var dev in deviceParamsGroups) { var uuidList = dev.Value.Select(k => k.devUUID).ToList(); var command = MinerExtraParameters.Parse(minerParams, algoParams, dev.Value.Select(v => v.paramList).ToList()); - foreach(var uuid in uuidList) + foreach (var uuid in uuidList) { parsedCommandsPerGroup.Add((uuid, command)); } @@ -355,5 +386,118 @@ private void IterateSubModelsAndConstructELPsForPlugin(MinerELPData miner) algo.AllCMDStrings = new ObservableCollection<(string uuid, string command)>(parsedCommandsPerGroup); } } +#if NHMWS4 + public Task<(ErrorCode err, string msg)> ExecuteTest(string uuid, ElpProfile bundle) + { + if (!MiningState.Instance.AnyDeviceRunning) return Task.FromResult((ErrorCode.ErrNoDeviceRunning, "No devices mining")); + var allContainers = AvailableDevices.Devices + .Where(d => d.B64Uuid == uuid)? + .Where(d => d.State == DeviceState.Mining || d.State == DeviceState.Testing)? + .SelectMany(d => d.AlgorithmSettings); + if (allContainers == null || !allContainers.Any()) return Task.FromResult((ErrorCode.TargetDeviceNotFound, "No targets found")); + + if (bundle.AlgoId != null && bundle.MinerId != null) allContainers = allContainers.Where(d => + bundle.AlgoId.Contains(d.AlgorithmName.ToLower()) && + bundle.MinerId.Contains(d.PluginName.ToLower()))?.ToList(); + else if (bundle.AlgoId != null) allContainers = allContainers.Where(d => bundle.AlgoId.Contains(d.AlgorithmName.ToLower()))?.ToList(); + else if (bundle.MinerId != null) allContainers = allContainers.Where(d => bundle.MinerId.Contains(d.PluginName.ToLower()))?.ToList(); + if (allContainers == null || !allContainers.Any()) return Task.FromResult((ErrorCode.TargetDeviceNotFound, "Action target mismatch, containers null")); + var target = allContainers.Where(c => c.IsCurrentlyMining)?.FirstOrDefault(); + if (target == null) + { + target = allContainers.Where(c => c.Enabled)?.FirstOrDefault(); + if (target == null) return Task.FromResult((ErrorCode.TargetContainerNotFound, "Failed to switch to target algorithm container")); + } + target.SetTargetElpProfile(bundle, true); + MiningManager.TriggerSwitchCheck(); + return Task.FromResult((ErrorCode.NoError, "Success")); + } + public Task<(ErrorCode err, string msg)> StopTest(string uuid, bool triggerSwitch) + { + var targetDeviceContainer = AvailableDevices.Devices + .Where(d => d.B64Uuid == uuid)? + .SelectMany(d => d.AlgorithmSettings)? + .Where(a => a.IsTesting || a.ActiveELPTestProfile != null)? + .FirstOrDefault(); + if (targetDeviceContainer == null) + { + Logger.Warn(_TAG, "Device not found for stop ELP test"); + return Task.FromResult((ErrorCode.TargetDeviceNotFound, "Device is not in test mode")); + } + targetDeviceContainer.SetTargetElpProfile(null, true); + if (triggerSwitch) MiningManager.TriggerSwitchCheck(); + return Task.FromResult((ErrorCode.NoError, "Success")); + } + public Task<(ErrorCode err, string msg)> ApplyELPBundle(List bundles) + { + if (bundles == null) return Task.FromResult((ErrorCode.NoError, "ELPBundles == null")); + List processed = new(); + var sorted = new List<(int, ElpProfile)>(); + foreach (var bundle in bundles) + { + if (bundle.MinerId != null && bundle.AlgoId != null) sorted.Add((0, bundle)); + else if (bundle.MinerId == null && bundle.AlgoId != null) sorted.Add((1, bundle)); + else if (bundle.MinerId != null && bundle.AlgoId == null) sorted.Add((2, bundle)); + else sorted.Add((3, bundle)); + } + sorted = sorted.OrderBy(item => item.Item1).ToList(); + foreach (var (type, bundle) in sorted) + { + var targetList = BundleManager.FindTargetGPUNames(bundle.DeviceName); + if (targetList == null) continue; + var current = new List(); + if (type == 0) current = AvailableDevices.Devices + .Where(d => targetList.Contains(d.Name.ToLower()))? + .SelectMany(d => d.AlgorithmSettings)? + .Where(c => bundle.AlgoId.Contains(c.AlgorithmName.ToLower()))? + .Where(c => bundle.MinerId.Contains(c.PluginName.ToLower()))? + .ToList(); + else if (type == 1) current = AvailableDevices.Devices + .Where(d => targetList.Contains(d.Name.ToLower()))? + .SelectMany(d => d.AlgorithmSettings)? + .Where(c => bundle.AlgoId.Contains(c.AlgorithmName.ToLower()))? + .ToList(); + else if (type == 2) current = AvailableDevices.Devices + .Where(d => targetList.Contains(d.Name.ToLower()))? + .SelectMany(d => d.AlgorithmSettings)? + .Where(c => bundle.MinerId.Contains(c.PluginName.ToLower()))? + .ToList(); + else current = AvailableDevices.Devices + .Where(d => targetList.Contains(d.Name.ToLower()))? + .SelectMany(d => d.AlgorithmSettings)? + .ToList(); + if (current == null) continue; + current = current.Where(c => !processed.Contains(c)).ToList(); + processed.AddRange(current); + foreach (var container in current) + { + Logger.Warn(_TAG, $"\t{container.ComputeDevice.ID}-{container.ComputeDevice.Name}/{container.AlgorithmName}/{container.PluginName}"); + container.SetTargetElpProfile(bundle, false); + } + } + MiningManager.TriggerSwitchCheck(); + return Task.FromResult((ErrorCode.NoError, "Success")); + } + + public Task ResetELPBundle(bool triggerSwitch = true) + { + var containers = AvailableDevices.Devices.SelectMany(d => d.AlgorithmSettings); + foreach (var container in containers) + { + container.SetTargetElpProfile(null, false); + } + if (triggerSwitch) MiningManager.TriggerSwitchCheck(); + return Task.FromResult((ErrorCode.NoError, "Success")); + } + public void RestartMiningInstanceIfNeeded() //not specific enough, just elp? + { + var containers = AvailableDevices.Devices.SelectMany(d => d.AlgorithmSettings); + foreach (var c in containers) + { + //if (c.ActiveELPProfile == null && c.ActiveELPTestProfile == null) continue; //WILL NOT WORK + c.TriggerELPReset(); + } + } +#endif } } diff --git a/src/NHMCore/Configs/Managers/FanManager.cs b/src/NHMCore/Configs/Managers/FanManager.cs new file mode 100644 index 000000000..2a829ff6b --- /dev/null +++ b/src/NHMCore/Configs/Managers/FanManager.cs @@ -0,0 +1,131 @@ +using NHM.Common; +using NHM.Common.Enums; +using NHMCore.ApplicationState; +using NHMCore.Mining; +using NHMCore.Nhmws; +using NHMCore.Nhmws.V4; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace NHMCore.Configs.Managers +{ + public class FanManager + { + private FanManager() { } + public static FanManager Instance { get; } = new FanManager(); + private readonly string _TAG = "FanManager"; + + public enum FanReturn + { + Success, + PartialSuccess, + Fail + } + + public Task<(ErrorCode err, string msg)> ExecuteTest(string uuid, FanProfile bundle) + { + if (!MiningState.Instance.AnyDeviceRunning) return Task.FromResult((ErrorCode.ErrNoDeviceRunning, "No devices mining")); + var allContainers = AvailableDevices.Devices + .Where(d => d.B64Uuid == uuid)? + .Where(d => d.State == DeviceState.Mining || d.State == DeviceState.Testing)? + .SelectMany(d => d.AlgorithmSettings); + if (allContainers == null || !allContainers.Any()) return Task.FromResult((ErrorCode.TargetDeviceNotFound, "No targets found")); + + if (bundle.AlgoId != null && bundle.MinerId != null) allContainers = allContainers.Where(d => + bundle.AlgoId.Contains(d.AlgorithmName) && + bundle.MinerId.Contains(d.PluginName))?.ToList(); + else if (bundle.AlgoId != null) allContainers = allContainers.Where(d => bundle.AlgoId.Contains(d.AlgorithmName))?.ToList(); + else if (bundle.MinerId != null) allContainers = allContainers.Where(d => bundle.MinerId.Contains(d.PluginName))?.ToList(); + if (allContainers == null || !allContainers.Any()) return Task.FromResult((ErrorCode.TargetDeviceNotFound, "Action target mismatch, containers null")); + var target = allContainers.Where(c => c.IsCurrentlyMining)?.FirstOrDefault(); + if (target == null) + { + target = allContainers.Where(c => c.Enabled)?.FirstOrDefault(); + if (target == null) return Task.FromResult((ErrorCode.TargetContainerNotFound, "Failed to switch to target algorithm container")); + } + target.SetTargetFanProfile(bundle, true); + MiningManager.TriggerSwitchCheck(); + return Task.FromResult((ErrorCode.NoError, "Success")); + } + public Task<(ErrorCode err, string msg)> StopTest(string uuid, bool triggerSwitch) + { + var targetDeviceContainer = AvailableDevices.Devices + .Where(d => d.B64Uuid == uuid)? + .SelectMany(d => d.AlgorithmSettings)? + .Where(a => a.IsTesting || a.ActiveFanTestProfile != null)? + .FirstOrDefault(); + if (targetDeviceContainer == null) + { + Logger.Warn(_TAG, "Device not found for stop FAN test"); + return Task.FromResult((ErrorCode.TargetDeviceNotFound, "Device is not in test mode")); + } + targetDeviceContainer.SetTargetFanProfile(null, true); + if (triggerSwitch) MiningManager.TriggerSwitchCheck(); + return Task.FromResult((ErrorCode.NoError, "Success")); + } + public Task<(ErrorCode err, string msg)> ApplyFanBundle(List bundles) + { + if (bundles == null) return Task.FromResult((ErrorCode.NoError, "FanBundles == null")); + List processed = new(); + var sorted = new List<(int, FanProfile)>(); + foreach (var bundle in bundles) + { + if (bundle.MinerId != null && bundle.AlgoId != null) sorted.Add((0, bundle)); + else if (bundle.MinerId == null && bundle.AlgoId != null) sorted.Add((1, bundle)); + else if (bundle.MinerId != null && bundle.AlgoId == null) sorted.Add((2, bundle)); + else sorted.Add((3, bundle)); + } + sorted = sorted.OrderBy(item => item.Item1).ToList(); + foreach (var (type, bundle) in sorted) + { + var targetList = BundleManager.FindTargetGPUNames(bundle.DeviceName); + if (targetList == null) continue; + var current = new List(); + if (type == 0) current = AvailableDevices.Devices + .Where(d => targetList.Contains(d.Name.ToLower()))? + .SelectMany(d => d.AlgorithmSettings)? + .Where(c => bundle.AlgoId.Contains(c.AlgorithmName.ToLower()))? + .Where(c => bundle.MinerId.Contains(c.PluginName.ToLower()))? + .ToList(); + else if (type == 1) current = AvailableDevices.Devices + .Where(d => targetList.Contains(d.Name.ToLower()))? + .SelectMany(d => d.AlgorithmSettings)? + .Where(c => bundle.AlgoId.Contains(c.AlgorithmName.ToLower()))? + .ToList(); + else if (type == 2) current = AvailableDevices.Devices + .Where(d => targetList.Contains(d.Name.ToLower()))? + .SelectMany(d => d.AlgorithmSettings)? + .Where(c => bundle.MinerId.Contains(c.PluginName.ToLower()))? + .ToList(); + else current = AvailableDevices.Devices + .Where(d => targetList.Contains(d.Name.ToLower()))? + .SelectMany(d => d.AlgorithmSettings)? + .ToList(); + if (current == null) continue; + current = current.Where(c => !processed.Contains(c)).ToList(); + processed.AddRange(current); + foreach (var container in current) + { + Logger.Warn(_TAG, $"\t{container.ComputeDevice.ID}-{container.ComputeDevice.Name}/{container.AlgorithmName}/{container.PluginName}"); + container.SetTargetFanProfile(bundle, false); + } + } + MiningManager.TriggerSwitchCheck(); + return Task.FromResult((ErrorCode.NoError, "Success")); + } + + public Task ResetFanBundle(bool triggerSwitch = true) + { + var containers = AvailableDevices.Devices.SelectMany(d => d.AlgorithmSettings); + foreach (var container in containers) + { + container.SetTargetFanProfile(null, false); + } + if (triggerSwitch) MiningManager.TriggerSwitchCheck(); + return Task.FromResult((ErrorCode.NoError, "Success")); + } + } +} diff --git a/src/NHMCore/Configs/Managers/OCManager.cs b/src/NHMCore/Configs/Managers/OCManager.cs new file mode 100644 index 000000000..9221b5304 --- /dev/null +++ b/src/NHMCore/Configs/Managers/OCManager.cs @@ -0,0 +1,128 @@ +//using log4net.Core; +using NHM.Common; +using NHM.Common.Enums; +using NHMCore.ApplicationState; +using NHMCore.Mining; +using NHMCore.Nhmws; +using NHMCore.Nhmws.V4; +using Org.BouncyCastle.Asn1.X509; +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Linq; +using System.Reflection.Metadata; +using System.Text; +using System.Threading.Tasks; +using System.Windows; + +namespace NHMCore.Configs.Managers +{ + public class OCManager + { + private OCManager() { } + public static OCManager Instance { get; } = new OCManager(); + private readonly string _TAG = "OCManager"; + public Task<(ErrorCode err, string msg)> ExecuteTest(string uuid, OcProfile bundle) + { + if (!MiningState.Instance.AnyDeviceRunning) return Task.FromResult((ErrorCode.ErrNoDeviceRunning, "No devices mining")); + var allContainers = AvailableDevices.Devices + .Where(d => d.B64Uuid == uuid)? + .Where(d => d.State == DeviceState.Mining || d.State == DeviceState.Testing)? + .SelectMany(d => d.AlgorithmSettings); + if (allContainers == null || !allContainers.Any()) return Task.FromResult((ErrorCode.TargetDeviceNotFound, "No targets found")); + + if (bundle.AlgoId != null && bundle.MinerId != null) allContainers = allContainers.Where(d => + bundle.AlgoId.Contains(d.AlgorithmName.ToLower()) && + bundle.MinerId.Contains(d.PluginName.ToLower())); + else if (bundle.AlgoId != null) allContainers = allContainers.Where(d => bundle.AlgoId.Contains(d.AlgorithmName.ToLower())); + else if (bundle.MinerId != null) allContainers = allContainers.Where(d => bundle.MinerId.Contains(d.PluginName.ToLower())); + if (allContainers == null || !allContainers.Any()) return Task.FromResult((ErrorCode.TargetDeviceNotFound, "Action target mismatch, containers null")); + var target = allContainers.Where(c => c.IsCurrentlyMining)?.FirstOrDefault(); + if(target == null) + { + target = allContainers.Where(c => c.Enabled)?.FirstOrDefault(); + if (target == null) return Task.FromResult((ErrorCode.TargetContainerNotFound, "Failed to switch to target algorithm container")); + } + target.SetTargetOcProfile(bundle, true); + MiningManager.TriggerSwitchCheck(); + return Task.FromResult((ErrorCode.NoError, "Success")); + } + public Task<(ErrorCode err, string msg)> StopTest(string uuid, bool triggerSwitch) + { + var targetDeviceContainer = AvailableDevices.Devices + .Where(d => d.B64Uuid == uuid)? + .SelectMany(d => d.AlgorithmSettings)? + .Where(a => a.IsTesting || a.ActiveOCTestProfile != null)? + .FirstOrDefault(); + if (targetDeviceContainer == null) + { + Logger.Warn(_TAG, "Device not found for stop OC test"); + return Task.FromResult((ErrorCode.TargetDeviceNotFound, "Device is not in test mode")); + } + targetDeviceContainer.SetTargetOcProfile(null, true); + if(triggerSwitch) MiningManager.TriggerSwitchCheck(); + return Task.FromResult((ErrorCode.NoError, "Success")); + } + public Task<(ErrorCode err, string msg)> ApplyOcBundle(List bundles) + { + if (bundles == null) return Task.FromResult((ErrorCode.NoError, "OcBundles == null")); + List processed = new(); + var sorted = new List<(int, OcProfile)>(); + foreach (var bundle in bundles) + { + if (bundle.MinerId != null && bundle.AlgoId != null) sorted.Add((0, bundle)); + else if (bundle.MinerId == null && bundle.AlgoId != null) sorted.Add((1, bundle)); + else if (bundle.MinerId != null && bundle.AlgoId == null) sorted.Add((2, bundle)); + else sorted.Add((3, bundle)); + } + sorted = sorted.OrderBy(item => item.Item1).ToList(); + foreach (var (type, bundle) in sorted) + { + var targetList = BundleManager.FindTargetGPUNames(bundle.DeviceName); + if (targetList == null) continue; + var current = new List(); + if (type == 0) current = AvailableDevices.Devices + .Where(d => targetList.Contains(d.Name.ToLower()))? + .SelectMany(d => d.AlgorithmSettings)? + .Where(c => bundle.AlgoId.Contains(c.AlgorithmName.ToLower()))? + .Where(c => bundle.MinerId.Contains(c.PluginName.ToLower()))? + .ToList(); + else if (type == 1) current = AvailableDevices.Devices + .Where(d => targetList.Contains(d.Name.ToLower()))? + .SelectMany(d => d.AlgorithmSettings)? + .Where(c => bundle.AlgoId.Contains(c.AlgorithmName.ToLower()))? + .ToList(); + else if (type == 2) current = AvailableDevices.Devices + .Where(d => targetList.Contains(d.Name.ToLower()))? + .SelectMany(d => d.AlgorithmSettings)? + .Where(c => bundle.MinerId.Contains(c.PluginName.ToLower()))? + .ToList(); + else current = AvailableDevices.Devices + .Where(d => targetList.Contains(d.Name.ToLower()))? + .SelectMany(d => d.AlgorithmSettings)? + .ToList(); + if (current == null) continue; + current = current.Where(c => !processed.Contains(c)).ToList(); + processed.AddRange(current); + foreach (var container in current) + { + Logger.Warn(_TAG, $"\t{container.ComputeDevice.ID}-{container.ComputeDevice.Name}/{container.AlgorithmName}/{container.PluginName}"); + container.SetTargetOcProfile(bundle, false); + } + } + MiningManager.TriggerSwitchCheck(); + return Task.FromResult((ErrorCode.NoError, "Success")); + } + + public Task ResetOcBundle(bool triggerSwitch = true) + { + var containers = AvailableDevices.Devices.SelectMany(d => d.AlgorithmSettings); + foreach (var container in containers) + { + container.SetTargetOcProfile(null, false); + } + if (triggerSwitch) MiningManager.TriggerSwitchCheck(); + return Task.FromResult((ErrorCode.NoError, "Success")); + } + } +} diff --git a/src/NHMCore/Configs/MiningSettings.cs b/src/NHMCore/Configs/MiningSettings.cs index 127c6f082..2f8115c4e 100644 --- a/src/NHMCore/Configs/MiningSettings.cs +++ b/src/NHMCore/Configs/MiningSettings.cs @@ -1,6 +1,8 @@ using NHM.Common; using NHMCore.Mining; +using NHMCore.Nhmws.V4; using System.Collections.Generic; +using System.Threading.Tasks; namespace NHMCore.Configs { @@ -101,6 +103,9 @@ public bool UseScheduler { _useScheduler = value; OnPropertyChanged(nameof(UseScheduler)); +#if NHMWS4 + _ = Task.Run(async () => await NHWebSocketV4.UpdateMinerStatus()); +#endif } } diff --git a/src/NHMCore/Configs/MiscSettings.cs b/src/NHMCore/Configs/MiscSettings.cs index d72a83dba..4d356784c 100644 --- a/src/NHMCore/Configs/MiscSettings.cs +++ b/src/NHMCore/Configs/MiscSettings.cs @@ -94,5 +94,45 @@ public bool AdvancedMode OnPropertyChanged(nameof(AdvancedMode)); } } + private bool _sendEvents = true; + public bool SendEvents + { + get => _sendEvents; + set + { + _sendEvents = value; + OnPropertyChanged(nameof(SendEvents)); + } + } + private bool _autoResetOC = true; + public bool AutoResetOC + { + get => _autoResetOC; + set + { + _autoResetOC = value; + OnPropertyChanged(nameof(AutoResetOC)); + } + } + private bool _enableGPUManagement = true; + public bool EnableGPUManagement + { + get => _enableGPUManagement; + set + { + _enableGPUManagement = value; + OnPropertyChanged(nameof(EnableGPUManagement)); + } + } + private bool _detectIntegratedDevs = true; + public bool DetectIntegratedDevices + { + get => _detectIntegratedDevs; + set + { + _detectIntegratedDevs = value; + OnPropertyChanged(nameof(DetectIntegratedDevices)); + } + } } } diff --git a/src/NHMCore/Configs/UpdateSettings.cs b/src/NHMCore/Configs/UpdateSettings.cs index 9080a4fdd..28e8b6253 100644 --- a/src/NHMCore/Configs/UpdateSettings.cs +++ b/src/NHMCore/Configs/UpdateSettings.cs @@ -1,4 +1,6 @@ using NHM.Common; +using NHMCore.Nhmws.V4; +using System.Threading.Tasks; namespace NHMCore.Configs { @@ -26,6 +28,9 @@ public bool AutoUpdateNiceHashMiner _autoUpdateNiceHashMiner = value; } OnPropertyChanged(nameof(AutoUpdateNiceHashMiner)); +#if NHMWS4 + _ = Task.Run(async () => await NHWebSocketV4.UpdateMinerStatus()); +#endif } } @@ -46,6 +51,9 @@ public bool AutoUpdateMinerPlugins _autoUpdateMinerPlugins = value; } OnPropertyChanged(nameof(AutoUpdateMinerPlugins)); +#if NHMWS4 + _ = Task.Run(async () => await NHWebSocketV4.UpdateMinerStatus()); +#endif } } } diff --git a/src/NHMCore/Mining/AlgorithmContainer.cs b/src/NHMCore/Mining/AlgorithmContainer.cs index d9089dc36..400b59f8b 100644 --- a/src/NHMCore/Mining/AlgorithmContainer.cs +++ b/src/NHMCore/Mining/AlgorithmContainer.cs @@ -5,11 +5,17 @@ using NHMCore.ApplicationState; using NHMCore.Configs; using NHMCore.Configs.ELPDataModels; +using NHMCore.Configs.Managers; using NHMCore.Mining.Plugins; -using NHMCore.Utils; +using NHMCore.Nhmws.V4; +using NHMCore.Notifications; using System; using System.Collections.Generic; using System.Linq; +using System.Reflection.Metadata; +using System.Threading.Tasks; +using Windows.Media.Protection.PlayReady; +using static NHMCore.Configs.Managers.OCManager; namespace NHMCore.Mining { @@ -29,6 +35,7 @@ public class AlgorithmContainer : NotifyChangedBase public DateTime IgnoreUntil { get; internal set; } = DateTime.UtcNow; private List _powerUsageHistory = new List(); private List _speedHistory = new List(); + private string _TAG = string.Empty; // status is always calculated public AlgorithmStatus Status @@ -66,6 +73,7 @@ public AlgorithmContainer(Algorithm algorithm, PluginContainer pluginContainer, PluginContainer = pluginContainer; Algorithm = algorithm; ComputeDevice = computeDevice; + _TAG = $"AC->{pluginContainer.Name}/{algorithm.AlgorithmName}/{computeDevice.Name}"; computeDevice.PropertyChanged += ComputeDevice_PropertyChanged; SwitchSettings.Instance.PropertyChanged += SettingsChanged; @@ -77,7 +85,11 @@ private void ComputeDevice_PropertyChanged(object sender, System.ComponentModel. { if (nameof(NHMCore.Mining.ComputeDevice.State) == e.PropertyName) { +#if NHMWS4 + var miningOrBenchmarking = ComputeDevice.State == DeviceState.Benchmarking || ComputeDevice.State == DeviceState.Mining || ComputeDevice.State == DeviceState.Testing; +#else var miningOrBenchmarking = ComputeDevice.State == DeviceState.Benchmarking || ComputeDevice.State == DeviceState.Mining; +#endif IsUserEditable = !miningOrBenchmarking; OnPropertyChanged(nameof(IsUserEditable)); } @@ -91,7 +103,7 @@ public MiningPair ToMiningPair() Algorithm = Algorithm }; } - public DeviceELPData FindInELPTree(string deviceUUID) => ELPManager.Instance.FindDeviceNode(this, deviceUUID); + public DeviceELPData FindInELPTree(string deviceUUID) => ELPManager.Instance.FindDeviceNode(this, deviceUUID); public void UpdateConfigVersionIfNeeded() { if ((_powerUsageHistory.Count >= 2 && _powerUsageHistory.Last() != _powerUsageHistory[_powerUsageHistory.Count - 2]) || @@ -163,6 +175,9 @@ public double BenchmarkSpeed Algorithm.Speeds[0] = value; UpdateConfigVersionIfNeeded(); NotifySpeedChanged(); +#if NHMWS4 + Task.Run(async () => await NHWebSocketV4.UpdateMinerStatus()); +#endif } } @@ -230,9 +245,21 @@ public virtual bool Enabled if (Algorithm != null) Algorithm.Enabled = value; OnPropertyChanged(); OnPropertyChanged(nameof(Status)); +#if NHMWS4 + Task.Run(async () => await NHWebSocketV4.UpdateMinerStatus()); +#endif + if (MinerUUID == null || MinerUUID == string.Empty) return; //initial stuff + if(value) EventManager.Instance.AddEventAlgoEnabled(ComputeDevice.B64Uuid, PluginName, new List { AlgorithmName } ); + else EventManager.Instance.AddEventAlgoDisabled(ComputeDevice.B64Uuid, PluginName, new List { AlgorithmName }); } } - + public void SetEnabled(bool enabled) //for enable without WS (bulk setting) + { + if (Algorithm != null) Algorithm.Enabled = enabled; + OnPropertyChanged(); + OnPropertyChanged(nameof(Enabled)); + OnPropertyChanged(nameof(Status)); + } /// /// Indicates whether this algorithm requires a benchmark /// @@ -302,7 +329,11 @@ public double CurrentEstimatedProfit return 1000; } - if (!_updateEstimatedProfitCalled) return -2; + if (!_updateEstimatedProfitCalled) + { + Logger.Error("AlgoContainer", "UpdateEstimatedProfit not called, returning -2"); + return -2; + } if (EstimatedProfitAllSMAPresent && EstimatedProfitAllSMAPositiveOrZero) { @@ -315,6 +346,7 @@ public double CurrentEstimatedProfit return Math.Round(newProfit, 8); } // we can't calculate + Logger.Error("AlgoContainer", "Cant calculate, returning -1"); return -1; } } @@ -393,7 +425,8 @@ public string CurPayingRatioStr /// Power consumption of this algorithm, in Watts /// private double _powerUsage = 0; - public virtual double PowerUsage { + public virtual double PowerUsage + { get { return _powerUsage; @@ -483,7 +516,7 @@ public void ClearSpeeds() this.Speeds = allZero; } - + #endregion @@ -541,5 +574,536 @@ void SettingsChanged(object sender, EventArgs e) } #endregion + + + internal bool IgnoreLocalELPInput //if ignore local ELPs for rig manager ones + { + get + { +#if NHMWS4 + if (ActiveELPProfile != null || ActiveELPTestProfile != null) return true; + return false; +#else + return false; +#endif + } + } +#if NHMWS4 + private readonly object _lock = new object(); + public enum ProfileType + { + None, + Normal, + Test, + } + public ProfileType GetTargetProfileType() + { + if (ActiveFanTestProfile != null || ActiveOCTestProfile != null || ActiveELPTestProfile != null) return ProfileType.Test; + if (ActiveFanProfile != null || ActiveOCProfile != null || ActiveELPProfile != null) return ProfileType.Normal; + return ProfileType.None; + } + public bool HasNormalProfileToSet() + { + return ActiveFanProfile != null || ActiveOCProfile != null || ActiveELPProfile != null; + } + public bool HasTestProfileToSet() + { + return ActiveFanTestProfile != null || ActiveOCTestProfile != null || ActiveELPTestProfile != null; + } + public bool HasTestProfileAndCanSet() + { + return GetTargetProfileType() == ProfileType.Test && HasTestProfileToSet(); + } + public bool HasNormalProfileAndCanSet() + { + return GetTargetProfileType() == ProfileType.Normal && HasNormalProfileToSet(); + } + private OcProfile _runningOCProfile = null; + public OcProfile RunningOcProfile + { + get + { + lock (_lock) + { + return _runningOCProfile; + } + } + set + { + lock (_lock) + { + _runningOCProfile = value; + } + } + } + private ElpProfile _runningELPProfile = null; + public ElpProfile RunningELPProfile + { + get + { + lock (_lock) + { + return _runningELPProfile; + } + } + set + { + lock (_lock) + { + _runningELPProfile = value; + } + } + } + public FanProfile _runningFanProfile = null; + public FanProfile RunningFanProfile + { + get + { + lock (_lock) + { + return _runningFanProfile; + } + } + set + { + lock (_lock) + { + _runningFanProfile = value; + } + } + } + public bool IsTesting => HasTestProfileToSet(); + #region OC + public string OCProfile + { + get + { + if (ActiveOCTestProfile != null) return ActiveOCTestProfile.Name; + if (ActiveOCProfile != null && !IsTesting) return ActiveOCProfile.Name; + return string.Empty; + } + } + public string OCProfileID + { + get + { + if (ActiveOCTestProfile != null) return ActiveOCTestProfile.Id; + if (ActiveOCProfile != null && !IsTesting) return ActiveOCProfile.Id; + return string.Empty; + } + } + + + private OcProfile _ActiveOCTestProfile = null; + public OcProfile ActiveOCTestProfile + { + get + { + lock (_lock) + { + return _ActiveOCTestProfile; + } + } + set + { + lock (_lock) + { + _ActiveOCTestProfile = value; + } + } + } + private OcProfile _ActiveOCProfile = null; + public OcProfile ActiveOCProfile + { + get + { + lock (_lock) + { + return _ActiveOCProfile; + } + } + set + { + lock (_lock) + { + _ActiveOCProfile = value; + } + } + } + public void SetTargetOcProfile(OcProfile profile, bool test) + { + if (test) + { + ActiveOCTestProfile = profile; + } + else + { + ActiveOCProfile = profile; + } + } + public Task SetOcForDevice(OcProfile bundle, bool reset = false) + { + //if (bundle != null) Logger.Warn(_TAG, $"Setting OC for {ComputeDevice.Name}: TDP={bundle.TDP},CC={bundle.CoreClock},MC={bundle.MemoryClock}"); + var ret = RigManagementReturn.Fail; + int valuesToSet = 0; + bool willSetCC = false; + bool willSetCCDelta = false; + bool willSetMC = false; + bool willSetMCDelta = false; + + if (bundle.CoreClockDelta != null) willSetCCDelta = true; + if (bundle.CoreClock != null) willSetCC = true; + if (bundle.MemoryClockDelta != null) willSetMCDelta = true; + if (bundle.MemoryClock != null) willSetMC = true; + + if (willSetCC || willSetCCDelta) valuesToSet++; + if (willSetMC || willSetMCDelta) valuesToSet++; + if (bundle.TDP != null) valuesToSet++; + if (bundle.CoreVoltage != null) valuesToSet++; + + if (valuesToSet == 0 && !reset) + { + Logger.Error(_TAG, "Have no values to set"); + return Task.FromResult(ret); + } + + int setValues = 4; + bool setTDP = false; + bool setCCabs = false; + bool setCCdelta = false; + bool setMCabs = false; + bool setMCdelta = false; + bool setCV = false; + + bool setCC; + bool setMC; + + if (reset) + { + Logger.Warn(_TAG, $"Resetting device {ComputeDevice.ID}"); + Logger.Warn(_TAG, $"[{ComputeDevice.ID}] reset TDP: {ComputeDevice.SetPowerModeManual(ComputeDevice.TDPLimits.def)}"); + Logger.Warn(_TAG, $"[{ComputeDevice.ID}] reset CC: {ComputeDevice.ResetCoreClock()}"); + Logger.Warn(_TAG, $"[{ComputeDevice.ID}] reset CCD: {ComputeDevice.ResetCoreClockDelta()}"); + Logger.Warn(_TAG, $"[{ComputeDevice.ID}] reset MC: {ComputeDevice.ResetMemoryClock()}"); + Logger.Warn(_TAG, $"[{ComputeDevice.ID}] reset MCD: {ComputeDevice.ResetMemoryClockDelta()}"); + Logger.Warn(_TAG, $"[{ComputeDevice.ID}] reset CV: {ComputeDevice.ResetCoreVoltage()}"); + } + + + if (ComputeDevice.DeviceType == DeviceType.AMD) + { + Logger.Warn(_TAG, $"Setting AMD device {ComputeDevice.ID}"); + if (bundle.TDP != null) Logger.Warn(_TAG, $"[{ComputeDevice.ID}] TDP to set: {(int)bundle.TDP}"); + if (bundle.CoreClock != null) Logger.Warn(_TAG, $"[{ComputeDevice.ID}] CoreClock to set: {(int)bundle.CoreClock}"); + if (bundle.MemoryClock != null) Logger.Warn(_TAG, $"[{ComputeDevice.ID}] MemoryClock to set: {(int)bundle.MemoryClock}"); + if (bundle.CoreVoltage != null) Logger.Warn(_TAG, $"[{ComputeDevice.ID}] CoreVoltage to set: {(int)bundle.CoreVoltage}"); + + setTDP = bundle.TDP == null ? false : ComputeDevice.SetPowerModeManual((int)bundle.TDP); + setCCabs = willSetCC ? ComputeDevice.SetCoreClock((int)bundle.CoreClock) : false; + setMCabs = willSetMC ? ComputeDevice.SetMemoryClock((int)bundle.MemoryClock) : false; + setCV = bundle.CoreVoltage == null ? false : ComputeDevice.SetCoreVoltage((int)bundle.CoreVoltage); + setCC = setCCabs; + setMC = setMCabs; + } + else + { + Logger.Warn(_TAG, $"Setting {ComputeDevice.DeviceType} device {ComputeDevice.ID}"); + if (bundle.TDP != null) Logger.Warn(_TAG, $"[{ComputeDevice.ID}] TDP to set: {(int)bundle.TDP}"); + if (bundle.CoreClock != null) Logger.Warn(_TAG, $"[{ComputeDevice.ID}] CoreClock to set: {(int)bundle.CoreClock}"); + if (bundle.CoreClockDelta != null) Logger.Warn(_TAG, $"[{ComputeDevice.ID}] CoreClockDelta to set: {(int)bundle.CoreClockDelta}"); + if (bundle.MemoryClock != null) Logger.Warn(_TAG, $"[{ComputeDevice.ID}] MemoryClock to set: {(int)bundle.MemoryClock}"); + if (bundle.MemoryClockDelta != null) Logger.Warn(_TAG, $"[{ComputeDevice.ID}] MemoryClockDelta to set: {(int)bundle.MemoryClockDelta}"); + if (bundle.CoreVoltage != null) Logger.Warn(_TAG, $"[{ComputeDevice.ID}] CoreVoltage to set: {(int)bundle.CoreVoltage}"); + + setTDP = bundle.TDP == null ? false : ComputeDevice.SetPowerModeManual((int)bundle.TDP); + setCCabs = willSetCC ? ComputeDevice.SetCoreClock((int)bundle.CoreClock) : false; + setCCdelta = willSetCCDelta ? ComputeDevice.SetCoreClockDelta((int)bundle.CoreClockDelta) : false; + setMCabs = willSetMC ? ComputeDevice.SetMemoryClock((int)bundle.MemoryClock) : false; + setMCdelta = willSetMCDelta ? ComputeDevice.SetMemoryClockDelta((int)bundle.MemoryClockDelta) : false; + setCV = bundle.CoreVoltage == null ? false : ComputeDevice.SetCoreVoltage((int)bundle.CoreVoltage); + setCC = setCCabs || setCCdelta; + setMC = setMCabs || setMCdelta; + } + + if (!setCC) setValues--; + if (!setMC) setValues--; + if (!setTDP) setValues--; + if (!setCV) setValues--; + + Logger.Warn(_TAG, $"[{ComputeDevice.BaseDevice.ID}] Setting core clock success: {setCC}"); + Logger.Warn(_TAG, $"[{ComputeDevice.BaseDevice.ID}] Setting memory clock success: {setMC}"); + Logger.Warn(_TAG, $"[{ComputeDevice.BaseDevice.ID}] Setting TDP success: {setTDP}"); + Logger.Warn(_TAG, $"[{ComputeDevice.BaseDevice.ID}] Setting voltage success: {setCV}"); + + if (setValues == valuesToSet) ret = RigManagementReturn.Success; + else if (setValues != 0 && setValues < valuesToSet) ret = RigManagementReturn.PartialSuccess; + + if (!reset && (ret == RigManagementReturn.Success || ret == RigManagementReturn.PartialSuccess)) + { + Logger.Warn(_TAG, $"Setting OC is successful"); + return Task.FromResult(ret); + } + Logger.Warn(_TAG, $"OC not in test mode anymore"); + return Task.FromResult(ret); + } + public Task ResetOcForDevice() + { + var res = SetOcForDevice(new OcProfile(), true); + return Task.FromResult(res.Result); + } + #endregion + #region ELP + public string DelayedELPString = string.Empty; + public string ELPProfile + { + get + { + if (ActiveELPTestProfile != null) return ActiveELPTestProfile.Name; + if (ActiveELPProfile != null && !IsTesting) return ActiveELPProfile.Name; + return string.Empty; + } + } + public string ELPProfileID + { + get + { + if (ActiveELPTestProfile != null) return ActiveELPTestProfile.Id; + if (ActiveELPProfile != null && !IsTesting) return ActiveELPProfile.Id; + return string.Empty; + } + } + private ElpProfile _ActiveELPTestProfile = null; + public ElpProfile ActiveELPTestProfile + { + get + { + lock (_lock) + { + return _ActiveELPTestProfile; + } + } + set + { + lock (_lock) + { + if ((value != null && _ActiveELPTestProfile == null) || + (value != null && _ActiveELPTestProfile != null)) + { + ELPTestChange = true; + } + else if (value == null && _ActiveELPTestProfile != null) + { + ELPTestChange = false; + } + _ActiveELPTestProfile = value; + } + } + } + private ElpProfile _ActiveELPProfile = null; + public ElpProfile ActiveELPProfile + { + get + { + lock (_lock) + { + return _ActiveELPProfile; + } + } + set + { + lock (_lock) + { + if ((value != null && _ActiveELPProfile == null) || + (value != null && _ActiveELPProfile != null)) + { + ELPChange = true; + } + else if (value == null && _ActiveELPProfile != null) + { + ELPChange = false; + } + _ActiveELPProfile = value; + } + } + } + private bool _newTestProfile = false; + private bool _newProfile = false; + public bool NewTestELPProfile + { + get + { + lock (_lock) + { + return _newTestProfile; + } + } + set + { + lock (_lock) + { + _newTestProfile = value; + } + } + } + public bool NewELPProfile + { + get + { + lock (_lock) + { + return _newProfile; + } + } + set + { + lock (_lock) + { + _newProfile = value; + } + } + } + private bool _ELPChange = false; + public bool ELPChange + { + get + { + lock (_lock) + { + return _ELPChange; + } + } + set + { + lock (_lock) + { + _ELPChange = value; + } + } + } + private bool _ELPTestChange = false; + public bool ELPTestChange + { + get + { + lock (_lock) + { + return _ELPTestChange; + } + } + set + { + lock (_lock) + { + _ELPTestChange = value; + } + } + } + public void ResetNewTestProfileStatus() { NewTestELPProfile = false; } + public void ResetNewProfileStatus() { NewELPProfile = false; } + public void SetTargetElpProfile(ElpProfile profile, bool test) + { + if (test) + { + ActiveELPTestProfile = profile; + NewTestELPProfile = true; + } + else + { + ActiveELPProfile = profile; + NewELPProfile = true; + } + SetELPForDevice(profile == null); + OnPropertyChanged(nameof(IgnoreLocalELPInput)); + } + public void TriggerELPReset() + { + NewELPProfile = true; + } + public RigManagementReturn SetELPForDevice(bool reset = false) + { + var ret = RigManagementReturn.Success; + if (!reset) + { + var cmd = string.Empty; + if (ActiveELPProfile != null && !IsTesting) cmd = ActiveELPProfile.Elp; + if (ActiveELPTestProfile != null) cmd = ActiveELPTestProfile.Elp; + Logger.Warn(_TAG, $"Setting ELP for {ComputeDevice.Name}: ELP={cmd}"); + ELPManager.Instance.SetAlgoCMDString(this, cmd); + Logger.Warn(_TAG, $"Setting ELP is successful"); + return ret; + } + ELPManager.Instance.IterateSubModelsAndConstructELPs(); + Logger.Warn(_TAG, $"ELP not in test mode anymore"); + return ret; + } + #endregion + #region FAN + public string FanProfile + { + get + { + if (ActiveFanTestProfile != null) return ActiveFanTestProfile.Name; + if (ActiveFanProfile != null && !IsTesting) return ActiveFanProfile.Name; + return string.Empty; + } + } + public string FanProfileID + { + get + { + if (ActiveFanTestProfile != null) return ActiveFanTestProfile.Id; + if (ActiveFanProfile != null && !IsTesting) return ActiveFanProfile.Id; + return string.Empty; + } + } + private FanProfile _ActiveFanTestProfile = null; + public FanProfile ActiveFanTestProfile + { + get + { + lock (_lock) + { + return _ActiveFanTestProfile; + } + } + set + { + lock (_lock) + { + _ActiveFanTestProfile = value; + } + } + } + private FanProfile _ActiveFanProfile = null; + public FanProfile ActiveFanProfile + { + get + { + lock (_lock) + { + return _ActiveFanProfile; + } + } + set + { + lock (_lock) + { + _ActiveFanProfile = value; + } + } + } + public void SetTargetFanProfile(FanProfile profile, bool test) + { + if (test) + { + ActiveFanTestProfile = profile; + } + else + { + ActiveFanProfile = profile; + } + } + #endregion +#endif } } diff --git a/src/NHMCore/Mining/AvailableDevices.cs b/src/NHMCore/Mining/AvailableDevices.cs index a1938591e..f131d6106 100644 --- a/src/NHMCore/Mining/AvailableDevices.cs +++ b/src/NHMCore/Mining/AvailableDevices.cs @@ -19,12 +19,14 @@ public static class AvailableDevices public static bool HasAmd => Devices.Any(d => d.DeviceType == DeviceType.AMD); public static bool HasCpu => Devices.Any(d => d.DeviceType == DeviceType.CPU); public static bool HasGpu => HasNvidia || HasAmd; - public static bool HasGpuToPause => Devices.Any(dev => dev.PauseMiningWhenGamingMode && dev.DeviceType != DeviceType.CPU); + //public static bool HasGpuToPause => Devices.Any(dev => dev.PauseMiningWhenGamingMode && dev.DeviceType != DeviceType.CPU); public static int AvailCpus => GetCountForType(DeviceType.CPU); public static int AvailNVGpus => GetCountForType(DeviceType.NVIDIA); public static int AvailAmdGpus => GetCountForType(DeviceType.AMD); - public static int AvailGpus => AvailAmdGpus + AvailNVGpus; + public static int AvailIntelGpus => GetCountForType(DeviceType.INTEL); + + public static int AvailGpus => AvailAmdGpus + AvailNVGpus + AvailIntelGpus; public static ulong AvailNvidiaGpuRam { @@ -56,6 +58,21 @@ public static ulong AvailAmdGpuRam } } + public static ulong AvailIntelGpuRam + { + get + { + var ramSum = 0ul; + var gpuRams = _devices + .Where(dev => dev.BaseDevice is IntelDevice) + .Select (dev => dev.BaseDevice) + .Cast() + .Select(gpu => gpu.GpuRam); + foreach(var ram in gpuRams) ramSum += ram; + return ramSum; + } + } + internal static void AddDevice(ComputeDevice dev) { _devices.Add(dev); diff --git a/src/NHMCore/Mining/ComputeDevice.cs b/src/NHMCore/Mining/ComputeDevice.cs index 7bc87c481..de7375ce8 100644 --- a/src/NHMCore/Mining/ComputeDevice.cs +++ b/src/NHMCore/Mining/ComputeDevice.cs @@ -1,17 +1,25 @@ -using NHM.Common; +using Newtonsoft.Json; +using NHM.Common; using NHM.Common.Device; using NHM.Common.Enums; using NHM.DeviceMonitoring; +using NHM.DeviceMonitoring.Core_clock; +using NHM.DeviceMonitoring.Core_voltage; +using NHM.DeviceMonitoring.Memory_clock; using NHM.DeviceMonitoring.TDP; using NHM.UUID; using NHMCore.ApplicationState; using NHMCore.Configs; using NHMCore.Configs.Data; using NHMCore.Nhmws; +using NHMCore.Nhmws.V4; +using NHMCore.Notifications; using System; using System.Collections.Generic; using System.ComponentModel; using System.Linq; +using System.Text.RegularExpressions; +using System.Threading.Tasks; namespace NHMCore.Mining { @@ -32,6 +40,23 @@ public class ComputeDevice : NotifyChangedBase // name count is the short name for displaying in moning groups public string NameCount { get; private set; } +#if NHMWS4 + public bool IsTesting => AlgorithmSettings.Any(a => a.IsTesting); + public bool IsMiningBenchingTesting => State == DeviceState.Mining || State == DeviceState.Testing || State == DeviceState.Benchmarking; + private PidController _pidController = new(); +#endif + private bool IsLessThan2KSeries(string name) + { + string pattern = @"\b(1[0-9]{3}|[1-9][0-9]{2})\b"; + Regex regex = new Regex(pattern); + Match match = regex.Match(name); + return match.Success; + } + public bool IsNvidiaAndSub2KSeries() + { + return DeviceType == DeviceType.NVIDIA && IsLessThan2KSeries(Name); + } + private int _memoryControlCounter = 0; private bool _enabled = true; public bool Enabled @@ -44,20 +69,14 @@ internal set StartState = false; State = value ? DeviceState.Stopped : DeviceState.Disabled; OnPropertyChanged(); + if (B64Uuid == null || B64Uuid == string.Empty || B64Uuid == "-1") return; //initial stuff + var eventType = value ? EventType.DeviceEnabled : EventType.DeviceDisabled; + if (value) EventManager.Instance.AddEventDevEnabled(Name, B64Uuid, true); + else EventManager.Instance.AddEventDevDisabled(Name, B64Uuid, true); } } - private bool _pauseMiningWhenGamingMode = false; - public bool PauseMiningWhenGamingMode - { - get => _pauseMiningWhenGamingMode; - internal set - { - if (value == _pauseMiningWhenGamingMode) return; - _pauseMiningWhenGamingMode = value; - OnPropertyChanged(); - } - } + public List SupportedDynamicProperties { get; set; } = new(); // disabled state check public bool IsDisabled => (!Enabled || State == DeviceState.Disabled); @@ -120,10 +139,12 @@ public string B64Uuid //CPU - 1 //GPU - 2 // NVIDIA //AMD - 3 - int type = DeviceType switch { + int type = DeviceType switch + { DeviceType.CPU => 1, DeviceType.NVIDIA => 2, DeviceType.AMD => 3, + DeviceType.INTEL => 4, _ => throw new Exception($"Unknown DeviceType {(int)DeviceType}"), }; var b64Web = UUID.GetB64UUID(Uuid); @@ -149,6 +170,55 @@ protected set } } } + public int ApplyNewAlgoStates(MinerAlgoState state) + { + if (State == DeviceState.Mining || State == DeviceState.Testing || State == DeviceState.Benchmarking) return -1; + foreach (var miner in state.Miners) + { + foreach (var algo in miner.Algos) + { + var targets = AlgorithmSettings.Where(a => a.AlgorithmName == algo.Id && a.PluginName == miner.Id)?.ToList(); + if (targets == null) continue; + if (!miner.Enabled) + { + targets.ForEach(t => t.SetEnabled((bool)false)); + continue; + } + targets.ForEach(t => t.SetEnabled((bool)algo.Enabled)); + } + var enabledAlgos = miner.Algos.Where(a => (bool)a.Enabled); + var disabledAlgos = miner.Algos.Where(a => (bool)!a.Enabled); + if(enabledAlgos != null && enabledAlgos.Count() > 0 && miner.Enabled) + { + EventManager.Instance.AddEventAlgoEnabled(B64Uuid, miner.Id, enabledAlgos.Select(a => a.Id).ToList(), true); + } + if(disabledAlgos != null && disabledAlgos.Count() > 0) + { + EventManager.Instance.AddEventAlgoDisabled(B64Uuid, miner.Id, disabledAlgos.Select(a => a.Id).ToList(), true); + } + else if (!miner.Enabled) + { + EventManager.Instance.AddEventAlgoDisabled(B64Uuid, miner.Id, miner.Algos.Select(a => a.Id).ToList(), true); + } + } + Task.Run(async () => NHWebSocketV4.UpdateMinerStatus()); + return 0; + } + + public int ApplyNewAlgoSpeeds(MinerAlgoSpeed speed) + { + foreach (var miner in speed.Miners) + { + foreach (var algo in miner.Combinations) + { + var targets = AlgorithmSettings.Where(a => a.AlgorithmName == algo.Id && a.PluginName == miner.Id)?.ToList(); + if (targets == null) continue; + targets.ForEach(t => t.BenchmarkSpeed = Convert.ToDouble(algo.Algos.FirstOrDefault().Speed)); + } + } + Task.Run(async () => NHWebSocketV4.UpdateMinerStatus()); + return 0; + } private List PluginAlgorithmSettings { get; set; } = new List(); @@ -167,7 +237,7 @@ public void SetDeviceMonitor(DeviceMonitor deviceMonitor) private bool CanMonitorStatus => !GlobalDeviceSettings.Instance.DisableDeviceStatusMonitoring && DeviceMonitor != null; - private bool CanSetTDP => !GlobalDeviceSettings.Instance.DisableDevicePowerModeSettings && DeviceMonitor != null; + private bool CanSetTDP => DeviceMonitor != null; public uint PowerTarget { @@ -265,15 +335,296 @@ public int MemoryControllerLoad return -1; } } + public int CoreClock + { + get + { + if (!GlobalDeviceSettings.Instance.DisableDeviceStatusMonitoring && DeviceMonitor != null && DeviceMonitor is ICoreClock get) return get.CoreClock; + return -1; + } + } + public int CoreClockDelta + { + get + { + if (!GlobalDeviceSettings.Instance.DisableDeviceStatusMonitoring && DeviceMonitor != null && DeviceMonitor is ICoreClockDelta get) return get.CoreClockDelta; + return -1; + } + } + public int PreferredCoreClock + { + get + { + if (DeviceType == DeviceType.NVIDIA) return CoreClockDelta; + if (DeviceType == DeviceType.AMD) return CoreClock; + if (DeviceType == DeviceType.INTEL) return CoreClockDelta; + return -1; + } + } + public int MemoryClock + { + get + { + if (!GlobalDeviceSettings.Instance.DisableDeviceStatusMonitoring && DeviceMonitor != null && DeviceMonitor is IMemoryClock get) return get.MemoryClock; + return -1; + } + } + + public int MemoryClockDelta + { + get + { + if (!GlobalDeviceSettings.Instance.DisableDeviceStatusMonitoring && DeviceMonitor != null && DeviceMonitor is IMemoryClockDelta get) return get.MemoryClockDelta; + return -1; + } + } + public int PreferredMemoryClock + { + get + { + if (DeviceType == DeviceType.NVIDIA) return MemoryClockDelta; + if (DeviceType == DeviceType.AMD) return MemoryClock; + if (DeviceType == DeviceType.INTEL) return MemoryClockDelta; + return -1; + } + } + + public (int min, int max, int def) TDPLimits + { + get + { + if (!GlobalDeviceSettings.Instance.DisableDeviceStatusMonitoring && DeviceMonitor != null && DeviceMonitor is ITDPLimits get) + { + var ret = get.GetTDPLimits(); + return (ret.min, ret.max, ret.def); + } + return (0, 0, 0); + } + } + + public (bool ok, int min, int max, int def) CoreClockRange + { + get + { + if (!GlobalDeviceSettings.Instance.DisableDeviceStatusMonitoring && DeviceMonitor != null && DeviceMonitor is ICoreClockRange get) + { + var ret = get.CoreClockRange; + return (ret.ok, ret.min, ret.max, ret.def); + } + return (false, -1, -1, -1); + } + } + + public (bool ok, int min, int max, int def) MemoryClockRange + { + get + { + if (!GlobalDeviceSettings.Instance.DisableDeviceStatusMonitoring && DeviceMonitor != null && DeviceMonitor is IMemoryClockRange get) + { + var ret = get.MemoryClockRange; + return (ret.ok, ret.min, ret.max, ret.def); + } + return (false, -1, -1, -1); + } + } + + public (bool ok, int min, int max, int def) MemoryClockRangeDelta + { + get + { + if (!GlobalDeviceSettings.Instance.DisableDeviceStatusMonitoring && DeviceMonitor != null && DeviceMonitor is IMemoryClockRangeDelta get) + { + var ret = get.MemoryClockRangeDelta; + return (ret.ok, ret.min, ret.max, ret.def); + } + return (false, -1, -1, -1); + } + } + + public int CoreVoltage + { + get + { + if (!GlobalDeviceSettings.Instance.DisableDeviceStatusMonitoring && DeviceMonitor != null && DeviceMonitor is ICoreVoltage get) return get.CoreVoltage; + return -1; + } + } + + public (bool ok, int min, int max, int def) CoreVoltageRange + { + get + { + if (!GlobalDeviceSettings.Instance.DisableDeviceStatusMonitoring && DeviceMonitor != null && DeviceMonitor is ICoreVoltageRange get) + { + var ret = get.CoreVoltageRange; + return (ret.ok, ret.min, ret.max, ret.def); + } + return (false, -1, -1, -1); + } + } #endregion Getters #region Setters public bool SetPowerMode(TDPSimpleType level) { + if (!MiscSettings.Instance.EnableGPUManagement) + { + Logger.Warn("ComputeDevice", "GPU Management is disabled(SetPowerMode)"); + return false; + } if (CanSetTDP && DeviceMonitor is ITDP set) return set.SetTDPSimple(level); return false; } + public bool SetPowerModeManual(int TDP) + { + if (!MiscSettings.Instance.EnableGPUManagement) + { + Logger.Warn("ComputeDevice", "GPU Management is disabled(SetPowerModeManual)"); + return false; + } + if (CanSetTDP && DeviceMonitor is ITDP set) return set.SetTDP(TDP); + return false; + } + public bool SetCoreClock(int coreClock) + { + if (!MiscSettings.Instance.EnableGPUManagement) + { + Logger.Warn("ComputeDevice", "GPU Management is disabled(SetCoreClock)"); + return false; + } + if (CanSetTDP && DeviceMonitor is ICoreClockSet set) return set.SetCoreClock(coreClock); + return false; + } + public bool SetCoreClockDelta(int coreClockDelta) + { + if (!MiscSettings.Instance.EnableGPUManagement) + { + Logger.Warn("ComputeDevice", "GPU Management is disabled(SetCoreClockDelta)"); + return false; + } + if (CanSetTDP && DeviceMonitor is ICoreClockSetDelta set) return set.SetCoreClockDelta(coreClockDelta); + return false; + } + public bool SetMemoryClock(int memoryClock) + { + if (!MiscSettings.Instance.EnableGPUManagement) + { + Logger.Warn("ComputeDevice", "GPU Management is disabled(SetMemoryClock)"); + return false; + } + if (CanSetTDP && DeviceMonitor is IMemoryClockSet set) return set.SetMemoryClock(memoryClock); + return false; + } + public bool SetMemoryClockDelta(int memoryClockDelta) + { + if (!MiscSettings.Instance.EnableGPUManagement) + { + Logger.Warn("ComputeDevice", "GPU Management is disabled(SetMemoryClockDelta)"); + return false; + } + if (CanSetTDP && DeviceMonitor is IMemoryClockSetDelta set) return set.SetMemoryClockDelta(memoryClockDelta); + return false; + } + public bool SetFanSpeedPercentage(int percent) + { + if (!MiscSettings.Instance.EnableGPUManagement) + { + Logger.Warn("ComputeDevice", "GPU Management is disabled(SetFanSpeedPercentage)"); + return false; + } + if (DeviceMonitor is ISetFanSpeedPercentage set) return set.SetFanSpeedPercentage(percent); + return false; + } + public bool ResetFanSpeed() + { + if (!MiscSettings.Instance.EnableGPUManagement) + { + Logger.Warn("ComputeDevice", "GPU Management is disabled(ResetFanSpeed)"); + return false; + } + if (DeviceMonitor is IResetFanSpeed set) return set.ResetFanSpeedPercentage(); + return false; + } + public bool SetCoreVoltage(int voltage) + { + if (!MiscSettings.Instance.EnableGPUManagement) + { + Logger.Warn("ComputeDevice", "GPU Management is disabled(SetCoreVoltage)"); + return false; + } + if (DeviceMonitor is ICoreVoltageSet set) return set.SetCoreVoltage(voltage); + return false; + } + public bool ResetCoreVoltage() + { + if (!MiscSettings.Instance.EnableGPUManagement) + { + Logger.Warn("ComputeDevice", "GPU Management is disabled(ResetCoreVoltage)"); + return false; + } + if (DeviceMonitor is ICoreVoltageSet set) return set.ResetCoreVoltage(); + return false; + } + public bool ResetCoreClock() + { + if (!MiscSettings.Instance.EnableGPUManagement) + { + Logger.Warn("ComputeDevice", "GPU Management is disabled(ResetCoreClock)"); + return false; + } + if (DeviceMonitor is ICoreClockSet set) return set.ResetCoreClock(); + return false; + } + public bool ResetMemoryClock() + { + if (!MiscSettings.Instance.EnableGPUManagement) + { + Logger.Warn("ComputeDevice", "GPU Management is disabled(ResetMemoryClock)"); + return false; + } + if (DeviceMonitor is IMemoryClockSet set) return set.ResetMemoryClock(); + return false; + } + public bool ResetCoreClockDelta() + { + if (!MiscSettings.Instance.EnableGPUManagement) + { + Logger.Warn("ComputeDevice", "GPU Management is disabled(ResetCoreClockDelta)"); + return false; + } + if (DeviceMonitor is ICoreClockSetDelta set) return set.ResetCoreClockDelta(); + return false; + } + public bool ResetMemoryClockDelta() + { + if (!MiscSettings.Instance.EnableGPUManagement) + { + Logger.Warn("ComputeDevice", "GPU Management is disabled(ResetMemoryClockDelta)"); + return false; + } + if (DeviceMonitor is IMemoryClockSetDelta set) return set.ResetMemoryClockDelta(); + return false; + } + public void ResetEverything() + { + if (!MiscSettings.Instance.EnableGPUManagement) + { + Logger.Warn("ComputeDevice", "GPU Management is disabled(ResetEverything)"); + ResetFanSpeed(); + return; + } + if (MiscSettings.Instance.AutoResetOC) + { + ResetCoreClock(); + ResetCoreClockDelta(); + ResetMemoryClock(); + ResetMemoryClockDelta(); + ResetCoreVoltage(); + SetPowerModeManual(TDPLimits.def); + } + ResetFanSpeed(); + } #endregion @@ -405,50 +756,47 @@ public void SetDeviceConfig(DeviceConfig config) //Enabled = config.Enabled; Enabled = config.Enabled; MinimumProfit = config.MinimumProfit; - PauseMiningWhenGamingMode = config.PauseMiningWhenGamingMode; - - if (!DeviceMonitorManager.DisableDevicePowerModeSettings) + //PauseMiningWhenGamingMode = config.PauseMiningWhenGamingMode; + + var tdpSimpleDefault = TDPSimpleType.HIGH; + var tdpSettings = config.TDPSettings; + if (tdpSettings != null && DeviceMonitor is ITDP tdp) { - var tdpSimpleDefault = TDPSimpleType.HIGH; - var tdpSettings = config.TDPSettings; - if (tdpSettings != null && DeviceMonitor is ITDP tdp) - { - tdp.SettingType = config.TDPSettings.SettingType; - switch (config.TDPSettings.SettingType) - { - case TDPSettingType.PERCENTAGE: - if (config.TDPSettings.Percentage.HasValue) - { - // config values are from 0.0% to 100.0% - tdp.SetTDPPercentage(config.TDPSettings.Percentage.Value / 100); - } - else - { - tdp.SetTDPSimple(tdpSimpleDefault); // fallback - } - break; - // here we decide to not allow per GPU disable state, default fallback is SIMPLE setting - case TDPSettingType.UNSUPPORTED: - case TDPSettingType.DISABLED: - case TDPSettingType.SIMPLE: - default: - tdp.SettingType = TDPSettingType.SIMPLE; - if (config.TDPSettings.Simple.HasValue) - { - tdp.SetTDPSimple(config.TDPSettings.Simple.Value); - } - else - { - tdp.SetTDPSimple(tdpSimpleDefault); // fallback - } - break; - } - } - else if (DeviceMonitor is ITDP tdpDefault) + tdp.SettingType = config.TDPSettings.SettingType; + switch (config.TDPSettings.SettingType) { - tdpDefault.SetTDPSimple(tdpSimpleDefault); // set default high + case TDPSettingType.PERCENTAGE: + if (config.TDPSettings.Percentage.HasValue) + { + // config values are from 0.0% to 100.0% + tdp.SetTDP(config.TDPSettings.Percentage.Value / 100); + } + else + { + tdp.SetTDPSimple(tdpSimpleDefault); // fallback + } + break; + // here we decide to not allow per GPU disable state, default fallback is SIMPLE setting + case TDPSettingType.UNSUPPORTED: + case TDPSettingType.DISABLED: + case TDPSettingType.SIMPLE: + default: + tdp.SettingType = TDPSettingType.SIMPLE; + if (config.TDPSettings.Simple.HasValue) + { + tdp.SetTDPSimple(config.TDPSettings.Simple.Value); + } + else + { + tdp.SetTDPSimple(tdpSimpleDefault); // fallback + } + break; } } + else if (DeviceMonitor is ITDP tdpDefault) + { + tdpDefault.SetTDPSimple(tdpSimpleDefault); // set default high + } if (config.PluginAlgorithmSettings == null) return; PluginAlgorithmSettings = config.PluginAlgorithmSettings; @@ -473,21 +821,14 @@ public DeviceConfig GetDeviceConfig() var TDPSettings = new DeviceTDPSettings { SettingType = TDPSettingType.UNSUPPORTED }; if (DeviceMonitor is ITDP tdp) { - if (DeviceMonitorManager.DisableDevicePowerModeSettings) + TDPSettings.SettingType = tdp.SettingType; + if (TDPSettings.SettingType == TDPSettingType.SIMPLE) { - TDPSettings.SettingType = TDPSettingType.DISABLED; + TDPSettings.Simple = tdp.TDPSimple; } - else + if (TDPSettings.SettingType == TDPSettingType.PERCENTAGE) { - TDPSettings.SettingType = tdp.SettingType; - if (TDPSettings.SettingType == TDPSettingType.SIMPLE) - { - TDPSettings.Simple = tdp.TDPSimple; - } - if (TDPSettings.SettingType == TDPSettingType.PERCENTAGE) - { - TDPSettings.Percentage = tdp.TDPPercentage * 100; - } + TDPSettings.Percentage = tdp.TDPPercentage * 100; } } var ret = new DeviceConfig @@ -497,7 +838,7 @@ public DeviceConfig GetDeviceConfig() Enabled = Enabled, MinimumProfit = MinimumProfit, TDPSettings = TDPSettings, - PauseMiningWhenGamingMode = PauseMiningWhenGamingMode + //PauseMiningWhenGamingMode = PauseMiningWhenGamingMode }; // init algo settings foreach (var algo in AlgorithmSettings) @@ -531,12 +872,18 @@ public DeviceConfig GetDeviceConfig() public bool AllEnabledAlgorithmsZeroPaying() { + if (MiningProfitSettings.Instance.MineRegardlessOfProfit) return false; return AlgorithmSettings .Where(a => a.Enabled) .All(a => a.CurrentEstimatedProfit <= 0d); } public bool AnyEnabledAlgorithmsNeedBenchmarking() => AlgorithmsForBenchmark().Any(); + public void PrepareForRebenchmark() + { + var algosToRebenchmark = AlgorithmSettings.Where(a => a.Enabled); + foreach(var algo in algosToRebenchmark) algo.IsReBenchmark = true; + } public IEnumerable AlgorithmsForBenchmark() { @@ -549,7 +896,7 @@ public IEnumerable AlgorithmsForBenchmark() public int TrySetMemoryTimings(string mtString) { - if(DeviceMonitor is IMemoryTimings mp) + if (DeviceMonitor is IMemoryTimings mp) { return mp.SetMemoryTimings(mtString); } @@ -558,7 +905,7 @@ public int TrySetMemoryTimings(string mtString) public int TryResetMemoryTimings() { - if(DeviceMonitor is IMemoryTimings mp) + if (DeviceMonitor is IMemoryTimings mp) { return mp.ResetMemoryTimings(); } @@ -571,5 +918,263 @@ public void PrintMemoryTimings() mp.PrintMemoryTimings(); } } +#if NHMWS4 + public string OCProfile + { + get + { + if (!MiscSettings.Instance.EnableGPUManagement) return string.Empty; + var testTarget = AlgorithmSettings.FirstOrDefault(a => a.IsCurrentlyMining); + if (testTarget != null) + { + return testTarget.OCProfile; + } + return string.Empty; + } + } + public string OCProfileID + { + get + { + if (!MiscSettings.Instance.EnableGPUManagement) return string.Empty; + var testTarget = AlgorithmSettings.FirstOrDefault(a => a.IsCurrentlyMining); + if (testTarget != null) + { + return testTarget.OCProfileID; + } + return string.Empty; + } + } + public string FanProfile + { + get + { + if (!MiscSettings.Instance.EnableGPUManagement) return string.Empty; + var testTarget = AlgorithmSettings.FirstOrDefault(a => a.IsCurrentlyMining); + if (testTarget != null) + { + return testTarget.FanProfile; + } + return string.Empty; + } + } + public string FanProfileID + { + get + { + if (!MiscSettings.Instance.EnableGPUManagement) return string.Empty; + var testTarget = AlgorithmSettings.FirstOrDefault(a => a.IsCurrentlyMining); + if (testTarget != null) + { + return testTarget.FanProfileID; + } + return string.Empty; + } + } + public string ELPProfile + { + get + { + if (!MiscSettings.Instance.EnableGPUManagement) return string.Empty; + var testTarget = AlgorithmSettings.FirstOrDefault(a => a.IsCurrentlyMining); + if (testTarget != null) + { + return testTarget.ELPProfile; + } + return string.Empty; + } + } + public string ELPProfileID + { + get + { + if (!MiscSettings.Instance.EnableGPUManagement) return string.Empty; + var testTarget = AlgorithmSettings.FirstOrDefault(a => a.IsCurrentlyMining); + if (testTarget != null) + { + return testTarget.ELPProfileID; + } + return string.Empty; + } + } + private bool HasNewTestItem(AlgorithmContainer target, string runningOC, string runningELP, string runningFAN) + { + return JsonConvert.SerializeObject(target.ActiveOCTestProfile) != runningOC || + JsonConvert.SerializeObject(target.ActiveELPTestProfile) != runningELP || + JsonConvert.SerializeObject(target.ActiveFanTestProfile) != runningFAN; + } + private bool HasNewItem(AlgorithmContainer target, string runningOC, string runningELP, string runningFAN) + { + return JsonConvert.SerializeObject(target.ActiveOCProfile) != runningOC || + JsonConvert.SerializeObject(target.ActiveELPProfile) != runningELP || + JsonConvert.SerializeObject(target.ActiveFanProfile) != runningFAN; + } + + public async Task AfterStartMining() + { + var target = AlgorithmSettings.Where(a => a.IsCurrentlyMining)?.FirstOrDefault(); + if (target == null) return; + if (!MiscSettings.Instance.EnableGPUManagement) + { + return; + } + var serializedRunningOC = JsonConvert.SerializeObject(target.RunningOcProfile); + var serializedRunningELP = JsonConvert.SerializeObject(target.RunningELPProfile); + var serializedRunningFan = JsonConvert.SerializeObject(target.RunningFanProfile); + if (target.HasTestProfileAndCanSet()) + { + if(HasNewTestItem(target, serializedRunningOC, serializedRunningELP, serializedRunningFan)) + { + ResetFanSpeed(); + await target.ResetOcForDevice(); + target.RunningOcProfile = null; + target.RunningFanProfile = null; + target.RunningELPProfile = null; + } + + if (target.ActiveOCTestProfile != null) + { + await target.SetOcForDevice(target.ActiveOCTestProfile, false); + target.RunningOcProfile = target.ActiveOCTestProfile; + State = DeviceState.Testing; + return; + } + if (target.ActiveELPTestProfile != null) + { + State = DeviceState.Testing; + target.RunningELPProfile = target.ActiveELPTestProfile; + return; + } + if (target.ActiveFanTestProfile != null) + { + State = DeviceState.Testing; + target.RunningFanProfile = target.ActiveFanTestProfile; + return; + } + } + if (target.HasNormalProfileAndCanSet() && !target.HasTestProfileAndCanSet()) + { + if (HasNewItem(target, serializedRunningOC, serializedRunningELP, serializedRunningFan)) + { + ResetFanSpeed(); + await target.ResetOcForDevice(); + target.RunningOcProfile = null; + target.RunningELPProfile = null; + target.RunningFanProfile = null; + } + if (target.ActiveOCProfile != null) + { + await target.SetOcForDevice(target.ActiveOCProfile, false); + target.RunningOcProfile = target.ActiveOCProfile; + } + else + { + target.RunningOcProfile = null; + } + if (target.ActiveFanProfile != null) + { + target.RunningFanProfile = target.ActiveFanProfile; + } + else + { + target.RunningFanProfile = null; + } + if (target.ActiveELPProfile != null) + { + target.RunningELPProfile = target.ActiveELPProfile; + } + else + { + target.RunningELPProfile = null; + } + State = DeviceState.Mining; + return; + } + if(!target.HasTestProfileAndCanSet() && !target.HasNormalProfileAndCanSet()) + { + if (HasNewItem(target, serializedRunningOC, serializedRunningELP, serializedRunningFan) || + HasNewTestItem(target, serializedRunningOC, serializedRunningELP, serializedRunningFan)) //IF HAS NEW ITEM + { + ResetFanSpeed(); + await target.ResetOcForDevice(); + target.RunningOcProfile = null; + target.RunningFanProfile = null; + target.RunningELPProfile = null; + } + State = DeviceState.Mining; + return; + } + State = DeviceState.Mining; + } + public void SetFanSpeedWithPidController() + { + if (!MiscSettings.Instance.EnableGPUManagement) return; + var testTarget = AlgorithmSettings.Where(a => a.IsCurrentlyMining)?.FirstOrDefault(); + if (testTarget == null) return; + var profile = testTarget.ActiveFanTestProfile ?? testTarget.ActiveFanProfile ?? null; + if (profile == null) return; + + switch (profile.Type) + { + case 0: + SetFanSpeedPercentage(profile.FanSpeed); + return; + case 1: + SetFanSpeed(profile); + return; + case 2: + SetFanSpeed(profile); + return; + case 3: + SetFanSpeedWithLoweringMemoryClocks(profile); + return; + default: + return; + } + } + + private void SetFanSpeed(FanProfile profile) + { + if (profile.Type == 1) + { + _pidController.SetPid(10, 0.8, 1); + _pidController.SetOutputLimit(100); + _pidController.SetReversed(true); + var speed = _pidController.GetOutput(Temp, profile.GpuTemp); + SetFanSpeedPercentage((int)speed); + } + else + { + _pidController.SetPid(10, 0.8, 1); + _pidController.SetOutputLimit(profile.MaxFanSpeed); + _pidController.SetReversed(true); + var speed = _pidController.GetOutput(Temp, Math.Min(profile.GpuTemp, profile.VramTemp)); + SetFanSpeedPercentage((int)speed); + } + } + + private void SetFanSpeedWithLoweringMemoryClocks(FanProfile profile) + { + _pidController.SetPid(10, 0.8, 1); + _pidController.SetOutputLimit(profile.MaxFanSpeed); + _pidController.SetReversed(true); + var speed = _pidController.GetOutput(Temp, Math.Min(profile.GpuTemp, profile.VramTemp)); + SetFanSpeedPercentage((int)speed); + + var deltaTemp = Math.Max(Temp, VramTemperature) - Math.Min(profile.GpuTemp, profile.VramTemp); + if (deltaTemp > 5) _memoryControlCounter++; + + if (_memoryControlCounter >= 5) + { + _pidController.SetPid(100, 0.8, 1); + _pidController.SetOutputLimits(MemoryClockRange.min, MemoryClockDelta); + _pidController.SetReversed(false); + var memory_clock = _pidController.GetOutput(Temp, Math.Min(profile.GpuTemp, profile.VramTemp)); + SetMemoryClock((int)memory_clock); + _memoryControlCounter = 0; + } + } + +#endif } } diff --git a/src/NHMCore/Mining/Grouping/BenchmarkingDevice.cs b/src/NHMCore/Mining/Grouping/BenchmarkingDevice.cs index 779e019cd..fe1358879 100644 --- a/src/NHMCore/Mining/Grouping/BenchmarkingDevice.cs +++ b/src/NHMCore/Mining/Grouping/BenchmarkingDevice.cs @@ -1,9 +1,11 @@ using NHM.Common; using NHM.Common.Enums; using NHM.MinerPlugin; +using NHM.MinerPluginToolkitV1; using NHM.MinerPluginToolkitV1.Interfaces; using NHMCore.ApplicationState; using NHMCore.Configs; +using NHMCore.Configs.Managers; using NHMCore.Mining.Benchmarking; using NHMCore.Notifications; using NHMCore.Utils; @@ -60,8 +62,7 @@ private async Task BenchmarkAlgorithm(AlgorithmContainer algo, Cancellat miner = plugin.CreateMiner(); miner.InitMiningPairs(miningPairs); - // fill service since the benchmark might be online. DemoUser.BTC must be used - miner.InitMiningLocationAndUsername("auto", DemoUser.BTC); + miner.InitMiningLocationAndUsername("auto", CredentialsSettings.Instance.BitcoinAddress); powerHelper.Start(); algo.ComputeDevice.State = DeviceState.Benchmarking; GPUProfileManager.Instance.Start(miningPairs, stop); @@ -124,10 +125,15 @@ private async Task Benchmark() { // per algo benchmark scope bool? benchmarkSuccess = null; + string currentPlugin = string.Empty; + string currentAlgo = string.Empty; _stopCurrentAlgorithmBenchmark = CancellationTokenSource.CreateLinkedTokenSource(_stopBenchmark.Token); try { var nextAlgo = benchAlgos.Dequeue(); + currentPlugin = nextAlgo.PluginName; + currentAlgo = nextAlgo.AlgorithmName; + //EventManager.Instance.AddEvent(EventType.BenchmarkStarted, @$"{nextAlgo.PluginName}\{nextAlgo.AlgorithmName}", nextAlgo.ComputeDevice.B64Uuid, false); //causes only 1 device to benchmark var benchmark = BenchmarkAlgorithm(nextAlgo, _stopCurrentAlgorithmBenchmark.Token); var firstFinished = await Task.WhenAny(new Task[] { commandTask, benchmark }); var ret = await firstFinished; @@ -170,7 +176,11 @@ private async Task Benchmark() finally { _stopCurrentAlgorithmBenchmark.Dispose(); - if (!_stopCurrentAlgorithmBenchmark.IsCancellationRequested && benchmarkSuccess.HasValue && !benchmarkSuccess.Value) showFailed = true; + if (!_stopCurrentAlgorithmBenchmark.IsCancellationRequested && benchmarkSuccess.HasValue && !benchmarkSuccess.Value) + { + showFailed = true; + AvailableNotifications.CreateFailedBenchmarksInfo(Device, currentAlgo, currentPlugin); + } } } startMining = !_stopBenchmark.IsCancellationRequested; @@ -180,7 +190,6 @@ private async Task Benchmark() var nextAlgo = benchAlgos.Dequeue(); nextAlgo.ClearBenchmarkPending(); } - if (showFailed) AvailableNotifications.CreateFailedBenchmarksInfo(Device); } catch (Exception ex) { diff --git a/src/NHMCore/Mining/Grouping/GroupingUtils.cs b/src/NHMCore/Mining/Grouping/GroupingUtils.cs index bf6310a0d..cfa1ae67f 100644 --- a/src/NHMCore/Mining/Grouping/GroupingUtils.cs +++ b/src/NHMCore/Mining/Grouping/GroupingUtils.cs @@ -1,5 +1,6 @@ using NHM.MinerPluginToolkitV1.CommandLine; using NHMCore.Configs.ELPDataModels; +using NHMCore.Configs.Managers; using NHMCore.Utils; using System.Collections.Generic; using System.Linq; @@ -25,7 +26,7 @@ private static bool CanGroupAlgorithmContainer(AlgorithmContainer a, AlgorithmCo var elpNodeA = a.FindInELPTree(a.ComputeDevice.Uuid) ?? new DeviceELPData();//state? var elpNodeB = b.FindInELPTree(b.ComputeDevice.Uuid) ?? new DeviceELPData(); - return a.PluginContainer.CanGroupAlgorithmContainer(a, b) && + return a.PluginContainer.CanGroupAlgorithmContainer(a, b) && MinerExtraParameters.CheckIfCanGroup(new List>> { elpNodeA.ConstructedELPs, elpNodeB.ConstructedELPs }); } @@ -38,23 +39,31 @@ public static Dictionary> GetGroupedAlgorithmCo var groupedAlgorithms = new Dictionary>(); bool isCurrentWithinGroup(AlgorithmContainer current, List group) => group.Any(p => p.ComputeDevice.Uuid == current.ComputeDevice.Uuid); bool isAlreadyGrouped(AlgorithmContainer current) => groupedAlgorithms.Values.Any(group => isCurrentWithinGroup(current, group)); - + bool needsToBeSeparated(AlgorithmContainer current) => (current.ELPChange || current.ELPTestChange); //todo if has something to set to? foreach (var current in profitableAlgorithmContainers) { if (isAlreadyGrouped(current)) continue; - var newGroup = new List() { current }; var restInGroup = profitableAlgorithmContainers .SkipWhile(algo => current != algo) .Where(algo => !isAlreadyGrouped(algo)) .Where(algo => CanGroupAlgorithmContainer(current, algo)); + if (needsToBeSeparated(current)) + { + var currentCMD = ELPManager.Instance.FindAppropriateCommandForAlgoContainer(new List { current }); + restInGroup = restInGroup + .Where(algo => needsToBeSeparated(algo))? + .Where(algo => ELPManager.Instance.FindAppropriateCommandForAlgoContainer(new List { algo }) == currentCMD); + } + else + { + restInGroup = restInGroup.Where(algo => !needsToBeSeparated(algo)); + } newGroup.AddRange(restInGroup); - // save newly grouped mining pairs var newGroupKey = CalcGroupedDevicesKey(newGroup, current.AlgorithmStringID); groupedAlgorithms[newGroupKey] = newGroup; } - return groupedAlgorithms; } } diff --git a/src/NHMCore/Mining/Grouping/MiningDevice.cs b/src/NHMCore/Mining/Grouping/MiningDevice.cs index 17d3b5581..743b24fec 100644 --- a/src/NHMCore/Mining/Grouping/MiningDevice.cs +++ b/src/NHMCore/Mining/Grouping/MiningDevice.cs @@ -55,6 +55,8 @@ public double GetPrevMostProfitValue public AlgorithmContainer GetMostProfitableAlgorithmContainer() { + var forcedContainer = Algorithms.Where(a => a.IsTesting)?.FirstOrDefault(); + if (forcedContainer != null) return forcedContainer; return Algorithms.FirstOrDefault(a => a.AlgorithmStringID == MostProfitableAlgorithmStringID); } @@ -87,7 +89,7 @@ public void CalculateProfits(Dictionary profits) var mostProfitable = Algorithms.Where(algo => algo.IgnoreUntil <= DateTime.UtcNow) .OrderByDescending(algo => algo.CurrentNormalizedProfit) .FirstOrDefault(); - if(mostProfitable.CurrentNormalizedProfit <= 0) // no sma yet + if(mostProfitable != null && mostProfitable.CurrentNormalizedProfit <= 0) // no sma yet { Logger.Warn("MiningDevice", "Profits array is all zeros, selecting algo with best ESTIMATED profit (will switch later if needed)."); mostProfitable = Algorithms.Where(algo => algo.IgnoreUntil <= DateTime.UtcNow) diff --git a/src/NHMCore/Mining/Miner.cs b/src/NHMCore/Mining/Miner.cs index dd9be514e..a3f40ebb3 100644 --- a/src/NHMCore/Mining/Miner.cs +++ b/src/NHMCore/Mining/Miner.cs @@ -226,7 +226,11 @@ private async Task StartAsync(CancellationToken stop, string username) var maxTimeout = _plugin.GetApiMaxTimeout(_miningPairs); MinerApiWatchdog.AddGroup(GroupKey, maxTimeout, DateTime.UtcNow); _algos.ForEach(a => a.IsCurrentlyMining = true); +#if NHMWS4 + _algos.ForEach(a => a.ComputeDevice.State = a.IsTesting ? DeviceState.Testing : DeviceState.Mining); +#else _algos.ForEach(a => a.ComputeDevice.State = DeviceState.Mining); +#endif return ret; } @@ -326,6 +330,7 @@ private async Task RunMinerWatchDogLoop(TaskCompletionSource tsc, Cancel } if (restartCount >= maxRestartCount) { + Logger.Error(MinerTag(), $"Restart count of {MinerDeviceName} - {MinerTag()} exceeded {maxRestartCount}, algorithm unstable"); var firstAlgo = _algos.FirstOrDefault(); Random randWait = new Random(); firstAlgo.IgnoreUntil = DateTime.UtcNow.AddMinutes(randWait.Next(20, 30)); diff --git a/src/NHMCore/Mining/MiningManager.cs b/src/NHMCore/Mining/MiningManager.cs index dffe97754..dd6e6742e 100644 --- a/src/NHMCore/Mining/MiningManager.cs +++ b/src/NHMCore/Mining/MiningManager.cs @@ -1,8 +1,11 @@ using NHM.Common; using NHM.Common.Enums; +using NHM.MinerPlugin; using NHMCore.ApplicationState; using NHMCore.Configs; +using NHMCore.Configs.Managers; using NHMCore.Mining.Grouping; +using NHMCore.Nhmws.V4; using NHMCore.Notifications; using NHMCore.Schedules; using NHMCore.Switching; @@ -10,6 +13,7 @@ using System; using System.Collections.Generic; using System.ComponentModel; +using System.Globalization; using System.Linq; using System.Text; using System.Threading; @@ -47,14 +51,15 @@ public static class MiningManager private static Dictionary _runningMiners = new Dictionary(); #endregion State for mining - + private abstract record Command { public TaskCompletionSource Tsc { get; init; } = new TaskCompletionSource(); } private record MainCommand : Command; - + private record TriggerSwitchCheckCommand : MainCommand; + private record IterateSwitchCommand : MainCommand; private record NormalizedProfitsUpdateCommand(Dictionary NormalizedProfits) : MainCommand; private record UsernameChangedCommand(string Username) : MainCommand; @@ -118,6 +123,13 @@ public static Task StopDevice(ComputeDevice device) _commandQueue.Enqueue(command); return command.Tsc.Task; } + public static Task TriggerSwitchCheck() + { + if (RunninLoops == null) return Task.CompletedTask; + var command = new TriggerSwitchCheckCommand(); + _commandQueue.Enqueue(command); + return command.Tsc.Task; + } private static Task NormalizedProfitsUpdate(Dictionary normalizedProfits) { @@ -228,13 +240,13 @@ static MiningManager() MiscSettings.Instance.PropertyChanged += MiscSettingsInstance_PropertyChanged; MiningProfitSettings.Instance.PropertyChanged += MiningProfitSettingsInstance_PropertyChanged; - _isPauseMiningWhenGamingEnabled = MiningSettings.Instance.PauseMiningWhenGamingMode; + //_isPauseMiningWhenGamingEnabled = MiningSettings.Instance.PauseMiningWhenGamingMode; _deviceToPauseUuid = MiningSettings.Instance.DeviceToPauseUuid; _useScheduler = MiningSettings.Instance.UseScheduler; MiningSettings.Instance.PropertyChanged += MiningSettingsInstance_PropertyChanged; } - + public static void StartLoops(CancellationToken stop, string username) { _username = username; @@ -256,7 +268,7 @@ private static void MiscSettingsInstance_PropertyChanged(object sender, Property nameof(MiscSettings.UseOptimizationProfiles) => UseOptimizationProfilesChanged(), nameof(MiscSettings.ResolveNiceHashDomainsToIPs) => DNSQChanged(), _ => Task.CompletedTask, - }; + }; } private static void MiningProfitSettingsInstance_PropertyChanged(object sender, PropertyChangedEventArgs e) @@ -268,7 +280,7 @@ private static void MiningSettingsInstance_PropertyChanged(object sender, Proper { _ = e.PropertyName switch { - nameof(MiningSettings.PauseMiningWhenGamingMode) => PauseMiningWhenGamingModeSettingsChanged(MiningSettings.Instance.PauseMiningWhenGamingMode), + //nameof(MiningSettings.PauseMiningWhenGamingMode) => PauseMiningWhenGamingModeSettingsChanged(MiningSettings.Instance.PauseMiningWhenGamingMode), nameof(MiningSettings.DeviceToPauseUuid) => SelectedGPUSettingsChanged(MiningSettings.Instance.DeviceToPauseUuid), nameof(MiningSettings.EnableSSLMining) => SSLMiningChanged(), nameof(MiningSettings.UseScheduler) => UseSchedulerSettingsChanged(MiningSettings.Instance.UseScheduler), @@ -305,7 +317,7 @@ private static async Task HandleDeferredCommands(List def .Select(g => g.Select(c => c).ToArray()) .Select(commands => (finalCommand: commands.LastOrDefault(), redundantCommands: commands.Reverse().Skip(1))) .ToArray(); - + var redundantCommands = deviceActions .SelectMany(p => p.redundantCommands) .ToArray(); @@ -354,7 +366,12 @@ private static async Task HandleDeferredCommands(List def foreach (var stopBenchmark in nonBenchmarkingCommands) await StopAndRemoveBenchmark(stopBenchmark); // set the stop and error states foreach (var stop in stopCommands) stop.Device.State = DeviceState.Stopped; // THIS TRIGERS STATE CHANGE TODO change this at the point where we initiate the actual change - foreach (var stop in startErrorCommands) stop.Device.State = DeviceState.Error; // THIS TRIGERS STATE CHANGE TODO change this at the point where we initiate the actual change + foreach (var stop in startErrorCommands) + { + Logger.Error("MiningManager", $"{stop.Device.Name} is in error state due to !t.anyAlgoToBenchmark && !t.anyAlgoToMine"); + stop.Device.State = DeviceState.Error; // THIS TRIGERS STATE CHANGE TODO change this at the point where we initiate the actual change + EventManager.Instance.AddEventDeviceError(stop.Device.Name, stop.Device.B64Uuid); + } // start and group devices for mining var devicesToMineChange = startMiningCommands @@ -391,7 +408,7 @@ private static async Task HandleDeferredCommands(List def //} await CheckGroupingAndUpdateMiners(new MainCommand()); } - foreach (var startMining in startMiningCommands) startMining.Device.State = DeviceState.Mining; // THIS TRIGERS STATE CHANGE TODO change this at the point where we initiate the actual change + foreach (var startMining in startMiningCommands) startMining.Device.State = startMining.Device.AlgorithmSettings.Any(a => a.IsTesting) ? DeviceState.Testing : DeviceState.Mining; // THIS TRIGERS STATE CHANGE TODO change this at the point where we initiate the actual change // start devices to benchmark or update existing benchmarks algorithms var devicesToBenchmark = startBenchmarkingCommands.Select(c => c.Device) @@ -589,6 +606,7 @@ private static async Task CheckGroupingAndUpdateMiners(MainCommand command) // #1 parse the command var commandType = command.GetType().Name; Logger.Debug(Tag, $"Command type {commandType}"); + if (command is NormalizedProfitsUpdateCommand normalizedProfitsUpdateCommand) { _normalizedProfits = normalizedProfitsUpdateCommand.NormalizedProfits; @@ -613,24 +631,24 @@ private static async Task CheckGroupingAndUpdateMiners(MainCommand command) else if (command is GPUToPauseChangedCommand gpuToPauseChangedCommand) { _deviceToPauseUuid = gpuToPauseChangedCommand.GpuUuid; - + // unpause device if not mining and not selected var devToUnpause = AvailableDevices.Devices.FirstOrDefault(d => d.Uuid != _deviceToPauseUuid && d.IsGaming == true); if (devToUnpause != null) devToUnpause.IsGaming = false; // set new selected gpu to true var newSelectedDev = AvailableDevices.GetDeviceWithUuid(_deviceToPauseUuid); - if(newSelectedDev != null) + if (newSelectedDev != null) { - newSelectedDev.PauseMiningWhenGamingMode = true; + //newSelectedDev.PauseMiningWhenGamingMode = true; ConfigManager.DeviceConfigFileCommit(newSelectedDev); } // set previous selected gpu to false - var oldSelectedDev = AvailableDevices.Devices.FirstOrDefault(d => d.Uuid != _deviceToPauseUuid && d.PauseMiningWhenGamingMode); + var oldSelectedDev = AvailableDevices.Devices.FirstOrDefault(d => d.Uuid != _deviceToPauseUuid); if (oldSelectedDev != null) { - oldSelectedDev.PauseMiningWhenGamingMode = false; + //oldSelectedDev.PauseMiningWhenGamingMode = false; ConfigManager.DeviceConfigFileCommit(oldSelectedDev); } } @@ -656,28 +674,47 @@ or DNSQChangedCommand foreach (var miner in _runningMiners.Values) await miner.StopTask(); // START foreach (var miner in _runningMiners.Values) await miner.StartMinerTask(_stopMiningManager, _username); +#if NHMWS4 + var miningDevs = AvailableDevices.Devices + .Where(d => d.State == DeviceState.Mining || d.State == DeviceState.Testing)? + .ToList(); + if (miningDevs.Any()) + { + foreach (var dev in miningDevs) + { + await dev.AfterStartMining(); + } + } + _ = NHWebSocketV4.UpdateMinerStatus(); //todo maybe not needeed +#endif } else if (_miningDevices.Count == 0) { await StopAllMinersTask(); ApplicationStateManager.StopMining(); } - else if (_isGameRunning && _isPauseMiningWhenGamingEnabled && _deviceToPauseUuid != null) - { - AvailableNotifications.CreateGamingStarted(); - var dev = AvailableDevices.Devices.FirstOrDefault(d => d.Uuid == _deviceToPauseUuid); - dev.IsGaming = true; -#if NHMWS4 - dev.State = DeviceState.Gaming; -#endif - bool skipProfitsThreshold = CheckIfShouldSkipProfitsThreshold(command); - await SwichMostProfitableGroupUpMethodTask(_normalizedProfits, skipProfitsThreshold); - } - else if(!_isGameRunning && _isPauseMiningWhenGamingEnabled && command is IsSteamGameRunningChangedCommand) +// else if (_isGameRunning && _isPauseMiningWhenGamingEnabled && _deviceToPauseUuid != null) +// { +// AvailableNotifications.CreateGamingStarted(); +// var dev = AvailableDevices.Devices.FirstOrDefault(d => d.Uuid == _deviceToPauseUuid); +// dev.IsGaming = true; +//#if NHMWS4 +// dev.State = DeviceState.Gaming; +//#endif +// bool skipProfitsThreshold = CheckIfShouldSkipProfitsThreshold(command); +// await SwichMostProfitableGroupUpMethodTask(_normalizedProfits, skipProfitsThreshold); +// } + //else if (!_isGameRunning && _isPauseMiningWhenGamingEnabled && command is IsSteamGameRunningChangedCommand) + //{ + // AvailableNotifications.CreateGamingFinished(); + // var dev = AvailableDevices.Devices.FirstOrDefault(d => d.Uuid == _deviceToPauseUuid); + // dev.IsGaming = false; + // bool skipProfitsThreshold = CheckIfShouldSkipProfitsThreshold(command); + // await SwichMostProfitableGroupUpMethodTask(_normalizedProfits, skipProfitsThreshold); + //} + else if (command is TriggerSwitchCheckCommand triggerSwitchCheckCommand) { - AvailableNotifications.CreateGamingFinished(); - var dev = AvailableDevices.Devices.FirstOrDefault(d => d.Uuid == _deviceToPauseUuid); - dev.IsGaming = false; + Logger.Info(Tag, "Switch triggered manually"); bool skipProfitsThreshold = CheckIfShouldSkipProfitsThreshold(command); await SwichMostProfitableGroupUpMethodTask(_normalizedProfits, skipProfitsThreshold); } @@ -686,7 +723,6 @@ or DNSQChangedCommand ApplicationStateManager.StartMining(); bool skipProfitsThreshold = CheckIfShouldSkipProfitsThreshold(command); await SwichMostProfitableGroupUpMethodTask(_normalizedProfits, skipProfitsThreshold); - } } @@ -694,7 +730,7 @@ or DNSQChangedCommand private static bool CheckIfShouldSkipProfitsThreshold(MainCommand command) { return MiningProfitSettings.Instance.MineRegardlessOfProfit || - command is MiningProfitSettingsChangedCommand || + command is MiningProfitSettingsChangedCommand || command is MinerRestartLoopNotifyCommand; } @@ -730,7 +766,7 @@ async private static void CheckIfIsOnSchedule() { _useScheduler = MiningSettings.Instance.UseScheduler; if (!_useScheduler) return; - if(!SchedulesManager.Instance.Schedules.Any()) return; + if (!SchedulesManager.Instance.Schedules.Any()) return; var shouldStart = false; var shouldStop = false; @@ -748,7 +784,11 @@ async private static void CheckIfIsOnSchedule() if (shouldStop && _runningMiners.Any()) { +#if NHMWS4 + var devicesToStop = AvailableDevices.Devices.Where(dev => dev.State == DeviceState.Mining || dev.State == DeviceState.Benchmarking || dev.State == DeviceState.Testing); +#else var devicesToStop = AvailableDevices.Devices.Where(dev => dev.State == DeviceState.Mining || dev.State == DeviceState.Benchmarking); +#endif foreach (var dev in devicesToStop) await StopDevice(dev); await StopAllMinersTask(); } @@ -897,21 +937,64 @@ private static async Task SwichMostProfitableGroupUpMethodTask(Dictionary currentRunningGroups.Contains(pair.Key)).Select(pair => pair.Key).OrderBy(uuid => uuid).ToArray(); - var toStartMinerGroupKeys = newGroupedMiningPairs.Where(pair => !currentRunningGroups.Contains(pair.Key)).Select(pair => pair.Key).OrderBy(uuid => uuid).ToArray(); - var toStopMinerGroupKeys = currentRunningGroups.Where(runningKey => !newGroupedMiningPairs.Keys.Contains(runningKey)).OrderBy(uuid => uuid).ToArray(); + var noChangeGroupMinersKeys = newGroupedMiningPairs.Where(pair => currentRunningGroups.Contains(pair.Key)).Select(pair => pair.Key).OrderBy(uuid => uuid).ToList(); + var toStartMinerGroupKeys = newGroupedMiningPairs.Where(pair => !currentRunningGroups.Contains(pair.Key)).Select(pair => pair.Key).OrderBy(uuid => uuid).ToList(); + var toStopMinerGroupKeys = currentRunningGroups.Where(runningKey => !newGroupedMiningPairs.Keys.Contains(runningKey)).OrderBy(uuid => uuid).ToList(); +#if NHMWS4 + //resetting in case of elp profile set + foreach (var noChangeKey in noChangeGroupMinersKeys) + { + var miningPairs = newGroupedMiningPairs[noChangeKey]; + if (miningPairs == null) continue; + //var miningPairsWithNewProfile = miningPairs.Where(p => (p.NewProfile == true && p.HasNormalProfileAndCanSet()) || (p.NewTestProfile == true && p.HasTestProfileAndCanSet())); + var miningPairsWithNewProfile = miningPairs.Where(p => (p.NewELPProfile == true) || (p.NewTestELPProfile == true)); + if (miningPairsWithNewProfile == null || miningPairsWithNewProfile.Count() == 0) continue; + foreach (var item in miningPairsWithNewProfile) + { + item.ResetNewProfileStatus(); + item.ResetNewTestProfileStatus(); + } + toStopMinerGroupKeys.Add(noChangeKey); + toStartMinerGroupKeys.Add(noChangeKey); + } +#endif + //todo logic here to add only those that SHOULD restart (new profile/new test profile) + // first stop currently running + List startAlgoContainers = new List(); + List stopAlgoContainers = new List(); foreach (var stopKey in toStopMinerGroupKeys) { - var stopGroup = _runningMiners[stopKey]; + var miningPairs = AvailableDevices.Devices + .SelectMany(d => d.AlgorithmSettings)? + .Where(a => a.IsCurrentlyMining)? + .Where(a => stopKey.Contains(a.ComputeDevice.Uuid))? + .ToList(); + if (miningPairs != null) + { + foreach (var pair in miningPairs) + { + stopAlgoContainers.Add(pair); + } + } + var stopGroup = _runningMiners[stopKey]; _runningMiners.Remove(stopKey); await stopGroup.StopTask(); } // start new foreach (var startKey in toStartMinerGroupKeys) { + //todo here access this device to check what is set now and what will be set? var miningPairs = newGroupedMiningPairs[startKey]; + if (miningPairs != null) + { + foreach (var pair in miningPairs) + { + startAlgoContainers.Add(pair); + } + } var cmd = ELPManager.Instance.FindAppropriateCommandForAlgoContainer(miningPairs); var toStart = Miner.CreateMinerForMining(miningPairs, startKey, cmd); if (toStart == null) @@ -922,44 +1005,50 @@ private static async Task SwichMostProfitableGroupUpMethodTask(Dictionary stopAlgoContainers.Any(stopItem => stopItem.ComputeDevice.B64Uuid == startItem.ComputeDevice.B64Uuid)) + .ToList(); + + foreach (var item in commonItems) + { + var started = startAlgoContainers.FirstOrDefault(i => i.ComputeDevice.B64Uuid == item.ComputeDevice.B64Uuid); + var stopped = stopAlgoContainers.FirstOrDefault(i => i.ComputeDevice.B64Uuid == item.ComputeDevice.B64Uuid); + if(started != null && stopped != null) + { + EventManager.Instance.AddEventSwitch(item.ComputeDevice.Name, item.ComputeDevice.B64Uuid, stopped.AlgorithmName, started.AlgorithmName); + Logger.Info(Tag, $"Switch event occurred"); + } + } + } + catch (Exception ex) + { + Logger.Error(Tag, $"Error calculating duplicates for switch"); + } + + var miningDevs = AvailableDevices.Devices + .Where(d => d.State == DeviceState.Mining || d.State == DeviceState.Testing)? + .ToList(); + if (miningDevs.Any())//todo if miningdev uuid is contained in both start and stop then dont do? + { + foreach (var dev in miningDevs) + { + await dev.AfterStartMining(); + } + } + _ = NHWebSocketV4.UpdateMinerStatus(); //todo maybe not needeed +#endif // log scope { - var stopLog = toStopMinerGroupKeys.Length > 0 ? string.Join(",", toStopMinerGroupKeys) : "EMTPY"; + var stopLog = toStopMinerGroupKeys.Count > 0 ? string.Join(",", toStopMinerGroupKeys) : "EMTPY"; Logger.Info(Tag, $"Stop Old Mining: ({stopLog})"); - var startLog = toStartMinerGroupKeys.Length > 0 ? string.Join(",", toStartMinerGroupKeys) : "EMTPY"; + var startLog = toStartMinerGroupKeys.Count > 0 ? string.Join(",", toStartMinerGroupKeys) : "EMTPY"; Logger.Info(Tag, $"Start New Mining : ({startLog})"); - var sameLog = noChangeGroupMinersKeys.Length > 0 ? string.Join(",", noChangeGroupMinersKeys) : "EMTPY"; + var sameLog = noChangeGroupMinersKeys.Count > 0 ? string.Join(",", noChangeGroupMinersKeys) : "EMTPY"; Logger.Info(Tag, $"No change : ({sameLog})"); } } - - // TODO check the stats calculation - //public static async Task MinerStatsCheck() - //{ - // await _semaphore.WaitAsync(); - // try - // { - // foreach (var m in _runningMiners.Values) - // { - // // skip if not running or if await already in progress - // if (!m.IsRunning || m.IsUpdatingApi) continue; - // var ad = m.GetSummaryAsync(); - // } - // // Update GUI - // //ApplicationStateManager.RefreshRates(); // just update the model - // // now we shoud have new global/total rate display it - // var kwhPriceInBtc = BalanceAndExchangeRates.Instance.GetKwhPriceInBtc(); - // var profitInBTC = MiningDataStats.GetProfit(kwhPriceInBtc); - // ApplicationStateManager.DisplayTotalRate(profitInBTC); - // } - // catch (Exception e) - // { - // Logger.Error(Tag, $"Error occured while getting mining stats: {e.Message}"); - // } - // finally - // { - // _semaphore.Release(); - // } - //} } } diff --git a/src/NHMCore/Mining/Plugins/MinerPluginsManager.cs b/src/NHMCore/Mining/Plugins/MinerPluginsManager.cs index c732d6967..7a7c14a3c 100644 --- a/src/NHMCore/Mining/Plugins/MinerPluginsManager.cs +++ b/src/NHMCore/Mining/Plugins/MinerPluginsManager.cs @@ -3,7 +3,6 @@ using FakePlugin; using LolMiner; using NanoMiner; -using NBMiner; using Newtonsoft.Json; using NHM.Common; using NHM.Common.Configs; @@ -25,7 +24,6 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; -using XMRig; namespace NHMCore.Mining.Plugins { @@ -49,24 +47,16 @@ static MinerPluginsManager() #endif // real miners -#if INTEGRATE_NBMiner_PLUGIN - new NBMinerPlugin(), -#endif #if INTEGRATE_NanoMiner_PLUGIN new NanoMinerPlugin(), #endif #if INTEGRATE_LolMiner_PLUGIN new LolMinerPlugin(), #endif -#if INTEGRATE_XMRig_PLUGIN - new XMRigPlugin(), -#endif #if INTEGRATE_ALL_PLUGINS - new NBMinerPlugin(), new NanoMinerPlugin(), new LolMinerPlugin(), - new XMRigPlugin(), #endif }; @@ -599,6 +589,9 @@ public static async Task RemovePlugin(string pluginUUID, bool crossReferenceInst finally { PluginInstaller.RemovedPluginStatus(pluginUUID, true); +#if NHMWS4 + ApplicationStateManager.ReSendLoginMessage(); +#endif await Task.CompletedTask; } } @@ -697,18 +690,50 @@ private static (string uuid, PluginPackageInfo packageInfo) CreateLocalPackageIn return (uuid,localPluginInfo); } + private static async Task?> FetchPluginsOnline(int version) + { + using var client = new NoKeepAliveHttpClient(); + string s = await client.GetStringAsync($"{Links.PluginsJsonApiUrl}?v={version}"); + PluginsListCacheManager.WritePluginCache(version, s); + return JsonConvert.DeserializeObject>(s, new JsonSerializerSettings + { + NullValueHandling = NullValueHandling.Ignore, + MissingMemberHandling = MissingMemberHandling.Ignore, + Culture = CultureInfo.InvariantCulture + }); + } + private static async Task GetOnlineMinerPlugins() { async Task> getPlugins(int version) { - using var client = new NoKeepAliveHttpClient(); - string s = await client.GetStringAsync($"{Links.PluginsJsonApiUrl}?v={version}"); - return JsonConvert.DeserializeObject>(s, new JsonSerializerSettings + var shouldUpdate = await PluginsListCacheManager.CheckIfShouldUpdateAndUpdateLatestDate(Links.PluginsJsonApiUrl, version); + Logger.Info("MinerPluginsManager", $"Should update plugins ({version}) {shouldUpdate}"); + if (shouldUpdate) { - NullValueHandling = NullValueHandling.Ignore, - MissingMemberHandling = MissingMemberHandling.Ignore, - Culture = CultureInfo.InvariantCulture - }); + return await FetchPluginsOnline(version); + } + var readPluginList = PluginsListCacheManager.ReadPluginCache(version); + if(readPluginList == string.Empty) + { + Logger.Warn("MinerPluginsManager", $"ReadPluginList was empty"); + return await FetchPluginsOnline(version); + } + try + { + var deserialized = JsonConvert.DeserializeObject>(readPluginList, new JsonSerializerSettings + { + NullValueHandling = NullValueHandling.Ignore, + MissingMemberHandling = MissingMemberHandling.Ignore, + Culture = CultureInfo.InvariantCulture + }); + return deserialized; + } + catch (Exception ex) + { + Logger.Error("MinerPluginsManager", $"Error occured while deserializing cached plugins: {ex.Message}"); + return await FetchPluginsOnline(version); + } } try { @@ -864,6 +889,9 @@ public static async Task DownloadAndInstall(string pluginUUID, IProgress x64 ..\..\Debug\app\ - TRACE;DEBUG;INTEGRATE_Joker_PLUGIN + TRACE;DEBUG;INTEGRATE_Joker_PLUGIN;NHMWS4 x64 ..\..\Release\app\ - TRACE;INTEGRATE_Joker_PLUGIN + TRACE;INTEGRATE_Joker_PLUGIN;NHMWS4 true 1701;1702;CA1416 - INTEGRATE_NBMiner_PLUGIN;INTEGRATE_NanoMiner_PLUGIN;INTEGRATE_LolMiner_PLUGIN;INTEGRATE_XMRig_PLUGIN;$(DefineConstants) + INTEGRATE_NanoMiner_PLUGIN;INTEGRATE_LolMiner_PLUGIN;$(DefineConstants) @@ -54,8 +54,6 @@ - - @@ -73,6 +71,6 @@ 1701;1702;CA1416 - + \ No newline at end of file diff --git a/src/NHMCore/Nhmws/ActionMutableMap.cs b/src/NHMCore/Nhmws/ActionMutableMap.cs new file mode 100644 index 000000000..8d1fdf5a5 --- /dev/null +++ b/src/NHMCore/Nhmws/ActionMutableMap.cs @@ -0,0 +1,69 @@ +using NHMCore.Nhmws.V4; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace NHMCore.Nhmws +{ + public static class ActionMutableMap + { + private static List _actionList = new(); + private static List _mutableList = new(); + private static readonly object _lock = new object(); + + public static List ActionList + { + get + { + lock(_lock ) + { + return _actionList; + } + } + set + { + lock(_lock ) + { + _actionList = value; + } + } + } + public static List MutableList + { + get + { + lock(_lock ) + { + return _mutableList; + } + } + set + { + lock(_lock ) + { + _mutableList = value; + } + } + } + + public static NhmwsAction FindActionOrNull(int actionID) + { + var actionRecord = ActionList.Where(a => a.ActionID == actionID).FirstOrDefault(); + if (actionRecord != null) return actionRecord; + return null; + } + public static OptionalMutableProperty FindMutableOrNull(int propID) + { + var mutableRecord = MutableList.Where(a => a.PropertyID == propID).FirstOrDefault(); + if (mutableRecord != null) return mutableRecord; + return null; + } + public static void ResetArrays() + { + ActionList.Clear(); + MutableList.Clear(); + } + } +} diff --git a/src/NHMCore/Nhmws/ErrorCode.cs b/src/NHMCore/Nhmws/ErrorCode.cs index 5e8ad5023..e0f97ebc6 100644 --- a/src/NHMCore/Nhmws/ErrorCode.cs +++ b/src/NHMCore/Nhmws/ErrorCode.cs @@ -1,7 +1,7 @@  namespace NHMCore.Nhmws { - enum ErrorCode : int + public enum ErrorCode : int { NoError = 0, DisabledDevice = -7, @@ -12,5 +12,16 @@ enum ErrorCode : int NonExistentDevice = -2, RedundantRpc = -1, InternalNhmError = 1, + + ActionNotFound = -100, + ErrNoDeviceRunning = -101, + TargetDeviceNotFound = -102, + TestPartialFail = -103, + TestTotalFail = -104, + TargetContainerNotFound = -105, + ErrNotAdmin = -106, + ErrNoAlgoDataFound = -107, + ErrPowerModeDisabled = -108, + ErrFailedSystemDump = -109 } } diff --git a/src/NHMCore/Nhmws/Messages.cs b/src/NHMCore/Nhmws/Messages.cs index 5cd300252..ef8637452 100644 --- a/src/NHMCore/Nhmws/Messages.cs +++ b/src/NHMCore/Nhmws/Messages.cs @@ -1,5 +1,6 @@ using Newtonsoft.Json; using Newtonsoft.Json.Linq; +using NHMCore.Nhmws.V4; using System.Collections.Generic; namespace NHMCore.Nhmws @@ -184,6 +185,39 @@ internal class MinerReset : IReceiveRpcMessage public string Level { get; set; } } + internal class MinerCallAction : IReceiveRpcMessage + { + [JsonProperty("method")] + public string Method => "miner.call.action"; + [JsonProperty("id")] + public int Id { get; set; } + [JsonProperty("device_id")] + public string DeviceId { get; set; } + [JsonProperty("action_id")] + public int ActionId { get; set; } + [JsonProperty("parameters")] + public List Parameters { get; set; } + } + + internal class MinerSetMutable : IReceiveRpcMessage + { + [JsonProperty("method")] + public string Method => "miner.set.mutable"; + [JsonProperty("id")] + public int Id { get; set; } + [JsonProperty("properties")] + public List Properties { get; set; } + [JsonProperty("devices")] + public List Devices { get; set; } + } + internal class SetMutableDevice + { + [JsonProperty("id")] + public string Id { get; set; } + [JsonProperty("properties")] + public List Properties { get; set; } + } + // RPC response internal class ExecutedCall : ISendMessage { diff --git a/src/NHMCore/Nhmws/V3/NHWebSocketV3.cs b/src/NHMCore/Nhmws/V3/NHWebSocketV3.cs index e7fcdd656..7bcdaf5f5 100644 --- a/src/NHMCore/Nhmws/V3/NHWebSocketV3.cs +++ b/src/NHMCore/Nhmws/V3/NHWebSocketV3.cs @@ -667,8 +667,6 @@ private static Task StopMining(string devs) private static Task SetPowerMode(string device, TDPSimpleType level) { - if (GlobalDeviceSettings.Instance.DisableDevicePowerModeSettings) throw new RpcException("Not able to set Power Mode: Device Power Mode Settings Disabled", ErrorCode.UnableToHandleRpc); - var devs = device == "*" ? AvailableDevices.Devices : AvailableDevices.Devices.Where(d => d.B64Uuid == device); diff --git a/src/NHMCore/Nhmws/V4/MessageParserV4.cs b/src/NHMCore/Nhmws/V4/MessageParserV4.cs index 898df8c68..e1ed2a304 100644 --- a/src/NHMCore/Nhmws/V4/MessageParserV4.cs +++ b/src/NHMCore/Nhmws/V4/MessageParserV4.cs @@ -1,20 +1,35 @@ -using Newtonsoft.Json; +using HidSharp; +using Newtonsoft.Json; using Newtonsoft.Json.Linq; +using NHM.Common; using NHM.Common.Device; using NHM.Common.Enums; using NHM.DeviceMonitoring; +using NHM.DeviceMonitoring.Core_clock; +using NHM.DeviceMonitoring.Core_voltage; +using NHM.DeviceMonitoring.Memory_clock; using NHM.DeviceMonitoring.TDP; +using NHMCore.Configs; +using NHMCore.Configs.Data; +using NHMCore.Configs.Managers; using NHMCore.Mining; using NHMCore.Mining.MiningStats; +using NHMCore.Notifications; +using NHMCore.Schedules; +using NHMCore.Utils; using System; using System.Collections.Generic; +using System.IO; using System.Linq; using System.Threading.Tasks; +using System.Windows.Controls; namespace NHMCore.Nhmws.V4 { static class MessageParserV4 { + private static readonly string _TAG = "MessageParserV4"; + private static Dictionary> IgnoredValues = new(); internal static IMethod ParseMessage(string jsonData) { var method = MessageParser.ParseMessageData(jsonData); @@ -37,10 +52,25 @@ internal static IMethod ParseMessage(string jsonData) "mining.stop" => JsonConvert.DeserializeObject(jsonData), "mining.set.power_mode" => JsonConvert.DeserializeObject(jsonData), "miner.reset" => JsonConvert.DeserializeObject(jsonData), + "miner.call.action" => JsonConvert.DeserializeObject(jsonData), + "miner.set.mutable" => JsonConvert.DeserializeObject(jsonData), // non supported _ => throw new Exception($"Unable to deserialize '{jsonData}' got method '{method}'."), }; } + internal static int NHMDeviceTypeToNHMWSDeviceType(DeviceType dt) + { + //rig manager enum + //const deviceClasses = ['UNKNOWN','CPU','NVIDIA','AMD','ASIC',5,6,7,8,9,'ASIC'] + return dt switch + { + DeviceType.CPU => 1, + DeviceType.NVIDIA => 2, + DeviceType.AMD => 3, + DeviceType.INTEL => 4, + _ => 0 + }; + } internal static IOrderedEnumerable SortedDevices(this IEnumerable devices) { @@ -52,98 +82,204 @@ private static string GetDevicePlugin(string UUID) { var data = MiningDataStats.GetDevicesMiningStats(); var devData = data.FirstOrDefault(dev => dev.DeviceUUID == UUID); - if (devData == null) return ""; - + if (devData == null) + { + var fallback = AvailableDevices.Devices + .Where(d => d.Uuid == UUID)? + .Where(d => d.State == DeviceState.Mining + || d.State == DeviceState.Benchmarking + || d.State == DeviceState.Testing)? + .SelectMany(d => d.AlgorithmSettings)? + .Where(a => a.IsCurrentlyMining)? + .FirstOrDefault(); + return fallback == null ? string.Empty : fallback.PluginName; + } return devData.MinerName; } - private static (List<(string name, string unit)> properties, JArray values) GetDeviceOptionalDynamic(ComputeDevice d) + private static (List<(string name, string? unit)> properties, JArray values) GetDeviceOptionalDynamic(ComputeDevice d, bool isLogin = false) { + if(!IgnoredValues.ContainsKey(d.B64Uuid)) IgnoredValues.Add(d.B64Uuid, new List { }); string getValue(T o) => (typeof(T).Name, o) switch { (nameof(ILoad), ILoad g) => $"{(int)g.Load}", - (nameof(IMemControllerLoad), IMemControllerLoad g) => $"{g.MemoryControllerLoad}", + //(nameof(IMemControllerLoad), IMemControllerLoad g) => $"{g.MemoryControllerLoad}", (nameof(ITemp), ITemp g) => $"{g.Temp}", (nameof(IGetFanSpeedPercentage), IGetFanSpeedPercentage g) => $"{g.GetFanSpeedPercentage().percentage}", + (nameof(IFanSpeedRPM), IFanSpeedRPM g) => $"{g.FanSpeedRPM}", (nameof(IPowerUsage), IPowerUsage g) => $"{g.PowerUsage}", (nameof(IVramTemp), IVramTemp g) => $"{g.VramTemp}", (nameof(IHotspotTemp), IHotspotTemp g) => $"{g.HotspotTemp}", + (nameof(ICoreClock), ICoreClock g) => $"{g.CoreClock}", + //(nameof(ICoreClockDelta), ICoreClockDelta g) => $"{g.CoreClockDelta}", + (nameof(IMemoryClock), IMemoryClock g) => $"{g.MemoryClock}", + //(nameof(IMemoryClockDelta), IMemoryClockDelta g) => $"{g.MemoryClockDelta}", + (nameof(ITDP), ITDP g) => $"{g.TDPPercentage * 100}", + (nameof(ITDPWatts), ITDPWatts g) => $"{g.TDPWatts}", + (nameof(ICoreVoltage), ICoreVoltage g) => $"{g.CoreVoltage}", (_, _) => null, }; string getValueForName(string name) => name switch { "Miner" => $"{GetDevicePlugin(d.Uuid)}", + "OC profile" => $"{d.OCProfile}", + "OC profile ID" => $"{d.OCProfileID}", + "Fan profile" => $"{d.FanProfile}", + "Fan profile ID" => $"{d.FanProfileID}", + "ELP profile" => $"{d.ELPProfile}", + "ELP profile ID" => $"{d.ELPProfileID}", _ => null, }; - (string name, string unit, string value)? pairOrNull(string name, string unit) + (DeviceDynamicProperties type, string name, string unit, string value)? pairOrNull(DeviceDynamicProperties type, string name, string unit) { - if (d.DeviceMonitor is T sensor) return (name, unit, getValue(sensor)); - if (typeof(T) == typeof(string)) return (name, unit, getValueForName(name)); + if (d.DeviceMonitor is T sensor) return (type, name, unit, getValue(sensor)); + if (typeof(T) == typeof(string)) return (type, name, unit, getValueForName(name)); return null; } // here sort manually by type - var dynamicPropertiesWithValues = new List<(string name, string unit, string value)?> + var dynamicPropertiesWithValues = new List<(DeviceDynamicProperties type, string name, string unit, string value)?> { - pairOrNull("Temp.","C"), - pairOrNull("VRAM T.","C"), - pairOrNull("Load","%"), - pairOrNull("MemCtrl Load","%"), - pairOrNull("Fan","%"), - pairOrNull("Power","W"), - pairOrNull("Miner", ""), + pairOrNull(DeviceDynamicProperties.Temperature ,"Temperature","°C"), + pairOrNull(DeviceDynamicProperties.VramTemp,"Memory Temperature","°C"), + pairOrNull(DeviceDynamicProperties.Load,"Load","%"), + //pairOrNull(DeviceDynamicProperties.MemoryControllerLoad, "MemCtrl Load","%"), + pairOrNull(DeviceDynamicProperties.FanSpeedPercentage, "Fan speed","%"), + pairOrNull(DeviceDynamicProperties.FanSpeedRPM, "Fan speed","RPM"), + pairOrNull(DeviceDynamicProperties.PowerUsage, "Power usage","W"), + pairOrNull(DeviceDynamicProperties.CoreClock, "Core clock", "MHz"), + //pairOrNull(DeviceDynamicProperties.CoreClockDelta, "Core clock delta", "MHz"), + pairOrNull(DeviceDynamicProperties.MemClock, "Memory clock", "MHz"), + //pairOrNull(DeviceDynamicProperties.MemClockDelta, "Memory clock", "MHz"), + pairOrNull(DeviceDynamicProperties.CoreVoltage, "Core voltage", "mV"), + pairOrNull(DeviceDynamicProperties.TDP, "Power Limit", "%"), + pairOrNull(DeviceDynamicProperties.TDPWatts, "Power Limit", "W"), + pairOrNull(DeviceDynamicProperties.NONE, "Miner", null), + pairOrNull(DeviceDynamicProperties.NONE, "OC profile", null), + pairOrNull(DeviceDynamicProperties.NONE, "OC profile ID", null), + pairOrNull(DeviceDynamicProperties.NONE, "Fan profile", null), + pairOrNull(DeviceDynamicProperties.NONE, "Fan profile ID", null), + pairOrNull(DeviceDynamicProperties.NONE, "ELP profile", null), + pairOrNull(DeviceDynamicProperties.NONE, "ELP profile ID", null), }; - var deviceOptionalDynamic = dynamicPropertiesWithValues .Where(p => p.HasValue) .Where(p => p.Value.value != null) .Select(p => p.Value) - .ToArray(); + .ToList(); + + if (isLogin) + { + foreach (var od in deviceOptionalDynamic) + { + if ((od.type == DeviceDynamicProperties.Temperature || + od.type == DeviceDynamicProperties.HotspotTemp || + od.type == DeviceDynamicProperties.VramTemp || + od.type == DeviceDynamicProperties.PowerUsage || + od.type == DeviceDynamicProperties.TDP || + od.type == DeviceDynamicProperties.TDPWatts || + od.type == DeviceDynamicProperties.CoreVoltage) && + Int32.TryParse(od.value, out var lessOrEqual) && lessOrEqual <= 0) + { + if (IgnoredValues.TryGetValue(d.B64Uuid, out var list) && + !list.Contains(od.type)) + { + list.Add(od.type); + } + } + if ((od.type == DeviceDynamicProperties.Load || + od.type == DeviceDynamicProperties.FanSpeedRPM || + od.type == DeviceDynamicProperties.FanSpeedPercentage || + od.type == DeviceDynamicProperties.CoreClock || + od.type == DeviceDynamicProperties.MemClock) && + Int32.TryParse(od.value, out var less) && less < 0) + { + if (IgnoredValues.TryGetValue(d.B64Uuid, out var list) && + !list.Contains(od.type)) + { + list.Add(od.type); + } + } + } + } - var optionalDynamicProperties = deviceOptionalDynamic.Select(p => (p.name, p.unit)).ToList(); + bool shouldRemoveDynamicVal(string b64uuid, (DeviceDynamicProperties type, string name, string unit, string value) dynamicVal) + { + //if (dynamicVal.unit == String.Empty) return false; + if (dynamicVal.type == DeviceDynamicProperties.NONE) return false; + if(IgnoredValues.TryGetValue(d.B64Uuid, out var list) && list.Contains(dynamicVal.type)) + { + return true; + } + return false; + }; + deviceOptionalDynamic.RemoveAll(dynamVal => shouldRemoveDynamicVal(d.B64Uuid, dynamVal)); + //deviceOptionalDynamic.ForEach(dynamVal => d.SupportedDynamicProperties.Add(dynamVal.type)); + //if (isLogin) deviceOptionalDynamic.ForEach(dynamVal => d.SupportedDynamicProperties.Add(dynamVal.type)); + //foreach (DeviceDynamicProperties i in Enum.GetValues(typeof(DeviceDynamicProperties))) + //{ + // if (!d.SupportedDynamicProperties.Contains(i)) deviceOptionalDynamic.RemoveAll(prop => prop.type == i); + //} + List<(string name, string? unit)> optionalDynamicProperties = deviceOptionalDynamic.Select(p => (p.name, p.unit)).ToList(); var values_odv = new JArray(deviceOptionalDynamic.Select(p => p.value)); return (optionalDynamicProperties, values_odv); } // we cache device properties so we persevere property IDs private static readonly Dictionary> _cachedDevicesOptionalMutable = new Dictionary>(); - private static (List properties, JArray values) GetDeviceOptionalMutable(ComputeDevice d) + private static (List properties, JArray values) GetDeviceOptionalMutable(ComputeDevice d, bool isLogin) { OptionalMutableProperty valueOrNull(OptionalMutableProperty v) => d.DeviceMonitor is T ? v : null; List getOptionalMutableProperties(ComputeDevice d) { + var optionalProperties = new List(); // TODO sort by type - var optionalProperties = new List + optionalProperties.Add(new OptionalMutablePropertyString + { + PropertyID = OptionalMutableProperty.NextPropertyId(), + DisplayGroup = 0, + DisplayName = "Miners settings", + DefaultValue = "", + Range = (8092, ""), + ExecuteTask = async (object p) => { - valueOrNull(new OptionalMutablePropertyEnum - { - PropertyID = OptionalMutableProperty.NextPropertyId(), // TODO this will eat up the ID - DisplayName = "TDP Simple", - DefaultValue = "Medium", - Range = new List{ "Low", "Medium", "High" }, - // TODO action/setter to execute - ExecuteTask = async (object p) => - { - // #1 validate JSON input - if (p is string pstr && pstr is not null) return Task.FromResult(null); - // TODO do something - return Task.FromResult(null); - }, - GetValue = () => - { - var ret = d.TDPSimple switch - { - TDPSimpleType.LOW => "Low", - TDPSimpleType.MEDIUM => "Medium", - TDPSimpleType.HIGH => "High", - _ => "ERROR", - }; - return ret; - } - }), - }; + if (p is not string prop) return -1; + var newState = JsonConvert.DeserializeObject(prop); + return d.ApplyNewAlgoStates(newState); + }, + GetValue = () => + { + string ret = null; + ret = string.Empty; + ret += GetMinersForDeviceDynamic(d); + return ret; + }, + ComputeDev = d + }); + optionalProperties.Add(new OptionalMutablePropertyString + { + PropertyID = OptionalMutableProperty.NextPropertyId(), + DisplayGroup = 0, + DisplayName = "Benchmark settings", + DefaultValue = "", + Range = (8092, ""), + ExecuteTask = async (object p) => + { + if (p is not string prop) return -1; + var newSpeed = JsonConvert.DeserializeObject(prop); + return d.ApplyNewAlgoSpeeds(newSpeed); + }, + GetValue = () => + { + var ret = string.Empty; + ret += GetMinersSpeedsForDeviceDynamic(d); + return ret; + }, + ComputeDev = d + }); + if (isLogin) optionalProperties.ForEach(i => ActionMutableMap.MutableList.Add(i)); return optionalProperties .Where(p => p != null) .ToList(); @@ -156,106 +292,302 @@ List getOptionalMutablePropertiesCached(ComputeDevice d } var props = getOptionalMutablePropertiesCached(d); - var values_omv = new JArray(props.Select(p => p.GetValue())); - + var selectedValues = props + .Where(p => p.GetValue() != null)? + .Select(p => p.GetValue()); + JArray values_omv = null; + if (selectedValues.Any()) + { + values_omv = new JArray(selectedValues); + } return (props, values_omv); } - private static LoginMessage _loginMessage = null; - public static LoginMessage CreateLoginMessage(string btc, string worker, string rigID, IOrderedEnumerable devices) - { - var sorted = SortedDevices(devices); - if (_loginMessage != null) return _loginMessage; - List createDefaultActions() => - new List - { - new NhnwsAction - { - ActionID = NhnwsAction.NextActionId(), - DisplayName = "Mining start", - DisplayGroup = 1, - }, - new NhnwsAction - { - ActionID = NhnwsAction.NextActionId(), - DisplayName = "Mining stop", - DisplayGroup = 1, - }, - new NhnwsAction - { - ActionID = NhnwsAction.NextActionId(), - DisplayName = "Mining enable", - DisplayGroup = 1, - }, - new NhnwsAction - { - ActionID = NhnwsAction.NextActionId(), - DisplayName = "Mining disable", - DisplayGroup = 1, - }, - }; - Device mapComputeDevice(ComputeDevice d) + public static List> DeviceOptionalDynamicToList(List<(string name, string? unit)> properties) + { + List> result = new List>(); + foreach (var property in properties) { - List getStaticPropertiesOptionalValues(ComputeDevice d) + if (property.unit == null) { - return d.BaseDevice switch - { - IGpuDevice gpu => new List - { - new JArray("bus_id", $"{gpu.PCIeBusID}"), - new JArray("vram", $"{gpu.GpuRam}"), - }, - _ => new List { }, - }; + result.Add(new List { property.name }); + continue; } + result.Add(new List { property.name, property.unit }); + } + return result; + } + + public static LoginMessage CreateLoginMessage(string btc, string worker, string rigID, IOrderedEnumerable devices) + { + var sorted = SortedDevices(devices); + //if (_loginMessage != null) return _loginMessage; + Device mapComputeDevice(ComputeDevice d) + { return new Device { StaticProperties = new Dictionary { { "device_id", d.B64Uuid }, - { "class", $"{(int)d.DeviceType}" }, + { "class", $"{NHMDeviceTypeToNHMWSDeviceType(d.DeviceType)}" }, { "name", d.Name }, - { "optional", getStaticPropertiesOptionalValues(d) }, + { "optional", GetStaticPropertiesOptionalValues(d) }, }, - Actions = createDefaultActions(), - OptionalDynamicProperties = GetDeviceOptionalDynamic(d).properties, - OptionalMutableProperties = GetDeviceOptionalMutable(d).properties, + Actions = CreateDefaultDeviceActions(d.B64Uuid), + OptionalDynamicProperties = DeviceOptionalDynamicToList(GetDeviceOptionalDynamic(d, true).properties), + OptionalMutableProperties = GetDeviceOptionalMutable(d, true).properties, }; } - - _loginMessage = new LoginMessage + var DevicesProperties = devices.Select(mapComputeDevice).ToList(); //needs to execute first + return new LoginMessage { Btc = btc, Worker = worker, RigID = rigID, - Version = new List { $"NHM/{NHMApplication.ProductVersion}", "NA/NA" }, - OptionalMutableProperties = new List + Version = new List { $"NHM/{NHMApplication.ProductVersion}", Environment.OSVersion.ToString() }, + OptionalMutableProperties = GetRigOptionalMutableValues(true).properties, + OptionalDynamicProperties = GetRigOptionalDynamicValues().properties, + Actions = CreateDefaultRigActions(), + Devices = DevicesProperties, + MinerState = GetMinerStateValues(worker, devices), + }; + } + private static (List properties, JArray values) GetRigOptionalMutableValues(bool isLogin) + { + List getOptionalMutableProperties() + { + var optionalProperties = new List() { new OptionalMutablePropertyString { PropertyID = OptionalMutableProperty.NextPropertyId(), DisplayGroup = 0, DisplayName = "User name", - DefaultValue = btc, - Range = (64, null), + DefaultValue = CredentialsSettings.Instance.BitcoinAddress, + Range = (64, String.Empty), + GetValue = () => + { + return CredentialsSettings.Instance.BitcoinAddress; + }, + //ExecuteTask = (object p) => + //{ + // var userSetResult = await ApplicationStateManager.SetBTCIfValidOrDifferent(btc, true); + // return userSetResult switch + // { + // NhmwsSetResult.CHANGED => true, // we return executed + // NhmwsSetResult.INVALID => throw new RpcException("Mining address invalid", ErrorCode.InvalidUsername), + // NhmwsSetResult.NOTHING_TO_CHANGE => throw new RpcException($"Nothing to change btc \"{btc}\" already set", ErrorCode.RedundantRpc), + // _ => throw new RpcException($"", ErrorCode.InternalNhmError), + // }; + //} }, new OptionalMutablePropertyString { PropertyID = OptionalMutableProperty.NextPropertyId(), DisplayGroup = 0, DisplayName = "Worker name", - DefaultValue = worker, - Range = (64, null), + DefaultValue = CredentialsSettings.Instance.WorkerName, + Range = (64, String.Empty), + GetValue = () => + { + return CredentialsSettings.Instance.WorkerName; + }, + //ExecuteTask = (object p) => + //{ + // var workerSetResult = ApplicationStateManager.SetWorkerIfValidOrDifferent(worker, true); + // return workerSetResult switch + // { + // NhmwsSetResult.CHANGED => Task.FromResult(true), // we return executed + // NhmwsSetResult.INVALID => throw new RpcException("Worker name invalid", ErrorCode.InvalidWorker), + // NhmwsSetResult.NOTHING_TO_CHANGE => throw new RpcException($"Nothing to change worker name \"{worker}\" already set", ErrorCode.RedundantRpc), + // _ => throw new RpcException($"", ErrorCode.InternalNhmError), + // }; + //} }, - }, - Actions = createDefaultActions(), - Devices = devices.Select(mapComputeDevice).ToList(), - MinerState = GetMinerStateValues(worker, devices), + new OptionalMutablePropertyString + { + PropertyID = OptionalMutableProperty.NextPropertyId(), + DisplayGroup = 0, + DisplayName = "Miners settings", + DefaultValue = "", + Range = (65536, String.Empty), + GetValue = () => + { + string ret = string.Empty; + var minersSettingsGlobal = new MinerAlgoStateRig(); + var mutables = ActionMutableMap.MutableList.Where(m => m.ComputeDev != null && m.DisplayName == "Miners settings"); + if(mutables == null || mutables.Count() <= 0) return ret; + foreach (var mutable in mutables) + { + if (mutable.GetValue() is not string val) continue; + minersSettingsGlobal.Miners.Add(JsonConvert.DeserializeObject(val)); + } + ret += JsonConvert.SerializeObject(minersSettingsGlobal); + return ret; + }, + ExecuteTask = async (object p) => + { + if(p is not string prop) return -1; + var newStates = JsonConvert.DeserializeObject(prop); + //for each device thats inside apply new algo state + var devices = AvailableDevices.Devices.Where(d => newStates.Miners.Any(m => m.DeviceID.Contains(d.B64Uuid))); + if(devices == null) return -2; + var successCount = 0; + foreach(var ns in newStates.Miners) + { + var targetDev = AvailableDevices.Devices.FirstOrDefault(d => d.B64Uuid == ns.DeviceID); + if(targetDev == null) continue; + var tempRes = targetDev.ApplyNewAlgoStates(ns); + if(tempRes != 0) continue; + successCount++; + } + return successCount == newStates.Miners.Count ? 0 : -3; + } + }, + new OptionalMutablePropertyString + { + PropertyID = OptionalMutableProperty.NextPropertyId(), + DisplayGroup = 0, + DisplayName = "Scheduler settings", + DefaultValue = "", + Range = (4096, string.Empty), + GetValue = () => + { + string ret = SchedulesManager.Instance.ScheduleToJSON(); + return ret; + }, + ExecuteTask = async (object p) => + { + if(p is not string prop) return -1; + var (schedulerEnabled, returnedSchedules) = SchedulesManager.Instance.ScheduleFromJSON(prop); + SchedulesManager.Instance.ClearScheduleList(); + MiningSettings.Instance.UseScheduler = schedulerEnabled; + if(returnedSchedules != null) + { + foreach(var returnedSchedule in returnedSchedules) + { + returnedSchedule.From = DateTime.Parse(returnedSchedule.From).ToLocalTime().ToString("HH:mm"); + returnedSchedule.To = DateTime.Parse(returnedSchedule.To).ToLocalTime().ToString("HH:mm"); + SchedulesManager.Instance.AddScheduleToList(returnedSchedule); + } + } + _ = Task.Run(async () => await NHWebSocketV4.UpdateMinerStatus()); + return 0; + } + }, + new OptionalMutablePropertyBool + { + PropertyID = OptionalMutableProperty.NextPropertyId(), + DisplayGroup = 0, + DisplayName = "Auto update", + DefaultValue = false, + GetValue = () => + { + return UpdateSettings.Instance.AutoUpdateMinerPlugins && UpdateSettings.Instance.AutoUpdateNiceHashMiner; + }, + ExecuteTask = async (object p) => + { + if(p is not bool prop) return -1; + UpdateSettings.Instance.AutoUpdateMinerPlugins = prop; + UpdateSettings.Instance.AutoUpdateNiceHashMiner = prop; + _ = Task.Run(async () => await NHWebSocketV4.UpdateMinerStatus()); + return 0; + } + }, + new OptionalMutablePropertyString + { + PropertyID = OptionalMutableProperty.NextPropertyId(), + DisplayGroup = 0, + DisplayName = "Benchmark settings", + DefaultValue = "", + Range = (65536, ""), + GetValue = () => + { + var ret = string.Empty; + var minerSpeedsGlobal = new MinerAlgoSpeedRig(); + var mutables = ActionMutableMap.MutableList.Where(m => m.ComputeDev != null && m.DisplayName == "Benchmark settings"); + if(mutables == null || mutables.Count() <= 0) return ret; + foreach (var mutable in mutables) + { + if (mutable.GetValue() is not string val) continue; + minerSpeedsGlobal.Miners.Add(JsonConvert.DeserializeObject(val)); + } + ret += JsonConvert.SerializeObject(minerSpeedsGlobal); + return ret; + }, + ExecuteTask = async (object p) => + { + if(p is not string prop) return -1; + var newSpeeds = JsonConvert.DeserializeObject(prop); + //for each device thats inside apply new algo state + var devices = AvailableDevices.Devices.Where(d => newSpeeds.Miners.Any(m => m.DeviceID.Contains(d.B64Uuid))); + if(devices == null) return -2; + var successCount = 0; + foreach(var ns in newSpeeds.Miners) + { + var targetDev = AvailableDevices.Devices.FirstOrDefault(d => d.B64Uuid == ns.DeviceID); + if(targetDev == null) continue; + var tempRes = targetDev.ApplyNewAlgoSpeeds(ns); + if(tempRes != 0) continue; + successCount++; + } + return successCount == newSpeeds.Miners.Count ? 0 : -3; + } + } + }; + if (isLogin) + optionalProperties.ForEach(i => ActionMutableMap.MutableList.Add(i)); + return optionalProperties + .Where(p => p != null) + .ToList(); + + }; + + List getOptionalMutablePropertiesCached() + { + //if (_cachedDevicesOptionalMutable.TryGetValue(out var cachedProps)) return cachedProps; + return getOptionalMutableProperties(); + } + + var props = getOptionalMutablePropertiesCached(); + var selectedValues = props + .Where(p => p.GetValue() != null)? + .Select(p => p.GetValue()); + JArray values_omv = null; + if (selectedValues.Any()) + { + values_omv = new JArray(selectedValues); + } + return (props, values_omv); + } + private static (List> properties, JArray values) GetRigOptionalDynamicValues() + { + var dynamic = new List<(List prop, string val)> + { + (new List + { + "Uptime", + "s" + }, Helpers.GetElapsedSecondsSinceStart().ToString()), + (new List + { + "IP address" + }, Helpers.GetLocalIP().ToString()), + (new List + { + "Profiles bundle id" + }, BundleManager.GetBundleInfo().BundleID), + (new List + { + "Profiles bundle name" + }, BundleManager.GetBundleInfo().BundleName) }; - return _loginMessage; + var props = dynamic.Select(d => d.prop).ToList(); + var vals = dynamic.Select(d => d.val); + return (props, new JArray(vals)); } private static JObject GetMinerStateValues(string workerName, IOrderedEnumerable devices) @@ -283,7 +615,7 @@ internal static MinerState GetMinerState(string workerName, IOrderedEnumerable s switch { DeviceState.Stopped => 1, // READY/IDLE/STOPPED @@ -293,7 +625,8 @@ MinerState.DeviceState toDeviceState(ComputeDevice d) DeviceState.Pending => 0, // NOT DEFINED DeviceState.Disabled => 4, // DISABLED #if NHMWS4 - DeviceState.Gaming => 6, //GAMING + //DeviceState.Gaming => 6, //GAMING + DeviceState.Testing => (MiscSettings.Instance.EnableGPUManagement ? 7 : 2), //TESTING #endif _ => 0, // UNKNOWN }; @@ -308,25 +641,235 @@ JArray mmv(ComputeDevice d) { return new JArray(deviceStateToInt(d.State)); } + //Logger.Warn(_TAG, $"\t[{d.BaseDevice.Name}](deviceState):{d.State} -- converted (int):{deviceStateToInt(d.State)}"); return new MinerState.DeviceState { - MutableDynamicValues = mdv(d), + MandatoryDynamicValues = mdv(d), OptionalDynamicValues = GetDeviceOptionalDynamic(d).values, // odv MandatoryMutableValues = mmv(d), - OptionalMutableValues = GetDeviceOptionalMutable(d).values, // omv + OptionalMutableValues = GetDeviceOptionalMutable(d, false).values, // omv }; } - + //Logger.Warn(_TAG, $"Miner state (rigstatus):{rig} -- converted (int):{rigStateToInt(rig)}"); return new MinerState { MutableDynamicValues = new JArray(rigStateToInt(rig)), - OptionalDynamicValues = new JArray(), + OptionalDynamicValues = GetRigOptionalDynamicValues().values, MandatoryMutableValues = new JArray(rigStateToInt(rig), workerName), - OptionalMutableValues = new JArray(), + OptionalMutableValues = GetRigOptionalMutableValues(false).values, Devices = devices.Select(toDeviceState).ToList(), }; } + + private static List CreateDefaultDeviceActions(string uuid) + { + return new List + { + NhmwsAction.ActionDeviceEnable(uuid), + NhmwsAction.ActionDeviceDisable(uuid), + NhmwsAction.ActionDeviceRebenchmark(uuid), + NhmwsAction.ActionOcProfileTest(uuid), + NhmwsAction.ActionOcProfileTestStop(uuid), + NhmwsAction.ActionFanProfileTest(uuid), + NhmwsAction.ActionFanProfileTestStop(uuid), + NhmwsAction.ActionElpProfileTest(uuid), + NhmwsAction.ActionElpProfileTestStop(uuid), + }; + } + private static List CreateDefaultRigActions() + { + return new List + { + NhmwsAction.ActionStartMining(), + NhmwsAction.ActionStopMining(), + NhmwsAction.ActionRebenchmark(), + NhmwsAction.ActionProfilesBundleSet(), + NhmwsAction.ActionProfilesBundleReset(), + NhmwsAction.ActionRigShutdown(), + NhmwsAction.ActionRigRestart(), + NhmwsAction.ActionSystemDump(), + }; + } + private static List GetStaticPropertiesOptionalValues(ComputeDevice d) + { + return d.BaseDevice switch + { + IGpuDevice gpu => new List + { + new JArray("bus_id", $"{gpu.PCIeBusID}"), + new JArray("vram", $"{gpu.GpuRam}"), + new JArray("miners", GetMinersForDeviceStatic(d)), + new JArray("limits", GetLimitsForDevice(d)), + }, + _ => new List + { + new JArray("miners", GetMinersForDeviceStatic(d)), + new JArray("limits", GetLimitsForDevice(d)), + }, + }; + } + private static string GetMinersForDeviceDynamic(ComputeDevice d) + { + var minersObject = new MinerAlgoState(); + var containers = d.AlgorithmSettings; + if (containers == null) return String.Empty; + var grouped = containers.GroupBy(c => c.PluginName).ToList(); + if (grouped == null) return String.Empty; + foreach (var group in grouped) + { + var containerEnabled = group.Any(c => c.Enabled); + var miner = new MinerDynamic() { Id = group.Key, Enabled = containerEnabled }; + var algos = new List(); + foreach (var algo in group) + { + var tempAlgo = new Algo() { Id = algo.AlgorithmName, Enabled = algo.Enabled }; + algos.Add(tempAlgo); + } + miner.Algos = algos; + minersObject.Miners.Add(miner); + } + minersObject.DeviceID = d.B64Uuid; + minersObject.DeviceName = d.Name; + var json = JsonConvert.SerializeObject(minersObject); + return json; + } + + private static string GetMinersSpeedsForDeviceDynamic(ComputeDevice d) + { + var minersObject = new MinerAlgoSpeed(); + var containers = d.AlgorithmSettings; + if (containers == null) return string.Empty; + var grouped = containers.GroupBy(c => c.PluginName).ToList(); + if (grouped == null) return string.Empty; + foreach (var group in grouped) + { + var combinations = new List(); + foreach (var algo in group) + { + var algorithms = new List() + { + new AlgoSpeed() + { + Id = Convert.ToString((int)algo.IDs[0]), + Speed = algo.BenchmarkSpeed.ToString() + } + + }; + var combination = new Combination() + { + Id = algo.AlgorithmName, + Algos = algorithms + }; + combinations.Add(combination); + } + var miner = new MinerSpeedDynamic() { Id = group.Key, Combinations = combinations }; + minersObject.Miners.Add(miner); + } + minersObject.DeviceID = d.B64Uuid; + minersObject.DeviceName = d.Name; + var json = JsonConvert.SerializeObject(minersObject); + return json; + } + + private static string GetMinersForDeviceStatic(ComputeDevice d) + { + MinersStatic miners = new MinersStatic(); + var uniquePlugins = d.AlgorithmSettings?.Select(item => item.PluginName)?.Distinct()?.Where(item => !string.IsNullOrEmpty(item)); + if (uniquePlugins == null) return String.Empty; + foreach (var plugin in uniquePlugins) + { + var uniqueAlgos = d.AlgorithmSettings?.Where(item => item.PluginName == plugin)?.Select(item => item.AlgorithmName)?.Distinct(); + if (uniqueAlgos == null) uniqueAlgos = new List(); + miners.Miners.Add(new MinerStatic() { Id = plugin, AlgoList = uniqueAlgos.ToList() }); + } + var json = JsonConvert.SerializeObject(miners); + return json; + } + + private static int CheckOrCorrectDefaultValue(int min, int max, int def) + { + if (def > min && def < max) return def; + return (min + max) / 2; + } + private static bool AreLimitsWrong(int min, int max) + { + return max - min <= 20; + } + + private static string GetLimitsForDevice(ComputeDevice d) + { + //todo granulate + ComplexLimit limit = new ComplexLimit(); + if (d.DeviceMonitor is ITDP && d.DeviceMonitor is ITDPLimits tdpLim) + { + var lims = tdpLim.GetTDPLimits(); + if (lims.ok) + { + string unit = d.DeviceType == DeviceType.AMD ? "%" : "W"; + int defVal = CheckOrCorrectDefaultValue(lims.min, lims.max, lims.def); + limit.limits.Add(new Limit { Name = "Power Limit", Unit = unit, Def = defVal, Range = ((int)lims.min, (int)lims.max) }); + } + } + if (d.DeviceMonitor is ICoreClockSet) + { + if (d.DeviceType == DeviceType.NVIDIA && d.DeviceMonitor is ICoreClockRangeDelta ccLimDelta) + { + var lims = ccLimDelta.CoreClockRangeDelta; + if (lims.ok) + { + int defVal = CheckOrCorrectDefaultValue(lims.min, lims.max, lims.def); + limit.limits.Add(new Limit { Name = "Core clock delta", Unit = "MHz", Def = defVal, Range = (lims.min, lims.max) }); + } + } + if (d.DeviceMonitor is ICoreClockRange ccLim && !d.IsNvidiaAndSub2KSeries()) + { + var lims = ccLim.CoreClockRange; + if (lims.ok) + { + var range = AreLimitsWrong(lims.min, lims.max) ? (300, 3000) : (lims.min, lims.max); //default, if range fails + int defVal = CheckOrCorrectDefaultValue(lims.min, lims.max, lims.def); + if (AreLimitsWrong(lims.min, lims.max)) AvailableNotifications.CreateCoreClockRangeGetFailed(d.BaseDevice.ID, d.FullName); + limit.limits.Add(new Limit { Name = "Core clock", Unit = "MHz", Def = defVal, Range = range }); + } + } + } + if (d.DeviceMonitor is IMemoryClockSet) + { + if (d.DeviceType == DeviceType.NVIDIA && d.DeviceMonitor is IMemoryClockRangeDelta mcLimDelta) + { + var lims = mcLimDelta.MemoryClockRangeDelta; + if (lims.ok) + { + int defVal = CheckOrCorrectDefaultValue(lims.min, lims.max, lims.def); + limit.limits.Add(new Limit { Name = "Memory clock delta", Unit = "MHz", Def = defVal, Range = (lims.min, lims.max) }); + } + } + if (d.DeviceMonitor is IMemoryClockRange mcLim && !d.IsNvidiaAndSub2KSeries()) + { + var lims = mcLim.MemoryClockRange; + if (lims.ok) + { + var range = AreLimitsWrong(lims.min, lims.max) ? (300, 10000) : (lims.min, lims.max); //default, if range fails + int defVal = CheckOrCorrectDefaultValue(lims.min, lims.max, lims.def); + if (AreLimitsWrong(lims.min, lims.max)) AvailableNotifications.CreateMemClockRangeGetFailed(d.BaseDevice.ID, d.FullName); + limit.limits.Add(new Limit { Name = "Memory clock", Unit = "MHz", Def = defVal, Range = range }); + } + } + } + if(d.DeviceMonitor is ICoreVoltageSet && d.DeviceMonitor is ICoreVoltageRange cvRange) + { + var lims = cvRange.CoreVoltageRange; + if (lims.ok && d.DeviceMonitor is ICoreVoltage cvGet) + { + var def = d.DeviceType == DeviceType.INTEL ? lims.def : cvGet.CoreVoltage; + def = CheckOrCorrectDefaultValue(lims.min, lims.max, def); + limit.limits.Add(new Limit { Name = "Core Voltage", Unit = "mV", Def = def, Range = (lims.min, lims.max) }); + } + } + var json = JsonConvert.SerializeObject(limit); + return json; + } } } diff --git a/src/NHMCore/Nhmws/V4/MessagesV4.cs b/src/NHMCore/Nhmws/V4/MessagesV4.cs index abf536f25..f5f5aa008 100644 --- a/src/NHMCore/Nhmws/V4/MessagesV4.cs +++ b/src/NHMCore/Nhmws/V4/MessagesV4.cs @@ -1,11 +1,44 @@ using Newtonsoft.Json; using Newtonsoft.Json.Linq; +using Newtonsoft.Json.Serialization; +using NHMCore.Mining; using System; using System.Collections.Generic; +using System.Runtime.InteropServices; +using System.Security.Policy; using System.Threading.Tasks; +using System.Windows.Media.Animation; +using Windows.Devices.Sensors; namespace NHMCore.Nhmws.V4 { + public enum Type : int + { + Int = 0, + Bool = 1, + Enum = 2, + String = 3, + } + public enum SupportedAction : int + { + ActionUnsupported = -1, + ActionStartMining, + ActionStopMining, + ActionProfilesBundleSet, + ActionProfilesBundleReset, + ActionDeviceEnable, + ActionDeviceDisable, + ActionOcProfileTest, + ActionFanProfileTest, + ActionElpProfileTest, + ActionElpProfileTestStop, + ActionOcProfileTestStop, + ActionFanProfileTestStop, + ActionRebenchmark, + ActionRestart, + ActionShutdown, + ActionSystemDump, + } internal class LoginMessage : ISendMessage { [JsonProperty("method")] @@ -20,79 +53,37 @@ internal class LoginMessage : ISendMessage public string RigID { get; set; } = ""; [JsonProperty("worker")] public string Worker { get; set; } = ""; - //[JsonProperty("group")] - //public string Group { get; set; } = ""; - - // "static_properties": { ... }, - - // "optional_dynamic_properties": [ ... ], - + [JsonProperty("optional_dynamic_properties")] + public List> OptionalDynamicProperties { get; set; } [JsonProperty("optional_mutable_properties")] public List OptionalMutableProperties { get; set; } [JsonProperty("actions")] - public List Actions { get; set; } + public List Actions { get; set; } [JsonProperty("devices")] public List Devices { get; set; } [JsonProperty("miner.state")] - public JObject MinerState { get; set; } + public JObject MinerState { get; set; } } - - //internal class LoginMessageBreak : ISendMessage - //{ - // [JsonProperty("method")] - // public string Method => "loginBreak2"; - //} - - - // new stuff - - //internal class MinerBye : ISendMessage - //{ - // [JsonProperty("method")] - // public string Method => "miner.bye"; - // [JsonProperty("params")] - // public List Params = new List(); - //} - - //internal class ServerBye : IReceiveMessage - //{ - // [JsonProperty("method")] - // public string Method => "server.bye"; - // [JsonProperty("params")] - // public List Params = new List(); - //} - - - - internal interface IStaticMandatoryProperty { } internal interface IStaticOptionalProperty { } - + internal interface IDynamicMandatoryProperty { } - + internal interface IDynamicOptionalProperty { } internal interface IMutableMandatoryProperty { } - + internal interface IMutableOptionalProperty { } - + internal interface IAction { } - internal abstract class OptionalMutableProperty + public abstract class OptionalMutableProperty { - public enum Type : int - { - Int = 0, - Bool = 1, - Enum = 2, - String = 3, - } - private static int _nextPropertyId = 100; internal static int NextPropertyId() => _nextPropertyId++; @@ -105,23 +96,17 @@ public enum Type : int [JsonProperty("display_group")] public int? DisplayGroup { get; set; } = 0; - [JsonProperty("display_unit")] - public string DisplayUnit { get; set; } + [JsonProperty("display_unit", NullValueHandling = NullValueHandling.Ignore)] + public string? DisplayUnit { get; set; } [JsonProperty("type")] abstract public Type PropertyType { get; } - - //[JsonProperty("default")] - //public T DefaultValue { get; set; } - - //[JsonProperty("range")] - //public TR Range { get; set; } - [JsonIgnore] public Func> ExecuteTask { get; set; } - [JsonIgnore] public Func GetValue { get; set; } + [JsonIgnore] + public ComputeDevice ComputeDev { get; set; } } internal class OptionalMutablePropertyInt : OptionalMutableProperty @@ -172,7 +157,7 @@ internal class OptionalMutablePropertyString : OptionalMutableProperty public (int len, string charset) Range { get; set; } } - internal class NhnwsAction + public class NhmwsAction { private static int _actionId = 0; internal static int NextActionId() => _actionId++; @@ -185,26 +170,280 @@ internal class NhnwsAction [JsonProperty("display_group")] public int DisplayGroup { get; set; } - + [JsonProperty("parameters")] + public List Parameters { get; set; } = new(); [JsonIgnore] - public Func> ExecuteTask { get; set; } + public SupportedAction ActionType { get; set; } + [JsonIgnore] + public Func> ExecuteTask { get; set; } + [JsonIgnore] + public string DeviceUUID = String.Empty; + public static NhmwsAction ActionDeviceEnable(string uuid) + { + var action = new NhmwsAction + { + ActionID = NhmwsAction.NextActionId(), + DisplayName = "Device enable", + DisplayGroup = 0, + ActionType = SupportedAction.ActionDeviceEnable, + DeviceUUID = uuid + }; + ActionMutableMap.ActionList.Add(action); + return action; + } + public static NhmwsAction ActionDeviceDisable(string uuid) + { + var action = new NhmwsAction + { + ActionID = NhmwsAction.NextActionId(), + DisplayName = "Device disable", + DisplayGroup = 0, + ActionType = SupportedAction.ActionDeviceDisable, + DeviceUUID = uuid + }; + ActionMutableMap.ActionList.Add(action); + return action; + } + public static NhmwsAction ActionDeviceRebenchmark(string uuid) + { + var action = new NhmwsAction + { + ActionID = NhmwsAction.NextActionId(), + DisplayName = "Rebenchmark", + DisplayGroup = 0, + ActionType = SupportedAction.ActionRebenchmark, + DeviceUUID = uuid + }; + ActionMutableMap.ActionList.Add(action); + return action; + } + public static NhmwsAction ActionOcProfileTest(string uuid) + { + var action = new NhmwsAction + { + ActionID = NhmwsAction.NextActionId(), + DisplayName = "OC profile test", + DisplayGroup = 1, + Parameters = new List() + { + new ParameterStringLogin() + { + DisplayName = "OC profile", + DefaultValue = "", + Range = (1024, "") + } + }, + ActionType = SupportedAction.ActionOcProfileTest, + DeviceUUID = uuid + }; + ActionMutableMap.ActionList.Add(action); + return action; + } + public static NhmwsAction ActionOcProfileTestStop(string uuid) + { + var action = new NhmwsAction + { + ActionID = NhmwsAction.NextActionId(), + DisplayName = "OC profile stop test", + DisplayGroup = 1, + Parameters = new(), + ActionType = SupportedAction.ActionOcProfileTestStop, + DeviceUUID = uuid + }; + ActionMutableMap.ActionList.Add(action); + return action; + } + public static NhmwsAction ActionFanProfileTest(string uuid) + { + var action = new NhmwsAction + { + ActionID = NhmwsAction.NextActionId(), + DisplayName = "Fan profile test", + DisplayGroup = 1, + Parameters = new List() + { + new ParameterStringLogin() + { + DisplayName = "Fan profile", + DefaultValue = "", + Range = (1024, "") + } + }, + ActionType = SupportedAction.ActionFanProfileTest, + DeviceUUID = uuid + }; + ActionMutableMap.ActionList.Add(action); + return action; + } + public static NhmwsAction ActionFanProfileTestStop(string uuid) + { + var action = new NhmwsAction + { + ActionID = NhmwsAction.NextActionId(), + DisplayName = "Fan profile stop test", + DisplayGroup = 1, + Parameters = new(), + ActionType = SupportedAction.ActionFanProfileTestStop, + DeviceUUID = uuid + }; + ActionMutableMap.ActionList.Add(action); + return action; + } + public static NhmwsAction ActionElpProfileTest(string uuid) + { + var action = new NhmwsAction + { + ActionID = NhmwsAction.NextActionId(), + DisplayName = "ELP profile test", + DisplayGroup = 1, + Parameters = new List() + { + new ParameterStringLogin() + { + DisplayName = "ELP profile", + DefaultValue = "", + Range = (1024, "") + } + }, + ActionType= SupportedAction.ActionElpProfileTest, + DeviceUUID = uuid + }; + ActionMutableMap.ActionList.Add(action); + return action; + } + public static NhmwsAction ActionElpProfileTestStop(string uuid) + { + var action = new NhmwsAction + { + ActionID = NhmwsAction.NextActionId(), + DisplayName = "ELP profile stop test", + DisplayGroup = 1, + Parameters = new(), + ActionType= SupportedAction.ActionElpProfileTestStop, + DeviceUUID = uuid + }; + ActionMutableMap.ActionList.Add(action); + return action; + } + public static NhmwsAction ActionStartMining() + { + var action = new NhmwsAction + { + ActionID = NhmwsAction.NextActionId(), + DisplayName = "Mining start", + DisplayGroup = 0, + ActionType = SupportedAction.ActionStartMining, + }; + ActionMutableMap.ActionList.Add(action); + return action; + } + public static NhmwsAction ActionStopMining() + { + var action = new NhmwsAction + { + ActionID = NhmwsAction.NextActionId(), + DisplayName = "Mining stop", + DisplayGroup = 0, + ActionType = SupportedAction.ActionStopMining, + }; + ActionMutableMap.ActionList.Add(action); + return action; + } + public static NhmwsAction ActionProfilesBundleSet() + { + var action = new NhmwsAction + { + ActionID = NhmwsAction.NextActionId(), + DisplayName = "Profiles bundle set", + DisplayGroup = 1, + Parameters = new List() + { + new ParameterStringLogin() + { + DisplayName = "Bundle profiles", + DefaultValue = "", + Range = (8192, "") + } + }, + ActionType = SupportedAction.ActionProfilesBundleSet, + }; + ActionMutableMap.ActionList.Add(action); + return action; + } + public static NhmwsAction ActionProfilesBundleReset() + { + var action = new NhmwsAction + { + ActionID = NhmwsAction.NextActionId(), + DisplayName = "Profiles bundle reset", + DisplayGroup = 1, + ActionType= SupportedAction.ActionProfilesBundleReset, + }; + ActionMutableMap.ActionList.Add(action); + return action; + } + public static NhmwsAction ActionRebenchmark() + { + var action = new NhmwsAction + { + ActionID = NhmwsAction.NextActionId(), + DisplayName = "Rebenchmark", + DisplayGroup = 0, + ActionType = SupportedAction.ActionRebenchmark + }; + ActionMutableMap.ActionList.Add(action); + return action; + } + public static NhmwsAction ActionRigShutdown() + { + var action = new NhmwsAction + { + ActionID = NhmwsAction.NextActionId(), + DisplayName = "Rig shutdown", + DisplayGroup = 0, + ActionType = SupportedAction.ActionShutdown, + }; + ActionMutableMap.ActionList.Add(action); + return action; + } + public static NhmwsAction ActionRigRestart() + { + var action = new NhmwsAction + { + ActionID = NhmwsAction.NextActionId(), + DisplayName = "Rig restart", + DisplayGroup = 0, + ActionType = SupportedAction.ActionRestart, + }; + ActionMutableMap.ActionList.Add(action); + return action; + } + public static NhmwsAction ActionSystemDump() + { + var action = new NhmwsAction + { + ActionID = NhmwsAction.NextActionId(), + DisplayName = "System dump", + DisplayGroup = 0, + ActionType = SupportedAction.ActionSystemDump, + }; + ActionMutableMap.ActionList.Add(action); + return action; + } } - internal class Device { [JsonProperty("static_properties")] public Dictionary StaticProperties { get; set; } [JsonProperty("optional_dynamic_properties")] - [JsonConverter(typeof(Nhmws4JSONConverter))] - public List<(string name, string unit)> OptionalDynamicProperties { get; set; } - - // + //[JsonConverter(typeof(Nhmws4JSONConverter))] + public List> OptionalDynamicProperties { get; set; } [JsonProperty("optional_mutable_properties")] public List OptionalMutableProperties { get; set; } [JsonProperty("actions")] - public List Actions { get; set; } + public List Actions { get; set; } } @@ -212,36 +451,323 @@ internal class MinerState : ISendMessage { internal class DeviceState { - [JsonProperty("mdv")] - public JArray MutableDynamicValues { get; set; } + [JsonProperty("mdv", NullValueHandling = NullValueHandling.Ignore)] + public JArray MandatoryDynamicValues { get; set; } - [JsonProperty("odv")] + [JsonProperty("odv", NullValueHandling = NullValueHandling.Ignore)] public JArray OptionalDynamicValues { get; set; } - [JsonProperty("mmv")] + [JsonProperty("mmv", NullValueHandling = NullValueHandling.Ignore)] public JArray MandatoryMutableValues { get; set; } - [JsonProperty("omv")] + [JsonProperty("omv", NullValueHandling = NullValueHandling.Ignore)] public JArray OptionalMutableValues { get; set; } } [JsonProperty("method")] public string Method => "miner.state"; - [JsonProperty("mdv")] + [JsonProperty("mdv", NullValueHandling = NullValueHandling.Ignore)] public JArray MutableDynamicValues { get; set; } - [JsonProperty("odv")] + [JsonProperty("odv", NullValueHandling = NullValueHandling.Ignore)] public JArray OptionalDynamicValues { get; set; } - [JsonProperty("mmv")] + [JsonProperty("mmv", NullValueHandling = NullValueHandling.Ignore)] public JArray MandatoryMutableValues { get; set; } - [JsonProperty("omv")] + [JsonProperty("omv", NullValueHandling = NullValueHandling.Ignore)] public JArray OptionalMutableValues { get; set; } - [JsonProperty("devices")] + [JsonProperty("devices", NullValueHandling = NullValueHandling.Ignore)] public List Devices { get; set; } } + public abstract class ParameterLogin + { + [JsonProperty("display_name")] + public string DisplayName { get; set; } + [JsonProperty("display_group", NullValueHandling = NullValueHandling.Ignore)] + public int? DisplayGroup { get; set; } + [JsonProperty("display_unit", NullValueHandling = NullValueHandling.Ignore)] + public string? DisplayUnit { get; set; } + [JsonProperty("type")] + abstract public Type PropertyType { get; } + } + internal class ParameterIntegerLogin : ParameterLogin + { + [JsonProperty("type")] + public override Type PropertyType => Type.Int; + + [JsonProperty("default")] + public int DefaultValue { get; set; } + + [JsonProperty("range")] + [JsonConverter(typeof(Nhmws4JSONConverter))] + public (int min, int max) Range { get; set; } + } + internal class ParameterBoolLogin : ParameterLogin + { + [JsonProperty("type")] + public override Type PropertyType => Type.Bool; + + [JsonProperty("default")] + public bool DefaultValue { get; set; } + } + internal class ParameterEnumLogin : ParameterLogin + { + [JsonProperty("type")] + public override Type PropertyType => Type.Enum; + + [JsonProperty("default")] + public string DefaultValue { get; set; } + + [JsonProperty("range")] + public List Range { get; set; } + } + internal class ParameterStringLogin : ParameterLogin + { + [JsonProperty("type")] + public override Type PropertyType => Type.String; + + [JsonProperty("default")] + public string DefaultValue { get; set; } + + [JsonProperty("range")] + [JsonConverter(typeof(Nhmws4JSONConverter))] + public (int len, string charset) Range { get; set; } + } + internal abstract class ActionParameter + { + [JsonProperty("device_name")] + public string DeviceName { get; set; } + [JsonProperty("name")] + public string Name { get; set; } + [JsonProperty("type")] + public int Type { get; set; } + } + internal class Property + { + [JsonProperty("prop_id")] + public int PropId { get; set; } + } + internal class PropertyInt : Property + { + [JsonProperty("value")] + public int Value { get; set; } + } + internal class PropertyBool : Property + { + [JsonProperty("value")] + public bool Value { get; set; } + } + internal class PropertyEnum : Property + { + [JsonProperty("value")] + public Type Value { get; set; } + } + internal class PropertyString : Property + { + [JsonProperty("value")] + public string Value { get; set; } + } + public class MinerAlgoState + { + [JsonProperty("miners")] + public List Miners { get; set; } = new List(); + [JsonProperty("device_id")] + public string DeviceID { get; set; } + [JsonProperty("device_name")] + public string DeviceName { get; set; } + } + public class MinerAlgoStateRig + { + [JsonProperty("devices")] + public List Miners { get; set; } = new List(); + } + public class MinerAlgoSpeed + { + [JsonProperty("miners")] + public List Miners { get; set; } = new List(); + [JsonProperty("device_id")] + public string DeviceID { get; set; } + [JsonProperty("device_name")] + public string DeviceName { get; set; } + } + public class MinerAlgoSpeedRig + { + [JsonProperty("devices")] + public List Miners { get; set; } = new(); + } + public class MinerDynamic + { + [JsonProperty("id")] + public string Id { get; set; } + [JsonProperty("enabled")] + public bool Enabled { get; set; } + [JsonProperty("algorithms")] + public List Algos { get; set; } = new List(); + } + public class MinerSpeedDynamic + { + [JsonProperty("id")] + public string Id { get; set; } + [JsonProperty("combination")] + public List Combinations { get; set; } = new List(); + } + internal class MinersStatic + { + [JsonProperty("miners")] + public List Miners { get; set; } = new List(); + } + internal class MinerStatic + { + [JsonProperty("id")] + public string Id { get; set; } + [JsonProperty("algorithms")] + public List AlgoList { get; set; } = new List(); + } + public class Algo + { + [JsonProperty("id")] + public string Id { get; set; } + [JsonProperty("enabled", NullValueHandling = NullValueHandling.Ignore)] + public bool? Enabled { get; set; } + } + + public class AlgoSpeed + { + [JsonProperty("id")] + public string Id { get; set; } + [JsonProperty("speed", NullValueHandling = NullValueHandling.Ignore)] + public string? Speed { get; set; } + } + + public class Combination + { + [JsonProperty("id")] + public string Id { get; set; } + [JsonProperty("algorithm")] + public List Algos { get; set; } = new List(); + } + + public class Bundle + { + [JsonProperty("id")] + public string Id { get; set; } + [JsonProperty("name")] + public string Name { get; set; } + [JsonProperty("oc", NullValueHandling = NullValueHandling.Ignore)] + public List? OcBundles { get; set; } + [JsonProperty("fan", NullValueHandling = NullValueHandling.Ignore)] + public List? FanBundles { get; set; } + [JsonProperty("elp", NullValueHandling = NullValueHandling.Ignore)] + public List? ElpBundles { get; set; } + } + public class GenericProfile + { + [JsonProperty("name")] + public string Name { get; set; } + [JsonProperty("id")] + public string Id { get; set; } + [JsonProperty("device_name")] + public string DeviceName { get; set; } + [JsonProperty("miner_id", NullValueHandling = NullValueHandling.Ignore)] + public List? MinerId { get; set; } + [JsonProperty("algorithm_id", NullValueHandling = NullValueHandling.Ignore)] + public List? AlgoId { get; set; } + } + public class ElpProfile : GenericProfile + { + [JsonProperty("elp")] + public string Elp { get; set; } + } + public class OcProfile : GenericProfile + { + [JsonProperty("core_clock")] + public int? CoreClock { get; set; } + [JsonProperty("core_clock_delta")] + public int? CoreClockDelta { get; set; } + [JsonProperty("memory_clock")] + public int? MemoryClock { get; set; } + [JsonProperty("memory_clock_delta")] + public int? MemoryClockDelta { get; set; } + [JsonProperty("power_limit")] + public int? TDP { get; set; } + [JsonProperty("core_voltage")] + public int? CoreVoltage { get; set; } + } + public class FanProfile : GenericProfile + { + [JsonProperty("type")] + public int Type { get; set; } + [JsonProperty("fan_speed")] + public int FanSpeed { get; set; } + [JsonProperty("gpu_temp")] + public int GpuTemp { get; set; } + [JsonProperty("vram_temp")] + public int VramTemp { get; set; } + [JsonProperty("max_fan_speed")] + public int MaxFanSpeed { get; set; } + } + internal class Limit + { + [JsonProperty("name")] + public string Name { get; set; } + [JsonProperty("unit")] + public string Unit { get; set; } + [JsonProperty("default")] + public int Def { get; set; } + [JsonProperty("range")] + [JsonConverter(typeof(Nhmws4JSONConverter))] + public (int min, int max) Range { get; set; } + + } + + internal class ComplexLimit + { + [JsonProperty("limits")] + public List limits = new List(); + } + + public class SchedulesWS4 + { + [JsonProperty("enabled")] + public bool enabled { get; set; } + [JsonProperty("slots")] + public List> slots = new(); + } + + public class NhmwsEvent : ISendMessage + { + [JsonProperty("method")] + public string Method => "miner.event"; + [JsonProperty("event_id")] + public int EventID { get; set; } + [JsonProperty("time")] + public long Time { get; set; } + [JsonProperty("device_id", NullValueHandling = NullValueHandling.Ignore)] + public string DeviceID { get; set; } + [JsonProperty("message", NullValueHandling = NullValueHandling.Ignore)] + public string Message { get; set; } + } + public class NhmwsEventContent + { + [JsonProperty("rig_name", NullValueHandling = NullValueHandling.Ignore)] + public string RigName { get; set; } + [JsonProperty("gpu_name", NullValueHandling = NullValueHandling.Ignore)] + public string GpuName { get; set; } + [JsonProperty("plugin_name", NullValueHandling = NullValueHandling.Ignore)] + public string PluginName { get; set; } + [JsonProperty("algo_name", NullValueHandling = NullValueHandling.Ignore)] + public string AlgoName { get; set; } + [JsonProperty("algo_name_old", NullValueHandling = NullValueHandling.Ignore)] + public string AlgoNameOld { get; set; } + [JsonProperty("algo_name_new", NullValueHandling = NullValueHandling.Ignore)] + public string AlgoNameNew { get; set; } + [JsonProperty("bundle_name", NullValueHandling = NullValueHandling.Ignore)] + public string BundleName { get; set; } + [JsonProperty("algo_names", NullValueHandling = NullValueHandling.Ignore)] + public List AlgoNames { get; set; } = new List(); + } } diff --git a/src/NHMCore/Nhmws/V4/NHWebSocketV4.cs b/src/NHMCore/Nhmws/V4/NHWebSocketV4.cs index 619b65df4..019b8a8f0 100644 --- a/src/NHMCore/Nhmws/V4/NHWebSocketV4.cs +++ b/src/NHMCore/Nhmws/V4/NHWebSocketV4.cs @@ -1,10 +1,13 @@ using Newtonsoft.Json; +using Newtonsoft.Json.Linq; using NHM.Common; using NHM.Common.Enums; using NHM.DeviceMonitoring.TDP; using NHMCore.ApplicationState; using NHMCore.Configs; +using NHMCore.Configs.Managers; using NHMCore.Mining; +using NHMCore.Notifications; using NHMCore.Switching; using NHMCore.Utils; using System; @@ -13,18 +16,22 @@ using System.Diagnostics; using System.Linq; using System.Reflection; +using System.Reflection.Metadata; using System.Threading; using System.Threading.Tasks; +using System.Windows.Threading; using WebSocketSharp; +using Windows.Media.PlayTo; +using Logger = NHM.Common.Logger; // static imports using NHLog = NHM.Common.Logger; namespace NHMCore.Nhmws.V4 { - static class NHWebSocketV4 + public static class NHWebSocketV4 { #region locking - + private static readonly string _logTag = "NHWebSocketV4"; private static readonly object _lock = new object(); private class LockingProperty { @@ -62,8 +69,9 @@ private enum MessageType { CLOSE_WEBSOCKET = 0, SEND_MESSAGE_STATUS, + SEND_MESSAGE_EVENT } - + private static readonly string _TAG = "NHWebSocketV4"; static private bool _isNhmwsRestart = false; static private bool IsWsAlive => _webSocket?.ReadyState == WebSocketState.Open; @@ -72,9 +80,10 @@ private enum MessageType static private LoginMessage _login = new LoginMessage { - Version = new List { $"NHM/{NHMApplication.ProductVersion}", "NA/NA" }, + Version = new List { $"NHM/{NHMApplication.ProductVersion}", Environment.OSVersion.ToString() }, Btc = DemoUser.BTC, }; + private static MinerState CachedState = null; static private ConcurrentQueue _recieveQueue { get; set; } = new ConcurrentQueue(); static private ConcurrentQueue> _sendQueue { get; set; } = new ConcurrentQueue>(); @@ -264,6 +273,7 @@ static private void HandleSendMessage() _isNhmwsRestart = true; break; case MessageType.SEND_MESSAGE_STATUS: + case MessageType.SEND_MESSAGE_EVENT: Send(data); _lastSendMinerStatusTimestamp.Value = DateTime.UtcNow; break; @@ -312,18 +322,137 @@ static public void ResetCredentials(string btc = null, string worker = null, str static public void SetCredentials(string btc = null, string worker = null, string group = null) { - _login = MessageParserV4.CreateLoginMessage(btc, worker, ApplicationStateManager.RigID(), AvailableDevices.Devices.SortedDevices()); + string workerToSend = worker == null ? string.Empty : worker; + string btcToSend = btc == null ? string.Empty : btc; + ActionMutableMap.ResetArrays(); + if (CachedState != null) CachedState = null; + _login = MessageParserV4.CreateLoginMessage(btcToSend, workerToSend, ApplicationStateManager.RigID(), AvailableDevices.Devices.SortedDevices()); if (!string.IsNullOrEmpty(btc)) _login.Btc = btc; - if (worker != null) _login.Worker = worker; + else _login.Btc = CredentialsSettings.Instance.BitcoinAddress; + if (!string.IsNullOrEmpty(worker)) _login.Worker = worker; + else _login.Worker = CredentialsSettings.Instance.WorkerName; //if (group != null) _login.Group = group; // on credentials change always send close websocket message var closeMsg = (MessageType.CLOSE_WEBSOCKET, $"Credentials change reconnecting {ApplicationStateManager.Title}."); _sendQueue.EnqueueParams(closeMsg); } + public static void SendEvent(NhmwsEvent ev) + { + //DateTimeOffset now = new DateTimeOffset(DateTime.UtcNow); + //var unixTime = now.ToUnixTimeSeconds(); + //var newEvent = new NhmwsEvent() + //{ + // EventID = (int)id, + // Time = unixTime, + // DeviceID = ev.DeviceID, + // Message = ev.Message + //}; + var eventMSG = (MessageType.SEND_MESSAGE_EVENT, JsonConvert.SerializeObject(ev)); + _sendQueue.EnqueueParams(eventMSG); + } + #region Message handling + private static bool AreEqual(JArray first, JArray second) + { + if (first == null && second == null) return true; + if (first == null || second == null) return false; + return JsonConvert.SerializeObject(first) == JsonConvert.SerializeObject(second); + } + private static MinerState.DeviceState GetDeviceStateDelta(MinerState.DeviceState first, MinerState.DeviceState second) + { + if (first == null || second == null) return second; + var devState = new MinerState.DeviceState(); + //if (!AreEqual(first.OptionalDynamicValues, second.OptionalDynamicValues)) + //{ + // devState.OptionalDynamicValues = second.OptionalDynamicValues; + //} + //if (!AreEqual(first.MandatoryDynamicValues, second.MandatoryDynamicValues)) + //{ + // devState.MandatoryDynamicValues = second.MandatoryDynamicValues; + //} + devState.OptionalDynamicValues = second.OptionalDynamicValues; + devState.MandatoryDynamicValues = second.MandatoryDynamicValues; + if (!AreEqual(first.OptionalMutableValues, second.OptionalMutableValues)) + { + devState.OptionalMutableValues = second.OptionalMutableValues; + } + if (!AreEqual(first.MandatoryMutableValues, second.MandatoryMutableValues)) + { + devState.MandatoryMutableValues = second.MandatoryMutableValues; + } + return devState; + } + private static bool AreDeviceListsComparable(List first, List second) + { + if (first == null || second == null) return true; + if (first.Count != second.Count) return false; + return true; + } - private static string CreateMinerStatusMessage() => JsonConvert.SerializeObject(MessageParserV4.GetMinerState(_login.Worker, AvailableDevices.Devices.SortedDevices())); + private static MinerState GetDeltaProperties(MinerState prev, MinerState next) + { + MinerState ret = new MinerState(); + //if (!AreEqual(prev.MutableDynamicValues, next.MutableDynamicValues)) + //{ + // ret.MutableDynamicValues = next.MutableDynamicValues; + //} + ret.MutableDynamicValues = next.MutableDynamicValues; + if (!AreEqual(prev.OptionalDynamicValues, next.OptionalDynamicValues)) + { + ret.OptionalDynamicValues = next.OptionalDynamicValues; + } + if (!AreEqual(prev.OptionalMutableValues, next.OptionalMutableValues)) + { + ret.OptionalMutableValues = next.OptionalMutableValues; + } + if (!AreEqual(prev.MandatoryMutableValues, next.MandatoryMutableValues)) + { + ret.MandatoryMutableValues = next.MandatoryMutableValues; + } + + if (AreDeviceListsComparable(prev.Devices, next.Devices)) + { + if (prev.Devices == null && next.Devices == null) return ret; + if(prev.Devices == null && next.Devices != null) + { + ret.Devices = next.Devices; + return ret; + } + if(prev.Devices != null && next.Devices == null) + { + ret.Devices = null; + return ret; + } + ret.Devices = new(); + for(int i = 0; i < next.Devices.Count; i++) + { + ret.Devices.Add(GetDeviceStateDelta(prev.Devices[i], next.Devices[i])); + } + } + else + { + ret.Devices = next.Devices; + } + return ret; + } + private static string CreateMinerStatusMessage() + { + var nextState = MessageParserV4.GetMinerState(_login.Worker, AvailableDevices.Devices.SortedDevices()); + var shrinkedState = new MinerState(); + var json = string.Empty; + if (CachedState != null) //if we have something cached + { + shrinkedState = GetDeltaProperties(CachedState, nextState); + json = JsonConvert.SerializeObject(shrinkedState); + } + else + { + json = JsonConvert.SerializeObject(nextState); + } + CachedState = nextState; + return json; + } static private async Task HandleMessage(MessageEventArgs e) { @@ -593,10 +722,12 @@ private static Task StopMining(string devs) } #endregion Stop + #region Actions + + #endregion Actions + private static Task SetPowerMode(string device, TDPSimpleType level) { - if (GlobalDeviceSettings.Instance.DisableDevicePowerModeSettings) throw new RpcException("Not able to set Power Mode: Device Power Mode Settings Disabled", ErrorCode.UnableToHandleRpc); - var devs = device == "*" ? AvailableDevices.Devices : AvailableDevices.Devices.Where(d => d.B64Uuid == device); @@ -673,9 +804,412 @@ async Task systemDump() _ => throw new RpcException($"RpcMessage MinerReset operation not supported for level '{level}'", ErrorCode.UnableToHandleRpc), }; } + private static Task<(ErrorCode err, string msg)> CallAction(MinerCallAction action) + { + var actionRecord = ActionMutableMap.FindActionOrNull(action.ActionId); + if (actionRecord == null) + { + Logger.Error("NHWebSocketV4", "Action not found"); + return Task.FromResult((ErrorCode.ActionNotFound, "Action not found")); + } + //action has single parameter anyway FOR NOW + //in the future return multiple actions success/partial/failiure + var ret = (ErrorCode.NoError, string.Empty); + foreach (var param in action.Parameters) + { + ret = ParseAndCallAction(actionRecord.DeviceUUID, action.Id, actionRecord.ActionType, param).Result; + } + if (!action.Parameters.Any()) + { + ret = ParseAndCallAction(actionRecord.DeviceUUID, action.Id, actionRecord.ActionType, string.Empty).Result; + } + return Task.FromResult(ret); + } + private static Task<(ErrorCode err, string msg)> ParseAndCallAction(string deviceUUID, int messageID, SupportedAction typeOfAction, string parameters) + { + ErrorCode err = ErrorCode.NoError; + var result = string.Empty; + switch (typeOfAction) + { + case SupportedAction.ActionStartMining: + _ = startMiningAllDevices(); + (err, result) = (ErrorCode.NoError, "OK"); + break; + case SupportedAction.ActionStopMining: + _ = stopMiningAllDevices(); + (err, result) = (ErrorCode.NoError, "OK"); + break; + case SupportedAction.ActionRebenchmark: + if(deviceUUID == string.Empty) (err, result) = ApplicationStateManager.StartReBenchmark().Result; + else + { + (err, result) = ApplicationStateManager.StartRebenchmarkSpecific(deviceUUID).Result; + } + break; + case SupportedAction.ActionProfilesBundleSet: + if (!Helpers.IsElevated) + { + (err, result) = (ErrorCode.ErrNotAdmin, "No admin privileges"); + break; + } + if (!MiscSettings.Instance.EnableGPUManagement) + { + (err, result) = (ErrorCode.InternalNhmError, "GPU management disabled"); + break; + } + var bundle = JsonConvert.DeserializeObject(parameters); + _ = ExecuteProfilesBundleReset(false); + _ = ExecuteProfilesBundleSet(bundle); + MiningState.Instance.CalculateDevicesStateChange(); + (err, result) = (ErrorCode.NoError, "OK"); + if(err == ErrorCode.NoError) + { + EventManager.Instance.AddEventBundleApplied(bundle.Name,true); + } + break; + case SupportedAction.ActionProfilesBundleReset: + if (!Helpers.IsElevated) + { + (err, result) = (ErrorCode.ErrNotAdmin, "No admin privileges"); + break; + } + if (!MiscSettings.Instance.EnableGPUManagement) + { + (err, result) = (ErrorCode.InternalNhmError, "GPU management disabled"); + break; + } + ExecuteProfilesBundleReset(); + MiningState.Instance.CalculateDevicesStateChange(); + (err, result) = (ErrorCode.NoError, "OK"); + break; + case SupportedAction.ActionDeviceEnable: + _ = SetDevicesEnabled(deviceUUID, true); + (err, result) = (ErrorCode.NoError, "OK"); + break; + case SupportedAction.ActionDeviceDisable: + _ = SetDevicesEnabled(deviceUUID, false); + (err, result) = (ErrorCode.NoError, "OK"); + break; + case SupportedAction.ActionOcProfileTest: + if (!Helpers.IsElevated) + { + (err, result) = (ErrorCode.ErrNotAdmin, "No admin privileges"); + break; + } + if (!MiscSettings.Instance.EnableGPUManagement) + { + (err, result) = (ErrorCode.InternalNhmError, "GPU management disabled"); + break; + } + var oc = JsonConvert.DeserializeObject(parameters); + (err, result) = ExecuteOCTest(deviceUUID, oc).Result; + var eventRet = err == ErrorCode.NoError ? EventType.TestOCApplied : EventType.TestOCFailed; + var dev = AvailableDevices.Devices.FirstOrDefault(dev => dev.B64Uuid == deviceUUID); + if (dev != null) + { + if (eventRet == EventType.TestOCApplied) EventManager.Instance.AddEventTestOCApplied(dev.Name, dev.B64Uuid, true); + else EventManager.Instance.AddEventTestOCFailed(dev.Name, dev.B64Uuid, true); + } + break; + case SupportedAction.ActionOcProfileTestStop: + if (!Helpers.IsElevated) + { + (err, result) = (ErrorCode.ErrNotAdmin, "No admin privileges"); + break; + } + if (!MiscSettings.Instance.EnableGPUManagement) + { + (err, result) = (ErrorCode.InternalNhmError, "GPU management disabled"); + break; + } + (err, result) = StopOCTestForDevice(deviceUUID).Result; + break; + case SupportedAction.ActionFanProfileTest: + if (!Helpers.IsElevated) + { + (err, result) = (ErrorCode.ErrNotAdmin, "No admin privileges"); + break; + } + if (!MiscSettings.Instance.EnableGPUManagement) + { + (err, result) = (ErrorCode.InternalNhmError, "GPU management disabled"); + break; + } + var fan = JsonConvert.DeserializeObject(parameters); + (err, result) = ExecuteFanTest(deviceUUID, fan).Result; + break; + case SupportedAction.ActionFanProfileTestStop: + if (!Helpers.IsElevated) + { + (err, result) = (ErrorCode.ErrNotAdmin, "No admin privileges"); + break; + } + if (!MiscSettings.Instance.EnableGPUManagement) + { + (err, result) = (ErrorCode.InternalNhmError, "GPU management disabled"); + break; + } + (err, result) = StopFanTestForDevice(deviceUUID).Result; + break; + case SupportedAction.ActionElpProfileTest: + if (!Helpers.IsElevated) + { + (err, result) = (ErrorCode.ErrNotAdmin, "No admin privileges"); + break; + } + var elp = JsonConvert.DeserializeObject(parameters); + (err, result) = ExecuteELPTest(deviceUUID, elp).Result; + MiningState.Instance.CalculateDevicesStateChange(); + break; + case SupportedAction.ActionElpProfileTestStop: + if (!Helpers.IsElevated) + { + (err, result) = (ErrorCode.ErrNotAdmin, "No admin privileges"); + break; + } + (err, result) = StopELPTestForDevice(deviceUUID).Result; + MiningState.Instance.CalculateDevicesStateChange(); + break; + case SupportedAction.ActionRestart: + EventManager.Instance.AddEventRigRestart(true); + _ = RestartRig(); + (err, result) = (ErrorCode.NoError, "Restarting rig"); + break; + case SupportedAction.ActionShutdown: + _ = ShutdownRig(); + (err, result) = (ErrorCode.NoError, "Shutting down rig"); + break; + case SupportedAction.ActionSystemDump: + (err, result) = CreateAndUploadSystemDump().Result; + break; + default: + NHLog.Warn(_logTag, "This type of action is unsupported: " + typeOfAction); + break; + } + _ = UpdateMinerStatus(); + if(err != ErrorCode.NoError) + { + Logger.Warn(_TAG, $"Action ({typeOfAction}) completed with non zero status: {err}"); + } + return Task.FromResult((err, result)); + } + private static async Task ShutdownRig() + { + try + { + if (AvailableDevices.Devices.Any(d => d.IsMiningBenchingTesting)) + { + var res = await stopMiningAllDevices(); + } + if (!MiscSettings.Instance.RunAtStartup) + { + Dispatcher.CurrentDispatcher.Invoke(() => + { + MiscSettings.Instance.RunAtStartup = true; + }); + } + } + catch (Exception e) + { + Logger.Error(_logTag, e.Message); + } + Logger.Warn(_logTag, "Rig shutdown called remotely, shutdown in 5 seconds"); + Process.Start("shutdown", "/s /t 5"); + } + + private static async Task RestartRig() + { + + try + { + if(AvailableDevices.Devices.Any(d => d.IsMiningBenchingTesting)) + { + var res = await stopMiningAllDevices(); + } + Helpers.CreateRunOnStartupBackup(); + if (!MiscSettings.Instance.RunAtStartup) + { + Dispatcher.CurrentDispatcher.Invoke(() => + { + MiscSettings.Instance.RunAtStartup = true; + }); + } + } + catch (Exception e) + { + Logger.Error(_logTag, e.Message); + } + Logger.Warn(_logTag, "Rig restart called remotely, shutdown in 5 seconds"); + Process.Start("shutdown", "/r /t 5"); + } + + public static async Task<(ErrorCode err, string msg)> CreateAndUploadSystemDump() + { + var (success, uuid, _) = await Helpers.CreateAndUploadLogReport(); + AvailableNotifications.CreateLogUploadResultInfo(success, uuid); + if (success) return (ErrorCode.NoError, "System dump upload successful"); + return (ErrorCode.ErrFailedSystemDump, "System dump upload failed"); + } + public static Task UpdateMinerStatus() + { + var minerStatusJsonStr = CreateMinerStatusMessage(); + _sendQueue.EnqueueParams((MessageType.SEND_MESSAGE_STATUS, minerStatusJsonStr)); + return Task.CompletedTask; + } + + private static Task ExecuteProfilesBundleSet(Bundle bundle) + { + BundleManager.SetBundleInfo(bundle.Name, bundle.Id); + _ = BundleManager.SaveBundle(bundle); + if (bundle.OcBundles != null) + { + var retOC = OCManager.Instance.ApplyOcBundle(bundle.OcBundles); + } + if (bundle.FanBundles != null) + { + var retFan = FanManager.Instance.ApplyFanBundle(bundle.FanBundles); + } + if (bundle.ElpBundles != null) + { + var retELP = ELPManager.Instance.ApplyELPBundle(bundle.ElpBundles); + } + return Task.CompletedTask; + } + private static Task StopTestsForDevice(string deviceUUID) + { + StopOCTestForDevice(deviceUUID, false); + StopFanTestForDevice(deviceUUID, false); + StopELPTestForDevice(deviceUUID, false); + return Task.CompletedTask; + } + private static Task ExecuteProfilesBundleReset(bool triggerSwitch = true) + { + BundleManager.ResetBundleInfo(); + var retOC = OCManager.Instance.ResetOcBundle(triggerSwitch); + var retFan = FanManager.Instance.ResetFanBundle(triggerSwitch); + var retElp = ELPManager.Instance.ResetELPBundle(triggerSwitch); + return Task.CompletedTask; + } + private static Task<(ErrorCode err, string msg)> ExecuteOCTest(string deviceUUID, OcProfile ocBundle) + { + if (!Helpers.IsElevated) return Task.FromResult((ErrorCode.ErrNotAdmin, "No administrator privileges")); + StopTestsForDevice(deviceUUID); + ELPManager.Instance.RestartMiningInstanceIfNeeded(); + var res = OCManager.Instance.ExecuteTest(deviceUUID, ocBundle); + return Task.FromResult(res.Result); + } + private static Task<(ErrorCode err, string msg)> StopOCTestForDevice(string deviceUUID, bool triggerSwitch = true) + { + if (!Helpers.IsElevated) return Task.FromResult((ErrorCode.ErrNotAdmin, "No administrator privileges")); + ELPManager.Instance.RestartMiningInstanceIfNeeded(); + var res = OCManager.Instance.StopTest(deviceUUID, triggerSwitch); + return Task.FromResult(res.Result); + } + private static Task<(ErrorCode err, string msg)> ExecuteELPTest(string deviceUUID, ElpProfile elpBundle) + { + StopTestsForDevice(deviceUUID); + ELPManager.Instance.RestartMiningInstanceIfNeeded(); + var res = ELPManager.Instance.ExecuteTest(deviceUUID, elpBundle); + return Task.FromResult(res.Result); + } + private static Task<(ErrorCode err, string msg)> StopELPTestForDevice(string deviceUUID, bool triggerSwitch = true) + { + var res = ELPManager.Instance.StopTest(deviceUUID, triggerSwitch); + ELPManager.Instance.RestartMiningInstanceIfNeeded(); + return Task.FromResult(res.Result); + } + + private static Task<(ErrorCode err, string msg)> ExecuteFanTest(string deviceUUID, FanProfile fanBundle) + { + if (!Helpers.IsElevated) return Task.FromResult((ErrorCode.ErrNotAdmin, "No administrator privileges")); + StopTestsForDevice(deviceUUID); + ELPManager.Instance.RestartMiningInstanceIfNeeded(); + var res = FanManager.Instance.ExecuteTest(deviceUUID, fanBundle); + return Task.FromResult(res.Result); + } + + private static Task<(ErrorCode err, string msg)> StopFanTestForDevice(string deviceUUID, bool triggerSwitch = true) + { + if (!Helpers.IsElevated) return Task.FromResult((ErrorCode.ErrNotAdmin, "No administrator privileges")); + ELPManager.Instance.RestartMiningInstanceIfNeeded(); + var res = FanManager.Instance.StopTest(deviceUUID, triggerSwitch); + return Task.FromResult(res.Result); + } + private static Task SetMutable(MinerSetMutable mutableCmd) + { + if (mutableCmd.Properties != null) + { + var resArray = new List(); + foreach (var property in mutableCmd.Properties) + { + resArray.Add(HandleProperty(property).Result); + } + if (resArray.All(r => r == 0)) return Task.FromResult(string.Empty); + var appendix = resArray.Contains(-3) ? "Have you stopped mining?" : string.Empty; + return Task.FromResult($"SetMutable error ({string.Join(",", resArray)}) {appendix}"); + } + if (mutableCmd.Devices == null) return Task.FromResult(string.Empty); + string result = string.Empty; + foreach (var device in mutableCmd.Devices) + { + if (device.Properties == null) continue; + var deviceTarget = AvailableDevices.Devices.Where(d => d.B64Uuid == device.Id).FirstOrDefault(); + if (deviceTarget == null) continue; + if (deviceTarget.IsMiningBenchingTesting) + { + result += $"({device.Id}):Stop device first\n"; + continue; + } + foreach (var property in device.Properties) + { + HandleProperty(property); + } + } + return Task.FromResult(result); + } + private static Task HandleProperty(object property) + { + if (property is not JToken token) return Task.FromResult(-1); + var genericProperty = token.ToObject(); + var mutable = ActionMutableMap.FindMutableOrNull(genericProperty.PropId);//this is null if per rig + if (mutable == null) return Task.FromResult(-2); + object t = mutable.PropertyType switch + { + Type.String => ParseAndActMutableString(mutable, token), + Type.Int => ParseAndActMutableInt(mutable, token), + Type.Enum => ParseAndActMutableEnum(mutable, token), + Type.Bool => ParseAndActMutableBool(mutable, token), + _ => throw new InvalidOperationException() + }; + if(t is Task res) return Task.FromResult(res.Result); + return Task.FromResult(0); + } + static Task ParseAndActMutableString(OptionalMutableProperty property, JToken command) + { + var mutable = command.ToObject(); + var res = property.ExecuteTask(mutable.Value); + if (res.Result is int resInt) return Task.FromResult(resInt); + return Task.FromResult(-100); + } + static Task ParseAndActMutableInt(OptionalMutableProperty property, JToken command) + { + var mutable = command.ToObject(); + return Task.CompletedTask; + } + static Task ParseAndActMutableEnum(OptionalMutableProperty property, JToken command) + { + var mutable = command.ToObject(); + return Task.CompletedTask; + } + static Task ParseAndActMutableBool(OptionalMutableProperty property, JToken command) + { + var mutable = command.ToObject(); + var res = property.ExecuteTask(mutable.Value); + if (res.Result is int resInt) return Task.FromResult(resInt); + return Task.FromResult(-101); + } #endregion RpcMessages - static private async Task HandleRpcMessage(IReceiveRpcMessage rpcMsg) { bool success = false; @@ -699,12 +1233,26 @@ static private async Task HandleRpcMessage(IReceiveRpcMessage rpcMsg) MiningStop m => await StopMining(m.Device), MiningSetPowerMode m => await SetPowerMode(m.Device, (TDPSimpleType)m.PowerMode), MinerReset m => await MinerReset(m.Level), // rpcAnswer + MinerCallAction m => await CallAction(m), + MinerSetMutable m => await SetMutable(m), _ => throw new RpcException($"RpcMessage operation not supported for method '{rpcMsg.Method}'", ErrorCode.UnableToHandleRpc), }; - - string rpcAnswer = t is string rpcAnws ? rpcAnws : null; - if (t is bool ok) success = ok; - executedCall = new ExecutedCall(rpcMsg.Id, 0, rpcAnswer); + if (t is bool ok) + { + success = ok; + executedCall = new ExecutedCall(rpcMsg.Id, 0, string.Empty); + } + else if (t is (ErrorCode err, string msg)) + { + success = err == ErrorCode.NoError ? true : false; + executedCall = new ExecutedCall(rpcMsg.Id, (int)err, msg); + } + else if (t is string answer) + { + var errorCode = answer == string.Empty ? 0 : -1; + executedCall = new ExecutedCall(rpcMsg.Id, errorCode, answer); + } + else executedCall = new ExecutedCall(rpcMsg.Id, -1, "Failed to execute!"); } catch (RpcException rpcEx) { diff --git a/src/NHMCore/Nhmws/V4/Nhmws4JSONConverter.cs b/src/NHMCore/Nhmws/V4/Nhmws4JSONConverter.cs index b904b5911..768152fd3 100644 --- a/src/NHMCore/Nhmws/V4/Nhmws4JSONConverter.cs +++ b/src/NHMCore/Nhmws/V4/Nhmws4JSONConverter.cs @@ -22,14 +22,14 @@ public override void WriteJson(JsonWriter writer, object value, JsonSerializer s serializer.Serialize(writer, sValue); } - public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) + public override object ReadJson(JsonReader reader, System.Type objectType, object existingValue, JsonSerializer serializer) { throw new NotImplementedException("Unnecessary because CanRead is false. The type will skip the converter."); } public override bool CanRead => false; - public override bool CanConvert(Type objectType) + public override bool CanConvert(System.Type objectType) { return objectType == typeof((int min, int max)) || objectType == typeof((int len, string charset)) diff --git a/src/NHMCore/Nhmws/V4/NhmwsOverheatDetector.cs b/src/NHMCore/Nhmws/V4/NhmwsOverheatDetector.cs new file mode 100644 index 000000000..5b2113234 --- /dev/null +++ b/src/NHMCore/Nhmws/V4/NhmwsOverheatDetector.cs @@ -0,0 +1,175 @@ + +using NHMCore.Notifications; +using System.Collections.Generic; +using System.Linq; + +namespace NHMCore.Nhmws.V4 +{ + internal class NhmwsOverheatDetector + { + public class OverheatInfo + { + public List temperatures { get; set; } = new List(); + public bool sentNotification { get; set; } = false; + } + private readonly int GPU_THR = 75; + private readonly int VRAM_THR = 105; + private readonly int CPU_THR = 90; + private NhmwsOverheatDetector() { } + private static NhmwsOverheatDetector instance = null; + public static NhmwsOverheatDetector Instance + { + get + { + if (instance == null) + { + instance = new NhmwsOverheatDetector(); + } + return instance; + } + } + + private Dictionary GpuTemps = new Dictionary(); + private Dictionary VRAMTemps = new Dictionary(); + private Dictionary CPUTemps = new Dictionary(); + private void InsertOrUpdateGpuTemp(int key, int value) + { + if (GpuTemps.ContainsKey(key)) + { + GpuTemps[key].temperatures.Add(value); + } + else + { + GpuTemps[key] = new OverheatInfo() { temperatures = new List { value } }; + } + if (GpuTemps[key].temperatures.Count > 20) + { + GpuTemps[key].temperatures.RemoveAt(0); + } + } + + private void InsertOrUpdateVRAMTemp(int key, int value) + { + if (VRAMTemps.ContainsKey(key)) + { + VRAMTemps[key].temperatures.Add(value); + } + else + { + VRAMTemps[key] = new OverheatInfo() { temperatures = new List { value } }; + } + if (VRAMTemps[key].temperatures.Count > 20) + { + VRAMTemps[key].temperatures.RemoveAt(0); + } + } + private void InsertOrUpdateCPUTemp(int key, int value) + { + if (CPUTemps.ContainsKey(key)) + { + CPUTemps[key].temperatures.Add(value); + } + else + { + CPUTemps[key] = new OverheatInfo() { temperatures = new List { value } }; + } + if (CPUTemps[key].temperatures.Count > 20) + { + CPUTemps[key].temperatures.RemoveAt(0); + } + } + private bool CheckIfSentForKey(int key) + { + if (GpuTemps.ContainsKey(key) && GpuTemps[key].sentNotification) + { + return true; + } + if (VRAMTemps.ContainsKey(key) && VRAMTemps[key].sentNotification) + { + return true; + } + return false; + } + + private bool CheckIfSentForKeyCPU(int key) + { + if (CPUTemps.ContainsKey(key) && CPUTemps[key].sentNotification) + { + return true; + } + return false; + } + + + public void UpdateCPUTempsAndWarnIfNeeded(int busID, string name, string b64id, int cpuTemp) + { + InsertOrUpdateCPUTemp(busID, cpuTemp); + bool CPUOverheat = false; + if (CPUTemps[busID].temperatures.Count > 2) + { + int first = CPUTemps[busID].temperatures.Last(); + int second = CPUTemps[busID].temperatures.ElementAt(CPUTemps[busID].temperatures.Count - 2); + var alreadySent = CheckIfSentForKey(busID); + CPUOverheat = first > CPU_THR && second > CPU_THR; + if (CPUOverheat && !alreadySent) + { + NHM.Common.Logger.Warn("OVERHEAT DETECTOR", $"CPU OVERHEAT WARNING {name}"); + EventManager.Instance.AddEventDeviceOverheating(name, b64id); + CPUTemps[busID].sentNotification = true; + } + } + if (CPUTemps[busID].temperatures.Count > 2 + && CPUTemps[busID].temperatures.Count > 2 + && !CPUOverheat + && CheckIfSentForKey(busID)) + { + CPUTemps[busID].sentNotification = false; + NHM.Common.Logger.Warn("OVERHEAT DETECTOR", $"CPU not overheating anymore {name}"); + } + } + public void UpdateTempsAndWarnIfNeeded(int busID, string gpu_name, string gpu_id, int gpuTemp, int vramTemp) + { + InsertOrUpdateGpuTemp(busID, gpuTemp); + InsertOrUpdateVRAMTemp(busID, vramTemp); + bool GPUoverheat = false; + bool VRAMoverheat = false; + if (GpuTemps[busID].temperatures.Count > 2) + { + int first = GpuTemps[busID].temperatures.Last(); + int second = GpuTemps[busID].temperatures.ElementAt(GpuTemps[busID].temperatures.Count - 2); + var alreadySent = CheckIfSentForKey(busID); + GPUoverheat = first > GPU_THR && second > GPU_THR; + if (GPUoverheat && !alreadySent) + { + NHM.Common.Logger.Warn("OVERHEAT DETECTOR", $"GPU OVERHEAT WARNING {gpu_name}"); + EventManager.Instance.AddEventDeviceOverheating(gpu_name, gpu_id); + GpuTemps[busID].sentNotification = true; + } + } + if (VRAMTemps[busID].temperatures.Count > 2) + { + int first = VRAMTemps[busID].temperatures.Last(); + int second = VRAMTemps[busID].temperatures.ElementAt(VRAMTemps[busID].temperatures.Count - 2); + var alreadySent = CheckIfSentForKey(busID); + VRAMoverheat = first > VRAM_THR && second > VRAM_THR; + if (VRAMoverheat && !alreadySent) + { + NHM.Common.Logger.Warn("OVERHEAT DETECTOR", $"VRAM OVERHEAT WARNING {gpu_name}"); + EventManager.Instance.AddEventDeviceOverheating(gpu_name, gpu_id); + VRAMTemps[busID].sentNotification = true; + } + } + + if (VRAMTemps[busID].temperatures.Count > 2 + && GpuTemps[busID].temperatures.Count > 2 + && !GPUoverheat + && !VRAMoverheat + && CheckIfSentForKey(busID)) + { + GpuTemps[busID].sentNotification = false; + VRAMTemps[busID].sentNotification = false; + NHM.Common.Logger.Warn("OVERHEAT DETECTOR", $"{gpu_name} not overheating anymore "); + } + } + } +} diff --git a/src/NHMCore/Notifications/AvailableNotifications.cs b/src/NHMCore/Notifications/AvailableNotifications.cs index 802a2eac0..cf55ff496 100644 --- a/src/NHMCore/Notifications/AvailableNotifications.cs +++ b/src/NHMCore/Notifications/AvailableNotifications.cs @@ -154,6 +154,7 @@ public static void CreatePluginUpdateInfo(string pluginName, bool success) public static void CreateMissingMinerBinsInfo(string pluginName) { + EventManager.Instance.AddEventMissingFiles(true); var notification = new Notification(NotificationsType.Info, NotificationsGroup.MissingMinerBins, Tr("Missing miner binaries"), Tr("Some of the {0} binaries are missing from the installation folder. Please make sure that the files are accessible and that your anti-virus is not blocking the application.", pluginName)); notification.Action = AvailableActions.ActionVisitAVHelp(); notification.NotificationUUID = Enum.GetName(typeof(NotificationsGroup), NotificationsGroup.MissingMinerBins); @@ -170,14 +171,16 @@ public static void CreateEnableLargePagesInfo() public static void CreateIncreaseVirtualMemoryInfo() { + EventManager.Instance.AddEventVirtualMemInsufficient(true); var notification = new Notification(NotificationsType.Warning, NotificationsGroup.VirtualMemory, Tr("Increase virtual memory"), Tr("NiceHash Miner recommends increasing virtual memory size so that all algorithms would work fine. Would you like to increase virtual memory?")); notification.Action = AvailableActions.ActionVisitMemoryHelp(); notification.NotificationUUID = Enum.GetName(typeof(NotificationsGroup), NotificationsGroup.VirtualMemory); NotificationsManager.Instance.AddNotificationToList(notification); } - public static void CreateFailedBenchmarksInfo(ComputeDevice device) + public static void CreateFailedBenchmarksInfo(ComputeDevice device, string algo, string plugin) { + EventManager.Instance.AddEventBenchmarkFailed(plugin, algo, device.Name, device.B64Uuid, true); var notification = new Notification(NotificationsType.Info, NotificationsGroup.FailedBenchmarks, Tr("Failed benchmarks"), Tr("Some benchmarks for {0} failed to execute. Check benchmark tab for more info.", device.Name)); notification.Action = AvailableActions.ActionFailedBenchmarksHelp(); notification.NotificationUUID = Enum.GetName(typeof(NotificationsGroup), NotificationsGroup.FailedBenchmarks); @@ -253,18 +256,6 @@ public static void CreateNullChecksumError(string pluginName) NotificationsManager.Instance.AddNotificationToList(notification); } - public static void CreateGamingStarted() - { - var notification = new Notification(NotificationsType.Info, NotificationsGroup.GamingStarted, Tr("Game started, mining is paused"), Tr("NiceHash Miner detected game is running and paused the mining. Mining will resume after the game is closed.")); - notification.NotificationUUID = Enum.GetName(typeof(NotificationsGroup), NotificationsGroup.GamingStarted); - NotificationsManager.Instance.AddNotificationToList(notification); - } - public static void CreateGamingFinished() - { - var notification = new Notification(NotificationsType.Info, NotificationsGroup.GamingFinished, Tr("Game stopped, mining has started"), Tr("NiceHash Miner resumed mining.")); - notification.NotificationUUID = Enum.GetName(typeof(NotificationsGroup), NotificationsGroup.GamingFinished); - NotificationsManager.Instance.AddNotificationToList(notification); - } public static void CreateOutdatedDriverWarningForPlugin(string pluginName, string pluginUUID, List<(DriverVersionLimitType outDatedType, BaseDevice dev, (DriverVersionCheckType checkReturnCode, Version minVersion) driverCheckReturn)> listOfOldDrivers) { string name = Tr("Detected older driver versions") + " (" + pluginName + ")"; @@ -355,5 +346,27 @@ public static void CreateNoOptimalDrivers(Version v) notification.Action = AvailableActions.ActionNoOptimalDrivers(); NotificationsManager.Instance.AddNotificationToList(notification); } + + public static void CreateNotAdminForRigManagement() + { + var notification = new Notification(NotificationsType.Warning, NotificationsGroup.RigManagementElevate, Tr("NHM needs administrator privileges for rig management"), Tr($"If you want to use rig manager for OC/Fan/command settings, you must run NHM as an administrator")); + notification.NotificationUUID = Enum.GetName(typeof(NotificationsGroup), NotificationsGroup.RigManagementElevate); + notification.Action = AvailableActions.ActionRunAsAdmin(); + NotificationsManager.Instance.AddNotificationToList(notification); + } + + public static void CreateMemClockRangeGetFailed(int busID, string gpuName) + { + var notification = new Notification(NotificationsType.Warning, NotificationsGroup.MemClockRangeGetFail, Tr("NHM failed to retrieve memory clock range"), Tr($"NHM failed to retrieve memory clock range. Default range will be used on [{busID}]:{gpuName}.")); + notification.NotificationUUID = Enum.GetName(typeof(NotificationsGroup), NotificationsGroup.MemClockRangeGetFail); + NotificationsManager.Instance.AddNotificationToList(notification); + } + + public static void CreateCoreClockRangeGetFailed(int busID, string gpuName) + { + var notification = new Notification(NotificationsType.Warning, NotificationsGroup.CoreClockRangeGetFail, Tr("NHM failed to retrieve core clock range"), Tr($"NHM failed to retrieve core clock range. Default range will be used on [{busID}]:{gpuName}.")); + notification.NotificationUUID = Enum.GetName(typeof(NotificationsGroup), NotificationsGroup.CoreClockRangeGetFail); + NotificationsManager.Instance.AddNotificationToList(notification); + } } } diff --git a/src/NHMCore/Notifications/EventManager.cs b/src/NHMCore/Notifications/EventManager.cs new file mode 100644 index 000000000..440257ff9 --- /dev/null +++ b/src/NHMCore/Notifications/EventManager.cs @@ -0,0 +1,327 @@ +using Newtonsoft.Json; +using NHM.Common; +using NHMCore.Configs; +using NHMCore.Nhmws.V4; +using NHMCore.Switching; +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Diagnostics; +using System.IO; +using System.Linq; +using System.Reflection.Metadata; +using System.Runtime.CompilerServices; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Threading; +using static NHM.MinerPluginToolkitV1.CommandLine.MinerConfigManager; +using static NHMCore.Utils.GPUProfileManager; + +namespace NHMCore.Notifications +{ + public class EventManager + { + public static EventManager Instance { get; } = new EventManager(); + + private string TAG = "EventManager"; + private readonly object _lock = new object(); + private readonly string _eventFile = Paths.RootPath("logs", "events.json"); + private List _events = new List(); + private readonly int _eventQuota = 20; + private bool _init = false; + public event EventHandler EventAdded; + public event EventHandler EventsLoaded; + + public class Event + { + public int ID; + public DateTime DateTime; + public string Content; + } + public void Init() + { + if (_init) return; + try + { + using StreamReader reader = new(_eventFile); + var text = reader.ReadToEnd(); + var existingRecord = JsonConvert.DeserializeObject>(text); + if (existingRecord != null) Events = existingRecord; + EventsLoaded?.Invoke(null, null); + } + catch (Exception e) + { + Logger.Warn(TAG, e.Message); + } + _init = true; + } + public List Events + { + get + { + lock (_lock) + { + return _events; + } + } + set + { + lock (_lock) + { + _events = value; + } + } + } + private long GetUnixNow() + { + DateTimeOffset timeNow = new DateTimeOffset(DateTime.UtcNow); + var unixTime = timeNow.ToUnixTimeSeconds(); + return unixTime; + } + public void AddEventUnknown(bool send = true) + { + var type = EventType.Unknown; + var worker = CredentialsSettings.Instance.GetCredentials().worker; + var content = JsonConvert.SerializeObject(new NhmwsEventContent { RigName = worker }); + var ev = new NhmwsEvent() { EventID = (int)type, Time = GetUnixNow(), Message = content }; + AddEvent(type, ev, send); + } + public void AddEventRigStarted(bool send = true) + { + var type = EventType.RigStarted; + var worker = CredentialsSettings.Instance.GetCredentials().worker; + var content = JsonConvert.SerializeObject(new NhmwsEventContent { RigName = worker }); + var ev = new NhmwsEvent() { EventID = (int)type, Time = GetUnixNow(), Message = content }; + AddEvent(type, ev, send); + } + public void AddEventRigStopped(bool send = true) + { + var type = EventType.RigStopped; + var worker = CredentialsSettings.Instance.GetCredentials().worker; + var content = JsonConvert.SerializeObject(new NhmwsEventContent { RigName = worker }); + var ev = new NhmwsEvent() { EventID = (int)type, Time = GetUnixNow(), Message = content }; + AddEvent(type, ev, send); + } + public void AddEventDevEnabled(string devName, string devID, bool send = true) + { + var type = EventType.DeviceEnabled; + var worker = CredentialsSettings.Instance.GetCredentials().worker; + var content = JsonConvert.SerializeObject(new NhmwsEventContent { GpuName = devName, RigName = worker }); + var ev = new NhmwsEvent() { EventID = (int)type, Time = GetUnixNow(), Message = content, DeviceID = devID }; + AddEvent(type, ev, send); + } + public void AddEventDevDisabled(string devName, string devID, bool send = true) + { + var type = EventType.DeviceDisabled; + var worker = CredentialsSettings.Instance.GetCredentials().worker; + var content = JsonConvert.SerializeObject(new NhmwsEventContent { GpuName = devName, RigName = worker }); + var ev = new NhmwsEvent() { EventID = (int)type, Time = GetUnixNow(), Message = content, DeviceID = devID }; + AddEvent(type, ev, send); + } + public void AddEventRigRestart(bool send = true) + { + var type = EventType.RigRestart; + var worker = CredentialsSettings.Instance.GetCredentials().worker; + var content = JsonConvert.SerializeObject(new NhmwsEventContent { RigName = worker }); + var ev = new NhmwsEvent() { EventID = (int)type, Time = GetUnixNow(), Message = content }; + AddEvent(type, ev, send); + } + public void AddEventPluginFail(string pluginName, bool send = true) + { + var type = EventType.PluginFailiure; + var worker = CredentialsSettings.Instance.GetCredentials().worker; + var content = JsonConvert.SerializeObject(new NhmwsEventContent { RigName = worker, PluginName = pluginName }); + var ev = new NhmwsEvent() { EventID = (int)type, Time = GetUnixNow(), Message = content }; + AddEvent(type, ev, send); + } + public void AddEventMissingFiles(bool send = true) + { + var type = EventType.MissingFiles; + var worker = CredentialsSettings.Instance.GetCredentials().worker; + var content = JsonConvert.SerializeObject(new NhmwsEventContent { RigName = worker }); + var ev = new NhmwsEvent() { EventID = (int)type, Time = GetUnixNow(), Message = content }; + AddEvent(type, ev, send); + } + public void AddEventVirtualMemInsufficient(bool send = true) + { + var type = EventType.VirtualMemory; + var worker = CredentialsSettings.Instance.GetCredentials().worker; + var content = JsonConvert.SerializeObject(new NhmwsEventContent { RigName = worker }); + var ev = new NhmwsEvent() { EventID = (int)type, Time = GetUnixNow(), Message = content }; + AddEvent(type, ev, send); + } + public void AddEventGeneralCfg(bool send = true) + { + var type = EventType.GeneralConfigErr; + var worker = CredentialsSettings.Instance.GetCredentials().worker; + var content = JsonConvert.SerializeObject(new NhmwsEventContent { RigName = worker }); + var ev = new NhmwsEvent() { EventID = (int)type, Time = GetUnixNow(), Message = content }; + AddEvent(type, ev, send); + } + public void AddEventDriverCrash(bool send = true) + { + var type = EventType.DriverCrash; + var worker = CredentialsSettings.Instance.GetCredentials().worker; + var content = JsonConvert.SerializeObject(new NhmwsEventContent { RigName = worker }); + var ev = new NhmwsEvent() { EventID = (int)type, Time = GetUnixNow(), Message = content }; + AddEvent(type, ev, send); + } + public void AddEventDeviceOverheating(string gpuName, string devID, bool send = true) + { + var type = EventType.DeviceOverheat; + var worker = CredentialsSettings.Instance.GetCredentials().worker; + var content = JsonConvert.SerializeObject(new NhmwsEventContent { RigName = worker, GpuName = gpuName }); + var ev = new NhmwsEvent() { EventID = (int)type, Time = GetUnixNow(), Message = content, DeviceID = devID }; + AddEvent(type, ev, send); + } + public void AddEventMissingDevice(string gpuName, bool send = true) + { + var type = EventType.MissingDevice; + var worker = CredentialsSettings.Instance.GetCredentials().worker; + var content = JsonConvert.SerializeObject(new NhmwsEventContent { RigName = worker, GpuName = gpuName }); + var ev = new NhmwsEvent() { EventID = (int)type, Time = GetUnixNow(), Message = content }; + AddEvent(type, ev, send); + } + public void AddEventSwitch(string gpuName, string devID, string oldAlgo, string newAlgo, bool send = true) + { + if (oldAlgo == newAlgo) return; + var type = EventType.AutoSwitch; + var worker = CredentialsSettings.Instance.GetCredentials().worker; + var content = JsonConvert.SerializeObject(new NhmwsEventContent { AlgoNameOld = oldAlgo, AlgoNameNew = newAlgo, RigName = worker, GpuName = gpuName }); + var ev = new NhmwsEvent() { EventID = (int)type, Time = GetUnixNow(), Message = content, DeviceID = devID }; + AddEvent(type, ev, send); + } + public void AddEventAlgoEnabled(string deviceID, string plugin, List algos, bool send = true) + { + var type = EventType.AlgoEnabled; + var worker = CredentialsSettings.Instance.GetCredentials().worker; + var content = JsonConvert.SerializeObject(new NhmwsEventContent { PluginName = plugin, AlgoNames = algos, RigName = worker }); + var ev = new NhmwsEvent() { EventID = (int)type, DeviceID = deviceID, Time = GetUnixNow(), Message = content }; + AddEvent(type, ev, send); + } + public void AddEventAlgoDisabled(string deviceID, string plugin, List algos, bool send = true) + { + var type = EventType.AlgoDisabled; + var worker = CredentialsSettings.Instance.GetCredentials().worker; + var content = JsonConvert.SerializeObject(new NhmwsEventContent { PluginName = plugin, AlgoNames = algos, RigName = worker }); + var ev = new NhmwsEvent() { EventID = (int)type, DeviceID = deviceID, Time = GetUnixNow(), Message = content }; + AddEvent(type, ev, send); + } + public void AddEventTestOCApplied(string devName, string devID, bool send = true) + { + var type = EventType.TestOCApplied; + var worker = CredentialsSettings.Instance.GetCredentials().worker; + var content = JsonConvert.SerializeObject(new NhmwsEventContent { GpuName = devName, RigName = worker }); + var ev = new NhmwsEvent() { EventID = (int)type, Time = GetUnixNow(), Message = content, DeviceID = devID }; + AddEvent(type, ev, send); + } + public void AddEventTestOCFailed(string devName, string devID, bool send = true) + { + var type = EventType.TestOCFailed; + var worker = CredentialsSettings.Instance.GetCredentials().worker; + var content = JsonConvert.SerializeObject(new NhmwsEventContent { GpuName = devName, RigName = worker }); + var ev = new NhmwsEvent() { EventID = (int)type, Time = GetUnixNow(), Message = content, DeviceID = devID }; + AddEvent(type, ev, send); + } + public void AddEventBundleApplied(string bundle, bool send = true) + { + var type = EventType.BundleApplied; + var worker = CredentialsSettings.Instance.GetCredentials().worker; + var content = JsonConvert.SerializeObject(new NhmwsEventContent { RigName = worker, BundleName = bundle }); + var ev = new NhmwsEvent() { EventID = (int)type, Time = GetUnixNow(), Message = content }; + AddEvent(type, ev, send); + } + public void AddEventBenchmarkFailed(string plugin, string algo, string gpu, string devID, bool send = true) + { + var type = EventType.BenchmarkFailed; + var worker = CredentialsSettings.Instance.GetCredentials().worker; + var content = JsonConvert.SerializeObject(new NhmwsEventContent { RigName = worker, GpuName = gpu, AlgoName = algo, PluginName = plugin }); + var ev = new NhmwsEvent() { EventID = (int)type, Time = GetUnixNow(), Message = content, DeviceID = devID }; + AddEvent(type, ev, send); + } + + public void AddEventDeviceError(string devName, string devID, bool send = true) + { + var type = EventType.DeviceError; + var worker = CredentialsSettings.Instance.GetCredentials().worker; + var content = JsonConvert.SerializeObject(new NhmwsEventContent { RigName = worker, GpuName = devName }); + var ev = new NhmwsEvent() { EventID = (int)type, Time = GetUnixNow(), Message = content, DeviceID = devID }; + AddEvent(type, ev, send); + } + private void AddEvent(EventType type, NhmwsEvent ev, bool send = true) + { + if (!_init) return; + if (!ApplicationStateManager.isInitFinished && + (type == EventType.DeviceEnabled || + type == EventType.DeviceDisabled || + type == EventType.AlgoEnabled || + type == EventType.AlgoDisabled)) + { + return; + } + var now = DateTime.Now; + var eventText = GetEventText(type, ev); + Events.Add(new Event() { ID = (int)type, DateTime = now, Content = eventText}); + if (Events.Count >= _eventQuota) Events.RemoveAt(0); + var events = JsonConvert.SerializeObject(Events, Formatting.Indented); + try + { + using StreamWriter w = File.CreateText(_eventFile); + w.Write(events); + } + catch(Exception ex) + { + Logger.Warn(TAG, $"{ex}"); + } + Logger.Warn(TAG, $"Event occurred: {eventText}"); + EventAdded?.Invoke(null, $"{String.Format("{0:G}", now)} - {eventText}"); +#if NHMWS4 + if (send && MiscSettings.Instance.SendEvents) + { + NHWebSocketV4.SendEvent(ev); + } +#endif + } + + private string GetEventText(EventType type, NhmwsEvent ev) + { + try + { + var additional = new NhmwsEventContent(); + if (ev.Message != null) + { + additional = JsonConvert.DeserializeObject(ev.Message); + } + string ret = type switch + { + EventType.Unknown => "", + EventType.RigStarted => $"Rig started mining.", + EventType.RigStopped => $"Rig stopped mining.", + EventType.DeviceEnabled => $"GPU {additional.GpuName} enabled.", + EventType.DeviceDisabled => $"GPU {additional.GpuName} disabled.", + EventType.RigRestart => $"Rebooting this rig.", + EventType.PluginFailiure => $"{additional.PluginName} failed to run successfully", + EventType.MissingFiles => $"Missing files. Check your antivirus software", + EventType.VirtualMemory => $"Virtual memory is low. Increase it", + EventType.GeneralConfigErr => $"Configuration error. Reinstall is suggested", + EventType.DriverCrash => $"GPU drivers crashed. Lower OC settings or reinstall the drivers", + EventType.MissingDevice => $"Missing some devices!", + EventType.AutoSwitch => $"Algo switch: ({additional.AlgoNameNew})", + EventType.AlgoEnabled => $"Algorithm enabled: {additional.AlgoName}", + EventType.AlgoDisabled => $"Algorithm disabled: {additional.AlgoName}", + EventType.TestOCApplied => $"Test overclock applied on device {additional.GpuName}", + EventType.TestOCFailed => $"Test overclock failed on device {additional.GpuName}", + EventType.BundleApplied => $"Bundle {additional.BundleName} applied.", + EventType.BenchmarkFailed => $"Benchmark combination {additional.PluginName}/{additional.AlgoName} has failed", + _ => "" + }; + return ret; + } + catch(Exception ex) + { + Logger.Error(TAG, "Event text retrieval error"); + } + return "Generic event occurred"; + } + } +} diff --git a/src/NHMCore/Notifications/EventType.cs b/src/NHMCore/Notifications/EventType.cs new file mode 100644 index 000000000..ef5c2c05a --- /dev/null +++ b/src/NHMCore/Notifications/EventType.cs @@ -0,0 +1,35 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace NHMCore.Notifications +{ + public enum EventType + { + Unknown = 0, + RigStarted = 1, + RigStopped = 2, + DeviceEnabled = 3, + DeviceDisabled = 4, + RigRestart = 5, + Unknown1 = 6, + PluginFailiure = 7, + MissingFiles = 8, + VirtualMemory = 9, + GeneralConfigErr = 10, + Unknown2 = 11, + DriverCrash = 12, + DeviceOverheat = 13, + MissingDevice = 14, + AutoSwitch = 15, + AlgoEnabled = 16, + AlgoDisabled = 17, + TestOCApplied = 18, + TestOCFailed = 19, + BundleApplied = 20, + DeviceError = 21, + BenchmarkFailed = 22, + } +} diff --git a/src/NHMCore/Notifications/NotificationsGroup.cs b/src/NHMCore/Notifications/NotificationsGroup.cs index 70f2640c7..97f61ce5d 100644 --- a/src/NHMCore/Notifications/NotificationsGroup.cs +++ b/src/NHMCore/Notifications/NotificationsGroup.cs @@ -44,7 +44,9 @@ public enum NotificationsGroup WrongChecksumDll, MinerRestart, NullChecksum, + [Obsolete] GamingStarted, + [Obsolete] GamingFinished, AdminRunRequired, MotherboardNotCompatible, @@ -53,6 +55,10 @@ public enum NotificationsGroup OptimizationProfilesElevate, RequireAdminForLHR, NoPowerInfo, - NoOptimalDrivers + NoOptimalDrivers, + RigManagementElevate, + OverclockingIsOff, + CoreClockRangeGetFail, + MemClockRangeGetFail } } diff --git a/src/NHMCore/Properties/AssemblyInfo.cs b/src/NHMCore/Properties/AssemblyInfo.cs index 7646afdf5..40d25ec97 100644 --- a/src/NHMCore/Properties/AssemblyInfo.cs +++ b/src/NHMCore/Properties/AssemblyInfo.cs @@ -35,5 +35,5 @@ // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("3.1.0.4")] -[assembly: AssemblyFileVersion("3.1.0.4")] +[assembly: AssemblyVersion("3.1.1.6")] +[assembly: AssemblyFileVersion("3.1.1.6")] diff --git a/src/NHMCore/README.md b/src/NHMCore/README.md index 0bc718330..35b42b545 100644 --- a/src/NHMCore/README.md +++ b/src/NHMCore/README.md @@ -1,7 +1,5 @@ ## Integrate plugins build tags - INTEGRATE_BrokenMiner_PLUGIN // test plugin - INTEGRATE_ExamplePlugin_PLUGIN // test plugin - - INTEGRATE_NBMiner_PLUGIN - INTEGRATE_NanoMiner_PLUGIN - INTEGRATE_LolMiner_PLUGIN - - INTEGRATE_XMRig_PLUGIN diff --git a/src/NHMCore/Schedules/SchedulesManager.cs b/src/NHMCore/Schedules/SchedulesManager.cs index 014d17fb2..35929086d 100644 --- a/src/NHMCore/Schedules/SchedulesManager.cs +++ b/src/NHMCore/Schedules/SchedulesManager.cs @@ -1,6 +1,8 @@ using Newtonsoft.Json; +using Newtonsoft.Json.Linq; using NHM.Common; using NHMCore.Configs; +using NHMCore.Nhmws.V4; using System; using System.Collections.Generic; using System.Collections.ObjectModel; @@ -30,11 +32,19 @@ public ObservableCollection Schedules return _schedules; } } + set + { + lock (_lock) + { + _schedules = value; + } + } } public void Init() { - if (File.Exists(Paths.ConfigsPath("Schedule.json"))){ + if (File.Exists(Paths.ConfigsPath("Schedule.json"))) + { var schedules = JsonConvert.DeserializeObject>(File.ReadAllText(Paths.ConfigsPath("Schedule.json"))); if (schedules != null && schedules.Any(s => s.Days.Any(d => d.Value == true))) { @@ -51,16 +61,153 @@ public void Init() public void AddScheduleToList(Schedule schedule) { - _schedules.Add(schedule); + Schedules.Add(schedule); OnPropertyChanged(nameof(Schedules)); ConfigManager.ScheduleConfigFileCommit(); + Task.Run(async () => await NHWebSocketV4.UpdateMinerStatus()); } public void DeleteScheduleFromList(Schedule schedule) { - _schedules.Remove(schedule); + Schedules.Remove(schedule); + OnPropertyChanged(nameof(Schedules)); + ConfigManager.ScheduleConfigFileCommit(); + Task.Run(async () => await NHWebSocketV4.UpdateMinerStatus()); + } + + public void ClearScheduleList() + { + Schedules.Clear(); OnPropertyChanged(nameof(Schedules)); ConfigManager.ScheduleConfigFileCommit(); + Task.Run(async () => await NHWebSocketV4.UpdateMinerStatus()); + } + + public string ScheduleToJSON() + { + var schedules = new SchedulesWS4(); + schedules.enabled = MiningSettings.Instance.UseScheduler; + foreach (var slot in Schedules) + { + var from = TimeSpan.Parse(DateTime.Parse(slot.From).ToUniversalTime().ToString("HH:mm")); + var to = TimeSpan.Parse(DateTime.Parse(slot.To).ToUniversalTime().ToString("HH:mm")); + var days = new List(); + int counter = 1; + foreach (var (_, enabled) in slot.DaysFrom) + { + if (enabled) days.Add(counter % 7); + counter++; + } + //if (days.Count == 7) days.Clear();//if empty it assumes all days are selected + days.Sort(); + var newSlot = new List { + from.Hours, + from.Minutes, + to.Hours, + to.Minutes, + days, + }; + schedules.slots.Add(newSlot); + } + var ret = JsonConvert.SerializeObject(schedules); + return ret; + } + + public (bool enabled, List schedules) ScheduleFromJSON(string schedule) + { + List ret = new List(); + var schedules = JsonConvert.DeserializeObject(schedule); + if (schedules == null || schedules.slots == null || schedules.slots.Count <= 0) return (false, null); + foreach (var slot in schedules.slots) + { + if (slot.Count != 5) continue; + if (slot[0] is long fromH && + slot[1] is long fromM && + slot[2] is long toH && + slot[3] is long toM && + slot[4] is JArray days) + { + var daysConverted = days.ToObject>(); + if (daysConverted.Count == 0) daysConverted.AddRange(new List { 0, 1, 2, 3, 4, 5, 6 }); + var formattedFromH = fromH <= 9 ? $"0{fromH}" : fromH.ToString(); + var formattedFromM = fromM <= 9 ? $"0{fromM}" : fromM.ToString(); + var formattedToH = toH <= 9 ? $"0{toH}" : toH.ToString(); + var formattedToM = toM <= 9 ? $"0{toM}" : toM.ToString(); + ret.Add(ScheduleToLocalFormat($"{formattedFromH}:{formattedFromM}", $"{formattedToH}:{formattedToM}", daysConverted)); + } + } + return (schedules.enabled, ret); + } + + public Schedule ScheduleToLocalFormat(string schedulerFrom, string schedulerTo, List days) + { + bool cboxMon = days.Contains(1); + bool cboxTue = days.Contains(2); + bool cboxWed = days.Contains(3); + bool cboxThu = days.Contains(4); + bool cboxFri = days.Contains(5); + bool cboxSat = days.Contains(6); + bool cboxSun = days.Contains(0); + + var isNextDay = Convert.ToDateTime(schedulerTo) < Convert.ToDateTime(schedulerFrom); + if (isNextDay) + { + var schedule = new Schedule() + { + From = schedulerFrom, + To = schedulerTo, + DaysFrom = new Dictionary() + { + ["Monday"] = cboxMon, + ["Tuesday"] = cboxTue, + ["Wednesday"] = cboxWed, + ["Thursday"] = cboxThu, + ["Friday"] = cboxFri, + ["Saturday"] = cboxSat, + ["Sunday"] = cboxSun, + }, + DaysTo = new Dictionary() + { + ["Monday"] = cboxSun, + ["Tuesday"] = cboxMon, + ["Wednesday"] = cboxTue, + ["Thursday"] = cboxWed, + ["Friday"] = cboxThu, + ["Saturday"] = cboxFri, + ["Sunday"] = cboxSat, + } + }; + return schedule; + } + else + { + var schedule = new Schedule() + { + From = schedulerFrom, + To = schedulerTo, + DaysFrom = new Dictionary() + { + ["Monday"] = cboxMon, + ["Tuesday"] = cboxTue, + ["Wednesday"] = cboxWed, + ["Thursday"] = cboxThu, + ["Friday"] = cboxFri, + ["Saturday"] = cboxSat, + ["Sunday"] = cboxSun, + }, + DaysTo = new Dictionary() + { + ["Monday"] = cboxMon, + ["Tuesday"] = cboxTue, + ["Wednesday"] = cboxWed, + ["Thursday"] = cboxThu, + ["Friday"] = cboxFri, + ["Saturday"] = cboxSat, + ["Sunday"] = cboxSun, + } + }; + return schedule; + } } } } diff --git a/src/NHMCore/Switching/AlgorithmSwitchingManager.cs b/src/NHMCore/Switching/AlgorithmSwitchingManager.cs index 3a9f8162a..a35b6598b 100644 --- a/src/NHMCore/Switching/AlgorithmSwitchingManager.cs +++ b/src/NHMCore/Switching/AlgorithmSwitchingManager.cs @@ -27,7 +27,7 @@ public class AlgorithmSwitchingManager private int _ticksForStable; private int _ticksForUnstable; - private double _smaCheckTime = 1; + private double _smaCheckTime = 5; // Simplify accessing config objects public static Interval StableRange => SwitchSettings.Instance.SwitchSmaTicksStable; diff --git a/src/NHMCore/Utils/Helpers.cs b/src/NHMCore/Utils/Helpers.cs index 368e12180..c412996d7 100644 --- a/src/NHMCore/Utils/Helpers.cs +++ b/src/NHMCore/Utils/Helpers.cs @@ -1,12 +1,14 @@ using Microsoft.Win32; using NHM.Common; using NHM.Common.Enums; +using NHMCore.Configs; using System; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.IO; using System.Linq; +using System.Net; using System.Net.Http; using System.Security.Principal; using System.Threading.Tasks; @@ -19,6 +21,7 @@ public class Helpers : PInvokeHelpers public static bool Is64BitOperatingSystem = Is64BitProcess || InternalCheckIsWow64(); public static readonly bool IsElevated; + private static int StartEpoch = 0; static Helpers() @@ -26,6 +29,7 @@ static Helpers() using var identity = WindowsIdentity.GetCurrent(); var principal = new WindowsPrincipal(identity); IsElevated = principal.IsInRole(WindowsBuiltInRole.Administrator); + StartEpoch = (int)(DateTime.UtcNow - new DateTime(1970, 1, 1)).TotalSeconds; } public static bool InternalCheckIsWow64() @@ -282,5 +286,49 @@ private static async Task UploadLogArchive(string tmpArchivePath, string u return false; } } + public static int GetElapsedSecondsSinceStart() + { + var elapsed = (int)(DateTime.UtcNow - new DateTime(1970, 1, 1)).TotalSeconds - StartEpoch; + return elapsed; + } + public static IPAddress GetLocalIP() + { + return IPAddress.Parse(Dns.GetHostEntry(Dns.GetHostName()).AddressList[1].ToString()) ?? IPAddress.None; + } + + public static void CreateRunOnStartupBackup() + { + try + { + var backupPath = Paths.ConfigsPath(".runOnStartup.txt"); + using (var writer = new StreamWriter(backupPath)) + { + writer.Write(MiscSettings.Instance.RunAtStartup.ToString()); + } + + Logger.Info("RunOnStartupBackup", $"Created RunOnStartupBackup file"); + } + catch (Exception ex) + { + Logger.Error("RunOnStartupBackup", $"Unable to create RunOnStartupBackup file: {ex.Message}"); + } + } + + public static bool GetRunOnStartupBackupValue() + { + try + { + var backupPath = Paths.ConfigsPath(".runOnStartup.txt"); + using (var reader = new StreamReader(backupPath)) + { + return Convert.ToBoolean(reader.ReadToEnd()); + } + } + catch (Exception ex) + { + Logger.Error("GetRunOnStartupBackup", $"Unable to read RunOnStartupBackup file: {ex.Message}"); + return false; + } + } } } diff --git a/src/NHMCore/Utils/SystemSpecs.cs b/src/NHMCore/Utils/SystemSpecs.cs index d2b3f11c3..7902ae86d 100644 --- a/src/NHMCore/Utils/SystemSpecs.cs +++ b/src/NHMCore/Utils/SystemSpecs.cs @@ -83,10 +83,10 @@ public static void QueryWin32_OperatingSystemDataAndLog() Logger.Info(Tag, $"PageFileSize = {PageFileSize}, {PageFileSize / 1024} MB"); } - public static bool CheckRam(int gpuCount, ulong nvRamSum, ulong amdRamSum) + public static bool CheckRam(int gpuCount, ulong nvRamSum, ulong amdRamSum, ulong intelRamSum) { // Make gpu ram needed not larger than 4GB per GPU - var totalGpuRam = Math.Min((ulong)((nvRamSum + amdRamSum) * 0.6 / 1024), + var totalGpuRam = Math.Min((ulong)((nvRamSum + amdRamSum + intelRamSum) * 0.6 / 1024), (ulong)gpuCount * 4 * 1024 * 1024); var totalSysRam = FreePhysicalMemory + FreeVirtualMemory; diff --git a/src/NiceHashMiner/App.xaml b/src/NiceHashMiner/App.xaml index a11f39ac5..d09ab8020 100644 --- a/src/NiceHashMiner/App.xaml +++ b/src/NiceHashMiner/App.xaml @@ -25,7 +25,7 @@ - + @@ -81,7 +81,7 @@ - + - - - - - - - - diff --git a/src/NiceHashMiner/Resources/Xaml/Tooltips.xaml b/src/NiceHashMiner/Resources/Xaml/Tooltips.xaml index 1b612a5a4..95506ab51 100644 --- a/src/NiceHashMiner/Resources/Xaml/Tooltips.xaml +++ b/src/NiceHashMiner/Resources/Xaml/Tooltips.xaml @@ -43,7 +43,6 @@ Amount of time (in milliseconds) that NiceHash Miner will wait before restarting the miner. Set starting port number from which miner API Bind ports will be set for communication. API query interval for ccminer, sgminer cpuminer and ethminer. - NiceHash Miner will detect when the game is started and will pause mining. Once the game is closed, mining will resume. Use NiceHash Mobile app and scan this QR code to add this rig to your Rig Manager automatically. diff --git a/src/NiceHashMiner/ViewModels/BenchmarkViewModel.cs b/src/NiceHashMiner/ViewModels/BenchmarkViewModel.cs index 76f93c7e4..d2cdd8951 100644 --- a/src/NiceHashMiner/ViewModels/BenchmarkViewModel.cs +++ b/src/NiceHashMiner/ViewModels/BenchmarkViewModel.cs @@ -29,7 +29,9 @@ public BenchmarkPerformanceType SelectedBenchmarkType public bool CanStartBenchmaring => BenchmarkManagerState.Instance.HasBenchmarkWork && BenchmarkManagerState.Instance.CanStartBenchmarking; public bool CanStart => BenchmarkManagerState.Instance.CanStart; - + + public bool StartEnabled => BenchmarkManagerState.Instance.StartEnabled; + public bool CanStartAndButtonEnabled => CanStart && StartEnabled; public BenchmarkViewModel() { BenchmarkManagerState.Instance.PropertyChanged += Instance_PropertyChanged; @@ -39,6 +41,8 @@ public BenchmarkViewModel() OnPropertyChanged(nameof(CanStart)); OnPropertyChanged(nameof(CanStartBenchmaring)); OnPropertyChanged(nameof(SelectedBenchmarkType)); + OnPropertyChanged(nameof(StartEnabled)); + OnPropertyChanged(nameof(CanStartAndButtonEnabled)); } private void Instance_PropertyChanged(object sender, PropertyChangedEventArgs e) @@ -46,21 +50,29 @@ private void Instance_PropertyChanged(object sender, PropertyChangedEventArgs e) if (e.PropertyName == nameof(BenchmarkManagerState.CanStart)) { OnPropertyChanged(nameof(CanStart)); + OnPropertyChanged(nameof(CanStartAndButtonEnabled)); } if (e.PropertyName == nameof(BenchmarkManagerState.HasBenchmarkWork) || e.PropertyName == nameof(BenchmarkManagerState.CanStartBenchmarking)) { OnPropertyChanged(nameof(HasBenchmarkWork)); OnPropertyChanged(nameof(CanStartBenchmaring)); + OnPropertyChanged(nameof(CanStartAndButtonEnabled)); } if (e.PropertyName == nameof(BenchmarkManagerState.BenchmarksPending)) { OnPropertyChanged(nameof(BenchmarksPending)); OnPropertyChanged(nameof(BenchmarksPendingStr)); + OnPropertyChanged(nameof(CanStartAndButtonEnabled)); } if (e.PropertyName == nameof(BenchmarkManagerState.SelectedBenchmarkType)) { OnPropertyChanged(nameof(SelectedBenchmarkType)); } + if(e.PropertyName == nameof(BenchmarkManagerState.StartEnabled)) + { + OnPropertyChanged(nameof(StartEnabled)); + OnPropertyChanged(nameof(CanStartAndButtonEnabled)); + } } public void StartBenchmark() diff --git a/src/NiceHashMiner/ViewModels/MainVM.cs b/src/NiceHashMiner/ViewModels/MainVM.cs index 2c73f9fd8..2d9f11777 100644 --- a/src/NiceHashMiner/ViewModels/MainVM.cs +++ b/src/NiceHashMiner/ViewModels/MainVM.cs @@ -8,6 +8,7 @@ using NHMCore.ApplicationState; using NHMCore.Configs; using NHMCore.Configs.ELPDataModels; +using NHMCore.Configs.Managers; using NHMCore.Mining; using NHMCore.Mining.IdleChecking; using NHMCore.Mining.MiningStats; @@ -128,10 +129,12 @@ public int MinerCount /// Elements of that represent actual devices (i.e. not total rows) and /// are in the mining state. /// - private IEnumerable WorkingMiningDevs => - MiningDevs?.OfType().Where(d => d.Dev.State == DeviceState.Mining); - +#if NHMWS4 + private IEnumerable WorkingMiningDevs => MiningDevs?.OfType().Where(d => d.Dev.State == DeviceState.Mining || d.Dev.State == DeviceState.Testing); +#else + private IEnumerable WorkingMiningDevs => MiningDevs?.OfType().Where(d => d.Dev.State == DeviceState.Mining); +#endif #region settingsLists @@ -141,14 +144,14 @@ public int MinerCount public IReadOnlyList ThemeOptions => _themeList; private List _themeList = new List { "Light", "Dark" }; - #endregion settingsLists +#endregion settingsLists public string PerDeviceDisplayString => $"/ {_devices?.Count() ?? 0}"; public DashboardViewModel Dashboard { get; } = new DashboardViewModel(); - #region Exposed settings +#region Exposed settings public BalanceAndExchangeRates BalanceAndExchangeRates => BalanceAndExchangeRates.Instance; public MiningState MiningState => MiningState.Instance; public CredentialsSettings CredentialsSettings => CredentialsSettings.Instance; @@ -170,10 +173,10 @@ public int MinerCount public GPUProfileManager GPUProfileManager => GPUProfileManager.Instance; public SchedulesManager SchedulesManager => SchedulesManager.Instance; public ELPManager ELPManager => ELPManager.Instance; - #endregion Exposed settings +#endregion Exposed settings - #region HelpNotifications +#region HelpNotifications private ObservableCollection _helpNotificationList; public ObservableCollection HelpNotificationList { @@ -195,13 +198,13 @@ private void RefreshNotifications_PropertyChanged(object sender, System.Componen } } - #endregion HelpNotifications +#endregion HelpNotifications // TODO these versions here will not work public string LocalVersion => VersionState.Instance.ProgramVersion.ToString(); public string OnlineVersion => VersionState.Instance.OnlineVersion?.ToString() ?? "N/A"; - #region Currency-related properties +#region Currency-related properties // TODO this section getting rather large, maybe good idea to break out into own class @@ -255,9 +258,9 @@ public string GlobalRate public string MinimumProfitString => $"Minimum Profit ({BalanceAndExchangeRates.Instance.SelectedFiatCurrency}/day)"; - #endregion +#endregion - #region MinerPlugins +#region MinerPlugins private ObservableCollection _plugins; public ObservableCollection Plugins { @@ -315,7 +318,7 @@ private void MinerPluginsManagerState_PropertyChanged(object sender, System.Comp } } - #endregion MinerPlugins +#endregion MinerPlugins public BenchmarkViewModel BenchmarkSettings { get; } = new BenchmarkViewModel(); @@ -486,6 +489,9 @@ public async Task InitializeNhm(IStartupLoader sl) ELPManager.ELPReiteration += ELPReScan; ReadELPConfigsOrCreateIfMissing(); ELPManager.IterateSubModelsAndConstructELPs(); +#if NHMWS4 + BundleManager.Init(); //must be called after elpmanager stuff +#endif if (MiningSettings.Instance.AutoStartMining) await StartMining(); } diff --git a/src/NiceHashMiner/ViewModels/Models/DeviceData.cs b/src/NiceHashMiner/ViewModels/Models/DeviceData.cs index d571b3170..929d3bdaa 100644 --- a/src/NiceHashMiner/ViewModels/Models/DeviceData.cs +++ b/src/NiceHashMiner/ViewModels/Models/DeviceData.cs @@ -6,6 +6,7 @@ using NHMCore.Configs; using NHMCore.Mining; using NHMCore.Mining.MiningStats; +using NHMCore.Nhmws.V4; using NHMCore.Utils; using System; using System.Collections.Generic; @@ -76,15 +77,24 @@ public bool AllAgorithmsEnabled { foreach (var algo in Dev.AlgorithmSettings) { - algo.Enabled = value; + //algo.Enabled = value; + algo.SetEnabled(value); } OnPropertyChanged(); + ConfigManager.CommitBenchmarksForDevice(Dev); + Task.Run(async () => await NHWebSocketV4.UpdateMinerStatus()); } } +#if NHMWS4 + public bool CanClearAllSpeeds => !(Dev.State == DeviceState.Benchmarking || Dev.State == DeviceState.Mining || Dev.State == DeviceState.Testing); + public bool CanStopBenchmark => Dev.Enabled && (Dev.State == DeviceState.Benchmarking || Dev.State == DeviceState.Testing); + public bool CanStopMining => Dev.Enabled && (Dev.State == DeviceState.Mining || Dev.State == DeviceState.Testing);//problem? if testing running from bench or from mining +#else public bool CanClearAllSpeeds => !(Dev.State == DeviceState.Benchmarking || Dev.State == DeviceState.Mining); public bool CanStopBenchmark => Dev.Enabled && Dev.State == DeviceState.Benchmarking; public bool CanStopMining => Dev.Enabled && Dev.State == DeviceState.Mining; +#endif public bool CanCopyFromOtherDevices => AvailableDevices.Devices.Count(dev => dev.DeviceType == Dev.DeviceType) > 1 && CanClearAllSpeeds; @@ -92,7 +102,11 @@ public bool AllAgorithmsEnabled // TODO Pending state and error states public bool CanStart => Dev.Enabled && Dev.State == DeviceState.Stopped; +#if NHMWS4 + public bool CanStop => Dev.Enabled && (Dev.State == DeviceState.Benchmarking || Dev.State == DeviceState.Mining || Dev.State == DeviceState.Testing); +#else public bool CanStop => Dev.Enabled && (Dev.State == DeviceState.Benchmarking || Dev.State == DeviceState.Mining); +#endif public string AlgoOptions { @@ -132,7 +146,11 @@ public string ButtonLabel { buttonLabel = "Start"; } +#if NHMWS4 + else if (Dev.State == DeviceState.Mining || Dev.State == DeviceState.Benchmarking || Dev.State == DeviceState.Testing) +#else else if (Dev.State == DeviceState.Mining || Dev.State == DeviceState.Benchmarking) +#endif { buttonLabel = "Stop"; } @@ -256,12 +274,16 @@ private void DevOnPropertyChanged(object sender, PropertyChangedEventArgs e) public float Temp { get; private set; } = -1; public int _fanSpeed = -1; + + private bool _isRPM = false; + public string FanSpeed { get { if (_fanSpeed < 0) return MISSING_INFO; - return $"{_fanSpeed}%"; + if(!_isRPM) return $"{_fanSpeed}%"; + return $"{_fanSpeed}RPM"; } } @@ -269,7 +291,8 @@ public void RefreshDiag() { Load = Dev.Load; Temp = Dev.Temp; - _fanSpeed = Dev.FanSpeed; + _isRPM = -1 == Dev.FanSpeed; + _fanSpeed = _isRPM ? Dev.FanSpeedRPM : Dev.FanSpeed; OnPropertyChanged(nameof(Load)); OnPropertyChanged(nameof(Temp)); OnPropertyChanged(nameof(FanSpeed)); @@ -301,8 +324,11 @@ public void EnableBenchmarkedOnly() { foreach (var a in Dev.AlgorithmSettings) { - a.Enabled = a.HasBenchmark; + a.SetEnabled(a.HasBenchmark); } + OnPropertyChanged(); + ConfigManager.CommitBenchmarksForDevice(Dev); + Task.Run(async () => await NHWebSocketV4.UpdateMinerStatus()); } #region AlgorithmSettingsCollection SORTING @@ -374,7 +400,7 @@ private void OrderAlgorithms() } - #endregion AlgorithmSettingsCollection SORTING +#endregion AlgorithmSettingsCollection SORTING public static implicit operator DeviceData(ComputeDevice dev) { diff --git a/src/NiceHashMiner/ViewModels/Models/DeviceDataTDP.cs b/src/NiceHashMiner/ViewModels/Models/DeviceDataTDP.cs index e35bdaa27..f8a57d947 100644 --- a/src/NiceHashMiner/ViewModels/Models/DeviceDataTDP.cs +++ b/src/NiceHashMiner/ViewModels/Models/DeviceDataTDP.cs @@ -26,7 +26,7 @@ public void SetSimple(TDPSimpleType type) public void SetPercentage(double value) { var perc = value / 100.0; - TDPSet(_tdpMon.SetTDPPercentage(perc)); + TDPSet(_tdpMon.SetTDP(perc)); } public DeviceDataTDP(ComputeDevice dev) diff --git a/src/NiceHashMiner/ViewModels/Plugins/PluginEntryVM.cs b/src/NiceHashMiner/ViewModels/Plugins/PluginEntryVM.cs index 8091eff3b..98e4ce50c 100644 --- a/src/NiceHashMiner/ViewModels/Plugins/PluginEntryVM.cs +++ b/src/NiceHashMiner/ViewModels/Plugins/PluginEntryVM.cs @@ -1,6 +1,6 @@ using NHM.Common; +using NHMCore.Configs.Managers; using NHMCore.Mining.Plugins; -using NHMCore.Utils; using NiceHashMiner.ViewModels.Models; using System; using System.Collections.Generic; diff --git a/src/NiceHashMiner/Views/Benchmark/ComputeDeviceItem/DeviceStatusVisibilityConverter.cs b/src/NiceHashMiner/Views/Benchmark/ComputeDeviceItem/DeviceStatusVisibilityConverter.cs index 854662002..ed6ae139c 100644 --- a/src/NiceHashMiner/Views/Benchmark/ComputeDeviceItem/DeviceStatusVisibilityConverter.cs +++ b/src/NiceHashMiner/Views/Benchmark/ComputeDeviceItem/DeviceStatusVisibilityConverter.cs @@ -12,7 +12,11 @@ public object Convert(object value, Type targetType, object parameter, CultureIn { if (value is DeviceState state) { +#if NHMWS4 + if (state == DeviceState.Benchmarking || state == DeviceState.Mining || state == DeviceState.Testing) +#else if (state == DeviceState.Benchmarking || state == DeviceState.Mining) +#endif { return Visibility.Hidden; } diff --git a/src/NiceHashMiner/Views/Dashboard/Dashboard.xaml b/src/NiceHashMiner/Views/Dashboard/Dashboard.xaml index 26953b4c7..80feec4a8 100644 --- a/src/NiceHashMiner/Views/Dashboard/Dashboard.xaml +++ b/src/NiceHashMiner/Views/Dashboard/Dashboard.xaml @@ -142,7 +142,7 @@ - How to create a Mining Address? @@ -131,16 +130,6 @@ -