Sự ra đời của bộ xử lý đa lõi CPU và đa nhân GPU được hiểu rằng nhiều chíp xử lý cùng thực hiện trong các hệ thống song song. Xa hơn nữa lý thuyết về song song của chúng ta là luật của Moore. Những thách thức đặt ra để dẫn tới việc phát triển các phần mềm ứng dụng là trong suốt sự song song trong tiến trình chạy lệnh ảnh hưởng bởi sự gia tăng số lượng lõi của bộ xử lý, rất cần thiết và quan trọng trong việc xử lý các lệnh của ứng dụng đồ hoạ 3D. CUDA là một ngôn ngữ lập trình và môi trường phần mềm thiết kế khắc phục được những khó khăn trong việc duy trì thời lượng học ngắn của lập trình viên và thân thiện với các ngôn ngữ lập trình chuẩn như C. Về bản chất , nó có 3 khái niệm quan trọng Phân cấp của các nhóm thread Phia sẻ bộ nhớ Đồng bộ hoá phân cách Nó thật đơn giản để người lập trình tìm hiểu cũng như cài đặt tối thiểu của sự mở rộng sang C.
Mục lục 1 PHẦN 1 - CUDA : NGÔN NGỮ LẬP TRÌNH SONG SONG 3 1.1 Giới thiệu chung 3 1.2 GPU: Bộ xử lý nhiều lõi độ song song cao đa thread 3 2 CHƯƠNG 2 - MÔ HÌNH LẬP TRÌNH 6 2.1 Mô hình lập trình CUDA 6 2.2 Phân cấp bộ nhớ 8 2.3 Ngăn xếp phần mềm 10 3 CHƯƠNG 3 - GIAO DIỆN LẬP TRÌNH 12 3.1 Một mở rộng của ngôn ngữ C 12 3.2 Những mở rộng của ngôn ngữ 12 3.3 Các loại hạn định của hàm 12 3.3.1 Chỉ thị __device__ 12 3.3.2 Chỉ thị __global__ 13 3.3.3 Chỉ thị __host__ 13 3.3.4 Những hạn chế 13 3.4 Các loại hạn định của biến 13 3.4.1 Chỉ thị __device__ 13 3.4.2 Chỉ thị __constant__ 14 3.4.3 Chỉ thị __share__ 14 3.4.4 Những hạn chế 15 3.5 Cấu hình thực thi 16 3.6 Những biến số định nghĩa sẵn 16 3.6.1 gridDim 16 3.7 blockIdx 16 3.7.1 blockDim 17 3.7.2 threadIdx 17 3.7.3 warpSize 17 3.7.4 Các hạn chế 17 3.8 Biên dịch với NVCC 17 3.8.1 __noinline__ 18 3.8.2 #pragma unroll 18 4 Các thành phần thực thi chung 18 4.1 Các kiểu Vector được dựng sẵn 18 4.1.1 char1, uchar1, char2, uchar2, char3, uchar3, char4, uchar4, short1, ushort1, short2, ushort2, short3, ushort3, short4, ushort4, int1, uint1, int2, uint2, int3, uint3, int4, uint4, long1, ulong1, long2, ulong2, long3, ulong3, long4, ulong4, float1, float2, float3, float4, double2 18 4.1.2 Kiểu dữ liệu dim3 19 4.2 Các hàm toán học 19 4.3 Hàm thời gian 19 4.4 Kiểu Texture 19 4.4.1 Khai báo Tham chiếu texture 20 4.4.2 Tính chất của của Tham chiếu texture 20 4.4.3 Texure từ bộ nhớ tuyến tính qua mảng của CUDA 20 5 Các thành phần chạy trên thiết bị tính toán 20 5.1 Các hàm toán học 21 5.2 Hàm đồng bộ 21 5.3 Hàm Texture 21 5.3.1 Texture từ bộ nhớ tuyến tính 21 5.3.2 Texture từ các mảng CUDA 22 5.4 Các hàm phần tử 23 6 Các thành phần trên máy chủ 23 Tài liệu tham khảo 24 1 PHẦN 1 - CUDA : NGÔN NGỮ LẬP TRÌNH SONG SONG 1.1 Giới thiệu chung Sự ra đời của bộ xử lý đa lõi CPU và đa nhân GPU được hiểu rằng nhiều chíp xử lý cùng thực hiện trong các hệ thống song song. Xa hơn nữa lý thuyết về song song của chúng ta là luật của Moore. Những thách thức đặt ra để dẫn tới việc phát triển các phần mềm ứng dụng là trong suốt sự song song trong tiến trình chạy lệnh ảnh hưởng bởi sự gia tăng số lượng lõi của bộ xử lý, rất cần thiết và quan trọng trong việc xử lý các lệnh của ứng dụng đồ hoạ 3D. CUDA là một ngôn ngữ lập trình và môi trường phần mềm thiết kế khắc phục được những khó khăn trong việc duy trì thời lượng học ngắn của lập trình viên và thân thiện với các ngôn ngữ lập trình chuẩn như C. Về bản chất , nó có 3 khái niệm quan trọng - Phân cấp của các nhóm thread - Phia sẻ bộ nhớ - Đồng bộ hoá phân cách Nó thật đơn giản để người lập trình tìm hiểu cũng như cài đặt tối thiểu của sự mở rộng sang C. Những khái niệm ở đây cung cấp về lý thuyết lập trình song song dữ liệu nhỏ sạch và lý thuyết lập trình song song thread, cùng với lý thuyết lập trình song song trên dữ liệu nhỏ thô và lập trình song song nhiệm vụ. một chương trình viết bằng CUDA được dịch có thể thực hiện trên nhiều lõi xử lý và chỉ chạy trong cùng một thời gian. 1.2 GPU: Bộ xử lý nhiều lõi độ song song cao đa thread Được xây dựng do yêu cầu của thị trường, đồ hoạ 3D phân giải cao, GPU có thể lập trình phát triển thành bộ xử lý nhiều lõi song song cao và đa thread với tốc độ tính toán cực cao và băng thông nhớ rất rộng , được minh hoạ trong hình vẽ dưới đây: Tốc độ tính toán trên giây và băng thông nhớ rộng của CPU và GPU Nguyên nhân của sự xung đột giữa CPU và GPU là GPU được thiết kế đặc biệt với khả năng tính toán mạnh, tính toán song song cao - cụ thể là do yêu cầu render của đồ hoạ - và do đó nó được thiết kế nhiều transistor hơn để sử dụng cho việc xử lý dữ liệu trên cache và điều khiển dòng GPU cần nhiều Transistor cho quá trình xử lý dữ liệu hơn Đặc biệt hơn, GPU rất thích hợp với các vấn đề liên quan tới địa chỉ có thể được thể hiện trong tính toán dữ liệu song song – các chương trình giống nhau được thực hiện một cách song song trên nhiều bộ dữ liệu với độ tính toán mạnh - tỉ lệ giữa độ phức tạp tính toán và bộ nhớ cho các phép tính. Bởi những chương trình giống nhau được thực hiện cho mỗi bộ dữ liệu, có những yêu cầu thấp hơn cho việc điều khiển dòng phức tạp; và còn bởi vì nó được thực hiện trên nhiều dữ liệu và độ mạnh tính toán cao , bộ nhớ truy nhập ẩn có thể bị che bởi các phép tính thay vì một cache dữ liệu thật lớn. Xử lý song song dữ liệu nối các phần tử dữ liệu voíư các thread xử lý song song . Nhiều ứng dụng xử lý lương lớn tập dữ liệu có thể dùng mô hình lập trình song song để tăng tốc độ tính toán. Trong việc render đồ hoạ 3D, một tập các điểm và đường thẳng đứng được nối với các thread song song CUDA là một ngôn ngữ lập trình rất thích hợp với khả năng tính toán song song của GPU. Phát triển cuối cùng về GPU của NVIDIA dựa trên sơ sở kiến trúc Tesla. Nó hỗ trợ mô hình lập trình CUDA và khả năng tăng tốc các ứng dụng viết trên CUDA. 2 CHƯƠNG 2 - MÔ HÌNH LẬP TRÌNH 2.1 Mô hình lập trình CUDA CUDA mở rộng C bằng việc cho phép người lập trình định nghĩa các hàm của C, được gọi Kernels, khi được gọi nó được thực hiện N lần song song bởi N thread CUDA khác nhau. Một kernel được định nghĩa bằng việc dùng _global_ để khai báo và số lượng thread cho mỗi lời gọi được chỉ ra bằng việc sử dụng cú pháp <<<…>>> // Kernel definition __global__ void vecAdd(float* A, float* B, float* C) { } int main() { // Kernel invocation vecAdd<<<1, N>>>(A, B, C); } Mỗi thread thực hiện một kernel mang một threadID riêng nó chứa bên trong thread và được tao bởi biến threadIdx . Giống như lý thuyết đưa ra, ví dụ dưới đây là một đoạn code thực hiện cộng hai vector A và B của N và lưu kết quả vào vector C: __global__ void vecAdd(float* A, float* B, float* C) { int i = threadIdx.x; C[i] = A[i] + B[i]; } int main() { // Kernel invocation vecAdd<<<1, N>>>(A, B, C); } Phân cấp Thread Để thuận tiện, ThreadIdx có 3vector , nhờ đó những thread có thể được định nghĩa bằng việc dùng 1, 2 hay 3 chiều chỉ số. Đoạn code dưới đây thể hiện việc cộng 2 ma trận A và B kích thước NxN và kết quả được lưu và ma trận C : __global__ void matAdd(float A[N][N], float B[N][N], float C[N][N]) { int i = threadIdx.x; int j = threadIdx.y; C[i][j] = A[i][j] + B[i][j]; } int main() { // Kernel invocation dim3 dimBlock(N, N); matAdd<<<1, dimBlock>>>(A, B, C); } Chỉ số của thread và threadID của nó liên quan tới nhau theo một cách dễ hiểu: khối 1 chiều , chúng giống nhau; với khối 2 chiều (Dx, Dy) , threadID của chỉ số (x, y) là (x+y Dx) ; với khối 3 chiều (Dx, Dy, Dz) threadID của chỉi số (x,y,z) là (x+y Dx+z Dx Dy). Thread bên trong block có thể kết hợp với nhau bằng việc chia sẻ dữ liệu thông qua vài vùng nhớ chia sẻ và đồng bộ hoá việc thực hiện chúng theo điều kiện truy nhập vùng nhớ. Rõ ràng hơn , có thể chỉ ra điểm đồng bộ trên kernel bằng việc gọi _syncthreads() trong hàm. Tuy nhiên kernel có thể được thực hiện bởi nhiều khối thread được phân chia bằng nhau, do đó tổng số thread bằng với số thread trên một khối nhân với số lượng khối. Các khối đa chiều thể hiện ở hình dưới đây . Chiều của lưới được xác định bởi tham số cú pháp <<<…>>> . Mỗi khối trong lưới được chỉ ra là 1 chiều 2 chiều có thể truy cập trong kernel thông qua biến blockIdx. chiều của khối thread được truy cập trong kernel qua biến blockDim. __global__ void matAdd(float A[N][N], float B[N][N], float C[N][N]) { int i = blockIdx.x * blockDim.x + threadIdx.x; int j = blockIdx.y * blockDim.y + threadIdx.y; if (i < N && j < N) C[i][j] = A[i][j] + B[i][j]; } int main() { // Kernel invocation dim3 dimBlock(16, 16); dim3 dimGrid((N + dimBlock.x – 1) / dimBlock.x, (N + dimBlock.y – 1) / dimBlock.y); matAdd<<<dimGrid, dimBlock>>>(A, B, C); } Khối thread kích thước 16x16 =256 thread được chọn và lưới được tạo với số khối đủ để có một thread tren một thành phần matrận như trước. Lưới khối thread 2.2 Phân cấp bộ nhớ Thread CUDA có thể truy cập dữ liệu từ nhiều không gian nhớ trong suốt quá trình thực hiện của nó như ví dụ minh hoạ trên. Mỗi thread có một vùng nhớ nội bộ riêng . Mỗi khối thread có vùng nhớ chia sẻ chúng với tất cả thread thuộc block đó và với các block trong cùng thời gian đó. Tóm lại đó là tất cả các thread có thể truy cập tới một vùng nhớ chung gọi là vùng nhớ cục bộ. Có những không gian nhớ chỉ có thể đọc bởi tất cả các thread: vùng nhớ không đổi và vùng nhớ kết cấu. Cả hai loại này được tối ưu hoá từ các vùng nhớ được sử dụng khác nhau (xem trong các chương sau) vùng nhớ kết cấu cho phép các mode địa chỉ khác nhau cũng như các cách lọc dữ liệu cho một số định dạng dữ liệu đặc biệt. Phân cấp bộ nhớ Host và thiết bị Các thread của CUDA được thực hiện trên các thiết bị vật lý cái mà thực thi như một bộ xử lý trên host chạy bằng chương trình C. Ví dụ một trường hợp, khi kernel thực hiện trên GPU và phần còn lại chương trình C được thực hiện trên CPU. 2.3 Ngăn xếp phần mềm Ngăn xếp phần mềm CUDA gồm các lớp như hình dưới đây. Driver của thiết bị, giao diện ứng dụng của chương trình(API) thời gian chạy và hai thư viện toán học mức cao CUFFT và CUBLAS cả hai đều được mô tả trong văn bản chung. [...]... tính toán 3 CHƯƠNG 3 - GIAO DIỆN LẬP TRÌNH 3.1 Một mở rộng của ngôn ngữ C Mục tiêu của giao diện lập trình CUDA là cũng cấp một mối liên hệ đơn giản cho người đã sử dụng quen thuộc ngôn ngữ C và dễ dàng viết các chương trình chạy trên các thiết bị Giao diện lập trình bào gồm: − Một số các mở rộng từ ngôn ngữ lập trình C cho phép lập trình viên thực hiện một phần của chương trình trên thiết bị tính toán... tượng cubun như một khởi tạo các mảng dữ liệu toàn cục và chứa một cấu hình thực thi để kích hoạt quá trình chạy của mã CUDA Giao diện của tiến trình biên dịch các tệp mã nguồn của CUDA tương thích với các cú pháp của ngôn ngữ C++ Mã trên máy chủ hỗ trợ toàn bộ cho mã C++ Tuy nhiên chỉ một phần ngôn ngữ C của C++ được hỗ trợ trên thiết bị tính toán C++ có các thành phần như lớp, kế thừa hay định nghĩa... tex1Dfetch( texture texRef, int x); float tex1Dfetch( texture texRef, int x); float tex1Dfetch( texture texRef, int x); float tex1Dfetch( texture texRef, int x); float tex1Dfetch( texture... trợ, ví dụ: float4 tex1Dfetch( texture texRef, int x); 5.3.2 Texture từ các mảng CUDA Khi texture từ các mảng CUDA, texture được truy xuất qua hàm tex1D(), tex2D() và tex3D(): template Type tex1D(texture texRef, float x); template Type tex2D(texture . hình lập trình CUDA và khả năng tăng tốc các ứng dụng viết trên CUDA. 2 CHƯƠNG 2 - MÔ HÌNH LẬP TRÌNH 2.1 Mô hình lập trình CUDA CUDA mở rộng C bằng việc cho phép người lập trình định nghĩa các. hoặc không và mặc định được đặt bằng 1. ReadMode bằng với giá trị cudaReadModeNormalizedFloat hoặc cudaReadModeElementType. Nếu cudaReadModeNormalizedFloat và Type là số nguyên 16 bit hoặc 8 bit,. song CUDA là một ngôn ngữ lập trình rất thích hợp với khả năng tính toán song song của GPU. Phát triển cuối cùng về GPU của NVIDIA dựa trên sơ sở kiến trúc Tesla. Nó hỗ trợ mô hình lập trình CUDA