Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 31 additions & 0 deletions src/Core/AutoOptimizationPolicy.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
using System;

namespace WinMemoryCleaner
{
internal static class AutoOptimizationPolicy
{
internal static Enums.Memory.Optimization.Reason? GetReason(
DateTimeOffset now,
DateTimeOffset lastAutoOptimizationByInterval,
DateTimeOffset lastAutoOptimizationByMemoryUsage,
int autoOptimizationInterval,
int autoOptimizationMemoryUsage,
int freePhysicalMemoryPercentage)
{
if (autoOptimizationInterval > 0 &&
now.Subtract(lastAutoOptimizationByInterval).TotalHours >= autoOptimizationInterval)
{
return Enums.Memory.Optimization.Reason.Schedule;
}

if (autoOptimizationMemoryUsage > 0 &&
freePhysicalMemoryPercentage < autoOptimizationMemoryUsage &&
now.Subtract(lastAutoOptimizationByMemoryUsage).TotalMinutes >= Constants.App.AutoOptimizationMemoryUsageInterval)
{
return Enums.Memory.Optimization.Reason.LowMemory;
}

return null;
}
}
}
103 changes: 103 additions & 0 deletions src/Test/AutoOptimizationPolicyTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
using NUnit.Framework;
using System;

#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member

namespace WinMemoryCleaner.AutomationTests
{
[TestFixture]
public class AutoOptimizationPolicyTests
{
[Test]
public void DisabledBoth_ReturnsNull()
{
var now = new DateTimeOffset(2024, 1, 1, 12, 0, 0, TimeSpan.Zero);

var result = AutoOptimizationPolicy.GetReason(now, now.AddHours(-24), now.AddMinutes(-30), 0, 0, 0);

Assert.IsNull(result);
}

[Test]
public void Schedule_WhenJustBeforeDue_ReturnsNull()
{
var now = new DateTimeOffset(2024, 1, 1, 12, 0, 0, TimeSpan.Zero);

var result = AutoOptimizationPolicy.GetReason(now, now.AddHours(-1).AddTicks(1), now, 1, 0, 0);

Assert.IsNull(result);
}

[Test]
public void Schedule_WhenExactlyDue_ReturnsSchedule()
{
var now = new DateTimeOffset(2024, 1, 1, 12, 0, 0, TimeSpan.Zero);

var result = AutoOptimizationPolicy.GetReason(now, now.AddHours(-1), now, 1, 0, 0);

Assert.AreEqual(Enums.Memory.Optimization.Reason.Schedule, result);
}

[Test]
public void LowMemory_WhenFreePercentageIsBelowThreshold_ReturnsLowMemory()
{
var now = new DateTimeOffset(2024, 1, 1, 12, 0, 0, TimeSpan.Zero);

var result = AutoOptimizationPolicy.GetReason(now, now, now.AddMinutes(-Constants.App.AutoOptimizationMemoryUsageInterval), 0, 40, 39);

Assert.AreEqual(Enums.Memory.Optimization.Reason.LowMemory, result);
}

[Test]
public void LowMemory_WhenFreePercentageEqualsThreshold_ReturnsNull()
{
var now = new DateTimeOffset(2024, 1, 1, 12, 0, 0, TimeSpan.Zero);

var result = AutoOptimizationPolicy.GetReason(now, now, now.AddMinutes(-Constants.App.AutoOptimizationMemoryUsageInterval), 0, 40, 40);

Assert.IsNull(result);
}

[Test]
public void LowMemory_WhenCooldownIsJustBeforeDue_ReturnsNull()
{
var now = new DateTimeOffset(2024, 1, 1, 12, 0, 0, TimeSpan.Zero);

var result = AutoOptimizationPolicy.GetReason(now, now, now.AddMinutes(-Constants.App.AutoOptimizationMemoryUsageInterval).AddTicks(1), 0, 40, 39);

Assert.IsNull(result);
}

[Test]
public void LowMemory_WhenCooldownIsExactlyDue_ReturnsLowMemory()
{
var now = new DateTimeOffset(2024, 1, 1, 12, 0, 0, TimeSpan.Zero);

var result = AutoOptimizationPolicy.GetReason(now, now, now.AddMinutes(-Constants.App.AutoOptimizationMemoryUsageInterval), 0, 40, 39);

Assert.AreEqual(Enums.Memory.Optimization.Reason.LowMemory, result);
}

[Test]
public void Schedule_WhenBothTriggersAreDue_ReturnsSchedule()
{
var now = new DateTimeOffset(2024, 1, 1, 12, 0, 0, TimeSpan.Zero);

var result = AutoOptimizationPolicy.GetReason(now, now.AddHours(-1), now.AddMinutes(-Constants.App.AutoOptimizationMemoryUsageInterval), 1, 40, 39);

Assert.AreEqual(Enums.Memory.Optimization.Reason.Schedule, result);
}

[Test]
public void Schedule_WhenNonZeroIntervalCrossesDateBoundary_ReturnsSchedule()
{
var now = new DateTimeOffset(2024, 1, 2, 0, 0, 0, TimeSpan.Zero);

var result = AutoOptimizationPolicy.GetReason(now, now.AddHours(-7), now, 7, 35, 100);

Assert.AreEqual(Enums.Memory.Optimization.Reason.Schedule, result);
}
}
}

