private static bool CheckIfShouldMine(double currentProfit, bool log = true) { var isProfitable = CheckIfProfitable(currentProfit, log); ApplicationStateManager.SetProfitableState(isProfitable); ApplicationStateManager.DisplayNoInternetConnection(!_isConnectedToInternet); if (!_isConnectedToInternet && log) { Logger.Info(Tag, $"No internet connection! Not able to mine."); } AvailableNotifications.CreateNotProfitableInfo(isProfitable); // if profitable and connected to internet mine var shouldMine = isProfitable && _isConnectedToInternet; return(shouldMine); }
private async Task Benchmark() { bool showFailed = false; bool startMining = false; _stopBenchmark = CancellationTokenSource.CreateLinkedTokenSource(ApplicationStateManager.ExitApplication.Token); try { foreach (var a in _algorithms) { a.SetBenchmarkPending(); } var benchAlgos = new Queue <AlgorithmContainer>(_algorithms); //BenchmarkingHandlers.TryAdd(Device, this); // whole benchmark scope var commandTask = GetCommand(_stopBenchmark.Token); // Until container is not empty while (benchAlgos.Any() && !_stopBenchmark.IsCancellationRequested) { // per algo benchmark scope bool?benchmarkSuccess = null; _stopCurrentAlgorithmBenchmark = CancellationTokenSource.CreateLinkedTokenSource(_stopBenchmark.Token); try { var nextAlgo = benchAlgos.Dequeue(); var benchmark = BenchmarkAlgorithm(nextAlgo, _stopCurrentAlgorithmBenchmark.Token); var firstFinished = await Task.WhenAny(new Task <object>[] { commandTask, benchmark }); var ret = await firstFinished; if (ret is IReadOnlyList <AlgorithmContainer> updatedAlgorithms) { commandTask = GetCommand(_stopBenchmark.Token); var stop = _algorithms.Except(updatedAlgorithms).Any(algo => algo == nextAlgo); var restAlgorithms = updatedAlgorithms.Where(algo => algo != nextAlgo).ToArray(); // update Algorithms _algorithms = restAlgorithms; foreach (var a in _algorithms) { a.SetBenchmarkPending(); } // updated benchAlgos = new Queue <AlgorithmContainer>(_algorithms); if (stop) { // THIS Throws _stopCurrentAlgorithmBenchmark.Cancel(); } else { // wait for the current benchmark to finish ret = await benchmark; } } if (ret is bool success) { benchmarkSuccess = success; } // this will drain the container await Task.Delay(MiningSettings.Instance.MinerRestartDelayMS, _stopCurrentAlgorithmBenchmark.Token); } catch (TaskCanceledException e) { Logger.Debug("BenchmarkingDevice", $"TaskCanceledException occurred in benchmark task: {e.Message}"); } catch (Exception e) { Logger.Error("BenchmarkingDevice", $"Exception occurred in benchmark task: {e.Message}"); } finally { _stopCurrentAlgorithmBenchmark.Dispose(); if (!_stopCurrentAlgorithmBenchmark.IsCancellationRequested && benchmarkSuccess.HasValue && !benchmarkSuccess.Value) { showFailed = true; } } } startMining = !_stopBenchmark.IsCancellationRequested; // clear what we didn't benchmark while (benchAlgos.Any()) { var nextAlgo = benchAlgos.Dequeue(); nextAlgo.ClearBenchmarkPending(); } if (showFailed) { AvailableNotifications.CreateFailedBenchmarksInfo(Device); } } catch (Exception ex) { Logger.Error("BenchmarkingDevice2", $"Exception occurred in benchmark task: {ex.Message}"); } finally { _stopBenchmark.Dispose(); if (startMining) { _ = MiningManager.StartDevice(Device); // important do not await } else { Device.State = DeviceState.Stopped; } } }
private async Task RunMinerWatchDogLoop(TaskCompletionSource <object> tsc, CancellationToken stop, string username) { // if we fail 3 times in a row under certain conditions mark on of them const int maxRestartCount = 3; int restartCount = 0; const int minRestartTimeInSeconds = 240; try { var firstStart = true; using (_endMiner = new CancellationTokenSource()) using (var linkedEndMiner = CancellationTokenSource.CreateLinkedTokenSource(stop, _endMiner.Token)) { Logger.Info(MinerTag(), $"Starting miner watchdog task"); while (!linkedEndMiner.IsCancellationRequested && (restartCount < maxRestartCount)) { var startTime = DateTime.UtcNow; try { if (!firstStart) { Logger.Info(MinerTag(), $"Restart Mining in {MiningSettings.Instance.MinerRestartDelayMS}ms"); AvailableNotifications.CreateRestartedMinerInfo(DateTime.UtcNow.ToLocalTime(), _plugin.Name); await TaskHelpers.TryDelay(MiningSettings.Instance.MinerRestartDelayMS, linkedEndMiner.Token); } var result = await StartAsync(linkedEndMiner.Token, username); if (firstStart) { firstStart = false; tsc.SetResult(result); } if (result is bool ok && ok) { var runningMinerTask = _miner.MinerProcessTask; if (_algos.Any(a => a.AlgorithmName == "RandomXmonero")) { _ = XMRingStartedWaitTime(runningMinerTask, linkedEndMiner.Token); } _ = MinerStatsLoop(runningMinerTask, linkedEndMiner.Token); await runningMinerTask; // TODO log something here Logger.Info(MinerTag(), $"Running Miner Task Completed"); } else { // TODO check if the miner file is missing or locked and blacklist the algorithm for a certain period of time Logger.Error(MinerTag(), $"StartAsync result: {result}"); } } catch (TaskCanceledException e) { Logger.Debug(MinerTag(), $"RunMinerWatchDogLoop TaskCanceledException: {e.Message}"); return; } catch (Exception e) { Logger.Error(MinerTag(), $"RunMinerWatchDogLoop Exception: {e.Message}"); } finally { var endTime = DateTime.UtcNow; var elapsedSeconds = (endTime - startTime).TotalSeconds - (MiningSettings.Instance.MinerRestartDelayMS / 1000); if (elapsedSeconds < minRestartTimeInSeconds) { restartCount++; } else { restartCount = 0; } if (restartCount >= maxRestartCount) { var firstAlgo = _algos.FirstOrDefault(); Random randWait = new Random(); firstAlgo.IgnoreUntil = DateTime.UtcNow.AddMinutes(randWait.Next(20, 30)); await MiningManager.MinerRestartLoopNotify(); } } }
//private static async Task ResumeAllMiners() //{ // foreach (var groupMiner in _runningMiners.Values) // { // await groupMiner.StartMinerTask(stopMiningManager, _username); // } // // TODO resume devices to Mining state //} 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; } else if (command is UsernameChangedCommand usernameChangedCommand) { _username = usernameChangedCommand.username; } else if (command is PauseMiningWhenGamingModeSettingsChangedCommand pauseMiningWhenGamingModeSettingsChangedCommand) { _isPauseMiningWhenGamingEnabled = pauseMiningWhenGamingModeSettingsChangedCommand.isPauseMiningWhenGamingModeSettingEnabled; if (!_isPauseMiningWhenGamingEnabled) { var dev = AvailableDevices.Devices.FirstOrDefault(d => d.IsGaming == true); if (dev != null) { dev.IsGaming = false; } } } else if (command is IsSteamGameRunningChangedCommand isSteamGameRunningChangedCommand) { _isGameRunning = isSteamGameRunningChangedCommand.isSteamGameRunning; } 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) { newSelectedDev.PauseMiningWhenGamingMode = true; ConfigManager.DeviceConfigFileCommit(newSelectedDev); } // set previous selected gpu to false var oldSelectedDev = AvailableDevices.Devices.FirstOrDefault(d => d.Uuid != _deviceToPauseUuid && d.PauseMiningWhenGamingMode); if (oldSelectedDev != null) { oldSelectedDev.PauseMiningWhenGamingMode = false; ConfigManager.DeviceConfigFileCommit(oldSelectedDev); } } bool isRestartMinersCommand(Command command) => command switch { UsernameChangedCommand => true, UseOptimizationProfilesChangedCommand => true, DNSQChangedCommand => true, SSLMiningChangedCommand => true, _ => false, }; // here we do the deciding // to mine we need to have the username mining location set and ofc device to mine with if (_username == null || _normalizedProfits == null) { if (_username == null) { Logger.Error(Tag, "_username is null"); } if (_normalizedProfits == null) { Logger.Error(Tag, "_normalizedProfits is null"); } await PauseAllMiners(); } else if (isRestartMinersCommand(command)) { // RESTART-STOP-START // STOP foreach (var miner in _runningMiners.Values) { await miner.StopTask(); } // START foreach (var miner in _runningMiners.Values) { await miner.StartMinerTask(_stopMiningManager, _username); } } 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; 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 { ApplicationStateManager.StartMining(); bool skipProfitsThreshold = CheckIfShouldSkipProfitsThreshold(command); await SwichMostProfitableGroupUpMethodTask(_normalizedProfits, skipProfitsThreshold); } }