View
0
Download
0
Category
Preview:
Citation preview
บทท 3
หนวยประมวลผลกราฟกส
3.1 หนวยประมวลผลกราฟกส (Graphics Processing Unit : GPU)
จากขอมลคณสมบตของ GPU ทแสดงในตารางท 3.1 จะเหนวา GPU รน GTX 570 ม
จ านวนโปรเซสเซอร (Streaming Processor : SP) หรอเรยกอกชอหนงวาคดาคอร (CUDA core)
ทงหมด 480 ตว นอกจากนน GTX 570 สามารถท างานไดทความถสญญาณนาฬกา 1484 MHz นน
หมายความวา GTX 570 มความเรวในการค านวณเลขทศนยมสงสดในทางทฤษฏเทากบ 480 x
1484 × 2 = 1424.64 GFlops นนเอง (GPU สามารถประมวลผลเลขทศนยมไดพรอมกน 2 ค าสง)
และ CPU รนทน ามาใชในงานวจยนคอ AMD Phenom II X4 965 ซงมความเรวในการค านวณเลข
ทศนยมสงสดในทางทฤษฏเทากบ 4 × 3400 × 4 = 54.4 GFlops (CPU สามารถประมวลผลได
พรอมกน 4 เธรดตอหนงคอรโปรเซสเซอร) ซงถาเปรยบเทยบประสทธภาพในการค านวณระหวาง
GPU และ CPU ดงกลาว จะเหนไดวา GPU มประสทธภาพในการประมวลผลในทางทฤษฏสงกวา
CPU ถงกวา 26 เทา
ตารางท 3.1 คณสมบตของ GPU รน GTX 570 และ CPU รน AMD Phenom II X4 965 [28]
GTX 570 AMD Phenom II X4 965
Engine
specification
CUDA cores 480 4
Processor clock
(MHz) 1484 3400
Memory
specification
Memory clock (MHz) 3800(DDR5) 1333(DDR3)
Memory Bandwidth
(GB/s) 152.0 10.6
Memory Interface
Width 320-bit 64-bit
13
3.2 สถาปตยกรรม CUDA (Compute Unified Device Architecture)
ในป ค.ศ.2006 ทางบรษท nVIDIA ไดพฒนา CUDA (Compute unified device
architecture) ซงเปนสถาปตยกรรมการประมวลผลแบบขนานเพอใหนกพฒนาซอฟตแวรทวไป
สามารถน า GPU ไปประยกตใชในงานประมวลผลทวไปได โดยสถาปตยกรรมของ CUDA แสดง
ไดดงรปท 3.1
รปท 3.1 สถาปตยกรรมของ CUDA [29]
สงทนกพฒนาซอฟตแวรตองท ากคอ การแบงปญหาทตองค านวณออกเปนสวนยอย ซงแต
ละสวนจะตองสามารถน ามาค านวณไดอยางอสระดงรปท 3.2 ซงจะเหนไดวายง GPU มจ านวน
คอรโปรเซสเซอรมากเทาไร การประมวลผลกจะเรวมากขนเทานน
14
รป 3.2 การแตกปญหาออกเปนปญหายอยหลายๆปญหา
3.3 การเขยนโปรแกรมพนฐานดวย CUDA
3.3.1 ฟงกชนเคอรเนล (Kernel function)
เคอรเนล เปนฟงกชนส าหรบใชเรยกใชงานหนวยประมวลผลกราฟกส ใหประมวลผล
แบบขนานใน CUDA ซงเคอรเนลจะมรปแบบในการใชงานคลายกบการเรยกใชฟงกชนในภาษาซ
แตมขอแตกตางกนเลกนอย คอ ตองประกาศโดยใชตวก าหนดประเภทเปน __global__ โดยตอง
เปนฟงกชนประเภทไมคนคา (void function) เทานน ดงนนการสงผานคาตวแปรจะเปนแบบ Pass
by reference และในการเรยกใช ตองมการก าหนดขนาดและมตของกรดและบลอคภายใน
เครองหมาย <<<…>>> รวมถงขนาดของหนวยความจ าแบบแชร(Shared memory) ดวยในบาง
กรณ
ในรปท 3.3 จะแสดงตวอยางการเรยกใชเคอรเนล myKernel เพอประมวลผลขอมล myData
ซงก าหนดใหเปนชดขอมลขนาด 512×512 โดยใชบลอก 2 มต ขนาด 16 ×16 และกรด 2 มต ขนาด
Multithreaded CUDA Program
Block 4
Block 1
Block 5
Block 0 Block 2
Block 6
Block 3
Block 7
GPU with 4 cores
Core 0 Core 1 Core 2 Core 3
Block 0 Block 1 Block 2 Block 3
Block 4 Block 5 Block 6 Block 7
GPU with 2 cores
Core 0 Core 1
Block 0 Block 1
Block 2 Block 3
Block 4 Block 5
Block 6 Block 7
15
32×32 ในการท างานนนขนาดของกรดตองสอดคลองกบขนาดของขอมลและขนาดของบลอค ซงก
คอ 512÷16 = 32 เพอใหมการประมวลผลครบทกขอมล ส าหรบ dim3 เปนตวแปรส าหรบเกบคามต
และขนาดของทงกรดและบลอก ซงผลลพธทไดของเคอรเนลน คอ myOutput
รป 3.3 ตวอยางการเรยกใชเคอรเนล
3.3.2 ล าดบขนของเธรดใน CUDA
การประมวลผลแบบขนานเปนการท างานตามจ านวนเธรด ซงเธรดเปนสวนทเลกทสดใน
การประมวลผล ค าสงทเขยนในเคอรเนล คอค าสงทแตละเธรดใชท างานกบขอมล 1 ชด เราสามารถ
ก าหนดจ านวนของเธรดทตองการใชงานได โดยปกตจะก าหนดจ านวนของเธรดใหเทากบจ านวน
ของขอมล เพอใหขอมลทกตวถกประมวลผลพรอมกนแบบขนาน
เธรดทงหมดในเคอรเนล จะตองถกจดเรยงเปนกลมเรยกวา บลอก (Block) โดยเรา
สามารถก าหนดขนาดของบลอกไดโดยอสระ ซงในปจจบน GPU สามารถทจะก าหนดขนาดของ
บลอกไดถง 1024 เธรดตอบลอก [3] และมรปแบบการจดเรยงไดไมเกน 3 มต แตในกรณทจ านวน
เธรดทตองการเรยกใชงานมมากกวาจ านวนเธรดสงสดทบลอกสามารถรองรบได กจะมวธการคอ
จดแบงเธรดออกเปนบลอกมากกวา 1 บลอก และแตละบลอกจะตองถกจดเรยงเปนกลมเรยกวา
กรด (Grid) ซง กรดจะมรปแบบการจดเรยงไดไมเกน 2 มต ดงนนในแตละเคอรเนลกคอการ
ประมวลผลของกรด 1 กรดนนเอง
ในการใชงาน GPU เราจะระบต าแหนงทตองการใชงานไดโดย ใชคอนดบทใชในการ
ระบเธรด หรอ threadID ส าหรบระบเธรดในบลอก และใชคอนดบในการระบบลอกหรอ blockID
ในการระบบลอกภายในกรด เชน การระบเธรดในบลอก 2 มต ขนาด (Dx, Dy) โดย threadID เปนค
อนดบ (x, y) คอ (x+yDx) และส าหรบการระบบลอกใน 3 มต ขนาด (Dx, Dy , Dz) โดยท threadID
dim3 dimBlock(16, 16);
dim3 dimGrid(32, 32);
MyKernel<<<dimGrid, dimBlock>>>(myData, myOutput);
16
เปนคอนดบ (x, y, z) คอ (x+yDx+zDxDy) ส าหรบการระบบลอกในกรด blockID กจะมลกษณะการ
ใชงานแบบเดยวกนกบการระบเธรดในบลอก
รปท 3.4 แสดง กรดของเธรดบลอก [3]
ยกตวอยางเชน ถากรดมขนาด 5 x 5 บลอก และแตละบลอกมขนาด 10 x 10 เธรด ในกรณ
นจะมเธรดทงหมด 2500 ตว ดงรปท 3.5
Block (1,1)
Thread(0,0)
Thread(0,1)
Thread(0,2)
Thread(1,1)
Thread(1,2) Thread(2,2)
Thread(2,1)
Thread(3,2)
Thread(3,1)
Thread(3,0) Thread(2,0) Thread(1,0)
Grid
Block(0,1) Block(1,1) Block(2,1)
Block(0,0) Block(1,0) Block(2,0)
17
รปท 3.5 โครงสรางของเธรด
3.3.3 ล าดบขนของหนวยความจ าใน CUDA
ใน CUDA เธรดจะเขาถงหนวยความจ าไดหลายระดบ ดงแสดงในรปท 3.6 แตละเธรดก
จะมหนวยความจ าเฉพาะตว (Per-thread local memory) และแตละบลอกจะมหนวยความจ าแบบ
รวมทเธรดในบลอกเดยวกนสามารถใชรวมกนได (Per-block shared memory) โดยหนวยความจ า
แบบรวมนจะสนสดการท างานพรอมกบบลอกนนๆ สวนหนวยความจ าททกเธรดเขาถงไดโดยไม
จ ากดบลอกและกรด คอ หนวยความจ ารวมทวไป (Global memory) และนอกจากนยงม
หนวยความจ าประเภทอานไดอยางเดยวททกเธรดสามารถเขาถงไดเชนกน คอ หนวยความจ า
ส าหรบเกบคาคงทและเกบคาพนผว
ส าหรบหนวยความจ าเหลาน ไดแก หนวยความจ ารวมทวไป(Global memory),
หนวยความจ าส าหรบเกบคาคงท(Constant memory) และหนวยความจ าส าหรบเกบคาพนผว
gridDim.x = 5
blockIdx.x = 0
blockIdx.y = 0
blockIdx.x = 4
blockIdx.y = 0
blockIdx.x = 1
blockIdx.y = 0
blockIdx.x = 3
blockIdx.y = 0
blockIdx.x = 2
blockIdx.y = 0
blockIdx.x = 0
blockIdx.y = 1
blockIdx.x = 4
blockIdx.y = 1
blockIdx.x = 1
blockIdx.y = 1
blockIdx.x = 3
blockIdx.y = 1
blockIdx.x = 2
blockIdx.y = 1
blockIdx.x = 0
blockIdx.y = 2
blockIdx.x = 4
blockIdx.y = 2
blockIdx.x = 1
blockIdx.y = 2
blockIdx.x = 3
blockIdx.y = 2
blockIdx.x = 2
blockIdx.y = 2
blockIdx.x = 0
blockIdx.y = 3
blockIdx.x = 4
blockIdx.y = 3
blockIdx.x = 1
blockIdx.y = 3
blockIdx.x = 3
blockIdx.y = 3
blockIdx.x = 2
blockIdx.y = 3
blockIdx.x = 0
blockIdx.y = 4
blockIdx.x = 4
blockIdx.y = 4
blockIdx.x = 1
blockIdx.y = 4
blockIdx.x = 3
blockIdx.y = 4
blockIdx.x = 2
blockIdx.y = 4
blockDim.x = 10
threadIdx.x = 3
threadIdx.y = 1
18
(Texture memory) จะสนสดการท างานลงพรอมกบโปรแกรมประยกต ดงนนทกเคอรเนลจะ
สามารถใชงานหนวยความจ าทงหมดดงกลาวรวมกนได
รปท 3.6 แสดงล าดบขนของหนวยความจ าใน CUDA [3]
3.3.4 การท างานรวมกนระหวาง GPU กบ CPU
รปแบบการโปรแกรมของ CUDA นน จะเปนการใชงาน GPU (หรอเรยกวา Device) มา
ท าหนาทเปนหนวยประมวลผลรวม (Co-processor) เพอใหสามารถท างานรวมกบ CPU (หรอ
เรยกวา Host) ทท าการประมวลผลโปรแกรมภาษา C อย สวนการคอมไพลโปรแกรมจะใชค าสง
nvcc ดงรปท 3.7
Per-thread local
memory
Global
memory
Per-Block shared
memory
Thread
Grid 0
Block (0,0) Block (1,0) Block (2,0)
Block (0,1) Block (1,1) Block (2,1)
Grid 1
Block (0,0)
Block (0,1)
Block (0,2)
Block (1,2)
Block (1,1)
Block (1,0)
Thread block
19
รปท 3.7 การคอมไพลโปรแกรม [29]
3.3.5 หนวยความจ าของ GPU
ในการประมวลผลขอมลบน GPU นน ขอมลทจะน ามาประมวลผลจะถก CPU เกบไวใน
Host memory โดยท Host memory กบ Device memory จะถกเชอมตอกนผานบสทใชกนอยใน
ปจจบน คอบส PCI Express ซงมแบนดวดธต ากวา Device memory มาก ดงนนหากในชวงท GPU
ท าการประมวลผลอย แลวมการเรยกใชขอมลจาก Host memory ตลอดเวลา จะท าใหมปญหาคอ
ขวดเกดขน เพอแกไขปญหาดงกลาว ในการใชงาน GPU จงจ าเปนตองมการโหลดขอมลจาก Host
memory ไปไวใน Device memory กอน แลวคอยให GPU ท าการประมวลผล หลงจากประมวลผล
เสรจและไดผลลพธเกบไวใน Device memory จงคอยสงผลลพธจาก Device memory คนให Host
memory เพอให CPU เอาประมวลผลตอไป หนวยความจ าใน GPU ประกอบไปดวยหนวยความจ า
สวนตางๆ ดงรปท 3.8
Integrated CPU
And GPU C source code
NVCC
PTX code
PTX to target
compiler
GT200 ….. Fermi
GCC
CPU code
CPU/GPU
Executable
GPU target code
20
รปท 3.8 แสดงหนวยความจ าตางๆของ GPU [29]
จากรปท 3.8 จะเหนวา GPU จะประกอบไปดวยหนวยความจ าหลายๆสวนดวยกน ไดแก
Local memory, Global memory, Constant memory, Texture memory, Shared memory และ
รจสเตอร ในบรรดาหนวยความจ าเหลาน หนวยความจ าทมพนทมากทสด คอ Global memory และ
Texture memory สวนหนวยความจ าทเขาถงไดเรวทสดคอ Constant memory, Shared memory
และ รจสเตอร สวน Global memory, Local memory และ Texture memory จะเขาถงไดชากวา
ลกษณะเดนของหนวยความจ าแตละแบบ ไดแสดงดงตารางท 3.2
ตารางท 3.2 แสดงลกษณะเดนของหนวยความจ าชนดตางๆใน GPU [29]
Memory Location On/off
chip Cached Access Scope Lifetime
Register On n/a R/W 1 thread Thread
Local Off + R/W 1 thread Thread
Shared On n/a R/W All threads in
block Block
Global Off + R/W All thread+host Host allocation
Constant Off Yes R All thread+host Host allocation
Texture Off Yes R All thread+host Host allocation
To host
Device
DRAM
Local
Global
Constant
Texture
GPU Multiprocessor
Constant and texture
caches
Multiprocessor
Multiprocessor
Registers Shared
memory
21
จากรปท 3.8 จะเหนไดวาใน GPU ประกอบไปดวย มลตโปรเซสเซอรหลายๆตว ซงแตละ
ตวจะมหนวยรจสเตอรเปนของตวเอง และมหนวยความจ าแบบแชรอยในชป (On-chip Shared
memory) ทยอมใหมลตโปรเซสเซอรสามารถใชงานรวมกนได สามารถอานและเขยนได รวมถงม
หนวยความจ าแคชทใชส าหรบเกบคาคงท (Constant cache) และส าหรบเกบคาพนผว (Texture
cache) ทเกบขอมลประเภทอานอยางเดยว อยในชปเชนกน สวนหนวยความจ าของการดแสดงผล
(Device memory หรอ DRAM) จะประกอบไปดวย Local memory, Global memory, Constant
memory และ Texture memory ซงเปนหนวยความจ าทอยบนบอรด(On-board memory) โดยท
Local memory และ Global memory จะสามารถอานและเขยนได สวน Constant memory และ
Texture memory สามารถอานไดอยางเดยว
CUDA ถกออกแบบใหมการเขาถงหนวยความจ าไดอยางอสระ ทงการเขาถงแบบ Gather
และ Scatter เหมอนกบ CPU รวมทงใชหนวยความจ าแบบแชร (On-chip shared memory) ท า
หนาทเปนแคชส าหรบประมวลผลขอมลแบบขนาน (Parallel Data Cache:PDC) ซงสามารถเขาถง
ขอมลไดเรวกวาหนวยความจ าของการดแสดงผล (Device memory) ท าใหสามารถใชขอไดเปรยบน
โดยการเกบขอมลทจ าเปนตองเขาถงบอยๆไวทหนวยความจ าแบบแชร(On-chip shared memory)
แทนหนวยความจ าการดแสดงผล (Device memory) เพอลดปญหาคอขวดได
3.3.6 ตวอยางการใชงาน CUDA [30]
- ตวอยางโปรแกรมบวกเวคเตอร
ในรปท 3.9 จะแสดงซอรสโคดของโปรแกรมบวกเวคเตอรทเขยนโดยภาษา C ประมวลผล
โดย CPU
22
รปท 3.9 ตวอยางโปรแกรมบวกเวคเตอรทเขยนดวยภาษา C
จากซอรสโคดรปท 3.10 ลองมาพจารณาเฉพาะสวนของฟงกชน add() ทเปนสวนของการ
ค านวณ ดงแสดงในรปท 3.9
รปท 3.10 แสดงฟงกชน add()
จากรปท 3.10 จะเหนไดวา add() เปนฟงกชนส าหรบการค านวณหาผลบวกเวคเตอร a และ
b แลวเกบผลลพธเปนเวคเตอร c ซงในลป while จะวนลปท างานดงกลาวเปนจ านวน N ครง ตาม
คาดชนของตวแปร tid และเราสามารถเขยนซอรสโคดของฟงกชน add() ไดใหมอกแบบดงรปท
3.11
void add(int *a, int *b, int *c){
int tid = 0;
while (tid < N){
c[tid] = a[tid] + b[tid];
tid += 1;
}
}
void add(int *a, int *b, int *c){
int tid = 0;
while (tid < N){
c[tid] = a[tid] + b[tid]; tid += 1;
}
}
int main(void){
int a[N], b[N], c[N];
for (int i=0; i<N; i++){
a[i] = -i; b[i] = i * i;
}
add(a, b, c);
for (int i = 0; i<N; i++){
printf(“%d + %d = %d\n”, a[i], b[i], c[i]);
}
return 0;
}
23
รปท 3.11 ซอรสโคดของฟงกชน add() ทเขยนใหม
จากซอรสโคดทเขยนใหมในรปท 3.11 จะเหนไดวา เราสามารถน าฟงกชน add() ไป
ประมวลผลแบบขนานโดยใช CPU หรอ GPU ทมหลายคอรได ยกตวอยางเชน ในโปรเซสเซอร
แบบสองคอร(Dual core Processor) เราจะเพมคาของตวแปรดชน tid ขนเปนทละ 2 และก าหนดคา
เรมตนใหคอรแรกประมวลผลตามดชนเลขค สวนคอรทสองใหประมวลผลตามดชนเลขค ซงจะท า
ใหฟงกชน add() ถกคอรทงสองของ CPU ชวยกนประมวลผล ดงแสดงในรปท 3.12
รปท 3.12 แสดงซอรสโคดของฟงกชน add() ทถกแบงใหแตละคอรของ CPU ท างาน
จะเหนไดวาซอรสโคดยาวขน เนองจากตองท าการแบงเธรดใหแตละคอรของ CPU ท างาน
ซงกเปนการท าใหใชทรพยากรเพมขน แตกแลกมาดวยความเรวในการประมวลผลแบบขนาน
วธการใช GPU ประมวลผลการบวกเวคเตอร
เราสามารถน าวธเดยวกนมาเขยนโปรแกรมให GPU ประมวลผลฟงกชน add() ได โดย
เปลยนไปใชDevice code เพอเรยกให GPU ประมวลผลแทน แตกอนทจะไปด Device code จะพด
ถงฟงกชน main() กอน ซงจะมความแตกตางจากซอรสโคดของ CPU เลกนอย ดงแสดงในรปท
3.13
CPU CORE 2
void add(int *a, int *b, int *c){
int tid = 1;
while (tid<N){
c[tid] = a[tid] + b[tid];
tid += 2;
}
}
CPU CORE 1
void add(int *a, int *b, int *c){
int tid = 0;
while (tid<N){
c[tid] = a[tid] + b[tid];
tid += 2;
}
}
void add(int *a, int *b, int *c){
for (i=0; i<N; i++){
c[tid] = a[tid] + b[tid];
}
}
24
รปท 3.13 แสดงซอรสโคดของ GPU
ซอรสโคดในรปท 3.13 มขนตอนการท างานดงน
- ใชค าสง cudaMalloc() ส าหรบจองพนทหนวยความจ าใน GPU โดยเกบคาของอารเรย
dev_a และ dev_b เปนอนพท และ dev_c ส าหรบเกบผลลพธ
- ใชค าสง cudaFree() ส าหรบเคลยรคาเดมในหนวยความจ าทจองไว
- ใชค าสง cudaMemcpy() เพอท าการคดลอกคาของเวคเตอร a และ b จากหนวยความจ า
หลกของ CPU มาไวใน global memory ของ GPU โดยใชพารามเตอร
cudaMemcpyDeviceToHost
- สงให GPU ด าเนนการฟงกชน add() โดยใชค าสง Add<<<N, 1>>>(dev_a, dev_b,
dev_c);
ส าหรบฟงกชน add() ใน Device code แสดงดงในรปท 3.14
int main(void){
int a[N], b[N], c[N];
int *dev_a, *dev_b, *dev_c;
cudaMalloc( (void**) &dev_a, N * sizeof(int) )
cudaMalloc( (void**) &dev_b, N * sizeof(int) )
cudaMalloc( (void**) &dev_c, N * sizeof(int) )
for (int i=0; i<N; i++){
a[i] = -i; b[i] = i * i;
}
cudaMemcpy( dev_a, a, N * sizeof(int),cudaMemcpyHostToDevice);
cudaMemcpy( dev_b, b, N * sizeof(int),cudaMemcpyHostToDevice);
add<<<N, 1>>>(dev_a, dev_b, dev_c);
cudaMemcpy( dev_c, c, N * sizeof(int),cudaMemcpyDeviceToHost);
for (int i = 0; i<N; i++){
printf(“%d + %d = %d\n”, a[i], b[i], c[i]);
}
cudaFree( dev_a ); cudaFree( dev_b ); cudaFree( dev_c );
return 0;
}
25
รปท 3.14 แสดง Device code ของฟงกชน add()
จากซอรสโคดในรปท 3.14 จะเหนวาค าสงคลายกบ CPU แตตางตรงทเพมตว __global__
เขามา และจากรปท 5-13 จะมค าสง add<<<N, 1>>>(dev_a, dev_b, dev_c); ซงเปนการก าหนดให
ใช block จ านวนเทากบ N มาท าการประมวลผลเคอรเนล add() ส าหรบการก าหนดการท างานให
block นน CUDA จะเปนตวก าหนดใหโดยอตโนมต โดยผานตวแปรชอ blockIdx ในรปท 3.14 จะ
เหนวาจะใช blockIdx.x เพราะ CUDA เปดโอกาสใหเราสามารถทจะก าหนดจ านวน block เปนสอง
มตได ส าหรบใชประมวลผลในงานทตองการการค านวณในสองมต เชน การค านวณเมทรกซ หรอ
อเมจโปรเซสซง(Image processing) เปนตน
เมอเราสงใหเคอรเนลท างาน การก าหนดคา N จะเปนการก าหนดจ านวนของ block โดยท
block จะถกจดเรยงอยใน grid หนงมต เปนจ านวนเทากบ N ซงคาของ blockIdx.x จะมคาเรมตงแต
0 ถง N-1 ดงแสดงในรปท 3.15
__global__ void add(int *a, int *b, int *c){
int tid = blockIdx.x;
if (tid < N){
c[tid] = a[tid] + b[tid];
}
}
26
รปท 3.15 แสดงการเรยงของ block ใน grid เมอใชค าสง tid = blockIdx.x
BLOCK 4
__global__ void
add(int *a, int *b, int *c){
int tid = 3;
if (tid<N){
c[tid] = a[tid] + b[tid];
}
}
BLOCK 3
__global__ void
add(int *a, int *b, int *c){
int tid = 2;
if (tid<N){
c[tid] = a[tid] + b[tid];
}
}
BLOCK 2
__global__ void
add(int *a, int *b, int *c){
int tid = 1;
if (tid<N){
c[tid] = a[tid] + b[tid];
}
}
BLOCK 1
__global__ void
add(int *a, int *b, int *c){
int tid = 0;
if (tid<N){
c[tid] = a[tid] + b[tid];
}
}
Recommended