From 0c1496a46c0b971095dde77e030b5c7ba8bcb0ff Mon Sep 17 00:00:00 2001 From: Smoke <40275383+creizlein@users.noreply.github.com> Date: Sat, 22 Jul 2023 22:31:34 -0300 Subject: [PATCH] ETW Native Library and RateCalculation fixes. --- .gitignore | 3 +- make-release.bat | 4 +- src/Classes/Shared.cs | 27 ++--- src/Classes/TaskManagerConnection.cs | 8 +- src/Classes/TaskManagerEtwNative.cs | 142 +++++++++++++++++++++++++++ src/Classes/TaskManagerProcess.cs | 24 ++--- src/Classes/TaskManagerSystem.cs | 12 +-- src/Forms/frmMain.cs | 4 +- src/Forms/tabPerformance.cs | 2 +- src/Properties/AssemblyInfo.cs | 10 +- src/sMkTaskManager.csproj | 8 +- 11 files changed, 193 insertions(+), 51 deletions(-) create mode 100644 src/Classes/TaskManagerEtwNative.cs diff --git a/.gitignore b/.gitignore index 54c8f3d..f95389c 100644 --- a/.gitignore +++ b/.gitignore @@ -13,7 +13,6 @@ global.json smk-*.bat frm*.resx tab*.resx -TODO.md # User-specific files (MonoDevelop/Xamarin Studio) *.userprefs @@ -366,4 +365,4 @@ MigrationBackup/ .ionide/ # Fody - auto-generated XML schema -FodyWeavers.xsd +FodyWeavers.xsd \ No newline at end of file diff --git a/make-release.bat b/make-release.bat index cdca733..65a9f8d 100644 --- a/make-release.bat +++ b/make-release.bat @@ -1,3 +1,3 @@ @echo off -dotnet publish --nologo -c Release /p:PublishProfileFullPath=%cd%\src\Properties\Release.pubxml -tar -a -cf %cd%\bin\Publish\sMkTaskManager.zip -C %cd%\bin\Publish *.exe +dotnet publish --nologo -c Release /p:PublishProfileFullPath="%cd%\src\Properties\Release.pubxml" +tar -a -cf "%cd%\bin\Publish\sMkTaskManager.zip" -C "%cd%\bin\Publish" *.exe diff --git a/src/Classes/Shared.cs b/src/Classes/Shared.cs index 991a500..a0d8902 100644 --- a/src/Classes/Shared.cs +++ b/src/Classes/Shared.cs @@ -2,18 +2,19 @@ using System.Runtime.Versioning; using System.Runtime.CompilerServices; using System.Globalization; - +using sMkTaskManager.Classes; namespace sMkTaskManager; [SupportedOSPlatform("windows")] internal static partial class Shared { private static string _SystemAccount = ""; - internal static int bpi = 20; // Base PID Ignore - internal static List skipProcess = new(new[] { "audiodg" }); - internal static List skipServices = new(); - internal static string TotalProcessorsBin = "".PadLeft(Environment.ProcessorCount, '1'); - internal static string DebuggerCmd = ""; + public static int bpi = 20; // Base PID Ignore + public static List skipProcess = new(new[] { "audiodg" }); + public static List skipServices = new(); + public static string TotalProcessorsBin = "".PadLeft(Environment.ProcessorCount, '1'); + public static string DebuggerCmd = ""; + public static TaskManagetETW ETW = new(); public static bool IsNumeric(string value) => double.TryParse(value, out _); public static bool IsNumeric(this object value) => double.TryParse(Convert.ToString(value), out _); @@ -35,15 +36,15 @@ public static string TimeDiff(long startTime, short Format = 1) { }; } - internal static void NotImplemented([CallerMemberName] string feature = "") { + public static void NotImplemented([CallerMemberName] string feature = "") { MessageBox.Show("This feature is not implemented yet.", feature, MessageBoxButtons.OK, MessageBoxIcon.Information); } - internal static void DebugTrap(Exception e, int Code = 0, [CallerMemberName] string Method = "") { + public static void DebugTrap(Exception e, int Code = 0, [CallerMemberName] string Method = "") { Debug.WriteLine($"*** Error at `{Method}` - Code: {Code} - Threw: {e.Message}"); Debug.WriteLine(e.ToString()); } - internal static string GetSystemAccount() { + public static string GetSystemAccount() { if (_SystemAccount != "") return _SystemAccount; try { System.Security.Principal.SecurityIdentifier sid = new(System.Security.Principal.WellKnownSidType.LocalSystemSid, null); @@ -56,7 +57,7 @@ internal static string GetSystemAccount() { } return _SystemAccount!; } - internal static void GetDebuggerCmd() { + public static void GetDebuggerCmd() { string SubKey = "Software\\Microsoft\\Windows NT\\CurrentVersion\\AeDebug"; string _Debugger = ""; Microsoft.Win32.RegistryKey ParentKey = Microsoft.Win32.Registry.LocalMachine; @@ -121,10 +122,10 @@ public static bool AddPrivilege(string privilege) { } else { return false; } } else { return false; } } - } + internal class CpuUsage { - private Classes.API.FILETIME _idleTime, _kernTime, _userTime; + private API.FILETIME _idleTime, _kernTime, _userTime; private long _oldCpuUsage = 0, _oldKernUsage = 0, _oldUserUsage = 0; private double _rawIdleTime, _rawKernTime, _rawUserTime; private int _CpuUsage, _UserUsage, _KernelUsage; @@ -132,7 +133,7 @@ internal class CpuUsage { private readonly int Processors = Environment.ProcessorCount; public void Refresh(long sinceWhen) { - Classes.API.GetSystemTimes(ref _idleTime, ref _kernTime, ref _userTime); + API.GetSystemTimes(ref _idleTime, ref _kernTime, ref _userTime); _now = DateTime.Now.Ticks; if (_oldCpuUsage == 0) { diff --git a/src/Classes/TaskManagerConnection.cs b/src/Classes/TaskManagerConnection.cs index a11a0a3..a8d2a0b 100644 --- a/src/Classes/TaskManagerConnection.cs +++ b/src/Classes/TaskManagerConnection.cs @@ -112,10 +112,10 @@ public void Update(in TaskManagerConnection sourceConnection) { LifeTime = Shared.TimeDiff(CreationTime, 1); - SentDeltaValue = ETW.NetStats(Ident[2..]).Sent - SentValue; - ReceivedDeltaValue = ETW.NetStats(Ident[2..]).Received - ReceivedValue; - SentValue = ETW.NetStats(Ident[2..]).Sent; - ReceivedValue = ETW.NetStats(Ident[2..]).Received; + SentDeltaValue = Shared.ETW.NetStats(Ident[2..]).Sent - SentValue; + ReceivedDeltaValue = Shared.ETW.NetStats(Ident[2..]).Received - ReceivedValue; + SentValue = Shared.ETW.NetStats(Ident[2..]).Sent; + ReceivedValue = Shared.ETW.NetStats(Ident[2..]).Received; SentRateValue = CalculateRateValue(SentDeltaValue); ReceivedRateValue = CalculateRateValue(ReceivedDeltaValue); diff --git a/src/Classes/TaskManagerEtwNative.cs b/src/Classes/TaskManagerEtwNative.cs new file mode 100644 index 0000000..cc91dc9 --- /dev/null +++ b/src/Classes/TaskManagerEtwNative.cs @@ -0,0 +1,142 @@ +using System.Diagnostics; +using Microsoft.Diagnostics.Tracing.Parsers; +using Microsoft.Diagnostics.Tracing.Parsers.Kernel; +using Microsoft.Diagnostics.Tracing.Session; +namespace sMkTaskManager.Classes; + +internal class TaskManagetETW { + private Thread? etwThread; + private TraceEventSession? kernelSession; + private readonly Dictionary _AllStats = new() { { 0, new() } }; + private readonly Dictionary _DiskStats = new(); + private readonly Dictionary _NetStats = new(); + + public string sessionName = "sMkTaskManager"; + public System.Threading.ThreadState? State => etwThread?.ThreadState; + public bool Running => etwThread?.ThreadState == (System.Threading.ThreadState.Running | System.Threading.ThreadState.Background); + public static bool IsElevated => TraceEventSession.IsElevated() ?? false; + + public EtwStats Stats(int PID) => _AllStats.ContainsKey(PID) ? _AllStats[PID] : new EtwStats(); + public EtwStats Stats(uint PID) => _AllStats.ContainsKey((int)PID) ? _AllStats[(int)PID] : new EtwStats(); + public EtwNetStats NetStats(string Hash) => _NetStats.ContainsKey(Hash) ? _NetStats[Hash] : new EtwNetStats(); + public EtwDiskStats DiskStats(int DiskNumber) => _DiskStats.ContainsKey(DiskNumber) ? _DiskStats[DiskNumber] : new EtwDiskStats(); + + public bool Start() { + if (!Running && IsElevated) { + StartMonitor(); + Debug.WriteLine("ETW has been Started"); + } + return Running; + } + public bool Stop() { + if (etwThread != null) { + StopSession(); + Debug.WriteLine("ETW Disposed"); + } + return !Running; + } + public void Flush() { + kernelSession?.Flush(); + } + + private void StartMonitor() { + etwThread = new Thread(StartSession) { + Name = "sMkETW", + IsBackground = true, + Priority = ThreadPriority.Normal + }; + etwThread.Start(); + } + private void StartSession() { + kernelSession = new TraceEventSession(sessionName); + kernelSession.EnableKernelProvider( + KernelTraceEventParser.Keywords.DiskIO | + KernelTraceEventParser.Keywords.NetworkTCPIP + ); + + kernelSession.Source.Kernel.DiskIORead += OnDiskRead; + kernelSession.Source.Kernel.DiskIOWrite += OnDiskWrite; + + kernelSession.Source.Kernel.TcpIpRecv += OnTcpIpRecv; + kernelSession.Source.Kernel.TcpIpRecvIPV6 += OnTcpIpRecvIPV6; + kernelSession.Source.Kernel.UdpIpRecv += OnUdpIpRecv; + kernelSession.Source.Kernel.UdpIpRecvIPV6 += OnUdpIpRecvIPV6; + + kernelSession.Source.Kernel.TcpIpSend += OnTcpIpSend; + kernelSession.Source.Kernel.TcpIpSendIPV6 += OnTcpIpSendIPV6; + kernelSession.Source.Kernel.UdpIpSend += OnUdpIpSend; + kernelSession.Source.Kernel.UdpIpSendIPV6 += OnUdpIpSendIPV6; + + kernelSession.Source.Process(); + } + private void StopSession() { + kernelSession?.Dispose(); + } + + private void OnDiskRead(DiskIOTraceData obj) { + _AllStats[0].DiskReaded += (uint)obj.TransferSize; + // Per Disk + if (!_DiskStats.ContainsKey(obj.DiskNumber)) _DiskStats.Add(obj.DiskNumber, new()); + _DiskStats[obj.DiskNumber].Readed += (uint)obj.TransferSize; + // Per Process + if (obj.ProcessID > 0) { + if (!_AllStats.ContainsKey(obj.ProcessID)) _AllStats.Add(obj.ProcessID, new()); + _AllStats[obj.ProcessID].DiskReaded += (uint)obj.TransferSize; + } + } + private void OnDiskWrite(DiskIOTraceData obj) { + _AllStats[0].DiskWroted += (uint)obj.TransferSize; + // Per Disk + if (!_DiskStats.ContainsKey(obj.DiskNumber)) _DiskStats.Add(obj.DiskNumber, new()); + _DiskStats[obj.DiskNumber].Wroted += (uint)obj.TransferSize; + // Per Process + if (obj.ProcessID > 0) { + if (!_AllStats.ContainsKey(obj.ProcessID)) _AllStats.Add(obj.ProcessID, new()); + _AllStats[obj.ProcessID].DiskWroted += (uint)obj.TransferSize; + } + } + private void OnTcpIpSend(TcpIpSendTraceData mof) { ProcessNetworkPacket(mof.ProcessID, mof.size, $"{mof.saddr}:{mof.sport}-{mof.daddr}:{mof.dport}", true); } + private void OnTcpIpSendIPV6(TcpIpV6SendTraceData mof) { ProcessNetworkPacket(mof.ProcessID, mof.size, $"{mof.saddr}:{mof.sport}-{mof.daddr}:{mof.dport}", true); } + private void OnTcpIpRecv(TcpIpTraceData mof) { ProcessNetworkPacket(mof.ProcessID, mof.size, $"{mof.saddr}:{mof.sport}-{mof.daddr}:{mof.dport}", false); } + private void OnTcpIpRecvIPV6(TcpIpV6TraceData mof) { ProcessNetworkPacket(mof.ProcessID, mof.size, $"{mof.saddr}:{mof.sport}-{mof.daddr}:{mof.dport}", false); } + private void OnUdpIpSend(UdpIpTraceData mof) { ProcessNetworkPacket(mof.ProcessID, mof.size, $"{mof.saddr}:{mof.sport}-{mof.daddr}:{mof.dport}", true); } + private void OnUdpIpSendIPV6(UpdIpV6TraceData mof) { ProcessNetworkPacket(mof.ProcessID, mof.size, $"{mof.saddr}:{mof.sport}-{mof.daddr}:{mof.dport}", true); } + private void OnUdpIpRecv(UdpIpTraceData mof) { ProcessNetworkPacket(mof.ProcessID, mof.size, $"{mof.saddr}:{mof.sport}-{mof.daddr}:{mof.dport}", false); } + private void OnUdpIpRecvIPV6(UpdIpV6TraceData mof) { ProcessNetworkPacket(mof.ProcessID, mof.size, $"{mof.saddr}:{mof.sport}-{mof.daddr}:{mof.dport}", false); } + private void ProcessNetworkPacket(in int ProcessID, in int Size, in string Hash, in bool isSent) { + if (Size <= 0) return; + /* Common for all Network Events, just prepare */ + if (ProcessID > 0 && !_AllStats.ContainsKey(ProcessID)) _AllStats.Add(ProcessID, new EtwStats()); + if (!_NetStats.ContainsKey(Hash)) _NetStats.Add(Hash, new EtwNetStats()); + + if (isSent) { + /* Compute to NetSent */ + _AllStats[0].NetSent += (uint)Size; + if (ProcessID > 0) _AllStats[ProcessID].NetSent += (uint)Size; + _NetStats[Hash].Sent += (uint)Size; + } else { + /* Compute to NetReceived */ + _AllStats[0].NetReceived += (uint)Size; + if (ProcessID > 0) _AllStats[ProcessID].NetReceived += (uint)Size; + _NetStats[Hash].Received += (uint)Size; + + } + + } + + public class EtwStats { + public ulong DiskReaded = 0; + public ulong DiskWroted = 0; + public ulong NetSent = 0; + public ulong NetReceived = 0; + } + public class EtwDiskStats { + public ulong Readed = 0; + public ulong Wroted = 0; + } + public class EtwNetStats { + public ulong Sent = 0; + public ulong Received = 0; + } + +} \ No newline at end of file diff --git a/src/Classes/TaskManagerProcess.cs b/src/Classes/TaskManagerProcess.cs index 293eca2..d640c86 100644 --- a/src/Classes/TaskManagerProcess.cs +++ b/src/Classes/TaskManagerProcess.cs @@ -257,11 +257,11 @@ public void Update(API.SYSTEM_PROCESS_INFORMATION spi, in HashSet vv, bo if (vv.Contains("VirtualMemoryPeak")) VirtualMemoryPeakValue = spi.PeakVirtualSize; // I/O Counters Values if (vv.Contains("ReadTransfer") || vv.Contains("ReadTransferDelta")) { - ReadTransferDeltaValue = (ReadTransferValue == 0) ? 0 : spi.ReadTransferCount - ReadTransferValue; + ReadTransferDeltaValue = (ReadTransferValue == 0) ? 0 : spi.ReadTransferCount - ReadTransferValue; ReadTransferValue = spi.ReadTransferCount; } if (vv.Contains("ReadOperations") || vv.Contains("ReadOperationsDelta")) { - ReadOperationsDeltaValue = (ReadOperationsValue == 0) ? 0 : spi.ReadOperationCount - ReadOperationsValue; + ReadOperationsDeltaValue = (ReadOperationsValue == 0) ? 0 : spi.ReadOperationCount - ReadOperationsValue; ReadOperationsValue = spi.ReadOperationCount; } if (vv.Contains("WriteTransfer") || vv.Contains("WriteTransferDelta")) { @@ -281,25 +281,25 @@ public void Update(API.SYSTEM_PROCESS_INFORMATION spi, in HashSet vv, bo OtherOperationsValue = spi.OtherOperationCount; } // ETW Data Values, if running - if (ETW.Running) { + if (Shared.ETW.Running) { if (vv.Contains("DiskRead") || vv.Contains("DiskReadDelta") || vv.Contains("DiskReadRate")) { - DiskReadDeltaValue = (DiskReadValue == 0) ? 0 : ETW.Stats(_PID).DiskReaded - DiskReadValue; - DiskReadValue = ETW.Stats(_PID).DiskReaded; + DiskReadDeltaValue = (DiskReadValue == 0) ? 0 : Shared.ETW.Stats(_PID).DiskReaded - DiskReadValue; + DiskReadValue = Shared.ETW.Stats(_PID).DiskReaded; DiskReadRateValue = CalculateRateValue(DiskReadDeltaValue); } if (vv.Contains("DiskWrite") || vv.Contains("DiskWriteDelta") || vv.Contains("DiskWriteRate")) { - DiskWriteDeltaValue = (DiskWriteValue == 0) ? 0 : ETW.Stats(_PID).DiskWroted - DiskWriteValue; - DiskWriteValue = ETW.Stats(_PID).DiskWroted; + DiskWriteDeltaValue = (DiskWriteValue == 0) ? 0 : Shared.ETW.Stats(_PID).DiskWroted - DiskWriteValue; + DiskWriteValue = Shared.ETW.Stats(_PID).DiskWroted; DiskWriteRateValue = CalculateRateValue(DiskWriteDeltaValue); } if (vv.Contains("NetSent") || vv.Contains("NetSentDelta") || vv.Contains("NetSentRate")) { - NetSentDeltaValue = (NetSentValue == 0) ? 0 : ETW.Stats(_PID).NetSent - NetSentValue; - NetSentValue = ETW.Stats(_PID).NetSent; + NetSentDeltaValue = (NetSentValue == 0) ? 0 : Shared.ETW.Stats(_PID).NetSent - NetSentValue; + NetSentValue = Shared.ETW.Stats(_PID).NetSent; NetSentRateValue = CalculateRateValue(NetSentDeltaValue); } if (vv.Contains("NetReceived") || vv.Contains("NetReceivedDelta") || vv.Contains("NetReceivedRate")) { - NetRcvdDeltaValue = (NetRcvdValue == 0) ? 0 : ETW.Stats(_PID).NetReceived - NetRcvdValue; - NetRcvdValue = ETW.Stats(_PID).NetReceived; + NetRcvdDeltaValue = (NetRcvdValue == 0) ? 0 : Shared.ETW.Stats(_PID).NetReceived - NetRcvdValue; + NetRcvdValue = Shared.ETW.Stats(_PID).NetReceived; NetRcvdRateValue = CalculateRateValue(NetRcvdDeltaValue); } } @@ -492,7 +492,7 @@ private static bool imSuspended(in API.SYSTEM_EXTENDED_THREAD_INFORMATION[] Thre private ulong CalculateRateValue(in ulong DeltaValue) { if (DeltaValue == 0) return 0; if ((LastUpdated - PreviousUpdate) <= 0) return DeltaValue; - return DeltaValue / (ulong)(LastUpdated - PreviousUpdate) / TimeSpan.TicksPerSecond; + return (ulong)Math.Round(DeltaValue / ((double)(LastUpdated - PreviousUpdate) / TimeSpan.TicksPerSecond)); } /* Public Static Methods */ diff --git a/src/Classes/TaskManagerSystem.cs b/src/Classes/TaskManagerSystem.cs index ec397fe..e6005f0 100644 --- a/src/Classes/TaskManagerSystem.cs +++ b/src/Classes/TaskManagerSystem.cs @@ -80,12 +80,12 @@ public void Refresh(bool cancellingEvents = false) { CpuUsageKernel.SetValue(_Cpu.KernelUsage); // Compute ETW Usages - if (ETW.Running) { - ETW.Flush(); - DiskRead.SetValue(ETW.Stats(0).DiskReaded); - DiskWrite.SetValue(ETW.Stats(0).DiskWroted); - NetSent.SetValue(ETW.Stats(0).NetSent); - NetReceived.SetValue(ETW.Stats(0).NetReceived); + if (Shared.ETW.Running) { + Shared.ETW.Flush(); + DiskRead.SetValue(Shared.ETW.Stats(0).DiskReaded); + DiskWrite.SetValue(Shared.ETW.Stats(0).DiskWroted); + NetSent.SetValue(Shared.ETW.Stats(0).NetSent); + NetReceived.SetValue(Shared.ETW.Stats(0).NetReceived); } LastUpdate = DateTime.Now.Ticks; diff --git a/src/Forms/frmMain.cs b/src/Forms/frmMain.cs index 56f3b5b..fbdd462 100644 --- a/src/Forms/frmMain.cs +++ b/src/Forms/frmMain.cs @@ -115,7 +115,7 @@ private void OnLoadParallelInit(object? sender, DoWorkEventArgs e) { Stopwatch sw = new(); Extensions.StartMeasure(sw); // We should use this to initialize something that is not really critical? - ETW.Start(); + Shared.ETW.Start(); if (Shared.PrivateMsgID == 0) Shared.PrivateMsgID = API.RegisterWindowMessage(Application.ExecutablePath.Replace("\\", "_")); // if (Shared.AddPrivilege("SeDebugPrivilege")) Debug.WriteLine("SeDebugPrivilege Set"); Shared.InitComplete = true; @@ -186,7 +186,7 @@ private void OnClosingEventHandler(object sender, FormClosingEventArgs e) { // If monitor is running we must stop it right now... if (MonitorRunning) MonitorToggle(); if (_TrayUpdateTimer.Enabled) { _TrayUpdateTimer.Stop(); } - if (ETW.Running) ETW.Stop(); + if (Shared.ETW.Running) Shared.ETW.Stop(); // Save Window Position & Tab... if (Settings.RememberPositions) { if (WindowState == FormWindowState.Normal) { diff --git a/src/Forms/tabPerformance.cs b/src/Forms/tabPerformance.cs index eb4ede1..531e46e 100644 --- a/src/Forms/tabPerformance.cs +++ b/src/Forms/tabPerformance.cs @@ -1368,7 +1368,7 @@ private void System_RefreshCompleted(object? sender, EventArgs e) { meterNet.SetValue(System.NetworkUsage, System.NetworkUsageString); chartNet.AddValue((double)System.NetReceived.Delta / 1024, (double)System.NetSent.Delta / 1024); // Always flush the ETW, if its active. - ETW.Flush(); + Shared.ETW.Flush(); } private bool FullScreen { diff --git a/src/Properties/AssemblyInfo.cs b/src/Properties/AssemblyInfo.cs index 2425c78..63f3962 100644 --- a/src/Properties/AssemblyInfo.cs +++ b/src/Properties/AssemblyInfo.cs @@ -16,8 +16,8 @@ [assembly: AssemblyConfiguration("Release")] #endif -[assembly: AssemblyVersion(".*")] -[assembly: AssemblyFileVersion("")] -[assembly: AssemblyInformationalVersion("")] -[assembly: GitCommit("")] -[assembly: BuildMark("1689993956")] +[assembly: AssemblyVersion("3.0.23.*")] +[assembly: AssemblyFileVersion("3.0.23")] +[assembly: AssemblyInformationalVersion("3.0.23")] +[assembly: GitCommit("gbbd4da60103107ed521589bf532f26c2a6ffe16e")] +[assembly: BuildMark("1690074458")] diff --git a/src/sMkTaskManager.csproj b/src/sMkTaskManager.csproj index 7e35c0e..442a69f 100644 --- a/src/sMkTaskManager.csproj +++ b/src/sMkTaskManager.csproj @@ -28,10 +28,6 @@ true Copyright © sMkDesigns 3.0.0 - false app.manifest sMkTaskManager.ico @@ -42,11 +38,14 @@ $([System.DateTime]::UtcNow.Ticks) + + @@ -55,6 +54,7 @@ True \ + True \