Lập trình song song với CUDA C/C++

Một phần của tài liệu Đánh giá hiệu năng phần mềm xử lý song song trên hệ thống kết hợp CPU và GPU (Trang 37)

6. Phƣơng pháp nghiên cứu

1.3.3.Lập trình song song với CUDA C/C++

a. Biên dịch chƣơng trình với NVCC

Các Kernel (nhân) có thể được viết sử dụng kiến trúc tập lệnh của CUDA được gọi là PTX. Nó thích hợp với các ngôn ngữ lập trình bậc cao như C/C++. Trong luận văn này, mã nguồn được đưa ra và biên dịch bằng NVCC.

NVCC là một trình điều khiển biên dịch bằng việc đơn giản hóa quá trình biên dịch mã CUDA: Nó cung cấp các tùy chọn dòng lệnh đơn giản và quen thuộc thực hiện chúng bằng cách gọi tập hợp của các công cụ thực hiện các công đoạn biên dịch khác nhau.

Các tệp mã nguồn được biên dịch với NVCC bao gồm tập các mã nguồn thực hiện trên host hay trên device. Công việc cơ bản của NVCC là tách riêng hai phần mã lệnh trên host và device và chuyển đổi chúng sang dạng các hàm thực thi.

b. CUDA C Runtime

CUDA Runtime được thực hiện trong các thư viện động cudart thường đi kèm trong gói cài đặt ứng dụng. Tất cả các điểm đầu vào của nó được bắt đầu với tiền tố cuda.

Như trong mô hình lập trình không đồng nhất nói đến ở trên, mô hình lập trình CUDA giả thiết hệ thống bao gồm 1 host và 1 device, mỗi thiết bị đó đều có bộ nhớ riêng biệt được sử dụng đến trong quá trình thực thi các hàm..

1.3.4. Nguyên tắc tối ƣu hóa hiệu năng a. Chiến lƣợc tối ƣu hóa hiệu năng

Việc thực hiện tối ưu hóa hiệu năng gồm ba chiến lược cơ bản sau:

38

 Tối ưu hóa sử dụng bộ nhớ để đạt được thông lượng bộ nhớ tối đa;

 Tối ưu hóa lệnh sử dụng để đạt được công suất tối đa.

Các chiến lược này sẽ mang lại hiệu suất tốt nhất cho một phần cụ thể của một ứng dụng phụ thuộc vào giới hạn hiệu suất của phần đó; tối ưu hóa lệnh sử dụng của một hạt nhân chủ yếu là cách giới hạn nhớ truy cập, nó sẽ không mang lại sự tăng hiệu suất đáng kể. Do đó, để tối ưu hóa phải liên tục đo lường và giám sát hiệu suất bị giới hạn, ví dụ bằng cách sử dụng CUDA Profiler. Ngoài ra, so sánh thông qua các phép toán dấu phảy động (floating-point) hoặc thông lượng bộ nhớ - tùy theo điều kiện nào có ý nghĩa hơn.

b. Tối đa hóa mức độ sử dụng (Maximize Ultilization)

Để tối đa hóa việc sử dụng, ứng dụng nên được cấu trúc theo một cách mà nó thực hiện song song càng nhiều càng tốt và hiệu quả của việc ánh xạ giữa các thành phần song song khác nhau của hệ thống sao cho chúng bận (thực hiện) trong hầu hết khoảng thời gian thực thi.

c. Tối đa hóa thông lƣợng bộ nhớ (Maximize Memory Throughput)

Bước đầu tiên trong việc tối đa hóa thông lượng bộ nhớ tổng thể cho ứng dụng là giảm thiểu truyền dữ liệu với băng thông thấp. Điều đó có nghĩa là giảm thiểu truyền dữ liệu giữa host và device, băng thông của chúng thấp hơn nhiều so với truyền dữ liệu giữa bộ nhớ toàn cục và device. Nó cũng có nghĩa là giảm thiểu truyền dữ liệu giữa bộ nhớ toàn cục và device bằng cách tối đa hóa sử dụng bộ nhớ on-chip: bộ nhớ chia sẻ và lưu trữ (ví dụ, L1/L2 cache có sẵn trên các device với khả năng năng tính toán 2.x và cao hơn, bộ đệm kết cấu bộ nhớ, các hằng trên tất cả các device).

Bộ nhớ chia sẻ (Shared memory) là tương đương với sử dụng một bộ nhớ cache. Với CUDA C Runtime, một cách lập trình điển hình giúp chuyển dữ liệu từ bộ nhớ device vào bộ nhớ chia sẻ, mỗi thread sẽ thực hiện:

 Load dữ liệu từ bộ nhớ device vào bộ nhớ chia sẻ,

 Đồng bộ hóa với tất cả các thread của block để cho mỗi thread có thể đọc một cách an toàn từ vị trí bộ nhớ chia sẻ đã được truy xuất bởi các thread khác,

