Нативные приложения - снятие нагрузки?

Общие вопросы программирования, алгоритмы и т.п.

Модератор: Модераторы

Re: Нативные приложения - снятие нагрузки?

Сообщение runewalsh » 19.08.2020 04:48:09

MysticCoder писал(а):Велосипедов из сообщений и прочего на замену Sleep городить не надо.

1) Надо.
2) Это не велосипед. Велосипед — это как раз-таки ожидания события в духе while not event.IsSet do Sleep(1) вместо event.WaitFor, или, в нашем случае, while true do begin PeekMessageW(...); Sleep(1); end вместо while true do GetMessageW(...).

Sleep отдаёт квант времени (условно 20 мс) до конца, но способы уснуть с явным ожиданием чего-либо могут иметь гораздо лучшую гранулярность и поведение в целом: мгновенно (а не за 20 мс) просыпаться, когда нужно, и вместе с тем не просыпаться, когда не нужно — всё это выгодно отличается от Sleep(1).

Об отправке сообщения шла речь как об (очевидном) способе разбудить, если очень надо, блокирующее ожидание сообщения (GetMessageW).
Аватара пользователя
runewalsh
постоялец
 
Сообщения: 467
Зарегистрирован: 27.04.2010 00:15:25

Re: Нативные приложения - снятие нагрузки?

Сообщение Seenkao » 19.08.2020 07:02:45

runewalsh, я попробую твой способ. Но меня будет больше тогда интересовать работа с таймерами, особенно когда их не один и не два. Есть информация где всё посмотреть?

А то "провалы" Sleep ни сколько не радуют.

Добавлено спустя 9 минут 26 секунд:
MysticCoder, нового ни чего не открыто...

Sleep(0), будет в "долгом" ожидании, в отличии от Sleep(1). Но, как говорилось выше, Sleep(1) так же может впасть в долгую спячку почти на целых 16 милисекунд, вместо одной. Я думаю это ощутимая разница. Потому и ищу способ где ожидание будет более конкретным.

Ну и в дополнение, если у людей монитор включен на другую частоту, отличную от стандартных (30, 60), на такие как 75, 85, 100, 144 и подобные, то лаги в самой программе выползут. А Sleep(1) их усугубит. Так как программу надо подстраивать под частоту монитора или в программе переключать монитор на нужную частоту. (я прикидываю как обрадуется пользователь, который выставил себе 85Гц, когда ему программа переключит монитор на 60Гц, или вообще на 30...).
Seenkao
новенький
 
Сообщения: 62
Зарегистрирован: 01.04.2020 03:37:12

Re: Нативные приложения - снятие нагрузки?

Сообщение MysticCoder » 19.08.2020 10:33:45

Если fps не важен(допустим, карточная игра), то используем Sleep(1) и не паримся.
Если fps критичен, то просто не отдаем свое время ОС. Загрузка ядра при этом будет 100 процентов, ну и что? Все игры гарантирующие высокий фпс грузят ядро на 100 процентов. Процессор это ресурс который можно и нужно использовать.

По поводу Sleep(0) - если нет других потоков для выполнения, а они будут только если другие потоки грузят проц, то Sleep не засыпает. А если другие потоки грузят проц, то о каких гарантиях fps может вообще идти речь?
А все эти таймеры и MsgWaitFor все равно у вас сведутся к тому, что будет вертеться отдельный поток, который будет сравнивать текущее время и будить если что главный поток, но при этом грузить проц на 100. Так проще делать все то же самое в главном потоке.
MysticCoder
постоялец
 
Сообщения: 153
Зарегистрирован: 14.09.2013 00:20:28

Re: Нативные приложения - снятие нагрузки?

Сообщение Seenkao » 19.08.2020 17:36:37

MysticCoder, об этом можно "не парится", когда мы разрабатываем свою программу и конкретно знаем для каких задач их используем. В данном случае, мне надо сделать рабочий код для всех, чтоб люди сами могли выбирать или вообще не заморачиваться по данному поводу (чтоб всё было на автомате).
Seenkao
новенький
 
Сообщения: 62
Зарегистрирован: 01.04.2020 03:37:12

Re: Нативные приложения - снятие нагрузки?

Сообщение runewalsh » 19.08.2020 19:01:26

Seenkao писал(а):Но меня будет больше тогда интересовать работа с таймерами, особенно когда их не один и не два. Есть информация где всё посмотреть?

Вот здесь, очевидно: https://docs.microsoft.com/en-us/window ... msg/timers (но у этих таймеров точность такая же, как у Sleep).

MysticCoder писал(а):А все эти таймеры и MsgWaitFor все равно у вас сведутся к тому, что будет вертеться отдельный поток, который будет сравнивать текущее время и будить если что главный поток, но при этом грузить проц на 100.

