Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.
Параллельное программирование<br />На современных видеокартах(GPGPU)<br />Алексей Тутубалинwww.gpgpu.rulexa@lexa.ru<br />
План встречи<br />
Параллельные вычисления: зачем?<br /><ul><li>Производительности всегда не хватает
Рост производительности CPU сильно замедлился</li></li></ul><li>The Landscape of Parallel Computer Research:  A View from ...
Параллельные вычисления<br />Как?<br />Одновременное исполнение независимых вычислений на разных процессорах с последующей...
Параллельные системы<br />
Высокая производительность: объективные проблемы<br />Задержки (Latency)<br />Часто определяют производительностьПример: У...
Вычисления на GPU: предпосылки<br />
«Старые видеокарты» (2003-2006)<br />Специализация под 3D-графику (отрисовка2D-проекции сцены)<br />Фиксированные стадии о...
2001-2006: «Многообещающие результаты»<br />~3000 научных публикацийС общим смыслом «вот на следующих поколениях оборудова...
Проблемы начального этапа<br />Неудобная парадигма «Потоковых вычислений» (Stream Computing):<br />«микропрограммы» (шейде...
2006: NVidia CUDA и G80 Compute Unified Device Architecture<br />Принципиально новая (для GPU) архитектура<br />Взаимодейс...
2006: интерес других производителей<br />ATI (AMD):<br />Инициатива Close-To-Metal: публикация спецификаций кода, надежда ...
2007-2008: быстрое взросление<br />>2000 публикаций про использование CUDA<br />Топовые конференции (Supercomputing)<br />...
Ускорение приложений на CUDA<br />2008 г.: NVidia 8800GTX в сравнении с AMD Opteron 248 (2.2GHz, 2 ядра)<br />
Современный этап: оборудование<br />Видеокарты:<br />ATI R800<br />2.7TFLOP/s single, 500 GFLOP/s double<br />Поддержка Op...
Современный этап: программы<br />Стандарт  OpenCL (лето-осень 2009): переносимые GPU-программы<br />Для пользователяускоре...
Современный этап: производительность<br />
Наглядная агитация<br />4xTesla  == Cray XT4  на задачах молекулярной биологии (AMBER11)(слайд с NVidia GPU Technology con...
NVidia CUDACompute Unified Device Architecture<br />Общий обзор «сверху вниз»<br />Как устроено оборудование<br />И как эт...
Общая схема исполнения программ<br />Все стадии независимы, одновременно можно:<br />Передавать в видеопамять<br />Считать...
Архитектура G80<br />До 16 одинаковых мультипроцессоровна чипе<br />Общая глобальная память (R/W): медленная и много (до 1...
2 специальных процессора (SFU) для сложных функций: 32 потока за 16 тактов, SIMD
Один диспетчер команд
до 768 потоков на одном SM в «одновременном» режиме
 потоки объединяются в пачки по 32 потока (warp), которые исполняются SIMD
 16 kb разделяемой памяти (shared memory)
 8192 32-битных регистра</li></ul>На 2 SM – один блок обработки текстур с текстурным кэшем и блоком аппаратной интерполяци...
Texture<br />Texture<br />Texture<br />Texture<br />Texture<br />Texture<br />Texture<br />Texture<br />Texture<br />Host<...
Логическая организация программ<br />Десятки тысяч – миллионы независимых потоков в программе<br />Поток – обрабатывает ча...
Логическая организация (2)<br />Блок исполняется на одном мультипроцессоре<br />Разные блоки – на разных<br />Порядок не о...
Иерархия памяти<br />
Параметры SM – не догма<br />G92:<br />16384регистров, до 1024 потоков  на SM<br />GF100 (Fermi)<br />32768 регистров и 32...
Пример: cложение двух векторов<br />Код GPU: складываем два элемента:<br />__global__ void VecAdd(float* A,float* B, float...
код на CPU<br />// аллоцируем память на GPU<br />size_t size = N * sizeof(float);<br />cudaMalloc((void**)&d_A, size);<br ...
CUDA:С/C++ с небольшими изменениями<br />Спецификаторы типа функции:<br />__global__- GPU, может быть вызвана с CPU (с пар...
Типы данных и переменные<br />Скалярные:char, short, int, long,longlong, float, double (и беззнаковые для целых)<br />Вект...
Двумерные блоки например, для двумерных моделей<br />На CPU:<br />dim3 blockSize(16, 16);<br />// некратным размером сетки...
Синхронизация, атомарные операции<br />Глобальная синхронизация всех блоков – завершение kernel<br />__syncthreads() – син...
Скалярное произведение<br />Накапливаем частные произведенияпо потокам:<br />__global__ result;<br />shared__ float psum[N...
Тонкости<br />Оптимальный доступ к глобальной памяти<br />Особенности доступа к shared memory<br />Условные операции<br />...
Доступ к глобальной памяти<br />Сложение векторов, 16 сложений на thread:<br />___________________________________________...
Доступ к глобальной памяти - 2<br />Прямые рекомендации из Programming Guide:<br />Оптимально, когда все потоки одного (по...
Разделяемая память<br />Разделена на банки <br />16 банков на G80-G200, 32 на GF100<br />Interleave 4 байта<br />Два поток...
Нет конфликта банков<br />Bank 0<br />Thread 0<br />Bank 0<br />Thread 0<br />Bank 1<br />Thread 1<br />Bank 1<br />Thread...
Конфликт банков<br />Bank 0<br />Bank 1<br />Thread 0<br />Bank 2<br />Thread 1<br />Bank 3<br />Thread 2<br />Bank 4<br /...
Условные операции<br />SIMD <br />поэтому если в одном warp разные ветки if, их исполнение будет последовательным:<br />if...
Распределение блоков по SM<br />Не меньше одного блока т.е. блок должен пролезать по ресурсам:<br />Общее число потоковв б...
Загрузка SM (occupancy)<br />Отношение числа работающих warps к из возможному количеству<br />В общем случае, к 100% надо ...
Разное<br />Целая арифметика:<br />G80-G200: 24-бита – быстрая, 32 бита – медленная<br />GF100 – 32 бита – быстрая, 24 бит...
Продолжение.....<br />Документация NvidiaОчень хорошая!http://developer.nvidia.com/object/cuda_download.html<br />CUDA Pro...
Программные средства<br />CUDA Toolkit – компилятор + библиотеки<br />Интегрируется с Visual C++ (добавление правил компил...
Подробности компиляции<br />float4 me = gx[gtid];<br />me.x += me.y * me.z;<br />C/C++ CUDA<br />Application<br />CPU-code...
Компиляция в внешний .cubin-файл и загрузка на runtime</li></ul>Финальную компиляцию  реальные коды делает драйвер видеока...
Два API<br />CUDA C API: <br />реализуется внешней библиотекой cudart<br />Высокоуровневое, более удобное<br />удобная под...
Альтернативы CUDA<br />OpenCL<br />CAL/IL (Compute Abstraction Layer/Intermediate Language)<br />Только видеокарты ATI<br ...
OpenCL<br />Многоплатформенный стандарт<br />Необычайно похож на CUDA Driver API<br />Детали:<br />Язык C для kernels, дру...
Сложение векторов<br />Код GPU:<br />__kernel void VectorAdd(__global const float* a,__global const float* b,__global floa...
Код CPU<br />// Создаем контекст GPU (до того был поиск устройств...)<br />Context = clCreateContext(0, 1, &cdDevice, NULL...
CUDA  OpenCL<br />AMD: Porting CUDA to OpenCLhttp://developer.amd.com/zones/OpenCLZone/Pages/portingcudatoopencl.aspx<br />
Переносимость и производительность<br />Переносимыйкод (NVidia, ATI,x86, Cell)<br />Производительность не переносится:<br ...
OpenCL и видеокарты ATI<br />Человеческий интерфейс (в отличие от CAL/IL)<br />HD5870 – производительность примеров SDK - ...
Почему GPU НАСТОЛЬКО быстрее?<br /><ul><li>Линейная алгебра: 5-8раз
Обработка сигналов, обработка изображений: десятки раз
Некоторые задачи (молекулярная динамика, N-body): бывают сотни раз</li></li></ul><li>Вот почему:<br />Другой аппаратный ди...
Upcoming SlideShare
Loading in …5
×

Параллельное программирование на современных видеокартах

26,956 views

Published on

Слайды со встречи на физфаке МГУ, 29 сентября 2010

Published in: Education

Параллельное программирование на современных видеокартах

  1. 1. Параллельное программирование<br />На современных видеокартах(GPGPU)<br />Алексей Тутубалинwww.gpgpu.rulexa@lexa.ru<br />
  2. 2. План встречи<br />
  3. 3. Параллельные вычисления: зачем?<br /><ul><li>Производительности всегда не хватает
  4. 4. Рост производительности CPU сильно замедлился</li></li></ul><li>The Landscape of Parallel Computer Research: A View from Berkeley (2006)<br />http://www.eecs.berkeley.edu/Pubs/TechRpts/2006/EECS-2006-183.pdf<br /> - старые парадигмы во многом устарели, параллельность – единственный (на сегодня) путь<br />Ответ индустрии оборудования: многоядерностьCPU<br /><ul><li>а до того – многопроцессорные машины с общей памятью (SMP) и векторные инструкции</li></ul>Программистам от параллельности деваться некуда<br />
  5. 5. Параллельные вычисления<br />Как?<br />Одновременное исполнение независимых вычислений на разных процессорах с последующей синхронизацией<br />Проблемы:<br />Правило Амдала: ускорение=P – доля программы, которую можно распараллелить, N – число потоков исполнения<br />Слишком маленькие независимые блоки много затрат на синхронизацию<br />Сложно программировать (много объектов, синхронизация, критические секции)<br />
  6. 6. Параллельные системы<br />
  7. 7. Высокая производительность: объективные проблемы<br />Задержки (Latency)<br />Часто определяют производительностьПример: Умножение матриц наивным способом - медленный доступ «по столбцам»: особенности памяти (и кэшей, если не повезло)<br />Синхронизация: всегда непроизводительное ожидание<br />Скорость чтения/записи в память (Bandwidth)<br />Часто определяет производительностьSSE на Core i7: две векторные (16 байт) операции на такт(96 байт/такт), скорость доступа к памяти порядка 6 байт/такт (или 1-1.5 байта на ядро)<br />Нужна быстрая память, кэши частично спасают<br />Нужно повышение сложности: больше операций над данными в регистрах.<br />Распределенные системы: линейный рост bandwidth<br />Арифметическая интенсивность (операций/единица данных)<br />a = b+c: 1 операция, 2 чтения, 1 запись<br />Распараллеливание может стать бессмысленным, весь выигрыш будет съеден пересылками<br />Чтобы был выигрыш от параллельности, алгоритмы должны быть либо сложнее O(n),либо для O(n) – константапри O – большая.<br />
  8. 8. Вычисления на GPU: предпосылки<br />
  9. 9. «Старые видеокарты» (2003-2006)<br />Специализация под 3D-графику (отрисовка2D-проекции сцены)<br />Фиксированные стадии обработки (вершины-геометрия-пиксели)<br />С 2001 – программируемые шейдеры (GeForce3, OpenGL 1.5)<br />Высокая производительность за счет:<br />Архитектуры, сделанной ровно под одну задачу<br />Высокой скорости линейного чтения памяти<br />Отсутствия синхронизации внутри стадии обработки<br />
  10. 10. 2001-2006: «Многообещающие результаты»<br />~3000 научных публикацийС общим смыслом «вот на следующих поколениях оборудования все будет хорошо...»<br />Первые средства разработки для не-графики: Brook, Sh<br />Результаты:<br />Ускорение линейной алгебры в разы (относительно CPU), но single precision<br />Сортировка: ускорение в разы, GPUTeraSortвыиграла Sort Benchmark 2006г<br />Промышленное использование:<br />Обработка сигналов<br />Обработка цифрового кино (поток 200-500Mb/sec)<br />
  11. 11. Проблемы начального этапа<br />Неудобная парадигма «Потоковых вычислений» (Stream Computing):<br />«микропрограммы» (шейдеры) – обработка одного элемента входного потока<br />Никакого взаимодействия между потоками<br />Многие задачи очень неудобно программировать<br />Только одинарная точность вычислений<br />Неудобство средств разработки<br />
  12. 12. 2006: NVidia CUDA и G80 Compute Unified Device Architecture<br />Принципиально новая (для GPU) архитектура<br />Взаимодействие между потоками вычислений<br />Произвольный код вместо шейдеров<br />Иерархическая структура памяти<br />345 GFLOP/s (single), 87Gb/sec memory bandwidth<br />Средства программирования общего назначения (CUDA):<br />Вычислительный код на языке «С»<br />Компактная архитектура запуска вычислителей<br />Много готовых вычислительных примеров<br />Готовые библиотеки BLAS и FFT в поставке<br />Прекрасная поддержка разработчиков и университетов<br />2007: NVidia Tesla – «Supercomputer on Desktop» - «видеокарты без видеовыхода», только вычисления<br />
  13. 13. 2006: интерес других производителей<br />ATI (AMD):<br />Инициатива Close-To-Metal: публикация спецификаций кода, надежда на отказ от OpenGL и появление нормальных компиляторов<br />FireStream – первый ускоритель для вычислений а не видеокарта<br />Остаются в парадигме потоковых вычислений<br />Cell (IBM-Sony-Toshiba)<br />8 ядер с локальной памятью (256кб на ядро)<br />Быстрая внешняя шина (25Gb/sec)<br />230 GFLOP/s single, 15-20GFLOP/s double<br />PlayStation 3 и плата в серверы<br />
  14. 14. 2007-2008: быстрое взросление<br />>2000 публикаций про использование CUDA<br />Топовые конференции (Supercomputing)<br />Хорошие готовые библиотеки<br />Новое оборудование:<br />Поддержка двойной точности у всех<br />NVidia: G200 – 800 GFLOP/s single, 100 – double, <br />ATI HD4870: 1000/240 GFLOP/s single/double, но все еще потоковое программирование<br />IBM PowerXCell: ~200/100 GFLOP/s<br />
  15. 15. Ускорение приложений на CUDA<br />2008 г.: NVidia 8800GTX в сравнении с AMD Opteron 248 (2.2GHz, 2 ядра)<br />
  16. 16. Современный этап: оборудование<br />Видеокарты:<br />ATI R800<br />2.7TFLOP/s single, 500 GFLOP/s double<br />Поддержка OpenCL (не только потоковые вычисления)<br />NVidia GF100 (Fermi):<br />Tesla 1.2 TFLOP/s single, 600 GFLOP/s double<br />Geforce GTX 480: 1.3 TFLOP/s single, ~180 GFLOP/s double<br />Для сравнения, топовые x86 CPU: 80-110GFLOP/s (double)<br />GPU-кластеры<br />Промышленные решения (Cray, IBM, Т-платформы)<br />Суперкомпьютеры: Nebulae - №2 в Supercomputer Top500 по реальной производительности, №1 по пиковой.<br />
  17. 17. Современный этап: программы<br />Стандарт OpenCL (лето-осень 2009): переносимые GPU-программы<br />Для пользователяускорение multimedia, обработка изображений и видео, 3D-моделирование, инженерные программы...<br />Для программиста<br />много готовых библиотек: линейная алгебра, обработка сигналов, computer vision<br />Для ученого: поддержка в расчетных программах<br />Общего назначения: Matlab, Mathematica<br />Специализированные пакеты: проектирование, компьютерная химия, компьютерная биология, молекулярная динамика<br />
  18. 18. Современный этап: производительность<br />
  19. 19. Наглядная агитация<br />4xTesla == Cray XT4 на задачах молекулярной биологии (AMBER11)(слайд с NVidia GPU Technology conference, 22 сентября 2010)<br />
  20. 20. NVidia CUDACompute Unified Device Architecture<br />Общий обзор «сверху вниз»<br />Как устроено оборудование<br />И как это отражается в логической структуре программ<br />Минимальные примеры программ<br />Некоторые тонкие моменты<br />Обзор средств программиста и дополнительных библиотек<br />Нет задачи и возможности заменить чтение документации и самостоятельные упражнения<br />
  21. 21. Общая схема исполнения программ<br />Все стадии независимы, одновременно можно:<br />Передавать в видеопамять<br />Считать (другие данные)<br />Передавать из видеопамяти<br />
  22. 22. Архитектура G80<br />До 16 одинаковых мультипроцессоровна чипе<br />Общая глобальная память (R/W): медленная и много (до 1.5Gb)<br />Общая константная память (RO): быстрая и мало<br />Общий планировщик потоков (блоками)<br />Общий исполняемый код на вечь чип<br />G80Streaming Multiprocessor (SM)<br /><ul><li> 8 простых процессоров (SP): исполняют 32 потока за 4 такта в SIMD-режиме
  23. 23. 2 специальных процессора (SFU) для сложных функций: 32 потока за 16 тактов, SIMD
  24. 24. Один диспетчер команд
  25. 25. до 768 потоков на одном SM в «одновременном» режиме
  26. 26. потоки объединяются в пачки по 32 потока (warp), которые исполняются SIMD
  27. 27. 16 kb разделяемой памяти (shared memory)
  28. 28. 8192 32-битных регистра</li></ul>На 2 SM – один блок обработки текстур с текстурным кэшем и блоком аппаратной интерполяции<br />…<br />TPC<br />TPC<br />TPC<br />TPC<br />TPC<br />TPC<br />Streaming Multiprocessor<br />Texture Processor Cluster<br />Instruction L1<br />Data L1<br />Instruction Fetch/Dispatch<br />SM<br />Shared Memory<br />TEX<br />SP<br />SP<br />SP<br />SP<br />SM<br />SFU<br />SFU<br />SP<br />SP<br />SP<br />SP<br />
  29. 29. Texture<br />Texture<br />Texture<br />Texture<br />Texture<br />Texture<br />Texture<br />Texture<br />Texture<br />Host<br />Input Assembler<br />Thread Execution Manager<br />Parallel DataCache<br />Parallel DataCache<br />Parallel DataCache<br />Parallel DataCache<br />Parallel DataCache<br />Parallel DataCache<br />Parallel DataCache<br />Parallel DataCache<br />Load/store<br />Load/store<br />Load/store<br />Load/store<br />Load/store<br />Load/store<br />Global Memory<br />G80: общая схема<br />
  30. 30. Логическая организация программ<br />Десятки тысяч – миллионы независимых потоков в программе<br />Поток – обрабатывает часть входных данных<br />Потоки объединены в блоки<br />Общая shared memory<br />Синхронизация<br />Блоки объединены в grid<br />Синхронизации нет<br />Grid of Thread Blocks<br />
  31. 31. Логическая организация (2)<br />Блок исполняется на одном мультипроцессоре<br />Разные блоки – на разных<br />Порядок не определен<br />Может быть несколько блоков на SM одновременно<br />Нумерация потоков в блоке: 1D, 2D или 3D<br />Нумерация блоков: 1D,2D<br />Каждый поток знает свое положение в сетке и блоке<br />
  32. 32. Иерархия памяти<br />
  33. 33. Параметры SM – не догма<br />G92:<br />16384регистров, до 1024 потоков на SM<br />GF100 (Fermi)<br />32768 регистров и 32/48 процессоров на SM <br />1536 потоков (48 warp) на SM<br />64kb shared memory+L1-cache (16/48 или 48/16 shared/cache)<br />Другие параметры другой оптимальный код<br />Другие улучшения<br />Атомарные операции (G86, G92)<br />Поддержка двойной точности (G200, GF100)<br />
  34. 34. Пример: cложение двух векторов<br />Код GPU: складываем два элемента:<br />__global__ void VecAdd(float* A,float* B, float* C, int N)<br />{<br /> int i = blockDim.x * blockIdx.x + threadIdx.x;<br /> if (i < N)<br /> C[i] = A[i]+B[i];<br />}<br />threadIdx – предопределенная переменная (3-компонентный вектор) – номер потока в блоке<br />blockDim – размерность одного блока (3D)<br />blockIdx – номер блока в сетке (2D)<br />
  35. 35. код на CPU<br />// аллоцируем память на GPU<br />size_t size = N * sizeof(float);<br />cudaMalloc((void**)&d_A, size);<br />cudaMalloc((void**)&d_B, size);<br />cudaMalloc((void**)&d_C, size);<br />// копируем данные на GPU<br />cudaMemcpy(d_A, h_A, size, cudaMemcpyHostToDevice); <br />cudaMemcpy(d_B, h_B, size, cudaMemcpyHostToDevice);<br />// запускаем kernel на GPU (1D сетка и блок):<br />int Nthreads = 256;<br />int Nblocks = (N+Nthreads-1)/Nthreads;<br />VecAdd<<<Nblocks,Nthreads>>>(d_A, d_B, d_C, N);<br />// получаем результаты с GPU<br />cudaMemcpy(h_C, d_C, size, cudaMemcpyDeviceToHost);<br />
  36. 36. CUDA:С/C++ с небольшими изменениями<br />Спецификаторы типа функции:<br />__global__- GPU, может быть вызвана с CPU (с параметрами)<br />__device__ - GPU, вызывается из __global__<br />__host__ - CPUРекурсия и указатели на функции: только Fermi (GF100) <br />Спецификаторы местоположения переменной<br />__device__ - глобальная память, R/W<br />__constant__ - константная память, R/O<br />__shared__ - shared memory, R/W, локальна в блоке<br />Автоматические переменные – могут быть в регистрах, если известен размер и регистров достаточно. Иначе – local memory, т.е. живут в медленной глобальной памяти<br />
  37. 37. Типы данных и переменные<br />Скалярные:char, short, int, long,longlong, float, double (и беззнаковые для целых)<br />Векторные: <br /><=32 бит/компонент – до 4 элементов (uchar2,float4)<br />64 бита – 2 элемента (double2, longlong2)<br />Векторных операций НЕТ: c.x=a.x+b.x работает, c=a+b - нет<br />dim3 – тип для задания размера сетки блоков<br />Встроенные переменные:<br />gridDim, blockDim– размер сетки и блока (dim3)<br />blockIdx, threadIdx– номер блока и потока (dim3)<br />warpSize – ширина SIMD (пока всегда 32)<br />
  38. 38. Двумерные блоки например, для двумерных моделей<br />На CPU:<br />dim3 blockSize(16, 16);<br />// некратным размером сетки пренебрегаем... <br />dim3 gridSize(width/blockSize.x, height/blockSize.y);<br />myKernel<<<gridSize,blockSize>>>(…..)<br />На GPU<br />uint x = blockIdx.x*blockDim.x+threadIdx.x;<br />uint y = blockIdx.y*blockDim.y +threadIdx.y;<br />
  39. 39. Синхронизация, атомарные операции<br />Глобальная синхронизация всех блоков – завершение kernel<br />__syncthreads() – синхронизация потоков блока<br />Атомарные сложения, вычитания и т.п. (atomicAdd() и т.д.) - G86+<br />Shared или Global memory (G86 – только global)<br />Атомарное исполнение<br />Медленные<br />
  40. 40. Скалярное произведение<br />Накапливаем частные произведенияпо потокам:<br />__global__ result;<br />shared__ float psum[NTHREADS];<br />psum[threadIdx.x] = 0;<br />for(j=0;j<K*NTHREADS;j+=NTHREADS)<br />psum[threadIdx.x] += A[base+j]*B[base+j];<br />__syncthreads();<br />// Складываем для блока<br />if(threadIdx.x == 0)<br />{<br /> for(j=1;j<blockDim.x;j++)<br />psum[0]+=psum[j];<br /> // синхронизации не надо!! 0-йthread<br />atomicAdd(&result,psum[0]);<br />}<br />
  41. 41. Тонкости<br />Оптимальный доступ к глобальной памяти<br />Особенности доступа к shared memory<br />Условные операции<br />Распределение блоков по процессорам<br />
  42. 42. Доступ к глобальной памяти<br />Сложение векторов, 16 сложений на thread:<br />___________________________________________________<br />int j,base = (blockDim.x*blockIdx.x+threadIdx.x)*16;<br />for(j=0;j<16;j++)<br />C[base+j] = A[base+j] + B[base+j]<br />Thread0: A[0], A[1]<br />Thread1: A[16], A[17]<br />Весь Warp обращается c «размахом» в 512 слов<br />______________________________________________________<br />int j,base = (blockDim.x*blockIdx.x)*16+threadIdx.x;<br />for(j=0;j<blockDim.x*16;j+=blockDim.x)<br />C[base+j] = A[base+j] + B[base+j]<br />Thread0: A[0], A[blockDim.x]...<br />Thread1: A[1], A[blockDim.x+1]....<br />Весь Warp обращается к соседним словам<br />Второй вариант – coalesced access: доступ к соседним адресам <br />
  43. 43. Доступ к глобальной памяти - 2<br />Прямые рекомендации из Programming Guide:<br />Оптимально, когда все потоки одного (полу)-warp*обращаются к одному 128-байтному сегменту<br />Для 16-байтных элементов (вектор) – два подряд 128-байтных сегмента.<br />В правильном порядке – k-йthread к k-му элементу в сегменте.<br />Идеальная ситуация: Array[base + treadIdx.x]Array[base] – выровнен на 128 байт<br />
  44. 44. Разделяемая память<br />Разделена на банки <br />16 банков на G80-G200, 32 на GF100<br />Interleave 4 байта<br />Два потока в 1 банк =>конфликт, каждый конфликт – 4 такта ожидания<br />Оптимальный доступ array[threadIdx]<br />
  45. 45. Нет конфликта банков<br />Bank 0<br />Thread 0<br />Bank 0<br />Thread 0<br />Bank 1<br />Thread 1<br />Bank 1<br />Thread 1<br />Bank 2<br />Thread 2<br />Bank 2<br />Thread 2<br />Bank 3<br />Thread 3<br />Bank 3<br />Thread 3<br />Bank 4<br />Thread 4<br />Bank 4<br />Thread 4<br />Bank 5<br />Thread 5<br />Bank 5<br />Thread 5<br />Bank 6<br />Thread 6<br />Bank 6<br />Thread 6<br />Bank 7<br />Thread 7<br />Bank 7<br />Thread 7<br />Bank 15<br />Thread 15<br />Bank 15<br />Thread 15<br />
  46. 46. Конфликт банков<br />Bank 0<br />Bank 1<br />Thread 0<br />Bank 2<br />Thread 1<br />Bank 3<br />Thread 2<br />Bank 4<br />Thread 3<br />Bank 5<br />Thread 4<br />Bank 6<br />Bank 7<br />Thread 8<br />Thread 9<br />Bank 15<br />Thread 10<br />Thread 11<br />GF100: несколько чтений разных потоков по одному адресу (не банку) – не приводят к конфликту (broadcast данных)<br />
  47. 47. Условные операции<br />SIMD <br />поэтому если в одном warp разные ветки if, их исполнение будет последовательным:<br />if (threadIdx.x %2)<br /> { четные ветки стоят, нечетные работают}<br />else<br /> { четные работают, нечетные стоят }<br />
  48. 48. Распределение блоков по SM<br />Не меньше одного блока т.е. блок должен пролезать по ресурсам:<br />Общее число потоковв блоке < лимита оборудования<br />Требуемое количество shared memory< лимита<br />Общее количество регистров (регистров на поток * число потоков) < лимита <br />Несколько блоков на SM – если достаточно ресурсов (регистров, shared memory, потоков)<br />G80-G200 – передача параметров в shared mem, 2 X 8192 – не влезет в 16 килобайт<br />
  49. 49. Загрузка SM (occupancy)<br />Отношение числа работающих warps к из возможному количеству<br />В общем случае, к 100% надо стремиться:<br />Прячется латентность доступа к памяти<br />Но мало регистров (G92 – 16 регистров/thread)<br />Альтернативный подход:<br />Мало потоков (128-192-256 на SM)<br />Зато много регистров на поток<br />Полезно для блочных алгоритмов<br />Подробнее: Volkov, V. 2010. Use registers and multiple outputs per thread on GPUhttp://www.cs.berkeley.edu/~volkov/volkov10-PMAA.pdf<br />
  50. 50. Разное<br />Целая арифметика:<br />G80-G200: 24-бита – быстрая, 32 бита – медленная<br />GF100 – 32 бита – быстрая, 24 бита - медленная<br />Текстуры: 1-2-3D-массивы<br />Кэшируются, кэш локален по координатам (эффективное кэширование по столбцам, при последовательном доступе – медленнее global memory)<br />Аппаратная интерполяция<br />
  51. 51. Продолжение.....<br />Документация NvidiaОчень хорошая!http://developer.nvidia.com/object/cuda_download.html<br />CUDA Programming Guide<br />CUDA Reference Guide<br />CUDA Best Practices Guide<br />Примеры SDK и документация к нимhttp://developer.download.nvidia.com/compute/cuda/sdk/website/samples.html<br />Форумы Nvidiahttp://forums.nvidia.com/index.php?showforum=62<br />
  52. 52. Программные средства<br />CUDA Toolkit – компилятор + библиотеки<br />Интегрируется с Visual C++ (добавление правил компиляции для .cu)<br />Отладчик – gdb (командная строка)<br />Visual Profiler – не на уровне отдельных строк кода<br />Parallel Nsight<br />Пошаговая отладка<br />Глобальный профайлинг<br />Standard (бесплатная) и Professional (бесплатная для ВУЗов) версии<br />CUDA-x86<br />Был эмулятор, но в Cuda 3.x удален<br />PGI обещает компилятор<br />
  53. 53. Подробности компиляции<br />float4 me = gx[gtid];<br />me.x += me.y * me.z;<br />C/C++ CUDA<br />Application<br />CPU-code компилируется родным компилятором<br />PTX – неоптимизированный ассемблер, дальнейшие варианты:<br /><ul><li> Компиляция в один executable
  54. 54. Компиляция в внешний .cubin-файл и загрузка на runtime</li></ul>Финальную компиляцию реальные коды делает драйвер видеокарты<br />NVCC<br />CPU Code<br />PTX Code<br />Virtual<br />Physical<br />PTX to Target<br />Compiler<br /> G80<br /> …<br /> GPU <br />Target code<br />
  55. 55. Два API<br />CUDA C API: <br />реализуется внешней библиотекой cudart<br />Высокоуровневое, более удобное<br />удобная поддержка нескольких контекстов (например для использования в многопоточных программах)<br />CUDA Driver API: <br />Аналогично по возможностям<br />Не требует дополнительных библиотек<br />Больше работы программисту<br />
  56. 56. Альтернативы CUDA<br />OpenCL<br />CAL/IL (Compute Abstraction Layer/Intermediate Language)<br />Только видеокарты ATI<br />Потоковое программирование<br />Плохо поддерживается<br />DirectX 11 (DirectCompute)<br />Только Windows <br />
  57. 57. OpenCL<br />Многоплатформенный стандарт<br />Необычайно похож на CUDA Driver API<br />Детали:<br />Язык C для kernels, другие ключевые слова<br />Компиляция из исходных текстов на ходу («в драйвере»)<br />Уже две версии (1.0 и 1.1)<br />Нестандартная конфигурация поддерживается через «расширения»<br />
  58. 58. Сложение векторов<br />Код GPU:<br />__kernel void VectorAdd(__global const float* a,__global const float* b,__global float* c, int N)<br />{<br /> int iGID = get_global_id(0);<br /> if (iGID < N)<br /> c[iGID] = a[iGID] + b[iGID];<br />}<br />
  59. 59. Код CPU<br />// Создаем контекст GPU (до того был поиск устройств...)<br />Context = clCreateContext(0, 1, &cdDevice, NULL, NULL, &ciErr1);<br />// и очередь команд<br />CommandQueue = clCreateCommandQueue(Context, cdDevice, 0, &ciErr1);<br />// Аллоцируем массив(ы) на GPU<br />cmDevSrcA = clCreateBuffer(Context, CL_MEM_READ_ONLY, sizeof(cl_float) * szGlobalWorkSize, NULL, &ciErr1);<br />…. И еще два аллоцирования ....<br />// Создаем (компилируем) программу из исходных текстов<br />cpProgram = clCreateProgramWithSource(Context, 1, (const char **)&cSourceCL, &szKernelLength, &ciErr1);<br />// создаем из нее kernel<br />ckKernel = clCreateKernel(cpProgram, "VectorAdd", &ciErr1);<br />// задаем ему аргумент(ы)<br />clSetKernelArg(ckKernel, 0, sizeof(cl_mem), (void*)&cmDevSrcA);<br />.... И еще три аргумента ......<br />// В очередь команд помещаем копирование данных и запуск kernel, все асинхронно<br />clEnqueueWriteBuffer(CommandQueue, cmDevSrcA, CL_FALSE, 0, sizeof(cl_float) * szGlobalWorkSize, srcA, 0, NULL, NULL);<br />.... И еще одно копирование....<br />clEnqueueNDRangeKernel(CommandQueue, ckKernel, 1, NULL, &szGlobalWorkSize, &szLocalWorkSize, 0, NULL, NULL);<br />// В очередь команд помещаем синхронное чтение результата<br />clEnqueueReadBuffer(CommandQueue, cmDevDst, CL_TRUE, 0, sizeof(cl_float) * szGlobalWorkSize, dst, 0, NULL, NULL);<br />
  60. 60. CUDA  OpenCL<br />AMD: Porting CUDA to OpenCLhttp://developer.amd.com/zones/OpenCLZone/Pages/portingcudatoopencl.aspx<br />
  61. 61. Переносимость и производительность<br />Переносимыйкод (NVidia, ATI,x86, Cell)<br />Производительность не переносится:<br />Либо используем векторные типы на векторных архитектурах (ATI, Cell) и получаем непереносимый код<br />Либо код получается переносимый и в разы медленнее<br />Перенос CUDA  OpenCL – потеря 20-30%. Компилятор??<br />CUDA всегда будет впереди т.к. нет этапа согласований с рабочей группой<br />
  62. 62. OpenCL и видеокарты ATI<br />Человеческий интерфейс (в отличие от CAL/IL)<br />HD5870 – производительность примеров SDK - на уровне GTX280 (в разы ниже ожидаемого)<br />HD4xxx – производительность плохая т.к. нет shared memory (эмуляция через глобальную)<br />Плохая документация (в сравнении с...)<br />Но что делать, если попалось такое оборудование и не хочется ассемблера.....<br />
  63. 63. Почему GPU НАСТОЛЬКО быстрее?<br /><ul><li>Линейная алгебра: 5-8раз
  64. 64. Обработка сигналов, обработка изображений: десятки раз
  65. 65. Некоторые задачи (молекулярная динамика, N-body): бывают сотни раз</li></li></ul><li>Вот почему:<br />Другой аппаратный дизайн:<br />CPU – оптимизация под любые задачи (включая очень плохой код) и низкую латентность. <br />GPU – оптимизация под общую производительность и только высокопараллельные задачи.<br />Быстрая память:<br />В разы выше bandwidth видеопамяти<br />Больше очень быстрой памяти(2-3Mbпротив 32-256Kb L1 cache CPU)<br />Аппаратная поддержка ряда функций (exp, sin, cos, pow, log….): разница с CPU в десятки и даже сотни (!) раз<br />Часто сравнивают с неоптимизированным кодом (а другого и нет, писать руками SSE-инструкции скучно)<br />
  66. 66. На каких задачах GPU медленнее?<br />Задачи, которые не распараллеливаются на тысячи независимых потоков<br />State machine, операции со строками<br />Обход (одного большого) графа<br />Неподходящий размер working set:<br />На GPU 1-3 Mbочень быстрой памяти<br />На CPU 4-8-12-64Mb L2 cache<br />Случайный доступ к большому массиву<br />Видеопамять медленнее при случайном доступе<br />Низкая арифметическая интенсивность<br />
  67. 67. Как с этим жить?<br />Дешевый способ увеличить производительность в 5-10-100 раз, в зависимости от задачи.<br />Рекомендации по самостоятельному использованию:<br />Учиться на CUDA<br />Использовать OpenCL <br />если действительно нужна переносимость<br />Если нет GPU, а попробовать хочется<br />Использовать ATI и CAL/IL если нужна максимальная производительность на потоковых операциях<br />Используйте mixed-precision схемы (на CPU тоже очень полезно!)<br />
  68. 68. Как с этим жить - 2<br />Используйте библиотеки:<br />CUBLAS, CUFFT, CUSPARSE – входят в CUDA SDK<br />CUDPP, MAGMA, GATLAS, OpenCV – 3rd party и бесплатны<br />ACML-GPU для ATI<br />.... библиотек уже много....<br />Расширения для Matlab<br />Parallel Computing Toolbox (R2010b)<br />Jacket<br />GPUmat, ViennaCL<br />
  69. 69. CUDA: Университетские курсы<br />University of Urbana самый первыйдоступный курс курс: http://courses.engr.illinois.edu/ece498/al/Syllabus.html (доступны слайды и запись голоса).<br />Курс по CUDA, читаемый на ВМКЗаписи 2009 года: http://esyr.org/lections/audio/cuda_2009_summer/ и http://esyr.org/video/cuda/Записи 2010 года: ftp://geophyslab.srcc.msu.ru/Events/CUDA2010/Google-группа к этому курсу: http://groups.google.ru/group/cudacsmsusu/<br />
  70. 70. CUDA: книги<br />На русском<br />А. В. Боресков, А. А. Харламов Основы работы с технологией CUDA (+ CD-ROM)http://www.ozon.ru/context/detail/id/5080841/<br />На английском<br />Programming Massively Parallel Processors: A Hands-on Approach, David B. Kirk, Wen-mei W. Hwuhttp://www.amazon.com/Programming-Massively-Parallel-Processors-Hands/dp/0123814723/ref=sr_1_1?ie=UTF8&s=books&qid=1284301217&sr=8-1<br /> CUDA by Example: An Introduction to General-Purpose GPU Programming by Jason Sanders and Edward Kandrothttp://www.amazon.com/CUDA-Example-Introduction-General-Purpose-Programming/dp/0131387685/ref=sr_1_4?ie=UTF8&s=books&qid=1284301217&sr=8-4<br />
  71. 71. Литература OpenCL<br />Сайт с описанием стандарта: http://www.khronos.org/opencl/далее по ссылкам.<br />Обзор «OpenCL: A Parallel Programming Standard for Heterogeneous Computing Systems» http://ieeexplore.ieee.org/stamp/stamp.jsp?tp=&arnumber=5457293<br />Документы AMD по миграции с CUDA на OpenCL: <br />http://developer.amd.com/documentation/articles/pages/OpenCL-and-the-ATI-Stream-v2.0-Beta.aspx#four<br />http://developer.amd.com/gpu/ATIStreamSDK/pages/TutorialOpenCL.aspx<br />Документы NVIdia по программированию OpenCL:<br />Programming Guide: http://developer.download.nvidia.com/compute/cuda/3_1/toolkit/docs/NVIDIA_OpenCL_ProgrammingGuide.pdf<br />Best Practices Guide: http://developer.download.nvidia.com/compute/cuda/3_1/toolkit/docs/NVIDIA_OpenCL_BestPracticesGuide.pdf<br />Code Samples: http://developer.download.nvidia.com/compute/opencl/sdk/website/samples.html<br />Книги:<br />The OpenCL Programming Book http://www.fixstars.com/en/company/books/opencl/<br />
  72. 72. Литература: Разное<br />Debunking the 100X GPU vs CPU Myth: an Evaluation of Throughput Computing on CPU and GPUhttp://www.hwsw.hu/kepek/hirek/2010/06/p451-lee.pdf<br />Относиться с осторожностью, авторам статьи (инженерам Intel) обидно за свои процессоры и они тянут одеяло в свою сторону<br />
  73. 73. Спасибо за внимание!<br />Задавайте вопросы<br />

×