Open Cl Report

35
OpenCL 1 ĐẠI HC QUC GIA TP. HCHÍ MINH TRƯỜNG ĐẠI HC KHOA HC TNHIÊN KHOA CNTT - BMÔN KHMT BÁO CÁO MÔN HC LP TRÌNH SONG SONG DLIU TRÊN GPU OpenCL Thông tin vnhóm thc hin: Cào Cào Hvà tên MSSV TL. đóng góp Nguyn Hùng Sơn 1/3 Nguyn Trung Tín 1/3 Thành viên Trn Quc T1/3

description

Open CL

Transcript of Open Cl Report

Page 1: Open Cl Report

OpenCL   1  

ĐẠI HỌC QUỐC GIA TP. HỒ CHÍ MINH TRƯỜNG ĐẠI HỌC KHOA HỌC TỰ NHIÊN

KHOA CNTT - BỘ MÔN KHMT

BÁO CÁO MÔN HỌC

LẬP TRÌNH SONG SONG DỮ LIỆU TRÊN GPU

OpenCL

Thông tin về nhóm thực hiện:

Cào Cào Họ và tên MSSV TL. đóng góp

Nguyễn Hùng Sơn 1/3

Nguyễn Trung Tín 1/3 Thành viên

Trần Quốc Tự 1/3

Page 2: Open Cl Report

OpenCL   2  

Mục lục I. Giới thiệu về OpenCL...................................................................................................... 4  

1. Tổng quan.................................................................................................................... 4  

2. Lịch sử hình thành....................................................................................................... 5  

3. Đặc điểm ..................................................................................................................... 5  

3.1. OpenCL, một chuẩn lập trình mở......................................................................... 5  

3.2. Tận dụng tối đa các tài nguyên có thể có của máy tính ....................................... 5  

4. Ngôn ngữ ..................................................................................................................... 6  

5. Hạ tầng (Platform)....................................................................................................... 6  

6. Tầm vực của OpenCL ................................................................................................. 7  

II. Kiến trúc OpenCL trên nền hệ điều hành Mac OS X..................................................... 8  

1. Sơ lược về Mac OS X ................................................................................................. 8  

2. Framework & Runtime................................................................................................ 8  

3. Compiler...................................................................................................................... 9  

4. Operation Model ......................................................................................................... 9  

4.1. Platform Model .................................................................................................... 9  

4.2. Execution Model ................................................................................................ 10  

4.3. Memory Model................................................................................................... 11  

4.4. Programming Model .......................................................................................... 12  

III. Workflow phát triển chương trình OpenCL................................................................ 13  

1. Các bước viết một chương trình OpenCL................................................................. 13  

1.1. Xác định những nhiệm vụ nào có thể thực hiện song song................................ 13  

1.2. Viết các kernel và các hàm bổ trợ ...................................................................... 13  

1.3. Setup context ...................................................................................................... 13  

1.4. Viết mã lệnh để biên dịch và build chương trình OpenCL ................................ 13  

1.5. Khởi tạo các đối tượng memory object .............................................................. 14  

1.6. Lập hàng đợi lệnh có thứ tự (enqueue command) để điều khiển việc thực thi liên tục và đồng bộ các kernel, đọc và ghi dữ liệu, và thao tác trên các memory object .14  

Page 3: Open Cl Report

OpenCL   3  

1.7. Đọc giá trị trả về................................................................................................. 14  

2. Viết Kernel ................................................................................................................ 14  

3. Truy vấn thiết bị ........................................................................................................ 16  

4. Khởi tạo OpenCL Context ........................................................................................ 16  

5. Khởi tạo Program Object .......................................................................................... 17  

6. Build Program Executable ........................................................................................ 19  

7. Khởi tạo Kernel Object ............................................................................................. 22  

8. Khởi tạo Memory Object .......................................................................................... 22  

9. Thực thi các kernel .................................................................................................... 22  

9.1. Xác định số chiều của dữ liệu: ........................................................................... 23  

9.2. Xác định số lượng work-item............................................................................. 23  

9.3. Chọn kích thước cho work-group ...................................................................... 23  

9.4. Enqueue Kernel Execution................................................................................. 25  

10. Nhận kết quả trả về.................................................................................................. 28  

10.1. Chờ cho đến khi các kernel hoàn tất thực thi ................................................... 28  

10.2. Đọc kết quả....................................................................................................... 29  

11. Giải phóng bộ nhớ ................................................................................................... 29  

12. Debug chương trình OpenCL.................................................................................. 29  

IV. Performance ................................................................................................................ 31  

1. GPGPU Performance ................................................................................................ 31  

1.1. Số thực................................................................................................................ 31  

1.2. Bandwidth .......................................................................................................... 32  

1.3. Nhận xét ............................................................................................................. 32  

2. CPU Performance...................................................................................................... 33  

2.1. Số học................................................................................................................. 33  

2.2. Bandwidth .......................................................................................................... 34  

2.3. Nhận xét ............................................................................................................. 34  

IV. Tài liệu tham khảo....................................................................................................... 35  

Page 4: Open Cl Report

OpenCL   4  

I. Giới thiệu về OpenCL

1. Tổng quan OpenCL (Open Computing Language) là chuẩn mở (công bố vào 12/2008) hỗ trợ lập trình song song trên các thiết bị (bao gồm cả GPU), được đề xuất bởi Apple và nhượng lại quyền phát triển cho Khronos Group. Dù chỉ mới ra đời nhưng OpenCL lại nhận được rất nhiều sự hỗ trợ từ các nhà sản xuất phần cứng.

Danh sách các nhà sản xuất phần cứng ủng hộ OpenCL

Page 5: Open Cl Report

OpenCL   5  

