Wykład 9 - Politechnika Warszawska
Transkrypt
Wykład 9 - Politechnika Warszawska
Maciej Sypniewski lato 2014, Politechnika Warszawska, Wydział Elektroniki i Technik Informacyjnych Maciej Sypniewski Politechnika Warszawska [email protected] OpenCL, C++ AMP Wybrane algorytmy obliczeniowe 2D Transpozycja macierzy Iloczyn macierzy Optymalizacja obliczeń GPU Elementy architektury Narzędzia optymalizacji lato 2014 SMOR 2 Maciej Sypniewski Politechnika Warszawska [email protected] OpenCL źródło – Kronos OpenCL specification lato 2014 SMOR 3 Maciej Sypniewski Politechnika Warszawska [email protected] OpenCL – architektura Model platformy Model pamięci Model wykonania Model programowy źródło – Kronos OpenCL specification lato 2014 SMOR 4 Maciej Sypniewski Politechnika Warszawska [email protected] OpenCL – model platformy źródło – Kronos OpenCL specification lato 2014 SMOR 5 Maciej Sypniewski Politechnika Warszawska [email protected] OpenCL – model platformy – przykład ICD – installable client driver Dwie platformy lato 2014 SMOR 6 Maciej Sypniewski Politechnika Warszawska [email protected] OpenCL – model platformy – przykład cd. Jedno urządzenie dla każdej platformy lato 2014 SMOR 7 Maciej Sypniewski Politechnika Warszawska [email protected] OpenCL – model pamięci Globalna Stała Lokalna Prywatna źródło – Kronos OpenCL specification lato 2014 SMOR 8 Maciej Sypniewski Politechnika Warszawska [email protected] OpenCL – model wykonania Kontekst – kontener urządzeń, obiektów pamięci i kolejek komend – ma szczególne znaczenie dla skomplikowanych scenariuszy zarządzania zasobami (wiele wielordzeniowych CPU, GPU itd. ) Kolejka komend – dla kolejki wykonujemy program „kernel” na urządzeniu ▪ Komendy kernela ▪ Komendy zarządzania pamięcią ▪ Komendy synchronizacji lato 2014 SMOR 9 Maciej Sypniewski Politechnika Warszawska [email protected] OpenCL – model wykonania Kontekst + kolejki kontekst dev1 dev2 q1 q2 ………. devn qn Komunikacja w ramach kontekstu odbywa się poprzez współdzielone bufory, komunikacja międzykontekstowa nie jest wspierana lato 2014 SMOR 10 Maciej Sypniewski Politechnika Warszawska [email protected] OpenCL – model wykonania GPU’s CPU’s kontekst Programy kompilacja lato 2014 Kernele Obiekty pamięci Ustawianie danych i argumentów SMOR Kolejki wykonanie 11 Maciej Sypniewski Politechnika Warszawska [email protected] OpenCL – model wykonania - przykład cl.hpp – opakowanie C++ dla cl.h lato 2014 SMOR 12 Maciej Sypniewski Politechnika Warszawska [email protected] OpenCL – cl.hpp – podstawowe struktury cl::Platform cl::Device cl::Context cl::Program cl::Program::Sources cl::Kernel cl::CommandQueue cl::Buffer cl::NDRange lato 2014 SMOR cl::Event cl::Error 13 Maciej Sypniewski Politechnika Warszawska [email protected] OpenCL – cl.hpp – podstawowe metody Konstruktory struktur get, get”WHAT”, getInfo<„WHAT”>() program.build({ dev }); queue.enqueue{Read,Write}Buffer kernel.setArg (nrArg,Arg) queue.enqueueNDRangeKernel lato 2014 SMOR 14 Maciej Sypniewski Politechnika Warszawska [email protected] OpenCL – cl.hpp – obsługa błędów catch ( cl::Error &err ) { std::cerr << „CL ERROR: " << err.what() << "(" << err.err() << ")" << std::endl; } lato 2014 SMOR 15 Maciej Sypniewski Politechnika Warszawska [email protected] OpenCL – kernel CUDA saxpy __global__ void saxpy (const int n, const float *const xt, const float a, float *const yt) { for (int i = blockIdx.x * blockDim.x + threadIdx.x; i < n; i += blockDim.x * gridDim.x) yt[i] += a*xt[i]; } OpenCL saxpy __kernel void saxpy(const int n,__global const float *const xt, const float a,__global float *const yt { const int gid=get_global_id(0); const int gis=get_global_size(0); for (int i = gid; i < n; i += gis) yt[i] += a*xt[i]; } C++AMP saxpy concurrency::parallel_for_each( concurrency::extent<1>(N), [&d_vx, &d_vy, a] (concurrency::index<1> idx) restrict(amp) { d_vy[idx] += a*d_vx[idx];} lato 2014 SMOR 16 Maciej Sypniewski Politechnika Warszawska [email protected] OpenCL – CUDA kernel indeksowanie CUDA OPENCL blockIdx.x blockDim.x threadIdx.x blockIdx.x * blockDim.x + threadIdx.x gridDim.x gridDim.x * blockDim.x get_group_id(0) get_local_size(0) get_local_id(0) get_global_id(0) get_num_groups(0) get_global_size(0) lato 2014 SMOR 17 Maciej Sypniewski Politechnika Warszawska [email protected] OpenCL – transpozycja macierzy macierze MxN umieszczone liniowo w std::vector Kernel 2D Rozwiązanie 1 – pamięć globalna Rozwiązanie 2 – pamięć dzielona Rozwiązanie 3 – pamięć dzielona z eliminacja konfliktów pamięci dzielonej lato 2014 SMOR 18 Maciej Sypniewski Politechnika Warszawska [email protected] OpenCL – transpozycja macierzy macierze MxN umieszczone liniowo w std::vector Kernel 2D Rozwiązanie 1 – pamięć globalna Rozwiązanie 2 – pamięć dzielona Rozwiązanie 3 – pamięć dzielona z eliminacja konfliktów pamięci dzielonej lato 2014 SMOR 19 Maciej Sypniewski Politechnika Warszawska [email protected] OpenCL – Windows, Nvidia, MS VC++ Konfiguracja OpenCL W7 CUDA 5.5/6.0 x64 Visual C++ 1. C++ -> General -> Additional Include Directories $(CUDA_INC_PATH) przykladowy wynik /I"C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v5.5\include" 2. Linker -> General -> Additional Library Directories $(CUDA_LIB_PATH) 3. Linker -> Input -> Additional Dependencies OpenCL.lib lato 2014 SMOR 20 Maciej Sypniewski Politechnika Warszawska [email protected] OpenCL/CUDA – transpozycja macierzy Rozwiązanie 1 – pamięć globalna Cuda Przykladowo M=N=8096, TILE_DIM=32, BLOCK 32x8=256 __global__ void transpose1(const int m, const int n, const float *const xt, const float a, float *const yt) { const int ix = blockIdx.x * TILE_DIM + threadIdx.x; const int iy = blockIdx.y * TILE_DIM + threadIdx.y; for (int j = 0; j < TILE_DIM; j += blockDim.y) { yt[ix*n + (iy+j)] = xt[ix + (iy+j)*m]; } } dim3 grids(M/TILE_DIM,N/TILE_DIM,1); dim3 blocks(TILE_DIM,8,1); transpose1<<<grids, blocks>>>(M, N, dev_x, a, dev_y); lato 2014 SMOR 21 Maciej Sypniewski Politechnika Warszawska [email protected] OpenCL/CUDA – transpozycja macierzy Rozwiązanie 1 – pamięć globalna OpenCL Przykladowo M=N=8096, TILE_DIM=32, BLOCK 32x8=256 __kernel void transpose1(const int m, const int n, const int TILE_DIM, __global const float *const xt, __global float *const yt) { const int ix = get_group_id(0) * TILE_DIM + get_local_id(0); const int iy = get_group_id(1) * TILE_DIM + get_local_id(1); for (int j = 0; j < TILE_DIM; j += get_local_size(1)) { yt[ix*n + (iy + j)] = xt[ix + (iy + j)*m]; } } cl::NDRange global(M , N/4 , 1); cl::NDRange local(TILE_DIM, TILE_DIM/4); queue.enqueueNDRangeKernel(kernel, cl::NullRange, global, local, NULL, &event); lato 2014 SMOR 22 Maciej Sypniewski Politechnika Warszawska [email protected] OpenCL/CUDA – transpozycja macierzy Rozwiązanie 1 – pamięć globalna Różnica w indeksowaniu – te sam schemat obliczeniowy 2D (MxN), BLOCK(32x8) OpenCL cl::NDRange global(M , N/4 , 1); cl::NDRange local(TILE_DIM, TILE_DIM/4); CUDA dim3 grids(M/TILE_DIM,N/TILE_DIM,1); dim3 blocks(TILE_DIM, TILE_DIM/4,1); lato 2014 SMOR 23 Maciej Sypniewski Politechnika Warszawska [email protected] OpenCL/CUDA – transpozycja macierzy Rozwiązanie 2 – pamięć dzielona aby uniknąć niełączonego zapisu lub odczytu lato 2014 SMOR 24 Maciej Sypniewski Politechnika Warszawska [email protected] OpenCL/CUDA – transpozycja macierzy Rozwiązanie 2 – pamięć dzielona OpenCL __kernel void transpose2(const int m, const int n, const int TILE_DIM, __global const float *const xt, __global float *const yt) { __local float tile[32][32]; int ix = get_group_id(0) * TILE_DIM + get_local_id(0); int iy = get_group_id(1) * TILE_DIM + get_local_id(1); for (int j = 0; j < TILE_DIM; j += get_local_size(1)) tile[get_local_id(1) + j][get_local_id(0)] = xt[(iy + j)*m + ix]; barrier(CLK_LOCAL_MEM_FENCE); ix = get_group_id(1) * TILE_DIM + get_local_id(0); // transpose block offset iy = get_group_id(0) * TILE_DIM + get_local_id(1); for (int j = 0; j < TILE_DIM; j += get_local_size(1)) yt[(iy + j)*m + ix] = tile[get_local_id(0)][get_local_id(1) + j]; } lato 2014 SMOR 25 Maciej Sypniewski Politechnika Warszawska [email protected] OpenCL/CUDA – transpozycja macierzy Rozwiązanie 3 – eliminacja konfliktów dostępu do pamięci dzielonej OpenCL __kernel void transpose3(const int m, const int n, const int TILE_DIM, __global const float *const xt, __global float *const yt) { __local float tile[32][33]; int ix = get_group_id(0) * TILE_DIM + get_local_id(0); int iy = get_group_id(1) * TILE_DIM + get_local_id(1); for (int j = 0; j < TILE_DIM; j += get_local_size(1)) tile[get_local_id(1) + j][get_local_id(0)] = xt[(iy + j)*m + ix]; barrier(CLK_LOCAL_MEM_FENCE); ix = get_group_id(1) * TILE_DIM + get_local_id(0); // transpose block offset iy = get_group_id(0) * TILE_DIM + get_local_id(1); for (int j = 0; j < TILE_DIM; j += get_local_size(1)) yt[(iy + j)*m + ix] = tile[get_local_id(0)][get_local_id(1) + j]; } lato 2014 SMOR 26 Maciej Sypniewski Politechnika Warszawska [email protected] OpenCL/CUDA – transpozycja macierzy Rozwiązanie 3 – eliminacja konfliktów dostępu do pamięci dzielonej Przykład - 4 banki pamięci pamięć dzielona 4x4/5 Konflikt pamięci dla odczytu kolumn Brak konfliktu pamięci dla odczytu kolumn 0/0 1/1 2/2 3/3 0/0 1/1 2/2 3/3 */0 4/0 5/1 6/2 7/3 4/1 5/2 6/3 7/0 */1 8/0 9/1 10/2 11/3 8/2 9/3 10/0 11/1 */2 12/0 13/1 14/2 15/3 12/3 13/0 14/1 15/2 */3 lato 2014 SMOR 27 Maciej Sypniewski Politechnika Warszawska [email protected] OpenCL/CUDA – transpozycja macierzy Wyniki CUDA 1 OpenCL 2 3 lato 2014 SMOR 28 Maciej Sypniewski Politechnika Warszawska [email protected] OpenCL – kompilacja kernela - clcc lato 2014 SMOR 29