将epoll与设备(/dev/event/..)一起使用是否有效



我正在开发一个单线程进程小程序,该小程序创建一个代理虚拟设备(更确切地说是一个虚拟Xbox 360pad);我确实设法用uinput接口创建了它,我正确地设置了它,它运行得很好。

为了将命令馈送到此虚拟设备,我从另一个真实接口(在本例中为PS3焊盘)读取事件,并打开带有以下标志的实际设备

fd = open("/dev/input/event22", O_RDONLY); // open the PS3 pad

主循环类似于(减去错误检查):

while(run) {
input_event ev = {0};
read(fd, &ev, sizeof(struct input_event));
// convert from PS3 --> Xbox 360
convert(ev);
// write to the new virtual pad
write(fd_virtual, &ev, sizeof(struct input_event));
}

正如您所想象的,read(fd, &ev, sizeof(struct input_event));是一个阻塞调用,我希望有一种超时来循环通过循环并检查其他事件/执行其他代码。

出于这些原因,我正在考虑将read(fd...调用封装在epoll循环中,这样我也可以有一个超时。

问题是,这样做是否有效?通过使用epoll_wait,我是否会向当前环路引入额外的延迟,从而延迟虚拟焊盘的响应?

通过使用epoll_wait,我是否在当前循环中引入了额外的延迟,从而延迟了虚拟焊盘的响应?

是的,你当然知道。

这样做会有效率吗?

我肯定是的,但这在很大程度上取决于你对"高效"的定义。

我们在这里谈论的是一个人工输入设备。在处理HID时,我们最关心的是延迟,它不应该滞后,对按键的反应应该是即时的。对于人类来说,什么是"瞬间"?这里有一个很好的讨论,但我最喜欢的一个论点是,在高水平的田径比赛中,你会因为在信号发出后不到100毫秒内起跑而被取消资格。

但100毫秒是对输入信号进行整体处理的时间预算,从按键到游戏中一些可感知的变化。维基百科关于投入滞后的页面上有一些关于预算通常如何使用的数字。

无论如何,我认为1ms是绝对安全的开销,你可以用代理添加,没有人会注意到,假设这是我们最大延迟的目标(正如"高效"的定义)。

因此,让我们假设您对当前代码的响应时间感到满意。添加epoll()呼叫后会发生什么变化?基本上,您需要增加一些时间来进行另一个系统调用,因为现在您需要进行两个系统调用来获得值,而不是一个系统呼叫。因此,它可能比原始代码慢两倍(暂时忘记不同系统调用的处理时间差异)。但真的那么糟糕吗?

为了回答这个问题,我们需要对系统调用开销有一些估计。如果我们懒得自己测量,我们可以使用一些20年前的数字,一些来自关心系统调用的人的数字,以及一些来自微内核的IPC数字(他们总是很关心),StackOverflow中的一些随机数,或者只是询问Rich,并在微秒级左右结算,作为一个安全的假设。

因此,问题归结为,在你的毫秒(如1000µs)时间预算内,增加一些(甚至说10)微秒是否值得注意。我想不是。

只有一个可能的小问题,当你要从"只是添加epoll()"到

循环循环并检查其他事件/执行其他代码。

您需要小心,在这些循环和检查的时间预算内。但话说回来,1毫秒对你来说可能绰绰有余。

相关内容

最新更新