Я пытаюсь написать простой игровой цикл для MacOS.Решение опроса событий , которое я нашел в библиотеках, таких как игровые порты GLFW, SDL и MacOS для DOOM, Quake, Handmade Hero, заключается в использовании nextEventMatchingMask
API.Меня интересует задержка опроса событий :
t0 = mach_absolute_time();
NSEvent *event = [NSApp nextEventMatchingMask:NSEventMaskAny
untilDate:nil
inMode:NSDefaultRunLoopMode
dequeue:YES];
t1 = mach_absolute_time();
latency=t1-t0
Эксперимент, который я запускаю ( исходный код ), состоит из открытия окна MacOS Cocoa и «случайно»генерирование событий мыши и клавиатуры.Типичные числа задержек, которые я получаю для первых 1000 событий в таком эксперименте, выглядят так:
# latency percentiles in milliseconds
: 0% 5% 10% 15% 20% 25% 30% 35%
: 0.033830 0.047655 0.060302 0.071263 0.073450 0.075871 0.079204 0.083330
: 40% 45% 50% 55% 60% 65% 70% 75%
: 0.093038 0.107813 0.134466 0.143095 0.180434 0.334789 0.448111 0.500118
: 80% 85% 90% 95% 100%
: 0.524535 0.583159 0.648065 0.719931 36.567810
Обратите внимание, что максимальная задержка 25% большечто полсекунды.Даже когда нет доступных событий (нули на графике), мы можем получить задержку более миллисекунды (см. Ноль, плавающий около 600-го события).Что еще хуже, это типичный случай, который я наблюдаю, когда у моего Macbook мало что происходит: только терминал и тестовая программа.Хуже, когда работает больше приложений.
Интересно, есть ли более эффективный способ получить следующее событие (мышь / клавиатура), если оно доступно в приложении MacOS.Не хватает ли уловки, которая делает nextEventMatchingMask
звонки более эффективными?
Исходный код для запуска этого теста и создания графика, подобного приведенному выше, можно найти здесь: https://github.com/laurolins/cocoa_poll_events_latency
(обновление) Следуя идее Папа , предложенной в комментариях, я запустил тест без каких-либо движений мыши / клавиатуры.Вот процентили задержки:
# latency without any keyboard/mouse event in milliseconds
: 0% 5% 10% 15% 20% 25%
: 0.04029500 0.07617675 0.07908070 0.08556100 0.10188940 0.12956500
: 30% 35% 40% 45% 50% 55%
: 0.13832200 0.14023150 0.14802140 0.15003550 0.15045250 0.15088950
: 60% 65% 70% 75% 80% 85%
: 0.15125000 0.15162535 0.15190300 0.15235550 0.15313200 0.15972645
: 90% 95% 100%
: 0.16802250 0.21194335 35.93352900
Идея ожидания 0,15 миллисекунд, чтобы выяснить, что событие не было сгенерировано, не подходит!
(обновление 2) Только по времени все SDL_EventPoll
и MessagePump
звонки на gzdoom , работающие на Ubuntu и распределении задержек, которые я получаю, выглядят намного лучше:
# 0% 5% 10% 15% 20% 25% 30%
:0.00095100 0.00186075 0.00215500 0.00226400 0.00234180 0.00241500 0.00255900
: 35% 40% 45% 50% 55% 60% 65%
:0.00289495 0.00652280 0.00712510 0.00749900 0.00770290 0.00807660 0.00888870
: 70% 75% 80% 85% 90% 95% 100%
:0.00897200 0.00905000 0.00931060 0.01374225 0.01728800 0.03256290 0.23016000
в то время как на MacOS gzdoom также борется смедленность nextEventMatchingMask
(латентные числа на сотни микросекунд).Вывод: не только мой тестовый код медленно получает следующее событие клавиатуры / мыши в MacOS.