CGEventPost在GPU负载下性能较弱
我们偶然发现了Quartz Events的一个性能问题,更具体地说是CGEventPost:在GPU负载过重时,CGEventPost可能会阻塞。 我们创build了一个小型的基准testing应用程序来演示这个问 这个应用程序只是一个创build,发布和发布事件的循环。
您可以在下面看到运行应用程序的结果。 第一次运行是在一个空闲的系统上。 第二次运行是FurMark(GPU压力testing),尽量使用转盘。
- 内部是内部循环需要多长时间,基本上只是使用Quartz Events创build,发布和发布事件。
- 外面是我们的程序等待被唤醒多久(睡眠)。 应该接近我们睡觉的时间,但是如果系统处于压力之下,可能会延迟。
- post是事件发布需要多长时间。
18:58:01.683 EventPerformance[4946:707] Measurements: (outer should be close to 10) 18:58:01.684 EventPerformance[4946:707] inner (ms): 0.04, outer (ms): 11.02, CGEventPost (ms): 0.03 18:58:01.684 EventPerformance[4946:707] inner (ms): 0.04, outer (ms): 11.02, CGEventPost (ms): 0.03 18:58:01.685 EventPerformance[4946:707] inner (ms): 0.07, outer (ms): 10.26, CGEventPost (ms): 0.03 18:58:01.685 EventPerformance[4946:707] inner (ms): 0.06, outer (ms): 10.85, CGEventPost (ms): 0.05 18:58:01.686 EventPerformance[4946:707] inner (ms): 0.07, outer (ms): 10.41, CGEventPost (ms): 0.04 18:58:01.686 EventPerformance[4946:707] inner (ms): 0.04, outer (ms): 10.39, CGEventPost (ms): 0.03 18:58:01.686 EventPerformance[4946:707] inner (ms): 0.05, outer (ms): 11.02, CGEventPost (ms): 0.03 18:58:01.687 EventPerformance[4946:707] inner (ms): 0.03, outer (ms): 10.67, CGEventPost (ms): 0.03 18:58:01.687 EventPerformance[4946:707] inner (ms): 0.08, outer (ms): 10.09, CGEventPost (ms): 0.05 18:58:01.688 EventPerformance[4946:707] Averages: (outer should be close to 10) 18:58:01.688 EventPerformance[4946:707] avg inner (ms): 0.05, avg outer (ms): 10.64, avg post (ms): 0.03
在这里我们可以看到发布该事件平均需要大约0.03毫秒。 而且这个线程似乎也太迟了0.5ms左右被唤醒了。 CGEventPost没有尖峰。
19:02:02.150 EventPerformance[5241:707] Measurements: (outer should be close to 10) 19:02:02.151 EventPerformance[5241:707] inner (ms): 0.03, outer (ms): 10.23, CGEventPost (ms): 0.02 19:02:02.151 EventPerformance[5241:707] inner (ms): 0.02, outer (ms): 10.54, CGEventPost (ms): 0.02 19:02:02.151 EventPerformance[5241:707] inner (ms): 0.02, outer (ms): 11.01, CGEventPost (ms): 0.01 19:02:02.152 EventPerformance[5241:707] inner (ms): 0.02, outer (ms): 10.74, CGEventPost (ms): 0.01 19:02:02.152 EventPerformance[5241:707] inner (ms): 0.02, outer (ms): 10.20, CGEventPost (ms): 0.01 19:02:02.152 EventPerformance[5241:707] inner (ms): 10.35, outer (ms): 11.01, CGEventPost (ms): 10.35 19:02:02.152 EventPerformance[5241:707] inner (ms): 0.03, outer (ms): 10.02, CGEventPost (ms): 0.02 19:02:02.153 EventPerformance[5241:707] inner (ms): 58.90, outer (ms): 10.11, CGEventPost (ms): 58.90 19:02:02.153 EventPerformance[5241:707] inner (ms): 0.03, outer (ms): 10.12, CGEventPost (ms): 0.02 19:02:02.153 EventPerformance[5241:707] Averages: (outer should be close to 10) 19:02:02.371 EventPerformance[5241:707] avg inner (ms): 7.71, avg outer (ms): 10.44, avg post (ms): 7.71
当系统处于沉重的GPU负载下时,发布事件可能需要(毫秒),而不是微秒。 在极端的GPU压力(<1 FPS)下,此值可能需要几秒钟。 CGEventPost 有时似乎在等待GPU返回前完成一些工作。 我们的线程仍然正常计划没有明显的延迟/尖峰(外)。
任何想法都表示赞赏。
我猜你正在填满队伍(下面的马特港)…
您可以使用仪器中的“调度”或“系统调用”工具来确认。 (创build一个新的空白文档,添加仪器,然后在File > Record Options...
确保select“延期模式”)。这将显示您的应用程序中的所有线程活动(当线程阻塞,睡觉时,被激活,为什么)。
我将首先尝试提高调用CGEventPost
的线程的线程优先级(参见man 3 PTHREAD_SCHEDPARAM
)。 如果您的线程被阻塞在优先级较低的线程上,内核应暂时提升阻塞线程的优先级,以避免优先级反转,并帮助您的任务提前完成。
总的来说,我认为你将不得不实施一个2线程解决scheme ,如下所示:
为要发布的事件创build一个队列。 将事件从主线程(或事件发布线程)发布到此队列中,然后发出第二个线程(您创build的事件使用者线程)来发送队列,并使用CGEventPost
发布任何未完成的事件。
当CGEventPost
阻塞时,你的第二个事件发布线程将被阻塞,但是这不会阻塞任何其他线程。 当CGEventPost
最终解除CGEventPost
,它将消耗由事件使用者线程发布的未决事件,并且事件使用者线程可以恢复发布事件。
另一种可能性:你可以采取事件吗? 有某些types的事件(鼠标移动?),您可以将事件减less到更less。 有时你可能还会遇到CGEventPost
的队列限制,我认为2线程的方法可能是你最好的select。