Ru-MaNGOS

Ru-MaNGOS (http://mangos.ytdb.ru/index.php)
-   Принятые патчи (http://mangos.ytdb.ru/forumdisplay.php?f=5)
-   -   [10924][patch] Timer system improved (http://mangos.ytdb.ru/showthread.php?t=3272)

Ambal 22.12.2010 14:32

[10924][patch] Timer system improved
 
Всем трямс :)

Данный пост - это дублирование оригинальной темы Timer system improved на getmangos.com.

Вкратце о патче: попытка реализовать отправку диффов времени между актуальными апдейтами объектов включая правку недостатков патчей [10677] "Send to creature/etc Update call real diff from last update and use it." и [10688] "New version of patch for send real diff from last update.". Как и что тестировать вы, я уверен, уже в курсе :yes3:

Тему решил продублировать на этом форуме исключительно по причине того, что на офф форуме добиться быстрых и полезных отзывов о патче практически нереально.

Мимо не проходим, тема актуальная и важная. Постить отзывы также не стесняемся. :yes3:

Репозиторий патча: https://github.com/Ambal/mangos
ветка: master

rsa 22.12.2010 15:26

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

Ambal 22.12.2010 15:31

Если вы не заметили, в этом патче мы имеем центр точного времени. Обратите внимание на код классов WorldTimer и как время системы используется в WorldObject::UpdateHelper для вычисления дифа между апдейтами объекта. Мы устанавливаем точное время в момент очередного "тика" основного цикла, потом этот момент времени является отправной точкой для прочих вычислений дифов.

Описание логики работы патча можете почитать на офф форуме, а также о его принципиальных отличиях в реализации "ни то, ни се".

rsa 22.12.2010 15:40

Это не центр точного времени а атомизация. См. выше. При наличии центра точного времени передача абсолютного значения тика по цепочке вызовов бессмысленна в принципе.
Логику работы я вполне достаточно изучил в процессе борьбы с 10688 и дальнейшего переругивания с Владимиром ;)

Ambal 22.12.2010 15:45

Пусть будет "атомизация времени", мне принципиально все равно. Также вам придется вспомнить логику работы в [10677] и найти принципиальное отличие с предложенный подходом.

P.S. Не будем вдаваться в полемику по поводу "центра точного времени" и "атомизации" ради решения тривиальной задачи "вычислить время между моментами А и В". На офф форуме я достаточно подробно нарисовал истинную причину появления огромных дифов, которые объекты получали в обеих патчах.

rsa 22.12.2010 16:00

Подобную картину вместе с решениями я рисовал в процессе борьбы. И с моей точки зрения, пока мы не начнем хранить время последнего обновления в свойствах объекта и не будем использовать настоящий центр точного времени, от вероятности появления огромных диффов мы не избавимся. Она и сейчас ненулевая хотя и очень низкая.

Ambal 22.12.2010 16:05

Цитата:

Сообщение от rsa (Сообщение 17492)
пока мы не начнем хранить время последнего обновления в свойствах объекта

Разве не это я делаю в предложенном патче? А точное время нас интересует исключительно с точки зрения "в какой момент времени у нас началось текущее обновление мира" - эти данные фиксированы на текущий тик, и если вы взглянете на код мангоса, то в Update(uint32 diff) ЛЮБЫМ объектам мы передаем ОДНО И ТОЖЕ значение diff независимо от того, в какой момент времени они были созданы. Собственно говоря, подобный подход реализован и в предложенном патче - ничего принципиально удивительного и невероятного.

rsa 22.12.2010 16:14

Вот именно в том что вами сейчас описано и имеет место основная проблема. Без ее решения установка дополнительных подпорок возможна, но непринципиальна.
1. время крайнего обновления должно храниться в объекте.
2. дифф должен не передаваться в ворлдтике а вычисляться в обновляемом объекте в момент обновления.
3. для реализации использования 1 и 2 нужна реалтаймнить с часами и механизм быстрого запроса времени, естественно блокируемый.
это конечно мое HO и наверняка приведет к куче других граблей. но уже _других_.

Ambal 22.12.2010 16:24

Цитата:

Сообщение от rsa (Сообщение 17495)
2. дифф должен не передаваться в ворлдтике а вычисляться в обновляемом объекте в момент обновления.

А он и вычисляется для каждого объекта в рантайме. С принципиальной разницей: если два объекта были созданы в один world_tick, то на второй тик они получат абсолютно одинаковые update_diff. Не думаю, что если один моб получит дифф в 200, а соседний в 199 мсек, то это привнесет в игру что-то принципиально новое в плане геймплея. Текущая схема с передачей в Update(uint32 diff) фиксированного world_diff почему-то никого не напрягает.

rsa 22.12.2010 16:38

Говорим о разных вещах... ACE_OS::gettimeofday(); получает время текущей нити. А оно квантованое. От 2 до 100мс в зависимости от ОС и ее загрузки. И полагаться на него вовсе не стоит - атомизация и то лучше. К тому же в других нитях может быть сдвиг на +-квант. И время его передачи внутри класса тоже гуляет. И еще загрузка влияет на все это... А текущая ситуация - "работает, не трожь".

Ambal 22.12.2010 16:43

Цитата:

Сообщение от rsa (Сообщение 17498)
К тому же в других нитях может быть сдвиг на +-квант. И время его передачи внутри класса тоже гуляет. И еще загрузка влияет на все это... А текущая ситуация - "работает, не трожь".

Так чем это усложняет нам работу если мы сохраняем время ворлд тика в момент очередного World::Update() ? А когда мы сохраняем timestamp времени последнего обновления объекта или для расчетов диффа, мы используем время текущего ворлд тика, а не данные, полученные через ACE_OS::gettimeofday().

rsa 22.12.2010 16:46

Это не усложняет нам работу. Это просто не имеет особых преимуществ по сравнению с текущей ситуацией - многопоточная обработка будет по прежнему рассинхронизирована. Даже при прямом использовании ACE_OS::gettimeofday() в объекте - см. замечание про квантование. А если не двигаться в сторону многопоточности - на кой вообще заводиться? "Работает - не трожь".

Ambal 22.12.2010 16:50

Цитата:

Сообщение от rsa (Сообщение 17500)
Это не усложняет нам работу. Это просто не имеет особых преимуществ по сравнению с текущей ситуацией.

Я согласен, какое же это преимущество иметь рабочий вариант решения проблемы с расчетом дифов между апдейтами объектов, который не страдает болезнями предыдущих решений... Пыль :pardon:

P.S. ИМХО, я не собираюсь решать проблемы, связанные с расчетом времени, когда точность +/- 3 км, ради того чтобы дифы апдейтов отличались незначительно. Либо вам придется привести серьезный пример мегабонуса с точным расчетом времени дифов для каждого объекта.

rsa 22.12.2010 16:58

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

Ambal 22.12.2010 17:00

Цитата:

Сообщение от rsa (Сообщение 17503)
потенциальные плюсы должны как минимум перевешивать потенциальные минусы, а тут этого нет.

Теперь вы потрудитесь объяснить, какие потенциальные минусы перевешивают потенциальные плюсы. С конкретными примерами.

P.S. Какие потенциальные минусы могут перевестить плюшки в виде респавнящихся на неактивных гридах мобов и подобных вещей?

rsa 23.12.2010 11:45

Цитата:

Сообщение от Ambal (Сообщение 17501)
P.S. ИМХО, я не собираюсь решать проблемы, связанные с расчетом времени, когда точность +/- 3 км, ради того чтобы дифы апдейтов отличались незначительно. Либо вам придется привести серьезный пример мегабонуса с точным расчетом времени дифов для каждого объекта.

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

Ambal 23.12.2010 11:52

Цитата:

Сообщение от rsa (Сообщение 17546)
представьте себе 2 объекта, находящихся рядом но обрабатываемых в разных нитях.

Во-первых, я как-то слабо себе представляю обработку двух объектов на одной карте разными потоками - это явно к мангосу отношения не имеет. Во-вторых, поинтересуйтесь изменениями в коде WorldTimer::getMSTimeDiff() - эта функция теперь не допустит огромных дифов если вы получили сдвиг времени назад, она просто вычислит наименьший дифф времени и выдаст его как результат.

rsa 23.12.2010 13:14

Цитата:

Сообщение от Ambal (Сообщение 17547)
Во-первых, я как-то слабо себе представляю обработку двух объектов на одной карте разными потоками - это явно к мангосу отношения не имеет. Во-вторых, поинтересуйтесь изменениями в коде WorldTimer::getMSTimeDiff() - эта функция теперь не допустит огромных дифов если вы получили сдвиг времени назад, она просто вычислит наименьший дифф времени и выдаст его как результат.

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

Ambal 23.12.2010 13:30

Цитата:

Сообщение от rsa (Сообщение 17552)
1. некоторые компиляторы давно умеют безо всякого спроса распараллеливать процессы.
2. а для решения нужна нить с точным временем.

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

2) По поводу отдельного потока, считающего время: вам в любом случае придется решать проблемы с квантованием времени, ставить подпорки на защиту от перевода системного таймера и прочие радости метрологии. Частично эти проблемы уже решены в данном патче. Хотите дальнейших улучшений? Предлагайте код, а не очередные претензии.

