Что хорошего в изменениях маски сходства потоков для текущего потока? - PullRequest
3 голосов
/ 03 февраля 2010

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

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

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

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

Я думаю, это было все, что я хотел знать на данный момент. Спасибо.

Ответы [ 6 ]

2 голосов
/ 03 февраля 2010

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

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

QueryPerformanceCounter(). все еще является вашим самым точным измерением. У Microsoft есть это, чтобы сказать об этом.

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

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

1 голос
/ 03 февраля 2010

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

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

1 голос
/ 03 февраля 2010

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

0 голосов
/ 04 февраля 2010

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

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

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

0 голосов
/ 03 февраля 2010

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

0 голосов
/ 03 февраля 2010

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

2) См. 1;)

...