Hiểu kích thước lưới CUDA, kích thước khối và tổ chức luồng (giải thích đơn giản) [đã đóng]


161

Các luồng được tổ chức để được thực thi bởi GPU như thế nào?


Hướng dẫn lập trình CUDA nên là một nơi tốt để bắt đầu cho việc này. Tôi cũng sẽ khuyên bạn nên kiểm tra giới thiệu CUDA từ đây .
Tom

Câu trả lời:


287

Phần cứng

Ví dụ, nếu một thiết bị GPU có 4 đơn vị đa xử lý và chúng có thể chạy 768 luồng mỗi luồng: thì tại một thời điểm nhất định, không quá 4 * 768 luồng sẽ thực sự chạy song song (nếu bạn lên kế hoạch cho nhiều luồng hơn, chúng sẽ chờ khởi đầu của họ).

Phần mềm

chủ đề được tổ chức trong các khối. Một khối được thực thi bởi một đơn vị đa xử lý. Các luồng của một khối có thể được xác định (lập chỉ mục) bằng cách sử dụng các chỉ mục 1Dimension (x), 2Dimensions (x, y) hoặc 3Dim (x, y, z) nhưng trong mọi trường hợp x y z <= 768 cho ví dụ của chúng tôi (áp dụng các hạn chế khác đến x, y, z, xem hướng dẫn và khả năng thiết bị của bạn).

Rõ ràng, nếu bạn cần nhiều hơn 4 * 768 luồng đó, bạn cần nhiều hơn 4 khối. Các khối cũng có thể được lập chỉ mục 1D, 2D hoặc 3D. Có một hàng các khối đang chờ để vào GPU (bởi vì, trong ví dụ của chúng tôi, GPU có 4 bộ xử lý và chỉ có 4 khối được thực thi đồng thời).

Bây giờ là một trường hợp đơn giản: xử lý ảnh 512x512

Giả sử chúng ta muốn một luồng xử lý một pixel (i, j).

Chúng tôi có thể sử dụng khối 64 chủ đề mỗi. Sau đó, chúng ta cần 512 * 512/64 = 4096 khối (để có 512x512 chủ đề = 4096 * 64)

Việc tổ chức (để lập chỉ mục hình ảnh dễ dàng hơn) các luồng trong các khối 2D có blockDim = 8 x 8 (64 luồng trên mỗi khối). Tôi thích gọi nó là threadPerBlock.

dim3 threadsPerBlock(8, 8);  // 64 threads

và 2D GridDim = 64 x 64 khối (cần 4096 khối). Tôi thích gọi nó là numBlocks.

dim3 numBlocks(imageWidth/threadsPerBlock.x,  /* for instance 512/8 = 64*/
              imageHeight/threadsPerBlock.y); 

Nhân được khởi chạy như thế này:

myKernel <<<numBlocks,threadsPerBlock>>>( /* params for the kernel function */ );       

Cuối cùng: sẽ có một cái gì đó giống như "một hàng gồm 4096 khối", trong đó một khối đang chờ để được chỉ định một trong nhiều bộ xử lý của GPU để thực hiện 64 luồng của nó.

Trong nhân, pixel (i, j) được xử lý bởi một luồng được tính theo cách này:

uint i = (blockIdx.x * blockDim.x) + threadIdx.x;
uint j = (blockIdx.y * blockDim.y) + threadIdx.y;

11
Nếu mỗi khối có thể chạy 768 luồng, tại sao chỉ sử dụng 64? Nếu bạn sử dụng giới hạn tối đa là 768, bạn sẽ có ít khối hơn và do đó hiệu suất tốt hơn.
Aliza

10
@Aliza: các khối là hợp lý , giới hạn của 768 luồng là cho mỗi đơn vị xử lý vật lý. Bạn sử dụng các khối theo thông số kỹ thuật của vấn đề của bạn để phân phối công việc cho các luồng. Không có khả năng là bạn luôn có thể sử dụng các khối của 768 luồng cho mọi vấn đề bạn gặp phải. Hãy tưởng tượng bạn phải xử lý hình ảnh 64x64 (4096 pixel). 4096/768 = 5.333333 khối?
cibercitizen1

1
khối là logic, nhưng mỗi khối được gán cho một lõi. nếu có nhiều khối hơn lõi, các khối được xếp hàng cho đến khi lõi trở nên tự do. Trong ví dụ của bạn, bạn có thể sử dụng 6 khối và có các luồng bổ sung không làm gì cả (2/3 số luồng trên khối 6).
Aliza

