Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Feat] Select specific app to monitor via packets #47

Merged
merged 1 commit into from
Dec 28, 2024
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
2 changes: 1 addition & 1 deletion .idea/runConfigurations/Run.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

13 changes: 13 additions & 0 deletions .idea/runConfigurations/Run_Standalone.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions HardwareMonitor/HardwareMonitor.sln.DotSettings.user
Original file line number Diff line number Diff line change
@@ -1,15 +1,18 @@
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AAction_00601_002Ecs_002Fl_003AC_0021_003FUsers_003Fdanil_003FAppData_003FRoaming_003FJetBrains_003FRider2024_002E3_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003Ffba9afd29efa49229d2dd911da0bdfedc8e910_003Fe6_003F851b45a1_003FAction_00601_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AAmd17Cpu_002Ecs_002Fl_003AC_0021_003FUsers_003Fdanil_003FAppData_003FRoaming_003FJetBrains_003FRider2024_002E2_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F7ce99d66e0c4488baa8ef8a4beb4c59eae000_003Ffa_003F18274e17_003FAmd17Cpu_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ABuffer_002Ecs_002Fl_003AC_0021_003FUsers_003Fdanil_003FAppData_003FRoaming_003FJetBrains_003FRider2024_002E2_003Fresharper_002Dhost_003FSourcesCache_003F6375e241186795c6c5ff2bdf1cdd7c9e0327f3b63f6fd16d6d06faf6d37fa_003FBuffer_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AComputer_002Ecs_002Fl_003AC_0021_003FUsers_003Fdanil_003FAppData_003FRoaming_003FJetBrains_003FRider2024_002E2_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003Fafcef64ae101438f8581177d18475e38a3400_003Fab_003F3c9b3ea6_003FComputer_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ADoubleToStringConverter_002Ecs_002Fl_003AC_0021_003FUsers_003Fdanil_003FAppData_003FRoaming_003FJetBrains_003FRider2024_002E2_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003Fbefafc39799c412db202c2e0b3c3d94e3a000_003Fef_003Fde50756f_003FDoubleToStringConverter_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AExceptionDispatchInfo_002Ecs_002Fl_003AC_0021_003FUsers_003Fdanil_003FAppData_003FLocal_003FSymbols_003Fsrc_003Fdotnet_003Fruntime_003F1381d5ebd2ab1f292848d5b19b80cf71ac332508_003Fsrc_003Flibraries_003FSystem_002EPrivate_002ECoreLib_003Fsrc_003FSystem_003FRuntime_003FExceptionServices_003FExceptionDispatchInfo_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AHardwareType_002Ecs_002Fl_003AC_0021_003FUsers_003Fdanil_003FAppData_003FRoaming_003FJetBrains_003FRider2024_002E2_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003Fafcef64ae101438f8581177d18475e38a3400_003F31_003F89b876a3_003FHardwareType_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AIdentifier_002Ecs_002Fl_003AC_0021_003FUsers_003Fdanil_003FAppData_003FRoaming_003FJetBrains_003FRider2024_002E2_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003Fafcef64ae101438f8581177d18475e38a3400_003F59_003F88686da1_003FIdentifier_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AIHardware_002Ecs_002Fl_003AC_0021_003FUsers_003Fdanil_003FAppData_003FRoaming_003FJetBrains_003FRider2024_002E2_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003Fafcef64ae101438f8581177d18475e38a3400_003F3e_003F8bdf4f5c_003FIHardware_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AIJsonTypeInfoResolver_002Ecs_002Fl_003AC_0021_003FUsers_003Fdanil_003FAppData_003FRoaming_003FJetBrains_003FRider2024_002E2_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F1144f5ec01aa4ebc8b74028bf382599c16e8a0_003Fe9_003Faf4463c8_003FIJsonTypeInfoResolver_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AISensor_002Ecs_002Fl_003AC_0021_003FUsers_003Fdanil_003FAppData_003FRoaming_003FJetBrains_003FRider2024_002E2_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F7ce99d66e0c4488baa8ef8a4beb4c59eae000_003F76_003F1acc4d79_003FISensor_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AISensor_002Ecs_002Fl_003AC_0021_003FUsers_003Fdanil_003FAppData_003FRoaming_003FJetBrains_003FRider2024_002E2_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003Fafcef64ae101438f8581177d18475e38a3400_003F81_003Fd37651c2_003FISensor_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AMemoryMappedFile_002EWindows_002Ecs_002Fl_003AC_0021_003FUsers_003Fdanil_003FAppData_003FRoaming_003FJetBrains_003FRider2024_002E2_003Fresharper_002Dhost_003FSourcesCache_003Fd717a8d9efed27fe3f87ab2b46d49bf8b8d7dd80c0d1a0c5a6f081ecbd9ccf_003FMemoryMappedFile_002EWindows_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AProcess_002Ecs_002Fl_003AC_0021_003FUsers_003Fdanil_003FAppData_003FRoaming_003FJetBrains_003FRider2024_002E3_003Fresharper_002Dhost_003FSourcesCache_003F272f7fa8ba8fe1496a488d5eda2dbd4f6cd182c1430c3cc7822b83dbf64b4b2_003FProcess_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ASensorType_002Ecs_002Fl_003AC_0021_003FUsers_003Fdanil_003FAppData_003FRoaming_003FJetBrains_003FRider2024_002E2_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003Fafcef64ae101438f8581177d18475e38a3400_003F77_003F28607699_003FSensorType_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ASocket_002Ecs_002Fl_003AC_0021_003FUsers_003Fdanil_003FAppData_003FRoaming_003FJetBrains_003FRider2024_002E2_003Fresharper_002Dhost_003FSourcesCache_003Fa299e1779ad4b8e88e2383ff219277767d32c7c4392d57de46e8332aec9a3d52_003FSocket_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AUnmanagedMemoryStream_002Ecs_002Fl_003AC_0021_003FUsers_003Fdanil_003FAppData_003FRoaming_003FJetBrains_003FRider2024_002E2_003Fresharper_002Dhost_003FSourcesCache_003F93f64a5821368f576c3fdae17ec5bbecad44d4b5e7ce1183336072c9fa859033_003FUnmanagedMemoryStream_002Ecs/@EntryIndexedValue">ForceIncluded</s:String></wpf:ResourceDictionary>
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
namespace HardwareMonitor.Monitor;