2. Lịch sử hình thành OpenCL ban đầu được đề xuất và phát triển bởi Apple sau này được phát triển thêm với sự hợp tác của AMD, IBM, Intel,và nVidia. Sau đó Apple nhượng lại quyền phát triển cho Khronos Group (tổ chức đang nắm giữ các chuẩn mở khác như OpenGL, OpenAL…).

• 16/06/2008: Nhóm Khronos Compute Working được thành lập với các đại diện đến từ các công ty CPU, GPU, thiết bị nhúng và các vi xử lý khác.

• 18/11/2008: đưa ra đặc tả kĩ thuật OpenCL 1.0. • 08/12/2008: bản OpenCL 1.0 chính thức được phát hành. • 20/04/2009: nVidia ra mắt OpenCL driver và SDK để phát triển trong chương

trình OpenCL Early Access. • 05/08/2009: AMD giới thiệu công cụ phát triển đầu tiên cho nền tảng OpenCL

như là một phần của chương trình ATI Stream SDK v2.0 Beta.

3. Đặc điểm

3.1.  OpenCL,  một  chuẩn  lập  trình  mở  

Đây là điều trước tiên phải nói đến, OpenCL là một chuẩn lập trình mở hỗ trợ miễn phí cho tất cả những hãng phần cứng nào có nhu cầu tìm hiểu và ứng dụng. Do đó, mọi hỗ trợ kĩ thuật của OpenCL đều đăng tải miễn phí trên website của Khronos Group. OpenCL được phát triển theo xu hướng cross-platform, độc lập với hạ tầng phần cứng của các thiết bị tính toán cũng như giữa các hệ điều hành nên đã nhận được sự ủng hộ của rất nhiều các nhà sản xuất.

 3.2.  Tận  dụng  tối  đa  các  tài  nguyên  có  thể  có  của  máy  tính  

OpenCL được phát triển theo xu hướng tận dụng được tất cả các thiết bị tính toán có thể thực thi song song. Điều đó có nghĩa là nếu ta có một CPU đa nhân với OpenCL thì có thể lập trình để thực thi các tác vụ song song trên CPU đó. Hơn nữa, OpenCL hỗ trợ lập trình song song tác vụ (task-parallel programming) và cả lập trình song song dữ liệu (data-parallel programming).

Page 6: Open Cl Report

OpenCL   6  

4. Ngôn ngữ OpenCL sử dụng ngôn ngữ OpenCL-C dựa trên chuẩn C99 cho lập trình kernel và IEEE-754 (chuẩn dấu chấm động cho số học) vì thế nên cú pháp hoàn toàn giống với C/C++.

5. Hạ tầng (Platform) Do được phát triển theo hướng độc lập với hạ tầng phần cứng nên OpenCL tự xây dựng một lớp phần cứng trừu tượng cho bản thân mình và độc lập hoàn toàn với hạ tầng phần cứng của thiết bị.

Mô hình hạ tầng:

• Một host bao gồm nhiều Compute Device (Core – CPU / SM – GPU / …). • Một Compute Device (CPU / GPU / …) bao gồm nhiều Compute Unit. • Một Compute Unit có thể được phân chia thành một hoặc nhiều Processing

Element (vd: 1 SP trong SM GPU).

Page 7: Open Cl Report

OpenCL   7  

6. Tầm vực của OpenCL Phần cứng: OpenCL hỗ trợ lập trình song song trên CPU, GPU hay thậm chí cả các thiết bị nhúng và di động. Danh sách các GPU được OpenCL chính thức hỗ trợ bao gồm:

Nvidia:

• GeForce 9400M • GeForce 9600M GT • GeForce 8600M GT • GeForce GT 120 • GeForce GT 130 • GeForce GTX 285 • GeForce 8800 GT • GeForce 8800 GS • Quadro FX 4800 • Quadro FX 5600

Thực tế các chip dòng G80, G90 của nVidia hoặc cao hơn, thậm chí là các GPU GTX200 series vẫn có thể hỗ trợ OpenCL nếu các GPU này có công nghệ CUDA của nVidia.

ATI:

• Radeon 4850 • Radeon 4870

Đối với CPU, OpenCL hỗ trợ các chip thuộc cả hai hãng lớn hiện nay là Intel và AMD.

Do OpenCL vẫn còn khá mới cho nên chưa nhiều các hãng thiết kế phần cứng hỗ trợ chuẩn này. Nhưng tương lai rất hứa hẹn khi OpenCL là chuẩn được nhiều “ông lớn” trong ngành công nghiệp phần cứng hỗ trợ nhất. Và dù mới chỉ ra đời không lâu nhưng các đại gia này đã chính thức hỗ trợ OpenCL trong loạt sản phẩm hiệu năng cao của mình.

Về nền tảng hệ điều hành: OpenCL có thể chạy được trên cả Mac OS X, Windows và Linux.

Page 8: Open Cl Report

OpenCL   8  

II. Kiến trúc OpenCL trên nền hệ điều hành Mac OS X

1. Sơ lược về Mac OS X Hệ máy Macintosh của Apple nổi tiếng vì thiết kế đẹp và tinh tế, hệ thống phần cứng cao cấp, sự tối đồng bộ tối ưu giữa phần cứng với phần mềm. Hệ điều hành Mac OS X góp phần không nhỏ vào thành công đó nhờ vào tính đơn giản ổn định, hệ màu chuẩn, ít bị tổn hại cùng với các công nghệ tiên tiến (Grand Central Dispatch, 64-bit,…) trong đó có OpenCL, và có thể nói Mac OS X Snow Leopard 10.6 là hệ điều hành đầu tiên trực tiếp đưa OpenCL vào “Core” của mình.

2. Framework & Runtime OpenCL framework trong Mac OS X cung cấp đầy đủ các headers cần thiết để dễ dàng thực hiện biên dịch mã nguồn OpenCL cũng như giao tiếp với OpenCL Runtime. Chỉ đơn giản với một dòng lệnh #include <opencl.h>, ta có thể sử dụng các API của OpenCL mà không cần phải khai báo gì thêm trong chương trình.

