Warsztat » Forum

[C++] Wskaźnik this dla obiektów dynamicznych

Feb 20, 2006 | bs.mechanik |
20 wypowiedzi na 2 stronach:
1 2
bs.mechanik
Feb 20, 2006

Wskaźnik this dla obiektów dynamicznych

Witam.

Ostatniego czasu, postanowiłem pobawić sie trochę w optymalizację obliczeń przy wykorzystaniu SSE.
Początkowo robiłem to pisząc wstawki assemblerowe, jednak po napotkaniu problemu, który tutaj opiszę, przenoisłem się na instrukcje Intrinsics.

Zaimplementowałem operator dodawania (kod w assemblerze i w c++)

Kod: 

__asm{
   mov edx,this;
   mov eax,vec;

   movups xmm0,[edx];
   addps xmm0,[eax];

   movaps retv,xmm0;
}


Kod: 

return CVector3D(_mm_add_ps(_mm_load_ps(vec.c_vecData),_mm_load_ps(c_vecData)));


gdzie vec to parametr operatura + (referencja na wektor), retv wektor zwracany a c_vecData to wyrównana do 16 bajtów tablica 4 floatów.

Dla zwykłego dodawania, typu: result = v1+v2 oraz dodawania w petli dla satycznych tablic (tworzonych na stosie) wszystko działa ok.
Jednak, gdy utworzę dynamicznie tablicę wektorów (operator new) i dla niej wywołam operator+, program sypie się (Access violation). Nie przekraczam zakresu (testowałem dla elementu 0).
Debugger w pierwszym przypadku wskazywał na linijkę: movups xmm0,[edx].
Jeśli chodzi o Intrinsics, zamiana _mm_load_ps(c_vecData) na _mm_set_ps(0.0f,0.0f,0.0f,0.0f) pomaga (program nie wysypuje się), jednak już  _mm_set_ps(c_vecData[0],c_vecData[1],c_vecData[2],c_vecData[3]) powoduje wyżej wspomniany błąd.

Bedę bardzo wdzięczny za pomoc w rozwiązaniu problemu :)
Xion
Feb 22, 2006

Odp: Wskaźnik this dla obiektów dynamicznych

Przypuszczam, że problemem jest wyrównanie. O ile pojedyncze zmienne są wyrównane do 16 bajtów, o tyle dynamicznie utworzona tablica już pewnie nie, i stąd ten AV.
Krzysiek K.
Feb 24, 2006

Odp: Wskaźnik this dla obiektów dynamicznych

Cytat:
Przypuszczam, że problemem jest wyrównanie. O ile pojedyncze zmienne są wyrównane do 16 bajtów, o tyle dynamicznie utworzona tablica już pewnie nie, i stąd ten AV.

Racja. Polecam zamienić ostatni "movaps" na "movups". Poza tym polecam sprawdzić konwencję wywołania metod obiektów, czy przypadkiem this'a nie masz nawsze w ecx. :)
mINA87
Feb 24, 2006

Odp: Wskaźnik this dla obiektów dynamicznych

_mm_loadu_ps - powinno pomóc.
Martwi mnie jednak co innego - używasz movups - to jest wersja dla danych unaligned - powinno być ok (na pewno sie wywala na tej linijce??), a wywalac się powinien dopiero na
Kod: 

addps xmm0,[eax];

bo tutaj procesor będzie chciał uzyskać dostęp do pamięci unaligned.. Dziwne. A spróbuj zamiast tego:
Kod: 

movups xmm0,[edx];
addps xmm0,[eax];
movaps retv,xmm0;

to:
Kod: 

movups xmm0,[edx]
movups xmm1,[eax]
addps xmm0,xmm1
movups retv,xmm0

Albo zrób sobie jakis alokator który zaalokuje ciągły blok pamięci, w nim będziesz mógł powydzielać bloki wyrównane i wtedy wystarczy, że zastosujesz placemnet new :)

//ADD
Krzysiek: addps też tutaj psuje.
bs.mechanik
Feb 23, 2006

Odp: Wskaźnik this dla obiektów dynamicznych

Faktycznie.
Załadowanie this'a do rejestru xmm za pomocą movups i _mm_loadu_ps pomogło. Mam tylko pytanie: czy nie będzie to wolniejsze w działaniu? Przyznam, dość mozno zależy mi na wydajności tego kodu (liczę takty :P), a operowanie na niewyrównanych danych jest wolniejsze. Mozna w jakis sposób to obejść (najlepiej niezauwazalny dla usera końcowego) ?

Cytat:

Poza tym polecam sprawdzić konwencję wywołania metod obiektów, czy przypadkiem this'a nie masz nawsze w ecx. :)


No konwencję miałem taką, że this'a trzymałem w jednym rejestrze. Nie mozna tak? :)
mINA87
Feb 24, 2006

Odp: Wskaźnik this dla obiektów dynamicznych

Jakos tam masakrycznie wolniejsze nie jest, ale nie pamiętam dokłądnei wyników testów.
Co do zrobenia tego na danych wyrównanych to mówię - użyj placement new :) Przykładowo alokuj wszystkie CVectory w jakimś managerze, który pobiera sobie z jakiegoś baseniku zakres już wczesniej zaalokowanej i wyrównanej pamięci i wywołuje na niej placement new. Ewentualnie jesli chcesz ukryć tworzenie obiektów przed użytkownikiem i sprawić by było to bardziej czytelniejsze, to niech klasa CVector nei zawiera skłądowych tylko wskaźnik na jakąś strukturkę je zawierającą i w konctruktorze CVector rób placement new pod wyrównany adres.
Krzysiek miał na myśli że w ecx przeważnie jest this.
Netrix
Feb 27, 2006

Odp: Wskaźnik this dla obiektów dynamicznych