3
@ cibercitizen1 - Tôi nghĩ rằng quan điểm của Aliza là một điểm tốt: nếu có thể, người ta muốn sử dụng càng nhiều chủ đề trên mỗi khối càng tốt. Nếu có một ràng buộc yêu cầu ít luồng hơn, tốt hơn là giải thích tại sao đó có thể là trường hợp trong ví dụ thứ hai (nhưng vẫn giải thích trường hợp đơn giản và mong muốn hơn, trước tiên).

6
@thouis Vâng, có thể. Nhưng trường hợp là dung lượng bộ nhớ cần thiết cho mỗi luồng phụ thuộc vào ứng dụng. Chẳng hạn, trong chương trình cuối cùng của tôi, mỗi luồng gọi một hàm tối ưu hóa bình phương nhỏ nhất, đòi hỏi "rất nhiều" bộ nhớ. Rất nhiều, khối đó không thể lớn hơn chủ đề 4 x 4. Mặc dù vậy, việc tăng tốc thu được rất ấn tượng, so với phiên bản tuần tự.
cibercitizen1

9

Giả sử GPU 9800GT:

  • nó có 14 bộ đa xử lý (SM)
  • mỗi SM có 8 bộ xử lý luồng (bộ xử lý luồng AKA, SP hoặc lõi)
  • cho phép tối đa 512 luồng trên mỗi khối
  • warpsize là 32 (có nghĩa là mỗi bộ xử lý luồng 14x8 = 112 có thể lên lịch lên tới 32 luồng)

https://www.tutorialspoint.com/cuda/cuda_threads.htm

Một khối không thể có nhiều luồng hoạt động hơn 512 do đó __syncthreadschỉ có thể đồng bộ hóa số lượng luồng hạn chế. tức là nếu bạn thực hiện như sau với 600 luồng:

func1();
__syncthreads();
func2();
__syncthreads();

sau đó kernel phải chạy hai lần và thứ tự thực hiện sẽ là:

  1. func1 được thực thi cho 512 luồng đầu tiên
  2. func2 được thực thi cho 512 luồng đầu tiên
  3. func1 được thực thi cho các luồng còn lại
  4. func2 được thực thi cho các luồng còn lại

Ghi chú:

Điểm chính __syncthreadslà một hoạt động toàn khối và nó không đồng bộ hóa tất cả các luồng.


Tôi không chắc chắn về số lượng chính xác của các luồng __syncthreadscó thể đồng bộ hóa, vì bạn có thể tạo một khối có hơn 512 luồng và để cho sợi dọc xử lý việc lập lịch. Theo hiểu biết của tôi, chính xác hơn để nói: func1 được thực thi ít nhất cho 512 luồng đầu tiên.

Trước khi tôi chỉnh sửa câu trả lời này (trở lại năm 2010) tôi đã đo các luồng 14x8x32 được đồng bộ hóa bằng cách sử dụng __syncthreads.

Tôi sẽ đánh giá rất cao nếu ai đó kiểm tra lại điều này để có thông tin chính xác hơn.


Điều gì xảy ra nếu func2 () phụ thuộc vào kết quả của func1 (). Tôi nghĩ điều này là sai
Chris

@Chris Tôi đã viết cái này bảy năm trước, nhưng nếu tôi nhớ lại một cách chính xác, tôi đã làm một bài kiểm tra về điều này và nhận được kết luận rằng hạt nhân có nhiều luồng hơn gpu hoạt động theo cách này. Nếu bạn tình cờ kiểm tra trường hợp này và đạt được kết quả khác thì tôi sẽ phải xóa bài đăng này.
Bizhan

Xin lỗi, tôi nghĩ điều này là sai, đồng thời, GPU chỉ có thể chạy đồng thời 112 luồng.
Steven Lu

@StevenLu bạn đã thử chưa? Ngoài ra, tôi không nghĩ 112 luồng đồng thời có ý nghĩa đối với GPU. 112 là số lượng bộ xử lý luồng. Tôi khó có thể nhớ CUDA bây giờ :)
Bizhan

1
@StevenLu số lượng chủ đề tối đa không phải là vấn đề ở đây, __syncthreadslà một hoạt động toàn khối và thực tế là nó không thực sự đồng bộ hóa tất cả các chủ đề là một phiền toái cho người học CUDA. Vì vậy, tôi đã cập nhật câu trả lời của mình dựa trên thông tin bạn đã cho tôi. Tôi rất trân trọng điều này.
Bizhan
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.