Theo hình vẽ minh họa bên, mô hình làm việc của OpenCL cũng tương tự như CAL của ATI hay CUDA của nVidia.

Một điều dễ thấy là OpenCL runtime làm việc trực tiếp với driver của phần cứng, vì thế một số ý kiến cho rằng OpenCL chỉ là một chuẩn về ngôn ngữ lập trình song song nên không thể chạy nhanh hơn CAL/CUDA là hoàn toàn sai lệch. Vì làm việc trực tiếp với driver của phần cứng nên OpenCL runtime có thể coi như tương đương với CAL/CUDA và việc hiệu năng có thể cao hơn CAL/CUDA là bình thường.

Một số hãng phần cứng như ATI đưa OpenCL vào bộ công cụ lập trình song song của mình, nhưng ở mức nào đó chỉ về mặt cú pháp hình thức chứ không sử dụng OpenCL

Page 9: Open Cl Report

OpenCL   9  

runtime và tầng giao tiếp với driver vẫn giữ CAL mà ko sử dụng OpenCL runtime. Đó là lý do STREAM chạy chậm hơn OpenCL vì một số nguyên nhân nào đó.

3. Compiler OpenCL compiler trong Mac OS X sử dụng LLVM. Khi biên dịch một chương trình OpenCL, trước hết các chỉ thị trong chương trình đó sẽ được dịch sang một dạng biểu diễn trung gian (Intermediate Representation – IR). Sau đó, LLVM sẽ dịch và tối ưu hóa IR sang mã phù hợp với thiết bị mà chương trình sẽ thực thi. Điểm nhấn nằm ở chỗ: chương trình chỉ cần viết một lần nhưng vẫn có thể chạy trên nhiều kiến trúc phần cứng khác nhau. Và ứng với mỗi hệ thống phần cứng, lần đầu tiên biên dịch của chương trình sẽ được “cache” lại để tránh việc biên dịch trùng lặp không cần thiết.

4. Operation Model Sự vận hành của OpenCL được mô tả bởi cụm các model có mối liên hệ với nhau, bao gồm Platform Model (mô hình hạ tầng), Execution Model (mô hình thực thi), Memory Model (mô hình bộ nhớ), và Programming Model (mô hình lập trình).

4.1.  Platform  Model  

Như đã nói ở trên, OpenCL device sẽ làm việc với host device – là device điều khiển chương trình hoạt động. Khi chương trình thực thi, host sẽ tạo ra một môi trường trừu tượng hay còn gọi là môi trường ảo (context) và cung cấp các thiết bị tính toán (compute device) cùng với khoảng vùng nhớ nhất định mà chương trình sẽ sử dụng. Bên cạnh đó một “hàng đợi lệnh có thứ tự” (command queue) cũng sẽ được tạo ra để chương trình có thể điều phối các lệnh trong kernel và thực hiện các thao tác truy xuất tới bộ nhớ.

Page 10: Open Cl Report

OpenCL   10  

Lưu ý: tốc độ truy xuất giữa các device sẽ chậm hơn rất nhiều so với tốc độ giao tiếp nội bộ của các thành phần trong device đó và bản thân host device (vd: CPU) cũng có thể là một OpenCL device.

 4.2.  Execution  Model    

Kernel: là một tập các lệnh được viết ra để thực thi trên một thiết bị hỗ trợ OpenCL (OpenCL device). Tập các kernel và các hàm bổ trợ (helper function) được gọi là Program.

Khi biên dịch chương trình, các kernel được biên dịch thành kernel object và tương tự với program ta có program object.

Việc thực thi một chương trình OpenCL bao gồm nhiều thực thi một cách đồng thời các instance của một kernel trên một hoặc nhiều OpenCL device trên command queue được điều phối bởi ứng dụng host (host application). Mỗi instance của một kernel gọi là một work-item. Mỗi work-item thực thi cùng một đoạn mã lệnh nhưng trên các vùng dữ liệu khác nhau và mỗi một work-item chạy trên một single-core của multiprocessor. Khi ấn định thực thi chương trình trên một device nào đó, ta xác định số lượng work-item cần thiết để hoàn tất việc xử lý dữ liệu mà ta sẽ gọi là index space (không gian chỉ mục). OpenCL hỗ trợ index space tối đa là 3 chiều.

Các work-item có thể nhóm lại thành những work-group. OpenCL cũng có cơ chế đồng bộ hóa tính toán giữa các work-item trong một work-group nhưng không hỗ trợ tương tự giữa các work-group với nhau.

Mỗi work-item trong chương trình có một định danh duy nhất - global ID để hỗ trợ truy xuất trong index space. Ví dụ, một work-item trong không gian chỉ mục 2 chiều có giá trị X là 23 và Y là 6 sẽ mang global ID (23, 6). Tương tự, mỗi work-

Page 11: Open Cl Report

OpenCL   11  

group cũng sẽ có một định danh duy nhất work-group ID, để xác định vị trí của work-group trong index space.

OpenCL cũng cho phép định vị trí của một work-item trong work-group thông qua local ID.

Ta có thể hình dung sự tương tự giữa OpenCL với CUDA, mỗi work-item tương đương một thread, và mỗi work-group tương đương với một thread block.

Memory object: là một handle tới vùng nhớ global (xem 4.3) được sử dụng để lưu dữ liệu từ ứng dụng vào vùng nhớ của thiết bị để thao tác. Có 2 loại chính: buffer object và image object, với buffer object có thể chứa bất cứ loại dữ liệu nào và image object được sử dụng đặc thù cho các dữ liệu ảnh. Host application dùng command-queue để thực hiện thao tác đọc và ghi lên memory object.

4.3.  Memory  Model  

