Skip to content

Commit

Permalink
Merge pull request #140 from BartoszCichecki/beta/2.3.0
Browse files Browse the repository at this point in the history
Beta 2.3.0
BartoszCichecki authored Aug 4, 2022

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
2 parents 0bdf3b0 + d7f3165 commit a5f0f76
Showing 73 changed files with 2,109 additions and 288 deletions.
2 changes: 0 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -202,8 +202,6 @@ PublishScripts/
*.nupkg
# NuGet Symbol Packages
*.snupkg
# The packages folder can be ignored because of Package Restore
**/[Pp]ackages/*
# except build/, which is used as an MSBuild target.
!**/[Pp]ackages/build/
# Uncomment if necessary however generally it will be regenerated when needed
17 changes: 8 additions & 9 deletions LenovoLegionToolkit.Lib.Automation/AutomationProcessor.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
@@ -42,12 +41,9 @@ public bool IsEnabled

public AutomationProcessor(AutomationSettings settings, PowerStateListener powerStateListener, ProcessListener processListener)
{
_settings = settings;
_powerStateListener = powerStateListener;
_processListener = processListener;

_powerStateListener.Changed += PowerStateListener_Changed;
_processListener.Changed += ProcessListener_Changed;
_settings = settings ?? throw new ArgumentNullException(nameof(settings));
_powerStateListener = powerStateListener ?? throw new ArgumentNullException(nameof(powerStateListener));
_processListener = processListener ?? throw new ArgumentNullException(nameof(processListener));
}

private async void ProcessListener_Changed(object? sender, ProcessEventInfo e)
@@ -82,6 +78,9 @@ public async Task InitializeAsync()
{
_pipelines = _settings.Store.Pipelines;
RaisePipelinesChanged();

_powerStateListener.Changed += PowerStateListener_Changed;
_processListener.Changed += ProcessListener_Changed;
}
}

@@ -141,7 +140,7 @@ public async Task RunNowAsync(AutomationPipeline pipeline)
catch (Exception ex)
{
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Pipeline run failed: {ex.Demystify()}");
Log.Instance.Trace($"Pipeline run failed.", ex);

throw;
}
@@ -201,7 +200,7 @@ private async Task RunAsync(object? context)
catch (Exception ex)
{
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Pipeline run failed: {ex.Demystify()} [name={pipeline.Name}, trigger={pipeline.Trigger}]");
Log.Instance.Trace($"Pipeline run failed. [name={pipeline.Name}, trigger={pipeline.Trigger}]", ex);
}

if (pipeline.IsExclusive)
1 change: 0 additions & 1 deletion LenovoLegionToolkit.Lib.Automation/IoCModule.cs
Original file line number Diff line number Diff line change
@@ -9,7 +9,6 @@ public class IoCModule : Module
protected override void Load(ContainerBuilder builder)
{
builder.Register<AutomationSettings>();

builder.Register<AutomationProcessor>();
}
}
Original file line number Diff line number Diff line change
@@ -8,7 +8,6 @@
<PackageReference Include="Autofac" Version="6.4.0" />
<PackageReference Include="Microsoft.CSharp" Version="4.7.0" />
<PackageReference Include="NeoSmart.AsyncLock" Version="3.2.1" />
<PackageReference Include="Ben.Demystifier" Version="0.4.1" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
</ItemGroup>
<ItemGroup>
Original file line number Diff line number Diff line change
@@ -16,7 +16,11 @@ public class ProcessesAreRunningAutomationPipelineTrigger : IAutomationPipelineT

public bool IsSatisfied(object? context)
{
return Processes.SelectMany(p => Process.GetProcessesByName(p.Name)).Any();
if (context is not ProcessEventInfo pei || pei.Type != ProcessEventInfoType.Started)
return false;

var result = Processes.SelectMany(p => Process.GetProcessesByName(p.Name)).Any();
return result;
}

public IAutomationPipelineTrigger DeepCopy() => new ProcessesAreRunningAutomationPipelineTrigger(Processes);
Original file line number Diff line number Diff line change
@@ -20,11 +20,8 @@ public bool IsSatisfied(object? context)
if (context is not ProcessEventInfo pei || pei.Type != ProcessEventInfoType.Stopped)
return false;

var matches = Processes.Contains(pei.Process);
if (!matches)
return false;

return Processes.SelectMany(pn => Process.GetProcessesByName(pn.Name)).IsEmpty();
var result = Processes.SelectMany(p => Process.GetProcessesByName(p.Name)).IsEmpty();
return result;
}

public IAutomationPipelineTrigger DeepCopy() => new ProcessesStopRunningAutomationPipelineTrigger(Processes);
Original file line number Diff line number Diff line change
@@ -21,9 +21,7 @@ public async Task RunAsync()
if (!_controller.IsSupported())
return;

await _controller.RefreshAsync().ConfigureAwait(false);

if (!_controller.CanBeDeactivated)
if (!await _controller.CanBeDeactivatedAsync().ConfigureAwait(false))
return;

