Слабая производительность CGEventPost под нагрузкой GPU


мы наткнулись на проблему производительности с событиями Quartz, более конкретно CGEventPost: во время большой нагрузки GPU CGEventPost может блокировать. Мы создали небольшое тестовое приложение для демонстрации проблемы. Это приложение - это просто цикл, который создает, публикует и выпускает события.

ниже вы можете увидеть результаты работы приложения. Первый запуск выполняется на холостом ходу системы. Второй запуск-с FurMark (GPU stress test) с циферблатами, настроенными как насколько это возможно.

  • Inner - это то, сколько времени занимает внутренний цикл, в основном просто создавая, публикуя и выпуская событие с кварцевыми событиями.
  • внешний - это то, как долго наша программа ждет, чтобы ее разбудили (сон). Должно быть близко к тому времени, когда мы спим, но если система находится под давлением, это может быть отложено.
  • сообщение - это сколько времени занимает сообщение о событии.

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,5 мс слишком поздно. Никаких всплесков в 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 (иногда похоже, что он ждет, когда GPU закончит некоторую работу, прежде чем вернуться. Наш поток все еще запланирован нормально без заметного задержка / шипы (внешние).

любые идеи приветствуются.

1 52

1 ответ:

Я думаю, вы заполняете очередь (базовый порт mach)...

вы можете подтвердить это с помощью инструмента" планирование "или" системный вызов " в инструментах. (Создайте новый пустой документ, добавьте инструмент, затем под File > Record Options... убедитесь, что установлен флажок "отложенный режим".) Это покажет всю активность потока в вашем приложении (когда потоки блокируются, когда они спят, когда они активированы и почему).

Я бы сначала попытался повысить приоритет потока(ср. man 3 PTHREAD_SCHEDPARAM) нити звоню CGEventPost. Если ваш поток заблокирован в потоке с более низким приоритетом, ядро должно временно повысить приоритет блокирующего потока, чтобы избежать инверсии приоритета и помочь вам выполнить задачу раньше.

в целом, я думаю, что вам придется реализовать 2-поток раствора, как показано ниже:

создать очередь для событий, которые вы хотите разместить. Отправляйте события в эту очередь из основного потока (или потока отправки событий), а затем сигнализируйте о втором потоке (событии потребительский поток, который вы создаете), чтобы пройти очередь и опубликовать любые выдающиеся события с CGEventPost.

, когда CGEventPost блоки, ваш второй поток публикации событий будет заблокирован, но это не будет блокировать любые другие потоки. Когда CGEventPost в конечном итоге разблокируется, он будет потреблять любые выдающиеся события, опубликованные вашим потоком потребителей событий, и поток потребителей событий может возобновить публикацию событий.

другая возможность: вы можете coallesce события? Есть определенные типы событий (перемещение мыши?) что вы могли бы уговорить на меньшее количество событий. Вероятно, вы все равно столкнетесь с ограничением очереди CGEventPost иногда, я думаю, что 2-нить подход, вероятно, ваш лучший выбор.