OpenCL phân chia tầm vực bộ nhớ vào bốn loại sau:

- Global memory: có thể đọc và ghi bởi tất cả các work-item trong các work-group. Đây chính là vùng nhớ được cấp phát đã mô tả trong Platform Model.

- Constant memory: là một vùng trên global memory chỉ hỗ trợ việc đọc bởi các work-item và giữ giá trị không đổi suốt quá trình thực thi của một kernel. Giá trị trên constant memory được cung cấp bởi host application.

- Local memory: có thể được đọc ghi bởi một work-group đặc thù và giữ giá trị chia sẻ bởi các work-item trong work-group đó.

- Private memory: chỉ có thể truy xuất bởi một work-item duy nhất.

Việc sử dụng bộ nhớ hiệu quả và tốc độ phụ thuộc rất nhiều vào cách dùng bốn loại bộ nhớ trên. Trong đó private memory và local memory cho tốc độ cao nhất, vùng nhớ cho tốc độ truy xuất chậm chính là global memory.

Page 12: Open Cl Report

OpenCL   12  

Các khái niệm về tầm vực của vùng nhớ trong OpenCL cũng tương tự với CUDA:

4.4.  Programming  Model   OpenCL hỗ trợ hai mô hình lập trình song song chính: song song dữ liệu (data-parallel) và song song tác vụ (task-parallel).

Các tiến trình song song dữ liệu thực thi nhiều instance có cùng kernel một cách đồng thời, mỗi instance xử lý một tập dữ liệu riêng biệt. Mỗi tập dữ liệu liên kết với một điểm trong không gian chỉ mục một, hai hay ba chiều.

Song song tác vụ lại tương tự như những tiến trình thực thi đa luồng có tính chất độc lập nhau, mỗi process thực hiện những nhiệm vụ khác nhau. Trong OpenCL, lập trình song song tác vụ bao gồm việc lập hàng đợi nhiều kernel, và để OpenCL thực hiện chúng một cách song song sử dụng các thiết bị tính toán có thể có.

Page 13: Open Cl Report

OpenCL   13  

III. Workflow phát triển chương trình OpenCL

1. Các bước viết một chương trình OpenCL Tiến trình phát triển một chương trình OpenCL bao gồm các bước dưới đây.

1.1.  Xác  định  những  nhiệm  vụ  nào  có  thể  thực  hiện  song  song   Để chương trình đạt được hiệu quả cao nhất, trước tiên ta phải xác định những gì có thể thực hiện đồng thời từ đó dễ dàng suy ra cách tổ chức bộ nhớ cũng như chi phí phù hợp cho chương trình.

 1.2.  Viết  các  kernel  và  các  hàm  bổ  trợ  

Để thực hiện tính toán song song trên OpenCL device, bắt buộc phải viết các kernel. Các kernel được đóng gói và biên dịch khi chương trình thực thi.

 1.3.  Setup  context  

Sử dụng các hàm có trong OpenCL framework để tìm và quyết định thiết bị nào sẽ dùng trong chương trình. Sau đó khởi tạo môi trường ảo bao gồm memory object và command queue.

 1.4.  Viết  mã  lệnh  để  biên  dịch  và  build  chương  trình  OpenCL  

Sau khi đã xác định được OpenCL device và setup context, chúng ta sẽ viết mã lệnh cho host application để biên dịch mã nguồn chương trình và sử dụng các kernel object từ mã nguồn đã biên dịch. Các lệnh sau được thực hiện liên tục theo thứ tự:

a. Hàm clCreateProgramWithSource để khởi tạo chương trình từ mã nguồn OpenCL-C cho trước, hoặc nếu có sẵn đoạn mã đã được biên dịch trước đó (được “cache” từ lần thực thi trước, ví dụ chương trình ngoài như các thư viện), gọi hàm clCreateProgramWithBinary. Các hàm này sẽ liên kết các kernels và các hàm bổ trợ vào một chương trình và trả về một program object.

Page 14: Open Cl Report

OpenCL   14  

b. Gọi hàm clBuildProgram để biên dịch program object phù hợp với các thiết bị đặc thù đang có của hệ thống.

c. Gọi clCreateKernel cho mỗi kernel, hoặc gọi clCreateKernelsInProgram để tạo các kernel object trong một chương trình OpenCL, hay nói khác đi, ta extract các đối tượng kernel đã được biên dịch từ một program object cho trước.

 1.5.  Khởi  tạo  các  đối  tượng  memory  object    

Để giữ các dữ liệu nhập xuất và trả về giá trị cho các đối số đầu vào (input object), memory object tham gia vào nhiệm vụ thao tác vùng nhớ giữa host device và OpenCL device.

 1.6.  Lập  hàng  đợi  lệnh  có  thứ  tự  (enqueue  command)  để  điều  khiển  việc  thực  thi  liên  tục  và  đồng  bộ  các  kernel,  đọc  và  ghi  dữ  liệu,  và  thao  tác  trên  các  memory  object  

Để thực thi một kernel, ta phải tuân theo các bước sau:

a. Gọi hàm clSetKernelArg để truyền các tham số đầu vào (parameter value) vào kernel.

b. Xác định kích thước work-group và lập index space để thực thi kernel. c. Đưa lệnh thực thi kernel vào command queue.

 1.7.  Đọc  giá  trị  trả  về  

Enqueue command để đọc giá trị xuất từ work-item và đưa nó vào host memory.

2. Viết Kernel Kernel được viết bằng ngôn ngữ OpenCL-C có cú pháp giống với C với một số điểm riêng biệt. Một kernel có dạng như sau:

Page 15: Open Cl Report

OpenCL   15  

Lưu ý:

1. Một kernel luôn được khai báo với tiết đầu tố __kernel.

2. Khi thực thi một kernel, ta dùng hàm clSetKernelArg để truyền giá trị vào các tham số được định nghĩa ở trên.

