Tôi có hạt nhân OpenCL sau:Viết vào bộ nhớ toàn cầu và địa phương tăng thời gian thực hiện kernel bằng 10000%
kernel void ndft(
global float *re, global float *im, int num_values,
global float *spectrum_re, global float *spectrum_im,
global float *spectrum_abs,
global float *sin_array, global float *cos_array,
float sqrt_num_values_reciprocal)
{
// MATH MAGIC - DISREGARD FROM HERE -----------
float x;
float y;
float sum_re = 0;
float sum_im = 0;
size_t thread_id = get_global_id(0);
//size_t local_id = get_local_id(0);
// num_values = 24 (live environment), 48 (test)
for (int i = 0; i < num_values; i++)
{
x = cos_array[thread_id * num_values + i] * sqrt_num_values_reciprocal;
y = sin_array[thread_id * num_values + i] * sqrt_num_values_reciprocal;
sum_re = sum_re + re[i] * x + im[i] * y;
sum_im = sum_im - re[i] * y + x * im[i];
}
// MATH MAGIC DONE ----------------------------
//spectrum_re[thread_id] = sum_re;
//spectrum_im[thread_id] = sum_im;
//spectrum_abs[thread_id] = hypot(sum_re, sum_im);
float asdf = hypot(sum_re, sum_im); // this is just a dummy calculation
}
Như thế này, thời gian thực hiện là khoảng 15 chúng tôi (kích thước nhóm làm việc = 567, 14 nhóm làm việc , cho tổng số 7938 chủ đề).
Tuy nhiên, bằng cách nào đó, tôi bằng cách nào đó cần truy xuất kết quả của hoạt động, đó là những gì mà một vài dòng cuối cùng dành cho, (nhận xét). Ngay sau khi tôi thực hiện một hoạt động bộ nhớ nào đó (và không quan trọng nếu spectrum_X
là global
, như trong ví dụ hoặc local
), thời gian exeuction của hạt nhân tăng lên ~ 1,4 đến 1,5 ms.
Tôi nghĩ thời gian thực hiện tăng lên là một số chi phí cố định, vì vậy tôi sẽ tích luỹ thêm dữ liệu để số lượng thời gian tương đối bị mất do hiệu ứng đó giảm thiểu. Nhưng khi tôi tăng gấp đôi số lượng chủ đề của mình (gấp đôi số lượng dữ liệu), thời gian thực hiện cũng tăng gấp đôi (lên 2.8 ~ 3.0 ms).
Tôi phát hiện ra rằng ngay cả khi tôi chỉ bỏ ghi chú một của các dòng đó, tôi có cùng thời gian thực hiện như thể tôi đã bỏ ghi chú cả ba. Ngay cả khi tôi thêm if (thread_id == 0)
và chạy nó, tôi cũng có cùng thời gian thực hiện. Tuy nhiên, nó chỉ là cách quá chậm theo cách này (giới hạn trên cho ứng dụng của tôi là khoảng 30 chúng tôi). Nó thậm chí còn nhanh hơn gấp 5 lần khi tôi chạy nó trong mã C thông thường trên CPU của tôi.
Bây giờ tôi rõ ràng đang làm điều gì đó sai, nhưng tôi không chắc chắn nơi để bắt đầu tìm kiếm một giải pháp.
Như tôi đã nhận xét về câu trả lời talonmies', tôi cũng đã làm như sau:
Từ đoạn code trên, tôi đã 4 dòng cuối cùng trông giống như
//spectrum_re[thread_id] = sum_re;
//spectrum_im[thread_id] = sum_im;
spectrum_abs[thread_id] = hypot(sum_re, sum_im);
//float asdf = hypot(sum_re, sum_im);
Theo dự kiến, thời gian thực hiện ~ 1,8 ms. Mã lắp ráp tạo ra cho hệ thống của tôi là:
//
// Generated by NVIDIA NVVM Compiler
// Compiler built on Tue Apr 03 12:42:39 2012 (1333449759)
// Driver
//
.version 3.0
.target sm_21, texmode_independent
.address_size 32
.entry ndft(
.param .u32 .ptr .global .align 4 ndft_param_0,
.param .u32 .ptr .global .align 4 ndft_param_1,
.param .u32 ndft_param_2,
.param .u32 .ptr .global .align 4 ndft_param_3,
.param .u32 .ptr .global .align 4 ndft_param_4,
.param .u32 .ptr .global .align 4 ndft_param_5,
.param .u32 .ptr .global .align 4 ndft_param_6,
.param .u32 .ptr .global .align 4 ndft_param_7,
.param .f32 ndft_param_8
)
{
.reg .f32 %f;
.reg .pred %p;
.reg .s32 %r;
ld.param.u32 %r3, [ndft_param_2];
// inline asm
mov.u32 %r18, %envreg3;
// inline asm
// inline asm
mov.u32 %r19, %ntid.x;
// inline asm
// inline asm
mov.u32 %r20, %ctaid.x;
// inline asm
// inline asm
mov.u32 %r21, %tid.x;
// inline asm
add.s32 %r22, %r21, %r18;
mad.lo.s32 %r11, %r20, %r19, %r22;
setp.gt.s32 %p1, %r3, 0;
@%p1 bra BB0_2;
mov.f32 %f46, 0f00000000;
mov.f32 %f45, %f46;
bra.uni BB0_4;
BB0_2:
ld.param.u32 %r38, [ndft_param_2];
mul.lo.s32 %r27, %r38, %r11;
shl.b32 %r28, %r27, 2;
ld.param.u32 %r40, [ndft_param_6];
add.s32 %r12, %r40, %r28;
ld.param.u32 %r41, [ndft_param_7];
add.s32 %r13, %r41, %r28;
mov.f32 %f46, 0f00000000;
mov.f32 %f45, %f46;
mov.u32 %r43, 0;
mov.u32 %r42, %r43;
BB0_3:
add.s32 %r29, %r13, %r42;
ld.global.f32 %f18, [%r29];
ld.param.f32 %f44, [ndft_param_8];
mul.f32 %f19, %f18, %f44;
add.s32 %r30, %r12, %r42;
ld.global.f32 %f20, [%r30];
mul.f32 %f21, %f20, %f44;
ld.param.u32 %r35, [ndft_param_0];
add.s32 %r31, %r35, %r42;
ld.global.f32 %f22, [%r31];
fma.rn.f32 %f23, %f22, %f19, %f46;
ld.param.u32 %r36, [ndft_param_1];
add.s32 %r32, %r36, %r42;
ld.global.f32 %f24, [%r32];
fma.rn.f32 %f46, %f24, %f21, %f23;
neg.f32 %f25, %f22;
fma.rn.f32 %f26, %f25, %f21, %f45;
fma.rn.f32 %f45, %f24, %f19, %f26;
add.s32 %r42, %r42, 4;
add.s32 %r43, %r43, 1;
ld.param.u32 %r37, [ndft_param_2];
setp.lt.s32 %p2, %r43, %r37;
@%p2 bra BB0_3;
BB0_4:
// inline asm
abs.f32 %f27, %f46;
// inline asm
// inline asm
abs.f32 %f29, %f45;
// inline asm
setp.gt.f32 %p3, %f27, %f29;
selp.f32 %f8, %f29, %f27, %p3;
selp.f32 %f32, %f27, %f29, %p3;
// inline asm
abs.f32 %f31, %f32;
// inline asm
setp.gt.f32 %p4, %f31, 0f7E800000;
mov.f32 %f47, %f32;
@%p4 bra BB0_6;
mov.f32 %f48, %f8;
bra.uni BB0_7;
BB0_6:
mov.f32 %f33, 0f3E800000;
mul.rn.f32 %f10, %f8, %f33;
mul.rn.f32 %f47, %f32, %f33;
mov.f32 %f48, %f10;
BB0_7:
mov.f32 %f13, %f48;
// inline asm
div.approx.f32 %f34, %f13, %f47;
// inline asm
mul.rn.f32 %f39, %f34, %f34;
add.f32 %f38, %f39, 0f3F800000;
// inline asm
sqrt.approx.f32 %f37, %f38; // <-- this is part of hypot()
// inline asm
mul.rn.f32 %f40, %f32, %f37;
add.f32 %f41, %f32, %f8;
setp.eq.f32 %p5, %f32, 0f00000000;
selp.f32 %f42, %f41, %f40, %p5;
setp.eq.f32 %p6, %f32, 0f7F800000;
setp.eq.f32 %p7, %f8, 0f7F800000;
or.pred %p8, %p6, %p7;
selp.f32 %f43, 0f7F800000, %f42, %p8;
shl.b32 %r33, %r11, 2;
ld.param.u32 %r39, [ndft_param_5];
add.s32 %r34, %r39, %r33;
st.global.f32 [%r34], %f43; // <-- stores the hypot's result in spectrum_abs
ret;
}
Trên thực tế tất cả các hoạt động tính toán của tôi ở đó - rất nhiều thêm/mults cũng như một sqrt
cho hypot
chức năng. Từ mã asm trên, tôi loại bỏ dòng cuối cùng thứ hai:
st.global.f32 [%r34], %f43;
đó là dòng mà thực sự lưu trữ các dữ liệu trong mảng toàn cầu spectrum_abs
. Sau đó, tôi đã sử dụng clCreateProgramWithBinary
và đã sử dụng tệp mã asm đã sửa đổi làm đầu vào. Thời gian thực hiện đã giảm xuống còn 20 chúng tôi.
Bạn đang chạy phần cứng này và phần cứng OpenCL nào? – talonmies
@talonmies NVIDIA GeForce 555M GT, bộ công cụ CUDA gần đây nhất. – dialer
Bạn có tích lũy tất cả các giá trị sau này không? Có một lý do cụ thể tại sao mỗi mục công việc cần tính 24 hoặc 48 giá trị liên tiếp không? Làm cách nào bạn tính sin_array và cos_array trước khi chuyển chúng vào hạt nhân của bạn? – mfa