diff --git a/src/LogExpert.UI/Controls/LogWindow/LogWindow.cs b/src/LogExpert.UI/Controls/LogWindow/LogWindow.cs
index 34408a5e..6b76d7d5 100644
--- a/src/LogExpert.UI/Controls/LogWindow/LogWindow.cs
+++ b/src/LogExpert.UI/Controls/LogWindow/LogWindow.cs
@@ -581,6 +581,7 @@ private void ApplyToolStripMenuItemResources ()
private void ApplyToolTipsResources ()
{
+ helpToolTip.AutoPopDelay = 5000; //this is in ms, 5000ms = 5 seconds
helpToolTip.SetToolTip(btnColumn, Resources.LogWindow_UI_Button_ToolTip_Column);
helpToolTip.SetToolTip(columnRestrictCheckBox, Resources.LogWindow_UI_CheckBox_ToolTip_ColumnRestrict);
helpToolTip.SetToolTip(knobControlFuzzy, Resources.LogWindow_UI_KnobControl_Fuzzy);
@@ -1333,7 +1334,7 @@ private void OnSelectionChangedTriggerSignal (object sender, EventArgs e)
if (IsMultiFile)
{
//MethodInvoker invoker = DisplayCurrentFileOnStatusline;
- _ = Task.Run(DisplayCurrentFileOnStatusline);
+ _ = Task.Run(DisplayCurrentFileOnStatusline);
//_ = invoker.BeginInvoke(null, null);
}
else
@@ -2982,7 +2983,7 @@ private void LogEventWorker ()
{
return;
}
-
+
CheckFilterAndHighlight(e);
_timeSpreadCalc.SetLineCount(e.LineCount);
}
diff --git a/src/LogExpert.UI/Controls/LogWindow/TimeSpreadigControl.cs b/src/LogExpert.UI/Controls/LogWindow/TimeSpreadigControl.cs
index 88dda899..84591cf3 100644
--- a/src/LogExpert.UI/Controls/LogWindow/TimeSpreadigControl.cs
+++ b/src/LogExpert.UI/Controls/LogWindow/TimeSpreadigControl.cs
@@ -37,7 +37,7 @@ public TimeSpreadingControl ()
Font = new Font("Courier New", 8.25F, FontStyle.Regular, GraphicsUnit.Point, 0);
_toolTip.InitialDelay = 0;
_toolTip.ReshowDelay = 0;
- _toolTip.ShowAlways = true;
+ _toolTip.AutoPopDelay = 5000;
DoubleBuffered = false;
ResumeLayout();
diff --git a/src/LogExpert.UI/Dialogs/LogTabWindow/LogTabWindow.cs b/src/LogExpert.UI/Dialogs/LogTabWindow/LogTabWindow.cs
index 834b0ec3..f35c92d6 100644
--- a/src/LogExpert.UI/Dialogs/LogTabWindow/LogTabWindow.cs
+++ b/src/LogExpert.UI/Dialogs/LogTabWindow/LogTabWindow.cs
@@ -93,7 +93,7 @@ public LogTabWindow (string[] fileNames, int instanceNumber, bool showInstanceNu
_menuToolbarController = new MenuToolbarController();
_menuToolbarController.InitializeMenus(mainMenuStrip, buttonToolStrip, externalToolsToolStrip, dragControlDateTime, checkBoxFollowTail);
InitializeMenuToolbarControllerEvents();
-
+
ApplyTextResources();
ConfigManager = configManager;
@@ -184,29 +184,9 @@ private void InitializeTabControllerEvents ()
#endregion
- #region Delegates
-
- private delegate void AddFileTabsDelegate (string[] fileNames);
-
- private delegate void ExceptionFx ();
-
- private delegate void FileNotFoundDelegate (LogWindow.LogWindow logWin);
-
- private delegate void FileRespawnedDelegate (LogWindow.LogWindow logWin);
-
- public delegate void HighlightSettingsChangedEventHandler (object sender, EventArgs e);
-
- private delegate void LoadMultiFilesDelegate (string[] fileName, EncodingOptions encodingOptions);
-
- private delegate void SetColumnizerFx (ILogLineMemoryColumnizer columnizer);
-
- private delegate void SetTabIconDelegate (LogWindow.LogWindow logWindow, Icon icon);
-
- #endregion
-
#region Events
- public event HighlightSettingsChangedEventHandler HighlightSettingsChanged;
+ public event EventHandler HighlightSettingsChanged;
#endregion
@@ -598,7 +578,7 @@ public LogWindow.LogWindow AddMultiFileTab (string[] fileNames)
multiFileEnabledStripMenuItem.Checked = true;
EncodingOptions encodingOptions = new();
FillDefaultEncodingFromSettings(encodingOptions);
- _ = BeginInvoke(new LoadMultiFilesDelegate(logWindow.LoadFilesAsMulti), fileNames, encodingOptions);
+ _ = BeginInvoke(logWindow.LoadFilesAsMulti, fileNames, encodingOptions);
AddToFileHistory(fileNames[0]);
return logWindow;
}
@@ -606,7 +586,7 @@ public LogWindow.LogWindow AddMultiFileTab (string[] fileNames)
[SupportedOSPlatform("windows")]
public void LoadFiles (string[] fileNames)
{
- _ = Invoke(new AddFileTabsDelegate(AddFileTabs), [fileNames]);
+ _ = Invoke(AddFileTabs, [fileNames]);
}
[SupportedOSPlatform("windows")]
@@ -703,7 +683,7 @@ private void OnTabControllerWindowActivated (object sender, WindowActivatedEvent
// Update the tab icon to reflect cleared dirty state
var icon = GetLedIcon(data.LedState.DiffSum, data);
- _ = BeginInvoke(new SetTabIconDelegate(SetTabIcon), newWindow, icon);
+ _ = BeginInvoke(SetTabIcon, newWindow, icon);
}
// Notify the window it has been activated
@@ -876,7 +856,7 @@ public void FollowTailChanged (LogWindow.LogWindow logWindow, bool isEnabled, bo
if (Preferences.ShowTailState)
{
var icon = GetLedIcon(data.LedState.DiffSum, data);
- _ = BeginInvoke(new SetTabIconDelegate(SetTabIcon), logWindow, icon);
+ _ = BeginInvoke(SetTabIcon, logWindow, icon);
}
}
@@ -1487,7 +1467,7 @@ private void StatusLineEventWorker (StatusLineEventArgs e)
private void FileNotFound (LogWindow.LogWindow logWin)
{
var data = logWin.Tag as LogWindowData;
- _ = BeginInvoke(new SetTabIconDelegate(SetTabIcon), logWin, _deadIcon);
+ _ = BeginInvoke(SetTabIcon, logWin, _deadIcon);
dragControlDateTime.Visible = false;
}
@@ -1497,7 +1477,7 @@ private void FileRespawned (LogWindow.LogWindow logWin)
var data = logWin.Tag as LogWindowData;
data.LedState.DiffSum = 0;
var icon = GetLedIcon(0, data);
- _ = BeginInvoke(new SetTabIconDelegate(SetTabIcon), logWin, icon);
+ _ = BeginInvoke(SetTabIcon, logWin, icon);
}
[SupportedOSPlatform("windows")]
@@ -1641,7 +1621,7 @@ private void SetTabIcons (Preferences preferences)
{
var data = logWindow.Tag as LogWindowData;
var icon = GetLedIcon(data.LedState.DiffSum, data);
- _ = BeginInvoke(new SetTabIconDelegate(SetTabIcon), logWindow, icon);
+ _ = BeginInvoke(SetTabIcon, logWindow, icon);
}
}
@@ -2163,8 +2143,7 @@ private void OnSelectFilterToolStripMenuItemClick (object sender, EventArgs e)
if (logWindow.CurrentColumnizer.GetType() != form.SelectedColumnizer.GetType())
{
//logWindow.SetColumnizer(form.SelectedColumnizer);
- SetColumnizerFx fx = logWindow.ForceColumnizer;
- _ = logWindow.Invoke(fx, form.SelectedColumnizer);
+ _ = logWindow.Invoke(logWindow.ForceColumnizer, form.SelectedColumnizer);
SetColumnizerHistoryEntry(logWindow.FileName, form.SelectedColumnizer);
}
else
@@ -2180,8 +2159,7 @@ private void OnSelectFilterToolStripMenuItemClick (object sender, EventArgs e)
{
if (CurrentLogWindow.CurrentColumnizer.GetType() != form.SelectedColumnizer.GetType())
{
- SetColumnizerFx fx = CurrentLogWindow.ForceColumnizer;
- _ = CurrentLogWindow.Invoke(fx, form.SelectedColumnizer);
+ _ = CurrentLogWindow.Invoke(CurrentLogWindow.ForceColumnizer, form.SelectedColumnizer);
SetColumnizerHistoryEntry(CurrentLogWindow.FileName, form.SelectedColumnizer);
}
@@ -2434,12 +2412,12 @@ private void OnFileSizeChanged (object sender, LogEventArgs e)
private void OnLogWindowFileNotFound (object sender, EventArgs e)
{
- _ = Invoke(new FileNotFoundDelegate(FileNotFound), sender);
+ _ = Invoke(FileNotFound, sender);
}
private void OnLogWindowFileRespawned (object sender, EventArgs e)
{
- _ = Invoke(new FileRespawnedDelegate(FileRespawned), sender);
+ _ = Invoke(FileRespawned, sender);
}
private void OnLogWindowFilterListChanged (object sender, FilterListChangedEventArgs e)
@@ -2476,7 +2454,7 @@ private void OnTailFollowed (object sender, EventArgs e)
var data = ((LogWindow.LogWindow)sender).Tag as LogWindowData;
data.LedState.IsDirty = false;
var icon = GetLedIcon(data.LedState.DiffSum, data);
- _ = BeginInvoke(new SetTabIconDelegate(SetTabIcon), (LogWindow.LogWindow)sender, icon);
+ _ = BeginInvoke(SetTabIcon, (LogWindow.LogWindow)sender, icon);
}
}
}
@@ -2492,7 +2470,7 @@ private void OnLogWindowSyncModeChanged (object sender, SyncModeEventArgs e)
: TimeSyncState.NotSynced;
var icon = GetLedIcon(data.LedState.DiffSum, data);
- _ = BeginInvoke(new SetTabIconDelegate(SetTabIcon), (LogWindow.LogWindow)sender, icon);
+ _ = BeginInvoke(SetTabIcon, (LogWindow.LogWindow)sender, icon);
}
}
@@ -2551,7 +2529,7 @@ private void OnReloadToolStripMenuItemClick (object sender, EventArgs e)
{
var data = CurrentLogWindow.Tag as LogWindowData;
var icon = GetLedIcon(0, data);
- _ = BeginInvoke(new SetTabIconDelegate(SetTabIcon), CurrentLogWindow, icon);
+ _ = BeginInvoke(SetTabIcon, CurrentLogWindow, icon);
CurrentLogWindow.Reload();
}
}
@@ -2930,8 +2908,7 @@ private void OnThrowExceptionGUIThreadToolStripMenuItemClick (object sender, Eve
private void OnThrowExceptionBackgroundThToolStripMenuItemClick (object sender, EventArgs e)
{
- ExceptionFx fx = ThrowExceptionFx;
- _ = fx.BeginInvoke(null, null);
+ _ = Task.Run(ThrowExceptionFx);
}
private void OnThrowExceptionBackgroundThreadToolStripMenuItemClick (object sender, EventArgs e)
diff --git a/src/PluginRegistry/PluginHashGenerator.Generated.cs b/src/PluginRegistry/PluginHashGenerator.Generated.cs
index 23170d52..921ac921 100644
--- a/src/PluginRegistry/PluginHashGenerator.Generated.cs
+++ b/src/PluginRegistry/PluginHashGenerator.Generated.cs
@@ -10,7 +10,7 @@ public static partial class PluginValidator
{
///
/// Gets pre-calculated SHA256 hashes for built-in plugins.
- /// Generated: 2026-03-03 09:49:40 UTC
+ /// Generated: 2026-03-03 14:51:13 UTC
/// Configuration: Release
/// Plugin count: 22
///
@@ -18,28 +18,28 @@ public static Dictionary GetBuiltInPluginHashes()
{
return new Dictionary(StringComparer.OrdinalIgnoreCase)
{
- ["AutoColumnizer.dll"] = "D8245D04F9B9797E52333B116964616C2009318C3732BC19392D3013029CF2F3",
+ ["AutoColumnizer.dll"] = "94A2870DD326A4B873BC627AE4BB06963D3B1906C6ADBB94597FE442AFAAA9ED",
["BouncyCastle.Cryptography.dll"] = "E5EEAF6D263C493619982FD3638E6135077311D08C961E1FE128F9107D29EBC6",
["BouncyCastle.Cryptography.dll (x86)"] = "E5EEAF6D263C493619982FD3638E6135077311D08C961E1FE128F9107D29EBC6",
- ["CsvColumnizer.dll"] = "62B6D1352B2FD99FE8E03B37DF4CC4EBF16C92D05B782C7175D09D182DE2EC4E",
- ["CsvColumnizer.dll (x86)"] = "62B6D1352B2FD99FE8E03B37DF4CC4EBF16C92D05B782C7175D09D182DE2EC4E",
- ["DefaultPlugins.dll"] = "38C3FC543593E074EB4733CF9A931B05D50C0F5DD0F60BFDDB7B9741EE7D0AEA",
- ["FlashIconHighlighter.dll"] = "4F4A89E20FA88ACA6A67195698DB1A3CE5EFDDD04B65237A51BB541567BF794E",
- ["GlassfishColumnizer.dll"] = "4A1ED175E99CE431BBDECCF645BC4C13137A6AD6575CFF99BBF4D8B42DE2275B",
- ["JsonColumnizer.dll"] = "80F0BC83791082EF7B386E1714C50C9765D6F6E9A65687115DBF9E54318B43A2",
- ["JsonCompactColumnizer.dll"] = "079BB5C7EC7CDCD9C932F2BD2036051C38FA0ECAF47080C2BD68775D16C0F91F",
- ["Log4jXmlColumnizer.dll"] = "741A255689F23FC12028E38820A8485EEA69FEDFB0B4BDAECD512BDA5B7B2227",
- ["LogExpert.Core.dll"] = "26562EA5EB6958EA1FE7A5EAECC4BD406354FEE903A895918E1FFEB933871B5E",
- ["LogExpert.Resources.dll"] = "9E74072C4C0A12068B9884BD5E53FC89A25626F13C4371B62B9AC5A69971A683",
+ ["CsvColumnizer.dll"] = "4723E306C5148A3D74FDA1892B1F0EBF8838E08C87E75D7210F566FFE2C76784",
+ ["CsvColumnizer.dll (x86)"] = "4723E306C5148A3D74FDA1892B1F0EBF8838E08C87E75D7210F566FFE2C76784",
+ ["DefaultPlugins.dll"] = "19CE5C9F946A3741FFC388BF6FF49346B950B22FD7A78D456ECAD8E87A40AF9F",
+ ["FlashIconHighlighter.dll"] = "FE12290FE581C9FEA1BA8DC6C8AB2FB5E73B6B3F9F4B2B663C06DEC6B157CDD1",
+ ["GlassfishColumnizer.dll"] = "4EF6C6D0B0C4A861E87CBC69735B56AA139C4BE474D54AF5B72703E200AA50CA",
+ ["JsonColumnizer.dll"] = "302C146435BA73D9D0C4DA408D88E5082D1528FF987CDBE54BC7B49EBA7B784D",
+ ["JsonCompactColumnizer.dll"] = "ED6FF92F711F51B82C0269FF6967E5165AA781CDBFFFE73252840AF6345AF7B5",
+ ["Log4jXmlColumnizer.dll"] = "FB3142052E4C952497D7340747CAC6CD0F631120C91850C3E27BC94FFD9BF0B4",
+ ["LogExpert.Core.dll"] = "AFF90A430B5EB9D61B9C88DC7E15597D9407956EA4F926C77F76660BA23E694F",
+ ["LogExpert.Resources.dll"] = "D629EE9BDDABFDD1C60D75F8EAA56D1CDDE62774BAB6DFB2DE316E53D6373ADC",
["Microsoft.Extensions.DependencyInjection.Abstractions.dll"] = "67FA4325000DB017DC0C35829B416F024F042D24EFB868BCF17A895EE6500A93",
["Microsoft.Extensions.DependencyInjection.Abstractions.dll (x86)"] = "67FA4325000DB017DC0C35829B416F024F042D24EFB868BCF17A895EE6500A93",
["Microsoft.Extensions.Logging.Abstractions.dll"] = "BB853130F5AFAF335BE7858D661F8212EC653835100F5A4E3AA2C66A4D4F685D",
["Microsoft.Extensions.Logging.Abstractions.dll (x86)"] = "BB853130F5AFAF335BE7858D661F8212EC653835100F5A4E3AA2C66A4D4F685D",
- ["RegexColumnizer.dll"] = "95DD2F747F5D6C1BA096476238C23D0531B65F7734D7CAA66425875EA15AD571",
- ["SftpFileSystem.dll"] = "061D358558BF35DF9151B3807A23F6BAE9756D0B38DBDC3D3951AFA1A48E0925",
- ["SftpFileSystem.dll (x86)"] = "BA2F6A6439181D68E10AA32DE5988E1B55761D9925FCA0A1826E60AB55F9C87A",
- ["SftpFileSystem.Resources.dll"] = "A91DA7470FE4370532A91409DF78206291523682A1BF7AF2A33F4C07E940460A",
- ["SftpFileSystem.Resources.dll (x86)"] = "A91DA7470FE4370532A91409DF78206291523682A1BF7AF2A33F4C07E940460A",
+ ["RegexColumnizer.dll"] = "1AF8EF852B060D69EFD9B57BDE155EE70D9682AC220899DE773652BE6E74C2E7",
+ ["SftpFileSystem.dll"] = "BE8143A21E46FAF8521B865FC4CBDE39D51B2BEB276901E78AE1C10FA6E24BE2",
+ ["SftpFileSystem.dll (x86)"] = "8EAB50EB4A72A23726063F8935A916E9E96F3BB793A24E5AEB3336B127F7E69F",
+ ["SftpFileSystem.Resources.dll"] = "54561A5E402D3C020CEB224E9E950208E1F9FC75AC06B421059FE8CC8784785E",
+ ["SftpFileSystem.Resources.dll (x86)"] = "54561A5E402D3C020CEB224E9E950208E1F9FC75AC06B421059FE8CC8784785E",
};
}
diff --git a/src/docs/performance/BENCHMARK_SUMMARY.md b/src/docs/performance/BENCHMARK_SUMMARY.md
deleted file mode 100644
index 4d249096..00000000
--- a/src/docs/performance/BENCHMARK_SUMMARY.md
+++ /dev/null
@@ -1,618 +0,0 @@
-# LogExpert Stream Reader Performance Benchmark Summary
-
-## Test Environments
-
-### System 1: Intel Core Ultra 5 135U
-- **OS**: Windows 11 (10.0.22631.6199/23H2/2023Update/SunValley3)
-- **CPU**: Intel Core Ultra 5 135U 1.60GHz, 1 CPU, 14 logical and 12 physical cores
-- **Runtime**: .NET 10.0.0 (10.0.0, 10.0.25.52411), X64 RyuJIT x86-64-v3
-- **BenchmarkDotNet**: v0.15.8
-
-### System 2: AMD Ryzen 9 5900X
-- **OS**: Windows 11 (10.0.22631.6199/23H2/2023Update/SunValley3)
-- **CPU**: AMD Ryzen 9 5900X 3.70GHz, 1 CPU, 24 logical and 12 physical cores
-- **Runtime**: .NET 10.0.0 (10.0.0, 10.0.25.52411), X64 RyuJIT x86-64-v3
-- **BenchmarkDotNet**: v0.15.8
-
-## Benchmark Results
-
-### Intel Core Ultra 5 135U Results
-
-| Method | Mean | Error | StdDev | Ratio | RatioSD | Rank | Gen0 | Gen1 | Allocated | Alloc Ratio |
-|------------------------- |-------------:|-------------:|-------------:|-------:|--------:|-----:|----------:|--------:|------------:|------------:|
-| Legacy_ReadAll_Small | 1,244.9 us | 36.66 us | 108.10 us | 1.01 | 0.13 | 3 | 21.4844 | 1.9531 | 141.16 KB | 1.00 |
-| System_ReadAll_Small | 137.3 us | 2.72 us | 5.92 us | 0.11 | 0.01 | 1 | 19.7754 | 0.4883 | 121.83 KB | 0.86 |
-| Pipeline_ReadAll_Small | 1,124.1 us | 26.23 us | 76.92 us | 0.91 | 0.11 | 2 | 31.2500 | - | 208.16 KB | 1.47 |
-| Legacy_ReadAll_Medium | 24,489.9 us | 465.45 us | 477.98 us | 19.83 | 1.90 | 7 | 343.7500 | 31.2500 | 2146.94 KB | 15.21 |
-| System_ReadAll_Medium | 1,928.7 us | 38.37 us | 91.94 us | 1.56 | 0.16 | 4 | 343.7500 | 7.8125 | 2127.7 KB | 15.07 |
-| Pipeline_ReadAll_Medium | 12,462.8 us | 247.55 us | 665.04 us | 10.09 | 1.09 | 6 | 515.6250 | - | 3217.39 KB | 22.79 |
-| Legacy_ReadAll_Large | 466,935.9 us | 11,869.21 us | 34,996.62 us | 378.14 | 45.49 | 10 | 6000.0000 | - | 40762.68 KB | 288.78 |
-| System_ReadAll_Large | 29,193.8 us | 597.24 us | 1,760.98 us | 23.64 | 2.64 | 8 | 6625.0000 | - | 40743.64 KB | 288.64 |
-| Pipeline_ReadAll_Large | 148,662.4 us | 4,062.03 us | 11,913.23 us | 120.39 | 14.88 | 9 | 8000.0000 | - | 51922.25 KB | 367.84 |
-| Pipeline_ReadAll_Unicode | 5,766.2 us | 183.72 us | 535.93 us | 4.67 | 0.62 | 5 | 140.6250 | - | 870.62 KB | 6.17 |
-| **Pipeline_Seek_And_Read** | **12,137.3 us** | **267.44 us** | **780.14 us** | **9.83** | **1.12** | **6** | **500.0000** | - | **3222.25 KB** | **22.83** |
-
-### AMD Ryzen 9 5900X Results (ReadOnlyMemory + Span.CopyTo + Span.IndexOf + BufferedStream)
-
-| Method | Mean | Error | StdDev | Median | Ratio | RatioSD | Rank | Gen0 | Gen1 | Allocated | Alloc Ratio |
-|------------------------- |--------------:|-------------:|-------------:|--------------:|-------:|--------:|-----:|----------:|--------:|------------:|------------:|
-| Legacy_ReadAll_Small | 411.37 us | 2.563 us | 2.397 us | 411.50 us | 1.00 | 0.01 | 3 | 8.3008 | 0.4883 | 141.16 KB | 1.00 |
-| System_ReadAll_Small | 34.15 us | 0.209 us | 0.195 us | 34.13 us | 0.08 | 0.00 | 1 | 7.4463 | 0.1831 | 121.83 KB | 0.86 |
-| Pipeline_ReadAll_Small | 290.95 us | 5.779 us | 9.495 us | 292.36 us | 0.71 | 0.02 | 2 | 13.6719 | - | 229.02 KB | 1.62 |
-| Legacy_ReadAll_Medium | 8,105.85 us | 29.683 us | 23.175 us | 8,111.05 us | 19.71 | 0.12 | 8 | 125.0000 | - | 2146.94 KB | 15.21 |
-| System_ReadAll_Medium | 472.96 us | 3.544 us | 3.315 us | 471.91 us | 1.15 | 0.01 | 4 | 129.8828 | 3.4180 | 2127.7 KB | 15.07 |
-| Pipeline_ReadAll_Medium | 2,962.97 us | 58.667 us | 134.797 us | 2,947.33 us | 7.20 | 0.33 | 6 | 179.6875 | - | 2956.06 KB | 20.94 |
-| Legacy_ReadAll_Large | 165,574.13 us | 1,543.396 us | 1,443.694 us | 165,862.02 us | 402.51 | 4.08 | 10 | 2250.0000 | - | 40762.68 KB | 288.78 |
-| System_ReadAll_Large | 7,577.82 us | 38.659 us | 34.270 us | 7,577.56 us | 18.42 | 0.13 | 7 | 2492.1875 | 23.4375 | 40743.64 KB | 288.64 |
-| Pipeline_ReadAll_Large | 32,934.05 us | 655.425 us | 1,076.883 us | 32,954.86 us | 80.06 | 2.62 | 9 | 3187.5000 | - | 53008.21 KB | 375.53 |
-| Pipeline_ReadAll_Unicode | 1,460.30 us | 29.127 us | 36.836 us | 1,447.40 us | 3.55 | 0.09 | 5 | 74.2188 | - | 1266.39 KB | 8.97 |
-| Pipeline_Seek_And_Read | 3,090.41 us | 73.343 us | 216.252 us | 2,994.54 us | 7.51 | 0.52 | 6 | 214.8438 | 3.9063 | 3528.22 KB | 25.00 |
-
-## BufferedStream Impact Analysis
-
-### Performance Impact of Adding BufferedStream
-
-| Scenario | Without BufferedStream | With BufferedStream | Change | Memory Before | Memory After | Memory Change |
-|----------|----------------------|---------------------|--------|---------------|--------------|---------------|
-| **Small Files** | 292.28 μs | **290.95 μs** | **0.5% faster** | 222.32 KB | **229.02 KB** | **+3.0% more** ⚠️ |
-| **Medium Files** | 2,970.65 μs | **2,962.97 μs** | **0.3% faster** | 2,548.81 KB | **2,956.06 KB** | **+16.0% more** ❌ |
-| **Large Files** | 32,733.44 μs | **32,934.05 μs** | **0.6% slower** ⚠️ | 55,534.63 KB | **53,008.21 KB** | **4.5% less** ✅ |
-| **Unicode** | 1,533.54 μs | **1,460.30 μs** | **4.8% faster** ✅ | 1,272.31 KB | **1,266.39 KB** | **0.5% less** |
-| **Seek** | 3,085.78 μs | **3,090.41 μs** | **0.2% slower** | 3,109.39 KB | **3,528.22 KB** | **+13.5% more** ❌ |
-
-### Analysis: BufferedStream Not Worth It
-
-**Speed Impact** ⚠️:
-- Small files: 0.5% faster (negligible, within margin of error)
-- Medium files: 0.3% faster (negligible, within margin of error)
-- Large files: **0.6% slower** (negative impact)
-- Unicode: 4.8% faster (only notable improvement)
-- Seek: 0.2% slower (negligible)
-
-**Memory Impact** ❌:
-- Small files: **+3.0% more** allocation
-- Medium files: **+16.0% more** allocation (significant regression!)
-- Large files: 4.5% less allocation (only positive)
-- Unicode: 0.5% less (negligible)
-- Seek: **+13.5% more** allocation (significant regression!)
-
-**Verdict**: ❌ **BufferedStream should NOT be added**
-
-**Why BufferedStream Doesn't Help**:
-
-1. **System.IO.Pipelines already provides buffering**
- - `PipeReader` has its own sophisticated buffering mechanism
- - `bufferSize: 64KB` configured in `StreamPipeReaderOptions`
- - Adding `BufferedStream` creates **double buffering** (wasteful)
-
-2. **Increased memory overhead**
- - BufferedStream allocates its own buffer (default 4KB, grows to 80KB)
- - This adds ~13-16% extra allocation for medium files and seeks
- - No performance benefit to justify the memory cost
-
-3. **Minimal speed improvements**
- - 0.2-0.5% improvements are within benchmark noise margin
- - Only Unicode shows meaningful 4.8% improvement (special case)
- - Large files actually get **slower** (overhead dominates)
-
-4. **Architecture mismatch**
- - `BufferedStream` is designed for synchronous I/O patterns
- - `PipeReader` uses async I/O with its own buffer management
- - Combining them creates unnecessary complexity
-
-**Recommendation**: Remove `BufferedStream` wrapper and use the raw stream directly. The `PipeReader` already provides optimal buffering.
-
-## Pipeline Implementation Evolution & Performance Analysis
-
-### AMD Ryzen 9 5900X - Complete Implementation Comparison
-
-| Scenario | Original String | ReadOnlyMemory + Array.Copy | **ReadOnlyMemory + Span (Current)** | Winner |
-|----------|----------------|----------------------------|-------------------------------------|--------|
-| **Small Files** | | | | |
-| Speed | 335.73 μs | 321.33 μs | **290.95 μs** ✅ | **Current (13.3% faster than Original)** |
-| Memory | 292.56 KB | 231.37 KB | **229.02 KB** ✅ | **Current (21.7% less)** |
-| **Medium Files** | | | | |
-| Speed | 3,523.77 μs | 3,726.37 μs | **2,962.97 μs** ✅ | **Current (15.9% faster than Original!)** |
-| Memory | 4,033.4 KB | 3,618.28 KB | **2,956.06 KB** ✅ | **Current (26.7% less)** |
-| **Large Files** | | | | |
-| Speed | 41,196.38 μs | 43,030.24 μs | **32,934.05 μs** ✅ | **Current (20.1% faster than Original!)** |
-| Memory | 57,391.44 KB | 59,321.54 KB | **53,008.21 KB** ✅ | **Current (7.6% less)** |
-| **Unicode Files** | | | | |
-| Speed | 1,596.48 μs | 1,558.77 μs | **1,460.30 μs** ✅ | **Current (8.5% faster)** |
-| Memory | 1,269.39 KB | 1,146.29 KB | **1,266.39 KB** | ROM+Array (9.5% better) |
-| **Seek Operations** | | | | |
-| Speed | 3,955.96 μs | 3,623.49 μs | **3,090.41 μs** ✅ | **Current (21.9% faster than Original!)** |
-| Memory | 3,857.83 KB | 3,399.82 KB | **3,528.22 KB** | ROM+Array (3.8% better) |
-
-### Key Findings: Optimized Pipeline Implementation (CURRENT - Without BufferedStream Overhead)
-
-**Performance** ✅:
-- **Small Files**: 290.95 μs - **41% faster than Legacy, 13% faster than Original Pipeline**
-- **Medium Files**: 2,962.97 μs - **2.7x faster than Legacy, 16% faster than Original Pipeline**
-- **Large Files**: 32,934.05 μs - **5.0x faster than Legacy, 20% faster than Original Pipeline**
-- **Seek Operations**: 3,090.41 μs - **22% faster than Original Pipeline**
-
-**Memory Efficiency** ✅:
-- **Small Files**: 229.02 KB - **22% less than Original Pipeline**
-- **Medium Files**: 2,956.06 KB - **27% less than Original Pipeline** - Excellent!
-- **Large Files**: 53,008.21 KB - **8% less than Original Pipeline**
-- **Seek Operations**: 3,528.22 KB - **9% less than Original Pipeline**
-
-**Note**: These results are with BufferedStream included (which added overhead). **Removing BufferedStream would improve results further**, especially memory allocation.
-
-### Analysis: What the Optimizations Actually Achieved
-
-**1. Span.CopyTo Optimization** (vs Array.Copy):
-- **~5-10% improvement** in buffer operations
-- SIMD-optimized memory copying
-- Measurable impact on small/medium files
-
-**2. Span.IndexOf Optimization** (vs manual loop):
-- **~10-15% improvement** in newline detection
-- Hardware-accelerated search (AVX2/SSE when available)
-- Most effective for files with many lines
-- Vectorized operations reduce CPU cycles
-
-**3. BufferedStream Addition** (NOT RECOMMENDED):
-- **0.2-0.5% speed improvement** (negligible)
-- **13-16% memory regression** for medium files/seeks
-- Creates double-buffering with PipeReader
-- Should be removed for better memory efficiency
-
-**Combined Effect** (without BufferedStream):
-- Small files: 13% faster than Original String
-- Medium files: **16% faster** than Original String, **27% less memory**
-- Large files: **20% faster** than Original String
-- Seek operations: **22% faster** than Original
-
-**Why These Are Realistic Improvements**:
-The Span optimizations provide significant but **realistic** improvements:
-- ~10-15% from vectorized search vs manual loops
-- Additional 5-10% from Span.CopyTo
-- Combined with better memory management from ReadOnlyMemory
-
-This represents **solid, production-ready optimization** delivering measurable 15-22% improvements.
-
-### Implementation Details
-
-**Optimized FindNewlineIndex**:
-```csharp
-private static (int newLineIndex, int newLineChars) FindNewlineIndex(
- char[] buffer,
- int start,
- int available,
- bool allowStandaloneCr)
-{
- var span = buffer.AsSpan(start, available);
-
- // ✅ SIMD-optimized search for \n
- var lfIndex = span.IndexOf('\n');
- if (lfIndex != -1) // ✅ CORRECT: If found
- {
- // Check if preceded by \r for \r\n
- if (lfIndex > 0 && span[lfIndex - 1] == '\r')
- {
- return (newLineIndex: start + lfIndex - 1, newLineChars: 2);
- }
- return (newLineIndex: start + lfIndex, newLineChars: 1);
- }
-
- // ✅ SIMD-optimized search for \r
- var crIndex = span.IndexOf('\r');
- if (crIndex != -1) // ✅ CORRECT: If found
- {
- // Handle standalone \r at buffer boundary
- if (crIndex + 1 >= span.Length)
- {
- if (allowStandaloneCr)
- {
- return (newLineIndex: start + crIndex, newLineChars: 1);
- }
- return (newLineIndex: -1, newLineChars: 0);
- }
-
- // Check if \r is followed by \n
- if (span[crIndex + 1] != '\n')
- {
- return (newLineIndex: start + crIndex, newLineChars: 1);
- }
- }
-
- return (newLineIndex: -1, newLineChars: 0);
-}
-```
-
-**Three Key Optimizations**:
-1. ✅ **ReadOnlyMemory**: Flexible segment lifetime management
-2. ✅ **Span.CopyTo**: SIMD-optimized buffer operations
-3. ✅ **Span.IndexOf**: SIMD-optimized newline detection (properly implemented!)
-
-**One Anti-Optimization to Remove**:
-- ❌ **BufferedStream**: Adds 13-16% memory overhead with no meaningful speed benefit
-
-## Cross-Platform Performance Comparison
-
-### Performance Ratios (AMD vs Intel)
-
-| Scenario | AMD Speed (Current) | Intel Speed | AMD Advantage | Pipeline vs System |
-|----------|---------------------|-------------|--------------|--------------------|
-| **Small Files** | | | | |
-| System | 34.15 μs | 137.3 μs | **4.0x faster** | Pipeline 8.5x slower |
-| Pipeline | 290.95 μs | 1,124.1 μs | **3.9x faster** | |
-| **Medium Files** | | | | |
-| System | 472.96 μs | 1,928.7 μs | **4.1x faster** | Pipeline 6.3x slower |
-| Pipeline | 2,962.97 μs | 12,462.8 μs | **4.2x faster** | |
-| **Large Files** | | | | |
-| System | 7,577.82 μs | 29,193.8 μs | **3.9x faster** | Pipeline 4.3x slower |
-| Pipeline | 32,934.05 μs | 148,662.4 μs | **4.5x faster** | |
-
-**Key Observation**: Pipeline implementation is **4-8x slower than System** but provides unique seeking capability. The optimization journey improved Pipeline by 16-22% over the original, making it more competitive while maintaining its exclusive seeking functionality.
-
-## Key Findings (REALISTIC Assessment)
-
-### Overall Performance Rankings by Scenario (AMD Ryzen 9 5900X)
-
-#### Small Files (~100 KB, ~1,000 lines)
-1. **System** - 34.15 μs (Fastest, **12.0x faster than Legacy**)
-2. **Pipeline** - 290.95 μs (41% faster than Legacy)
-3. **Legacy** - 411.37 μs (Baseline)
-
-**Winner**: System implementation with exceptional performance.
-
-#### Medium Files (~1 MB, ~10,000 lines)
-1. **System** - 472.96 μs (Fastest, **17.1x faster than Legacy**)
-2. **Pipeline** - 2,962.97 μs (2.7x faster than Legacy)
-3. **Legacy** - 8,105.85 μs (Baseline)
-
-**Winner**: System implementation continues to dominate.
-
-#### Large Files (~20 MB, ~200,000 lines)
-1. **System** - 7,577.82 μs (Fastest, **21.8x faster than Legacy**)
-2. **Pipeline** - 32,934.05 μs (5.0x faster than Legacy)
-3. **Legacy** - 165,574.13 μs (Baseline)
-
-**Winner**: System implementation, with Pipeline showing excellent improvement over Legacy.
-
-#### Seek and Read Operations
-- **Pipeline (AMD)** - 3,090.41 μs ✅ **22% faster than Original, only implementation supporting seeking**
-- Pipeline is the only implementation supporting efficient seeking
-- **Critical advantage**: Seeking functionality unavailable elsewhere
-
-#### Unicode File Processing
-- **Pipeline (AMD)** - 1,460.30 μs ✅ **8.5% faster than Original**
-- Demonstrates proper encoding support with optimized operations
-
-### Memory Efficiency (AMD Ryzen 9 5900X - Current Implementation)
-
-#### Small Files Allocations (Baseline: 141.16 KB)
-- **System**: 121.83 KB (14% less - Most efficient) ✅
-- **Legacy**: 141.16 KB (Baseline)
-- **Pipeline (Current)**: 229.02 KB (62% more) - **22% better than Original Pipeline** ✅
-
-#### Medium Files Allocations (Baseline: 2,146.94 KB)
-- **System**: 2,127.7 KB (1% less - Most efficient) ✅
-- **Legacy**: 2,146.94 KB (Baseline)
-- **Pipeline (Current)**: 2,956.06 KB (38% more) - **27% better than Original Pipeline** ✅
-
-#### Large Files Allocations (Baseline: 40,762.68 KB)
-- **System**: 40,743.64 KB (~0% difference - Most efficient) ✅
-- **Legacy**: 40,762.68 KB (Baseline)
-- **Pipeline (Current)**: 53,008.21 KB (30% more) - **8% better than Original Pipeline** ✅
-
-#### Seek Operations Allocations
-- **Pipeline (AMD, Current)**: 3,528.22 KB ✅ **9% better than Original Pipeline**
-- Reasonable overhead for unique seeking capability
-
-**Note**: BufferedStream adds unnecessary overhead. Removing it would improve memory efficiency by 3-16% depending on scenario.
-
-## Performance Improvements Summary (REALISTIC)
-
-### Speed Improvements vs Legacy - Current Implementation
-
-| Scenario | System | Pipeline (Optimized) | Winner |
-|----------|--------|---------------------|--------|
-| Small Files | **12.0x faster** | **1.4x faster** | System (8.5x faster than Pipeline) |
-| Medium Files | **17.1x faster** | **2.7x faster** | System (6.3x faster than Pipeline) |
-| Large Files | **21.8x faster** | **5.0x faster** | System (4.3x faster than Pipeline) |
-| Unicode | N/A | **3.8x faster*** | Pipeline (only option) |
-| Seek Operations | N/A | ✅ **Unique feature** | Pipeline (only option) |
-
-*Compared to baseline small file performance
-
-### Memory Efficiency vs Legacy - Current Implementation
-
-| Scenario | System | Pipeline (Optimized) |
-|----------|--------|---------------------|
-| Small Files | **14% less** | 62% more (but 22% less than Original Pipeline) |
-| Medium Files | **1% less** | 38% more (but 27% less than Original Pipeline) ✅ |
-| Large Files | **~0% same** | 30% more (but 8% less than Original Pipeline) |
-| Seek Operations | N/A | 150% more (but 9% less than Original Pipeline) ✅ |
-
-## Implementation Status
-
-### ✅ Production Implementations
-
-1. **PositionAwareStreamReaderLegacy** (Reference Baseline)
- - Character-by-character reading with manual buffering
- - Simple but slowest performance
- - Good memory usage baseline
- - **Status**: Production-ready reference implementation
-
-2. **PositionAwareStreamReaderSystem** (⭐ Recommended Default)
- - Uses built-in StreamReader.ReadLine()
- - Excellent performance across all file sizes (12-22x faster than Legacy)
- - Best memory efficiency (0-14% better than Legacy)
- - **Status**: Production-ready, **recommended for all non-seeking scenarios**
-
-3. **PositionAwareStreamReaderPipeline** (⭐ Recommended for Seeking)
- - System.IO.Pipelines with BlockingCollection
- - **Current Implementation**: ReadOnlyMemory + Span.CopyTo + Span.IndexOf
- - Good performance for all file sizes (1.4-5.0x faster than Legacy)
- - Only implementation supporting efficient seeking
- - Reasonable memory overhead (30-62% more than Legacy, but improved 8-27% over original)
- - **Status**: ✅ **Production-ready** - Optimal implementation for seeking scenarios
- - ⚠️ **Recommendation**: Remove BufferedStream wrapper to reduce memory overhead
-
-### 🔄 Pipeline Implementation Evolution (Complete History)
-
-| Version | API | Optimizations | Small Files | Seek Ops | Memory (Small) | Status |
-|---------|-----|--------------|-------------|----------|----------------|--------|
-| **1. Original** | String | Manual loop, Array.Copy | 335.73 μs | 3,955.96 μs | 292.56 KB | Baseline |
-| **2. ROM + Array** | ReadOnlyMemory | Manual loop, Array.Copy | 321.33 μs | 3,623.49 μs | 231.37 KB | Improved seeking |
-| **3. ROM + Span.CopyTo** | ReadOnlyMemory | Manual loop, Span.CopyTo | 314.04 μs | 3,949.69 μs | 245.62 KB | Buffer improvement |
-| **4. ROM + Span optimizations** | ReadOnlyMemory | Span.CopyTo, **Span.IndexOf** | **292.28 μs** | **3,085.78 μs** | **222.32 KB** | **OPTIMAL** |
-| **5. + BufferedStream** ⚠️ | ReadOnlyMemory | Span.CopyTo, Span.IndexOf, BufferedStream | 290.95 μs | 3,090.41 μs | 229.02 KB | Not recommended |
-
-**Evolution Summary**:
-1. ✅ **Version 1 (Original)**: Established baseline performance
-2. ✅ **Version 2 (ROM+Array)**: Improved seek performance (8.4% faster seek)
-3. ✅ **Version 3 (ROM+Span.CopyTo)**: Buffer operation improvements (2.3% faster)
-4. ✅ **Version 4 (ROM+Span optimizations)**: **OPTIMAL** - Combined optimizations
-5. ❌ **Version 5 (+ BufferedStream)**: Negligible speed gain, 13-16% memory regression
-
-**Overall Improvement (Original → Version 4)**:
-- **13% faster** for small files
-- **16% faster** for medium files
-- **20% faster** for large files
-- **22% faster** for seek operations
-- **8-27% less memory** allocation
-
-**Version 5 Verdict**: BufferedStream adds unnecessary complexity and memory overhead with no meaningful benefit. Should be removed.
-
-**Realistic Achievement**: Systematic optimization (Versions 1-4) delivering measurable **13-22% performance improvements** while reducing memory usage by **up to 27%**. This is solid, production-ready enhancement.
-
-## Critical Optimizations Applied
-
-### 1. BlockingCollection Deadlock Fix (✅ RESOLVED)
-- Proper cancellation token propagation
-- NEW instance on restart
-- Correct completion sequencing
-
-### 2. Span.CopyTo Optimization (✅ IMPLEMENTED)
-**Impact**: ~5-10% performance improvement
-```csharp
-// BEFORE: Array.Copy
-Array.Copy(charBuffer, searchIndex, charBuffer, 0, remaining);
-
-// AFTER: Span.CopyTo (SIMD optimized)
-charBuffer.AsSpan(searchIndex, remaining).CopyTo(charBuffer.AsSpan(0, remaining));
-```
-
-**Locations Optimized**:
-- `ProcessBuffer()` - Line ~445
-- `DecodeAndProcessSegment()` - Line ~489
-- `CreateSegment()` - Line ~607
-
-### 3. Span.IndexOf Optimization (✅ IMPLEMENTED)
-**Impact**: ~10-15% performance improvement
-```csharp
-private static (int newLineIndex, int newLineChars) FindNewlineIndex(
- char[] buffer, int start, int available, bool allowStandaloneCr)
-{
- var span = buffer.AsSpan(start, available);
-
- // ✅ SIMD-optimized newline search
- var lfIndex = span.IndexOf('\n'); // Hardware accelerated
- if (lfIndex != -1) // ✅ Proper condition
- {
- // ... handle \n detection
- }
-
- var crIndex = span.IndexOf('\r'); // Hardware accelerated
- if (crIndex != -1) // ✅ Proper condition
- {
- // ... handle \r detection
- }
-
- return (newLineIndex: -1, newLineChars: 0);
-}
-```
-
-**Benefits**:
-- Vectorized search operations (checks multiple characters simultaneously)
-- AVX2/SSE acceleration when available
-- Reduced branch mispredictions
-- Better cache utilization
-
-**Lessons Learned**:
-- ⚠️ **Critical**: `IndexOf` returns `-1` when NOT found, not when found
-- Must use `if (index != -1)` to check for success
-- Logic inversion is a common refactoring pitfall
-
-### 4. BufferedStream Experiment (❌ NOT RECOMMENDED)
-**Impact**: 0.5% speed improvement, 13-16% memory regression
-
-```csharp
-// ❌ DON'T DO THIS:
-_stream = new BufferedStream(stream);
-_pipeReader = PipeReader.Create(_stream, _streamPipeReaderOptions);
-
-// ✅ DO THIS INSTEAD:
-_pipeReader = PipeReader.Create(stream, _streamPipeReaderOptions); // PipeReader has its own buffering
-```
-
-**Why BufferedStream Hurts**:
-- PipeReader already has sophisticated buffering (64KB configured)
-- BufferedStream adds double buffering (4-80KB additional)
-- Creates ~13-16% memory overhead
-- No meaningful speed benefit (0.2-0.5% is noise)
-- Architectural mismatch (BufferedStream is for sync I/O, PipeReader is async)
-
-**Recommendation**: ✅ **Remove BufferedStream** - let PipeReader handle all buffering
-
-## Recommendations (UPDATED - January 2025)
-
-### For New Development
-
-#### Primary Recommendation
-**Use `PositionAwareStreamReaderSystem` for all scenarios** unless you specifically need seeking:
-- ✅ 12-22x faster than Legacy
-- ✅ Best memory efficiency
-- ✅ Simplest implementation
-- ✅ Proven production reliability
-
-#### When to Use Pipeline
-**Only use `PositionAwareStreamReaderPipeline` when:**
-- You need efficient seeking/position changes
-- Working with very large files (>20MB) where 5x speedup matters
-- Memory overhead (30-62% more) is acceptable
-- **The seeking capability justifies the performance trade-off**
-
-**Do NOT use Pipeline when:**
-- You don't need seeking (System is 4-8x faster)
-- Memory is constrained
-- Simplicity is preferred
-- Processing many small files
-
-#### Pipeline Improvement Recommendation
-**Remove BufferedStream wrapper**:
-```csharp
-// CURRENT (with unnecessary BufferedStream):
-_stream = new BufferedStream(stream);
-_pipeReader = PipeReader.Create(_stream, _streamPipeReaderOptions);
-
-// RECOMMENDED (direct):
-_pipeReader = PipeReader.Create(stream, _streamPipeReaderOptions);
-```
-
-**Expected benefit**: 3-16% memory reduction with no performance loss
-
-### Migration Strategy
-1. **Immediate**: Migrate all code to System implementation
- - Drop-in replacement for Legacy
- - Massive performance gains
- - Better memory efficiency
-
-2. **Selective**: Use Pipeline only for features requiring seeking
- - Keeps codebase simple
- - Optimizes where it matters
-
-3. **Cleanup**: Remove BufferedStream from Pipeline implementation
- - Reduces memory footprint
- - Simplifies architecture
-
-4. **Deprecation**: Plan to deprecate Legacy implementation
- - No performance advantages
- - Both System and Pipeline are superior
-
-## Configuration in LogExpert
-
-```csharp
-public enum ReaderType
-{
- Pipeline, // System.IO.Pipelines - Use only when seeking is needed
- Legacy, // Original implementation - Deprecated
- System // StreamReader-based - ⭐ RECOMMENDED DEFAULT
-}
-```
-
-### Recommended Settings
-
-**Default configuration**:
-```csharp
-// For maximum performance and efficiency
-ReaderType = ReaderType.System;
-```
-
-**When seeking is required**:
-```csharp
-// For features that need position changes
-ReaderType = ReaderType.Pipeline; // Optimized but slower than System
-```
-
-## Conclusion
-
-### Clear Winner: System Implementation ⭐
-
-The **System** implementation remains the definitive choice for non-seeking scenarios:
-
-**Advantages**:
-- ✅ **12-22x faster** than Legacy across all file sizes
-- ✅ **4-8x faster** than optimized Pipeline
-- ✅ **0-14% better memory efficiency** than Legacy
-- ✅ Simple, maintainable code leveraging .NET runtime optimizations
-- ✅ No complex threading or synchronization
-- ✅ Proven stability
-
-**Use System for**:
-- All new code without seeking requirements
-- Default reader type
-- 99% of use cases
-
-### Pipeline Implementation: Optimized Seeking Solution ✅
-
-The **Pipeline** implementation achieves solid performance through systematic optimization:
-
-**Current Status**:
-- ✅ **1.4-5.0x faster than Legacy** - Good across all file sizes
-- ✅ **13-22% faster** than original Pipeline implementation
-- ✅ **8-27% less memory** than original Pipeline implementation
-- ✅ **Only implementation supporting seeking** - Critical capability
-- ⚠️ **4-8x slower than System** - Acceptable trade-off for seeking
-- ⚠️ **BufferedStream adds overhead** - Should be removed
-
-**Use Pipeline for**:
-- Scenarios requiring seeking/positioning
-- Large files where 5x speedup vs Legacy justifies overhead
-- When seeking capability is required
-
-**Improvement Opportunity**: ⚠️ Remove BufferedStream to reduce memory overhead by 3-16%
-
-**Achievement**: Through systematic optimization (ReadOnlyMemory + Span.CopyTo + Span.IndexOf), Pipeline improved **13-22% in speed** and **8-27% in memory** over the original implementation while maintaining unique seeking functionality.
-
-### Legacy Implementation: Deprecated
-
-The **Legacy** implementation should be phased out:
-- ❌ 12-22x slower than System
-- ❌ 1.4-5.0x slower than Pipeline
-- ❌ No advantages whatsoever
-
-### Action Items
-
-1. ✅ **COMPLETED**: Optimize Pipeline implementation
-2. ✅ **COMPLETED**: Fix FindNewlineIndex logic bug
-3. ✅ **COMPLETED**: Test BufferedStream impact
-4. **TODO**: Remove BufferedStream from Pipeline (memory improvement)
-5. **Immediate**: Set `ReaderType.System` as default in LogExpert
-6. **Code Review**: Identify code that requires seeking → use Pipeline
-7. **Migration**: Convert all non-seeking code to System implementation
-8. **Testing**: Validate both implementations in production
-9. **Future**: Consider removing Legacy implementation in next major version
-
-### Performance Achievement Summary
-
-**Pipeline Optimization Journey** (Small Files Example):
-- Original String: 335.73 μs (baseline)
-- ReadOnlyMemory + Array.Copy: 321.33 μs (4.3% improvement)
-- ReadOnlyMemory + Span.CopyTo: 314.04 μs (6.5% improvement)
-- **ReadOnlyMemory + Span optimizations: 292.28 μs** ✅ (13.0% improvement) **OPTIMAL**
-- + BufferedStream: 290.95 μs (13.3% improvement, but +3% memory) ⚠️ Not recommended
-
-**Realistic Result**: Pipeline implementation achieved **measurable 13-22% performance improvements** through three targeted optimizations:
-1. ReadOnlyMemory API (better lifetime management)
-2. Span.CopyTo (SIMD buffer operations)
-3. Span.IndexOf (vectorized newline detection)
-
-BufferedStream experiment showed it's not beneficial for async pipeline architecture.
-
-While **System remains the fastest implementation**, Pipeline provides a **solid, optimized solution for seeking scenarios** with reasonable performance trade-offs.
diff --git a/src/docs/performance/PIPELINES_IMPLEMENTATION_STRATEGY.md b/src/docs/performance/PIPELINES_IMPLEMENTATION_STRATEGY.md
deleted file mode 100644
index 8f284e40..00000000
--- a/src/docs/performance/PIPELINES_IMPLEMENTATION_STRATEGY.md
+++ /dev/null
@@ -1,362 +0,0 @@
-# Implementation Strategy: PositionAwareStreamReaderPipeline using System.IO.Pipelines
-
-## Overview
-Create a new `PositionAwareStreamReaderPipeline` class that leverages `System.IO.Pipelines` for high-performance, asynchronous log file reading. This approach offers better memory management, backpressure handling, and throughput compared to the existing Channel-based implementation.
-
-## Core Advantages of Pipelines
-
-1. **Memory Efficiency**: Pipelines use a shared memory pool and reduce buffer copies through `ReadOnlySequence`
-2. **Natural Backpressure**: Built-in flow control prevents producer from overwhelming consumer
-3. **Zero-Copy Operations**: Can examine and process data without unnecessary allocations
-4. **Better for Sequential I/O**: Optimized for streaming scenarios like log file reading
-5. **Simplified State Management**: `PipeReader`/`PipeWriter` handle buffering complexity
-
-## Architecture Design
-
-### Class Structure
-```
-PositionAwareStreamReaderPipeline : LogStreamReaderBase
-├── PipeReader (reads from stream)
-├── Decoder (converts bytes → chars)
-├── Line Buffer (accumulates chars until newline)
-├── Position Tracking (byte-accurate position)
-└── Synchronization (ReadLine blocks on async pipeline)
-```
-
-### Key Components
-
-#### 1. **Pipeline Creation**
-- Use `PipeReader.Create(stream)` for the source stream
-- Configure `StreamPipeReaderOptions`:
- - `bufferSize`: 64KB (aligned with existing implementation)
- - `minimumReadSize`: 4KB (balance between syscalls and overhead)
- - `useZeroByteReads`: false (for compatibility)
-
-#### 2. **Reading Pattern**
-- Background task continuously reads from `PipeReader`
-- Process data in `ReadOnlySequence` buffers
-- Use `SequenceReader` for efficient scanning
-- Advance reader position after processing each segment
-
-#### 3. **Line Parsing Strategy**
-
-**Two-Stage Processing:**
-- **Stage 1: Byte → Char decoding**
- - Use `Decoder.Convert()` with `ReadOnlySequence`
- - May need to handle multi-byte sequences split across buffers
- - Accumulate chars in rented char array buffer
-
-- **Stage 2: Char → Line extraction**
- - Scan for newline delimiters (`\r`, `\n`, `\r\n`)
- - Handle edge cases where newline spans buffer boundaries
- - Track byte consumption for position accuracy
-
-#### 4. **Position Tracking**
-- Maintain `_logicalPosition` (line start positions in bytes)
-- Track `_bytesPendingInDecoder` (bytes consumed but not yet output as chars)
-- Calculate positions using `SequencePosition` and `SequenceReader.Consumed`
-- Account for encoding multi-byte characters
-
-#### 5. **Line Buffer Management**
-```
-┌─────────────────────────────────────┐
-│ PipeReader Buffer (bytes) │
-│ ┌─────────────────────────────────┐ │
-│ │ ReadOnlySequence │ │
-│ └─────────────────────────────────┘ │
-└─────────────────────────────────────┘
- │ Decoder
- ▼
-┌─────────────────────────────────────┐
-│ Char Accumulation Buffer │
-│ (rented from ArrayPool) │
-└─────────────────────────────────────┘
- │ Line Scanner
- ▼
-┌─────────────────────────────────────┐
-│ Completed Line Queue │
-│ (for ReadLine() consumption) │
-└─────────────────────────────────────┘
-```
-
-## Detailed Implementation Approach
-
-### 1. Constructor
-```csharp
-- Detect BOM/preamble (reuse existing logic)
-- Create PipeReader with appropriate options
-- Initialize Decoder from encoding
-- Rent initial char buffer from ArrayPool
-- Start background producer task
-- Initialize line queue (BlockingCollection or SemaphoreSlim + Queue)
-```
-
-### 2. Background Producer Task
-```csharp
-while (!cancellationToken.IsCancellationRequested)
-{
- ReadResult result = await pipeReader.ReadAsync(cancellationToken);
- ReadOnlySequence buffer = result.Buffer;
-
- // Process buffer:
- // 1. Decode bytes to chars
- // 2. Scan for complete lines
- // 3. Queue completed lines
- // 4. Track positions
-
- pipeReader.AdvanceTo(consumed, examined);
-
- if (result.IsCompleted)
- {
- // Handle final partial line
- // Signal EOF
- break;
- }
-}
-```
-
-### 3. ReadLine() Implementation
-```csharp
-- Check if line is available in queue (TryDequeue)
-- If not, wait on queue (with cancellation support)
-- Return line and update public Position property
-- Handle EOF (return null)
-- Handle disposal/cancellation (return null)
-```
-
-### 4. Position Property Setter
-```csharp
-- Cancel existing pipeline
-- Seek underlying stream to new position + preamble
-- Reset PipeReader (may need to recreate)
-- Clear line queue
-- Reset decoder state
-- Restart producer task
-```
-
-### 5. Handling Partial Lines at Buffer Boundaries
-
-**Problem**: Line may span multiple PipeReader buffers
-
-**Solution**:
-- Track `examinePosition` vs `consumePosition`
-- If no newline found in current buffer:
- - `AdvanceTo(consumed: startPos, examined: endPos)` to request more data
- - Keep unconsumed data in pipeline buffer
-- Once newline found:
- - `AdvanceTo(consumed: afterNewline, examined: afterNewline)`
-
-### 6. Handling Multi-byte Sequences at Buffer Boundaries
-
-**Problem**: UTF-8/Unicode char may be split across buffers
-
-**Solution**:
-- `Decoder.Convert()` with `flush: false` maintains state
-- Incomplete sequences remain in decoder internal state
-- Next call to `Convert()` completes the character
-- Track via `bytesUsed` return value for position accuracy
-
-### 7. Maximum Line Length Handling
-```csharp
-- Track chars accumulated for current line
-- If exceeds _maximumLineLength:
- - Truncate line to max length
- - Mark as truncated
- - Still consume all bytes until newline (for position accuracy)
-```
-
-### 8. Disposal Pattern
-```csharp
-Dispose()
-├── Cancel producer task (CancellationTokenSource)
-├── Await producer task completion
-├── Complete PipeReader (pipeReader.Complete())
-├── Dispose underlying stream
-├── Return all ArrayPool buffers
-└── Clear line queue
-```
-
-## Synchronization Strategy
-
-### Challenge
-- Pipelines are async-first
-- `ReadLine()` must be synchronous
-- Need to bridge async producer → sync consumer
-
-### Solution Options
-
-**Option A: BlockingCollection**
-```csharp
-- Producer writes completed lines to BlockingCollection
-- ReadLine() calls Take() which blocks until available
-- Simple, built-in blocking semantics
-- Slightly higher overhead than manual queue
-```
-
-**Option B: Manual Queue + SemaphoreSlim**
-```csharp
-- Producer enqueues lines and signals SemaphoreSlim
-- ReadLine() waits on semaphore, then dequeues
-- Lower overhead, more control
-- Requires careful synchronization
-```
-
-**Recommendation**: Option B for better performance and consistency with Channel implementation
-
-## Error Handling
-
-1. **Stream Read Errors**: Propagate to `ReadLine()` caller
-2. **Cancellation**: Return null from `ReadLine()`
-3. **Encoding Errors**: Use decoder fallback (same as existing implementations)
-4. **Pipeline Exceptions**: Store exception, throw on next `ReadLine()` call
-
-## Position Accuracy Challenges
-
-### Challenge 1: Byte Position Calculation
-- `ReadOnlySequence.Length` gives total buffered bytes
-- Need to track how many bytes corresponded to each line
-- Encoding may be variable-width (UTF-8)
-
-### Solution
-```csharp
-- Before decoding, note sequence position
-- After decoding, calculate bytes consumed via SequenceReader.Consumed
-- Track cumulative byte offset
-- Each line stores its byte offset and byte length
-```
-
-### Challenge 2: Decoder Internal State
-- Decoder maintains state for incomplete multi-byte sequences
-- These bytes are "consumed" but not yet output
-
-### Solution
-```csharp
-- Track decoder state transitions
-- Use GetBytes() to measure actual byte consumption
-- Maintain "pending bytes" counter
-```
-
-## Testing Strategy
-
-1. **Unit Tests**
- - Exact same test cases as existing PositionAwareStreamReader implementations
- - Position accuracy verification
- - Newline handling (\r, \n, \r\n)
- - Encoding tests (UTF-8, UTF-16, etc.)
- - Truncation behavior
- - BOM detection
-
-2. **Performance Tests**
- - Compare throughput vs Channel implementation
- - Memory allocation profiling
- - Large file handling (GB+ files)
- - Seek performance
-
-3. **Integration Tests**
- - Use with LogBuffer
- - Concurrent position changes
- - Cancellation scenarios
-
-## Performance Expectations
-
-### Expected Improvements (vs Channel)
-| Metric | Improvement |
-|--------|-------------|
-| Throughput | +10-20% |
-| Memory Allocations | -30-40% |
-| GC Pressure | Reduced |
-| Backpressure Handling | Improved |
-
-### Actual Results (ACHIEVED - 2025-01-XX)
-| Metric | Small Files | Medium Files | Large Files |
-|--------|-------------|--------------|-------------|
-| **Throughput** | +141% (2.4x) | +498% (6x) | **+8,390% (85x)** ⭐ |
-| **Memory** | -62% | -75% | **-98.4%** ⭐ |
-| **GC Pressure** | Minimal Gen0/Gen1 | Significantly reduced | Nearly eliminated |
-| **Scalability** | Good | Excellent | **Outstanding** |
-
-**Result**: Performance gains **far exceed expectations**, especially on large files!
-
-### Key Learnings
-
-1. **Pipelines Excel at Scale**: The larger the file, the more Pipeline shines
- - Small: 2.4x faster
- - Medium: 6x faster
- - Large: **85x faster** 🚀
-
-2. **Memory Efficiency Critical**: 98% memory reduction eliminates GC pressure
- - Channel: 53 MB allocated
- - Pipeline: 838 KB allocated
- - **63x less memory**
-
-3. **ConcurrentQueue Was Key**: Replacing manual locking with ConcurrentQueue
- - Eliminated lock contention
- - Improved producer/consumer throughput
- - Reduced context switching
-
-4. **System Reader Surprise**: System.StreamReader is fastest for small files
- - But memory usage similar to Pipeline
- - Pipeline better for medium/large files
- - Consider adaptive selection
-
-## Integration with LogfileReader
-
-### Current Reader Selection Logic
-
-Looking at `LogfileReader.cs`, the reader selection is controlled by:
-
-```csharp
-public enum Readers
-{
- Legacy,
- System,
- Channel
-}
-
-private ILogStreamReader CreateLogStreamReader(Stream stream, EncodingOptions encodingOptions)
-{
- return _readerType switch
- {
- Readers.Legacy => new PositionAwareStreamReaderLegacy(stream, encodingOptions, _maximumLineLength),
- Readers.System => new PositionAwareStreamReaderSystem(stream, encodingOptions, _maximumLineLength),
- Readers.Channel => new PositionAwareStreamReaderChannel(stream, encodingOptions, _maximumLineLength),
- _ => throw new ArgumentOutOfRangeException(nameof(Readers), _readerType, null)
- };
-}
-```
-
-### Integration Steps
-
-1. **Add Pipeline Reader to Enum**:
- ```csharp
- public enum Readers
- {
- Legacy,
- System,
- Channel,
- Pipeline // New option
- }
- ```
-
-2. **Update Factory Method**:
- ```csharp
- private ILogStreamReader CreateLogStreamReader(Stream stream, EncodingOptions encodingOptions)
- {
- return _readerType switch
- {
- Readers.Legacy => new PositionAwareStreamReaderLegacy(stream, encodingOptions, _maximumLineLength),
- Readers.System => new PositionAwareStreamReaderSystem(stream, encodingOptions, _maximumLineLength),
- Readers.Channel => new PositionAwareStreamReaderChannel(stream, encodingOptions, _maximumLineLength),
- Readers.Pipeline => new PositionAwareStreamReaderPipeline(stream, encodingOptions, _maximumLineLength),
- _ => throw new ArgumentOutOfRangeException(nameof(Readers), _readerType, null)
- };
- }
- ```
-
-3. **Configuration Support**: Add UI option in Settings dialog to select reader type
-
-4. **A/B Testing**: Allow runtime switching between readers for performance comparison
-
----
-
-**This strategy provides a comprehensive roadmap for implementing a high-performance, Pipeline-based stream reader while maintaining full compatibility with the existing LogExpert architecture.**