Dlaczego Farseer 2.x przechowuje pliki tymczasowe jako członków, a nie na stosie? (.NETTO)

10

AKTUALIZACJA: To pytanie dotyczy Farseer 2.x. Nowsza wersja 3.x tego nie robi.

W tej chwili używam Farseer Physics Engine dość szeroko i zauważyłem, że wydaje się, że przechowuje wiele tymczasowych typów wartości jako członków klasy, a nie na stosie, jak można się spodziewać.

Oto przykład z Bodyklasy:

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;
}

Wygląda na ręczną optymalizację wydajności. Ale nie rozumiem, w jaki sposób mogłoby to poprawić wydajność? (Jeśli cokolwiek, myślę, że zaszkodziłoby, gdyby obiekty były znacznie większe).

Andrew Russell
źródło

Odpowiedzi:

6

Chociaż typy wartości .NET są przechowywane na stosie, co powoduje minimalny koszt alokacji, nie eliminuje to jednak kosztu inicjalizacji.

W tym przypadku mamy zestaw funkcji wykorzystujących jedną lub dwie macierze tymczasowe, co spowodowałoby inicjalizację 16-32 liczb zmiennoprzecinkowych na wywołanie. Chociaż może się to wydawać nieistotne, jeśli metody są stosowane wystarczająco często (powiedzmy tysiące i tysiące razy na ramkę), całkowity narzut może mieć znaczący wpływ. Jeżeli taka technika jest stosowana systematycznie we wszystkich takich metodach, wyeliminowane koszty ogólne mogą być znaczne.

Chociaż zastosowanie takiej techniki eliminuje możliwość zapewnienia bezpieczeństwa gwintu na poziomie poszczególnych obiektów, generalnie nierozsądne jest zapewnienie tej gwarancji na tak szczegółowym poziomie.

Jason Kozak
źródło
Jesteś pewien? Jedną z moich myśli było to, że można unikać wywoływania konstruktorów. Ale dla typów wartości nie musisz wywoływać konstruktora - w tym domyślnego konstruktora bez parametrów - jeśli zamierzasz ustawić wszystkie elementy (lub przekazać go jako outparametr). Jestem całkiem pewien, że cały sens tej reguły jest taki, aby kompilator mógł pominąć zerowanie tej pamięci - prawda? (Czy to naprawdę tak wolno przesuwać wskaźnik stosu?)
Andrew Russell
Zaskakujące, nie? Niestety, jeśli przejrzysz wygenerowaną IL, macierze tymczasowe zostaną zainicjowane. Kilka szybkich testów pokazuje, że wersja członkostwa jest ~ 10-15% szybsza.
Jason Kozak,
1
Jestem oszołomiony . W „Understanding XNA Framework Performance” (GDC2008) Shawn Hargreaves mówi o strukturach: „[JIT] zwykle zorientuje się:„ w następnym wierszu natychmiast ustawia wszystkie trzy pola [Vector3], więc nawet nie potrzebuję aby zainicjować go do zera ” . Z których pochodzą moje informacje. Ale teraz, słuchając ponownie, mówi tylko „zwykle”. Bezpośrednim następnym punktem prezentacji jest to, że JIT zachowuje się inaczej z dołączonym debuggerem, wpływając na wydajność (jak testowałeś?). Ponadto: mówi tutaj o JIT, więc być może IL pozostaje „miły” (weryfikowalność?).
Andrew Russell
IL został sprawdzony przez Reflector, a testy zostały przeprowadzone poza wbudowanym w IDE wydaniem (w systemie Windows nie mam już członkostwa w CC do testowania)
Jason Kozak
1
W oparciu o to - zastanawiam się, czy byłoby lepiej (i o ile lepiej byłoby) uczynić tych członków tymczasowych static(i / lub bardziej agresywnie ponownie ich używać). Na przykład Bodyklasa Farseer ma około 73 pływaków o wartości „niepotrzebnych” członków.
Andrew Russell,
-1

Dobre pytanie. Jestem dość ostrym facetem C # / .NET i trochę wariatem wydajności, co wydaje mi się dość dziwną decyzją projektową. Pierwszą rzeczą, która mnie zaskakuje, jest to, że ten kod nie jest w żaden sposób bezpieczny dla wątków. Nie wiem, czy jest to problem w systemie fizyki, ale przechowywanie danych tymczasowych poza zakresem metody jest często receptą na katastrofę.

Szczerze mówiąc, gdybym regularnie spotykał się z tego rodzaju kodem w frameworku innej firmy, prawdopodobnie spróbowałbym znaleźć inny framework.

Mike Strobel
źródło
3
Naprawdę nie odpowiada na pytanie.
Brian Ortiz
Tak, najlepiej, co mogłem zrobić, to potwierdzić, że nie jest szalony, i wydaje się, że nie ma żadnej realnej korzyści z tego, że jest tak kodowany. Jedyne, co się naprawdę dzieje, to zapytać faceta, który napisał kod :).
Mike Strobel,
Dzięki, Mike. Zaczynam podejrzewać, że pierwotny deweloper jest szalony, nie ja. Ale zawsze pomaga to sprawdzić;)
Andrew Russell
Bezpieczeństwo wątków może czasami stanowić kosztowną gwarancję, szczególnie przy pisaniu dużej biblioteki obliczeń FP dla platformy, która nie korzysta z instrukcji SIMD.
Jason Kozak,
-1

GC na 360 w zasadzie robi tylko kolekcje GEN 2, które są drogie, więc zmienne tymczasowe, które są tworzone i usuwane z każdej ramki (jak obiekty tymczasowe) powodują, że działają całe kolekcje, co bardzo szybko zabija wydajność.

Podejrzewam, że zrobili to w ten sposób, aby ponownie użyć tego obiektu i nie odebrać go.

Steven Evers
źródło
1
To również przydarzyło mi się, ale członkowie tymczasowi wydają się być typami wartości, więc i tak nie zostaną przydzieleni do zarządzanej sterty.
Mike Strobel
2
Racja, ale tylko jeśli są członkami klasy. Jeśli są lokalni (w zakresie metody), zostaną przydzieleni na stosie. Pytanie brzmi, dlaczego po prostu nie poszli tą drogą.
Mike Strobel,
1
@Blair - Według MSDN ( msdn.microsoft.com/en-us/library/bb203912.aspx ) Xbox360 korzysta z .NET Compact Framework. Wygląda na to, że różnica w GC jest z tym związana, więc kontynuowałbym to do dalszych badań w tej sprawie.
Logan Kincaid,
1
@Blair: @Logan Kincaid jest poprawny. Moduł czyszczenia pamięci CF zachowuje się inaczej niż zwykłe ramy. W XNA Game Studio 3.0 Unleashed jest dobra rozmowa na ten temat - jednak ta książka wkrótce przestanie być aktualna wraz z wydaniem 4.0.
Steven Evers,
1
@Blair: Z powodu ograniczonego środowiska pamięci 360 (i większości urządzeń atakowanych przez CF), używany jest Mark & ​​Sweep GC. W rezultacie wiele małych alokacji uruchomi kolekcję, a czas gromadzenia zależy od liczby referencji. Wiele szczegółów tutaj: download.microsoft.com/.../Mobility/…
Jason Kozak