用光传感器测量键盘到光子的延迟

2020-05-31 23:38:52

很长一段时间以来,当我想测试电脑和UI的延迟时,我一直在iPhone的高速摄像头上使用is it snappy应用程序来计算从我按下一个键到屏幕变化之间的帧数。然而,这样做的问题是需要一段时间才能找到您想要的确切帧,这在进行大量测试时很烦人。这也使得很难找出延迟的可变性是什么样子。我已经在我的键盘固件中添加了一种模式,可以在发送USB事件后改变LED的颜色,从而使这类测试变得更容易,但这只会让它更快、更精确。我想要更好的东西。

因此,我追随我的朋友拉斐尔的脚步,做了一个硬件延迟测试器,它可以发送键盘事件,然后使用光传感器来测量屏幕改变所需的时间!这相当简单,在这篇文章中,我将回顾我发现的一些延迟结果,讨论为什么好的延迟测试是棘手的,并解释如何构建您自己的延迟测试器。

基本上,我的潜伏期测试仪是一个来自亚马逊的光传感器模块,由一个连接到一个小小的lc微控制器上的可调支架臂固定,该控制器按下“a”键,等待光线水平改变,然后删除它,只要按住一个按钮,就会继续采集样本。然后,只需短按一个按钮,它就会输入一个漂亮的延迟直方图,如下所示:

后者i=60.3+/-9.3,a=60,d=59(n=65,q=41)|239_|。

这一行告诉我插入(i=)、删除(d=)和两者加在一起的平均延迟(a=)、插入时间的标准偏差(+/-)、测量计数(n=)和质量(q=),以及一个小的ASCII直方图,其中每个字符都是一个10ms的桶,数字按比例表示桶有多满。_表示一个桶,它至少有一个样本,但不足以至少是顶部桶的九分之一,所以我可以看到尾部延迟。下面是它的样子(用肖像监视器拍照,但所有的测试都是在风景中进行的):

我也这样做了,如果您再次按下按钮,它将输入所有原始测量结果,如[35,35,33,44],这样您就可以进行自定义绘图:

两台4k显示器支持超凡文本、MacOS、无分心全屏模式:lat i=35.3+/-4.7、a=36、d=36(n=67,q=99)|193|Dell P2415Q桌面i=52.9+/-5.0、a=53、d=54(n=66、q=45)|_391|Dell P2415Q Bottomlat i=65.1+/-5.0、a=64、d=63(n=109、。q=114)|89_|HP Z27底部。

首先,我喜欢单行固定宽度的直方图格式,它允许我在文本文件中将结果一个接一个地放在一起,并将它们标记到右侧以供比较。

我们可以看到,在60 Hz的帧中,每个监视器顶部和底部的延迟与扫描出行所需的时间之间的预期差异为16ms。

标准偏差仅仅是4.6ms,这是由于未与16ms显示刷新周期对齐而产生的均匀分布的方差所固有的。

HP Z27比Dell P2415Q慢约30ms!这是从可以检测到变化的开始进行衡量的,我非常肯定Z27也需要更长的时间才能完全过渡。有了Z27和Sublime,我几乎一半的端到端延迟是显示器不必要的延迟!

本文其余部分的所有测量均相应地在我的Dell P2415Q上进行。两个监视器都将响应时间设置为“快速”,Z27的响应时间设置甚至更高,但它们只影响过渡时间,并引入难看的鬼影跟踪,而不会帮助初始延迟。

实际上,进行良好的延迟测量比您想象的要困难得多。我比大多数人更努力地尝试获得现实的测量结果,但在头几次我必须修复的方式上仍然失败了。

首先,使用硬件延迟测试仪的原因是有许多不完整或可能具有欺骗性的方法来测量端到端延迟。

