Почему Farseer 2.x хранит временные файлы как члены, а не в стеке? (.СЕТЬ)

10

ОБНОВЛЕНИЕ: Этот вопрос относится к Farseer 2.x. Более новый 3.x, кажется, не делает этого.

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

Вот пример из Bodyкласса:

private Vector2 _worldPositionTemp = Vector2.Zero;

private Matrix _bodyMatrixTemp = Matrix.Identity;
private Matrix _rotationMatrixTemp = Matrix.Identity;
private Matrix _translationMatrixTemp = Matrix.Identity;

public void GetBodyMatrix(out Matrix bodyMatrix)
{
    Matrix.CreateTranslation(position.X, position.Y, 0, out _translationMatrixTemp);
    Matrix.CreateRotationZ(rotation, out _rotationMatrixTemp);
    Matrix.Multiply(ref _rotationMatrixTemp, ref _translationMatrixTemp, out bodyMatrix);
}

public Vector2 GetWorldPosition(Vector2 localPosition)
{
    GetBodyMatrix(out _bodyMatrixTemp);
    Vector2.Transform(ref localPosition, ref _bodyMatrixTemp, out _worldPositionTemp);
    return _worldPositionTemp;
}

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

Эндрю Рассел
источник

Ответы:

6

Хотя типы значений в .NET хранятся в стеке, что приводит к минимальной стоимости размещения, это, тем не менее, не устраняет стоимость инициализации.

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

Хотя использование такого метода исключает возможность обеспечения безопасности потоков на уровне отдельных объектов, в общем случае неразумно предоставлять такую ​​гарантию на таком детальном уровне.

Джейсон Козак
источник
Вы уверены, что? У меня была одна мысль: возможно, следует избегать вызова конструкторов. Но для типов значений вам не нужно вызывать конструктор - включая конструктор по умолчанию без параметров - если вы собираетесь установить все члены (или передать его в качестве outпараметра). Я вполне уверен, что весь смысл этого правила таков, что компилятор может пропустить обнуление этой памяти - верно? (Действительно ли так медленно перемещать указатель стека?)
Эндрю Рассел
Удивительно, нет? К сожалению, если вы проверяете сгенерированный IL, временные матрицы инициализируются. Несколько быстрых тестов показывают, что временная версия члена на ~ 10-15% быстрее.
Джейсон Козак
1
Я ошеломлен . В «Понимании производительности XNA Framework» (GDC2008) Шон Харгривз говорит о структурах: «[JIT] обычно выяснит :« в следующей строке он сразу устанавливает все три поля [вектора 3], поэтому мне даже не нужно инициализировать его до нуля » . Отсюда моя информация. Но теперь, слушая снова, он говорит только «обычно». Следующий момент в презентации заключается в том, что JIT ведет себя по-разному с подключенным отладчиком, что влияет на производительность (как вы тестировали?). Кроме того: он говорит о JIT здесь, так что, возможно, IL остается "хорошим" (проверяемость?).
Эндрю Рассел
IL был проверен с помощью Reflector, и тесты выполнялись за пределами IDE, встроенной в Release (в Windows у меня больше нет членов CC для тестирования)
Джейсон Козак,
1
Исходя из этого - мне интересно, было бы лучше (и насколько лучше) сделать этих временных членов static(и / или более агрессивно их повторно использовать). Так, например, у Bodyкласса в Farseer есть около 73 поплавков «ненужных» членов.
Эндрю Рассел
-1

Хороший вопрос. Я довольно проницательный парень из C # / .NET и немного псих, и это кажется мне довольно странным дизайнерским решением. Первое, что бросается в глаза, это то, что этот код никоим образом не безопасен для потоков. Я не знаю, является ли это проблемой в физической системе, но хранение временных данных вне области действия метода часто приводит к катастрофе.

Честно говоря, если бы я регулярно сталкивался с такого рода кодом в сторонних фреймворках, я, вероятно, попытался бы найти другой фреймворк.

Майк Штробель
источник
3
На самом деле не отвечает на вопрос.
Брайан Ортис
Да, лучшее, что я мог сделать, это подтвердить, что он не сумасшедший, и, кажется, нет никакой реальной выгоды, если бы его кодировали таким образом. Единственный способ узнать истинное намерение - это спросить парня, который написал код :).
Майк Штробель
Спасибо, Майк. Я начинаю подозревать, что оригинальный разработчик - сумасшедший, а не я. Но это всегда помогает проверить;)
Эндрю Рассел
Иногда обеспечение безопасности потоков может быть дорогостоящей гарантией, особенно при написании тяжелой библиотеки вычислений FP для платформы, которая не использует SIMD-инструкции.
Джейсон Козак
-1

GC на 360 в основном делает только коллекции GEN 2, которые дороги, поэтому временные переменные, которые создаются и удаляются каждый кадр (например, временные объекты), приводят к запуску целых коллекций, что очень быстро снижает производительность.

Я подозреваю, что они сделали это таким образом, чтобы повторно использовать этот объект, а не собирать его.

Стивен Эверс
источник
1
Это также произошло со мной, но временные члены, по-видимому, являются типами значений, поэтому они не будут размещаться в управляемой куче в любом случае.
Майк Штробель
2
Правильно, но только если они ученики. Если они являются локальными (метод-область), они будут размещены в стеке. Вопрос в том, почему они просто не пошли по этому пути.
Майк Штробель
1
@Blair - Согласно MSDN ( msdn.microsoft.com/en-us/library/bb203912.aspx ) Xbox360 использует .NET Compact Framework. Похоже, что разница в GC связана с этим, поэтому я бы продолжил это для дальнейшего исследования по этому вопросу.
Логан Кинкейд
1
@Blair: @Logan Kincaid - это правильно. Сборщик мусора CF ведет себя иначе, чем обычные рамки. В XNA Game Studio 3.0 Unleashed есть хороший разговор на эту тему - однако эта книга скоро выйдет из употребления с выходом 4.0.
Стивен Эверс
1
@Blair: из-за ограниченной среды памяти 360 (и большинства устройств, предназначенных для CF), используется Mark & ​​Sweep GC. В результате, большое количество небольших выделений инициирует сбор, а время сбора зависит от количества ссылок. Много подробностей здесь: download.microsoft.com/.../Mobility/…
Джейсон Козак