3. Các hàm get_global_id và get_local_size để lấy thông tin về work-item khi thực thi kernel.

4. mul24 là hàm toán học có sẵn trong OpenCL-C, và có rất nhiều hàm có khả năng tính toán hiệu suất cao được hỗ trợ sẵn cho cả dữ liệu có hướng lẫn vector.

5. Kernel có thể được gọi từ một kernel khác trong cùng một chương trình OpenCL.

Page 16: Open Cl Report

OpenCL   16  

3. Truy vấn thiết bị Mỗi chương trình OpenCL đòi hỏi phải có một context, bao gồm danh sách các OpenCL device tồn tại trên hệ thống. Sử dụng hàm clGetDeviceIDs để truy vấn danh sách thiết bị trên máy hỗ trợ OpenCL. Ta có thể giới hạn việc truy vấn dựa vào đặc thù của loại thiết bị hoặc kết hợp các thiết bị (vd: chỉ dùng GPU, CPU hay kết hợp cả 2), bên cạnh đó ta cũng có thể giới hạn số lượng thiết bị muốn sử dụng.

Ví dụ: giả sử chúng ta muốn thực thi code trên GPU và không quan tâm có bao nhiêu GPU sử dụng được vì ta chỉ cần một. Ta gán CL_DEVICE_TYPE_GPU vào tham số device_type trong hàm clGetDeviceIDs và gán num_entires = 1, OpenCL sẽ trả về ID của GPU đầu tiên mà nó tìm thấy.

4. Khởi tạo OpenCL Context Một khi đã xác định được sẽ sử dụng OpenCL device nào để tính toán và có ít nhất một thiết bị sử dụng được, chúng ta bắt tay vào khởi tạo OpenCL context nhằm phục vụ cho việc nhónm các thiết bị lại với nhau để có thể chia sẻ vùng nhớ giữa các compute device, hoặc chúng ta cũng có thể khởi tạo context từ một OpenGL context đã tồn tại trước đó

Page 17: Open Cl Report

OpenCL   17  

nếu có nhu cầu kết hợp OpenGL và OpenCL với nhau. Việc chia sẻ bộ nhớ giữa 2 context hoàn toàn có thể thực hiện được.

Để khởi tạo một context, trước tiên ta phải xác định thiết bị nào sẽ dùng (kết quả trả về từ hàm clGetDeviceIDs), và truyền nó vào hàm clCreateContext.

5. Khởi tạo Program Object Một chương trình OpenCL bao gồm một tập các kernel, các hàm bổ trợ có thể gọi từ kernel (các kernel luôn phải bắt đầu bằng từ khóa __kernel). Tuy nhiên, những hàm bổ trợ này có thể không thực thi đúng vai trò như một entry point từ OpenCL API. Có nghĩa là, ta chỉ có thể enqueue các kernel đã thông báo như trên. Một program object đóng gói chương trình nguồn OpenCL, đi kèm với phiên bản thực thi được build lần trước của chương trình, cũng như build options, build log, và danh sách các thiết bị mà chương trình đã biên dịch để dùng trước đó.

Ta có thể khởi tạo một program object trực tiếp từ mã nguồn của chương trình OpenCL và biên dịch nó trực tiếp vào thời điểm thực thi ứng dụng (application runtime). Thêm vào đó, ta cũng có thể build program object sử dụng mã nhị phân của lần build thành công trước đó để tránh phải build khi thực thi ứng dụng.

Page 18: Open Cl Report

OpenCL   18  

Lưu ý:

1. Mã nguồn của kernel được đưa vào ứng dụng nhưng một con trỏ kiểu char, ta có thể khai báo trực tiếp hoặc lưu vào file, từ đó đọc chuỗi ra con trỏ này và sử dụng trong hàm clCreateProgramWithSource.

2. Nếu không kết thúc chuỗi bởi NULL, ta phải quy định số lượng ký tự tối đa của một chuỗi cho mỗi mã nguồn kernel.

Hàm clCreateProgramWithSource tạo ra một program object chứa mã nguồn, nhưng nó vẫn không có khả năng thực thi đến khi nào được biên dịch và liên kết.

Một khi đã tạo bản nhị phân của chương trình, ta có thể sử dụng hàm clGetProgramInfo để chứa phiên bản nhị phân này. Nếu ta cache lại, lần chạy tới của chương trình ta có thể sử dụng phiên bản nhị phân thay cho mã nguồn để tạo program

Page 19: Open Cl Report

OpenCL   19  

object. Thao tác này giảm đáng kể thời gian khởi tạo và thực thi chương trình sau lần đầu tiên ứng dụng chạy trên một thiết bị nhất định.

Việc khởi tạo program object từ mã nhị phân cũng tương tự với từ mã nguồn, ngoại trừ việc ta phải cung cấp mỗi phiên bản nhị phân khác nhau cho mỗi thiết bị khác nhau mà kernel sẽ chạy. Ta có hàm clCreateProgramWithBinary:

Lưu ý:

1. Xem mục “Truy vấn thiết bị”. 2. Giá trị trả về từ hàm clGetDeviceIDs. 3. Khi đã có program binary, ta có thể lấy thông tin về program object từ hàm

clGetProgramInfo. 4. Vì mỗi compute device đều có tập lệnh riêng biệt, ta phải cung cấp những mã nhị

phân riêng biệt cho mỗi thiết bị muốn sử dụng. Khi gọi hàm clCreateProgramWithBinary, OpenCL kiểm tra mỗi mỗi bản nhị phân đó với từng thiết bị có trên hệ thống mà nó tìm được để đảm bảo bản nhị phân này phù hợp với thiết bị. Tham số binaryStatus trả về một mảng thông tin chứa kết quả kiểm tra cho mỗi bản nhị phân.

