Подтвердить что ты не робот

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

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

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

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

 

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

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

4b9b3361

Ответ 1

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

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

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

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

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

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

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