W takim razie trzeba zrobić cały manager na te wektory, bo zwykłe tablice nie będą działać. Gdybyśmy przeciążyli operator new[] i w środku wyrównali to byłby problem ze skakaniem po tej tablicy, czy się mylę?
bs.mechanik
Mar 7, 2006

Odp: Wskaźnik this dla obiektów dynamicznych

mINA87:
To moje ostatnie pytanie - jak można za pomocą new zaalokować wyrównany obszar pamięci?
Składnia:

Kod: 

c_pData = new __declspec(align(16)) float[4];


działa, jednak tylko podczas kompilacji :)
Krzysiek K.
Mar 8, 2006

Odp: Wskaźnik this dla obiektów dynamicznych

Cytat:
To moje ostatnie pytanie - jak można za pomocą new zaalokować wyrównany obszar pamięci?

Zaallokuj odpowiednio więcej i wyrównaj sobie sam. :)
Regedit
Mar 16, 2006

Odp: Wskaźnik this dla obiektów dynamicznych

Każdy typ w C++, oprócz rozmiaru, ma też wyrównanie. Tak jak sizeof zwraca rozmiar, tak __alignof zwraca wyrównanie. Wyrównanie dla typu można ustalić za pomocą __declspec(align(x)) lub #pragma pack(...). Jeśli jakiś typ ma odpowiednie wyrównanie, to kompilator automatycznie go przestrzega tak przy tworzeniu zmiennych lokalnych tego typu na stosie, jak i alokowaniu dynamicznym obiektów na stercie operatorem new. Tylko brutalne rzutowanie z innego typu może dać wskaźnik do niewyrównanych danych. Przykład:

Kod: __declspec(align(16))
struct VEC4 {
  float Tablica[4];
};

...
c_pData = new VEC4;
Esidar
Mar 17, 2006

Odp: Wskaźnik this dla obiektów dynamicznych

Cytat:

jak i alokowaniu dynamicznym obiektów na stercie operatorem new

Jeżeli to sprawdziłeś, to akurat ci dziala zupełnie przypadkiem bo na ogół zwracany jest adres wyrównany do 16 bajtów (taki urok bibliotecznego new) ;) Jak ustawisz align na 256 to nie zadziała :) new nie uwzględnia atrybutu __align bo nie ma za bardzo jak. new używa zwykłego malloc bez podania wyrównania. Nie może też sam wyrównać bo wtedy musiałby dawać specjalny nagłówek z "prawdziwym" nie wyrównanym adresem który przekaże do free.


Cytat:

To moje ostatnie pytanie - jak można za pomocą new zaalokować wyrównany obszar pamięci?

Wyrównywanie w new możesz zrobić tylko przeciążając operator new oraz new[].
mINA87
Mar 19, 2006

Odp: Wskaźnik this dla obiektów dynamicznych

Krzysiek napisał Ci co masz zrobić, a Esidar napisał Ci gdzie masz zrobić :)
Najprościej zrobić to tak - zaalokuj pamięć + align, zwrócony wskaźnik zapisz na boku, normalny wskaźnik potraktuj bitowym & aby odrzucić niewyrównane bity i teraz do adresu który otrzymasz dodaj align - voila :)
Jedyny problem takiego rozwiązania to to, że następuje słabe pokrycie zaalokowanej pamięci i sporo może się marnować, dlatego lepiej zrobić sobie jakiś alokator który będzie przydzielał takie wyrównane bloki z jakiejś większej sterty.
Netrix
Mar 21, 2006

Odp: Wskaźnik this dla obiektów dynamicznych

Czyli bez managera się nie obejdzie, bo "coś" musi trzymać ten niewyrównany wskaźnik.

Wyrównanie to chyba najprościej zrobić tak:
Kod: 

// new[]
Vec* ptr = new[n + 1]; // Ten trzeba zapisać
Vec* aPtr = (Vec*)(((int(ptr) / 16)++) * 16); // kochane nawiasy :>
return aPtr;
yarpen
Mar 22, 2006

Odp: Wskaźnik this dla obiektów dynamicznych

Cytat:

Cytat:

jak i alokowaniu dynamicznym obiektów na stercie operatorem new

Jeżeli to sprawdziłeś, to akurat ci dziala zupełnie przypadkiem bo na ogół zwracany jest adres wyrównany do 16 bajtów (taki urok bibliotecznego new) ;) Jak ustawisz align na 256 to nie zadziała :) new nie uwzględnia atrybutu __align bo nie ma za bardzo jak. new używa zwykłego malloc bez podania wyrównania. Nie może też sam wyrównać bo wtedy musiałby dawać specjalny nagłówek z "prawdziwym" nie wyrównanym adresem który przekaże do free.

Nie do konca. Wg standardu new gwarantuje wyrownanie poprawne dla tworzonego typu. Nie uwzglednia to jednak "hackow" z declspec.
mINA87
Mar 22, 2006

Odp: Wskaźnik this dla obiektów dynamicznych

Możesz go zapisać przed właściwymi danymi ;)
Kod: 

[ dane_pomieniete_na_ewentualne_wyrownanie | adres_poczatkowy | poczatek_wyrownanego_bloku ]
^                                                             ^
||                                                            ||
adres_poczatkowy                          zwracany i wykorzystywany adres

Wtedy manager Ci niepotrzebny a jedynie musisz wykonać proste operacje na wskaźniku.
Netrix
Mar 20, 2006

Odp: Wskaźnik this dla obiektów dynamicznych

Faktycznie, wystarczy dla tablicy wektorów wziąć 1 element więcej + 4 bajty, więc w takim wypadku najlepiej sprowadza się operowanie na tablicy char. Genialne, a takie proste thx :>.
Strony:
1 2