Skip to content
Merged
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
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,12 @@ adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [Unreleased]

## [1.20.41] - 2026-06-17

### Fixed
- **"Restore All" in Performance Mode now fully clears the saved baseline.** After restoring everything to the original state, the on-disk snapshot was left behind, so the next change reloaded the now-reverted values as its baseline — a later "Restore All" could then re-apply stale settings. The saved snapshot is now deleted when you restore all.
- **Applying several performance tweaks at once can no longer race the baseline capture.** The independent Apply buttons (power plan, visual effects, Game Mode, Xbox Game Bar, GPU, processor state) each captured the "before" snapshot without coordination, so two run together could both think no baseline existed. Baseline capture is now serialized so the original state is recorded exactly once.

## [1.20.40] - 2026-06-17

### Fixed
Expand Down
16 changes: 16 additions & 0 deletions SysManager/SysManager/Services/PerformanceService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,22 @@ public static void SaveSnapshot(OriginalSnapshot snapshot)
catch (UnauthorizedAccessException ex) { Log.Warning(ex, "Failed to save performance snapshot"); }
}

/// <summary>
/// Delete the persisted snapshot from disk. Called after "Restore All" so the next
/// Apply captures a fresh baseline instead of reloading the now-reverted pre-restore
/// state via <see cref="LoadSnapshot"/>.
/// </summary>
public static void DeleteSnapshot()
{
try
{
if (File.Exists(SnapshotPath)) File.Delete(SnapshotPath);
Log.Information("Performance snapshot deleted from {Path}", SnapshotPath);
}
catch (IOException ex) { Log.Warning(ex, "Failed to delete performance snapshot"); }
catch (UnauthorizedAccessException ex) { Log.Warning(ex, "Failed to delete performance snapshot"); }
}

/// <summary>Load a previously saved snapshot from disk. Returns null if none exists.</summary>
public static OriginalSnapshot? LoadSnapshot()
{
Expand Down
6 changes: 3 additions & 3 deletions SysManager/SysManager/SysManager.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@
<RootNamespace>SysManager</RootNamespace>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<NoWarn>NU1603;NU1701</NoWarn>
<Version>1.20.40</Version>
<FileVersion>1.20.40.0</FileVersion>
<AssemblyVersion>1.20.40.0</AssemblyVersion>
<Version>1.20.41</Version>
<FileVersion>1.20.41.0</FileVersion>
<AssemblyVersion>1.20.41.0</AssemblyVersion>
<Product>SysManager</Product>
<Description>SysManager — Windows system monitoring toolkit by laurentiu021. Network, updates, health, logs, safe deep cleanup.</Description>
<PackageProjectUrl>https://github.com/laurentiu021/SystemManager</PackageProjectUrl>
Expand Down
21 changes: 17 additions & 4 deletions SysManager/SysManager/ViewModels/PerformanceViewModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@ public sealed partial class PerformanceViewModel : ViewModelBase
{
private readonly PerformanceService _service;
private PerformanceService.OriginalSnapshot? _snapshot;
// Serializes the load-modify of _snapshot so two Apply commands running at once
// can't both observe a null snapshot and race the capture/save.
private readonly SemaphoreSlim _snapshotGate = new(1, 1);

[ObservableProperty] private bool _isElevated;
[ObservableProperty] private PerformanceProfile _profile = new();
Expand Down Expand Up @@ -71,10 +74,15 @@ private async Task InitAsync()
/// <summary>Ensure snapshot exists before any change.</summary>
private async Task EnsureSnapshotAsync()
{
_snapshot ??= PerformanceService.LoadSnapshot()
?? await _service.TakeSnapshotAsync();
PerformanceService.SaveSnapshot(_snapshot);
HasSnapshot = true;
await _snapshotGate.WaitAsync().ConfigureAwait(false);
try
{
_snapshot ??= PerformanceService.LoadSnapshot()
?? await _service.TakeSnapshotAsync();
PerformanceService.SaveSnapshot(_snapshot);
HasSnapshot = true;
}
finally { _snapshotGate.Release(); }
}

private void UpdateSummary()
Expand Down Expand Up @@ -508,6 +516,10 @@ private async Task RestoreAllAsync()
Log.Information("Performance settings restored to original snapshot");
_snapshot = null;
HasSnapshot = false;
// Delete the persisted snapshot too — otherwise the next Apply reloads the
// now-reverted pre-restore baseline via LoadSnapshot and a later Restore All
// would re-apply stale values.
PerformanceService.DeleteSnapshot();
await RefreshAsync();
}
catch (InvalidOperationException ex) { StatusMessage = $"Restore all settings failed: {ex.Message}"; }
Expand Down Expand Up @@ -561,6 +573,7 @@ protected override void Dispose(bool disposing)
if (disposing)
{
_snapshot = null;
_snapshotGate.Dispose();
}
base.Dispose(disposing);
}
Expand Down
Loading