kategoria: Asembler
[#31] Re: Czyszczenie bloku pamięci w Asemblerze

@mateusz_s, post #28

problem chyba leży w tym wywoływaniu 10 000 razy, bez tej petli tylko z wiekszym buforem wyniki troche mniej sie rozniły


// ---------------------------
file: asm.s

	xdef _my_clear

_my_clear:
	moveq #0,d0

loop:
	move.l d0,(a0)+
	move.l d0,(a0)+
	subq.l #1,d1
	bne loop

	rts

// ----------------------------


file: main.c

void my_clear(
 unsigned char* buffer asm("a0"),
 long value asm("d1")
);

#define mysize	320*240
unsigned char* buffer;

main()
{
	buffer = (unsigned char*)malloc(mysize * sizeof(unsigned char));


	// ~1.42 s
	// for (int i = 0; i < 10000; i++) memset(buffer, 0, mysize); 

	// ~7 s
	for (int i = 0; i < 10000; i++) my_clear(buffer, mysize/8- 1);	
}
[#32] Re: Czyszczenie bloku pamięci w Asemblerze

@drsky, post #30

Movem.l nie ma dozwolonego trybu adresowania ()+ kiedy źródłem są rejestry ale można ustawić na koniec czyszczonego obszaru i czyścić w kierunku początku bufora.
Zastanawiam się czemu Kiero czyści z użyciem move16. Movem.l pozwala wyczyścić 56 bajtów na raz kosztem 1 cykl per 4 bajty na 060. Movem16 zajmuje 18 cykli per 16 bajtów i wymaga dekrementacji adresu źródłowego. Obie są pEOP-only.

Edit. Doczytałem że movem16 to 11 cykli na 16 bajtów gdy dane źródłowe są w cache. Dalej to i tak trzy razy wolniej od movem co zgadzałoby się z wynikami testu.

Ostatnia aktualizacja: 03.06.2021 09:45:33 przez Kefir_Union
[#33] Re: Czyszczenie bloku pamięci w Asemblerze

@Kefir_Union, post #32

To jest przypadek kiedy ilość cykli nie ma większego znaczenia. Tu chodzi o prędkość pamięci, cache itp. Nie pamiętam już teraz dokładnie jak działał zapis do pamięci przy zapisie całej linii i innych szczegółów tego problemu, ale znalazłem wątek który powinien nieco rozjaśnić. No i jak zawsze odsyłam do 68040/60 UM:)

Dodatkowa zaleta move16 w tym przypadku jest taka, że nie powoduje wyrzucenia innych danych z cache. Tak więc jeżeli mamy gorące dane przed czyszczeniem/kopiowaniem pamięci nie zostaną one wyrzucone. Bardzo sytuacyjne oczywiście.

PS. Testowanie tego na UAE to kompletna pomyłka. Musiałbyś mieć dokładną emulację cache i prędkości pamięci. UAE nie ma nawet dokładnej emulacji samej 68040/060:)

Ostatnia aktualizacja: 03.06.2021 10:36:16 przez kiero
1
[#34] Re: Czyszczenie bloku pamięci w Asemblerze

@kiero, post #33

tu jeszcze na gorąco wynik z V4 (tak wiem że nie lubicie :) ale Koledzy akurat mieli pod ręką)

my_clear: 0.14 s
memtest: 0.12 s

jakby dodać kilka move to pewnie by jezszcze bylo troceh szybciej

odnośnie move16 - to ponoć ono robi READ i WRITE wiec jest 2x wolniesze:

taki był kod testujący, bez petli tylko bufor o rozmiarze 3200*2400*5

// ---------------------------
file: asm.s

	xdef _my_clear

_my_clear:
	moveq #0,d0

loop:
	move.l d0,(a0)+
	move.l d0,(a0)+
	move.l d0,(a0)+
	move.l d0,(a0)+
	move.l d0,(a0)+
	move.l d0,(a0)+
	move.l d0,(a0)+
	move.l d0,(a0)+

	subq.l #1,d1
	bne loop

	rts

// ----------------------------


file: main.c

unsigned char* buffer;

void my_clear(
 unsigned char* buffer asm("a0"),
 long value asm("d1")
);

#define mysize	3200*2400*5

int main(void)
{

	buffer = (unsigned char*)malloc(mysize * sizeof(unsigned char));

	printf("memsize: %d\n MB", mysize/1024);

	for (int i = 0; i < mysize; i++)
	{
		buffer[i] = i;
	}


	long now = clock();
   	my_clear(buffer, mysize/32- 1);
	float end = (float)(clock() - now) / CLOCKS_PER_SEC;  
	printf("my_clear time: %.5f\n\n", end);


	now = clock();
	memset(buffer, 0,mysize);
	end = (float)(clock() - now) / CLOCKS_PER_SEC;
	printf("memset time: %.5f\n\n", end);

	return 0;
}


Ostatnia aktualizacja: 03.06.2021 11:45:13 przez mateusz_s
[#35] Re: Czyszczenie bloku pamięci w Asemblerze

@mateusz_s, post #34

odnośnie move16 - to ponoć ono robi READ i WRITE wiec jest 2x wolniesze:

Move16 jest 3 razy wolniejsze licząc czas wykonywania instrukcji. Z tego co pisze Kiero to gdy dostęp do pamięci jest wolny i procesor czeka na dane z szyny to przestaje mieć znaczenie ponieważ czas oczekiwania jest dłuższy niż czas wykonywania wolniejszego move16. Bardzo ciekawy jestem jakie to są wartości bo nic nie udało mi się znaleźć na ten temat. Stawiam że przy Vampire pamięć jest tak szybka jak procesor tzn. cykl cpu w cykl szyny i move16 będzie wolniejsze.
Zaletą użycia move16 ma być to że nie wpływa na dane umieszczone w cache.
Accesses by the MOVE16 instruction also do not allocate cache lines in the data cache foreither read or write misses. Read hits on either valid or dirty cache lines are read from thecache. Write hits invalidate a matching line and perform an external access. Interacting withthe cache in this manner prevents a large block move or block initialization implemented witha MOVE16 from being cached, since the data may not be needed immediately.


Ostatnia aktualizacja: 03.06.2021 14:03:13 przez Kefir_Union
[#36] Re: Czyszczenie bloku pamięci w Asemblerze

@mateusz_s, post #34

Nie chodzi o to, ze move16 robi read and write, ale chodzi o dlugosc dzialania tej instrukcji ona dziala na 16 bajtach (128 bitach) na raz, przez to dobrze uzyta powinna byc szybsza niz inne sposoby czyszczenia pamieci na 68040/68060. Co do 68080 to moze dzialac na 64 bitach, wiec najprawdopodobniej laczy 2x move.l D0,(A0)+ w jeden zapis 64 bitowy, ale nie sledze rozwoju 68080 az tak dokladnie, na pewno potrafi juz robic movem.l 64 bitowy w 1 cyklu, a wczesniej nie potrafil, mial 32 bity na 1 cykl tylko. Spytaj sie SpeedGeeka o czyszczenie pamieci z uzyciem move16. I zrob test tej procedury na realnej 68040 i 68060.
[#37] Re: Czyszczenie bloku pamięci w Asemblerze

@Kefir_Union, post #35

Ja gdzies znalazlem info, ze move16 potrzebuje tylko 5 cykli, ale nie moge tego znowu znalezc. Na pewno jest szybszy niz move.l lub movem.l na 68040 i 68060, jezeli jest odpowiednio uzyty. Bo nie bylby uzywany przez FastATA i RoadShow.
[#38] Re: Czyszczenie bloku pamięci w Asemblerze

@Don_Adan, post #37

https://images91.fotosik.pl/507/9313e7e21d05f470.jpg

Movem reg->mem potrzebuje 1 cykl na 4 bajty. Move16 potrzebuje w najlepszym przypadku 11 cykli na 16 bajtów.

Różnica tkwi w ilości cykli dostępu do pamięci. Move16 potrzebuje dwóch a movem czterech (przy zapisie 16 bajtów). To oznacza że im wolniejsza pamięć tym czas wykonywania będzie relatywnie coraz szybszy na move16 i coraz wolniejszy dla movem. W którymś momencie te linie na wykresie się przetną, ciekawy jestem kiedy tzn. jak wolna musi być pamięć żeby move16 było szybsze.

Ostatnia aktualizacja: 03.06.2021 14:38:10 przez Kefir_Union
[#39] Re: Czyszczenie bloku pamięci w Asemblerze

@Kefir_Union, post #38

Pewnie masz racje, choc wydaje mi sie ze movem.l wymaga 1 plus 1 cykl na kazdy rejestr. Bo movem.l ,-(SP) to 1 cykl, a movem.l D0,-(SP) to wedlug mnie 2 cykle, a nie 1. No chyba, ze movem.l bezrejestrowe dziala z ta sama predkoscia co movem.l z jednym rejestrem, choc w to watpie.
[#40] Re: Czyszczenie bloku pamięci w Asemblerze

@mateusz_s, post #34

Warto też zastanowić się, czy potrzebujesz czyścić tablicę wyrażeń logicznych co ramkę (1/50 sekundy).

Pisałem wcześniej, że niektóre elementy logiki gry można robić rzadziej niż wyświetlanie animacji na ekranie.

Przykładowo czasami wystarczy nawet 1/10 sekundy dla obsługi obiektów (entities) w grze, a nawet sekunda, jeżeli np. zliczasz czas gry.

Dotyczy to np. wszelakich mechanizmów w grze - jakieś wydarzenia, przyciski, wajchy, ruchy przeciwników itp.

Można to zrealizować np. za pomocą timer.device lub zliczania klatek VBlank - rozkładasz sobie wtedy różne zadania w czasie.

Daje to mnóstwo oddechu programowi i kodowi. Warto wybrać taką dokładność, jaka jest potrzebna.

W wielu przypadkach można ograniczyć liczbę obiektów w grze do przeskanowania, stosując właściwe struktury danych.

Np. jak masz planszę 20x16 i wiesz, że pojawi się tam nie więcej niż np. 50 obiektów, warto przetrzymywać je na osobnej liście, a nie w tej tablicy dwuwymiarowej, która ma 320 pól i co najwyżej dać odnośnik w tej tablicy.

Skanowanie obiektów jest wtedy szybsze i zależy od liczby obiektów, a nie rozmiaru planszy.
[#41] Re: Czyszczenie bloku pamięci w Asemblerze

@Hexmage960, post #40

W tym przypadku chyba by nie zadziałało, ponieważ ja tego buforka używam do zaznaczenia miejsca gdzie został wpisany pixel tworzący ścianę. Korzystam z tego przy rysowaniu podlogi i sufitów zeby się "wstrzelić" i nie rysować po ścianach, ponieważ najpierw rysuje ściany a potem sufity.

No i okazało się, że samo czyszczenie memsetem jednak nie zużywa tak dużo fps jak myślałem, właściwie to wpływ jest znikomy, fps zabiera samo wsadzanie do tej tablicy podczas rysowania ścian..

ale jeszcze mi przyszło go głowy, tzn. przypomniałem sobie - żeby wywalić ten bufor w ogóle i skorzystać z wyjsciowego bufora w ktorym są juz narysowane ściany..

już tak kiedyś robiłem przy wcześniejszych wariantach, ale dużo się pozmieniało w kodzie od tego czasu, wiec warto jeszcze raz to przetestować, przy czym wcześniej tym kolorem "przeźroczystym" był zerowy - (zeby szybciej sprawdzać) - wieć textury nie mogły mieć koloru czarnego.. ale przecież mój kolor jest 4 bajtowy wiec mam dodatkowy kanał wiec mogę to sprawdzić przez operator logiczny, potestuje to dzisiaj.. może coś zyskam..
[#42] Re: Czyszczenie bloku pamięci w Asemblerze

@Don_Adan, post #39

Na 060 tryb adresowania -(Ax) jest za darmo. Manual motoroli strona 10-14.
[#43] Re: Czyszczenie bloku pamięci w Asemblerze

@Kefir_Union, post #42

Ok. Co do szybkosci dzialania move16 vs movem to wyglada, ze dla pamieci typu SIMM na pewno move16 jest szybsze, skoro i dla DIMM jest szybsze. A na Warpie czy TF1260 to trzeba by sprawdzic.
Tutaj sa wyniki dla CT60 z Atari Falcon. Do tego tutaj jest kod bez tst.w 16(Ax) wiec nie wiem czy to jest optymalny kod do uzywania move16.

link
[#44] Re: Czyszczenie bloku pamięci w Asemblerze

@Don_Adan, post #43

Pod tym linkiem nie ma nic o czyszczeniu, jest o kopiowaniu. Kopiowanie wymaga użycia dwóch instrukcji movem więc nie ma czego porównywać. Zresztą w tamtym wątku nie są podane żadne czasy. Widać że nie bardzo ludzie mają pojęcie o 060, niektórzy pokazują tabelki cykli dla starszych procesorów
1
[#45] Re: Czyszczenie bloku pamięci w Asemblerze

@Kefir_Union, post #44

Ja to rozumiem tak, ze on to mierzyl w 60 Hz VBL. Czyli jakies 0.16666 s, o ile dobrze licze. Ale zawsze lepiej testy zrobic samemu.
1
[#46] Re: Czyszczenie bloku pamięci w Asemblerze

@Don_Adan, post #45

Z takiego testu wynika że dwie movem.l są nieznacznie wolniejsze od jednego move16. Przy czyszczeniu potrzebny jest tylko jeden movem.l więc będzie prawie dwa razy szybciej.
1
[#47] Re: Czyszczenie bloku pamięci w Asemblerze

@kiero, post #22

Takie pytanie. Uzywales move16 w demach? Bo przeciwnikiem uzywania tej instrukcji na Amidze jest Thor. Ale on czesto marudzi, jest zafiksowany na MMU. A ta instrukcja nie jest MMU friendly.
1
[#48] Re: Czyszczenie bloku pamięci w Asemblerze

@Kefir_Union, post #46

Tutaj sa nastepne testy dotyczace kopiowania, wynika z nich, ze move16 jest ponad 30% szybsze niz standardowe kopiowanie na jego konfigu z 68060. To juz moze byc oplacalne, zeby uzywac przy kopiowaniu.

link
Na stronie www.PPA.pl, podobnie jak na wielu innych stronach internetowych, wykorzystywane są tzw. cookies (ciasteczka). Służą ona m.in. do tego, aby zalogować się na swoje konto, czy brać udział w ankietach. Ze względu na nowe regulacje prawne jesteśmy zobowiązani do poinformowania Cię o tym w wyraźniejszy niż dotychczas sposób. Dalsze korzystanie z naszej strony bez zmiany ustawień przeglądarki internetowej będzie oznaczać, że zgadzasz się na ich wykorzystywanie.
OK, rozumiem