switch (State)
58 changes: 15 additions & 43 deletions LenovoLegionToolkit.Lib/Controllers/CPUBoostController.cs
Original file line number Diff line number Diff line change
@@ -2,9 +2,7 @@
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using LenovoLegionToolkit.Lib.Extensions;
using LenovoLegionToolkit.Lib.System;
using LenovoLegionToolkit.Lib.Utils;

@@ -15,10 +13,6 @@ public class CPUBoostModeController
private const string ProcessorPowerManagementSubgroupGUID = "54533251-82be-4824-96c1-47b60b740d00";
private const string PowerSettingGUID = "be337238-0d82-4146-a960-4f3749d470c7";

private static readonly Regex _guidRegex = new(@"(?im)[{(]?[0-9A-F]{8}[-]?(?:[0-9A-F]{4}[-]?){3}[0-9A-F]{12}[)}]?");
private static readonly Regex _nameRegex = new(@"(?im)\((.*)\)");
private static readonly Regex _activeRegex = new(@"(?im)\*$");

public async Task<List<CPUBoostModeSettings>> GetSettingsAsync()
{
if (Log.Instance.IsTraceEnabled)
@@ -29,15 +23,16 @@ public async Task<List<CPUBoostModeSettings>> GetSettingsAsync()
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Getting power plans...");

var powerPlans = await GetPowerPlansAsync();
var powerPlans = await Power.GetPowerPlansAsync().ConfigureAwait(false);
var cpuBoostModes = await GetCPUBoostModesAsync().ConfigureAwait(false);

var result = new List<CPUBoostModeSettings>();
foreach (var powerPlan in powerPlans)
{
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Getting perfboostmodes for power plan {powerPlan.Name}... [powerPlan.instanceID={powerPlan.InstanceID}]");

var settings = await GetCPUBoostSettingsAsync(powerPlan);
var settings = await GetCPUBoostSettingsAsync(powerPlan, cpuBoostModes);

if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Perfboostmodes settings retrieved for power plan {settings.PowerPlan.Name} [powerPlan.instanceID={settings.PowerPlan.InstanceID}, {string.Join(",", settings.CPUBoostModes.Select(cbm => $"{{{cbm.Name}:{cbm.Value}}}"))}, acSettingsValue={settings.ACSettingValue}, dcSettingValue={settings.DCSettingValue}]");
@@ -74,49 +69,26 @@ private async Task EnsureAttributeVisibleAsync()
Log.Instance.Trace($"Perfboostmode is visible.");
}

private async Task<List<PowerPlan>> GetPowerPlansAsync()
private async Task<List<CPUBoostMode>> GetCPUBoostModesAsync()
{
var output = await CMD.RunAsync("powercfg", "/LIST");
var outputLines = output
.Split(Environment.NewLine)
.Where(s => s.StartsWith("Power Scheme GUID", StringComparison.InvariantCultureIgnoreCase));

var result = new List<PowerPlan>();

foreach (var line in outputLines)
{
var guid = _guidRegex.Match(line).Groups[0].Value;
var name = _nameRegex.Match(line).Groups[1].Value;
var active = _activeRegex.Match(line).Success;

if (string.IsNullOrWhiteSpace(guid) || string.IsNullOrWhiteSpace(name)) { continue; }

result.Add(new PowerPlan(guid, name, active));
}

return result.OrderBy(pp => pp.Name).ToList();
var result = await WMI.ReadAsync("root\\CIMV2\\power",
$"SELECT * FROM Win32_PowerSettingDefinitionPossibleValue WHERE InstanceID LIKE '%{PowerSettingGUID}%'",
pdc =>
{
var name = (string)pdc["ElementName"].Value;
var value = Convert.ToInt32(pdc["UInt32Value"].Value);
return new CPUBoostMode(value, name);
}).ConfigureAwait(false);
return result.ToList();
}

private async Task<CPUBoostModeSettings> GetCPUBoostSettingsAsync(PowerPlan powerPlan)
private async Task<CPUBoostModeSettings> GetCPUBoostSettingsAsync(PowerPlan powerPlan, List<CPUBoostMode> cpuBoostModes)
{
var output = await CMD.RunAsync("powercfg", $"/QUERY {powerPlan.InstanceID} {ProcessorPowerManagementSubgroupGUID} {PowerSettingGUID}");
var output = await CMD.RunAsync("powercfg", $"/QUERY {powerPlan.Guid} {ProcessorPowerManagementSubgroupGUID} {PowerSettingGUID}");
var outputLines = output
.Split(Environment.NewLine)
.Select(s => s.Trim());

var possibleSettingLinesGroupped = outputLines
.Where(s => s.StartsWith("Possible Setting", StringComparison.InvariantCultureIgnoreCase))
.Split(2);

var cpuBoostModes = new List<CPUBoostMode>();
foreach (var possibleSettingLinesGroup in possibleSettingLinesGroupped)
{
var indexString = possibleSettingLinesGroup.ElementAt(0).Split(":").Last().Trim();
var index = int.Parse(indexString);
var name = possibleSettingLinesGroup.ElementAt(1).Split(":").Last().Trim();
cpuBoostModes.Add(new CPUBoostMode(index, name));
}

var acSettingValueString = outputLines.First(s => s.StartsWith("Current AC Power Setting Index")).Split(":").Last().Replace("0x", "").Trim();
var dcSettingValueString = outputLines.First(s => s.StartsWith("Current DC Power Setting Index")).Split(":").Last().Replace("0x", "").Trim();

66 changes: 39 additions & 27 deletions LenovoLegionToolkit.Lib/Controllers/GPUController.cs
Original file line number Diff line number Diff line change
@@ -78,7 +78,14 @@ public bool IsSupported()
}
}