Ты меня вообще не понимаешь.
Первый пост делает буквально вот это: while true do begin PeekMessageW(...); Sleep(1); end;.
Я уже несколько раз объяснил, что это переспрашивание плохо (и как раз является велосипедом, в котором ты меня обвиняешь) и специально для этого сценария предназначена функция GetMessageW, которая не возвращается, пока не получит сообщение.

FPS выше частоты обновления экрана не имеет смысла, кроме как узнать, сколько производительности у тебя в запасе.
FPS, равный частоте обновления экрана, обеспечивается не Sleep, а включением VSync. Этот как раз проявление того, что ожидание конкретного, не привязанного явно ко времени события имеет лучшую гранулярность: скажем, для 144 Гц-экрана оно, если отрисовка укладывается меньше чем в 1/144 секунды, выдаст 144 FPS (очень точно прождёт от 0 до 7 мс — Sleep так не умеет). Конкретный способ VSync зависит от подсистемы: по-видимому, для Vista+ Direct3D (возможно, и GDI?) это DwmFlush.
Вот для FPS, меньшего частоты обновления экрана (как раз когда «fps не важен»), можно и поспать заданное время. Но делать это желательно через таймеры (WM_TIMER), т. к. Sleep вешает поток и т. о. мешает обработке остальных оконных сообщений.

MsgWaitFor — это именно способ подождать какого-то своего события из главного потока (изнутри цикла с GetMessage), НЕ МЕШАЯ обработке сообщений (в отличие от Sleep): MsgWaitFor(event, timeout) возвращается либо когда событие event происходит, либо когда приходит оконное сообщение, либо когда проходит таймаут с точностью до кванта (и различает эти случаи). Не надо было вообще про него говорить, чтобы ты не прицепился; пока у нас только окно и его сообщения, в том числе, возможно, от таймеров (WM_TIMER), он не нужен.

Крутиться в 100% загрузке только ради того, чтобы на рассматриваемом 144 Гц-экране выдать, скажем, ровно 120 FPS (вместо 50–60, которые дадут таймеры по умолчанию, или больше — 80–100 – при timerBeginPeriod(1)), нет АБСОЛЮТНО, потому что банально отсутствие ограничения FPS даст (сюрприз) ту же 100% загрузку. Ограничение ради ограничения? Ума не приложу, почему ты вообще рассматриваешь этот вариант.
Аватара пользователя
runewalsh
постоялец
 
Сообщения: 467
Зарегистрирован: 27.04.2010 00:15:25

Re: Нативные приложения - снятие нагрузки?

Сообщение скалогрыз » 19.08.2020 19:40:03

VSync наше всё.
отключать его имеет смысл, только в случае проблем с драйверами/железом. (у меня такое было, что при включённом VSync всё начинало тормозить)

runewalsh писал(а):MsgWaitFor — это именно способ подождать какого-то своего события из главного потока (изнутри цикла с GetMessage), НЕ МЕШАЯ обработке сообщений (в отличие от Sleep)

я бы побоялся использовать MsgWaitFor из-за страха перед рекурсией.
Можно огрести себе проблем аналогичных злоупотреблению Application.ProcessMessages().
скалогрыз
долгожитель
 
Сообщения: 1722
Зарегистрирован: 03.09.2008 02:36:48

Re: Нативные приложения - снятие нагрузки?

Сообщение runewalsh » 19.08.2020 21:11:20

скалогрыз писал(а):из-за страха перед рекурсией

В нём самом по себе нет рекурсии (в отличие от ProcessMessages), он ПРОСТО возвращается по одной из причин.
Положим, ты хочешь подождать в главном цикле события (пока что-нибудь докачается там), выставляемого извне, тогда он может быть организован как:
Код: Выделить всё
var
   ExternalEvent: HANDLE;
...

// главный цикл
repeat
   // подождать сообщения или события
   case MsgWaitForMultipleObjects(1, @ExternalEvent, true, INFINITE, QS_ALLINPUT) of
      WAIT_OBJECT_0:
         // произошло событие ExternalEvent
         DoSomething;
      WAIT_OBJECT_0 + 1:
         // пришло сообщение
         while PeekMessage(msg, win, 0, 0, PM_REMOVE) do
         begin
            // обработать msg
            case msg.Msg of
               ...
            end;
         end;
      else ...
   end;
until false;
Аватара пользователя
runewalsh
постоялец
 
Сообщения: 467
Зарегистрирован: 27.04.2010 00:15:25

Re: Нативные приложения - снятие нагрузки?

Сообщение Seenkao » 19.08.2020 23:12:05

runewalsh писал(а):FPS, равный частоте обновления экрана, обеспечивается не Sleep, а включением VSync

Лично я уже не раз написал, что Sleep(1) даст нам максимум 60 кадров в ограничении, с остальным будут лаги.