public enum MonitorPacketCommand : short
{
Data = 0,
RefreshPresentMonApps = 1,
SelectPresentMonApp = 2,
PresentMonApps = 3,
}
61 changes: 60 additions & 1 deletion HardwareMonitor/HardwareMonitor/Monitor/MonitorPoller.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,10 @@ protected override async Task ExecuteAsync(CancellationToken stoppingToken)

_computer.Open();
_computer.Accept(new UpdateVisitor());
_presentMonPoller.Start();
_presentMonPoller.Start(stoppingToken);
_socketHost.StartServer();
_socketHost.onClientData += OnClientData;
_socketHost.onClientConnected += OnClientConnected;

var sharedMemoryData = QueryHardwareData();

Expand All @@ -46,6 +48,7 @@ protected override async Task ExecuteAsync(CancellationToken stoppingToken)
using var writer = new BinaryWriter(memoryStream);
var accumulator = 0;

writer.Write((short)MonitorPacketCommand.Data);
writer.Write(sharedMemoryData.Hardwares.Count);
writer.Write(sharedMemoryData.Sensors.Count);

Expand Down Expand Up @@ -97,6 +100,7 @@ protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
GC.Collect();
accumulator = 0;
SendPresentMonAppsToClients();
}

accumulator += 500;
Expand All @@ -107,6 +111,60 @@ protected override async Task ExecuteAsync(CancellationToken stoppingToken)
hostApplicationLifetime.StopApplication();
}