rsa 23.12.2010 13:58

И даже при использовании mtmaps (достаточно простом варианте многопоточности) можно пострадать при разном времени в разных нитях. Потому что без синхронизации не обойтись.
Никаких претензий я не предъявлял, уже было написано что работа нужная, но уж делать - так делать в комплексе. Предлагать код - бессмысленно, вы в этой теме понимаете гораздо больше меня. Направление для улучшения - я предложил. Надо расписать блоксхему?
При наличии отдельного потока для времени решать проблемы с квантованием более не придется - для этого оно и предназначено. Квант везде будет одинаков.

Ambal 23.12.2010 14:12

Цитата:

Сообщение от rsa (Сообщение 17554)
При наличии отдельного потока для времени решать проблемы с квантованием более не придется - для этого оно и предназначено.

Проблема с отдельным потоком в том, что классическая схема

Код:

while(_running)
{
time_t tmStart = getMSTime();
Sleep(1);
uint32 tick = getMSTime() - tmStart;
}

в любом случае предполагает что квант времени будет равен значению системного таймера, который "пляшет" на разных ОСях в самых разных диапазонах. Для примера, ОС Windows имеет стандартный таймер на 15 мсек (т.е. Sleep(1) на самом деле является Sleep(15)). Даже если мы будет использовать мьютексы аля WaitForSingleObject(handle, 1), поток все равно "проспит" количество времени равное разрешению системного таймера. Таким образом ТОЧНОЕ время вы все равно не получите, а будете ограничены алгоритмом работы потока-счетчика и результатом, который он успел насчитать во время последней активности.

