鼠标轮询率

来自 ArchWiki

如果您购买了高分辨率鼠标,调整 USB 轮询率是利用其带来的更高精度的常用技巧。轮询率(或报告率)决定了鼠标向计算机发送信息的频率。

轮询率和轮询间隔

设备的轮询率以赫兹 (Hz) 为单位测量,并由轮询间隔决定。轮询间隔以毫秒 (ms) 或微秒为单位测量,等同于延迟时间。

默认轮询间隔为 10 毫秒。但是,USB 控制器会将间隔向下舍入到最接近的 2 的幂。因此,间隔设置为 10 毫秒实际上会使用 8 毫秒,7 毫秒将使用 4 毫秒,依此类推。

如果轮询率为 125 赫兹,鼠标位置将每 8 毫秒更新一次。在延迟至关重要的情况下(例如游戏),一些用户会尽可能减小间隔。但是,这会给 CPU 带来更多负载,因此在调整此值时应谨慎。

对于 USB 2.0 高速和 USB 3.0+ 设备,能够以小于 1 毫秒的间隔进行轮询 - 在这种情况下,内核将以微秒为单位报告轮询间隔。

下表显示了轮询率赫兹与相应的间隔毫秒(速率 = 1000 / 间隔)和微秒(速率 = 1000000 / 间隔)之间的关系

赫兹 8000 4000 2000 1000 500 250 125
毫秒 0.125 0.25 0.5 1 2 4 8
微秒 125 250 500 1000 2000 4000 8000

测量轮询率

通过 libinput 测量轮询率

如果主机上使用了 libinput,则可以在运行 root 权限 或以其他方式访问 /dev 伪文件系统时使用 libinput debug-events,并观察到事件定期发生。例如,对于 500 赫兹的鼠标轮询率,可以看到两个连续事件之间的最大差异为 0.002 秒,对于 1000 赫兹的更新,每个毫秒(即 0.001 秒),对于更高的轮询率,报告的事件可能发生在同一毫秒。

# libinput debug-events

对于 500 赫兹

event22  POINTER_MOTION          +10.918s	  1.22/  1.22 ( +1.00/ +1.00)
event22  POINTER_MOTION          +10.920s	  0.00/  1.22 ( +0.00/ +1.00)
event22  POINTER_MOTION          +10.922s	  0.00/  1.12 ( +0.00/ +1.00)
event22  POINTER_MOTION          +10.924s	  1.25/  1.25 ( +1.00/ +1.00)

对于 1000 赫兹

event18  POINTER_MOTION          +0.235s	 -1.87/ -1.87 ( -1.00/ -1.00)
event18  POINTER_MOTION          +0.236s	 -1.87/  0.00 ( -1.00/ +0.00)
event18  POINTER_MOTION          +0.237s	 -1.66/  0.00 ( -1.00/ +0.00)
event18  POINTER_MOTION          +0.238s	 -1.66/  0.00 ( -1.00/ +0.00)

对于 2000 赫兹

event22  POINTER_MOTION          +14.114s	 -2.00/  0.00 ( -1.00/ +0.00)
event22  POINTER_MOTION          +14.114s	 -2.00/  0.00 ( -1.00/ +0.00)
event22  POINTER_MOTION          +14.115s	  0.00/ -2.00 ( +0.00/ -1.00)
event22  POINTER_MOTION          +14.115s	 -2.00/  0.00 ( -1.00/ +0.00)

通过 evhz 测量轮询率

evhz 工具可以显示鼠标的实际刷新率。

您可以从 evhz-gitAUR 安装它,并以 root 权限执行

# evhz

现在连续大幅度地画圈移动鼠标,直到显示的 Average 值稳定下来,然后按 Ctrl+c 退出。

如果 Latest 值不稳定并在两个值之间切换,则尝试的轮询率快于设备所能达到的速度;请参阅 #USB 设备速度

通过 Wine+DirectX 测量轮询率