39

 Xử lý dữ liệu trong bộ nhớ chia sẻ,

 Đồng bộ hóa một lần nữa nếu cần thiết để đảm bảo rằng kết quả trong bộ nhớ chia sẻ đã được cập nhật,

 Ghi kết quả lại cho bộ nhớ device.

Tối ưu hóa thông lượng truy cập bộ nhớ là đặc biệt quan trọng cho bộ nhớ toàn cục trong trường hợp băng thông bộ nhớ toàn cục là thấp, vì vậy không cần tối ưu truy cập bộ nhớ toàn cục đã có băng thông cao.

d. Tối đa hóa thông lƣợng chỉ thị lệnh (Maximize Instruction Throughput)

Để tối ưu hóa thông lượng chỉ thị lệnh cho ứng dụng, nên:

 Giảm thiểu việc sử dụng các lệnh số học với thông lượng thấp, điều này bao gồm theo dõi chính xác về tốc độ khi nó không ảnh hưởng đến kết quả cuối cùng, chẳng hạn như bằng cách sử dụng các hàm định nghĩa sẵn thay vì sử dụng các hàm thông thường, độ chính xác đơn thay vì độ chính xác kép;

 Giảm thiểu các warps khác nhau bằng các lệnh điều khiển;

 Giảm số lượng các lệnh, bằng cách tối ưu hóa, đồng bộ hóa điểm ở các vị trí có thể đồng bộ sử dụng mô tả __ restrict __.

Vấn đề đánh giá hiệu năng phần mềm xử lý song song 1.4. (adsbygoogle = window.adsbygoogle || []).push({});

1.4.1. Định nghĩa về đánh giá hiệu năng phần mềm

Đánh giá hiệu năng phần mềm là việc sử dụng các phương pháp, kỹ thuật hay công cụ để phân tích thời gian xử lý một lượng dữ liệu đầu vào với kết quả đầu ra tương ứng của chương trình, từ đó đưa ra những kết luận về tốc độ tính toán, tốc độ truyền thông và khả năng truy cập bộ nhớ và kết luận về hiệu năng thực của hệ thống.

Đánh giá hiệu năng phần mềm được thực hiện dựa trên việc khảo sát quá trình hoạt động của các thư viện được cài đặt trong chương trình như các thư viện tính toán, các thư viện truyền thông điệp.

40

1.4.2. Mục đích của việc đánh giá hiệu năng phần mềm xử lý song song

Để giải quyết bài toán xử lý khối lượng lớn dữ liệu đòi hỏi các bộ xử lý phải có hiệu năng cao. Và hệ thống máy tính song song ra đời với mục đích làm tăng khả năng tính toán của máy tính bằng cách kết hợp nhiều bộ xử lý tham gia đồng thời vào quá trình xử lý. Đó là sự kết hợp giữa bộ xử lý của CPU và GPU. Khi phần cứng đã đáp ứng được yêu cầu xử lý dữ liệu lớn, để tận dụng được khả năng tính toán siêu tốc thay vì một phần mềm được lập trình tuần tự thì cần phải viết nó theo cách song song nhiều tiến trình xử lý. Một kỹ thuật lập trình đã ra đời đó là “Lập trình song song”. Để khảo sát hoạt động của phần mềm xử lý song song cần phải đánh giá hiệu năng của chúng.

Các phần mềm xử lý song song được sử dụng trong các bài toán như: khai phá dữ liệu, mô phỏng các hiện tượng trong khoa học vũ trụ,... Với việc thử nghiệm bằng nhiều bộ dữ liệu đầu vào rồi đo các thông số về tính toán, truyền thông. Khi đó ta có thể đưa ra những đánh giá đúng đắn, những hiệu chỉnh cần thiết để có thể triển khai hệ thống trong tương lai một cách tối ưu nhất về cả cấu trúc phần cứng cũng như phần mềm.

1.4.3. Yêu cầu của bài toán đánh giá hiệu năng

Đối với phần mềm được lập trình tuần tự, việc đánh giá hiệu năng cần đưa ra những thông số cụ thể phản ánh tốc độ tính toán, tốc độ truy cập bộ nhớ trong khi thực hiện bài toán trên CPU đơn của máy tính. Từ những thông số cụ thể, người lập trình có thể đưa những đánh giá về năng lực tính toán cũng như kích thước của bài toán là bao nhiêu thì sẽ phù hợp.

Đối với phần mềm lập trình song song trên hệ thống kết hợp CPU và GPU, việc đánh giá hiệu năng không chỉ dừng lại ở việc đo tốc độ tính toán, tốc độ truy cập bộ nhớ trên CPU mà còn đo các thông số đó trên GPU. Tổng hợp các thông số cho phép đánh giá hiệu năng của ứng dụng đang được triển khai về mức độ tăng tốc, hiệu quả xử lý cũng như khả năng mở rộng của bài toán.