#pragma warning restore CS1591 // Missing XML comment for publicly visible type or member
29 changes: 14 additions & 15 deletions src/ViewModel/MainViewModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1636,24 +1636,23 @@ private void MonitorApp()
{
if (CanOptimize)
{
// Interval
if (Settings.AutoOptimizationInterval > 0 &&
DateTimeOffset.Now.Subtract(_lastAutoOptimizationByInterval).TotalHours >= Settings.AutoOptimizationInterval)
var reason = AutoOptimizationPolicy.GetReason(
DateTimeOffset.Now,
_lastAutoOptimizationByInterval,
_lastAutoOptimizationByMemoryUsage,
Settings.AutoOptimizationInterval,
Settings.AutoOptimizationMemoryUsage,
Computer.Memory.Physical.Free.Percentage);

if (reason.HasValue)
{
OptimizeAsync(Enums.Memory.Optimization.Reason.Schedule);
OptimizeAsync(reason.Value);

_lastAutoOptimizationByInterval = DateTimeOffset.Now;
continue;
}

// Memory usage
if (Settings.AutoOptimizationMemoryUsage > 0 &&
Computer.Memory.Physical.Free.Percentage < Settings.AutoOptimizationMemoryUsage &&
DateTimeOffset.Now.Subtract(_lastAutoOptimizationByMemoryUsage).TotalMinutes >= Constants.App.AutoOptimizationMemoryUsageInterval)
{
OptimizeAsync(Enums.Memory.Optimization.Reason.LowMemory);
if (reason.Value == Enums.Memory.Optimization.Reason.Schedule)
_lastAutoOptimizationByInterval = DateTimeOffset.Now;
else
_lastAutoOptimizationByMemoryUsage = DateTimeOffset.Now;

_lastAutoOptimizationByMemoryUsage = DateTimeOffset.Now;
continue;
}
}
Expand Down
2 changes: 2 additions & 0 deletions src/WinMemoryCleaner.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,7 @@
<Compile Include="Converters\PercentageToWidthConverter.cs" />
<Compile Include="Converters\StringFormatConverter.cs" />
<Compile Include="Converters\SumNumericConverter.cs" />
<Compile Include="Core\AutoOptimizationPolicy.cs" />
<Compile Include="Core\Constants.cs" />
<Compile Include="Core\DependencyInjection.cs" />
<Compile Include="Core\Enums.cs" />
Expand Down Expand Up @@ -158,6 +159,7 @@
<Compile Include="Service\ComputerService.cs" />
<Compile Include="Service\HotkeyService.cs" />
<Compile Include="Service\NotificationService.cs" />
<Compile Include="Test\AutoOptimizationPolicyTests.cs" />
<Compile Include="Test\CommandTests.cs" />
<Compile Include="Test\ConverterTests.cs" />
<Compile Include="Test\CoreTests.cs" />
Expand Down
29 changes: 14 additions & 15 deletions src/WindowsService/WinService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -116,24 +116,23 @@ private void OnTimer(object sender, ElapsedEventArgs e)
// Update memory info
_computer.Memory = _computerService.Memory;

// Interval
if (Settings.AutoOptimizationInterval > 0 &&
DateTimeOffset.Now.Subtract(_lastAutoOptimizationByInterval).TotalHours >= Settings.AutoOptimizationInterval)
var reason = AutoOptimizationPolicy.GetReason(
DateTimeOffset.Now,
_lastAutoOptimizationByInterval,
_lastAutoOptimizationByMemoryUsage,
Settings.AutoOptimizationInterval,
Settings.AutoOptimizationMemoryUsage,
_computer.Memory.Physical.Free.Percentage);

if (reason.HasValue)
{
DependencyInjection.Container.Resolve<IComputerService>().Optimize(Enums.Memory.Optimization.Reason.Schedule, Settings.MemoryAreas);
DependencyInjection.Container.Resolve<IComputerService>().Optimize(reason.Value, Settings.MemoryAreas);

_lastAutoOptimizationByInterval = DateTimeOffset.Now;
return;
}

// Memory usage
if (Settings.AutoOptimizationMemoryUsage > 0 &&
_computer.Memory.Physical.Free.Percentage < Settings.AutoOptimizationMemoryUsage &&
DateTimeOffset.Now.Subtract(_lastAutoOptimizationByMemoryUsage).TotalMinutes >= Constants.App.AutoOptimizationMemoryUsageInterval)
{
DependencyInjection.Container.Resolve<IComputerService>().Optimize(Enums.Memory.Optimization.Reason.LowMemory, Settings.MemoryAreas);
if (reason.Value == Enums.Memory.Optimization.Reason.Schedule)
_lastAutoOptimizationByInterval = DateTimeOffset.Now;
else
_lastAutoOptimizationByMemoryUsage = DateTimeOffset.Now;

_lastAutoOptimizationByMemoryUsage = DateTimeOffset.Now;
return;
}
}
Expand Down
Loading