或者,可以使用 Wine 运行 Windows 工具,例如 DirectX mouserate checker。或者使用基于网站的检测器,例如 CPS-Check 提供的检测器

显示轮询间隔

注意: 这仅显示设备请求的轮询间隔,而不是实际使用的间隔。请参阅 BBS

如果 debugfs 已挂载并且您具有 root 权限,则可以在其中找到包括轮询间隔在内的设备信息。

首先,使用以下命令查找您设备的供应商 ID 和产品 ID

$ lsusb
Bus 001 Device 002: ID 045e:0024 Microsoft Corp. Trackball Explorer
Bus 001 Device 001: ID 1d6b:0001 Linux Foundation 1.1 root hub

然后使用这些 ID 以 root 权限运行以下命令,以显示该设备的调试信息

# grep -B3 -A6 "045e.*0024" /sys/kernel/debug/usb/devices
T:  Bus=01 Lev=01 Prnt=01 Port=01 Cnt=01 Dev#=  2 Spd=1.5  MxCh= 0
D:  Ver= 1.10 Cls=00(>ifc ) Sub=00 Prot=00 MxPS= 8 #Cfgs=  1
P:  Vendor=045e ProdID=0024 Rev= 1.21
S:  Manufacturer=Microsoft
S:  Product=Microsoft Trackball Explorer®
C:* #Ifs= 1 Cfg#= 1 Atr=a0 MxPwr=100mA
I:* If#= 0 Alt= 0 #EPs= 1 Cls=03(HID  ) Sub=01 Prot=02 Driver=usbhid
E:  Ad=81(I) Atr=03(Int.) MxPS=   4 Ivl=10ms