public Task RefreshAsync() => RefreshLoopAsync(0, 0, CancellationToken.None);
public async Task<bool> CanBeDeactivatedAsync()
{
using (await _lock.LockAsync().ConfigureAwait(false))
{
await RefreshLoopAsync(0, 0, CancellationToken.None);
return CanBeDeactivated;
}
}

public async Task StartAsync(int delay = 1_000, int interval = 5_000)
{
@@ -127,45 +134,47 @@ public async Task StopAsync(bool waitForFinish = false)
public async Task DeactivateGPUAsync()
{
using (await _lock.LockAsync().ConfigureAwait(false))

{
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Deactivating... [isActive={IsActive}, canBeDeactivated={CanBeDeactivated}, gpuInstanceId={_gpuInstanceId}]");

if (!IsActive || !CanBeDeactivated || string.IsNullOrEmpty(_gpuInstanceId))
return;
if (!IsActive || !CanBeDeactivated || string.IsNullOrEmpty(_gpuInstanceId))
return;

await CMD.RunAsync("pnputil", $"/restart-device \"{_gpuInstanceId}\"").ConfigureAwait(false);
await CMD.RunAsync("pnputil", $"/restart-device \"{_gpuInstanceId}\"").ConfigureAwait(false);

if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Deactivated [isActive={IsActive}, canBeDeactivated={CanBeDeactivated}, gpuInstanceId={_gpuInstanceId}]");
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Deactivated [isActive={IsActive}, canBeDeactivated={CanBeDeactivated}, gpuInstanceId={_gpuInstanceId}]");
}
}

public async Task KillGPUProcessesAsync()
{
using (await _lock.LockAsync().ConfigureAwait(false))

{
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Killing GPU processes... [isActive={IsActive}, canBeDeactivated={CanBeDeactivated}, gpuInstanceId={_gpuInstanceId}]");

if (!IsActive || !CanBeDeactivated || string.IsNullOrEmpty(_gpuInstanceId))
return;
if (!IsActive || !CanBeDeactivated || string.IsNullOrEmpty(_gpuInstanceId))
return;

foreach (var process in _processes)
{
try
{
process.Kill(true);
await process.WaitForExitAsync().ConfigureAwait(false);
}
catch (Exception ex)
foreach (var process in _processes)
{
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Couldnt kill process: {ex.Demystify()} [pid={process.Id}, name={process.ProcessName}]");
try
{
process.Kill(true);
await process.WaitForExitAsync().ConfigureAwait(false);
}
catch (Exception ex)
{
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Couldnt kill process. [pid={process.Id}, name={process.ProcessName}]", ex);
}
}
}

if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Killed GPU processes. [isActive={IsActive}, canBeDeactivated={CanBeDeactivated}, gpuInstanceId={_gpuInstanceId}]");
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Killed GPU processes. [isActive={IsActive}, canBeDeactivated={CanBeDeactivated}, gpuInstanceId={_gpuInstanceId}]");
}
}

private async Task RefreshLoopAsync(int delay, int interval, CancellationToken token)
@@ -182,7 +191,7 @@ private async Task RefreshLoopAsync(int delay, int interval, CancellationToken t

await Task.Delay(delay, token).ConfigureAwait(false);

while (interval > 0)
while (true)
{
token.ThrowIfCancellationRequested();

@@ -201,13 +210,16 @@ private async Task RefreshLoopAsync(int delay, int interval, CancellationToken t
Refreshed?.Invoke(this, new RefreshedEventArgs(IsActive, CanBeDeactivated, _status, _performanceState, _processes));
}

await Task.Delay(interval, token).ConfigureAwait(false);
if (interval > 0)
await Task.Delay(interval, token).ConfigureAwait(false);
else
break;
}
}
catch (Exception ex) when (ex is not TaskCanceledException)
{
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Exception: {ex.Demystify()}");
Log.Instance.Trace($"Exception occured", ex);

throw;
}
@@ -259,7 +271,7 @@ private async Task RefreshStateAsync()
catch (Exception ex)
{
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"GPU status error: {ex.Demystify()}");
Log.Instance.Trace($"GPU status exception.", ex);

_performanceState = "Unknown";
}
Loading

0 comments on commit a5f0f76

Please sign in to comment.