Trên thực tế chưa có một phương pháp cụ thể để đánh giá hiệu năng một phần mềm xử lý song song. Hầu hết người ta dựa vào việc kết hợp nhiều kỹ thuật khác nhau để có thể đánh giá hiệu năng phần mềm xử lý song song. Trong khuôn khổ luận văn này, tác giả

41 nghiên cứu và trình bày các giải pháp kỹ thuật được dùng trong đánh giá hiệu năng một phần mềm xử lý song song trên hệ thống kết hợp CPU và GPU. Sau đó áp dụng các kỹ thuật đó vào đánh giá hiệu năng bài toán N-Body.

42

GIẢI PHÁP KỸ THUẬT ĐÁNH GIÁ HIỆU NĂNG PHẦN MỀM CHƢƠNG 2:

XỬ LÝ SONG SONG

Trong chương này, tác giả sẽ trình bày các giải pháp kỹ thuật chính trong đánh giá hiệu năng phần mềm sử lý song song. Bài toán N-Body được chọn làm mẫu áp dụng giải pháp kỹ thuật được trình bày để đánh giá hiệu năng.

Việc đánh giá hiệu năng của phần mềm xử lý song song trên hệ thống kết hợp CPU và GPU có thể chia làm 4 kỹ thuật chính theo các bước thực hiện như sau:

 Phân tích mô hình (Analytical modelling),

 Mô phỏng chương trình (Simulation),

 Đo lường (Measurement),

 Đánh giá kết quả (Evaluation)

Thông thường việc đánh giá hiệu năng sẽ bắt đầu từ phân tích mô hình hệ thống, tức là thiết lập một mô hình toán học với các phương trình mô tả các trạng thái của hệ thống, sau đó thực hiện mô phỏng, đo các thông số cần thiết như thời gian thực hiện, hiệu quả xử lý và cuối cùng là đánh giá các kết quả đo được để đưa ra các kết luận về hiệu năng của hệ thống.

Kỹ thuật phân tích mô hình bài toán 2.1.

Phân tích mô hình liên quan đến việc tạo ra một mô hình toán học của hệ thống. Trong tính toán song song việc phân tích mô hình là tiền đề cho việc tạo ra các đoạn chương trình xử lý song song khi cài đặt. Khi phân tích mô hình ta sẽ tìm ra được các công việc cần được song song hóa và có thể song song hóa thông qua việc khảo sát; phân tích các công thức toán học giải quyết các nhiệm vụ chính của chương trình. Ví dụ lớp bài toán ma trận thường được sử dụng trong tính toán song song, ta xét bài toán đơn giản là cộng hai ma trận A, B kích thước m x n cho ra một ma trận kết quả C, khi đó ta có công thức sau:

43 Với ví dụ trên, từ công thức cộng hai ma trận ta có thể chỉ ra được bản chất của việc cộng hai ma trận là thực hiện cộng từng phần tử ở cùng vị trí. Như vậy, nếu thực hiện song song hóa bài toán trên, ta sẽ chọn phép cộng Aij + Bij là một Kernel (nhân).

Kỹ thuật mô phỏng chƣơng trình 2.2.

Như đã trình bày trong phần tổng quan về đánh giá hiệu năng phần mềm, lớp bài toán xử lý song song thường là những bài toán xuất phát từ việc xử lý một lượng lớn dữ liệu, để thuận tiện cho việc đo hiệu năng thì mô phỏng là kỹ thuật cần thiết trước đó. Bản chất của kỹ thuật mô phỏng là tạo ra các đoạn chương trình mô tả các thuật toán song song thực hiện các công việc cần thiết của bài toán. Kỹ thuật này đòi hỏi người thực hiện phải hiểu rõ mô hình toán học đã phân tích ở mục trên và có kỹ năng lập trình song song.

Khi thực hiện kỹ thuật mô phỏng, ta có thể xác định được các điểm cần đo hiệu năng và độ đo của bài toán. Quay trở lại bài toán cộng hai ma trận ở trên, ta có thể mô phỏng bài toán đó qua một Kernel như sau:

// Định nghĩa Kernel cộng 2 ma trận

__global__ void MatAdd(float A[M][N], float B[M][N], Float C[M][N]) { (adsbygoogle = window.adsbygoogle || []).push({});

Int i = threadIdx.x; Int j = threadIdx.y; C[i][j] = A[i][j] + B[i][j]; }