6. Build Program Executable Sau khi đã khởi tạo thành công program object sử dụng clCreateProgramWithSource hay clCreateProgramWithBinary, ta phải xây dựng phiên bản thực thi của chương trình (build program executable) từ program object đó. Việc build một chương trình biên dịch bất cứ mã nguồn nào có trong program

Page 20: Open Cl Report

OpenCL   20  

object và liên kết mã máy trả về với một chương trình có thể thực thi được. Hàm clBuildProgram được sử dụng để thực hiện việc này.

Hàm clBuildProgram tác động chỉnh sửa lên chính program object mà ta đã truyền để thêm vào phiên bản thực thi của chương trình. Do đó, một số program object chứa bản thực thi, một số không.

Khi biên dịch mã nguồn chương trình, có thể chúng ta sẽ gặp lỗi. OpenCL framework cung cấp hàm clGetProgramBuildInfo để hỗ trợ truy vấn trình biên dịch của OpenCL nhằm lấy thông tin chi tiết về lần build cuối cùng. Ta có thể sử dụng hàm này kết hợp với clBuildProgram như sau:

Page 21: Open Cl Report

OpenCL   21  

Trong ví dụ trên, ứng dụng dùng hằng số CL_PROGRAM_BUILD_LOG nhằm lấy thông tin chi tiết lỗi. Ta có thể sử dụng clGetProgramBuildInfo để lấy những thông tin khác như build options mà ta đã sử dụng khi gọi hàm clBuildProgram, hay tình trạng biên dịch hiện tại.

Page 22: Open Cl Report

OpenCL   22  

7. Khởi tạo Kernel Object Một kernel object chứa những thông tin đặc biệt về kernel function được khai báo trong chương trình cũng như mã nguồn, tham số sử dụng khi thực thi kernel. Mặt khác, bản thân kernel là một hàm, nhưng một kernel là một cấu trúc dữ liệu phức tạp bao gồm kernel function và cả dữ liệu mà kernel đó thao tác. Khi muốn thực thi một kernel, ta sử dụng kernel object chứa kernel đó đưa vào command queue.

Sử dụng hàm clCreateKernel để khởi tạo một kernel object hoặc gọi hàm clCreateKernelsInProgram để tạo các kernel object cho tất cả kernel trong chương trình OpenCL.

Các phần tiếp theo cung cấp cái nhìn tổng quan về cách khởi tạo memory object để chứa dữ liệu, kết hợp dữ liệu với kernel object và thực thi kernel.

8. Khởi tạo Memory Object Memory object thực chất là “một vùng bảo quản” từ global memory của thiết bị có thể được xem như nơi chứa dữ liệu chương trình. Sau khi đã khởi tạo và đăng ký kernel với OpenCL runtime, chúng ta có thể gửi dữ liệu của ứng dụng tới các kernel đang chạy trên những thiết bị khác nhau bằng cách đóng gói dữ liệu vào memory object trước tiên, sau đó liên kết memory object này với kernel đặc biệt nào đó. Như đã mô tả ở trên, có 2 loại memory object: buffer object là một khối bộ nhớ, trong khi image object lại là một cấu trúc phức tạp, đặc thù dành để biểu diễn các đối tượng ảnh 2D hay 3D.

Để khởi tạo buffer object, ta dùng hàm clCreateBuffer. Tương tự ta có thể sử dụng các hàm clCreateImage2D hay clCreateImage3D cho các dữ liệu ảnh phù hợp. Các hàm này trả về đối tượng có kiểu dữ liệu là cl_mem.

9. Thực thi các kernel OpenCL luôn thực thi các kernel theo cơ chế song song dữ liệu, có nghĩa là, các instance của cùng một kernel (hay còn gọi là các work-item) thực thi trên các phần khác nhau của tập dữ liệu. (Nếu muốn thực thi song song tác vụ, ta phải enqueue nhiều kernel trên các thiết bị khác nhau) Mỗi work-item chịu trách nhiệm thực thi kernel đúng một lần và thao tác trên phần dữ liệu được giao. Chúng ta có nhiệm vụ xác định số lượng work-item cần

Page 23: Open Cl Report

OpenCL   23  

thiết để xử lý tất cả dữ liệu. Bởi vì tập dữ liệu thường được tổ chức dưới dạng một, hai, hoặc ba chiều (dữ liệu âm thanh, ảnh hai hay ba chiều, các đối tượng ba chiều).

9.1.  Xác  định  số  chiều  của  dữ  liệu:   Bước đầu tiên khi chuẩn bị thực thi một kernel là xác định số chiều mà ta muốn sử dụng để biểu diễn dữ liệu. Ví dụ, nếu dữ liệu biểu diễn một ảnh hai chiều có kích thước m x n, khi đó ta có tập dữ liệu hai chiều với mỗi điểm dữ liệu biểu diễn bởi tọa độ của nó trên hai trục m và n.

OpenCL chưa hỗ trợ số chiều lớn hơn 3.

 9.2.  Xác  định  số  lượng  work-­item  

Bước kế tiếp khi muốn thực thi kernel là xác định có bao nhiêu work-item cần thiết để xử lý hết dữ liệu (global work size), và nó định nghĩa tổng số work-item cả ba chiều. Với dữ liệu một chiều, global work size bằng với với số lượng data item. Với dữ liệu hai chiều, global work size là m*n. Tương tự là x*y*z với dữ liệu 3 chiều có x, y, và z work-item trong mỗi chiều. Thực tế không có giới hạn về số lượng work-item, và số lượng work-item lớn sẽ tận dụng được khả năng tính toán của GPU (hơn 1000).

 9.3.  Chọn  kích  thước  cho  work-­group  