Надо знать, как работает VSync, и понимать, что VSinc ни как не ограничит частоту кадров передаваемых на экран. VSinc - это внутренняя работа самой видеокарты (учитывая от того что мы используем OpenGL, DirectX или ещё что), на код, который пишет пользователь, этот параметр ни как не влияет.

Моя задача ограничить эту частоту, не посылать данные которые загрузят видеокарту, а толку от этого ни какого не будет, кроме нагрева самой видеокарты и усиленного жужания её кулера.

runewalsh писал(а):но у этих таймеров точность такая же, как у Sleep

:( плохо, тогда и смысл пропадает полостью проверять, проще будет засунуть цикл и забить его холостым ходом, лишь бы избавится от лишних кадров посылаемых на видеокарту.

Я уже так же писал, что надо будет ещё под частоту мониторов подгонять, либо "заставлять" пользователя пользоваться частотой не более 60Гц.

В общем... дебилизм...
Seenkao
новенький
 
Сообщения: 62
Зарегистрирован: 01.04.2020 03:37:12

Re: Нативные приложения - снятие нагрузки?

Сообщение runewalsh » 19.08.2020 23:55:42

Seenkao писал(а):Надо знать, как работает VSync, и понимать, что VSinc ни как не ограничит частоту кадров передаваемых на экран. VSinc - это внутренняя работа самой видеокарты (учитывая от того что мы используем OpenGL, DirectX или ещё что), на код, который пишет пользователь, этот параметр ни как не влияет.

Не, нифига. По-моему, ты уже аналогично в теме Чеба пытался рассуждать о теме, в которой недостаточно разбираешься ;).

При включённом VSync этим ожиданием занимается какая-то из API-процедур, которые ты вызываешь, оно не выполняется полностью невидимо от программиста и уж тем более не «где-то внутри видеокарты». В случае WGL_EXT_swap_control при включённом VSync ждать будет вызов SwapBuffers — он не вернёт управление, пока не закончится обновление экрана. Поскольку SwapBuffers вызывается после отрисовки (и тем же потоком, который только что рисовал), это автоматически означает, что отрисовка выполнится не больше раз, чем обновится экран. То есть SwapBuffers (или, как выше, DwmFlush) становятся заменой Sleep.
Аватара пользователя
runewalsh
постоялец
 
Сообщения: 467
Зарегистрирован: 27.04.2010 00:15:25

Re: Нативные приложения - снятие нагрузки?

Сообщение Seenkao » 20.08.2020 00:33:45

Хорошо, я вполне возможно не корректен в этом вопросе, по VSync, но функция отправки данных на видеокарту (рендер) ни кто не блокирует этой функцией! Возможно блокировка SwapBuffers происходит, но этот буфер всё равно заполняется вызываемой функцией (рендером), и данные, всё равно уходят в отработку.

Если я вижу код и понимаю что происходит, почему вдруг кто-то другой говорит, что я не правильно вижу? :lol:

Но дискутировать полезно, можно таким образом "обманывать" машину используя условное ограничение на рендер и VSync.

runewalsh писал(а):По-моему, ты уже аналогично в теме Чеба пытался рассуждать о теме, в которой недостаточно разбираешься ;).

Я всегда стараюсь обдумывать что делаю. И говорить что я не разбираюсь, далеко не всегда верно! Это так же не значит что я не могу ошибаться.

оффтоп: Обработка мыши не должна задевать рендер, а раз задевает, значит код не доделан (исключение только когда сами рисуем мышку, но и в том случае у мыши только координаты спрашиваются, а рендерится всё уже когда работает рендер). Это не не критично, это заметно.
Seenkao
новенький
 
Сообщения: 62
Зарегистрирован: 01.04.2020 03:37:12

Re: Нативные приложения - снятие нагрузки?

Сообщение скалогрыз » 20.08.2020 06:21:32

runewalsh писал(а):В нём самом по себе нет рекурсии (в отличие от ProcessMessages), он ПРОСТО возвращается по одной из причин.

а как без рекурсии такое реализовать?! оке, там не прямая рекурсия, но косвенная.

допустим, некий обработчик сообщения (н.р. WM_CLICK) вызовет MsgWaitForMultipleObjects().
Единственный способ не блокировать очередь сообщений, это её обрабатывать. При-этом сам обработчик WM_CLICK не завершился, потому что он честно ждёт этот пока MsgWaitFor что-нить вернёт.

сам факт, что кто-то обрабатывает очередь сообщений, уже говорит, о том, что возможна "рекурсия" обработчика одного и того же WM_CLICK.

Seenkao писал(а):оффтоп: Обработка мыши не должна задевать рендер, а раз задевает, значит код не доделан (исключение только когда сами рисуем мышку, но и в том случае у мыши только координаты спрашиваются, а рендерится всё уже когда работает рендер). Это не не критично, это заметно.