Возникает логичный вопрос: если мы в любом случае будем иметь фиксированное значение системного времени в интервале неактивности потока таймера, то как будет клиент реагировать на такие timestamps? Если клиент преспокойно проживет получая одно и тоже время в пределах одного тика, то имеет прямой смысл (на первых порах) "точный таймер" реализовать в контексте основного потока - изменять его значение перед каждым вызовом World::Update().

Vladimir 23.12.2010 15:00

rsa, при текущей выбранной схеме как цели с тиком в одном потоке и только отработкой тика в Update в разных потоках разные значения таймера сохранненого пeред паралельной частью быть не может. А другие схемы мы поддержитвать вроде не собираемся. Всякие локальные распаралеливания на это не влияют до тех пор пока значени сохранненого времени только читается и все потоки гарантированно замерзают до следующего общего тика.

Ambal 23.12.2010 15:38

Пока мы тратили 2 дня на словесную перепалку на форуме, в голову закралась мысля использовать функцию clock_t clock(void); которая возвращает количество тиков системного таймера с момента запуска процесса.

CPU and Process times
clock function

rsa 23.12.2010 15:45

Цитата:

Сообщение от Ambal (Сообщение 17556)
в любом случае предполагает что квант времени будет равен значению системного таймера, который "пляшет" на разных ОСях в самых разных диапазонах. Для примера, ОС Windows имеет стандартный таймер на 15 мсек (т.е. Sleep(1) на самом деле является Sleep(15)). Даже если мы будет использовать мьютексы аля WaitForSingleObject(handle, 1), поток все равно "проспит" количество времени равное разрешению системного таймера. Таким образом ТОЧНОЕ время вы все равно не получите, а будете ограничены алгоритмом работы потока-счетчика и результатом, который он успел насчитать во время последней активности.

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

--- timeThread
While(true)
{
WhiteForMutex1()
GetSystemTime()
SendTimeOverQueueOrPipe();
DropMutex1();
SendMutex2();
}
-- ClientThreads
getTime
{
SendMutex1()
WhiteForMutex2();
GetTimeFromQueueOrPipe();
DropMutex2();
}

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

Добавлено через 4 минуты
Цитата:

Сообщение от Vladimir (Сообщение 17561)
rsa, при текущей выбранной схеме как цели с тиком в одном потоке и только отработкой тика в Update в разных потоках разные значения таймера сохранненого пeред паралельной частью быть не может. А другие схемы мы поддержитвать вроде не собираемся. Всякие локальные распаралеливания на это не влияют до тех пор пока значени сохранненого времени только читается и все потоки гарантированно замерзают до следующего общего тика.

ну во первых может (я пытался завести распараллеливание не map-based а grid-based. вышло хреново. но возможно и при map-based, объекты-то иногда перемещаются...). а во вторых - надо стремиться к максимальному thread-safe. причем желательно на стадии проектирования.

Ambal 24.12.2010 11:39

В мангосе вычисление разницы между временными точками применяется слишком редко чтобы заморачиваться с отдельным потоком, считающим "точное время" с определенной погрешностью.
В рамках предложенного в патче подхода к вычислению диффа между апдейтами объектов мы не нуждаемся в "точном времени" - с нас достаточно хранить и использовать время начала очередного world_tick, которое будет вычисляться и дальше в одном (главном) потоке.
Все прочие схемы, ИМХО, как работы потоков так и алгоритмов расчета диффов объектов, не имеют особой практической ценности. Поэтому, также ИМХО, не вижу смысла заморачиваться с их реализацией.

zhenya 25.12.2010 07:25

Оффтоп. а почему не openmp? :-) вроде тоже неплохое решение.

Ambal 27.12.2010 11:27

Цитата:

Сообщение от zhenya (Сообщение 17674)
а почему не openmp?

А смысл? OpenMP имеет лишь одно преимущество - это сокрытие под всяческими прагмами нюансов реализации тех или иных объектов синхронизации и параллельных алгоритмов. У нас все это есть в ТВВ и АСЕ. ИМХО, зачем тянуть еще один рантайм непонятно...

Оффтоп: патч хоть кто-то смог потестировать? :) Или его надо в основную ветку закоммитить дабы получить по нему отзывы? :)


Текущее время: 02:06. Часовой пояс GMT +3.

ru-mangos.ru - Русское сообщество MaNGOS