Upload
others
View
5
Download
0
Embed Size (px)
Citation preview
Вычисления на GPU с помощью OpenCL
библиотеки и инструменты
Максим Шевцов, [email protected]
Архитектор по разработке программного обеспечения, SSG-DPD, Intel
Intel Delta-4 Course 2015
Что вы знаете про GPU
Intel® Graphics:специальные (graphics/media) блоки и блоки для
произвольных вычислений
Rin
g B
us /
LLC
/ M
emor
y
CommandStreamer
(CS)
Vertex Fetch(VF)
Vertex Shader
(VS)
Hull Shader(HS)
Tessellator
Domain Shader
(DS)
Geometry Shader
(GS)
Stream Out(SOL)
Clip/Setup
Thread D
ispatch
Video Front End
(VFE)
Video QualityEngine
Multi-FormatCODEC
Blitter Display
Slice 0
L3$ Pixel OpsRasterizer /
DepthRender$Depth$
L1IC$
3D Sampler
Media Sampler
Data Port
Tex$
Sub
Slic
e 1
L1IC$
3D Sampler
Media Sampler
Data Port
Tex$
Sub
Slic
e 0
EU EU EU EU EU
EUEUEUEUEU
EU EU EU EU EU
EUEUEUEUEU
Slice 1
L3$ Pixel OpsRasterizer /
DepthRender$Depth$
L1IC$
3D Sampler
Media Sampler
Data Port
Tex$
Sub
Slic
e 3
L1IC$
3D Sampler
Media Sampler
Data Port
Tex$
Sub
Slic
e 2
EU EU EU EU EU
EUEUEUEUEU
EU EU EU EU EU
EUEUEUEUEU
(Second slice in Intel® Iris™ Graphics
and Intel® Iris™ Pro Graphics only)
Intel® Graphics Architecture Building Blocks:
Slice->Execution Unit (EU)->SIMD+threads
Sub
Slic
e
L1IC$
3D Sampler
Media Sampler
Data Port
Tex$
EU EU EU EU EU
EUEUEUEUEU
EUThread 0
Thread 2
Thread 4
Thread 6
Thread 1`
Thread 3
Thread 5
this();
if ( x )
that();
else
another();
finish();
SIMD lane
time
Example: “x” sometimes true
Peak GFlops: #EUs x ( 2 x 4-wide ALUs ) x ( MUL + ADD ) x Clock Rate
For Intel® Iris™ Pro 5200: 40 x 8 x 2 x 1.3 = 832 GFlops!
Введение в GPGPU
GPGPU
• Начиная с программируемых шейдеров (графические APIs)
• Через доменно-ограниченные языки (через DirectX/OpenGL)
• например обработки изображений
• stream computing
• К почти полной программируемости GPU, за исключением:
• Исключений (exceptions)->виртуальной памяти
• Стэка-> рекурсии
• Указателей на функции-> виртуальных функций
• и тд
Важно понимать фундаментальные концепции, ограничения и тенденции
а не конкретный API (OpenCL, OpenGL/DirectX compute, CUDA, RenderScript, Metal,Vulkan- какой след.? А через 10 лет?)
Далее, мы разберем OpenCL в качестве примера
Введение в OpenCL (историческое)
OpenCL–открытый стандарт для
программирования гетерогенных платформ
CPUsMultiple cores driving
performance increases
GPUsIncreasingly general purpose
data-parallel computing
Graphics APIs and Shading Languages
Multi-processor programming –
e.g. OpenMP
EmergingIntersection
HeterogeneousComputing
OpenCL – Open Computing Language
Параллельность, Портируемость, Производительность
Рабочая группа OpenCL в Khronos
• Чрезвычайное разнообразие представителей индустрии
(производители «железа», OEMs, производители ПО, ...)
• OpenCL уже стал важным кросс-платформенным стандартом
(покрытие рынка непрерывно растет)
• Intel активно участвует в разработке стандарта
(в т.ч. предоставляя оптимизированную реализацию для собственных платформ)
Введение в OpenCL
(техническое)
OpenCL: платфора и отдельные
устройства
12
•(Загружаемой) Реализации OpenCL
• Икапсулирует ресурсы (например память)
• Икапсулирует устройства (Compute Devices)
• Обеспечивает очереди и запуск задач, синхронизацию
• Обеспечивает компиляцию кода задач для конкр. устройств
• А также передачу данных, и многое другое....
Приложение использующее OpenCL состоит из
•Управляющей части (Host)
• Обычная программа
• Использующая базовую библиотеку от Khronos
• Чтобы общаться с конкретной платформой (реализацией)
OpenCL: контекст и его объекты
Все в OpenCL происходит в рамках
конкретных контекстов
Device[2]
In
Order
Queue
Out of
Order
Queue
Device[1]
In
Order
Queue
Out of
Order
Queue
Memory Objects
Context
Command Queues
Images
OpenCL Programs Kernels
#define g_c __global const
__kernel void dot_prod (g_c float4 *a,
g_c float4 *b,
g_c float *c)
{
int tid = get_global_id(0);
c[tid] = dot(a[tid], b[tid]);
}
__kernel void buff_add (g_c float4 *a,
g_c float4 *b,
g_c float *c)
{
int tid = get_global_id(0);
c[tid] = a[tid] +b[tid];
}
…
Compiled
ProgramBuffers
compute_device[0]
compute_device[1]
compute_device[2]
Kernel
Handler
Args List
Device[0]
In
Order
Queue
Out of
Order
Queue
dot_prod
buff_add
Function
arg[0]
arg[1]
Compile codeCreate data &
argumentsSend to
execution
На каждой точке итерационного пространства вызывается
кернел
Например обработка картинки 1024х1024, вызывая кернел попиксельно
имеем 1024 x 1024 = 1,048,576 вызовов
14
void
scalar_mul(int n,
const float *a,
const float *b,
float *c)
{
int i;
for (i=0; i<n; i++)
c[i] = a[i] * b[i]; }
__kernel void
dp_mul(global const float *a,
global const float *b,
global float *c)
{
size_t id = get_global_id(0);
c[id] = a[id] * b[id];
} // execute over “n” work-items
OpenCL: как происходят вычисления
(nDRange)
OpenCL™: Setting up the environment
Select and grab a platform
Select a device the platform provides
Create a context (can support multiple OR-ed devices)
Create a command queue to feed the device
err = clGetPlatformIDs(1, &platformId, &numPlatforms);
err = clGetDeviceIDs(platformId, CL_DEVICE_TYPE_GPU, 1, &device_id, NULL);
context = clCreateContext(platformId, 1, &device_id, NULL, NULL, &err);
Queue = clCreateCommandQueue(context, device_id, 0, &err);
Compute for Mobile Devices: Performance-focused
APIs Tutorial
OpenCL™: Create and Build the
Kernels
Define source code for the kernel program as a string literal or read from a file
Build the program object and Compile the program
Fetch and print error messages
Kernels can also be created from binaries
program = clCreateProgramWithSource(context, 1 &KernelSource, NULL, &err);
err = clBuildProgram(program, 0, NULL, NULL, NULL, NULL);
size_t len; char buffer[2048];
clGetProgramBuildInfo(program, device_id, CL_PROGRAM_BUILD_LOG,
sizeof(buffer), buffer, &len);
printf(“%s\n”, buffer);
Compute for Mobile Devices: Performance-focused
APIs Tutorial
OpenCL™: Setup Memory Objects
For the Vector addition example, we need 3 memory objects: 2
input buffers (A and B) and one output buffer (D).
A_buffer = clCreateBuffer(context, CL_MEM_READ_ONLY | CL_MEM_USE_HOST_PTR,
sizeof(float) * count, A_data, NULL);
B_buffer = clCreateBuffer(context, CL_MEM_READ_ONLY | CL_MEM_USE_HOST_PTR,
sizeof(float) * count, B_data, NULL);
D_buffer = clCreateBuffer(context, CL_MEM_WRITE_ONLY, sizeof(float) * count,
NULL, NULL);
Compute for Mobile Devices: Performance-focused
APIs Tutorial
OpenCL™: Define the kernel
Create kernel object from kernel function “vadd”
Attach arguments to kernel object
kernel = clCreateKernel(program, “vadd”, &err);
err = clSetKernelArg(kernel, 0, sizeof(cl_mem), &A_buffer);
err = clSetKernelArg(kernel, 1, sizeof(cl_mem), &B_buffer);
err = clSetKernelArg(kernel, 2, sizeof(cl_mem), &D_buffer);
err = clSetKernelArg(kernel, 3, sizeof(cl_float), &constant);
Compute for Mobile Devices: Performance-focused
APIs Tutorial
OpenCL™: Submit commands / Execute
Enqueue the kernel for execution
Read back results
This API call is blocking. It returns only after the pipeline (queue) is complete,
beyond the read operation.
size_t range[3] = {count, 1, 1}; // Define global size of execution
err = clEnqueueNDRangeKernel(queue, kernel, 1, NULL, range, NULL, 0, NULL, NULL);
err = clEnqueueReadBuffer(queue, D_buffer, CL_TRUE, 0, sizeof(float) * count, D_data,
0, NULL, NULL);
Compute for Mobile Devices: Performance-focused
APIs Tutorial
OpenCL: модель памяти
Мы не будем вдаваться в
подробности, отметим только что
есть:
•«Глобальная» память – большая
и медленная
•«Локальная» память-маленькая и
быстрая
• Напоминающая кэш
• Но управляемый «руками»
20
Концепции OpenCL: как всё это
соответствует современному процессору?
Например в обычном процессоре это2 OpenCL устройства (compute devices)• CPU
o 4 compute units (2 ядра * гипертрединг)o Число Processing Elements – ширина SIMD
(например 8 для floating point)• Интегр. GPU
o 16 compute units и в каждомo 16 Processing Elements – SIMD
OpenCL
Platform
Model*
Сравнение производительности для OpenCL и трад. «нативных» моделей (на CPU)
а также OpenCL на GPU
Немного про векторизатор
__kernel void program(float4* pos, int numBodies, float deltaTime)
{
float myPos = gid;
float refPos = numBodies + deltaTime;
float4 r = pos[refPos – myPos];
float distSqr = r.x * r.x + r.y * r.y + r.z * r.z;
float invDist = sqrt(distSqr + epsSqr);
float invDistCube = invDist * invDist * invDist;
float4 acc = invDistCube * r;
float4 oldVel = vel[gid];
float newPos = myPos.w;
}
Код OpenCL керенлаНеск. едениц работыСлед: Графическая аналогия
Графическая аналогия…След: Скаляризация
Код скаляризуется…След: Векторизация
Как векторизуется код…
Векторные инструкцийКоличество вызовов
кернела соотв сокращается
Векторизация производит код
эффективно зайдействующий
векторные конвейеры устройства
Производительность(оригинальное демо с Siggraph’12)
Производительность(оригинальный слайд с Siggraph’10)
Nbody - вычислительно-требовательная, но
довольная простая (в смысле кода) задача:
•Отсутствуют if/else
•Много арфиметики
•Немного входных-выходных данных
Именно поэтому OpenCL так хорошо для нее
подходит:
•Скалярный кернел замечательно векторизуется
(«ручная» вектор. версия не намного быстрей)
•Скалируемость (по потокам) близка к линейной
=>Прозводительность близка к ручному SSE
Производительность(оригинальное демо с GDC’11)
1 Results measured on CoreTM i7 975, 3.3
GHz, 6GB DDR32 Results depends on the
algorithm/implementation
Use relaxed math flag when possible with OpenCL!
Game Dev Sweet Spot!
Relative solver Performance within same grid size
Производительность(оригинальный слайд с GDC’11)
В отличии от Nbody – этот солвер
прибрежной воды не только вычислительно-
требовательная, но и сложная (в смысле
кода) задача:
•Множество if/else, косвенной адресации
•Много разнотипных вычислений
•Много входных-выходных данных
И всё таки интеловский OpenCL справлятся
=>Прозводительность близка к ручному
SSE (но не требует переписывания на
AVX/AVX2/AVX3 и тд)
Гетерогенное
использование OpenCL
GP
U
CP
U
Как оптимизировать приложения с
OpenCL
General flow of OpenCL™ optimizations
1. Check general CPU/GPU utilization and frequencies
Basic HW metrics in VTune (offline) or GPA System Analyzer (online/offline)
2. Host (app)-level sanity
Find/fix gaps in the timeline
3. Kernel-level BKMs
Advanced/precise EUs metrics in VTune
Memory BW metrics in VTune
Tracking GPU frequency with System Analyzer helped proper Turbo-ing
Gen OCL device for the CPU+GPU mode
Gen freq
Turbo-edGen freq
stays high
Switching from CPU to CPU+GPU mode
doesn’t trigger Turbo for GPU by default
Gen freq
stays flat
After short “GPU-only” warming added,
Gen’s freq get boosted
Initial code
Optimized code
31
Example: Check CPU/GPU frequencies with GPA
System Analyzer
Intel® VTune™ Amplifier XE correlates
CPU/GPU activities
CPU or GPU bound?
32
Regular CPU hotspots
GPU/CPU activities
Host (app-) optimizations check-list
Using any tracer watch for
Redundant synchronisation: APIs like clFinish, clWaitForEvents, etc
100(s) of microseconds
Redundant copies: APIs like clEnqueueRead/Write/XXX ( ~milliseconds)
Intensive objects manipulation: APIs like clCreateXXX, clReleaseXXX (~ms)
Only then switch to kernel-level optimizations
General CPU activity is
still important- all calls
except clEnqueueXXX
happen in host threads
Example host optimizations: OpenCV gftt func
case-studyclCreateBuffer clReleaseMemObject clReleaseMemObject clEnqueueNDRangeKernel clGetKernelWorkGroupInfo
clCreateSubBuffer clReleaseMemObject clReleaseMemObject clFlush clEnqueueNDRangeKernel
clEnqueueWriteBuffer clCreateBuffer clGetKernelWorkGroupInfo clFinish clFlush
clCreateBuffer clCreateSubBuffer clEnqueueNDRangeKernel clReleaseMemObject clGetKernelWorkGroupInfo
clCreateSubBuffer clEnqueueWriteBuffer clFlush clReleaseMemObject clEnqueueNDRangeKernel
clEnqueueWriteBuffer clCreateBuffer clCreateBuffer clGetKernelWorkGroupInfo clFlush
clCreateBuffer clCreateSubBuffer clCreateSubBuffer clEnqueueNDRangeKernel clGetKernelWorkGroupInfo
clCreateSubBuffer clEnqueueWriteBuffer clGetKernelWorkGroupInfo clFlush clEnqueueNDRangeKernel
clGetKernelWorkGroupInfo clCreateBuffer clEnqueueNDRangeKernel clEnqueueReadBuffer clFlush
clEnqueueNDRangeKernel clCreateSubBuffer clFlush clFinish clGetKernelWorkGroupInfo
clFlush clGetKernelWorkGroupInfo clEnqueueReadBuffer clReleaseMemObject clEnqueueNDRangeKernel
clGetKernelWorkGroupInfo clEnqueueNDRangeKernel clFinish clReleaseMemObject clFlush
clEnqueueNDRangeKernel clFlush clReleaseMemObject clEnqueueReadBuffer clGetKernelWorkGroupInfo
clFlush clGetKernelWorkGroupInfo clReleaseMemObject clEnqueueReadBuffer clEnqueueNDRangeKernel
clFinish clEnqueueNDRangeKernel clCreateImage clEnqueueWriteBuffer clFlush
clReleaseMemObject clFlush clEnqueueCopyBufferToImage clEnqueueReadBuffer clEnqueueReadBuffer
clReleaseMemObject clFinish clCreateBuffer clEnqueueWriteBuffer clEnqueueReadBuffer
clFinish clReleaseMemObject clCreateSubBuffer clReleaseMemObject clEnqueueWriteBuffer
clReleaseMemObject clReleaseMemObject clCreateBuffer clFinish clFinish
clReleaseMemObject clFinish clCreateSubBuffer
clFinish clReleaseMemObject clEnqueueWriteBuffer
clReleaseMemObject clGetKernelWorkGroupInfo
clFinish
new callsold calls sequence
Original kernel
uses images
Significant
overheads
since input
comes in buffer
Code altered to
use buffers
4X speedup
EU Active / EU Stalled / EU Idle
Each metric is ratio of Execution Unit (EU) time spent in one
of the three states below vs total time
EU executing instructions
=> EU Active
EU waiting (e.g. for data) with at least one thread scheduled
=> EU Stalled
no threads scheduled
=> EU Idle
35
Kernel-level optimizations
Fix overall device utilization (“GPU Busy”), prev foils
Check the values with VTune/GPA
Ensure good EU utilization (“EUActive” is high)
Especially reduce time with “EUs Idle” (launch enough work for all EUs)
Make each work-item do enough work to amortize thread launch
Check the values with VTune/GPA
Ensure optimal memory BW (“EUStalled” low, “GPU reads/writes” high)
Proper access pattern
Proper data types
Check the values with VTune/GPA
Немного о взаимодействии с
другими API
Взаимодействие с MSDK(оригинальный пример для интегр. GPU из SDK)
•Аппаратное видео-декодирование с MSDK
•Пост-обработка с помощью OpenCL
•И никаких лишних копирований между ними
И еще о взаимодействии с другими
API
Примеры в SDK
Обзор инструментов
Intel® OpenCL Code BuilderРедактор кернелов с возможностью запуска и отладки
All other trademarks are property of their respective owners. *The OpenCL trademark and logo are property of Apple , Inc. used by
permission by Khronos.
Intel® GPAТрассировка команд и очередей с Intel® GPA Platform Analyzer
All other trademarks are property of their respective owners. *The OpenCL trademark and logo are property of Apple , Inc. used by
permission by Khronos.
Intel® GPAВажные метрики в Intel® GPA’s System Analyzer
All other trademarks are property of their respective owners. *The OpenCL trademark and logo are property of Apple , Inc. used by
permission by Khronos.
Intel® VTune™ Amplifier XE
Overall summaryRenderScript* OpenCL™ Metal* GLES™
Fragments Shaders
GLES™ Compute Shaders
Support for devices beyond GPU Yes Yes No No NoExplicit jobs scheduling No Yes No No NoSimple API Yes No No No NoRich kernel language Yes Yes Yes No YesOS integration Yes No Yes Yes YesInteroperability with other APIs Yes Yes Yes No NoLow-level tuning No Yes Yes No YesPortable across OSes No Yes No Yes Yes
Compute for Mobile Devices: Performance-focused
APIs Tutorial
Few Recommendations
If not using OpenGL ES™ already, better not to use Compute Shaders
Especially since there is no universal support by devices
OpenCL™ is better for large-bad things like physics library
Best to write portable code for visual computing apps
GLES fragment shaders is the only portable/ubiquitous way today
Less ways to optimize comparing to the dedicated Compute APIs
Do a lot of image processing with CPU and just seek for a speedup?
Look at RenderScript* (Metal* for iOS)
Look into domain-specific libs like OpenCV*
“Transparent” acceleration on GPU (OpenCL) , CPU (via Intel IPP®), DSPs (OpenVX*)
Compute for Mobile Devices: Performance-focused
APIs Tutorial
Couple of Thoughts for Compute APIs
Directions
47
Improved handling of long-running kernels (preemption)
Half float (16-bit) support, like in Metal
Better graphics/media interop
Managed execution
Faster dispatching allowing finer-grain tasks
Thermal and device load hints (adaptive quality)
and still…simpler API