ну тебе точно нужно исповедовадь Андроид подход. Там основая очередь <> очередь отрисовки.
И по-умолчанию всё рисование происходит параллельно основному потоку.

В принципе, ты мог бы такой подход сделать единственным для своей версии ZenGL. Расшарки контекстов работают очень давно.
Всё что тебе нужно в основном потоке, проверять, закончил ли поток отрисовки сцену, и если да - вызывать SwapBuffer.
Естествено, поток рисования рисует не в буффер, а в текстуру, а основной перед SwapBuffer-ом, отрисовывает ровно один quad на экран.
Все довольны!
скалогрыз
долгожитель
 
Сообщения: 1722
Зарегистрирован: 03.09.2008 02:36:48

Re: Нативные приложения - снятие нагрузки?

Сообщение runewalsh » 20.08.2020 07:29:37

скалогрыз писал(а):а как без рекурсии такое реализовать?! оке, там не прямая рекурсия, но косвенная.

Если MsgWaitForMultipleObjects вернула WAIT_OBJECT_0 + n (признак, что пришло сообщение) — ты НИЧЕГО НЕ ДЕЛАЕШЬ, вернее, как можно быстрее возвращаешься из своего обработчика, тем самым просто выходишь на следующую итерацию главного цикла, который обработает эти сообщения в общем порядке. Правда, если MsgWait* был промежуточным шагом какого-то сложного процесса, придётся помнить контекст, как async-await прямо — то, что происходит после MsgWait*, становится continuation'ом того, что было до него, так что это будет неудобно, да. В терминах LCL этот continuation можно попытаться упихнуть в TThread.Queue.
Аватара пользователя
runewalsh
постоялец
 
Сообщения: 467
Зарегистрирован: 27.04.2010 00:15:25

Re: Нативные приложения - снятие нагрузки?

Сообщение скалогрыз » 20.08.2020 08:10:18

runewalsh писал(а):вернее, как можно быстрее возвращаешься из своего обработчика, тем самым просто выходишь на следующую итерацию главного цикла

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

Но тогда, по сути, её можно использовать только c QS_ALLEVENTS (либо QS_POSTMESSAGE or QS_SENDMESSAGE). Если использовать что-то другое, то приложение может ощутимо подвиснуть.
Я то думал, она будет ожидать только WAKE сообщения, а все другие тихонечко куртить в себе.
НО используя эту же функцию, вполне несложно такой обработчик написать.

runewalsh писал(а): В терминах LCL этот continuation можно попытаться упихнуть в TThread.Queue.

TThread это FPC RTL, и LCL на него не влияет.

чтобы LCL мог попытаться сделать, так это эмулировать WaitForMultipleObjects на всех платформах. (добавив свою обёртку для объектов синхронизации).

И тогда можно было бы сделать Application.ProcessMessagesWithWaitObjects() :)
а сейчас нужно делать Application.HandleMessage() , а потом с нулевым таймаутом объекты ожидать
скалогрыз
долгожитель
 
Сообщения: 1722
Зарегистрирован: 03.09.2008 02:36:48

Re: Нативные приложения - снятие нагрузки?

Сообщение Seenkao » 20.08.2020 10:35:16

скалогрыз, вообще, я лишь хотел снизить нагрузку. ))) Но в свете того какую информацию получил, то ли оставлять всё как было, то ли конкретно прорабатывать всё и вводить полтонны условий. :)

И это касательно только (как я понимаю) Windows, если и на маке будет так же как на Linux, то эти изменения кроме Windows ни какой платформы не коснутся.
Seenkao
новенький
 
Сообщения: 62
Зарегистрирован: 01.04.2020 03:37:12

Re: Нативные приложения - снятие нагрузки?

Сообщение Seenkao » 21.08.2020 14:39:52

Странно, что все забыли, но вертикальная синхронизация вообще не создана для ограничения FPS.
На ноутбуке установил очередной линукс и понять не мог, что за фигня, прокручиваю страницу, а прорисовывается она "плохо", так называемый "tearing". И вот тут то я вспомнил про вертикальную синхронизацию и для чего она нужна. Чтоб изображение не было "ломаным".

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

Ограничение по FPS - это должен определять разработчик (игрок в игре), а вертикальная синхронизация должна разве что рядом идти.
читаем: https://zen.yandex.ru/media/mywebpc.ru/ ... 00af1e7f39
(и не обязательно что частота посылки кадров видеокарты должна быть больше частоты монитора, может и просто попасть, а в случаях с 60Гц видеокарта и 60Гц монитор, вообще постоянно быть).
Seenkao
новенький
 
Сообщения: 62
Зарегистрирован: 01.04.2020 03:37:12

Пред.След.

Вернуться в Общее

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 2

Рейтинг@Mail.ru