Khi enqueue một kernel để thực thi nó trên một thiết bị, ta có thể chỉ định kích thước của work-group mà OpenCL sử dụng trong quá trình thực thi. Các work-item trong cùng work-group có thể chia sẻ bộ nhớ và thực thi một cách đồng bộ. Để tận dụng những đặc điểm này, tuy nhiên, cần phải biết kích thước cực đại của work-group mà OpenCL device muốn thực thi cho phép. Ta sử dụng hàm clGetKernelWorkGroupInfo và thuộc tính CL_KERNEL_WORK_GROUP_SIZE để lấy thông tin này. Nếu không cần chia sẻ dữ liệu giữa các work-item trong một work-group, truyền giá trị NULL vào tham số local_work_size khi enque kernel khi thực.

Lưu ý là cũng cần dùng hàm clGetDeviceInfo với tham số CL_DEVICE_MAX_WORK_ITEM_SIZE để lấy kích thước cực đại trong mỗi

Page 24: Open Cl Report

OpenCL   24  

chiều của work-group, và gọi hàm clGetKernelWorkGroupInfo với tham số CL_KERNEL_WORK_GROUP_SIZE để lấy kích thước tổng của work-group.

Có 3 điều kiện cần được đáp ứng để kích thước địa phương được đảm bảo:

1. Số lượng work-item đối với từng chiều (local_x, local_y, và local_z) trong một work-group phải nhỏ hơn giá trị trả về từ hàm clGetDeviceInfo(CL_DEVICE_MAX_WORK_ITEM_SIZES).

2. Tổng số work-item trong mỗi work-group (local_x*local_y*local_z) phải nhỏ hơn hoặc bằng với giá trị trả về từ hàm clGetKernelWorkGroupInfo(CL_KERNEL_WORK_GROUP_SIZ).

3. Số lượng work-item ứng với từng chiều trong mỗi work-group phải được chia đều cho tổng số các work-item trong chiều đó (global_n mod local_n = 0).

Đoạn mã sau minh họa việc sử dụng hàm clGetKernelWorkGroupInfo:

Page 25: Open Cl Report

OpenCL   25  

 9.4.  Enqueue  Kernel  Execution  

Sau khi đã xác định số chiều cần thiết để biểu diễn dữ liệu, số work-item cho mỗi chiều, và kích thước work-group phù hợp. ta có thể enqueue kernel để thực thi nó.

Page 26: Open Cl Report

OpenCL   26  

Page 27: Open Cl Report

OpenCL   27  

Lưu ý:

1. Có thể dùng hàm clSetKernelArg để truyền giá trị cho tham số của kernel, thứ tự tùy thuộc vào thứ tự khai báo của tham số trong định nghĩa của kernel.

2. Các bước trung gian cần thực hiện trong những phần trước trước khi xử lý enqueue kernel để thực thi (xem “Các bước viết một chương trình OpenCL” – 1).

3. Chỉ mục của tham số bắt đầu từ 0. 4. Dữ liệu có thể một, hai, hoặc ba chiều (xem “Xác định số chiều của dữ

liệu” – 9.1). 5. Tham số local là một mảng xác định kích thước của mỗi chiều của mảng dữ

liệu để xử lý tất cả dữ liệu bởi kernel. Ví dụ, nếu có dữ liệu là dạng ảnh hai chiều với kích thước 64x128, thì mảng kích thước sẽ có dạng [64, 128].

6. Nếu muốn chỉ định kích thước của một work-group, ta phải chỉ định theo dạng một mảng với cùng số lượng chiều sử dụng cho dữ liệu. Giá trị của mảng phải chia đều cho mảng giá trị của global work size. Ví dụ, nếu global work size là [64, 144], thì work-group-size sẽ là [8, 12], [4, 4], hay [32, 34], nhưng không thể là [24, 32]. Không nhất thiết phải chỉ định kích thước work-group khi enqueue một kernel. Ta có thể để OpenCL làm việc đó bằng cách truyền giá trị NULL vào tham số local_work_size.

7. Tham số này và hai tham số kế tiếp được dùng để kiểm soát chuỗi các sự kiện nếu sự cố xảy ra ngoài ý muốn khi gọi hàm clCreateCommandQueue. Tham số này xác định số lượng các mục trong hai tham số tiếp theo.

Page 28: Open Cl Report

OpenCL   28  

8. Nếu đang sử dụng các đối tượng sự kiện (event objects) để quản lý chuỗi thực thi, ta có thể chỉ định những sự kiện nào phải hoàn thành trước khi lệnh này được thực hiện.

9. Nếu muốn chỉ định các lệnh khác phải chờ cho đến khi lệnh này được thực hiện xong, hay muốn truy vấn instance thực thi của kernel sau này, ta cần chứa một event object cho việc thực thi instance đó.

10. Nhận kết quả trả về Sau khi kernel thực thi xong, ta phải đọc kết quả trả về từ device và đưa nó vào host memory.

10.1.  Chờ  cho  đến  khi  các  kernel  hoàn  tất  thực  thi   Gán giá trị CL_TRUE vào tham số block_read để đảm bảo lệnh clEnqueueReadBuffer hay clEnqueueReadImage không kết thúc cho đến khi dữ liệu đã được đọc và chép vào bộ nhớ. (Dù ta có thể sử dụng hàm clFinish để bắt host application ngưng lại cho đến khi tất cả command trong một command queue đã thực hiện xong, nhưng hàm này gây ảnh hưởng đến hiệu quả về tốc độ của chương trình).

Lưu ý là trong một command queue cho trước, tất cả các lệnh luôn thực hiện theo thứ tự. Ta phải đồng bộ hóa hoặc chờ các lệnh đang thực thi trên các command queue khác nhau (tức trên các thiết bị khác nhau). Cũng lưu ý là dù ta có thể đọc và ghi từ cùng một buffer object trong một kernel, đối với image object ta phải có những object riêng biệt phục vụ cho việc đọc và ghi.

