Dostęp do elementó tablicy

0

Cześć.

W moim programie mocno skupiam się na wydajności.
Wąskim gardłem okazują się wykonywane w pętli operacje.
Operacje te to sięganie do tablicy.

W jaki sposób można przyśpieszyć dostęp do zmiennych, tablicy, obiektów? Jest na to jakiś sposób aby dostęp do tablicy był szybszy?
Wskaźnik odpada, gdyż podczas działania pętli nie wiadomo do jakiego elementu trzeba się dobrać, więc sam wskaźnik nie wiadomo o ile należy przesunąć.

0

Wskaźnik odpada, gdyż podczas działania pętli nie wiadomo do jakiego elementu trzeba się dobrać, więc sam wskaźnik nie wiadomo o ile należy przesunąć.

Jak nie wiadomo? To jakiej Ty tablicy używasz?

0

Nie wiadomo bo elementy są pobierane randomowo.

0

Pokaż kod, bo jakoś nie mogę sobie tego wyobrazić

0

Nie mam teraz przy sobie kodu, ale niby co w tym trudnego do wyobrażenia?

int zmienna = tablica[rand.next(50)];

prosty przykład. Mniej-więcej tak to wygląda.

0
int r = rand.Next(50); //<-- wylosowana liczba nie jest 'nieznana'
int zmienna = tablica[r];

Żeby przyspieszyć możesz wyłącz sprawdzanie czy nie przekraczasz tablicy. Przykład:

int[] fib;
fib = new int[100];
unsafe fixed ( int* p = fib )   
{
    p[0] = p[1] = 1;
    for( int i=2; i<100; ++i ) p[i] = p[i-1] + p[i-2];
}

źródło: http://msdn.microsoft.com/en-us/library/a3hd7ste(VS.80).aspx

0

I co z tego?
Przecież teraz muszę dopisać zmienną do kolejnej zmiennej (kolejny cykl procesora), następnie odwołać się do wskaźnika i go przesunąć (kolejne cykle procesora).

W rzeczywistości wyjdzie wolniej niż jest teraz.

0

Ok, dzięki. To może zadziałać. Jak będę tylko mógł to sprawdzę.

0
MomentObrotowy napisał(a):

Przecież teraz muszę dopisać zmienną do kolejnej zmiennej (kolejny cykl procesora), następnie odwołać się do wskaźnika i go przesunąć (kolejne cykle procesora).

Kod wygenerowany przez kompilator nie wygląda dokładnie tak, jak napisany przez programistę. To, że zdefiniujesz sobie jakąś pomocniczą zmienną, nie znaczy, że w kodzie wynikowym taka się znajdzie.

0

Ok, dzięki wszystkim za odpowiedzi. Zrobiłem to za pomocą wskaźników oraz dodatkowo stackalloc podczas tworzenia tablicy do, której mam mnóstwo odwołań.

0

Mam jeszcze jeden problem.

Otóż mam fragment kodu przetwarzający obraz.

for (int i = 0; i < height; i++)
            {
                for (int j = 0; j < width; j++)
                {
                    imagePointer1[0] = tabValue[imagePointer1[0]]; //*(p + imagePointer1[0]);
                    imagePointer1[1] = tabValue[imagePointer1[1]]; //*(p + imagePointer1[1]);
                    imagePointer1[2] = tabValue[imagePointer1[2]]; //*(p + imagePointer1[2]);
                    //imagePointer1[3] = imagePointer1[3];
                    imagePointer1 += 4;
                }
                imagePointer1 += strideBuff;
            }

imagePointer to wskaźnik na piksel.
tabValue to tablica, przechowująca wyniki dla wszystkich liczb jakie są możliwe (od 0 do 256) inaczej zwana tablicą LUT.

kanał alpha został zakomentowany, gdyż nie bierze on udziału w operacji.
wskaźnik jest przesuwany o wartość 4, gdyż działamy na obrazie z 32 bitami na piksel (mimo, że nie korzystamy z kanału alpha)

zakomentowany fragment: *(p + imagePointer1[0]); to przykład zapisania tego samego w inny sposób. p to wskaźnik na elementy tablicy LUT (p zawsze wskazuje na pierwszy element i dodajemy do tego wartość do przesunięcia).

Niestety kod działa... dobrze, ale dobrze mnie nie zadowala.
Konkretnie program uzyskuje szybkość około 200 milisekund na obrazie 5000x3750 pikseli.
To jest ok, ale chciałbym uzyskać około 50 milisekund, no najwyżej 120.

W jaki sposób mógłbym przyśpieszyć ten fragment kodu?
Zaznaczam, iż tabValue jest trzymana na stosie dzięki stackalloc, więc to już jest zoptymalizowane.

Dostęp do pikseli to około 100 milisekund a zapis na piksel to również około 100 milisekund.
Właściwie te dwa fragmenty kodu są najbardziej obciążające.

Czy da się jakoś dostać szybciej do pikseli oraz do elementów tablicy LUT tak, aby ten proces przyśpieszyć?

0

imagePointer - stary czytałeś dokumentacje na ten temat? jak można używać takiego słownictwa?

0

skąd masz pewność że w tej właśnie pętli jest wąskie gardło?

Sprawdziłem sobie Stopwatch-em.

0

imagePointer - stary czytałeś dokumentacje na ten temat? jak można używać takiego słownictwa?

Chyba Ty nie czytałeś jednak dokumentacji, albo nie do końca wiesz o co w niej chodzi.
Poza tym kod tutaj przedstawiony to tylko kod testowy - tymczasowy.

0

Niewiele możesz zrobić w takiej sytuacji; odwoływanie się po kolei do 18750000 elementów po prostu jest czasochłonne.
Możesz najwyżej spróbować rozdzielić to pomiędzy poszczególne rdzenie procesora korzystając z wątków.

0

Co ciekawe, w trybie Debug kod działa szybciej niż w trybie Release.
Może uda mi się coś wyciągnąć z ustawień kompilatora.

1

Co ciekawe, w trybie Debug kod działa szybciej niż w trybie Release.

Huh? Niemożliwe ;). Tzn. technicznie Debug vs. Release w C# (a nawet w CLR) nie wpływa na wydajność, ale typowo przy debug optymalizacje są wyłączone.

Masz VS lepsze niż Express? Pokaż może wynik z okna Disassembly podczas działania programu, okaże się co kompilator z tego robi (może będzie widać jakieś problemy wydajnościowe).

Poza tym możesz zawsze czekać na nową wersję, optymalizacje z czasem się poprawiają. Na przykład ta pętla świetnie by się dała pewnie przyśpieszyć jakimś MMX czy innym SIMDem, ale dość rzadko się to mu udaje. Na mono (od 2.2) jest wsparcie dla jawnego używania SIMD, w oficjalnej wersji niespecjalnie.

Możesz próbować jakoś prefetchować dane z tego obrazka, chociaż nie wiem czy różnica w tym przypadku będzie znacząca (spróbuj).

Możesz próbować ręcznie unrollować pętlę, ale to bardzo brzydkie i efekty będą na 99% niezauważalne/żadne/tylko pogorszą sprawę.

Poza tym tabValue[imagePointer1[0]] jest niefajne, ale pewnie nie masz szans tego inaczej zapisać (w sensie, dwie dereferencje).

A tak to jak patryk mówi - odwoływanie się po kolei do 18750000 elementów po prostu jest czasochłonne..

1 użytkowników online, w tym zalogowanych: 0, gości: 1