atomic mi nie działa, wynik jest taki sam jaki był.
W załączniku projekt dodaję
Z czego nauczyć się używać OpenCL?
- Rejestracja: dni
- Ostatnio: dni
- Postów: 39
- Rejestracja: dni
- Ostatnio: dni
- Lokalizacja: XML Hills
Po każdej instrukcji gdzie zwracany jest kod błędu, wypisz go. Czyli jakieś printf("%d\n", error); czy coś w ten deseń. W którymś miejscu prawdopodobnie wyskoczył ci błąd, a ty radośnie olewasz wszystkie błędy.
- Rejestracja: dni
- Ostatnio: dni
- Postów: 39
Według tego:
https://onedrive.live.com/redir?resid=35c2a5b0aaf9523b!1516&authkey=!ANKiPo_X2hEQRsc&v=3&ithint=photo%2cjpg
nie ma żadnego błędu.
A zrobiłem tak jak pisałeś i po każdej instrukcji zwracającej error wypisałem go przy pomocy:
std::cout << error << std::endl;
- Rejestracja: dni
- Ostatnio: dni
- Postów: 39
Ewentualnie zamiast sprawdzać dlaczego u mnie to nie działa może powiesz jak z tym sumowaniem hierarchicznym to wygląda?
- Rejestracja: dni
- Ostatnio: dni
- Lokalizacja: XML Hills
Oprócz sprawdzania wyniku końcowego sprawdź sobie też wynik pośredni, czyli wykonanie tego kernela "Cmp".
Sumowanie hierarchiczne już przedstawiałem. Ale może jeszcze raz. Załóżmy, że każdy work-item sumuje 3 liczby i zapisuje wynik w drugiej tablicy.
Tablica wejściowa (11 elementów): 3, 4, 5, 8, 9, 0, 1, 2, 3, 5, 6
Sumowanie: 3+4+5, 8+9+0,1+2+3,5+6
Po zsumowaniu: 12,17,6,11
Kolejne przejście:
Tablica wejściowa: 12,17,6,11
Sumowanie: 12+17+6,11
Po zsumowaniu: 35,11
Kolejne przejście:
Tablica wejściowa: 35,11
Sumowanie: 35+11
Po zsumowaniu: 46
Został jeden element więc sumowanie jest zakończone.
Jak widać synchronizacja nie jest potrzebna bo work-itemy nie zapisują do tych samych komórek pamięci. Jednocześnie praca jest podzielona tak, by mogło być odpalonych naraz dużo work-itemów, co sprawi, że kernel będzie się szybko wykonywał na GPU, które może wykonywać wiele work-itemów naraz.
- Rejestracja: dni
- Ostatnio: dni
- Postów: 39
Tylko jak to zaimplementować? To co napisałeś zrozumiałem, nie wiem jak to zakodować. Pamiętaj, że nie mogę zsumować wszystkiego jak leci tylko co czwarty element tablicy.
Czyli jak mam przykład podany przez Ciebie to:
3+9+3 to pierwszy wynik
4+0+5 to drugi wynik
5+1+6 to trzeci wynik
8+2 to czwarty wynik.
Za to wracając do mojego projektu tablicą którą w powyższy sposób trzeba zsumować jest tablica c którą przekazuję do kernela Add i jak to zaimplementować?
Wracając do kernela Cmp. Ma on postać następującą:
__kernel void Cmp(__global int* a, __global int* b, __global int* c, int size)
{
int n = get_global_id(0);
if (n < size)
{
c[n] = a[n] == b[n] ? 1 : 0;
}
}
I działa poprawnie ponieważ wynik jego działań jest to trzecia dolna kolumna z poprzednich zrzutów.
- Rejestracja: dni
- Ostatnio: dni
- Lokalizacja: XML Hills
No to dla ułatwienia możesz zrobić osobny kernel, który rozplątuje tablicę do czterech tablic. Wtedy przy sumowaniu nie będziesz musiał się tym martwić.
- Rejestracja: dni
- Ostatnio: dni
- Postów: 39
a jak potem wykonać to sumowanie? Ma to wyglądać jakoś w ten sposób?
gdzie
__kernel void Cmp(__global int* a, __global int* b, int size)
{
int n = get_global_id(0);
if (n < size)
{
a[n] = b[n] + b[n+1] +b[n+2];
}
gdzie size jest wielkością tablicy a ?
- Rejestracja: dni
- Ostatnio: dni
- Lokalizacja: XML Hills
Bardziej coś w ten deseń:
__kernel void PartialAdd(__global int* a, __global int* b, int aSize) {
int bi = get_global_id(0);
int ai = bi * 3;
int br = 0;
for (int i = 0; i < 3; i++) {
if (ai + i < aSize) {
br += a[ai + i];
}
}
b[bi] = br;
}
- Rejestracja: dni
- Ostatnio: dni
- Postów: 39
możesz mi opisać zmienne? bo tak, o ile dobrze rozumuję to
a jest to tablica wynikowa,
b to tablica z danymi.
aSize wielkość tablicy a,
bi identyfikator,
br wynik cząstkowy,
ale dalczego:
ai = bi * 3;
a[ai + i];
dlaczego tak to jest zrobione?
i czy mógłbyś mi wytłumaczyć prostymi słowami na jakiej zasadzie działa get_global_id(0);? Dlaczego argumentem jest 0?
- Rejestracja: dni
- Ostatnio: dni
- Lokalizacja: XML Hills
bi to indeks w tablicy wynikowej b
ai to początkowy indeks w tablicy źródłowej a
ai = bi * 3, ponieważ sumujemy trójki, więc w tablicy a zaczynamy od 3x dalszego miejsca niż w b
a[ai + i] ponieważ sumujemy trójki, a więc efektywnie będzie to a[ai + 0], a[ai + 1] i a[ai + 2]
opis get_global_id masz tutaj: https://www.khronos.org/registry/cl/sdk/1.0/docs/man/xhtml/get_global_id.html
0 jest dlatego, że odpowiada on pierwszemu wymiarowi. OpenCL pozwala na maksymalnie 3 wymiary, ale często używa się tylko jednego.
- Rejestracja: dni
- Ostatnio: dni
- Postów: 39
Zatem w momencie kiedy wykorzystywałbym 2wymiarową tablicę to jak by to wyglądało?
Załóżmy, że 'a' , 'b' i c są to tablice 2D. W tym wypadku jak by wyglądał ten kernel?
__kernel void Cmp(__global int* a, __global int* b, __global int* c, int size)
{
int n = get_global_id(0);
if (n < size)
{
c[n] = a[n] == b[n] ? 1 : 0;
}
}
Co należałoby zmienić? Co dodać?
- Rejestracja: dni
- Ostatnio: dni
- Lokalizacja: XML Hills
Nie bawiłem się jeszcze w wywołania dwuwymiarowe w OpenCLu, ale wtedy musiałbyś użyć też get_global_id(1) żeby dowiedzieć się jaki masz drugi wymiar.
Wymiary tablic są niezależne od wymiarów wywołania kernela. Żadna tablica nie jest 'główna'. Z tego powodu można się obejść bez wielowymiarowych wywołań i samemu sobie ręcznie kombinować z indeksami tablic.
- Rejestracja: dni
- Ostatnio: dni
- Postów: 39
A są gdzieś jakieś przykłady tablic 2-3 wymiarowych w oppenCL same kernele mnie obchodzą tak właściwie bo jeżeli tak to miałbym już całkowitą bazę pod mój projekt
- Rejestracja: dni
- Ostatnio: dni
- Lokalizacja: XML Hills
Tutaj jest coś: http://www.thebigblob.com/gaussian-blur-using-opencl-and-the-built-in-images-textures/
Wygląda to na tablicę jednowymiarową + wielowymiarowe wywołanie kernela + ręczną zabawę z indeksami. Zabawa jest identyczna jak by to miało miejsce w C/ C++/ czymkolwiek. A więc jest sobie linijka:
blurredImage[pos.x+pos.y*get_global_size(0)] = sum;
Czyli inaczej:
index = x + y * Xsize;
blurredImage[index] = sum;
W ogólności kod w C/ C++ typu:
int * tab = new int[Xsize * Ysize];
for (int y = 0; y < Ysize; y++) {
for (int x = 0; x < Xsize; x++) {
tab[x + y * Xsize] = cośtam;
}
}
Można zastąpić dwuwymiarowym wywołaniem kernela o postaci:
int x = get_global_id(0);
int y = get_global_id(1);
int Xsize = get_global_size(0);
tab[x + y * Xsize] = cośtam;