Skip to content

Commit

Permalink
Merge pull request #47 from Danil0v3s/feat/select-specific-app-to-mon…
Browse files Browse the repository at this point in the history
…itor-fps

[Feat] Select specific app to monitor via packets
  • Loading branch information
Danil0v3s authored Dec 28, 2024
2 parents e2e2315 + 22de350 commit 7574ab3
Show file tree
Hide file tree
Showing 20 changed files with 558 additions and 181 deletions.
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 @@ namespace HardwareMonitor.PresentMon;

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 @@ private void ParseData(string? argsData)
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 @@ private void ParseData(string? argsData)
}
}
}

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

0 comments on commit 7574ab3

Please sign in to comment.