Upgrade to Pro — share decks privately, control downloads, hide ads and more …

11 встреча — Введение в GPGPU (А. Свириденков)

11 встреча — Введение в GPGPU (А. Свириденков)

11 встреча Smolensk Computer Science Club
Презентация Анатолия Свириденкова про программирование GPGPU, CUDA, OpenCL
ВКонтакте: http://vk.com/scsc11
Видео: http://www.youtube.com/watch?v=VoC5wqzriI4

More Decks by Smolensk Computer Science Club

Other Decks in Programming

Transcript

  1. Чего ожидать от параллелизма Закон Амдала (ускорение от параллелизма): Sp

    = 1 / (a + (1 – a) / p) p – количество потоков a – доля последовательных вычислений p = 2 p = 8 p = 1000 a = 0,9 1,05 1,1 1,11 a = 0,5 1,33 1,77 2,0 a = 0,1 1,81 4,71 9,91
  2. - Параллелизм данных, DPL: MMX, SSE, и т. д. -

    Параллелизм кода, IPL: спекулятивные вычисления и конвейер, VLIW - Квази многопоточность, многоядерность, hyper threading - Кластеры Примеры параллелизма
  3. Core DUO CORE CORE L1 L1 L2 Memory L2 -

    общий кэш L1 - отдельный кэш у каждого ядра Необходима синхронизация образа памяти для каждого ядра
  4. Cell SPU SPU SPU SPU SPU SPU SPU SPU BUS

    CPU Memory SPU - Synergistic Processing Unit, векторный процессор Cell сложен в программировании, не распространен
  5. Терминология - host - CPU - device - GPU -

    ядро — код запускаемого на GPU из основного приложения - поток — часть вычислений исполняемых параллельно - сетка (grid) — все множество потоков для одного ядра - блок — набор потоков исполняемых на одном SM - warp — набор потоков физически исполняемых параллельно
  6. Обобщенная архитектура GPU TPC TPC TPC TPC TPC TPC DRAM

    (на видео карте) PCI-Express CPU RAM SM — Streaming Multiprocessor TPC — Texture Processor Cluster TeX — Блок доступа к текстурам SM SM TeX TPC GPU device host
  7. Обобщенная архитектра SM CU0 CU1 CU2 CU3 CU4 CU5 CU6

    CU7 Кеш текстурной и константной памяти Регистры Разделяемая память Выборка инструкций (Instructions fetch) К DRAM SFU вычисление функций (sin, cos, exp) SFU вычисление функций (sin, cos, exp) CU — вычислительный модуль
  8. GPU GeForce 8800GTX Hardware: - 16 мультипроцессоров (SM) / 128

    вычислительных модулей (CU) - до 8 блоков исполняются на каждом SM - до 24 варпов исполняются на каждом SM - до 768 потоков исполняются на каждом SM - 8192 регистра на SM - 16k общей памяти на SM / 16 банков - 64k памяти констант (кэшируется по 8k на SM)
  9. Программная модель потоков B (0:0) B (0:1) B (0:2) B

    (0:3) B (1:0) B (1:1) B (1:2) B (1:3) B (2:0) B (2:1) B (2:2) B (2:3) B (3:0) B (3:1) B (3:2) B (3:3) B (4:0) B (4:1) B (4:2) B (4:3) Grid Block T (0:0:0) T (0:1:0) T (0:2:0) T (1:0:0) T (1:1:0) T (1:2:0) T (2:0:0) T (2:1:0) T (2:2:0) Приведен пример сетки из 20 блоков (5x4), в каждом блоке 18 (3x3x2) потоков. Всего в сетке 360 потоков.
  10. Программная модель памяти Тип Доступ Расположение Латентность Регистры Поток GPU

    (R\W) SM 2-4 такта Локальная Поток GPU (R\W) DRAM ~500 тактов Разделяемая Блок потоков GPU (R\W) SM 2-4 такта Глобальная CPU(R\W), GPU(R\W) DRAM ~500 тактов Константная CPU(R\W), GPU(Read-only) DRAM + КЕШ SM ~500 к DRAM 2-4 к кешу Текстурная CPU(R\W), GPU(Read-only) DRAM + КЕШ SM ~500 к DRAM 2-4 к кешу
  11. Особенности программирования - функция ядро возвращает только void - память

    — узкое место в вычисленях и требует особого внимания - шина PCI-Express — узкое место в вычислениях - ветвления внутри warp снижают быстродействие
  12. Последняя версия CUDA Toolkit 5.5 RC - https://nvdeveloper.nvidia.com Состав: -

    Драйвер для разработчиков - GPU Computing SDK GPU Computing SDK: - Компилятор - Набор утилит - Документация - Библиотеки (CUBLAS, CUSPARSE) - Примеры CUDA Toolkit
  13. Самый важный параметр: --help (-help) — печатает справку Основные выходные

    форматы (и ключи компиляции): --cubin (-cubin) — компилирует в виртуальный формат cubin --ptx (-ptx) — компиляция в ассемблер для gpu --gpu (-gpu) — компиляция в бинарный формат NVIDIA Parallel nSight специально разработан для работы в Visual Studio Компилятор NVCC
  14. Типы функций Обозначение Где расположена Кто может вызывать __global__ GPU

    CPU __device__ GPU GPU __host__ CPU CPU - по умолчанию все функции __host__ - __host__ и __device__ совместимы, компилятор создаст две версии: для CPU и GPU __global__ void sum(float *c, float *a, float b); __host__ __device__ float add(float a, float b);
  15. Hello World! Сложение массивов. #define N 1024 // GPU __global__

    void sum(float *c, float *a, float *b) { int index = blockIdx.x * blockDim.x + threadIdx.x; c[index] = a[index] + b[index]; } // CPU void sum(float *c, float *a, float b) { for(int i = 0; i < N; i++) { c[i] = a[i] + b[i]; } } Встроеные константы: blockIdx — номер блока у текущего потока; blockDim — количество блоков; threadIdx — номер потока в блоке.
  16. Hello World! CPU инициализация int main(int argc, char **argv) {

    float *a, *b, *c; float *A, *B, *C; a = (float*) malloc(N * sizeof(float)); b = (float*) malloc(N * sizeof(float)); c = (float*) malloc(N * sizeof(float)); cudaMalloc((void **)&A, N * sizeof(float)); cudaMalloc((void **)&B, N * sizeof(float)); cudaMalloc((void **)&C, N * sizeof(float)); for(int i = 0; i < N; i++) { a[i] = RandFloat(0.0f, 1.0f); b[i] = RandFloat(0.0f, 1.0f); }
  17. Hello World! CPU вызов ядра cudaMemcpy(A, a, N * sizeof(float),

    cudaMemcpyHostToDevice); cudaMemcpy(B, b, N * sizeof(float), cudaMemcpyHostToDevice); sum<<<N/256, 256>>>(C, A, B); cudaMemcpy(c, C, N * sizeof(float), cudaMemcpyDeviceToHost); cudaFree(A); cudaFree(B); cudaFree(C); free(a); free(b); free(c); }
  18. Hello World! CPU вызов ядра cudaMemcpy(A, a, N * sizeof(float),

    cudaMemcpyHostToDevice); cudaMemcpy(B, b, N * sizeof(float), cudaMemcpyHostToDevice); sum<<<N/256, 256>>>(C, A, B); cudaMemcpy(c, C, N * sizeof(float), cudaMemcpyDeviceToHost); cudaFree(A); cudaFree(B); cudaFree(C); free(a); free(b); free(c); }
  19. Hello World! CPU вызов ядра cudaMemcpy(A, a, N * sizeof(float),

    cudaMemcpyHostToDevice); cudaMemcpy(B, b, N * sizeof(float), cudaMemcpyHostToDevice); sum<<<N/256, 256>>>(C, A, B); cudaMemcpy(c, C, N * sizeof(float), cudaMemcpyDeviceToHost); cudaFree(A); cudaFree(B); cudaFree(C); free(a); free(b); free(c); }
  20. Hello World! CPU вызов ядра cudaMemcpy(A, a, N * sizeof(float),

    cudaMemcpyHostToDevice); cudaMemcpy(B, b, N * sizeof(float), cudaMemcpyHostToDevice); sum<<<N/256, 256>>>(C, A, B); cudaMemcpy(c, C, N * sizeof(float), cudaMemcpyDeviceToHost); cudaFree(A); cudaFree(B); cudaFree(C); free(a); free(b); free(c); }
  21. GPGPU прочее DirectCompute — библиотека от Microsoft. Часть DirectX; OpenCL

    — кроссплатформенная библиотека; Готовые библиотеки с поддержкой GPGPU: - OpenCV — обработка изображения и компьютерное зрение - CUBLAS — математические вычисления - CUFFT — быстрые преобразования фурье - CUSPARSE — библиотека линейной алгебры Пакеты ПО со встроенной поддержкой GPU, например Matlab
  22. OpenCV #include <iostream> #include "opencv2/opencv.hpp" #include "opencv2/gpu/gpu.hpp" int main (int

    argc, char* argv[]) { cv::gpu::GpuMat dst, src = cv::imread("file.png", CV_LOAD_IMAGE_GRAYSCALE); cv::gpu::threshold(src, dst, 128.0, 255.0, CV_THRESH_BINARY); cv::imshow("Result", dst); cv::waitKey(); return 0; }
  23. OpenCL обзор Особенности языка: - Отсутствие указателей на функции, рекурсии,

    битовых полей, массивов переменной длины, стандартных заголовочных файлов; - Расширения языка для параллелизма: векторные типы, синхронизация, функции для Work-items/Work-Groups; - Квалификаторы типов памяти: __global, __local, __constant, __private; - Свой набор встроенных функций; - Для работы на целевой системе нужен OpenCL драйвер.
  24. OpenCL инициализация // создание вычислительного контекста для GPU (видеокарты) context

    = clCreateContextFromType(NULL, CL_DEVICE_TYPE_GPU, NULL, NULL, NULL); // создание очереди команд queue = clCreateCommandQueue(context, NULL, 0, NULL); // выделение памяти в виде буферов memobjs[0] = clCreateBuffer(context, CL_MEM_READ_ONLY | CL_MEM_COPY_HOST_PTR, sizeof(float) * 2 * numElem, src, NULL); memobjs[1] = clCreateBuffer(context, CL_MEM_READ_WRITE, sizeof(float) * 2 * numElem, NULL, NULL); // создание программы из исходных текстов program = clCreateProgramWithSource(context, 1, &sourcesStr, NULL, NULL); // компиляция программы clBuildProgram(program, 0, NULL, NULL, NULL, NULL);
  25. OpenCL подготовка // создание объекта kernel из скомпилированной программы kernel

    = clCreateKernel(program, "kernel", NULL); // подготовка аргументов clSetKernelArg(kernel, 0, sizeof(cl_mem), (void *)&memobjs[0]); clSetKernelArg(kernel, 1, sizeof(cl_mem), (void *)&memobjs[1]); // задание N-D диапазона globalWorkSize[0] = numElem / 64; localWorkSize[0] = 64; // отправка в очередь исполнения clEnqueueNDRangeKernel(queue, kernel, 1, NULL, globalWorkSize, localWorkSize, 0, NULL, NULL);
  26. OpenCL ядро __kernel void kernel(__global float *in, __global float *out)

    { int tid = get_local_id(0); int blockIdx = get_group_id(0) * 1024 + tid; // адрес начала обрабатываемых данных в глобальной памяти in = in + blockIdx; out = out + blockIdx; *out = 2 * (*in); }
  27. Полезные источники: - GPU Gems 1- 3 - https://www.coursera.org/course/hetero -

    курс от Coursera - https://www.udacity.com/course/cs344 - курс от Udacity - http://www.nvidia.ru/object/cuda_home_new_ru.html - о CUDA - http://www.nvidia.ru/object/cuda_opencl_new_ru.html - OpenCL - http://www.nvidia.ru/object/directcompute_ru.html - DirectCompute - http://gpgpu.org/ - подборка информации по GPGPU - http://www.gpgpu.ru - GPGPU по-русски