Nếu muốn chờ một kernel kết thúc thực thi và sau đó enqueue một kernel khác trên cùng một command queue, ta có thể dùng một event object cho một instance thực thi kernel đã được quenque và chỉ định lệnh kế tiếp chờ event object này trước khi thực thi (xem thêm phần Lưu ý 7, 8, 9 trong mục “Thực thi kernel” – 9.4).

Ngoài ra, ta có thể enqueue lệnh clEnqueueBarrier hay các lệnh “chắn rào” bộ nhớ (mem_fence, read_mem_fence, write_mem_fence) để đồng bộ hóa các lệnh trong một work-group. Để đồng bộ hóa các lệnh trong các work-group khác nhau, ta có thể dùng các event object. Sử dụng clWaitForEvents,

Page 29: Open Cl Report

OpenCL   29  

clEnqueueWaitForEvents và clGetEvenInfo lấy thông tin về một lệnh, bao gồm cả trạng thái thực thi của nó.

 10.2.  Đọc  kết  quả  

Khi kernel kết thúc thực thi, ta có thể đọc dữ liệu từ device trả về host để host applicatin có thể xử lý dữ liệu này. Để đọc dữ liệu, gọi hàm clEnqueueReadBuffer hay clEnguqueReadImage, tùy thuộc vào loại memory object ta đã tạo ra để chứa kết quả output (xem thêm “Execution Model / Memory Object” – II / 4.2).

Lưu ý: trừ khi có ý định sử dụng cùng một đối tượng memory object để giữ input và output của một kernel, nên khởi tạo một memory object riêng để chứa dữ liệu output, và gán nó như một đối số của kernel.

11. Giải phóng bộ nhớ Khi host application không còn yêu cầu các tài nguyên khác nhau phục vụ việc chạy OpenCL cũng như context, ta cần giải phóng các tài nguyên này. Các hàm bao gồm:

• clReleaseMemObject • clReleaseKernel • clReleaseProgram • clReleaseCommandQueue

12. Debug chương trình OpenCL Hiện tại có một vài cách phổ biến như sử dụng gdb debugger để xem mã hợp ngữ một khi chương trình đã được biên dịch, hoặc khai báo vùng nhớ với kích thước tường minh để tìm ra những trường hợp out-of-range khi truy xuất địa chỉ vùng nhớ (hiện nay chưa có cơ chế bảo vệ vùng nhớ trên các GPU). Hay sử dụng tiện ích Shark để điều chỉnh performance của chương trình. Tuy nhiên, bước đơn giản và “thô sơ” nhất vẫn là thực thi kernel trên CPU và dùng lệnh printf trong chính kernel.

Page 30: Open Cl Report

OpenCL   30  

Cũng cần đảm bảo một điều rằng kernel không mất quá nhiều thời gian để thực hiện trên GPU khi bản thân GPU là một tài nguyên chia sẻ cho các ứng dụng khác, việc chạy quá lâu có thể tác động xấu đến phản hồi của hệ thống (gây treo máy chẳng hạn).

Page 31: Open Cl Report

OpenCL   31  

IV. Performance

1. GPGPU Performance

1.1.  Số  thực   Môi trường : Windows Vista x64 SP2; Catalyst 9.11 video / STREAM 1.4.427 / OpenCL 1.0 Beta 4; ForceWare 190.89 video / CUDA 2.3 / OpenCL 1.0 live release. Dựa theo bảng thống kê này ta thấy được rằng OpenCL vẫn chậm hơn CUDA đôi chút trong tính toán floating-point, nhưng lại nhỉnh hơn khi tính toán double-emulation và nhanh hơn rất nhiều so với CAL.

Page 32: Open Cl Report

OpenCL   32  

 

1.2.  Bandwidth   Môi trường: Windows Vista x64 SP2; Catalyst 9.11 video / STREAM 1.4.427 / OpenCL 1.0 Beta 4; ForceWare 190.89 video / CUDA 2.3 / OpenCL 1.0 live release.

1.3.  Nhận  xét  

Hiệu suất hoạt động của OpenCL bản 1.0 gần như tương đương với CUDA thậm chí nhanh hơn trong một số trường hợp.

Page 33: Open Cl Report

OpenCL   33  

2. CPU Performance

2.1.  Số  học  

Môi trường: Windows Vista SP2, Server 2003 SP2, AMD CPU OpenCL 1.0 preview.

Page 34: Open Cl Report

OpenCL   34  

2.2.  Bandwidth  

Môi trường: Windows Vista SP2, Server 2003 SP2, AMD CPU OpenCL 1.0 preview.

 

2.3.  Nhận  xét  

So với những tiền bối như .Net hay Java thì hiện nay OpenCL vẫn chưa thực sự chạy tốt hơn.

Page 35: Open Cl Report

OpenCL   35  

IV. Tài liệu tham khảo • OpenCL Programming Guide for Mac OS X, Mac Develeoper Center - Apple Inc.,

2009. • OpenCL Techonology Brief, Apple Inc., 2009. • OpenCL – The Open Standard for Heterogeneous Parallel Programming, Kronos

Group, 2009. • The OpenCL Specification, Aaftab Munshi – Kronos OpenCL Working Group, 2009. • OpenCL Quickcard Reference, Kronos OpenCL Working Group, 2009. • OpenCL Tutorials, Ph.D David W. Gohara, Center for Computational Biology,

Washing University School of Medicine, 2009. • OpenCL Samples & Introduction, MacResearch, 2009. • Benchmarks : OpenCL GPGPU Performance (OpenCL vs. CUDA/STREAM),

http://www.sisoftware.net/index.html?dir=qa&location=gpu_opencl&langx=en&a= • Benchmarks : OpenCL CPU Performance (OpenCL vs native/Java/.Net),

http://www.sisoftware.net/index.html?dir=qa&location=cpu_opencl&langx=en&a=