tất cả:
Tôi đang tìm hiểu cách bộ nhớ dùng chung tăng tốc quá trình lập trình GPU. Tôi đang sử dụng mã bên dưới để tính giá trị bình phương của từng phần tử cộng với giá trị bình phương của giá trị trung bình của các phần tử lân cận bên trái và bên phải của nó. Khi code chạy thì kết quả không như mong đợi.
10 kết quả đầu tiên được in ra là 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 và kết quả tôi mong đợi là 25, 2, 8, 18, 32, 50, 72,98,128,162;
Mã như sau, được trích dẫnđây ;
Bạn có thể cho tôi biết có chuyện gì không? Cảm ơn bạn rất nhiều vì sự giúp đỡ của bạn.
#include
#include
#include
#include
const int N=1024;
__global__ void tính_it(dữ liệu float *)
{
int tid = threadIdx.x;
__shared__ float myblock[N];
thả nổi tmp;
// tải phần tử dữ liệu của thread vào bộ nhớ dùng chung
myblock[tid] = dữ liệu[tid];
// đảm bảo rằng tất cả các thread đã nạp giá trị của chúng vào
// bộ nhớ dùng chung; nếu không, một luồng có thể đang tính toán
// trên dữ liệu được đơn vị hóa.
__syncthreads();
// tính trung bình của các hàng xóm bên trái và bên phải của luồng này
tmp = (myblock[tid>0?tid-1:(N-1)] + myblock[tid<(N-1)?tid+1:0]) * 0,5f;
// bình phương kết quả trước đó và cộng giá trị của tôi, bình phương
tmp = tmp*tmp + myblock[tid]*myblock[tid];
// ghi kết quả trở lại bộ nhớ chung
dữ liệu[tid] = myblock[tid];
__syncthreads();
}
int chính(){
phím char;
nổi *a;
nổi *dev_a;
a = (float*)malloc(N*sizeof(float));
cudaMalloc((void**)&dev_a,N*sizeof(float));
cho (int i=0; i
a[i] = tôi;
}
cudaMemcpy(dev_a, a, N*sizeof(float), cudaMemcpyHostToDevice);
tính_it<<>>(dev_a);
cudaMemcpy(a, dev_a, N*sizeof(float), cudaMemcpyDeviceToHost);
cho (int i=0; i<10; i++){
std::cout<
}
std::cin>>key;
miễn phí (a);
miễn phí (dev_a);
Một trong những câu hỏi đơn giản nhất trong mã hạt nhân là:
dữ liệu[tid] = myblock[tid];
Tôi nghĩ bạn có thể có ý này:
dữ liệu[tid] = tmp;
Ngoài ra, bạn sẽ bắt đầu 1024 khối, một luồng trên mỗi khối. Đây không phải là cách sử dụng GPU đặc biệt hiệu quả, điều đó có nghĩa là trong mỗi khối luồng tin tức
Các biến đều bằng 0 (và chỉ 0, vì chỉ có một luồng trên mỗi khối luồng.)
Có nhiều vấn đề với cách tiếp cận này, nhưng đây là một vấn đề đơn giản:
tmp = (myblock[tid>0?tid-1:(N-1)] + myblock[tid<31?tid+1:0]) * 0,5f;
bởi vì tin tức
luôn bằng 0, do đó mảng bộ nhớ dùng chung (khối của tôi
) được điền vào nên logic ở dòng này không có ý nghĩa. khi tin tức
bằng 0, bạn chọn khối của tôi[N-1]
như được giao cho tmp
của học kỳ đầu tiên, nhưng khối của tôi [1023]
Không có gì được lấp đầy.
Có vẻ như bạn không hiểu các hệ thống phân cấp CUDA khác nhau:
- Lưới là tất cả các luồng liên quan đến khởi chạy kernel
- Lưới bao gồm các khối luồng
- Mỗi khối luồng là một nhóm các luồng làm việc cùng nhau trên một SM duy nhất
- Tài nguyên bộ nhớ dùng chung đượctài nguyên trên mỗi SM, thay vì tài nguyên trong phạm vi thiết bị
__synthreads()
Cũng chạy trên cơ sở khối luồng (không phải phạm vi thiết bị)
threadIdx.x
là biến tích hợp cung cấp ID luồng duy nhất cho tất cả các luồng trong khối luồng, nhưng không phải trên toàn bộ lưới.
Thay vào đó, bạn nên chia vấn đề của mình thành các nhóm khối luồng có kích thước hợp lý (nghĩa là nhiều luồng). Sau đó, mỗi khối luồng sẽ có thể chạy gần giống như cách bạn đã vạch ra. Sau đó, bạn cần thực hiện xử lý đặc biệt đối với hành vi của điểm bắt đầu và điểm kết thúc (trong dữ liệu của bạn) của từng khối luồng.
Bạn cũng làm không đúng kiểm tra lỗi cudaĐiều này được khuyến khích, đặc biệt nếu bạn gặp vấn đề với mã CUDA.
Nếu bạn thực hiện các thay đổi trong mã hạt nhân mà tôi đã chỉ ra trước tiên và đảo ngược thứ tự của các tham số khởi động hạt nhân khối và lưới:
tính_it<<<1,N>>>(dev_a);
Như Kristof đã nói, tôi nghĩ bạn sẽ đạt được thứ gì đó gần với những gì bạn muốn. Tuy nhiên, bạn sẽ không thể dễ dàng mở rộng quy mô này vượt quá N=1024 mà không thực hiện các thay đổi khác đối với mã của mình.
Dòng mã này cũng không chính xác:
miễn phí (dev_a);
bởi vì dev_a
là sử dụng cudaMalloc
được phân bổ trên thiết bị, vì vậy bạn nên giải phóng nó như thế này:
cudaFree (dev_a);
Tôi là một lập trình viên xuất sắc, rất giỏi!