Ivl 是轮询间隔;此设备已请求 10 毫秒(实际上如 #轮询率和轮询间隔 中所述,每 8 毫秒报告一次)。Spd#USB 设备速度 中解释的设备速度。有关其他字段的信息,请参阅 内核文档

如果 debugfs 或 root 权限不可用,则可以使用以下命令显示轮询间隔

$ lsusb -vd 045e:0024 | grep bInterval
bInterval 10

USB 设备速度

USB 设备设计为以特定比特率运行。许多指点设备是“低速” 1.5Mbit/s 设备。设备的速度可以按照 #显示轮询间隔 中的说明显示。

“低速”设备可能无法以小于 8 毫秒的间隔进行轮询。

所有 USB 集线器都应至少能够达到“全速” 12Mbit/s。连接设备的集线器的速度可以使用以下命令显示,Bus=xx 与设备相同

# grep -B1 -A10 "Bus=01 Lev=00" /sys/kernel/debug/usb/devices
T:  Bus=01 Lev=00 Prnt=00 Port=00 Cnt=00 Dev#=  1 Spd=12   MxCh= 2
B:  Alloc= 11/900 us ( 1%), #Int=  1, #Iso=  0
D:  Ver= 1.10 Cls=09(hub  ) Sub=00 Prot=00 MxPS=64 #Cfgs=  1
P:  Vendor=1d6b ProdID=0001 Rev= 4.01
S:  Manufacturer=Linux 4.1.18-1-lts uhci_hcd
S:  Product=UHCI Host Controller
S:  SerialNumber=0000:00:10.0
C:* #Ifs= 1 Cfg#= 1 Atr=e0 MxPwr=  0mA
I:* If#= 0 Alt= 0 #EPs= 1 Cls=09(hub  ) Sub=00 Prot=00 Driver=hub
E:  Ad=81(I) Atr=03(Int.) MxPS=   2 Ivl=255ms

集线器的 Ivl 独立于设备,并且不影响设备的轮询率。

设置轮询间隔

要配置轮询率,请使用 usbhid 内核模块mousepoll 选项。默认值为 0,表示模块使用设备请求的间隔。

可以使用以下命令验证该选项的当前值

$ systool -m usbhid -A mousepoll
Module = "usbhid"
    mousepoll           = "0"

要更改配置,请添加以下 内核模块参数

options usbhid mousepoll=4

此示例请求 250Hz 的轮询率。同样,您可以分别使用 jspoll 或 kbpoll 来更改游戏手柄/操纵杆或键盘的轮询率。

要在不重启的情况下更改轮询间隔

# modprobe -r usbhid && modprobe usbhid mousepoll=4
警告: 如果第二个命令失败,您将无法使用任何 USB 鼠标或键盘,可能需要重启或 ssh 进入您的机器。

您可能需要拔下鼠标并重新插入才能使更改生效。

注意: 如果您的 initramfs 镜像中包含 usbhid 模块,您可能还需要将 /etc/modprobe.d/usbhid.conf 添加到镜像中。请参阅 Kernel modules#Using modprobe.d 中的注释。或者,您可以将 usbhid.mousepoll=X 添加到您的内核命令行。请参阅 Kernel modules#Using kernel command line
提示: 当使用小于默认间隔的间隔时,您可能需要调整 鼠标加速度 选项 VelocityScale 以匹配。

已知问题

轮询率只有请求速率的一半

存在一个内核错误,在某些配置下会阻止设备达到 1000 Hz (1ms) 的轮询率。请参阅 BBSBug

一个可能有帮助的解决方法是将设备连接到使用不同驱动程序的端口。

轮询率不改变

USB 3 驱动程序 xhci-hcd 可能会忽略 usbhid mousepoll 设置。请参阅 linux-usb 邮件列表消息Bug

xhci-hcd 模块应尊重设备请求的间隔,因此请查看设备文档以获取硬件或固件设置。

一个可能有帮助的解决方法是将设备连接到使用不同驱动程序的端口。

另一个解决方法是禁用 xHCI。BIOS 中可能有此设置,或者您可以通过 黑名单 xhci-hcd 模块来完成此操作。但是,无论哪种方式都会导致任何 USB 3 端口都充当 USB 2,因为内核将改用 ehci-hcd 模块。

作为替代方案,可以安装内核模块 wmo_oc-dkmsAUR(或从 wmo_oc-kmod 手动构建),它是 gcadapter-oc-kmod 的一个分支,用于 wmo1.1a (MS Wheel Mouse Optical 1.1a)。wmo_oc-dkms 使用鼠标的供应商 ID 和产品 ID (VID:PID) 值来识别鼠标,以便即使使用 XHCI 集线器也能对其进行超频,而不会丢失 USB 3 功能。更改除默认 wmo1.1a 之外的任何 USB 鼠标的轮询率需要修改模块源文件 wmo_oc.c(位于 /usr/src/module_name/ 中)中的默认 VID:PID 值,并最终使用 DKMS 重建(删除和安装)内核模块。wmc_oc 模块的轮询率可以通过编辑源代码或使用运行时选项(例如 /etc/modprobe.d/ 中的 .conf 文件)来配置。

options wmc_oc rate=2

上面的示例将设置 2 毫秒或 500Hz 的间隔。

提示: 要查看正在使用哪些 hcd 驱动程序,请查看 /sys/kernel/debug/usb/devices 中集线器设备的 S: Manufacturer 行。

轮询率导致 wine 出现延迟

使用高轮询率鼠标并使用 wine 可能会导致游戏延迟;请参阅 此处。创建该 bug 的用户似乎通过更新 bios 解决了问题。但是,该 bug 尚未为其他用户解决。

如果您的计算机只有 USB3 xHCI 控制器,则无法使用本 wiki 中的方法(“usbhid”方法)更改鼠标的轮询率。

遗憾的是,对于同时拥有高轮询率鼠标和仅有 USB3 xHCI 控制器的用户,目前尚无修复方法。

一种解决方法是使用轮询率较低的鼠标。

高于 1000hz 的轮询率

确保设备连接到标准高于 USB 2 的 USB 插槽:高于 1khz 的轮询率仅在 USB 3 及更高版本的设备上受支持。这将允许设备以更高的速率“被轮询”。

参见