vdi-cloud/tools/input-latency-bench.ps1

86 lines
3.8 KiB
PowerShell

# Temporary interactive test window; exits after ten minutes. No system settings.
$ErrorActionPreference = 'Stop'
$benchDir = 'C:\ProgramData\VDI\input-bench-20261103'
New-Item -ItemType Directory -Force $benchDir | Out-Null
Set-Content -LiteralPath "$benchDir\pid.txt" -Value $PID
Add-Type -ReferencedAssemblies System.Windows.Forms,System.Drawing -TypeDefinition @'
using System;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Runtime.InteropServices;
using System.Windows.Forms;
public class VDIInputBenchForm : Form {
[DllImport("user32.dll")] public static extern bool SetProcessDPIAware();
[DllImport("winmm.dll")] public static extern uint timeBeginPeriod(uint period);
[DllImport("winmm.dll")] public static extern uint timeEndPeriod(uint period);
readonly Stopwatch watch = Stopwatch.StartNew();
readonly Timer timer = new Timer();
readonly string folder;
int paints, clicks;
long lastReport;
long lastFrameIndex = -1;
public VDIInputBenchForm(string path) {
folder = path;
Text = "VDI Input Latency Bench";
FormBorderStyle = FormBorderStyle.None;
Bounds = Screen.PrimaryScreen.Bounds;
TopMost = true;
DoubleBuffered = true;
File.WriteAllText(Path.Combine(folder,"clicks.csv"), "ms,x,y,target\n");
// A WinForms 16ms timer can quantize to ~31ms at the default timer
// resolution and accidentally cap the *source* at 32FPS. Pace by an
// absolute monotonic frame index, not accumulated timer ticks.
timer.Interval = 1;
timer.Tick += delegate {
if(watch.Elapsed.TotalMinutes >= 10) { Close(); return; }
long frameIndex = watch.ElapsedTicks * 60 / Stopwatch.Frequency;
if(frameIndex != lastFrameIndex) { lastFrameIndex = frameIndex; Invalidate(); }
};
timer.Start();
}
protected override void OnMouseDown(MouseEventArgs e) {
base.OnMouseDown(e);
string target = e.X < Width/2 ? "L" : "R";
File.AppendAllText(Path.Combine(folder,"clicks.csv"),
watch.ElapsedMilliseconds+","+e.X+","+e.Y+","+target+"\n");
++clicks;
Invalidate();
}
protected override void OnPaint(PaintEventArgs e) {
base.OnPaint(e);
long ms = watch.ElapsedMilliseconds;
e.Graphics.Clear(Color.FromArgb(16,24,39));
using(Brush left = new SolidBrush(Color.FromArgb(35,85,130)))
using(Brush right = new SolidBrush(Color.FromArgb(50,115,90))) {
e.Graphics.FillRectangle(left,50,180,Width/2-100,Height-260);
e.Graphics.FillRectangle(right,Width/2+50,180,Width/2-100,Height-260);
}
int x = (int)((ms*0.6)%(Width+100))-100;
e.Graphics.FillRectangle(Brushes.Gold,x,0,60,Height);
using(Font font = new Font("Consolas",24)) {
e.Graphics.DrawString("VDI test: moving bars + ordered clicks | "+clicks+" clicks | "+ms+" ms",
font,Brushes.White,70,40);
e.Graphics.DrawString("LEFT",font,Brushes.White,Width/4-50,Height/2);
e.Graphics.DrawString("RIGHT",font,Brushes.White,Width*3/4-50,Height/2);
}
++paints;
if(ms-lastReport>=1000) {
File.WriteAllText(Path.Combine(folder,"status.txt"),
"width="+Width+" height="+Height+" paints="+paints+" elapsed_ms="+ms+" clicks="+clicks);
lastReport=ms;
}
}
protected override void OnFormClosed(FormClosedEventArgs e) {
timer.Stop(); timer.Dispose(); base.OnFormClosed(e);
}
}
'@
[VDIInputBenchForm]::SetProcessDPIAware() | Out-Null
$timerResult=[VDIInputBenchForm]::timeBeginPeriod(1)
try {
[System.Windows.Forms.Application]::Run((New-Object VDIInputBenchForm($benchDir)))
} finally {
if($timerResult -eq 0) { [VDIInputBenchForm]::timeEndPeriod(1) | Out-Null }
}