有一篇非常优秀的著名博客文章,名为“快乐打字”,它用良好的分析和漂亮的图表比较了不同操作系统上不同文本编辑器的延迟。但是,它通过使用OSAPI模拟输入事件和屏幕抓取来实现这一点。我没有与他做任何重叠的测量,所以不能指出任何特别的错误,但这有很多潜在的问题。例如,检查CPU上的屏幕缓冲区可能会不适当地惩罚GPU渲染的应用程序,因为在某些捕获可能起作用的方式下,窗口缓冲区副本可能会影响GPU渲染的应用程序。模拟输入可能会遇到与实际输入不同的路径。无论如何,即使它给出了相当不错的相对测量结果(如果没有根据端到端测试进行验证,您就无法真正知道),它也不能告诉您用户的全部延迟体验。

用户体验到的延迟来源之一是键盘延迟,这是我的测试仪没有测量到的。由于8ms的USB轮询间隔、较低的键盘网格扫描速率、较慢的固件,以及更有争议的不同机械设计,许多键盘可能会引入比我整个键盘到光子的延迟(包括我过去的键盘)更多的延迟。

您不能只使用任何可以模拟键盘的微控制器来构建低方差延迟测试器,因为它们可能使用默认的125 Hz轮询。幸运的是,我的首选微控制器是少数几个默认为1000 Hz的LC之一。

在我建造了我的延迟测试器之后,我第一次没有任何信号强度的测量。最终,我被一些略微不同的场景中的一些测量结果搞糊涂了,因为相同的应用程序和屏幕的结果截然不同。我做了一些测试,发现有时使用小字体或传感器放置不当,屏幕内容的变化只能勉强检测到,所以我会一直测量,直到显示器完成转换,而通常我测量到显示器开始转换(这是它自己微妙的主观测量选择)。

我知道要怀疑过渡时间,因为在我编写固件之前,我只是每毫秒采样一次光传感器,并在我键入并退格一个字母时使用Arduino串行绘图仪绘制测量结果,只是为了看看信号是什么样子。您可以看到,光传感器和监视器的某些组合需要近100ms才能完全过渡。基于拍摄的是不是很快,我的Z27似乎只需要20ms左右的时间就可以感知到完成屏幕的过渡。

为了避免这种情况,我在完全转换到我的输出之后添加了峰峰值信号强度测量,这样我就可以确保我的5步阈值在接近转换开始时获得了足够的分辨率。这些是你在q=之后看到的数字。我了解到保持大字体和高屏幕亮度设置很重要。

在测量的内容中,看似很小的差异可能会在延迟方面产生明显的差异。例如,我想看看Sublime和VSCode在纯文本突出显示的小文件上的延迟与在具有复杂突出显示语法和自动完成弹出窗口的大文件上的延迟是否有显着差异。当然有,但是在注意到一些可变性之后,我做了更多的测试,发现在空行上键入‘a’和在现有的‘a’(‘aa’)之后键入‘a’之间的延迟有明显的不同。

这是在6199个巨大的parser.rs中的第3469行之后的新行的结果,所有这些都是用类似的传感器位置拍摄的,位置在我的戴尔显示器下面,比最上面的位置更低。

后i=40.2+/-4.1,a=40,d=39(n=38,q=90)|_89|最小.txtlat i=41.2+/-6.9,a=41,d=42(n=54,q=92)|992|最高AA parser.rslat i=43.6+/-6.1,a=43,d=42(n=48,q=100)|492|lat i=52.2+/-6.0,a。d=42(n=45,q=100)|391|lat i=42.7+/-7.6,a=42,d=42(n=46,q=100)|_491|lat i=48.1+/-6.8,a=49,d=50(n=43,q=89)|269|崇高a parser.rslat i=43.9+/-5.4,a=48,d=52(n=32,q=97)|197|lat i。a=47,d=49(n=42,q=97)|196_|lat i=63.3+/-9.3,a=63,d=62(n=68,q=118)|_963__|vscode AA parser.rslat i=63.6+/-7.6,a=64,d=65(n=71,q=139)|_49_|lat i=62.3+/-6.3,a=61,d=59(n=52,q=111)|_49_|lat i=61.9+/-9.7,a=62,d=61(n=35,q=111)|981_|lat i=53.1+/-7.7,a=51,d=49(n=54,q=116)|_79__|vscode a parser.rslat i=52.2+/-6.3,a=52,d=51(n=41,q=133)|692|lat i=53.2。D=52(n=55,q=134)|591_|。