Trong đoạn chương trình trên có 1 phép tính dấu phẩy động. Tốc độ xử lý của bài toán sẽ phụ thuộc vào thời gian thực hiện phép cộng các phần tử. Vậy ta có thể chỉ ra được độ đo để đánh giá hiệu năng của bài toán là số phép toán dấu phảy động trên một đơn vị thời gian.

44 Kỹ thuật phân tích mô hình và mô phỏng chương trình đôi khi có thể được kết hợp thành một mô hình duy nhất. Cả hai đều trải qua các mô hình trừu tượng của hệ thống và được định hướng theo hướng dự đoán hiệu suất..

Kỹ thuật đo hiệu năng 2.3.

Để có thể đánh giá được hiệu năng phần mềm xử lý song song, kỹ thuật quan trọng nhất là đo lường sẽ được trình bày trong phần dưới đây. Đo hiệu năng thường được thực hiện với các phép đo trực tiếp bằng cách sử dụng phần mềm hoặc theo dõi phần cứng. Kỹ thuật đo lường chỉ được thực hiện khi hệ thống vận hành, có thể trong môi trường mô phỏng. Khi tiến hành đo hiệu năng của một phần mềm xử lý song song trên hệ thống kết hợp CPU và GPU người ta thường đo: hiệu năng tính toán, hiệu năng truy cập bộ nhớ và hiệu năng truyền thông. Sau khi có kết quả ta có thể sử dụng các định luật đo sự tăng tốc xử lý để có thể đánh giá hiệu năng của ứng dụng.

2.3.1. Đo hiệu năng tính toán

Đo hiệu năng tính toán là việc xác định số phép toán, số lệnh hay tổng số hàm của chương trình thực hiện trên một đơn vị thời gian.

Để tiến hành đo hiệu năng tính toán, ta có thể sử dụng các phần mềm chuyên dụng như: WhetStone, DhryStone, Linpack…Trong đó WhetStone và DhryStone là những phần mềm đo hiệu năng tính toán đầu tiên.

WhetStone đo hiệu năng bằng cách thực hiện một tập các module con, mỗi module con có thể chứa các lệnh tính toán (ví dụ: các phép toán số nguyên, số thực dấu phảy động hay các cấu trúc điều khiển, lời gọi hàm), kết quả được in ra màn hình. Kết quả đo được qua WhetStone có được tính theo đơn vị KWIPS (Kilo Whetstone Instructions Per Second) hoặc MWIPS (Mega Whetstone Instructions Per Second).

DhryStone là công cụ dùng để đo hiệu năng các chương trình tính toán không chứa các phép tính số phải động. Nó thích hợp với các chương trình có kích thước mã nguồn nhỏ như các chương trình hệ thống (liên quan đến số nguyên). Đầu ra của DhryStone là số các DhryStones trên giây (tức là số phép lặp của vòng lặp chính trên giây). Đơn vị đo

45 của DhryStone là MIPS (số triệu lệnh trên giây). Về sau còn sử dụng thêm đơn vị DMIPS (Dhrystone MIPS),

Tuy nhiên cả hai công cụ trên đều thiết kế với mục đích đo hiệu năng của các chương trình xử lý tuần tự CPU. Hiện nay, nhiều chương trình tính toán song song trên hệ thống kết hợp CPU và GPU ra đời kéo theo sự ra đời của các công cụ đo hiệu năng tính toán song song. Một trong những công cụ tiêu biểu về đo hiệu năng tính toán song song trong những năm gần đây là Linpack [8] của tác giả Jack Dongarra trường Đại học Tennesse. Linpack sử dụng chủ yếu các phép toán trên kiểu dữ liệu số thực dấu phẩy động (floating point). Kết quả trả về có thứ nguyên là MFLOPS (hàng triệu phép tính dấu phẩy động trên 1 giây). Công cụ này được sử dụng rất phổ biến và đã được phát triển thêm các phiên bản viết bằng ngôn ngữ C và Java từ phiên bản ban đầu viết bằng ngôn ngữ Fortran.

Gần đây cùng với việc phát triển phần cứng hỗ trợ tính toán song song, tập đoàn NVIDA cũng xây dựng các công cụ và môi trường phần mềm giúp các nhà phát triển phần mềm có thể làm việc dễ dàng trên các thiết bị của hãng. Hệ thống thư viện CUDA đã cũng cấp nhiều bài toán đã được thiết kế với các chế độ benchmark, đo hiệu năng tính toán trên CPU hay kết hợp cả CPU và GPU. Lập trình viên có thể nghiệm đo hiệu năng tính toán bằng các sử dụng trực tiếp các thư viện này thay vì một công cụ khác. Đơn vị đo chính của các bài toán benchmack với CUDA là GFLOPs (Giga Flop Per Second).

Một phần của tài liệu Đánh giá hiệu năng phần mềm xử lý song song trên hệ thống kết hợp CPU và GPU (Trang 37)