private void OnClientConnected()
{
SendPresentMonAppsToClients();
}

private void OnClientData(byte[] data)
{
var cmd = (MonitorPacketCommand) BitConverter.ToInt16(data, 0);
logger.LogInformation("Received command from client: {Command}", cmd);
switch (cmd)
{
case MonitorPacketCommand.RefreshPresentMonApps:
SendPresentMonAppsToClients();
break;
case MonitorPacketCommand.SelectPresentMonApp:
SelectPresentMonApp(data);
break;

// server -> client cases
case MonitorPacketCommand.Data:
case MonitorPacketCommand.PresentMonApps:
break;
default:
throw new ArgumentOutOfRangeException();
}
}

private void SelectPresentMonApp(byte[] data)
{
// start at 2 because the first 2 were the command
var size = BitConverter.ToInt16(data, 2);
var appName = Encoding.UTF8.GetString(data, 4, size);
_presentMonPoller.SetSelectedApp(appName);
}

private void SendPresentMonAppsToClients()
{
using var memoryStream = new MemoryStream();
using var writer = new BinaryWriter(memoryStream);

writer.Write((short)MonitorPacketCommand.PresentMonApps);
//logger.LogInformation("Sending presentmon apps to clients {Count}", _presentMonPoller.CurrentApps.Count);
writer.Write((short)_presentMonPoller.CurrentApps.Count);
foreach (var app in _presentMonPoller.CurrentApps)
{
writer.Write(GetBytes(app, SharedMemoryConsts.NameSize));
}

if (_socketHost.HasConnections())
{
_socketHost.SendToAll(memoryStream.ToArray());
}
}

private SharedMemoryData QueryHardwareData()
{
var hardwareList = new List<SharedMemoryHardware>();
Expand Down Expand Up @@ -155,6 +213,7 @@ private void Stop()
_computer.Close();
_presentMonPoller.Stop();
_socketHost.Close();
_socketHost.onClientData -= OnClientData;
}

private static SharedMemoryHardware MapHardware(IHardware hardware) => new()
Expand Down
71 changes: 63 additions & 8 deletions HardwareMonitor/HardwareMonitor/PresentMon/PresentMonPoller.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,45 +7,58 @@

public class PresentMonPoller(ILogger logger)
{
private const string NO_SELECTED_APP = "NONE";

private IHardware _hardware = new PresentMonHardware();
public PresentMonSensor Displayed { get; private set; }

Check warning on line 13 in HardwareMonitor/HardwareMonitor/PresentMon/PresentMonPoller.cs

View workflow job for this annotation

GitHub Actions / build

Non-nullable property 'Displayed' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the property as nullable.
public PresentMonSensor Presented { get; private set; }

Check warning on line 14 in HardwareMonitor/HardwareMonitor/PresentMon/PresentMonPoller.cs

View workflow job for this annotation

GitHub Actions / build

Non-nullable property 'Presented' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the property as nullable.
public PresentMonSensor Frametime { get; private set; }

Check warning on line 15 in HardwareMonitor/HardwareMonitor/PresentMon/PresentMonPoller.cs

View workflow job for this annotation

GitHub Actions / build

Non-nullable property 'Frametime' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the property as nullable.
public HashSet<string> CurrentApps { get; private set; }

Check warning on line 16 in HardwareMonitor/HardwareMonitor/PresentMon/PresentMonPoller.cs

View workflow job for this annotation

GitHub Actions / build

Non-nullable property 'CurrentApps' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the property as nullable.

private Process _process;
private CultureInfo _cultureInfo = (CultureInfo)CultureInfo.CurrentCulture.Clone();

public async void Start()
private string _currentSelectedApp = NO_SELECTED_APP;


public async void Start(CancellationToken stoppingToken)
{
_cultureInfo.NumberFormat.NumberDecimalSeparator = ".";

Displayed = new PresentMonSensor(_hardware, "displayed", 0, "Displayed Frames");
Presented = new PresentMonSensor(_hardware, "presented", 1, "Presented Frames");
Frametime = new PresentMonSensor(_hardware, "frametime", 2, "Frametime");
CurrentApps = [];

using var reader = new StreamReader(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "presentmon", "ignored-processes.txt"));
var text = await reader.ReadToEndAsync();
var processes = text
using var reader = new StreamReader(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "presentmon",
"ignored-processes.txt"));
var text = (await reader.ReadToEndAsync())
.Split("\n", StringSplitOptions.RemoveEmptyEntries)
.Select(x => $"--exclude {x.Trim()}");
var filteredApps = string.Join(" ", text);