为了确认效果,我在不同的时间进行了一系列的运行,只做了一些微小的改动,你可以看到,在同一场景下的测量结果之间存在差异,但在现有的“a”之后只键入“a”和添加“a”之间的差异明显更大。请尝试查看‘a=’列,因为它同时包含插入和删除度量,因此交叉运行噪声最小。Suplime在‘aa’比‘a’快,VSCode在‘a’比‘aa’快。

在这两个编辑器中,‘aa’会导致自动完成弹出窗口在两个列表之间交替,而‘a’会导致它出现和消失。我可以猜到Sublime在‘a’的情况下可能会慢一些,因为打开和关闭自动完成弹出窗口是有成本的,但我没有一个强有力的假设来解释为什么在‘aa’的情况下VSCode在插入和删除时都会慢一些。

我注意到的下一件可疑的事情是,我的方差似乎太低了。有时我会得到1ms的标准偏差,而我对系统工作原理的理解是,由于16ms的屏幕刷新间隔,我应该会得到超过4.6ms的标准偏差。

我查看了我的代码,发现我无意中将我的测量与屏幕刷新同步了。每当我测量更改时,我的固件都会准确地等待300ms,然后再次键入‘a’或退格键,然后再进行另一次测量。这意味着输入总是在屏幕刷新后大约300ms发送,因此在屏幕刷新间隔中会落在一个相当恒定的点上。我通过在两次测量之间添加50ms的随机延迟来修补此问题。

这主要导致不正确的低方差,但如果输入事件在帧中出现较晚,应用程序将错过绘制截止日期,但在测试期间从未错过,则可能会导致不正确的平均值。我在这篇文章的测试过程中发现了这一点,不想费心重新做低于这一点的所有测试,所以你可能会注意到一些小的方差,但我确实重新检查了像Sublime和VSCode这样的重要结果的平均值。

我在同一个纯文本文件上测试了一些文本编辑器的延迟,但请注意,上面这些是在我添加抖动之前的,尽管我在抖动之后对Sublime和VSCode做了更多的测试(上面可以看到)。

后i=32.5+/-4.0,a=34,d=35(n=38,q=78)|9|崇高文本i=33.4+/-1.4,a=33,d=33(n=68,q=23)|_9|textteditlat i=47.6+/-7.0,a=47,d=47(n=71,q=130)|219|vscridelat i=34.2+/-3.5,a=34,d=。d=33(n=55,q=30)|9|库存Mac emacslat i=45.6+/-7.0,a=43,d=41(n=35,q=56)|992_|Atomlat i=35.0+/-4.7,a=35,d=35(n=66,q=11)|9_|xi。

考虑到没有抖动,我会将这些结果解释为除了VSCode和Atom之外的所有东西,它们类似地“基本上是您能得到的最好的”。请注意,即使是VSCode和Atom,其正常键入的延迟损失也比您在显示器或键盘上可以轻松获得的要小。

我还测量了不同的终端。看起来默认的Apple终端和Kitty具有相似的近似最佳延迟,而iTerm2和Alacritty的延迟更差。

后面i=53.1+/-6.6,a=54,d=55(n=53,q=59)|291|iterm2 GPU渲染器i=50.5+/-2.5,a=50,d=50(n=56,q=59)|19_|iterm2 no gPulat i=35.8+/-7.0,a=34,d=33(n=73,q=48)|9_||苹果终端i=35.1+/-2.5,a。q=52)|9_|苹果终端vimlat i=50.4+/-3.9,a=50,d=49(n=60,q=269)|_59|alacrittylat i=36.1+/-5.6,a=35,d=34(n=78,q=199)|9_|小猫。

