2010-02-03 6 views
3

Я пишу игровой движок, и мне нужен способ получить точное и точное значение «deltatime», из которого можно получить текущий FPS для отладки, а также ограничить частоту кадров (это важно для нашего проекта).Что хорошего в маске слияния нитей для текущей темы?

Выполнение небольшого исследования, я узнал, что один из лучших способов сделать это - использовать функцию QueryPerformanceCounter WinAPI. GetTicksCount должен использоваться для предотвращения forward counter leaps, но это само по себе не очень точно.

Теперь проблема с QueryPerformanceCounter заключается в том, что она, по-видимому, может возвращать значения, которые выглядели бы, если бы время искажалось (т. Е. Вызов может возвращать значение ранее по времени относительно другого вызова в прошлом). Это происходит только тогда, когда значение, полученное с помощью данного ядра процессора сравнивается со значением, полученным с другим ядром процессора, что приводит меня к основным вопросам, которые побудили меня сделать этот пост:

  1. мая OS «перераспределить» нить в другое ядро, пока поток уже запущен, или поток выделяется для данного ядра, и это до тех пор, пока нить не умрет?
  2. Если нить не может быть перераспределена (и это, по крайней мере, имеет для меня большой смысл), то почему это возможно для меня сделать что-то вроде SetThreadAffinityMask(GetCurrentThread(),mask)? Ogre3D делает это в своем Ogre::Timer class (Windows implementation), и я предполагаю, что во избежание повторного возвращения. Но для того, чтобы это было правдой, мне пришлось бы рассмотреть возможность того, что потоки будут перемещаться из одного ядра в другое произвольно ОС, что кажется мне довольно странным (не совсем понятно).

Я думаю, это было все, что я хотел знать. Благодарю.

ответ

2

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

Что касается таймера apis. timeGetTime предназначен для синхронизации мультимедиа, поэтому он немного точнее, чем GetTickCount.

QueryPerformanceCounter(). все еще ваше самое точное измерение. Microsoft говорит об этом.

На многопроцессорном компьютере не должно иметь значения, какой процессор вызывается.Тем не менее, вы можете получить разные результаты на разных процессорах из-за ошибок в базовой системе ввода/вывода (BIOS) или слоя абстракции аппаратного обеспечения (HAL). Чтобы указать сродство процессора к потоку, используйте функцию SetThreadAffinityMask.

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

+0

Полезно знать. Я действительно задавался вопросом, сколько методов было для таких измерений. Действительно ли существуют только те 3 известных портативных метода? –

+1

Насколько я знаю, только те 3. Есть тактика часов в реальном времени, но трудно выйти из режима ядра. и это всего лишь 1,1 Mhz тик. –

+0

Что касается выполнения временных тестов на конкретном компьютере, как я уже сказал, это ** не ** для теста производительности. Это важная и неотъемлемая часть конечного продукта. Но спасибо за комментарий. –

1

Резьбы могут быть и есть (если они не имеют набора аффинити), перераспределенные во время работы потока. Windows увеличивает нагрузку на все процессоры, чтобы максимизировать производительность.

+0

Итак, из того, что вы можете сказать, не устанавливая маску сродства только к одному ядру и используя QueryFrequencyCounter, действительно заставит счетчик warp вернуться, когда функция будет вызвана из разных ядер. Это так? –

+0

Существует вероятность того, что при переключении ядер время может вернуться назад. –

+0

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

0

1) Нить может выделять нить в зависимости от того, какое ядро ​​имеет запасное время обработки. Вот почему вы часто будете видеть программное обеспечение, использующее 50% на четырехъядерной машине, но когда вы проверите графики, используя половину всех четырех.

2) См 1;)

0

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

+0

Зачем кому-то запускать несколько экземпляров игры? – Crashworks

+0

Кто знает. Возможно, фрагменты приложения разбиты на отдельные приложения. Что еще более важно, какое это имеет значение? –

+0

@Crashworks Никто не будет, но у него действительно есть точка. Вот почему я просто не стал настраивать аффинити, не спросив сначала. Я также думал, что это нужно делать только по срокам. Приятно слышать кого-то, кто думал, как я. –

1

Даже если вы заблокируете нить на одном процессоре, используя SetAffinityMask, QPC может работать в обратном направлении, если вам действительно не повезло, а аппаратная часть отстойна. Лучше просто иметь дело с случаем, когда QPC возвращает плохие значения. В Windows 7 QPC значительно улучшилась в этом отношении, но поскольку вы пишете игру, вы, вероятно, нацеливаетесь на XP, где это вам не поможет.

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

+0

Итак, каково ваше предложение? Всякий раз, когда я обнаруживаю обратный ход, игнорируйте событие и используем последнее deltatime? Я мог бы сделать это только в том случае, если бы был уверен, что этого не происходит постоянно. У тебя есть другие идеи? –

+1

Это не будет плохой подход или будет поддерживать среднее число последних 4 кадров и использовать это вместо этого, если вы получите мусор. В общем, вы не увидите, что QPC все время это делает с вами, это довольно редкое явление - это просто тупой игровой код, который делает беззнаковое вычитание и недочеты, что является проблемой –

0

Как правило, нам приходится блокировать нашу игру в один поток при выполнении таймингов из-за этого; нет эффективного пути, который мы нашли, так как вам нужно субмикросекундное разрешение при измерении perf.

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

Аналогично, потому что мы знаем, что например цикл рендеринга всегда будет на ядре 0, мы используем его для временной частоты кадров.

Смежные вопросы