await TerminateCurrentPresentMon();
var processStartInfo = new ProcessStartInfo
{
CreateNoWindow = true,
RedirectStandardOutput = true,
RedirectStandardError = true,
UseShellExecute = false,
FileName = "presentmon\\presentmon.exe",
Arguments = $"--stop_existing_session --no_console_stats --output_stdout {string.Join(' ', processes)}"
Arguments = $"--stop_existing_session --no_console_stats --output_stdout --session_name HardwareMonitor {filteredApps}",
};
logger.LogInformation("Starting PresentMon process with {Arguments}", processStartInfo.Arguments);

_process = new Process();
_process.StartInfo = processStartInfo;

_process.OutputDataReceived += (sender, args) => ParseData(args.Data);
_process.Exited += (sender, args) => Start();
_process.ErrorDataReceived += (sender, args) => logger.LogError(args.Data);

_process.Start();
_process.BeginOutputReadLine();
_process.BeginErrorReadLine();

ClearCurrentAppsAsync(stoppingToken);
await _process.WaitForExitAsync();
}

Expand All @@ -60,6 +73,13 @@
if (argsData != null)
{
parts = argsData.Split(",");
CurrentApps.Add(parts[0]);

if (_currentSelectedApp != NO_SELECTED_APP && _currentSelectedApp != parts[0])
{
return;
}

if (float.TryParse(parts[9], NumberStyles.Any, _cultureInfo, out var frametime))
{
Frametime.Value = frametime;
Expand All @@ -76,4 +96,39 @@
}
}
}

public void SetSelectedApp(string appName)
{
if (appName == "Auto") {
_currentSelectedApp = NO_SELECTED_APP;
return;
}
_currentSelectedApp = appName;
}
private async Task TerminateCurrentPresentMon()
{
var processStartInfo = new ProcessStartInfo
{
CreateNoWindow = true,
RedirectStandardOutput = true,
RedirectStandardError = true,
UseShellExecute = false,
FileName = "presentmon\\presentmon.exe",
Arguments = $"--terminate_existing_session --no_console_stats --output_stdout --session_name HardwareMonitor",
};
logger.LogInformation("Starting PresentMon process with {Arguments}", processStartInfo.Arguments);

var process = new Process();
process.StartInfo = processStartInfo;
process.Start();
await process.WaitForExitAsync();
}

private async Task ClearCurrentAppsAsync(CancellationToken cancellationToken)
{
if (cancellationToken.IsCancellationRequested) return;
await Task.Delay(10_000, cancellationToken);
CurrentApps.Clear();
ClearCurrentAppsAsync(cancellationToken);
}
}
2 changes: 1 addition & 1 deletion HardwareMonitor/HardwareMonitor/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "LogFiles",
$"{DateTime.Now.Year}-{DateTime.Now.Month}-{DateTime.Now.Day}", "Log.txt"),
rollingInterval: RollingInterval.Infinite,
outputTemplate: "[{Timestamp:yyyy-MM-dd HH:mm:ss.fff} [{Level}] {Message}{NewLine}{Exception}")
outputTemplate: "[{Timestamp:yyyy-MM-dd HH:mm:ss.fff}] [{Level}] {Message}{NewLine}{Exception}")
.WriteTo.Console()
);

Expand Down
Loading
Loading