12美元:一张青少年LC或任何其他青少年3+。你也可以使用Arduino,但Teensy的USB库使用1000 Hz轮询(1ms延迟),而大多数USB设备默认为125 hz(在您的测量中额外的8ms随机延迟)。不过,您也有可能让您选择的微控制器进行1000 Hz的轮询。如果你不想焊接引脚,买一个带有预焊引脚的引脚,如果你想要亚马逊Prime送货,这可能需要购买更昂贵的Teensy3。

12美元:一个光传感器模块(亚马逊只有10个包,我只用了1个)。您可以为此制作自己的电路,但这些模块节省了大量时间,并且易于集成。

13美元:一只帮助你将光传感器稳定地举到屏幕上的手。

用电工胶带做一个黑色的软屏,以限制传感器的视线。

确切地说,你如何组装它有很大的灵活性。您只需以某种方式将3根导线(3V,接地,模拟输出)从光传感器模块连接到Tensy上的相应引脚(3V,接地和任何支持模拟的引脚)。要做到这一点,最简单的方法,甚至不需要任何焊接,如果你买了一个预焊接头引脚的青少年是使用3母对母跳线。然后,您只需要某种类型的开关来激活延迟测试,在该测试中,您将一个管脚连接到Tensy上的接地,将另一个管脚连接到数字IO管脚。如果你真的很懒,这可以像你碰在一起的两根电线一样简单!

为了确保光传感器模块只能看到屏幕的有限区域,我将传感器包裹在一个小胶带圆柱体中,并用剪刀干净利落地剪掉了一端。这做了一个小圆窗,我可以用手按在屏幕上,将外界干扰降到最低,得到最干净的信号。

我已经做了一个脚踏盒,里面有一个很小的LC和一个小面包板,它的一侧有一个额外的TRRS插孔,我已经预料到了这种项目,所以对我来说,这个项目是将光传感器模块焊接到TRRS电缆上。然后我就可以用我现有的一个脚踏板来控制测试了!

对于焊接,我很幸运,因为我很方便地为这个项目买了磁性的帮手,我可以用它来焊接过程。令人不便的是,我意识到我实际上没有太多的铁块供它们附着,所以我最终在焊接时使用了铸铁平底锅,在我的桌子上使用了我的钨方(后来发现它有点铁磁性)。

我鼓励你玩得开心,试着做一些花哨的东西,而不仅仅是悬挂跳线。脚踏盒我从当地的一家电子商店买了一个塑料投影盒,用钻床在侧面打了几个洞,还安装了大大小小的耳机插孔和一个小面包板,这样我就可以重新配置东西的连接方式。亚马逊上有成吨的脚踏板,供纹身机和使用1/4英寸手机插头的电动钢琴使用,你可以从中挑选。这些都是我最喜欢的感觉和沉默,但也有更便宜的选择,可能是不可靠的,难以按下或大声。

虽然我不建议在传感器模块使用TRRS插孔,它们又好又小,而且有很多可用的线缆,但在我意识到它们会在插入和拔出不同的连接时导致大量短路的问题之前,我使用了它们。我试图通过将电源和接地放在相反的两端来尽量减少这种影响,但您应该考虑一些更好的电缆类型,比如电话线。

我没有编写最花哨的固件来寻找过渡的开始和结束,但我花了一些精力来调整它以使其正常工作,并添加了各种功能,所以我建议从我的固件开始。安装Teensyduino软件,然后你就可以使用我的延迟测试仪Arduino sketch,它也可以作为脚踏板盒子代码,但你可以注释掉它,并将其配置为使用正确的引脚。然后只需长按您的开关采集样本,短按即可将结果打印出来!