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

## [Unreleased]

## [0.48.33] - 2026-05-18

### Changed
- **ConsoleViewModel** — buffer trimming now uses clear-and-rebuild when
removing more than 25% of lines, reducing worst-case from O(n×excess)
to O(n) (CQ-LOW: ConsoleViewModel O(n²)).
- **LogsViewModel** — event log entries are now dispatched to the UI thread
in batches of 50 instead of one-at-a-time, reducing dispatcher overhead
by ~98% when loading large event logs (CQ-LOW: LogsViewModel batch dispatch).

## [0.48.32] - 2026-05-18

### Fixed
Expand Down
20 changes: 16 additions & 4 deletions SysManager/SysManager/ViewModels/ConsoleViewModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -38,11 +38,23 @@ public void Append(PowerShellLine line)
Lines.Add(line);
if (Lines.Count > MaxLines)
{
// PERF-005: Remove excess items from front (index 0). Each removal
// is O(n) but unavoidable with ObservableCollection.
// PERF: When excess is large relative to buffer, clear-and-rebuild
// is O(n) vs O(n*excess) for repeated RemoveAt(0).
var excess = Lines.Count - MaxLines;
for (int i = 0; i < excess; i++)
Lines.RemoveAt(0);
if (excess > Lines.Count / 4)
{
var keep = new PowerShellLine[MaxLines];
for (int i = 0; i < MaxLines; i++)
keep[i] = Lines[excess + i];
Lines.Clear();
foreach (var item in keep)
Lines.Add(item);
}
else
{
for (int i = 0; i < excess; i++)
Lines.RemoveAt(0);
}
}
}
}
Expand Down
31 changes: 29 additions & 2 deletions SysManager/SysManager/ViewModels/LogsViewModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -132,14 +132,41 @@ private async Task RefreshAsync()

try
{
const int batchSize = 50;
var batch = new List<FriendlyEventEntry>(batchSize);

await foreach (var entry in _eventLogs.ReadAsync(opt, _cts.Token))
{
batch.Add(entry);
if (batch.Count >= batchSize)
{
var items = batch.ToArray();
batch.Clear();
Post(() =>
{
foreach (var item in items)
{
Entries.Add(item);
UpdateCounts(item, 1);
}
});
}
}

// Flush remaining items
if (batch.Count > 0)
{
var remaining = batch.ToArray();
Post(() =>
{
Entries.Add(entry);
UpdateCounts(entry, 1);
foreach (var item in remaining)
{
Entries.Add(item);
UpdateCounts(item, 1);
}
});
}

StatusMessage = $"Loaded {Entries.Count} events from {SelectedLog}";
UpdateVisibleCount();
}
Expand Down
Loading